From 826a5f7892c044f65eb8784fbecb57c7170ab2e0 Mon Sep 17 00:00:00 2001
From: garamond13 <98652255+garamond13@users.noreply.github.com>
Date: Wed, 13 May 2026 02:16:46 +0200
Subject: [PATCH 1/2] Luma: Add managed resources
---
Source/Core/Core.vcxproj | 2 +
Source/Core/Core.vcxproj.filters | 6 ++
Source/Core/core.hpp | 6 ++
Source/Core/includes/callbacks.h | 17 ++++
Source/Core/includes/instance_data.h | 8 +-
Source/Core/includes/managed_resources.h | 33 +++++++
Source/Core/includes/math.h | 7 ++
Source/Core/utils/draw.hpp | 115 +++++++++++++----------
Source/Games/BioShock Series/main.cpp | 3 +-
9 files changed, 144 insertions(+), 53 deletions(-)
create mode 100644 Source/Core/includes/callbacks.h
create mode 100644 Source/Core/includes/managed_resources.h
diff --git a/Source/Core/Core.vcxproj b/Source/Core/Core.vcxproj
index 30f1f9f3..3c3e216f 100644
--- a/Source/Core/Core.vcxproj
+++ b/Source/Core/Core.vcxproj
@@ -608,6 +608,7 @@
+
@@ -615,6 +616,7 @@
+
diff --git a/Source/Core/Core.vcxproj.filters b/Source/Core/Core.vcxproj.filters
index 721c82a4..5287438d 100644
--- a/Source/Core/Core.vcxproj.filters
+++ b/Source/Core/Core.vcxproj.filters
@@ -105,5 +105,11 @@
Includes
+
+ Includes
+
+
+ Includes
+
\ No newline at end of file
diff --git a/Source/Core/core.hpp b/Source/Core/core.hpp
index 209b623b..20d8c6a8 100644
--- a/Source/Core/core.hpp
+++ b/Source/Core/core.hpp
@@ -2959,6 +2959,12 @@ namespace
// TODO: put code to track all recently created resources and late upgraded them if the size/aspect ratio now matches the swapchain (some games resize the swapchain after resources, so in that case we should handle indirect upgrades like this)
}
+ // Execute all Luma callbacks.
+ for (const auto& callback : LumaCallbacks::on_init_swapchain)
+ {
+ callback.second();
+ }
+
game->OnInitSwapchain(swapchain);
}
diff --git a/Source/Core/includes/callbacks.h b/Source/Core/includes/callbacks.h
new file mode 100644
index 00000000..d5a28341
--- /dev/null
+++ b/Source/Core/includes/callbacks.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+#include
+
+// struct cause maybe we want to make some members private in future
+//
+// So far std::unoredered_map may be the best solution for this.
+// std::unordered_set could be better, but it won't work with std::function.
+// std::vector could be too much manual management for the user (developer)?
+//
+// Signal user that callback was executed?
+struct LumaCallbacks final
+{
+ // Executed after swapchaiin resize and after swapchain creation.
+ static inline std::unordered_map> on_init_swapchain;
+};
\ No newline at end of file
diff --git a/Source/Core/includes/instance_data.h b/Source/Core/includes/instance_data.h
index eea5f224..2f7230d8 100644
--- a/Source/Core/includes/instance_data.h
+++ b/Source/Core/includes/instance_data.h
@@ -16,6 +16,8 @@
#include
#include
+#include "managed_resources.h"
+
// Forward declarations
struct GameDeviceData;
@@ -90,7 +92,7 @@ struct TraceDrawCallData
AppendCommandList,
ResetCommmandList,
FlushCommandList,
- Custom, // Custom draw call for custom passes we added/replaced
+ Custom, // Custom draw call for custom passes we added/replaced
};
TraceDrawCallType type = TraceDrawCallType::Shader;
@@ -583,6 +585,8 @@ struct __declspec(uuid("cfebf6d4-d184-4e1a-ac14-09d088e560ca")) DeviceData
buffers.push_back(luma_ui_data.get());
return buffers;
}
+
+ ManagedResources managed_resources;
};
struct __declspec(uuid("c5805458-2c02-4ebf-b139-38b85118d971")) SwapchainData
@@ -595,5 +599,5 @@ struct __declspec(uuid("c5805458-2c02-4ebf-b139-38b85118d971")) SwapchainData
std::vector> display_composition_rtvs;
// Whether the original SDR (vanilla) swapchain was linear space (e.g. sRGB formats)
- bool vanilla_was_linear_space = false;
+ bool vanilla_was_linear_space = false;
};
diff --git a/Source/Core/includes/managed_resources.h b/Source/Core/includes/managed_resources.h
new file mode 100644
index 00000000..b0f4236c
--- /dev/null
+++ b/Source/Core/includes/managed_resources.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+#include
+#include "com_ptr.h"
+
+struct ManagedResources
+{
+ // Key should be result of CompileTimeStringHash()!
+ // Example usage: shader_resource_views[CompileTimeStringHash("scene")] = srv_scene;
+ // Example usage: shader_resource_views["scene"_h] = srv_scene;
+ std::unordered_map> shader_resource_views;
+ std::unordered_map> render_target_views;
+ std::unordered_map> unordered_access_views;
+ std::unordered_map> depth_stencil_views;
+ std::unordered_map> resources;
+ std::unordered_map> buffers;
+ std::unordered_map> textures_1d;
+ std::unordered_map> textures_2d;
+ std::unordered_map> textures_3d;
+ std::unordered_map> input_layouts;
+ std::unordered_map> rasterizers;
+ std::unordered_map> samplers;
+ std::unordered_map> blends;
+ std::unordered_map> depth_stencils;
+ std::unordered_map> vertex_shaders;
+ std::unordered_map> compute_shaders;
+ std::unordered_map> pixel_shaders;
+ std::unordered_map> domain_shaders;
+ std::unordered_map> geometry_shaders;
+ std::unordered_map> hull_shaders;
+};
\ No newline at end of file
diff --git a/Source/Core/includes/math.h b/Source/Core/includes/math.h
index 61b1d2a7..44a4054b 100644
--- a/Source/Core/includes/math.h
+++ b/Source/Core/includes/math.h
@@ -182,6 +182,13 @@ namespace Math
return hash;
}
+ // User-defined literal for CompileTimeStringHash.
+ // Usage: `"some_string"_h`, this is equivalent to `CompileTimeStringHash("some_string")`.
+ consteval uint32_t operator"" _h(const char* str, size_t len)
+ {
+ return CompileTimeStringHash(str);
+ }
+
uint32_t FindNextUniqueNumberInRange(uint32_t value, uint32_t min_value, uint32_t max_value, std::unordered_set excluded_values)
{
assert(value >= min_value && value <= max_value);
diff --git a/Source/Core/utils/draw.hpp b/Source/Core/utils/draw.hpp
index 079477f6..ebd74f9e 100644
--- a/Source/Core/utils/draw.hpp
+++ b/Source/Core/utils/draw.hpp
@@ -3,6 +3,11 @@
#include "../texture_data/SMAA_AreaTex.h"
#include "../texture_data/SMAA_SearchTex.h"
+#include "../includes/callbacks.h"
+#include "../includes/math.h"
+
+using Math::operator"" _h;
+
enum class DrawStateStackType
{
// Same as "FullGraphics" but skips some states that are usually not changed by our code.
@@ -1319,16 +1324,10 @@ void SanitizeNaNs(ID3D11Device* device, ID3D11DeviceContext* device_context, ID3
}
}
-struct DrawSMAAData
+void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, DeviceData& device_data, ID3D11RenderTargetView* rtv, ID3D11ShaderResourceView* srv_color_tex, ID3D11ShaderResourceView* srv_color_tex_gamma, ID3D11ShaderResourceView* srv_predication_tex = nullptr)
{
- ComPtr srv_area_tex;
- ComPtr srv_search_tex;
- ComPtr ds_disable_depth_replace_stencil;
- ComPtr ds_disable_depth_use_stencil;
-};
+ auto& managed_resources = device_data.managed_resources;
-void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const DeviceData& device_data, DrawSMAAData& data, ID3D11RenderTargetView* rtv, ID3D11ShaderResourceView* srv_color_tex, ID3D11ShaderResourceView* srv_color_tex_gamma, ID3D11ShaderResourceView* srv_predication_tex = nullptr)
-{
// Backup IA.
D3D11_PRIMITIVE_TOPOLOGY primitive_topology_original;
device_context->IAGetPrimitiveTopology(&primitive_topology_original);
@@ -1388,38 +1387,41 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
viewport.Height = tex_desc.Height;
// Create DS.
- [[unlikely]] if (!data.ds_disable_depth_replace_stencil)
+ [[unlikely]] if (!managed_resources.depth_stencils["smaa_disable_depth_replace_stencil"_h])
{
CD3D11_DEPTH_STENCIL_DESC ds_desc(D3D11_DEFAULT);
ds_desc.DepthEnable = FALSE;
ds_desc.StencilEnable = TRUE;
ds_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
- ensure(device->CreateDepthStencilState(&ds_desc, data.ds_disable_depth_replace_stencil.put()), >= 0);
+ ensure(device->CreateDepthStencilState(&ds_desc, managed_resources.depth_stencils["smaa_disable_depth_replace_stencil"_h].put()), >= 0);
}
// Create DSV.
- tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
- tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
- ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- ComPtr dsv;
- ensure(device->CreateDepthStencilView(tex.get(), nullptr, dsv.put()), >= 0);
+ [[unlikely]] if (!managed_resources.depth_stencil_views["smaa_dsv"_h])
+ {
+ tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+ tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+ ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
+ ensure(device->CreateDepthStencilView(tex.get(), nullptr, managed_resources.depth_stencil_views["smaa_dsv"_h].put()), >= 0);
+ }
// Create RT and views.
- tex_desc.Format = DXGI_FORMAT_R8G8_UNORM;
- tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
- ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- ComPtr rtv_edge_detection;
- ensure(device->CreateRenderTargetView(tex.get(), nullptr, rtv_edge_detection.put()), >= 0);
- ComPtr srv_edge_detection;
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, srv_edge_detection.put()), >= 0);
+ [[unlikely]] if (!managed_resources.render_target_views["smaa_edge_detection"_h])
+ {
+ tex_desc.Format = DXGI_FORMAT_R8G8_UNORM;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
+ ensure(device->CreateRenderTargetView(tex.get(), nullptr, managed_resources.render_target_views["smaa_edge_detection"_h].put()), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, managed_resources.shader_resource_views["smaa_edge_detection"_h].put()), >= 0);
+ }
// Bindings.
device_context->OMSetBlendState(nullptr, nullptr, UINT_MAX);
- device_context->OMSetDepthStencilState(data.ds_disable_depth_replace_stencil.get(), 1);
- device_context->OMSetRenderTargets(1, &rtv_edge_detection, dsv.get());
+ device_context->OMSetDepthStencilState(managed_resources.depth_stencils["smaa_disable_depth_replace_stencil"_h].get(), 1);
+ device_context->OMSetRenderTargets(1, &managed_resources.render_target_views["smaa_edge_detection"_h], managed_resources.depth_stencil_views["smaa_dsv"_h].get());
device_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- device_context->VSSetShader(device_data.native_vertex_shaders.at(Math::CompileTimeStringHash("SMAA Edge Detection VS")).get(), nullptr, 0);
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("SMAA Edge Detection PS")).get(), nullptr, 0);
+ device_context->VSSetShader(device_data.native_vertex_shaders.at("SMAA Edge Detection VS"_h).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("SMAA Edge Detection PS"_h).get(), nullptr, 0);
const std::array ps_samplers = { device_data.sampler_state_linear.get(), device_data.sampler_state_point.get() };
device_context->PSSetSamplers(0, ps_samplers.size(), ps_samplers.data());
const std::array ps_srvs_edge_detection = { srv_color_tex_gamma, srv_predication_tex };
@@ -1428,8 +1430,8 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
device_context->RSSetState(nullptr);
static constexpr FLOAT clear_color[4] = {};
- device_context->ClearRenderTargetView(rtv_edge_detection.get(), clear_color);
- device_context->ClearDepthStencilView(dsv.get(), D3D10_CLEAR_STENCIL, 1.0f, 0);
+ device_context->ClearRenderTargetView(managed_resources.render_target_views["smaa_edge_detection"_h].get(), clear_color);
+ device_context->ClearDepthStencilView(managed_resources.depth_stencil_views["smaa_dsv"_h].get(), D3D11_CLEAR_STENCIL, 1.0f, 0);
device_context->Draw(3, 0);
//
@@ -1438,7 +1440,7 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
//
// Create area texture.
- [[unlikely]] if (!data.srv_area_tex)
+ [[unlikely]] if (!managed_resources.shader_resource_views["smaa_area_tex"_h])
{
D3D11_TEXTURE2D_DESC tex_desc = {};
tex_desc.Width = AREATEX_WIDTH;
@@ -1453,11 +1455,11 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
subresource_data.pSysMem = areaTexBytes;
subresource_data.SysMemPitch = AREATEX_PITCH;
ensure(device->CreateTexture2D(&tex_desc, &subresource_data, tex.put()), >= 0);
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, data.srv_area_tex.put()), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, managed_resources.shader_resource_views["smaa_area_tex"_h].put()), >= 0);
}
// Create search texture.
- [[unlikely]] if (!data.srv_search_tex)
+ [[unlikely]] if (!managed_resources.shader_resource_views["smaa_search_tex"_h])
{
D3D11_TEXTURE2D_DESC tex_desc = {};
tex_desc.Width = SEARCHTEX_WIDTH;
@@ -1472,36 +1474,37 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
subresource_data.pSysMem = searchTexBytes;
subresource_data.SysMemPitch = SEARCHTEX_PITCH;
ensure(device->CreateTexture2D(&tex_desc, &subresource_data, tex.put()), >= 0);
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, data.srv_search_tex.put()), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, managed_resources.shader_resource_views["smaa_search_tex"_h].put()), >= 0);
}
// Create DS.
- [[unlikely]] if (!data.ds_disable_depth_use_stencil)
+ [[unlikely]] if (!managed_resources.depth_stencils["smaa_disable_depth_use_stencil"_h])
{
CD3D11_DEPTH_STENCIL_DESC ds_desc(D3D11_DEFAULT);
ds_desc.DepthEnable = FALSE;
ds_desc.StencilEnable = TRUE;
ds_desc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;
- ensure(device->CreateDepthStencilState(&ds_desc, data.ds_disable_depth_use_stencil.put()), >= 0);
+ ensure(device->CreateDepthStencilState(&ds_desc, managed_resources.depth_stencils["smaa_disable_depth_use_stencil"_h].put()), >= 0);
}
// Create RT and views.
- tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- ComPtr rtv_blending_weight_calculation;
- ensure(device->CreateRenderTargetView(tex.get(), nullptr, rtv_blending_weight_calculation.put()), >= 0);
- ComPtr srv_blending_weight_calculation;
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, srv_blending_weight_calculation.put()), >= 0);
+ [[unlikely]] if (!managed_resources.render_target_views["smaa_blending_weight_calculation"_h])
+ {
+ tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
+ ensure(device->CreateRenderTargetView(tex.get(), nullptr, managed_resources.render_target_views["smaa_blending_weight_calculation"_h].put()), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, managed_resources.shader_resource_views["smaa_blending_weight_calculation"_h].put()), >= 0);
+ }
// Bindings.
- device_context->OMSetDepthStencilState(data.ds_disable_depth_use_stencil.get(), 1);
- device_context->OMSetRenderTargets(1, &rtv_blending_weight_calculation, dsv.get());
- device_context->VSSetShader(device_data.native_vertex_shaders.at(Math::CompileTimeStringHash("SMAA Blending Weight Calculation VS")).get(), nullptr, 0);
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("SMAA Blending Weight Calculation PS")).get(), nullptr, 0);
- const std::array ps_srvs_blending_weight_calculation = { srv_edge_detection.get(), data.srv_area_tex.get(), data.srv_search_tex.get() };
+ device_context->OMSetDepthStencilState(managed_resources.depth_stencils["smaa_disable_depth_use_stencil"_h].get(), 1);
+ device_context->OMSetRenderTargets(1, &managed_resources.render_target_views["smaa_blending_weight_calculation"_h], managed_resources.depth_stencil_views["smaa_dsv"_h].get());
+ device_context->VSSetShader(device_data.native_vertex_shaders.at("SMAA Blending Weight Calculation VS"_h).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("SMAA Blending Weight Calculation PS"_h).get(), nullptr, 0);
+ const std::array ps_srvs_blending_weight_calculation = { managed_resources.shader_resource_views["smaa_edge_detection"_h].get(), managed_resources.shader_resource_views["smaa_area_tex"_h].get(), managed_resources.shader_resource_views["smaa_search_tex"_h].get() };
device_context->PSSetShaderResources(0, ps_srvs_blending_weight_calculation.size(), ps_srvs_blending_weight_calculation.data());
- device_context->ClearRenderTargetView(rtv_blending_weight_calculation.get(), clear_color);
+ device_context->ClearRenderTargetView(managed_resources.render_target_views["smaa_blending_weight_calculation"_h].get(), clear_color);
device_context->Draw(3, 0);
//
@@ -1511,15 +1514,29 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, const D
// Bindings.
device_context->OMSetRenderTargets(1, &rtv, nullptr);
- device_context->VSSetShader(device_data.native_vertex_shaders.at(Math::CompileTimeStringHash("SMAA Neighborhood Blending VS")).get(), nullptr, 0);
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("SMAA Neighborhood Blending PS")).get(), nullptr, 0);
- const std::array ps_srvs_neighborhood_blending = { srv_color_tex, srv_blending_weight_calculation.get() };
+ device_context->VSSetShader(device_data.native_vertex_shaders.at("SMAA Neighborhood Blending VS"_h).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("SMAA Neighborhood Blending PS"_h).get(), nullptr, 0);
+ const std::array ps_srvs_neighborhood_blending = { srv_color_tex, managed_resources.shader_resource_views["smaa_blending_weight_calculation"_h].get() };
device_context->PSSetShaderResources(0, ps_srvs_neighborhood_blending.size(), ps_srvs_neighborhood_blending.data());
device_context->Draw(3, 0);
//
+ // Reset resolution dependent resources on init swapchain.
+ // Some are intentionaly left out, we will recreate them here (in the DrawSMAA function).
+ [[unlikely]] if (!LumaCallbacks::on_init_swapchain["luma_smaa"_h])
+ {
+ auto on_init_swapchain = [&]()
+ {
+ managed_resources.depth_stencil_views["smaa_dsv"_h].reset();
+ managed_resources.render_target_views["smaa_edge_detection"_h].reset();
+ managed_resources.render_target_views["smaa_blending_weight_calculation"_h].reset();
+ };
+
+ LumaCallbacks::on_init_swapchain["luma_smaa"_h] = on_init_swapchain;
+ }
+
// Restore.
device_context->OMSetBlendState(blend_original.get(), blend_factor_original, sample_mask_original);
device_context->OMSetDepthStencilState(ds_original.get(), stencil_ref_original);
diff --git a/Source/Games/BioShock Series/main.cpp b/Source/Games/BioShock Series/main.cpp
index fb19f5d3..71a61d2e 100644
--- a/Source/Games/BioShock Series/main.cpp
+++ b/Source/Games/BioShock Series/main.cpp
@@ -152,7 +152,6 @@ struct GameDeviceDataBioshockSeries final : public GameDeviceData
com_ptr scene_texture_srv;
ComPtr srv_depth;
- DrawSMAAData draw_smaa_data;
DrawLumaBloomData draw_luma_bloom_data;
ComPtr cb_bloom;
};
@@ -825,7 +824,7 @@ class BioshockSeries final : public Game
com_ptr rtv;
native_device->CreateRenderTargetView(resource.get(), nullptr, &rtv);
- DrawSMAA(native_device, native_device_context, device_data, game_device_data.draw_smaa_data, rtv.get(), srv_copy.get(), srv_linear_to_gamma.get(), game_device_data.srv_depth.get());
+ DrawSMAA(native_device, native_device_context, device_data, rtv.get(), srv_copy.get(), srv_linear_to_gamma.get(), game_device_data.srv_depth.get());
}
if (g_luma_bloom_enable)
From c22ae83804e2666b3467f039abaf9d1997c7a603 Mon Sep 17 00:00:00 2001
From: garamond13 <98652255+garamond13@users.noreply.github.com>
Date: Fri, 15 May 2026 13:34:27 +0200
Subject: [PATCH 2/2] Luma: Refactor Luma bloom
---
Source/Core/core.hpp | 6 +
Source/Core/includes/callbacks.h | 5 +-
Source/Core/includes/managed_resources.h | 15 +-
Source/Core/utils/draw.hpp | 194 ++++++++++++-----------
Source/Games/BioShock Series/main.cpp | 3 +-
5 files changed, 128 insertions(+), 95 deletions(-)
diff --git a/Source/Core/core.hpp b/Source/Core/core.hpp
index 20d8c6a8..7d475bc4 100644
--- a/Source/Core/core.hpp
+++ b/Source/Core/core.hpp
@@ -2570,6 +2570,12 @@ namespace
}
#endif // ENABLE_SR
+ // Execute all Luma callbacks.
+ for (const auto& callback : LumaCallbacks::on_destroy_device)
+ {
+ callback.second();
+ }
+
device->destroy_private_data();
}
diff --git a/Source/Core/includes/callbacks.h b/Source/Core/includes/callbacks.h
index d5a28341..dc1e8765 100644
--- a/Source/Core/includes/callbacks.h
+++ b/Source/Core/includes/callbacks.h
@@ -12,6 +12,9 @@
// Signal user that callback was executed?
struct LumaCallbacks final
{
- // Executed after swapchaiin resize and after swapchain creation.
+ // Executed after swapchain resize and after swapchain creation.
static inline std::unordered_map> on_init_swapchain;
+
+ // Executed before device is destroyed.
+ static inline std::unordered_map> on_destroy_device;
};
\ No newline at end of file
diff --git a/Source/Core/includes/managed_resources.h b/Source/Core/includes/managed_resources.h
index b0f4236c..403379ed 100644
--- a/Source/Core/includes/managed_resources.h
+++ b/Source/Core/includes/managed_resources.h
@@ -30,4 +30,17 @@ struct ManagedResources
std::unordered_map> domain_shaders;
std::unordered_map> geometry_shaders;
std::unordered_map> hull_shaders;
-};
\ No newline at end of file
+};
+
+// TODO: Move this somewhere else.
+inline void ResetCOMArray(auto& array)
+{
+ for (auto*& ptr : array)
+ {
+ if (ptr)
+ {
+ ptr->Release();
+ ptr = nullptr;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Core/utils/draw.hpp b/Source/Core/utils/draw.hpp
index ebd74f9e..09f5e404 100644
--- a/Source/Core/utils/draw.hpp
+++ b/Source/Core/utils/draw.hpp
@@ -1525,17 +1525,14 @@ void DrawSMAA(ID3D11Device* device, ID3D11DeviceContext* device_context, DeviceD
// Reset resolution dependent resources on init swapchain.
// Some are intentionaly left out, we will recreate them here (in the DrawSMAA function).
- [[unlikely]] if (!LumaCallbacks::on_init_swapchain["luma_smaa"_h])
+ auto on_init_swapchain = [&]()
{
- auto on_init_swapchain = [&]()
- {
- managed_resources.depth_stencil_views["smaa_dsv"_h].reset();
- managed_resources.render_target_views["smaa_edge_detection"_h].reset();
- managed_resources.render_target_views["smaa_blending_weight_calculation"_h].reset();
- };
+ managed_resources.depth_stencil_views["smaa_dsv"_h].reset();
+ managed_resources.render_target_views["smaa_edge_detection"_h].reset();
+ managed_resources.render_target_views["smaa_blending_weight_calculation"_h].reset();
+ };
- LumaCallbacks::on_init_swapchain["luma_smaa"_h] = on_init_swapchain;
- }
+ LumaCallbacks::on_init_swapchain.try_emplace("luma_smaa"_h, on_init_swapchain);
// Restore.
device_context->OMSetBlendState(blend_original.get(), blend_factor_original, sample_mask_original);
@@ -1608,15 +1605,35 @@ struct alignas(16) CBLumaBloomData
float sigma;
};
-struct DrawLumaBloomData
+void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, DeviceData& device_data, ID3D11ShaderResourceView* srv_scene, int nmips, const float* sigmas, ID3D11ShaderResourceView** srv_bloom)
{
- ComPtr cb;
- ComPtr blend;
-};
+ auto& managed_resources = device_data.managed_resources;
-void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const DeviceData& device_data, DrawLumaBloomData& draw_luma_bloom_data, ID3D11ShaderResourceView* srv_scene, int nmips, const float* sigmas, ID3D11ShaderResourceView** srv_bloom)
-{
- // Backup IA.
+ // TODO: Reorganize this better.
+ static std::vector rtv_mips_x(nmips);
+ static std::vector srv_mips_x(nmips);
+ static std::vector rtv_mips_y(nmips);
+ static std::vector srv_mips_y(nmips);
+
+#if DEVELOPMENT
+ static int last_nmips = nmips;
+ if (nmips != last_nmips)
+ {
+ ResetCOMArray(rtv_mips_x);
+ ResetCOMArray(srv_mips_x);
+ ResetCOMArray(rtv_mips_y);
+ ResetCOMArray(srv_mips_y);
+
+ rtv_mips_x.resize(nmips);
+ srv_mips_x.resize(nmips);
+ rtv_mips_y.resize(nmips);
+ srv_mips_y.resize(nmips);
+
+ last_nmips = nmips;
+ }
+#endif
+
+ // Backup IA.
D3D11_PRIMITIVE_TOPOLOGY primitive_topology_original;
device_context->IAGetPrimitiveTopology(&primitive_topology_original);
@@ -1655,9 +1672,6 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
ComPtr dsv_original;
device_context->OMGetRenderTargets(rtvs_original.size(), rtvs_original.data(), dsv_original.put());
- // Create MIPs and views.
- //
-
// Get the scene resource and texture description from the SRV.
ComPtr resource;
srv_scene->GetResource(resource.put());
@@ -1669,82 +1683,73 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
const auto scene_width = tex_desc.Width;
const auto scene_height = tex_desc.Height;
- // Create Y MIPs and views.
- ////
-
- tex_desc.Width /= 2;
- tex_desc.Height /= 2;
- tex_desc.MipLevels = nmips;
- tex_desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
- tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
- ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
+ const UINT x_mip0_width = tex_desc.Width / 2;
+ const UINT x_mip0_height = tex_desc.Height;
- const UINT y_mip0_width = tex_desc.Width;
- const UINT y_mip0_height = tex_desc.Height;
+ const UINT y_mip0_width = tex_desc.Width / 2;
+ const UINT y_mip0_height = tex_desc.Height / 2;
- std::vector rtv_mips_y(nmips);
- std::vector srv_mips_y(nmips);
+ // Create Y MIPs and views.
+ [[unlikely]] if (!rtv_mips_y[0])
+ {
+ tex_desc.Width = y_mip0_width;
+ tex_desc.Height = y_mip0_height;
+ tex_desc.MipLevels = nmips;
+ tex_desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
- rtv_desc.Format = tex_desc.Format;
- rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
+ rtv_desc.Format = tex_desc.Format;
+ rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
- D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
- srv_desc.Format = tex_desc.Format;
- srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- srv_desc.Texture2D.MipLevels = 1;
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+ srv_desc.Format = tex_desc.Format;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = 1;
- for (int i = 0; i < nmips; ++i)
- {
- rtv_desc.Texture2D.MipSlice = i;
- ensure(device->CreateRenderTargetView(tex.get(), &rtv_desc, &rtv_mips_y[i]), >= 0);
- srv_desc.Texture2D.MostDetailedMip = i;
- ensure(device->CreateShaderResourceView(tex.get(), &srv_desc, &srv_mips_y[i]), >= 0);
+ for (int i = 0; i < nmips; ++i)
+ {
+ rtv_desc.Texture2D.MipSlice = i;
+ ensure(device->CreateRenderTargetView(tex.get(), &rtv_desc, &rtv_mips_y[i]), >= 0);
+ srv_desc.Texture2D.MostDetailedMip = i;
+ ensure(device->CreateShaderResourceView(tex.get(), &srv_desc, &srv_mips_y[i]), >= 0);
+ }
}
- ////
-
// Create X MIPs and views.
- ////
-
- std::vector rtv_mips_x(nmips);
- std::vector srv_mips_x(nmips);
-
- // Create X MIP0 and views.
- tex_desc.Width = scene_width / 2;
- tex_desc.Height = scene_height;
- tex_desc.MipLevels = 1;
- ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- ensure(device->CreateRenderTargetView(tex.get(), nullptr, &rtv_mips_x[0]), >= 0);
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, &srv_mips_x[0]), >= 0);
-
- const UINT x_mip0_width = tex_desc.Width;
- const UINT x_mip0_height = tex_desc.Height;
-
- // Create rest of X MIPs and views.
- for (UINT i = 1; i < nmips; ++i) {
- tex_desc.Width = max(1u, x_mip0_width >> i);
- tex_desc.Height = max(1u, x_mip0_height >> i);
+ [[unlikely]] if (!rtv_mips_x[0])
+ {
+ // Create X MIP0 and views.
+ tex_desc.Width = x_mip0_width;
+ tex_desc.Height = x_mip0_height;
+ tex_desc.MipLevels = 1;
ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
- ensure(device->CreateRenderTargetView(tex.get(), nullptr, &rtv_mips_x[i]), >= 0);
- ensure(device->CreateShaderResourceView(tex.get(), nullptr, &srv_mips_x[i]), >= 0);
- }
+ ensure(device->CreateRenderTargetView(tex.get(), nullptr, &rtv_mips_x[0]), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, &srv_mips_x[0]), >= 0);
- ////
-
- //
+ // Create rest of X MIPs and views.
+ for (UINT i = 1; i < nmips; ++i)
+ {
+ tex_desc.Width = max(1u, x_mip0_width >> i);
+ tex_desc.Height = max(1u, x_mip0_height >> i);
+ ensure(device->CreateTexture2D(&tex_desc, nullptr, tex.put()), >= 0);
+ ensure(device->CreateRenderTargetView(tex.get(), nullptr, &rtv_mips_x[i]), >= 0);
+ ensure(device->CreateShaderResourceView(tex.get(), nullptr, &srv_mips_x[i]), >= 0);
+ }
+ }
// Create bloom CB.
//
- if (!draw_luma_bloom_data.cb)
+ [[unlikely]] if (!managed_resources.buffers["luma_bloom_cb"_h])
{
D3D11_BUFFER_DESC buffer_desc = {};
buffer_desc.ByteWidth = sizeof(CBLumaBloomData);
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- ensure(device->CreateBuffer(&buffer_desc, nullptr, draw_luma_bloom_data.cb.put()), >= 0);
+ ensure(device->CreateBuffer(&buffer_desc, nullptr, managed_resources.buffers["luma_bloom_cb"_h].put()), >= 0);
}
CBLumaBloomData cb_data;
@@ -1752,9 +1757,9 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
auto update_constant_buffer = [&]()
{
D3D11_MAPPED_SUBRESOURCE mapped_subresource;
- ensure(device_context->Map(draw_luma_bloom_data.cb.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_subresource), >= 0);
+ ensure(device_context->Map(managed_resources.buffers["luma_bloom_cb"_h].get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_subresource), >= 0);
std::memcpy(mapped_subresource.pData, &cb_data, sizeof(CBLumaBloomData));
- device_context->Unmap(draw_luma_bloom_data.cb.get(), 0);
+ device_context->Unmap(managed_resources.buffers["luma_bloom_cb"_h].get(), 0);
};
//
@@ -1778,7 +1783,7 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
device_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
device_context->VSSetShader(device_data.native_vertex_shaders.at(Math::CompileTimeStringHash("Bloom VS")).get(), nullptr, 0);
device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("Bloom Downsample PS")).get(), nullptr, 0);
- device_context->PSSetConstantBuffers(11, 1, &draw_luma_bloom_data.cb);
+ device_context->PSSetConstantBuffers(11, 1, &managed_resources.buffers["luma_bloom_cb"_h]);
const std::array ps_samplers = { device_data.sampler_state_linear.get() };
device_context->PSSetSamplers(0, ps_samplers.size(), ps_samplers.data());
device_context->PSSetShaderResources(0, 1, &srv_scene);
@@ -1800,7 +1805,7 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
// Bindings.
device_context->OMSetRenderTargets(1, &rtv_mips_y[0], nullptr);
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("Bloom Prefilter PS")).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("Bloom Prefilter PS"_h).get(), nullptr, 0);
device_context->PSSetShaderResources(0, 1, &srv_mips_x[0]);
device_context->RSSetViewports(1, &viewports_y[0]);
@@ -1812,10 +1817,11 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
// Downsample passes
//
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("Bloom Downsample PS")).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("Bloom Downsample PS"_h).get(), nullptr, 0);
// Render downsample passes.
- for (UINT i = 1; i < nmips; ++i) {
+ for (UINT i = 1; i < nmips; ++i)
+ {
viewport_x.Width = max(1u, x_mip0_width >> i);
viewport_x.Height = max(1u, x_mip0_height >> i);
@@ -1857,15 +1863,15 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
// Upsample passes
//
- device_context->PSSetShader(device_data.native_pixel_shaders.at(Math::CompileTimeStringHash("Bloom Upsample PS")).get(), nullptr, 0);
+ device_context->PSSetShader(device_data.native_pixel_shaders.at("Bloom Upsample PS"_h).get(), nullptr, 0);
- if (!draw_luma_bloom_data.blend)
+ [[unlikely]] if (!managed_resources.blends["luma_bloom_blend"_h])
{
CD3D11_BLEND_DESC blend_desc(D3D11_DEFAULT);
blend_desc.RenderTarget[0].BlendEnable = TRUE;
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_BLEND_FACTOR;
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_BLEND_FACTOR;
- ensure(device->CreateBlendState(&blend_desc, draw_luma_bloom_data.blend.put()), >= 0);
+ ensure(device->CreateBlendState(&blend_desc, managed_resources.blends["luma_bloom_blend"_h].put()), >= 0);
}
for (int i = nmips - 1; i > 0; --i)
@@ -1882,7 +1888,7 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
device_context->OMSetRenderTargets(1, &rtv_mips_y[i - 1], nullptr);
device_context->PSSetShaderResources(0, 1, &srv_mips_y[i]);
device_context->RSSetViewports(1, &viewports_y[i - 1]);
- device_context->OMSetBlendState(draw_luma_bloom_data.blend.get(), blend_factor, UINT_MAX);
+ device_context->OMSetBlendState(managed_resources.blends["luma_bloom_blend"_h].get(), blend_factor, UINT_MAX);
device_context->Draw(3, 0);
}
@@ -1906,10 +1912,16 @@ void DrawBloom(ID3D11Device* device, ID3D11DeviceContext* device_context, const
device_context->RSSetState(rasterizer_original.get());
// Release com arrays.
- auto release_com_array = [](auto& array){ for (auto* p : array) if (p) p->Release(); };
- release_com_array(rtvs_original);
- release_com_array(rtv_mips_x);
- release_com_array(srv_mips_x);
- release_com_array(rtv_mips_y);
- release_com_array(srv_mips_y);
+ ResetCOMArray(rtvs_original);
+
+ auto reset_mips = [&]()
+ {
+ ResetCOMArray(rtv_mips_x);
+ ResetCOMArray(srv_mips_x);
+ ResetCOMArray(rtv_mips_y);
+ ResetCOMArray(srv_mips_y);
+ };
+
+ LumaCallbacks::on_destroy_device.try_emplace("luma_bloom"_h, reset_mips);
+ LumaCallbacks::on_init_swapchain.try_emplace("luma_bloom"_h, reset_mips);
}
\ No newline at end of file
diff --git a/Source/Games/BioShock Series/main.cpp b/Source/Games/BioShock Series/main.cpp
index 71a61d2e..73df8a82 100644
--- a/Source/Games/BioShock Series/main.cpp
+++ b/Source/Games/BioShock Series/main.cpp
@@ -152,7 +152,6 @@ struct GameDeviceDataBioshockSeries final : public GameDeviceData
com_ptr scene_texture_srv;
ComPtr srv_depth;
- DrawLumaBloomData draw_luma_bloom_data;
ComPtr cb_bloom;
};
@@ -838,7 +837,7 @@ class BioshockSeries final : public Game
native_device_context->PSSetConstantBuffers(0, 1, &game_device_data.cb_bloom);
ComPtr srv_bloom;
- DrawBloom(native_device, native_device_context, device_data, game_device_data.draw_luma_bloom_data, srv_original.get(), g_bloom_nmips, g_bloom_sigmas.data(), srv_bloom.put());
+ DrawBloom(native_device, native_device_context, device_data, srv_original.get(), g_bloom_nmips, g_bloom_sigmas.data(), srv_bloom.put());
native_device_context->PSSetConstantBuffers(0, 1, &cb_original);