Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 54ad0b6

Browse files
authored
[Impeller] Manage the onscreen stencil in EntityPass (#41563)
Moves onscreen stencil management from the surface to EntityPass for Metal and Vulkan. EntityPass has enough context to set up the stencil optimally. Also forces us to fail loudly when the supplied stencil is set up in a way that can't be used for rendering the pass on GLES. - On Vulkan, when we're blitting, we don't need to set up a onscreen stencil attachment at all. - And on both Vulkan and Metal, the onscreen stencil can be transient when no pass reads are necessary (fixes the benchmark regressions introduced by #41509).
1 parent e116810 commit 54ad0b6

File tree

4 files changed

+68
-76
lines changed

4 files changed

+68
-76
lines changed

impeller/aiks/picture.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,22 @@ std::shared_ptr<Texture> Picture::RenderToTexture(
5656
auto impeller_context = context.GetContext();
5757
RenderTarget target;
5858
if (impeller_context->GetCapabilities()->SupportsOffscreenMSAA()) {
59-
target = RenderTarget::CreateOffscreenMSAA(*impeller_context, size);
59+
target = RenderTarget::CreateOffscreenMSAA(
60+
*impeller_context, // context
61+
size, // size
62+
"Picture Snapshot MSAA", // label
63+
RenderTarget::
64+
kDefaultColorAttachmentConfigMSAA, // color_attachment_config
65+
std::nullopt // stencil_attachment_config
66+
);
6067
} else {
61-
target = RenderTarget::CreateOffscreen(*impeller_context, size);
68+
target = RenderTarget::CreateOffscreen(
69+
*impeller_context, // context
70+
size, // size
71+
"Picture Snapshot", // label
72+
RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config
73+
std::nullopt // stencil_attachment_config
74+
);
6275
}
6376
if (!target.IsValid()) {
6477
VALIDATION_LOG << "Could not create valid RenderTarget.";

impeller/entity/entity_pass.cc

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -214,37 +214,30 @@ uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const {
214214

215215
bool EntityPass::Render(ContentContext& renderer,
216216
const RenderTarget& render_target) const {
217-
if (render_target.GetColorAttachments().empty()) {
218-
VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
219-
return false;
220-
}
221-
222-
if (!render_target.GetStencilAttachment().has_value()) {
223-
VALIDATION_LOG << "The root RenderTarget must have a stencil attachment.";
224-
return false;
225-
}
217+
auto root_render_target = render_target;
226218

227-
auto stencil_texture = render_target.GetStencilAttachment()->texture;
228-
if (!stencil_texture) {
229-
VALIDATION_LOG << "The root RenderTarget must have a stencil texture.";
219+
if (root_render_target.GetColorAttachments().empty()) {
220+
VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
230221
return false;
231222
}
232223

233224
StencilCoverageStack stencil_coverage_stack = {StencilCoverageLayer{
234-
.coverage = Rect::MakeSize(render_target.GetRenderTargetSize()),
225+
.coverage = Rect::MakeSize(root_render_target.GetRenderTargetSize()),
235226
.stencil_depth = 0}};
236227

237-
bool supports_root_pass_reads =
228+
bool supports_onscreen_backdrop_reads =
238229
renderer.GetDeviceCapabilities().SupportsReadFromOnscreenTexture() &&
239230
// If the backend doesn't have `SupportsReadFromResolve`, we need to flip
240231
// between two textures when restoring a previous MSAA pass.
241-
renderer.GetDeviceCapabilities().SupportsReadFromResolve() &&
242-
stencil_texture->GetTextureDescriptor().storage_mode !=
243-
StorageMode::kDeviceTransient;
244-
if (!supports_root_pass_reads && GetTotalPassReads(renderer) > 0) {
232+
renderer.GetDeviceCapabilities().SupportsReadFromResolve();
233+
bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
234+
// In this branch path, we need to render everything to an offscreen texture
235+
// and then blit the results onto the onscreen texture. If using this branch,
236+
// there's no need to set up a stencil attachment on the root render target.
237+
if (!supports_onscreen_backdrop_reads && reads_from_onscreen_backdrop) {
245238
auto offscreen_target =
246-
CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true,
247-
clear_color_.Premultiply());
239+
CreateRenderTarget(renderer, root_render_target.GetRenderTargetSize(),
240+
true, clear_color_.Premultiply());
248241

249242
if (!OnRender(renderer, // renderer
250243
offscreen_target.GetRenderTarget()
@@ -263,22 +256,25 @@ bool EntityPass::Render(ContentContext& renderer,
263256
auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
264257
command_buffer->SetLabel("EntityPass Root Command Buffer");
265258

259+
// If the context supports blitting, blit the offscreen texture to the
260+
// onscreen texture. Otherwise, draw it to the parent texture using a
261+
// pipeline (slower).
266262
if (renderer.GetContext()
267263
->GetCapabilities()
268264
->SupportsTextureToTextureBlits()) {
269265
auto blit_pass = command_buffer->CreateBlitPass();
270266

271267
blit_pass->AddCopy(
272268
offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
273-
render_target.GetRenderTargetTexture());
269+
root_render_target.GetRenderTargetTexture());
274270

275271
if (!blit_pass->EncodeCommands(
276272
renderer.GetContext()->GetResourceAllocator())) {
277273
VALIDATION_LOG << "Failed to encode root pass blit command.";
278274
return false;
279275
}
280276
} else {
281-
auto render_pass = command_buffer->CreateRenderPass(render_target);
277+
auto render_pass = command_buffer->CreateRenderPass(root_render_target);
282278
render_pass->SetLabel("EntityPass Root Render Pass");
283279

284280
{
@@ -309,11 +305,43 @@ bool EntityPass::Render(ContentContext& renderer,
309305
return true;
310306
}
311307

308+
// If we make it this far, that means the context is capable of rendering
309+
// everything directly to the onscreen texture.
310+
311+
// The safety check for fetching this color attachment is at the beginning of
312+
// this method.
313+
auto color0 = root_render_target.GetColorAttachments().find(0)->second;
314+
315+
// If a root stencil was provided by the caller, then verify that it has a
316+
// configuration which can be used to render this pass.
317+
if (root_render_target.GetStencilAttachment().has_value()) {
318+
auto stencil_texture = root_render_target.GetStencilAttachment()->texture;
319+
if (!stencil_texture) {
320+
VALIDATION_LOG << "The root RenderTarget must have a stencil texture.";
321+
return false;
322+
}
323+
324+
auto stencil_storage_mode =
325+
stencil_texture->GetTextureDescriptor().storage_mode;
326+
if (reads_from_onscreen_backdrop &&
327+
stencil_storage_mode == StorageMode::kDeviceTransient) {
328+
VALIDATION_LOG << "The given root RenderTarget stencil needs to be read, "
329+
"but it's marked as transient.";
330+
return false;
331+
}
332+
}
333+
// Setup a new root stencil with an optimal configuration if one wasn't
334+
// provided by the caller.
335+
else {
336+
root_render_target.SetupStencilAttachment(
337+
*renderer.GetContext(), color0.texture->GetSize(),
338+
renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
339+
"ImpellerOnscreen",
340+
GetDefaultStencilConfig(reads_from_onscreen_backdrop));
341+
}
342+
312343
// Set up the clear color of the root pass.
313-
auto color0 = render_target.GetColorAttachments().find(0)->second;
314344
color0.clear_color = clear_color_.Premultiply();
315-
316-
auto root_render_target = render_target;
317345
root_render_target.SetColorAttachment(color0, 0);
318346

319347
EntityPassTarget pass_target(

impeller/renderer/backend/metal/surface_mtl.mm

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,33 +108,8 @@
108108
color0.store_action = StoreAction::kMultisampleResolve;
109109
color0.resolve_texture = resolve_tex;
110110

111-
TextureDescriptor stencil_tex_desc;
112-
stencil_tex_desc.storage_mode = StorageMode::kDevicePrivate;
113-
stencil_tex_desc.type = TextureType::kTexture2DMultisample;
114-
stencil_tex_desc.sample_count = SampleCount::kCount4;
115-
stencil_tex_desc.format =
116-
context->GetCapabilities()->GetDefaultStencilFormat();
117-
stencil_tex_desc.size = msaa_tex_desc.size;
118-
stencil_tex_desc.usage =
119-
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
120-
auto stencil_tex =
121-
context->GetResourceAllocator()->CreateTexture(stencil_tex_desc);
122-
123-
if (!stencil_tex) {
124-
VALIDATION_LOG << "Could not create stencil texture.";
125-
return nullptr;
126-
}
127-
stencil_tex->SetLabel("ImpellerOnscreenStencil");
128-
129-
StencilAttachment stencil0;
130-
stencil0.texture = stencil_tex;
131-
stencil0.clear_stencil = 0;
132-
stencil0.load_action = LoadAction::kClear;
133-
stencil0.store_action = StoreAction::kDontCare;
134-
135111
RenderTarget render_target_desc;
136112
render_target_desc.SetColorAttachment(color0, 0u);
137-
render_target_desc.SetStencilAttachment(stencil0);
138113

139114
// The constructor is private. So make_unique may not be used.
140115
return std::unique_ptr<SurfaceMTL>(

impeller/renderer/backend/vulkan/surface_vk.cc

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,32 +60,8 @@ std::unique_ptr<SurfaceVK> SurfaceVK::WrapSwapchainImage(
6060
color0.store_action = StoreAction::kMultisampleResolve;
6161
color0.resolve_texture = resolve_tex;
6262

63-
TextureDescriptor stencil0_tex;
64-
stencil0_tex.storage_mode = StorageMode::kDevicePrivate;
65-
stencil0_tex.type = TextureType::kTexture2DMultisample;
66-
stencil0_tex.sample_count = SampleCount::kCount4;
67-
stencil0_tex.format = context->GetCapabilities()->GetDefaultStencilFormat();
68-
stencil0_tex.size = msaa_tex_desc.size;
69-
stencil0_tex.usage =
70-
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
71-
72-
auto stencil_tex =
73-
context->GetResourceAllocator()->CreateTexture(stencil0_tex);
74-
if (!stencil_tex) {
75-
VALIDATION_LOG << "Could not create stencil texture.";
76-
return nullptr;
77-
}
78-
stencil_tex->SetLabel("ImpellerOnscreenStencil");
79-
80-
StencilAttachment stencil0;
81-
stencil0.texture = stencil_tex;
82-
stencil0.clear_stencil = 0;
83-
stencil0.load_action = LoadAction::kClear;
84-
stencil0.store_action = StoreAction::kDontCare;
85-
8663
RenderTarget render_target_desc;
8764
render_target_desc.SetColorAttachment(color0, 0u);
88-
render_target_desc.SetStencilAttachment(stencil0);
8965

9066
// The constructor is private. So make_unique may not be used.
9167
return std::unique_ptr<SurfaceVK>(

0 commit comments

Comments
 (0)