• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 not
56     bool hasPendingWorks(Context *context) const;
57 
58     void setUsedByCommandBufferWithQueueSerial(uint64_t serial, bool writing);
59     void setWrittenToByRenderEncoder(uint64_t serial);
60 
getCommandBufferQueueSerial()61     uint64_t getCommandBufferQueueSerial() const { return mUsageRef->cmdBufferQueueSerial; }
62 
63     // Flag indicate whether we should synchronize the content to CPU after GPU changed this
64     // resource's content.
isCPUReadMemNeedSync()65     bool isCPUReadMemNeedSync() const { return mUsageRef->cpuReadMemNeedSync; }
resetCPUReadMemNeedSync()66     void resetCPUReadMemNeedSync() { mUsageRef->cpuReadMemNeedSync = false; }
67 
isCPUReadMemSyncPending()68     bool isCPUReadMemSyncPending() const { return mUsageRef->cpuReadMemSyncPending; }
setCPUReadMemSyncPending(bool value)69     void setCPUReadMemSyncPending(bool value) const { mUsageRef->cpuReadMemSyncPending = value; }
resetCPUReadMemSyncPending()70     void resetCPUReadMemSyncPending() { mUsageRef->cpuReadMemSyncPending = false; }
71 
isCPUReadMemDirty()72     bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
resetCPUReadMemDirty()73     void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
74 
getLastWritingRenderEncoderSerial()75     bool getLastWritingRenderEncoderSerial() const
76     {
77         return mUsageRef->lastWritingRenderEncoderSerial;
78     }
setLastWritingRenderEncoderSerial(uint64_t serial)79     void setLastWritingRenderEncoderSerial(uint64_t serial) const
80     {
81         mUsageRef->lastWritingRenderEncoderSerial = serial;
82     }
83 
84     virtual size_t estimatedByteSize() const = 0;
85     virtual id getID() const                 = 0;
86 
87   protected:
88     Resource();
89     // Share the GPU usage ref with other resource
90     Resource(Resource *other);
91 
92     void reset();
93 
94   private:
95     struct UsageRef
96     {
97         // The id of the last command buffer that is using this resource.
98         uint64_t cmdBufferQueueSerial = 0;
99 
100         // This flag means the resource was issued to be modified by GPU, if CPU wants to read
101         // its content, explicit synchronization call must be invoked.
102         bool cpuReadMemNeedSync = false;
103 
104         // This flag is set when synchronization for the resource has been
105         // encoded on the GPU, and a map operation must wait
106         // until it's completed.
107         bool cpuReadMemSyncPending = false;
108 
109         // This flag is useful for BufferMtl to know whether it should update the shadow copy
110         bool cpuReadMemDirty = false;
111 
112         // The id of the last render encoder to write to this resource
113         uint64_t lastWritingRenderEncoderSerial = 0;
114     };
115 
116     // One resource object might just be a view of another resource. For example, a texture 2d
117     // object might be a view of one face of a cube texture object. Another example is one texture
118     // object of size 2x2 might be a mipmap view of a texture object size 4x4. Thus, if one object
119     // is being used by a command buffer, it means the other object is being used also. In this
120     // case, the two objects must share the same UsageRef property.
121     std::shared_ptr<UsageRef> mUsageRef;
122 };
123 
124 class Texture final : public Resource,
125                       public WrappedObject<id<MTLTexture>>,
126                       public std::enable_shared_from_this<Texture>
127 {
128   public:
129     static angle::Result Make2DTexture(ContextMtl *context,
130                                        const Format &format,
131                                        uint32_t width,
132                                        uint32_t height,
133                                        uint32_t mips /** use zero to create full mipmaps chain */,
134                                        bool renderTargetOnly,
135                                        bool allowFormatView,
136                                        TextureRef *refOut);
137 
138     // On macOS, memory will still be allocated for this texture.
139     static angle::Result MakeMemoryLess2DTexture(ContextMtl *context,
140                                                  const Format &format,
141                                                  uint32_t width,
142                                                  uint32_t height,
143                                                  TextureRef *refOut);
144 
145     static angle::Result MakeCubeTexture(ContextMtl *context,
146                                          const Format &format,
147                                          uint32_t size,
148                                          uint32_t mips /** use zero to create full mipmaps chain */,
149                                          bool renderTargetOnly,
150                                          bool allowFormatView,
151                                          TextureRef *refOut);
152 
153     static angle::Result Make2DMSTexture(ContextMtl *context,
154                                          const Format &format,
155                                          uint32_t width,
156                                          uint32_t height,
157                                          uint32_t samples,
158                                          bool renderTargetOnly,
159                                          bool allowFormatView,
160                                          TextureRef *refOut);
161 
162     static angle::Result Make2DArrayTexture(ContextMtl *context,
163                                             const Format &format,
164                                             uint32_t width,
165                                             uint32_t height,
166                                             uint32_t mips,
167                                             uint32_t arrayLength,
168                                             bool renderTargetOnly,
169                                             bool allowFormatView,
170                                             TextureRef *refOut);
171 
172     static angle::Result Make3DTexture(ContextMtl *context,
173                                        const Format &format,
174                                        uint32_t width,
175                                        uint32_t height,
176                                        uint32_t depth,
177                                        uint32_t mips,
178                                        bool renderTargetOnly,
179                                        bool allowFormatView,
180                                        TextureRef *refOut);
181     static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
182 
183     // Allow CPU to read & write data directly to this texture?
184     bool isCPUAccessible() const;
185     // Allow shaders to read/sample this texture?
186     // Texture created with renderTargetOnly flag won't be readable
187     bool isShaderReadable() const;
188     // Allow shaders to write this texture?
189     bool isShaderWritable() const;
190 
191     bool supportFormatView() const;
192 
193     void replace2DRegion(ContextMtl *context,
194                          const MTLRegion &region,
195                          const MipmapNativeLevel &mipmapLevel,
196                          uint32_t slice,
197                          const uint8_t *data,
198                          size_t bytesPerRow);
199 
200     void replaceRegion(ContextMtl *context,
201                        const MTLRegion &region,
202                        const MipmapNativeLevel &mipmapLevel,
203                        uint32_t slice,
204                        const uint8_t *data,
205                        size_t bytesPerRow,
206                        size_t bytesPer2DImage);
207 
208     void getBytes(ContextMtl *context,
209                   size_t bytesPerRow,
210                   size_t bytesPer2DInage,
211                   const MTLRegion &region,
212                   const MipmapNativeLevel &mipmapLevel,
213                   uint32_t slice,
214                   uint8_t *dataOut);
215 
216     // Create 2d view of a cube face which full range of mip levels.
217     TextureRef createCubeFaceView(uint32_t face);
218     // Create a view of one slice at a level.
219     TextureRef createSliceMipView(uint32_t slice, const MipmapNativeLevel &level);
220     // Create a view of a level.
221     TextureRef createMipView(const MipmapNativeLevel &level);
222     // Create a view with different format
223     TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
224     // Create a view for a shader image binding.
225     TextureRef createShaderImageView(const MipmapNativeLevel &level,
226                                      int layer,
227                                      MTLPixelFormat format);
228     // Same as above but the target format must be compatible, for example sRGB to linear. In this
229     // case texture doesn't need format view usage flag.
230     TextureRef createViewWithCompatibleFormat(MTLPixelFormat format);
231     // Create a swizzled view
232     TextureRef createSwizzleView(MTLPixelFormat format, const TextureSwizzleChannels &swizzle);
233 
234     MTLTextureType textureType() const;
235     MTLPixelFormat pixelFormat() const;
236 
237     uint32_t mipmapLevels() const;
238     uint32_t arrayLength() const;
239     uint32_t cubeFacesOrArrayLength() const;
240 
241     uint32_t width(const MipmapNativeLevel &level) const;
242     uint32_t height(const MipmapNativeLevel &level) const;
243     uint32_t depth(const MipmapNativeLevel &level) const;
244 
245     gl::Extents size(const MipmapNativeLevel &level) const;
246     gl::Extents size(const ImageNativeIndex &index) const;
247 
widthAt0()248     uint32_t widthAt0() const { return width(kZeroNativeMipLevel); }
heightAt0()249     uint32_t heightAt0() const { return height(kZeroNativeMipLevel); }
depthAt0()250     uint32_t depthAt0() const { return depth(kZeroNativeMipLevel); }
sizeAt0()251     gl::Extents sizeAt0() const { return size(kZeroNativeMipLevel); }
252 
253     uint32_t samples() const;
254 
255     bool hasIOSurface() const;
256     bool sameTypeAndDimemsionsAs(const TextureRef &other) const;
257 
258     angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height);
259 
260     // For render target
getColorWritableMask()261     MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
setColorWritableMask(MTLColorWriteMask mask)262     void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
263 
264     // Get reading copy. Used for reading non-readable texture or reading stencil value from
265     // packed depth & stencil texture.
266     // NOTE: this only copies 1 depth slice of the 3D texture.
267     // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture.
268     // The returned pointer will be retained by the original texture object.
269     // Calling getReadableCopy() will overwrite previously returned texture.
270     TextureRef getReadableCopy(ContextMtl *context,
271                                mtl::BlitCommandEncoder *encoder,
272                                const uint32_t levelToCopy,
273                                const uint32_t sliceToCopy,
274                                const MTLRegion &areaToCopy);
275 
276     void releaseReadableCopy();
277 
278     // Get stencil view
279     TextureRef getStencilView();
280     // Get linear color
281     TextureRef getLinearColorView();
282 
283     // Change the wrapped metal object. Special case for swapchain image
284     void set(id<MTLTexture> metalTexture);
285 
286     // Explicitly sync content between CPU and GPU
287     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
setEstimatedByteSize(size_t bytes)288     void setEstimatedByteSize(size_t bytes) { mEstimatedByteSize = bytes; }
estimatedByteSize()289     size_t estimatedByteSize() const override { return mEstimatedByteSize; }
getID()290     id getID() const override { return get(); }
291 
292   private:
293     using ParentClass = WrappedObject<id<MTLTexture>>;
294 
295     static angle::Result MakeTexture(ContextMtl *context,
296                                      const Format &mtlFormat,
297                                      MTLTextureDescriptor *desc,
298                                      uint32_t mips,
299                                      bool renderTargetOnly,
300                                      bool allowFormatView,
301                                      TextureRef *refOut);
302 
303     static angle::Result MakeTexture(ContextMtl *context,
304                                      const Format &mtlFormat,
305                                      MTLTextureDescriptor *desc,
306                                      uint32_t mips,
307                                      bool renderTargetOnly,
308                                      bool allowFormatView,
309                                      bool memoryLess,
310                                      TextureRef *refOut);
311 
312     static angle::Result MakeTexture(ContextMtl *context,
313                                      const Format &mtlFormat,
314                                      MTLTextureDescriptor *desc,
315                                      IOSurfaceRef surfaceRef,
316                                      NSUInteger slice,
317                                      bool renderTargetOnly,
318                                      TextureRef *refOut);
319 
320     Texture(id<MTLTexture> metalTexture);
321     Texture(ContextMtl *context,
322             MTLTextureDescriptor *desc,
323             uint32_t mips,
324             bool renderTargetOnly,
325             bool allowFormatView);
326     Texture(ContextMtl *context,
327             MTLTextureDescriptor *desc,
328             uint32_t mips,
329             bool renderTargetOnly,
330             bool allowFormatView,
331             bool memoryLess);
332 
333     Texture(ContextMtl *context,
334             MTLTextureDescriptor *desc,
335             IOSurfaceRef iosurface,
336             NSUInteger plane,
337             bool renderTargetOnly);
338 
339     // Create a texture view
340     Texture(Texture *original, MTLPixelFormat format);
341     Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, NSRange slices);
342     Texture(Texture *original, MTLPixelFormat format, const TextureSwizzleChannels &swizzle);
343 
344     // Creates a view for a shader image binding.
345     Texture(Texture *original,
346             MTLTextureType type,
347             const MipmapNativeLevel &level,
348             int layer,
349             MTLPixelFormat pixelFormat);
350 
351     void syncContentIfNeeded(ContextMtl *context);
352 
353     AutoObjCObj<MTLTextureDescriptor> mCreationDesc;
354 
355     // This property is shared between this object and its views:
356     std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
357 
358     // Linear view of sRGB texture
359     TextureRef mLinearColorView;
360 
361     TextureRef mStencilView;
362     // Readable copy of texture
363     TextureRef mReadCopy;
364 
365     size_t mEstimatedByteSize = 0;
366 };
367 
368 class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
369 {
370   public:
371     static MTLStorageMode getStorageModeForSharedBuffer(ContextMtl *contextMtl);
372     using Usage = gl::BufferUsage;
373     static MTLStorageMode getStorageModeForUsage(ContextMtl *context, Usage usage);
374 
375     static angle::Result MakeBuffer(ContextMtl *context,
376                                     size_t size,
377                                     const uint8_t *data,
378                                     BufferRef *bufferOut);
379 
380     static angle::Result MakeBufferWithStorageMode(ContextMtl *context,
381                                                    MTLStorageMode storageMode,
382                                                    size_t size,
383                                                    const uint8_t *data,
384                                                    BufferRef *bufferOut);
385 
386     angle::Result reset(ContextMtl *context,
387                         MTLStorageMode storageMode,
388                         size_t size,
389                         const uint8_t *data);
390 
391     const uint8_t *mapReadOnly(ContextMtl *context);
392     uint8_t *map(ContextMtl *context);
393     uint8_t *mapWithOpt(ContextMtl *context, bool readonly, bool noSync);
394 
395     void unmap(ContextMtl *context);
396     // Same as unmap but do not do implicit flush()
397     void unmapNoFlush(ContextMtl *context);
398     void unmapAndFlushSubset(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
399     void flush(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
400 
401     size_t size() const;
402     MTLStorageMode storageMode() const;
403 
404     // Explicitly sync content between CPU and GPU
405     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
406 
estimatedByteSize()407     size_t estimatedByteSize() const override { return size(); }
getID()408     id getID() const override { return get(); }
409 
getNumContextSwitchesAtLastUse()410     size_t getNumContextSwitchesAtLastUse() { return mContextSwitchesAtLastUse; }
setNumContextSwitchesAtLastUse(size_t num)411     void setNumContextSwitchesAtLastUse(size_t num) { mContextSwitchesAtLastUse = num; }
getNumCommandBufferCommitsAtLastUse()412     size_t getNumCommandBufferCommitsAtLastUse() { return mCommandBufferCommitsAtLastUse; }
setNumCommandBufferCommitsAtLastUse(size_t num)413     void setNumCommandBufferCommitsAtLastUse(size_t num) { mCommandBufferCommitsAtLastUse = num; }
414 
415   private:
416     Buffer(ContextMtl *context, MTLStorageMode storageMode, size_t size, const uint8_t *data);
417 
418     bool mMapReadOnly = true;
419     // For garbage collecting shadow buffers in BufferManager.
420     size_t mContextSwitchesAtLastUse      = 0;
421     size_t mCommandBufferCommitsAtLastUse = 0;
422 };
423 
424 class NativeTexLevelArray
425 {
426   public:
at(const MipmapNativeLevel & level)427     TextureRef &at(const MipmapNativeLevel &level) { return mTexLevels.at(level.get()); }
at(const MipmapNativeLevel & level)428     const TextureRef &at(const MipmapNativeLevel &level) const
429     {
430         return mTexLevels.at(level.get());
431     }
432 
433     TextureRef &operator[](const MipmapNativeLevel &level) { return at(level); }
434     const TextureRef &operator[](const MipmapNativeLevel &level) const { return at(level); }
435 
begin()436     gl::TexLevelArray<TextureRef>::iterator begin() { return mTexLevels.begin(); }
begin()437     gl::TexLevelArray<TextureRef>::const_iterator begin() const { return mTexLevels.begin(); }
end()438     gl::TexLevelArray<TextureRef>::iterator end() { return mTexLevels.end(); }
end()439     gl::TexLevelArray<TextureRef>::const_iterator end() const { return mTexLevels.end(); }
440 
441   private:
442     gl::TexLevelArray<TextureRef> mTexLevels;
443 };
444 
445 }  // namespace mtl
446 }  // namespace rx
447 
448 #endif /* LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_ */
449