xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/mtl_resources.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // mtl_resources.h:
7 //    Declares wrapper classes for Metal's MTLTexture and MTLBuffer.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_
11 #define LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_
12 
13 #import <Metal/Metal.h>
14 
15 #include <atomic>
16 #include <memory>
17 
18 #include "common/FastVector.h"
19 #include "common/MemoryBuffer.h"
20 #include "common/angleutils.h"
21 #include "libANGLE/Error.h"
22 #include "libANGLE/angletypes.h"
23 #include "libANGLE/renderer/metal/mtl_common.h"
24 #include "libANGLE/renderer/metal/mtl_format_utils.h"
25 
26 namespace rx
27 {
28 
29 class ContextMtl;
30 
31 namespace mtl
32 {
33 
34 class ContextDevice;
35 class CommandQueue;
36 class BlitCommandEncoder;
37 class Resource;
38 class Texture;
39 class Buffer;
40 
41 using ResourceRef    = std::shared_ptr<Resource>;
42 using TextureRef     = std::shared_ptr<Texture>;
43 using TextureWeakRef = std::weak_ptr<Texture>;
44 using BufferRef      = std::shared_ptr<Buffer>;
45 using BufferWeakRef  = std::weak_ptr<Buffer>;
46 
47 class Resource : angle::NonCopyable
48 {
49   public:
~Resource()50     virtual ~Resource() {}
51 
52     // Check whether the resource still being used by GPU including the pending (uncommitted)
53     // command buffer.
54     bool isBeingUsedByGPU(Context *context) const;
55     // Checks whether the last command buffer that uses the given resource has been committed or
56     // not
57     bool hasPendingWorks(Context *context) const;
58     bool hasPendingRenderWorks(Context *context) const;
59 
60     void setUsedByCommandBufferWithQueueSerial(uint64_t serial, bool writing, bool isRenderCommand);
61 
getCommandBufferQueueSerial()62     uint64_t getCommandBufferQueueSerial() const { return mUsageRef->cmdBufferQueueSerial; }
63 
64     // Flag indicate whether we should synchronize the content to CPU after GPU changed this
65     // resource's content.
isCPUReadMemNeedSync()66     bool isCPUReadMemNeedSync() const { return mUsageRef->cpuReadMemNeedSync; }
resetCPUReadMemNeedSync()67     void resetCPUReadMemNeedSync() { mUsageRef->cpuReadMemNeedSync = false; }
68 
isCPUReadMemSyncPending()69     bool isCPUReadMemSyncPending() const { return mUsageRef->cpuReadMemSyncPending; }
setCPUReadMemSyncPending(bool value)70     void setCPUReadMemSyncPending(bool value) const { mUsageRef->cpuReadMemSyncPending = value; }
resetCPUReadMemSyncPending()71     void resetCPUReadMemSyncPending() { mUsageRef->cpuReadMemSyncPending = false; }
72 
isCPUReadMemDirty()73     bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
resetCPUReadMemDirty()74     void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
75 
getLastReadingRenderEncoderSerial()76     uint64_t getLastReadingRenderEncoderSerial() const
77     {
78         return mUsageRef->lastReadingRenderEncoderSerial;
79     }
getLastWritingRenderEncoderSerial()80     uint64_t getLastWritingRenderEncoderSerial() const
81     {
82         return mUsageRef->lastWritingRenderEncoderSerial;
83     }
84 
getLastRenderEncoderSerial()85     uint64_t getLastRenderEncoderSerial() const
86     {
87         return std::max(mUsageRef->lastReadingRenderEncoderSerial,
88                         mUsageRef->lastWritingRenderEncoderSerial);
89     }
90 
91     virtual size_t estimatedByteSize() const = 0;
92     virtual id getID() const                 = 0;
93 
94   protected:
95     struct UsageRef;
96 
97     Resource();
98     // Share the GPU usage ref with other resource
99     Resource(Resource *other);
100     Resource(std::shared_ptr<UsageRef> otherUsageRef);
101 
102     void reset();
103 
104     struct UsageRef
105     {
106         // The id of the last command buffer that is using this resource.
107         uint64_t cmdBufferQueueSerial = 0;
108 
109         // This flag means the resource was issued to be modified by GPU, if CPU wants to read
110         // its content, explicit synchronization call must be invoked.
111         bool cpuReadMemNeedSync = false;
112 
113         // This flag is set when synchronization for the resource has been
114         // encoded on the GPU, and a map operation must wait
115         // until it's completed.
116         bool cpuReadMemSyncPending = false;
117 
118         // This flag is useful for BufferMtl to know whether it should update the shadow copy
119         bool cpuReadMemDirty = false;
120 
121         // The id of the last render encoder to read/write to this resource
122         uint64_t lastReadingRenderEncoderSerial = 0;
123         uint64_t lastWritingRenderEncoderSerial = 0;
124     };
125 
126     // One resource object might just be a view of another resource. For example, a texture 2d
127     // object might be a view of one face of a cube texture object. Another example is one
128     // texture object of size 2x2 might be a mipmap view of a texture object size 4x4. Thus, if
129     // one object is being used by a command buffer, it means the other object is being used
130     // also. In this case, the two objects must share the same UsageRef property.
131     std::shared_ptr<UsageRef> mUsageRef;
132 };
133 
134 class Texture final : public Resource,
135                       public WrappedObject<id<MTLTexture>>,
136                       public std::enable_shared_from_this<Texture>
137 {
138   public:
139     static angle::Result Make2DTexture(ContextMtl *context,
140                                        const Format &format,
141                                        uint32_t width,
142                                        uint32_t height,
143                                        uint32_t mips /** use zero to create full mipmaps chain */,
144                                        bool renderTargetOnly,
145                                        bool allowFormatView,
146                                        TextureRef *refOut);
147 
148     // On macOS, memory will still be allocated for this texture.
149     static angle::Result MakeMemoryLess2DMSTexture(ContextMtl *context,
150                                                    const Format &format,
151                                                    uint32_t width,
152                                                    uint32_t height,
153                                                    uint32_t samples,
154                                                    TextureRef *refOut);
155 
156     static angle::Result MakeCubeTexture(ContextMtl *context,
157                                          const Format &format,
158                                          uint32_t size,
159                                          uint32_t mips /** use zero to create full mipmaps chain */,
160                                          bool renderTargetOnly,
161                                          bool allowFormatView,
162                                          TextureRef *refOut);
163 
164     static angle::Result Make2DMSTexture(ContextMtl *context,
165                                          const Format &format,
166                                          uint32_t width,
167                                          uint32_t height,
168                                          uint32_t samples,
169                                          bool renderTargetOnly,
170                                          bool allowFormatView,
171                                          TextureRef *refOut);
172 
173     static angle::Result Make2DArrayTexture(ContextMtl *context,
174                                             const Format &format,
175                                             uint32_t width,
176                                             uint32_t height,
177                                             uint32_t mips,
178                                             uint32_t arrayLength,
179                                             bool renderTargetOnly,
180                                             bool allowFormatView,
181                                             TextureRef *refOut);
182 
183     static angle::Result Make3DTexture(ContextMtl *context,
184                                        const Format &format,
185                                        uint32_t width,
186                                        uint32_t height,
187                                        uint32_t depth,
188                                        uint32_t mips,
189                                        bool renderTargetOnly,
190                                        bool allowFormatView,
191                                        TextureRef *refOut);
192     static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
193 
194     // Allow CPU to read & write data directly to this texture?
195     bool isCPUAccessible() const;
196     // Allow shaders to read/sample this texture?
197     // Texture created with renderTargetOnly flag won't be readable
198     bool isShaderReadable() const;
199     // Allow shaders to write this texture?
200     bool isShaderWritable() const;
201 
202     bool supportFormatView() const;
203 
204     void replace2DRegion(ContextMtl *context,
205                          const MTLRegion &region,
206                          const MipmapNativeLevel &mipmapLevel,
207                          uint32_t slice,
208                          const uint8_t *data,
209                          size_t bytesPerRow);
210 
211     void replaceRegion(ContextMtl *context,
212                        const MTLRegion &region,
213                        const MipmapNativeLevel &mipmapLevel,
214                        uint32_t slice,
215                        const uint8_t *data,
216                        size_t bytesPerRow,
217                        size_t bytesPer2DImage);
218 
219     void getBytes(ContextMtl *context,
220                   size_t bytesPerRow,
221                   size_t bytesPer2DInage,
222                   const MTLRegion &region,
223                   const MipmapNativeLevel &mipmapLevel,
224                   uint32_t slice,
225                   uint8_t *dataOut);
226 
227     // Create 2d view of a cube face which full range of mip levels.
228     TextureRef createCubeFaceView(uint32_t face);
229     // Create a view of one slice at a level.
230     TextureRef createSliceMipView(uint32_t slice, const MipmapNativeLevel &level);
231     // Create a levels range view
232     TextureRef createMipsView(const MipmapNativeLevel &baseLevel, uint32_t levels);
233     // Create a view of a level.
234     TextureRef createMipView(const MipmapNativeLevel &level);
235     // Create a view with different format
236     TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
237     // Create a view for a shader image binding.
238     TextureRef createShaderImageView2D(const MipmapNativeLevel &level,
239                                        int layer,
240                                        MTLPixelFormat format);
241     // Same as above but the target format must be compatible, for example sRGB to linear. In
242     // this case texture doesn't need format view usage flag.
243     TextureRef createViewWithCompatibleFormat(MTLPixelFormat format);
244     // Create a swizzled view
245     TextureRef createMipsSwizzleView(const MipmapNativeLevel &baseLevel,
246                                      uint32_t levels,
247                                      MTLPixelFormat format,
248                                      const MTLTextureSwizzleChannels &swizzle);
249 
250     MTLTextureType textureType() const;
251     MTLPixelFormat pixelFormat() const;
252 
253     uint32_t mipmapLevels() const;
254     uint32_t arrayLength() const;
255     uint32_t cubeFaces() const;
256     uint32_t cubeFacesOrArrayLength() const;
257 
258     uint32_t width(const MipmapNativeLevel &level) const;
259     uint32_t height(const MipmapNativeLevel &level) const;
260     uint32_t depth(const MipmapNativeLevel &level) const;
261 
262     gl::Extents size(const MipmapNativeLevel &level) const;
263     gl::Extents size(const ImageNativeIndex &index) const;
264 
widthAt0()265     uint32_t widthAt0() const { return width(kZeroNativeMipLevel); }
heightAt0()266     uint32_t heightAt0() const { return height(kZeroNativeMipLevel); }
depthAt0()267     uint32_t depthAt0() const { return depth(kZeroNativeMipLevel); }
sizeAt0()268     gl::Extents sizeAt0() const { return size(kZeroNativeMipLevel); }
269 
270     uint32_t samples() const;
271 
272     bool hasIOSurface() const;
273     bool sameTypeAndDimemsionsAs(const TextureRef &other) const;
274 
275     angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height);
276 
277     // Get the color write mask to restrict writing to certain color channels in this texture. It's
278     // used for textures having emulated mtl::Format such as RGB which should always have alpha
279     // value being one.
getColorWritableMask()280     MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
setColorWritableMask(MTLColorWriteMask mask)281     void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
282 
283     // Get reading copy. Used for reading non-readable texture or reading stencil value from
284     // packed depth & stencil texture.
285     // NOTE: this only copies 1 depth slice of the 3D texture.
286     // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture.
287     // The returned pointer will be retained by the original texture object.
288     // Calling getReadableCopy() will overwrite previously returned texture.
289     TextureRef getReadableCopy(ContextMtl *context,
290                                mtl::BlitCommandEncoder *encoder,
291                                const uint32_t levelToCopy,
292                                const uint32_t sliceToCopy,
293                                const MTLRegion &areaToCopy);
294 
295     void releaseReadableCopy();
296 
297     // Get stencil view
298     TextureRef getStencilView();
299     // Get linear color
300     TextureRef getLinearColorView();
301 
302     TextureRef parentTexture();
303     MipmapNativeLevel parentRelativeLevel();
304     uint32_t parentRelativeSlice();
305 
306     // Change the wrapped metal object. Special case for swapchain image
307     void set(id<MTLTexture> metalTexture);
308 
309     // Explicitly sync content between CPU and GPU
310     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
setEstimatedByteSize(size_t bytes)311     void setEstimatedByteSize(size_t bytes) { mEstimatedByteSize = bytes; }
estimatedByteSize()312     size_t estimatedByteSize() const override { return mEstimatedByteSize; }
getID()313     id getID() const override { return get(); }
314 
315     // Should we disable MTLLoadActionLoad & MTLStoreActionStore when using this texture
316     // as render pass' attachment. This is usually used for memoryless textures and
317     // EXT_multisampled_render_to_texture.
shouldNotLoadStore()318     bool shouldNotLoadStore() const { return mShouldNotLoadStore; }
319 
320   private:
321     using ParentClass = WrappedObject<id<MTLTexture>>;
322 
323     static angle::Result MakeTexture(ContextMtl *context,
324                                      const Format &mtlFormat,
325                                      MTLTextureDescriptor *desc,
326                                      uint32_t mips,
327                                      bool renderTargetOnly,
328                                      bool allowFormatView,
329                                      TextureRef *refOut);
330 
331     static angle::Result MakeTexture(ContextMtl *context,
332                                      const Format &mtlFormat,
333                                      MTLTextureDescriptor *desc,
334                                      uint32_t mips,
335                                      bool renderTargetOnly,
336                                      bool allowFormatView,
337                                      bool memoryLess,
338                                      TextureRef *refOut);
339 
340     static angle::Result MakeTexture(ContextMtl *context,
341                                      const Format &mtlFormat,
342                                      MTLTextureDescriptor *desc,
343                                      IOSurfaceRef surfaceRef,
344                                      NSUInteger slice,
345                                      bool renderTargetOnly,
346                                      TextureRef *refOut);
347 
348     Texture(id<MTLTexture> metalTexture);
349 
350     // Create a texture that shares ownership of usageRef, underlying MTLTexture and colorWriteMask
351     // with the original texture.
352     Texture(std::shared_ptr<UsageRef> usageRef,
353             id<MTLTexture> metalTexture,
354             std::shared_ptr<MTLColorWriteMask> colorWriteMask);
355 
356     Texture(ContextMtl *context,
357             MTLTextureDescriptor *desc,
358             uint32_t mips,
359             bool renderTargetOnly,
360             bool allowFormatView);
361     Texture(ContextMtl *context,
362             MTLTextureDescriptor *desc,
363             uint32_t mips,
364             bool renderTargetOnly,
365             bool allowFormatView,
366             bool memoryLess);
367 
368     Texture(ContextMtl *context,
369             MTLTextureDescriptor *desc,
370             IOSurfaceRef iosurface,
371             NSUInteger plane,
372             bool renderTargetOnly);
373 
374     // Create a texture view
375     Texture(Texture *original, MTLPixelFormat pixelFormat);
376     Texture(Texture *original,
377             MTLPixelFormat pixelFormat,
378             MTLTextureType textureType,
379             NSRange levels,
380             NSRange slices);
381     Texture(Texture *original,
382             MTLPixelFormat pixelFormat,
383             MTLTextureType textureType,
384             NSRange levels,
385             NSRange slices,
386             const MTLTextureSwizzleChannels &swizzle);
387 
388     void syncContentIfNeeded(ContextMtl *context);
389 
390     AutoObjCObj<MTLTextureDescriptor> mCreationDesc;
391 
392     // This property is shared between this object and its views:
393     std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
394 
395     // Linear view of sRGB texture
396     TextureRef mLinearColorView;
397 
398     TextureRef mStencilView;
399     // Readable copy of texture
400     TextureRef mReadCopy;
401 
402     TextureRef mParentTexture;
403 
404     size_t mEstimatedByteSize = 0;
405 
406     bool mShouldNotLoadStore = false;
407 };
408 
409 class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
410 {
411   public:
412     static MTLStorageMode getStorageModeForSharedBuffer(ContextMtl *contextMtl);
413     using Usage = gl::BufferUsage;
414     static MTLStorageMode getStorageModeForUsage(ContextMtl *context, Usage usage);
415 
416     static angle::Result MakeBuffer(ContextMtl *context,
417                                     size_t size,
418                                     const uint8_t *data,
419                                     BufferRef *bufferOut);
420 
421     static angle::Result MakeBufferWithStorageMode(ContextMtl *context,
422                                                    MTLStorageMode storageMode,
423                                                    size_t size,
424                                                    const uint8_t *data,
425                                                    BufferRef *bufferOut);
426 
427     angle::Result reset(ContextMtl *context,
428                         MTLStorageMode storageMode,
429                         size_t size,
430                         const uint8_t *data);
431 
432     const uint8_t *mapReadOnly(ContextMtl *context);
433     uint8_t *map(ContextMtl *context);
434     uint8_t *mapWithOpt(ContextMtl *context, bool readonly, bool noSync);
435 
436     void unmap(ContextMtl *context);
437     // Same as unmap but do not do implicit flush()
438     void unmapNoFlush(ContextMtl *context);
439     void unmapAndFlushSubset(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
440     void flush(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
441 
442     size_t size() const;
443     MTLStorageMode storageMode() const;
444 
445     // Explicitly sync content between CPU and GPU
446     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
447 
estimatedByteSize()448     size_t estimatedByteSize() const override { return size(); }
getID()449     id getID() const override { return get(); }
450 
getNumContextSwitchesAtLastUse()451     size_t getNumContextSwitchesAtLastUse() { return mContextSwitchesAtLastUse; }
setNumContextSwitchesAtLastUse(size_t num)452     void setNumContextSwitchesAtLastUse(size_t num) { mContextSwitchesAtLastUse = num; }
getNumCommandBufferCommitsAtLastUse()453     size_t getNumCommandBufferCommitsAtLastUse() { return mCommandBufferCommitsAtLastUse; }
setNumCommandBufferCommitsAtLastUse(size_t num)454     void setNumCommandBufferCommitsAtLastUse(size_t num) { mCommandBufferCommitsAtLastUse = num; }
455 
456   private:
457     Buffer(ContextMtl *context, MTLStorageMode storageMode, size_t size, const uint8_t *data);
458 
459     bool mMapReadOnly = true;
460     // For garbage collecting shadow buffers in BufferManager.
461     size_t mContextSwitchesAtLastUse      = 0;
462     size_t mCommandBufferCommitsAtLastUse = 0;
463 };
464 
465 class NativeTexLevelArray
466 {
467   public:
at(const MipmapNativeLevel & level)468     TextureRef &at(const MipmapNativeLevel &level) { return mTexLevels.at(level.get()); }
at(const MipmapNativeLevel & level)469     const TextureRef &at(const MipmapNativeLevel &level) const
470     {
471         return mTexLevels.at(level.get());
472     }
473 
474     TextureRef &operator[](const MipmapNativeLevel &level) { return at(level); }
475     const TextureRef &operator[](const MipmapNativeLevel &level) const { return at(level); }
476 
begin()477     gl::TexLevelArray<TextureRef>::iterator begin() { return mTexLevels.begin(); }
begin()478     gl::TexLevelArray<TextureRef>::const_iterator begin() const { return mTexLevels.begin(); }
end()479     gl::TexLevelArray<TextureRef>::iterator end() { return mTexLevels.end(); }
end()480     gl::TexLevelArray<TextureRef>::const_iterator end() const { return mTexLevels.end(); }
481 
482   private:
483     gl::TexLevelArray<TextureRef> mTexLevels;
484 };
485 
486 }  // namespace mtl
487 }  // namespace rx
488 
489 #endif /* LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_ */
490