| Flutter Impeller |

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
5 #include "impeller/renderer/render_target.h"
6
7 #include <sstream>
8
9 #include "impeller/base/strings.h"
10 #include "impeller/base/validation.h"
11 #include "impeller/core/allocator.h"
12 #include "impeller/core/texture.h"
13 #include "impeller/renderer/context.h"
14
15 namespace impeller {
16
17 RenderTargetAllocator::RenderTargetAllocator(
18 std::shared_ptr<Allocator> allocator)
19 : allocator_(std::move(allocator)) {}
20
21 void RenderTargetAllocator::Start() {}
22
23 void RenderTargetAllocator::End() {}
24
25 std::shared_ptr<Texture> RenderTargetAllocator::CreateTexture(
26 const TextureDescriptor& desc) {
27 return allocator_->CreateTexture(desc);
28 }
29
30 RenderTarget::RenderTarget() = default;
31
32 RenderTarget::~RenderTarget() = default;
33
34 bool RenderTarget::IsValid() const {
35 // Validate that there is a color attachment at zero index.
36 if (!HasColorAttachment(0u)) {
37 VALIDATION_LOG
38 << "Render target does not have color attachment at index 0.";
39 return false;
40 }
41
42 // Validate that all attachments are of the same size.
43 {
44 std::optional<ISize> size;
45 bool sizes_are_same = true;
46 auto iterator = [&](const Attachment& attachment) -> bool {
47 if (!size.has_value()) {
48 size = attachment.texture->GetSize();
49 }
50 if (size != attachment.texture->GetSize()) {
51 sizes_are_same = false;
52 return false;
53 }
54 return true;
55 };
56 IterateAllAttachments(iterator);
57 if (!sizes_are_same) {
58 VALIDATION_LOG
59 << "Sizes of all render target attachments are not the same.";
60 return false;
61 }
62 }
63
64 // Validate that all attachments are of the same type and sample counts.
65 {
66 std::optional<TextureType> texture_type;
67 std::optional<SampleCount> sample_count;
68 bool passes_type_validation = true;
69 auto iterator = [&](const Attachment& attachment) -> bool {
70 if (!texture_type.has_value() || !sample_count.has_value()) {
71 texture_type = attachment.texture->GetTextureDescriptor().type;
72 sample_count = attachment.texture->GetTextureDescriptor().sample_count;
73 }
74
75 if (texture_type != attachment.texture->GetTextureDescriptor().type) {
76 passes_type_validation = false;
77 VALIDATION_LOG << "Render target has incompatible texture types: "
78 << TextureTypeToString(texture_type.value()) << " != "
79 << TextureTypeToString(
80 attachment.texture->GetTextureDescriptor().type)
81 << " on target " << ToString();
82 return false;
83 }
84
85 if (sample_count !=
86 attachment.texture->GetTextureDescriptor().sample_count) {
87 passes_type_validation = false;
88 VALIDATION_LOG << "Render target (" << ToString()
89 << ") has incompatible sample counts.";
90
91 return false;
92 }
93
94 return true;
95 };
96 IterateAllAttachments(iterator);
97 if (!passes_type_validation) {
98 return false;
99 }
100 }
101
102 return true;
103 }
104
105 void RenderTarget::IterateAllAttachments(
106 const std::function<bool(const Attachment& attachment)>& iterator) const {
107 for (const auto& color : colors_) {
108 if (!iterator(color.second)) {
109 return;
110 }
111 }
112
113 if (depth_.has_value()) {
114 if (!iterator(depth_.value())) {
115 return;
116 }
117 }
118
119 if (stencil_.has_value()) {
120 if (!iterator(stencil_.value())) {
121 return;
122 }
123 }
124 }
125
126 SampleCount RenderTarget::GetSampleCount() const {
127 if (auto found = colors_.find(0u); found != colors_.end()) {
128 return found->second.texture->GetTextureDescriptor().sample_count;
129 }
130 return SampleCount::kCount1;
131 }
132
133 bool RenderTarget::HasColorAttachment(size_t index) const {
134 if (auto found = colors_.find(index); found != colors_.end()) {
135 return true;
136 }
137 return false;
138 }
139
140 std::optional<ISize> RenderTarget::GetColorAttachmentSize(size_t index) const {
141 auto found = colors_.find(index);
142
143 if (found == colors_.end()) {
144 return std::nullopt;
145 }
146
147 return found->second.texture->GetSize();
148 }
149
150 ISize RenderTarget::GetRenderTargetSize() const {
151 auto size = GetColorAttachmentSize(0u);
152 return size.has_value() ? size.value() : ISize{};
153 }
154
155 std::shared_ptr<Texture> RenderTarget::GetRenderTargetTexture() const {
156 auto found = colors_.find(0u);
157 if (found == colors_.end()) {
158 return nullptr;
159 }
160 return found->second.resolve_texture ? found->second.resolve_texture
161 : found->second.texture;
162 }
163
164 PixelFormat RenderTarget::GetRenderTargetPixelFormat() const {
165 if (auto texture = GetRenderTargetTexture(); texture != nullptr) {
166 return texture->GetTextureDescriptor().format;
167 }
168
169 return PixelFormat::kUnknown;
170 }
171
172 size_t RenderTarget::GetMaxColorAttacmentBindIndex() const {
173 size_t max = 0;
174 for (const auto& color : colors_) {
175 max = std::max(color.first, max);
176 }
177 return max;
178 }
179
180 RenderTarget& RenderTarget::SetColorAttachment(
181 const ColorAttachment& attachment,
182 size_t index) {
183 if (attachment.IsValid()) {
184 colors_[index] = attachment;
185 }
186 return *this;
187 }
188
189 RenderTarget& RenderTarget::SetDepthAttachment(
190 std::optional<DepthAttachment> attachment) {
191 if (!attachment.has_value()) {
192 depth_ = std::nullopt;
193 } else if (attachment->IsValid()) {
194 depth_ = std::move(attachment);
195 }
196 return *this;
197 }
198
199 RenderTarget& RenderTarget::SetStencilAttachment(
200 std::optional<StencilAttachment> attachment) {
201 if (!attachment.has_value()) {
202 stencil_ = std::nullopt;
203 } else if (attachment->IsValid()) {
204 stencil_ = std::move(attachment);
205 }
206 return *this;
207 }
208
209 const std::map<size_t, ColorAttachment>& RenderTarget::GetColorAttachments()
210 const {
211 return colors_;
212 }
213
214 const std::optional<DepthAttachment>& RenderTarget::GetDepthAttachment() const {
215 return depth_;
216 }
217
218 const std::optional<StencilAttachment>& RenderTarget::GetStencilAttachment()
219 const {
220 return stencil_;
221 }
222
223 RenderTarget RenderTarget::CreateOffscreen(
224 const Context& context,
225 RenderTargetAllocator& allocator,
226 ISize size,
227 const std::string& label,
228 AttachmentConfig color_attachment_config,
229 std::optional<AttachmentConfig> stencil_attachment_config) {
230 if (size.IsEmpty()) {
231 return {};
232 }
233
234 RenderTarget target;
235 PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat();
236 TextureDescriptor color_tex0;
237 color_tex0.storage_mode = color_attachment_config.storage_mode;
238 color_tex0.format = pixel_format;
239 color_tex0.size = size;
240 color_tex0.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget) |
241 static_cast<uint64_t>(TextureUsage::kShaderRead);
242
243 ColorAttachment color0;
244 color0.clear_color = color_attachment_config.clear_color;
245 color0.load_action = color_attachment_config.load_action;
246 color0.store_action = color_attachment_config.store_action;
247 color0.texture = allocator.CreateTexture(color_tex0);
248
249 if (!color0.texture) {
250 return {};
251 }
252 color0.texture->SetLabel(SPrintF("%s Color Texture", label.c_str()));
253 target.SetColorAttachment(color0, 0u);
254
255 if (stencil_attachment_config.has_value()) {
256 target.SetupStencilAttachment(context, allocator, size, false, label,
257 stencil_attachment_config.value());
258 } else {
259 target.SetStencilAttachment(std::nullopt);
260 }
261
262 return target;
263 }
264
265 RenderTarget RenderTarget::CreateOffscreenMSAA(
266 const Context& context,
267 RenderTargetAllocator& allocator,
268 ISize size,
269 const std::string& label,
270 AttachmentConfigMSAA color_attachment_config,
271 std::optional<AttachmentConfig> stencil_attachment_config) {
272 if (size.IsEmpty()) {
273 return {};
274 }
275
276 RenderTarget target;
277 PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat();
278
279 // Create MSAA color texture.
280
281 TextureDescriptor color0_tex_desc;
282 color0_tex_desc.storage_mode = color_attachment_config.storage_mode;
283 color0_tex_desc.type = TextureType::kTexture2DMultisample;
284 color0_tex_desc.sample_count = SampleCount::kCount4;
285 color0_tex_desc.format = pixel_format;
286 color0_tex_desc.size = size;
287 color0_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
288
289 if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
290 // See below ("SupportsImplicitResolvingMSAA") for more details.
291 color0_tex_desc.storage_mode = StorageMode::kDevicePrivate;
292 }
293
294 auto color0_msaa_tex = allocator.CreateTexture(color0_tex_desc);
295 if (!color0_msaa_tex) {
296 VALIDATION_LOG << "Could not create multisample color texture.";
297 return {};
298 }
299 color0_msaa_tex->SetLabel(
300 SPrintF("%s Color Texture (Multisample)", label.c_str()));
301
302 // Create color resolve texture.
303
304 TextureDescriptor color0_resolve_tex_desc;
305 color0_resolve_tex_desc.storage_mode =
306 color_attachment_config.resolve_storage_mode;
307 color0_resolve_tex_desc.format = pixel_format;
308 color0_resolve_tex_desc.size = size;
309 color0_resolve_tex_desc.compression_type = CompressionType::kLossy;
310 color0_resolve_tex_desc.usage =
311 static_cast<uint64_t>(TextureUsage::kRenderTarget) |
312 static_cast<uint64_t>(TextureUsage::kShaderRead);
313
314 auto color0_resolve_tex = allocator.CreateTexture(color0_resolve_tex_desc);
315 if (!color0_resolve_tex) {
316 VALIDATION_LOG << "Could not create color texture.";
317 return {};
318 }
319 color0_resolve_tex->SetLabel(SPrintF("%s Color Texture", label.c_str()));
320
321 // Color attachment.
322
323 ColorAttachment color0;
324 color0.clear_color = color_attachment_config.clear_color;
325 color0.load_action = color_attachment_config.load_action;
326 color0.store_action = color_attachment_config.store_action;
327 color0.texture = color0_msaa_tex;
328 color0.resolve_texture = color0_resolve_tex;
329
330 if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
331 // If implicit MSAA is supported, then the resolve texture is not needed
332 // because the multisample texture is automatically resolved. We instead
333 // provide a view of the multisample texture as the resolve texture (because
334 // the HAL does expect a resolve texture).
335 //
336 // In practice, this is used for GLES 2.0 EXT_multisampled_render_to_texture
337 // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
338 color0.resolve_texture = color0_msaa_tex;
339 }
340
341 target.SetColorAttachment(color0, 0u);
342
343 // Create MSAA stencil texture.
344
345 if (stencil_attachment_config.has_value()) {
346 target.SetupStencilAttachment(context, allocator, size, true, label,
347 stencil_attachment_config.value());
348 } else {
349 target.SetStencilAttachment(std::nullopt);
350 }
351
352 return target;
353 }
354
355 void RenderTarget::SetupStencilAttachment(
356 const Context& context,
357 RenderTargetAllocator& allocator,
358 ISize size,
359 bool msaa,
360 const std::string& label,
361 AttachmentConfig stencil_attachment_config) {
362 TextureDescriptor stencil_tex0;
363 stencil_tex0.storage_mode = stencil_attachment_config.storage_mode;
364 if (msaa) {
365 stencil_tex0.type = TextureType::kTexture2DMultisample;
366 stencil_tex0.sample_count = SampleCount::kCount4;
367 }
368 stencil_tex0.format = context.GetCapabilities()->GetDefaultStencilFormat();
369 stencil_tex0.size = size;
370 stencil_tex0.usage =
371 static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
372
373 StencilAttachment stencil0;
374 stencil0.load_action = stencil_attachment_config.load_action;
375 stencil0.store_action = stencil_attachment_config.store_action;
376 stencil0.clear_stencil = 0u;
377 stencil0.texture = allocator.CreateTexture(stencil_tex0);
378
379 if (!stencil0.texture) {
380 return; // Error messages are handled by `Allocator::CreateTexture`.
381 }
382 stencil0.texture->SetLabel(SPrintF("%s Stencil Texture", label.c_str()));
383 SetStencilAttachment(std::move(stencil0));
384 }
385
386 size_t RenderTarget::GetTotalAttachmentCount() const {
387 size_t count = 0u;
388 for (const auto& [_, color] : colors_) {
389 if (color.texture) {
390 count++;
391 }
392 if (color.resolve_texture) {
393 count++;
394 }
395 }
396 if (depth_.has_value()) {
397 count++;
398 }
399 if (stencil_.has_value()) {
400 count++;
401 }
402 return count;
403 }
404
405 std::string RenderTarget::ToString() const {
406 std::stringstream stream;
407
408 for (const auto& [index, color] : colors_) {
409 stream << SPrintF("Color[%zu]=(%s)", index,
410 ColorAttachmentToString(color).c_str());
411 }
412 if (depth_) {
413 stream << ",";
414 stream << SPrintF("Depth=(%s)",
415 DepthAttachmentToString(depth_.value()).c_str());
416 }
417 if (stencil_) {
418 stream << ",";
419 stream << SPrintF("Stencil=(%s)",
420 StencilAttachmentToString(stencil_.value()).c_str());
421 }
422 return stream.str();
423 }
424
425 } // namespace impeller
impeller::RenderTarget::SetupStencilAttachment
void SetupStencilAttachment(const Context &context, RenderTargetAllocator &allocator, ISize size, bool msaa, const std::string &label="Offscreen", AttachmentConfig stencil_attachment_config=kDefaultStencilAttachmentConfig)
Definition: render_target.cc:355
impeller::RenderTarget::GetTotalAttachmentCount
size_t GetTotalAttachmentCount() const
Definition: render_target.cc:386
impeller::RenderTarget::AttachmentConfig::store_action
StoreAction store_action
Definition: render_target.h:54
impeller::RenderTarget::AttachmentConfig::load_action
LoadAction load_action
Definition: render_target.h:53
impeller::TextureUsageMask
uint64_t TextureUsageMask
Definition: formats.h:295
impeller::Attachment::store_action
StoreAction store_action
Definition: formats.h:637
impeller::RenderTargetAllocator::Start
virtual void Start()
Mark the beginning of a frame workload.
Definition: render_target.cc:21
impeller::Context::GetCapabilities
virtual const std::shared_ptr< const Capabilities > & GetCapabilities() const =0
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
impeller::ColorAttachment
Definition: formats.h:642
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:40
impeller::RenderTarget::SetColorAttachment
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
Definition: render_target.cc:180
impeller::RenderTarget::AttachmentConfigMSAA::store_action
StoreAction store_action
Definition: render_target.h:62
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::RenderTarget::GetRenderTargetPixelFormat
PixelFormat GetRenderTargetPixelFormat() const
Definition: render_target.cc:164
impeller::RenderTarget::GetColorAttachmentSize
std::optional< ISize > GetColorAttachmentSize(size_t index) const
Definition: render_target.cc:140
impeller::RenderTargetAllocator::RenderTargetAllocator
RenderTargetAllocator(std::shared_ptr< Allocator > allocator)
Definition: render_target.cc:17
impeller::RenderTarget::GetColorAttachments
const std::map< size_t, ColorAttachment > & GetColorAttachments() const
Definition: render_target.cc:209
impeller::TextureDescriptor::sample_count
SampleCount sample_count
Definition: texture_descriptor.h:45
impeller::RenderTarget::AttachmentConfigMSAA::load_action
LoadAction load_action
Definition: render_target.h:61
validation.h
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:43
impeller::RenderTarget::AttachmentConfigMSAA::resolve_storage_mode
StorageMode resolve_storage_mode
Definition: render_target.h:60
impeller::RenderTarget::AttachmentConfigMSAA
Definition: render_target.h:58
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:94
impeller::RenderTarget::AttachmentConfig
Definition: render_target.h:51
impeller::TextureDescriptor::type
TextureType type
Definition: texture_descriptor.h:39
impeller::TextureType::kTexture2DMultisample
@ kTexture2DMultisample
impeller::StencilAttachment
Definition: formats.h:650
impeller::TSize< int64_t >
impeller::RenderTarget::GetDepthAttachment
const std::optional< DepthAttachment > & GetDepthAttachment() const
Definition: render_target.cc:214
impeller::ColorAttachment::clear_color
Color clear_color
Definition: formats.h:643
impeller::RenderTarget::GetRenderTargetTexture
std::shared_ptr< Texture > GetRenderTargetTexture() const
Definition: render_target.cc:155
impeller::RenderTarget::IterateAllAttachments
void IterateAllAttachments(const std::function< bool(const Attachment &attachment)> &iterator) const
Definition: render_target.cc:105
impeller::RenderTarget::~RenderTarget
~RenderTarget()
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:634
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::ColorAttachmentToString
std::string ColorAttachmentToString(const ColorAttachment &color)
Definition: formats.cc:123
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::RenderTarget::AttachmentConfig::storage_mode
StorageMode storage_mode
Definition: render_target.h:52
impeller::RenderTargetAllocator::CreateTexture
virtual std::shared_ptr< Texture > CreateTexture(const TextureDescriptor &desc)
Create a new render target texture, or recycle a previously allocated render target texture.
Definition: render_target.cc:25
impeller::Attachment
Definition: formats.h:633
impeller::RenderTarget
Definition: render_target.h:49
impeller::StencilAttachment::clear_stencil
uint32_t clear_stencil
Definition: formats.h:651
impeller::CompressionType::kLossy
@ kLossy
strings.h
impeller::RenderTarget::IsValid
bool IsValid() const
Definition: render_target.cc:34
impeller::RenderTargetAllocator
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
Definition: render_target.h:23
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::RenderTarget::AttachmentConfig::clear_color
Color clear_color
Definition: render_target.h:55
impeller::RenderTarget::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_target.cc:150
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:41
impeller::RenderTarget::CreateOffscreen
static RenderTarget CreateOffscreen(const Context &context, RenderTargetAllocator &allocator, ISize size, const std::string &label="Offscreen", AttachmentConfig color_attachment_config=kDefaultColorAttachmentConfig, std::optional< AttachmentConfig > stencil_attachment_config=kDefaultStencilAttachmentConfig)
Definition: render_target.cc:223
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
allocator.h
impeller::TextureTypeToString
constexpr const char * TextureTypeToString(TextureType type)
Definition: formats.h:264
impeller::Attachment::resolve_texture
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:635
impeller::RenderTarget::AttachmentConfigMSAA::storage_mode
StorageMode storage_mode
Definition: render_target.h:59
impeller::RenderTarget::SetStencilAttachment
RenderTarget & SetStencilAttachment(std::optional< StencilAttachment > attachment)
Definition: render_target.cc:199
impeller::Context
To do anything rendering related with Impeller, you need a context.
Definition: context.h:47
std
Definition: comparable.h:95
impeller::DepthAttachmentToString
std::string DepthAttachmentToString(const DepthAttachment &depth)
Definition: formats.cc:130
impeller::RenderTargetAllocator::End
virtual void End()
Mark the end of a frame workload.
Definition: render_target.cc:23
impeller::SampleCount
SampleCount
Definition: formats.h:290
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:636
texture.h
impeller::Attachment::IsValid
bool IsValid() const
Definition: formats.cc:26
context.h
impeller::SampleCount::kCount1
@ kCount1
impeller::RenderTarget::GetMaxColorAttacmentBindIndex
size_t GetMaxColorAttacmentBindIndex() const
Definition: render_target.cc:172
impeller::SampleCount::kCount4
@ kCount4
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:38
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:37
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: size.h:105
render_target.h
impeller::RenderTarget::GetStencilAttachment
const std::optional< StencilAttachment > & GetStencilAttachment() const
Definition: render_target.cc:218
impeller::RenderTarget::SetDepthAttachment
RenderTarget & SetDepthAttachment(std::optional< DepthAttachment > attachment)
Definition: render_target.cc:189
impeller::RenderTarget::GetSampleCount
SampleCount GetSampleCount() const
Definition: render_target.cc:126
impeller::TextureDescriptor::compression_type
CompressionType compression_type
Definition: texture_descriptor.h:46
impeller::RenderTarget::HasColorAttachment
bool HasColorAttachment(size_t index) const
Definition: render_target.cc:133
impeller
Definition: aiks_context.cc:10
impeller::StencilAttachmentToString
std::string StencilAttachmentToString(const StencilAttachment &stencil)
Definition: formats.cc:137
impeller::RenderTarget::ToString
std::string ToString() const
Definition: render_target.cc:405
impeller::RenderTarget::CreateOffscreenMSAA
static RenderTarget CreateOffscreenMSAA(const Context &context, RenderTargetAllocator &allocator, ISize size, const std::string &label="Offscreen MSAA", AttachmentConfigMSAA color_attachment_config=kDefaultColorAttachmentConfigMSAA, std::optional< AttachmentConfig > stencil_attachment_config=kDefaultStencilAttachmentConfig)
Definition: render_target.cc:265
impeller::RenderTarget::AttachmentConfigMSAA::clear_color
Color clear_color
Definition: render_target.h:63
impeller::RenderTarget::RenderTarget
RenderTarget()