| Flutter Impeller |

texture_mtl.mm
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/backend/metal/texture_mtl.h"
6
7 #include <format>
8 #include <memory>
9
10 #include "impeller/base/strings.h"
11 #include "impeller/base/validation.h"
12 #include "impeller/core/formats.h"
13 #include "impeller/core/texture_descriptor.h"
14
15 namespace impeller {
16
17 std::shared_ptr<Texture> WrapperMTL(TextureDescriptor desc,
18 const void* mtl_texture,
19 std::function<void()> deletion_proc) {
20 return TextureMTL::Wrapper(desc, (__bridge id<MTLTexture>)mtl_texture,
21 std::move(deletion_proc));
22 }
23
24 TextureMTL::TextureMTL(TextureDescriptor p_desc,
25 const AcquireTextureProc& aquire_proc,
26 bool wrapped,
27 bool drawable)
28 : Texture(p_desc), aquire_proc_(aquire_proc), is_drawable_(drawable) {
29 const auto& desc = GetTextureDescriptor();
30
31 if (!desc.IsValid() || !aquire_proc) {
32 return;
33 }
34
35 if (desc.size != GetSize()) {
36 VALIDATION_LOG << "The texture and its descriptor disagree about its size.";
37 return;
38 }
39
40 is_wrapped_ = wrapped;
41 is_valid_ = true;
42 }
43
44 std::shared_ptr<TextureMTL> TextureMTL::Wrapper(
45 TextureDescriptor desc,
46 id<MTLTexture> texture,
47 std::function<void()> deletion_proc) {
48 if (deletion_proc) {
49 return std::shared_ptr<TextureMTL>(
50 new TextureMTL(
51 desc, [texture]() { return texture; }, true),
52 [deletion_proc = std::move(deletion_proc)](TextureMTL* t) {
53 deletion_proc();
54 delete t;
55 });
56 }
57 return std::shared_ptr<TextureMTL>(
58 new TextureMTL(desc, [texture]() { return texture; }, true));
59 }
60
61 std::shared_ptr<TextureMTL> TextureMTL::Create(TextureDescriptor desc,
62 id<MTLTexture> texture) {
63 return std::make_shared<TextureMTL>(desc, [texture]() { return texture; });
64 }
65
66 TextureMTL::~TextureMTL() {
67 #ifdef IMPELLER_DEBUG
68 if (debug_allocator_) {
69 auto desc = GetTextureDescriptor();
70 if (desc.storage_mode == StorageMode::kDeviceTransient) {
71 return;
72 }
73 debug_allocator_->Decrement(desc.GetByteSizeOfBaseMipLevel());
74 }
75 #endif // IMPELLER_DEBUG
76 }
77
78 void TextureMTL::SetLabel(std::string_view label) {
79 #ifdef IMPELLER_DEBUG
80 if (is_drawable_) {
81 return;
82 }
83 [aquire_proc_() setLabel:@(label.data())];
84 #endif // IMPELLER_DEBUG
85 }
86
87 void TextureMTL::SetLabel(std::string_view label, std::string_view trailing) {
88 #ifdef IMPELLER_DEBUG
89 if (is_drawable_) {
90 return;
91 }
92 std::string combined = std::format("{} {}", label, trailing);
93 [aquire_proc_() setLabel:@(combined.data())];
94 #endif // IMPELLER_DEBUG
95 }
96
97 // |Texture|
98 bool TextureMTL::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
99 size_t slice) {
100 // Metal has no threading restrictions. So we can pass this data along to the
101 // client rendering API immediately.
102 return OnSetContents(mapping->GetMapping(), mapping->GetSize(), slice);
103 }
104
105 #ifdef IMPELLER_DEBUG
106 void TextureMTL::SetDebugAllocator(
107 const std::shared_ptr<DebugAllocatorStats>& debug_allocator) {
108 debug_allocator_ = debug_allocator;
109 }
110 #endif // IMPELLER_DEBUG
111
112 // |Texture|
113 bool TextureMTL::OnSetContents(const uint8_t* contents,
114 size_t length,
115 size_t slice) {
116 if (!IsValid() || !contents || is_wrapped_ || is_drawable_) {
117 return false;
118 }
119
120 const auto& desc = GetTextureDescriptor();
121
122 // Out of bounds access.
123 if (length != desc.GetByteSizeOfBaseMipLevel()) {
124 return false;
125 }
126
127 const auto region =
128 MTLRegionMake2D(0u, 0u, desc.size.width, desc.size.height);
129 [aquire_proc_() replaceRegion:region //
130 mipmapLevel:0u //
131 slice:slice //
132 withBytes:contents //
133 bytesPerRow:desc.GetBytesPerRow() //
134 bytesPerImage:desc.GetByteSizeOfBaseMipLevel() //
135 ];
136
137 return true;
138 }
139
140 ISize TextureMTL::GetSize() const {
141 if (is_drawable_) {
142 return GetTextureDescriptor().size;
143 }
144 const auto& texture = aquire_proc_();
145 return {static_cast<ISize::Type>(texture.width),
146 static_cast<ISize::Type>(texture.height)};
147 }
148
149 id<MTLTexture> TextureMTL::GetMTLTexture() const {
150 return aquire_proc_();
151 }
152
153 bool TextureMTL::IsValid() const {
154 return is_valid_;
155 }
156
157 bool TextureMTL::IsWrapped() const {
158 return is_wrapped_;
159 }
160
161 bool TextureMTL::IsDrawable() const {
162 return is_drawable_;
163 }
164
165 bool TextureMTL::GenerateMipmap(id<MTLBlitCommandEncoder> encoder) {
166 if (is_drawable_) {
167 return false;
168 }
169
170 auto texture = aquire_proc_();
171 if (!texture) {
172 return false;
173 }
174
175 [encoder generateMipmapsForTexture:texture];
176 mipmap_generated_ = true;
177
178 return true;
179 }
180
181 } // namespace impeller
impeller::Texture
Definition: texture.h:17
impeller::Texture::GetTextureDescriptor
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:57
impeller::Texture::mipmap_generated_
bool mipmap_generated_
Definition: texture.h:79
impeller::TextureMTL
Definition: texture_mtl.h:17
impeller::TextureMTL::GetMTLTexture
id< MTLTexture > GetMTLTexture() const
Definition: texture_mtl.mm:149
impeller::TextureMTL::~TextureMTL
~TextureMTL() override
Definition: texture_mtl.mm:66
impeller::TextureMTL::TextureMTL
TextureMTL(TextureDescriptor desc, const AcquireTextureProc &aquire_proc, bool wrapped=false, bool drawable=false)
Definition: texture_mtl.mm:24
impeller::TextureMTL::IsDrawable
bool IsDrawable() const
Whether or not this texture is wrapping a Metal drawable.
Definition: texture_mtl.mm:161
impeller::TextureMTL::IsValid
bool IsValid() const override
Definition: texture_mtl.mm:153
impeller::TextureMTL::AcquireTextureProc
std::function< id< MTLTexture >()> AcquireTextureProc
This callback needs to always return the same texture when called multiple times.
Definition: texture_mtl.h:21
impeller::TextureMTL::IsWrapped
bool IsWrapped() const
Definition: texture_mtl.mm:157
impeller::TextureMTL::GenerateMipmap
bool GenerateMipmap(id< MTLBlitCommandEncoder > encoder)
Definition: texture_mtl.mm:165
impeller::TextureMTL::Wrapper
static std::shared_ptr< TextureMTL > Wrapper(TextureDescriptor desc, id< MTLTexture > texture, std::function< void()> deletion_proc=nullptr)
Definition: texture_mtl.mm:44
impeller::TextureMTL::Create
static std::shared_ptr< TextureMTL > Create(TextureDescriptor desc, id< MTLTexture > texture)
Definition: texture_mtl.mm:61
formats.h
impeller
Definition: allocation.cc:12
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::WrapperMTL
std::shared_ptr< Texture > WrapperMTL(TextureDescriptor desc, const void *mtl_texture, std::function< void()> deletion_proc)
Definition: texture_mtl.mm:17
impeller::ISize
ISize64 ISize
Definition: size.h:162
strings.h
impeller::TSize::Type
T Type
Definition: size.h:26
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
impeller::TextureDescriptor::GetByteSizeOfBaseMipLevel
constexpr size_t GetByteSizeOfBaseMipLevel() const
Definition: texture_descriptor.h:48
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
impeller::TextureDescriptor::IsValid
constexpr bool IsValid() const
Definition: texture_descriptor.h:85
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:39
texture_descriptor.h
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:68
texture_mtl.h
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91