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);