Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
render_target.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <format>
8#include <sstream>
9
16
17namespace impeller {
18
19// The dimensions of `texture` at `mip_level`, clamped to a minimum of 1x1.
20// Rendering into a mip level uses that level's size, not the base size.
21static ISize SizeForMipLevel(const std::shared_ptr<Texture>& texture,
22 uint32_t mip_level) {
23 ISize size = texture->GetSize();
24 // Any real texture reaches 1x1 well before this; clamping the shift also
25 // avoids undefined behavior for absurd mip levels.
26 uint32_t shift = std::min(mip_level, 31u);
27 return ISize{std::max<int64_t>(1, size.width >> shift),
28 std::max<int64_t>(1, size.height >> shift)};
29}
30
32
34
36 // Validate that there is a color attachment at zero index.
37 if (!HasColorAttachment(0u)) {
39 << "Render target does not have color attachment at index 0.";
40 return false;
41 }
42
43#ifndef NDEBUG
44 // Validate that all attachments are of the same size.
45 {
46 std::optional<ISize> size;
47 bool sizes_are_same = true;
48 auto iterator = [&](const Attachment& attachment) -> bool {
49 ISize attachment_size =
50 SizeForMipLevel(attachment.texture, attachment.mip_level);
51 if (!size.has_value()) {
52 size = attachment_size;
53 }
54 if (size != attachment_size) {
55 sizes_are_same = false;
56 return false;
57 }
58 return true;
59 };
60 IterateAllAttachments(iterator);
61 if (!sizes_are_same) {
63 << "Sizes of all render target attachments are not the same.";
64 return false;
65 }
66 }
67
68 // Validate that all attachments are of the same type and sample counts.
69 {
70 std::optional<TextureType> texture_type;
71 std::optional<SampleCount> sample_count;
72 bool passes_type_validation = true;
73 auto iterator = [&](const Attachment& attachment) -> bool {
74 if (!texture_type.has_value() || !sample_count.has_value()) {
75 texture_type = attachment.texture->GetTextureDescriptor().type;
76 sample_count = attachment.texture->GetTextureDescriptor().sample_count;
77 }
78
79 if (texture_type != attachment.texture->GetTextureDescriptor().type) {
80 passes_type_validation = false;
81 VALIDATION_LOG << "Render target has incompatible texture types: "
82 << TextureTypeToString(texture_type.value()) << " != "
84 attachment.texture->GetTextureDescriptor().type)
85 << " on target " << ToString();
86 return false;
87 }
88
89 if (sample_count !=
90 attachment.texture->GetTextureDescriptor().sample_count) {
91 passes_type_validation = false;
92 VALIDATION_LOG << "Render target (" << ToString()
93 << ") has incompatible sample counts.";
94
95 return false;
96 }
97
98 return true;
99 };
100 IterateAllAttachments(iterator);
101 if (!passes_type_validation) {
102 return false;
103 }
104 }
105#endif // NDEBUG
106
107 return true;
108}
109
111 const std::function<bool(size_t index, const ColorAttachment& attachment)>&
112 iterator) const {
113 if (color0_.has_value()) {
114 if (!iterator(0, color0_.value())) {
115 return false;
116 }
117 }
118 for (const auto& [index, attachment] : colors_) {
119 if (!iterator(index, attachment)) {
120 return false;
121 }
122 }
123 return true;
124}
125
127 const std::function<bool(const Attachment& attachment)>& iterator) const {
128 if (color0_.has_value()) {
129 if (!iterator(color0_.value())) {
130 return;
131 }
132 }
133 for (const auto& color : colors_) {
134 if (!iterator(color.second)) {
135 return;
136 }
137 }
138
139 if (depth_.has_value()) {
140 if (!iterator(depth_.value())) {
141 return;
142 }
143 }
144
145 if (stencil_.has_value()) {
146 if (!iterator(stencil_.value())) {
147 return;
148 }
149 }
150}
151
153 if (color0_.has_value()) {
154 return color0_.value().texture->GetTextureDescriptor().sample_count;
155 }
157}
158
159bool RenderTarget::HasColorAttachment(size_t index) const {
160 if (index == 0u) {
161 return color0_.has_value();
162 }
163 if (auto found = colors_.find(index); found != colors_.end()) {
164 return true;
165 }
166 return false;
167}
168
169std::optional<ISize> RenderTarget::GetColorAttachmentSize(size_t index) const {
170 if (index == 0u) {
171 if (color0_.has_value()) {
172 return SizeForMipLevel(color0_.value().texture,
173 color0_.value().mip_level);
174 }
175 return std::nullopt;
176 }
177 auto found = colors_.find(index);
178
179 if (found == colors_.end()) {
180 return std::nullopt;
181 }
182
183 return SizeForMipLevel(found->second.texture, found->second.mip_level);
184}
185
187 auto size = GetColorAttachmentSize(0u);
188 return size.has_value() ? size.value() : ISize{};
189}
190
191std::shared_ptr<Texture> RenderTarget::GetRenderTargetTexture() const {
192 if (!color0_.has_value()) {
193 return nullptr;
194 }
195 return color0_->resolve_texture ? color0_->resolve_texture : color0_->texture;
196}
197
199 if (auto texture = GetRenderTargetTexture(); texture != nullptr) {
200 return texture->GetTextureDescriptor().format;
201 }
202
204}
205
207 size_t max = 0;
208 for (const auto& color : colors_) {
209 max = std::max(color.first, max);
210 }
211 return max;
212}
213
215 const ColorAttachment& attachment,
216 size_t index) {
217 if (!attachment.IsValid()) {
218 return *this;
219 }
220 if (index == 0u) {
221 color0_ = attachment;
222 } else {
223 colors_[index] = attachment;
224 }
225 return *this;
226}
227
229 std::optional<DepthAttachment> attachment) {
230 if (!attachment.has_value()) {
231 depth_ = std::nullopt;
232 } else if (attachment->IsValid()) {
233 depth_ = std::move(attachment);
234 }
235 return *this;
236}
237
239 std::optional<StencilAttachment> attachment) {
240 if (!attachment.has_value()) {
241 stencil_ = std::nullopt;
242 } else if (attachment->IsValid()) {
243 stencil_ = std::move(attachment);
244 }
245 return *this;
246}
247
249 if (index == 0) {
250 if (color0_.has_value()) {
251 return color0_.value();
252 }
253 return ColorAttachment{};
254 }
255 std::map<size_t, ColorAttachment>::const_iterator it = colors_.find(index);
256 if (it != colors_.end()) {
257 return it->second;
258 }
259 return ColorAttachment{};
260}
261
262const std::optional<DepthAttachment>& RenderTarget::GetDepthAttachment() const {
263 return depth_;
264}
265
266const std::optional<StencilAttachment>& RenderTarget::GetStencilAttachment()
267 const {
268 return stencil_;
269}
270
272 size_t count = 0u;
273 for (const auto& [_, color] : colors_) {
274 if (color.texture) {
275 count++;
276 }
277 if (color.resolve_texture) {
278 count++;
279 }
280 }
281 if (color0_.has_value()) {
282 count++;
283 }
284 if (depth_.has_value()) {
285 count++;
286 }
287 if (stencil_.has_value()) {
288 count++;
289 }
290 return count;
291}
292
293std::string RenderTarget::ToString() const {
294 std::stringstream stream;
295
296 if (color0_.has_value()) {
297 stream << std::format("Color[{}]=({})", 0,
298 ColorAttachmentToString(color0_.value()));
299 }
300 for (const auto& [index, color] : colors_) {
301 stream << std::format("Color[{}]=({})", index,
303 }
304 if (depth_) {
305 stream << ",";
306 stream << std::format("Depth=({})",
307 DepthAttachmentToString(depth_.value()));
308 }
309 if (stencil_) {
310 stream << ",";
311 stream << std::format("Stencil=({})",
312 StencilAttachmentToString(stencil_.value()));
313 }
314 return stream.str();
315}
316
318 if (!color0_.has_value()) {
319 return RenderTargetConfig{};
320 }
321 const auto& color_attachment = color0_.value();
322 return RenderTargetConfig{
323 .size = color_attachment.texture->GetSize(),
324 .mip_count = color_attachment.texture->GetMipCount(),
325 .has_msaa = color_attachment.resolve_texture != nullptr,
326 .has_depth_stencil = depth_.has_value() && stencil_.has_value()};
327}
328
330 std::shared_ptr<Allocator> allocator)
331 : allocator_(std::move(allocator)) {}
332
334
336
338 const Context& context,
339 ISize size,
340 int mip_count,
341 std::string_view label,
342 RenderTarget::AttachmentConfig color_attachment_config,
343 std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config,
344 const std::shared_ptr<Texture>& existing_color_texture,
345 const std::shared_ptr<Texture>& existing_depth_stencil_texture,
346 std::optional<PixelFormat> target_pixel_format) {
347 if (size.IsEmpty()) {
348 return {};
349 }
350
352
353 std::shared_ptr<Texture> color0_tex;
354 if (existing_color_texture) {
355 color0_tex = existing_color_texture;
356 } else {
357 TextureDescriptor color0_tex_desc;
358 color0_tex_desc.storage_mode = color_attachment_config.storage_mode;
359 color0_tex_desc.format =
360 target_pixel_format.has_value()
361 ? target_pixel_format.value()
362 : context.GetCapabilities()->GetDefaultColorFormat();
363 color0_tex_desc.size = size;
364 color0_tex_desc.mip_count = mip_count;
365 color0_tex_desc.usage =
367 color0_tex = allocator_->CreateTexture(color0_tex_desc);
368 if (!color0_tex) {
369 return {};
370 }
371 }
372 color0_tex->SetLabel(label, "Color Texture");
373
374 ColorAttachment color0;
375 color0.clear_color = color_attachment_config.clear_color;
376 color0.load_action = color_attachment_config.load_action;
377 color0.store_action = color_attachment_config.store_action;
378 color0.texture = color0_tex;
379 target.SetColorAttachment(color0, 0u);
380
381 if (stencil_attachment_config.has_value()) {
382 target.SetupDepthStencilAttachments(
383 context, *allocator_, size, false, label,
384 stencil_attachment_config.value(), existing_depth_stencil_texture);
385 } else {
386 target.SetStencilAttachment(std::nullopt);
387 target.SetDepthAttachment(std::nullopt);
388 }
389
390 return target;
391}
392
394 const Context& context,
395 ISize size,
396 int mip_count,
397 std::string_view label,
398 RenderTarget::AttachmentConfigMSAA color_attachment_config,
399 std::optional<RenderTarget::AttachmentConfig> stencil_attachment_config,
400 const std::shared_ptr<Texture>& existing_color_msaa_texture,
401 const std::shared_ptr<Texture>& existing_color_resolve_texture,
402 const std::shared_ptr<Texture>& existing_depth_stencil_texture,
403 std::optional<PixelFormat> target_pixel_format) {
404 if (size.IsEmpty()) {
405 return {};
406 }
407
409 PixelFormat pixel_format =
410 target_pixel_format.has_value()
411 ? target_pixel_format.value()
412 : context.GetCapabilities()->GetDefaultColorFormat();
413
414 // Create MSAA color texture.
415 std::shared_ptr<Texture> color0_msaa_tex;
416 if (existing_color_msaa_texture) {
417 color0_msaa_tex = existing_color_msaa_texture;
418 } else {
419 TextureDescriptor color0_tex_desc;
420 color0_tex_desc.storage_mode = color_attachment_config.storage_mode;
422 color0_tex_desc.sample_count = SampleCount::kCount4;
423 color0_tex_desc.format = pixel_format;
424 color0_tex_desc.size = size;
425 color0_tex_desc.usage = TextureUsage::kRenderTarget;
426 if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
427 // See below ("SupportsImplicitResolvingMSAA") for more details.
429 }
430 color0_msaa_tex = allocator_->CreateTexture(color0_tex_desc);
431 if (!color0_msaa_tex) {
432 VALIDATION_LOG << "Could not create multisample color texture.";
433 return {};
434 }
435 }
436 color0_msaa_tex->SetLabel(label, "Color Texture (Multisample)");
437
438 // Create color resolve texture.
439 std::shared_ptr<Texture> color0_resolve_tex;
440 if (existing_color_resolve_texture) {
441 color0_resolve_tex = existing_color_resolve_texture;
442 } else {
443 TextureDescriptor color0_resolve_tex_desc;
444 color0_resolve_tex_desc.storage_mode =
445 color_attachment_config.resolve_storage_mode;
446 color0_resolve_tex_desc.format = pixel_format;
447 color0_resolve_tex_desc.size = size;
448 color0_resolve_tex_desc.compression_type = CompressionType::kLossy;
449 color0_resolve_tex_desc.usage =
451 color0_resolve_tex_desc.mip_count = mip_count;
452 color0_resolve_tex = allocator_->CreateTexture(color0_resolve_tex_desc);
453 if (!color0_resolve_tex) {
454 VALIDATION_LOG << "Could not create color texture.";
455 return {};
456 }
457 }
458 color0_resolve_tex->SetLabel(label, "Color Texture");
459
460 // Color attachment.
461
462 ColorAttachment color0;
463 color0.clear_color = color_attachment_config.clear_color;
464 color0.load_action = color_attachment_config.load_action;
465 color0.store_action = color_attachment_config.store_action;
466 color0.texture = color0_msaa_tex;
467 color0.resolve_texture = color0_resolve_tex;
468
469 if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
470 // If implicit MSAA is supported, then the resolve texture is not needed
471 // because the multisample texture is automatically resolved. We instead
472 // provide a view of the multisample texture as the resolve texture (because
473 // the HAL does expect a resolve texture).
474 //
475 // In practice, this is used for GLES 2.0 EXT_multisampled_render_to_texture
476 // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
477 color0.resolve_texture = color0_msaa_tex;
478 }
479
480 target.SetColorAttachment(color0, 0u);
481
482 // Create MSAA stencil texture.
483
484 if (stencil_attachment_config.has_value()) {
485 target.SetupDepthStencilAttachments(context, *allocator_, size, true, label,
486 stencil_attachment_config.value(),
487 existing_depth_stencil_texture);
488 } else {
489 target.SetDepthAttachment(std::nullopt);
490 target.SetStencilAttachment(std::nullopt);
491 }
492
493 return target;
494}
495
497 const Context& context,
499 ISize size,
500 bool msaa,
501 std::string_view label,
502 RenderTarget::AttachmentConfig stencil_attachment_config,
503 const std::shared_ptr<Texture>& existing_depth_stencil_texture) {
504 std::shared_ptr<Texture> depth_stencil_texture;
505 if (existing_depth_stencil_texture) {
506 depth_stencil_texture = existing_depth_stencil_texture;
507 } else {
508 TextureDescriptor depth_stencil_texture_desc;
509 depth_stencil_texture_desc.storage_mode =
510 stencil_attachment_config.storage_mode;
511 if (msaa) {
512 depth_stencil_texture_desc.type = TextureType::kTexture2DMultisample;
513 depth_stencil_texture_desc.sample_count = SampleCount::kCount4;
514 }
515 depth_stencil_texture_desc.format =
516 context.GetCapabilities()->GetDefaultDepthStencilFormat();
517 depth_stencil_texture_desc.size = size;
518 depth_stencil_texture_desc.usage = TextureUsage::kRenderTarget;
519 depth_stencil_texture = allocator.CreateTexture(depth_stencil_texture_desc);
520 if (!depth_stencil_texture) {
521 return; // Error messages are handled by `Allocator::CreateTexture`.
522 }
523 }
524
525 DepthAttachment depth0;
526 depth0.load_action = stencil_attachment_config.load_action;
527 depth0.store_action = stencil_attachment_config.store_action;
528 depth0.clear_depth = 0u;
529 depth0.texture = depth_stencil_texture;
530
531 StencilAttachment stencil0;
532 stencil0.load_action = stencil_attachment_config.load_action;
533 stencil0.store_action = stencil_attachment_config.store_action;
534 stencil0.clear_stencil = 0u;
535 stencil0.texture = std::move(depth_stencil_texture);
536 stencil0.texture->SetLabel(label, "Depth+Stencil Texture");
537
538 SetDepthAttachment(std::move(depth0));
539 SetStencilAttachment(std::move(stencil0));
540}
541
542} // namespace impeller
An object that allocates device memory.
Definition allocator.h:24
To do anything rendering related with Impeller, you need a context.
Definition context.h:69
RenderTargetAllocator(std::shared_ptr< Allocator > allocator)
virtual RenderTarget CreateOffscreenMSAA(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config=RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_msaa_texture=nullptr, const std::shared_ptr< Texture > &existing_color_resolve_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
virtual RenderTarget CreateOffscreen(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen", RenderTarget::AttachmentConfig color_attachment_config=RenderTarget::kDefaultColorAttachmentConfig, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
virtual void Start()
Mark the beginning of a frame workload.
virtual void End()
Mark the end of a frame workload.
ColorAttachment GetColorAttachment(size_t index) const
Get the color attachment at [index].
std::shared_ptr< Texture > GetRenderTargetTexture() const
SampleCount GetSampleCount() const
void IterateAllAttachments(const std::function< bool(const Attachment &attachment)> &iterator) const
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
bool HasColorAttachment(size_t index) const
std::string ToString() const
RenderTarget & SetDepthAttachment(std::optional< DepthAttachment > attachment)
size_t GetMaxColorAttachmentBindIndex() const
PixelFormat GetRenderTargetPixelFormat() const
size_t GetTotalAttachmentCount() const
ISize GetRenderTargetSize() const
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
bool IterateAllColorAttachments(const std::function< bool(size_t index, const ColorAttachment &attachment)> &iterator) const
std::optional< ISize > GetColorAttachmentSize(size_t index) const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
void SetupDepthStencilAttachments(const Context &context, Allocator &allocator, ISize size, bool msaa, std::string_view label="Offscreen", RenderTarget::AttachmentConfig stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &depth_stencil_texture=nullptr)
RenderTargetConfig ToConfig() const
uint32_t * target
std::shared_ptr< ImpellerAllocator > allocator
FlTexture * texture
std::string DepthAttachmentToString(const DepthAttachment &depth)
Definition formats.cc:144
std::string ColorAttachmentToString(const ColorAttachment &color)
Definition formats.cc:137
std::string StencilAttachmentToString(const StencilAttachment &stencil)
Definition formats.cc:151
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition formats.h:99
static ISize SizeForMipLevel(const std::shared_ptr< Texture > &texture, uint32_t mip_level)
constexpr const char * TextureTypeToString(TextureType type)
Definition formats.h:457
Definition ref_ptr.h:261
std::shared_ptr< ContextGLES > context
std::shared_ptr< Texture > resolve_texture
Definition formats.h:910
bool IsValid() const
Definition formats.cc:26
LoadAction load_action
Definition formats.h:911
std::shared_ptr< Texture > texture
Definition formats.h:909
StoreAction store_action
Definition formats.h:912
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define VALIDATION_LOG
Definition validation.h:91