Skip to content

Commit b7143c9

Browse files
committed
Fix stencil texture invalidation on RenderPass reset
1 parent 8ef6526 commit b7143c9

3 files changed

Lines changed: 93 additions & 2 deletions

File tree

Modules/Graphics/RHI/Base/Sources/Methane/Graphics/Base/RenderPass.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ bool RenderPass::Update(const Rhi::RenderPassSettings& settings)
5555
m_non_frame_buffer_attachment_textures.clear();
5656
m_color_attachment_textures.clear();
5757
m_depth_attachment_texture_ptr = nullptr;
58+
m_stencil_attachment_texture_ptr = nullptr;
5859
}
5960

6061
InitAttachmentStates();

Tests/Graphics/RHI/RenderPassTest.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Unit-tests of the RHI RenderPass
2828
#include <Methane/Graphics/RHI/RenderPattern.h>
2929
#include <Methane/Graphics/RHI/RenderPass.h>
3030
#include <Methane/Graphics/RHI/ObjectRegistry.h>
31+
#include <Methane/Graphics/Base/RenderPass.h>
32+
#include <Methane/Graphics/Base/Texture.h>
3133

3234
#include <memory>
3335
#include <taskflow/taskflow.hpp>
@@ -132,6 +134,25 @@ TEST_CASE("RHI Render Pass Functions", "[rhi][render][pass]")
132134
CHECK(render_pass.GetSettings() == new_render_pass_resources.settings);
133135
}
134136

137+
SECTION("Update Settings Invalidates Attachment Textures Cache")
138+
{
139+
const auto& base_render_pass = dynamic_cast<const Base::RenderPass&>(render_pass.GetInterface());
140+
141+
// Populate lazily-initialized attachment texture caches with the original attachments
142+
const Base::Texture* orig_color_texture_ptr = &base_render_pass.GetColorAttachmentTextures().front().get();
143+
const Base::Texture* orig_depth_texture_ptr = base_render_pass.GetDepthAttachmentTexture();
144+
CHECK(orig_color_texture_ptr == render_pass_resources.frame_buffer_texture.GetInterfacePtr().get());
145+
CHECK(orig_depth_texture_ptr == render_pass_resources.depth_stencil_texture.GetInterfacePtr().get());
146+
147+
const Test::RenderPassResources new_render_pass_resources = Test::GetRenderPassResources(render_pattern);
148+
CHECK(render_pass.Update(new_render_pass_resources.settings));
149+
150+
CHECK(&base_render_pass.GetColorAttachmentTextures().front().get() ==
151+
new_render_pass_resources.frame_buffer_texture.GetInterfacePtr().get());
152+
CHECK(base_render_pass.GetDepthAttachmentTexture() ==
153+
new_render_pass_resources.depth_stencil_texture.GetInterfacePtr().get());
154+
}
155+
135156
SECTION("Release Attachment Textures")
136157
{
137158
const Rhi::RenderPassSettings& render_pass_settings = render_pass.GetSettings();
@@ -140,3 +161,50 @@ TEST_CASE("RHI Render Pass Functions", "[rhi][render][pass]")
140161
CHECK(render_pass_settings.attachments.empty());
141162
}
142163
}
164+
165+
TEST_CASE("RHI Render Pass with Stencil Attachment Functions", "[rhi][render][pass]")
166+
{
167+
const Rhi::RenderPattern render_pattern = render_context.CreateRenderPattern(Test::GetRenderPatternSettings(true));
168+
const Test::RenderPassResources render_pass_resources = Test::GetRenderPassResources(render_pattern);
169+
const Rhi::RenderPass render_pass = render_pattern.CreateRenderPass(render_pass_resources.settings);
170+
const auto& base_render_pass = dynamic_cast<const Base::RenderPass&>(render_pass.GetInterface());
171+
172+
SECTION("Get Stencil Attachment Texture")
173+
{
174+
REQUIRE(render_pass_resources.stencil_texture.IsInitialized());
175+
CHECK(base_render_pass.GetStencilAttachmentTexture() ==
176+
render_pass_resources.stencil_texture.GetInterfacePtr().get());
177+
}
178+
179+
SECTION("Update Settings Invalidates Stencil Attachment Texture Cache")
180+
{
181+
// Populate the lazily-initialized stencil attachment texture cache with the original attachment
182+
REQUIRE(base_render_pass.GetStencilAttachmentTexture() ==
183+
render_pass_resources.stencil_texture.GetInterfacePtr().get());
184+
185+
const Test::RenderPassResources new_render_pass_resources = Test::GetRenderPassResources(render_pattern);
186+
REQUIRE(new_render_pass_resources.stencil_texture.GetInterfacePtr() !=
187+
render_pass_resources.stencil_texture.GetInterfacePtr());
188+
CHECK(render_pass.Update(new_render_pass_resources.settings));
189+
190+
CHECK(base_render_pass.GetStencilAttachmentTexture() ==
191+
new_render_pass_resources.stencil_texture.GetInterfacePtr().get());
192+
}
193+
194+
SECTION("Update Settings Invalidates Non-Frame-Buffer Attachment Textures Cache")
195+
{
196+
// Frame buffer color attachment is excluded from the non-frame-buffer textures, so only depth & stencil remain
197+
const Ptrs<Base::Texture>& orig_textures = base_render_pass.GetNonFrameBufferAttachmentTextures();
198+
REQUIRE(orig_textures.size() == 2U);
199+
CHECK(orig_textures[0].get() == render_pass_resources.depth_stencil_texture.GetInterfacePtr().get());
200+
CHECK(orig_textures[1].get() == render_pass_resources.stencil_texture.GetInterfacePtr().get());
201+
202+
const Test::RenderPassResources new_render_pass_resources = Test::GetRenderPassResources(render_pattern);
203+
CHECK(render_pass.Update(new_render_pass_resources.settings));
204+
205+
const Ptrs<Base::Texture>& new_textures = base_render_pass.GetNonFrameBufferAttachmentTextures();
206+
REQUIRE(new_textures.size() == 2U);
207+
CHECK(new_textures[0].get() == new_render_pass_resources.depth_stencil_texture.GetInterfacePtr().get());
208+
CHECK(new_textures[1].get() == new_render_pass_resources.stencil_texture.GetInterfacePtr().get());
209+
}
210+
}

Tests/Graphics/RHI/RhiSettings.hpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ inline Rhi::RenderContextSettings GetRenderContextSettings()
4949
};
5050
}
5151

52-
inline Rhi::RenderPatternSettings GetRenderPatternSettings()
52+
inline Rhi::RenderPatternSettings GetRenderPatternSettings(bool with_stencil_attachment = false)
5353
{
5454
return Rhi::RenderPatternSettings
5555
{
@@ -67,7 +67,14 @@ inline Rhi::RenderPatternSettings GetRenderPatternSettings()
6767
Rhi::RenderPassAttachment::StoreAction::Store,
6868
0.F
6969
},
70-
.stencil_attachment = std::nullopt,
70+
.stencil_attachment = with_stencil_attachment
71+
? Opt<Rhi::RenderPassStencilAttachment>(Rhi::RenderPassStencilAttachment{
72+
2U, PixelFormat::Depth32Float, 1U,
73+
Rhi::RenderPassAttachment::LoadAction::Clear,
74+
Rhi::RenderPassAttachment::StoreAction::Store,
75+
0U
76+
})
77+
: std::nullopt,
7178
.shader_access = Rhi::RenderPassAccessMask{ Rhi::RenderPassAccess::ShaderResources },
7279
.is_final_pass = true
7380
};
@@ -77,6 +84,7 @@ struct RenderPassResources
7784
{
7885
Rhi::Texture frame_buffer_texture;
7986
Rhi::Texture depth_stencil_texture;
87+
Rhi::Texture stencil_texture;
8088
Rhi::RenderPassSettings settings;
8189
};
8290

@@ -97,6 +105,20 @@ inline RenderPassResources GetRenderPassResources(const Rhi::RenderPattern& rend
97105
resources.settings.frame_size = frame_size;
98106
resources.settings.attachments.push_back(resources.frame_buffer_texture.GetTextureView());
99107
resources.settings.attachments.push_back(resources.depth_stencil_texture.GetTextureView());
108+
109+
// Separate stencil attachment texture is added only when the render pattern declares a stencil attachment,
110+
// so that its index in the render pass attachments matches RenderPassStencilAttachment::attachment_index.
111+
if (const Opt<Rhi::RenderPassStencilAttachment>& stencil_attachment = render_pattern.GetSettings().stencil_attachment;
112+
stencil_attachment)
113+
{
114+
resources.stencil_texture = render_pattern.GetRenderContext().CreateTexture(
115+
Rhi::TextureSettings::ForDepthStencil(
116+
Dimensions(frame_size),
117+
stencil_attachment->format,
118+
DepthStencilValues(0.f, 0.f),
119+
Rhi::ResourceUsageMask({ Rhi::ResourceUsage::RenderTarget })));
120+
resources.settings.attachments.push_back(resources.stencil_texture.GetTextureView());
121+
}
100122
return resources;
101123
}
102124

0 commit comments

Comments
 (0)