• 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
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 MakeMemoryLess2DTexture(ContextMtl *context,
150                                                  const Format &format,
151                                                  uint32_t width,
152                                                  uint32_t height,
153                                                  TextureRef *refOut);
154 
155     static angle::Result MakeCubeTexture(ContextMtl *context,
156                                          const Format &format,
157                                          uint32_t size,
158                                          uint32_t mips /** use zero to create full mipmaps chain */,
159                                          bool renderTargetOnly,
160                                          bool allowFormatView,
161                                          TextureRef *refOut);
162 
163     static angle::Result Make2DMSTexture(ContextMtl *context,
164                                          const Format &format,
165                                          uint32_t width,
166                                          uint32_t height,
167                                          uint32_t samples,
168                                          bool renderTargetOnly,
169                                          bool allowFormatView,
170                                          TextureRef *refOut);
171 
172     static angle::Result Make2DArrayTexture(ContextMtl *context,
173                                             const Format &format,
174                                             uint32_t width,
175                                             uint32_t height,
176                                             uint32_t mips,
177                                             uint32_t arrayLength,
178                                             bool renderTargetOnly,
179                                             bool allowFormatView,
180                                             TextureRef *refOut);
181 
182     static angle::Result Make3DTexture(ContextMtl *context,
183                                        const Format &format,
184                                        uint32_t width,
185                                        uint32_t height,
186                                        uint32_t depth,
187                                        uint32_t mips,
188                                        bool renderTargetOnly,
189                                        bool allowFormatView,
190                                        TextureRef *refOut);
191     static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
192 
193     // Allow CPU to read & write data directly to this texture?
194     bool isCPUAccessible() const;
195     // Allow shaders to read/sample this texture?
196     // Texture created with renderTargetOnly flag won't be readable
197     bool isShaderReadable() const;
198     // Allow shaders to write this texture?
199     bool isShaderWritable() const;
200 
201     bool supportFormatView() const;
202 
203     void replace2DRegion(ContextMtl *context,
204                          const MTLRegion &region,
205                          const MipmapNativeLevel &mipmapLevel,
206                          uint32_t slice,
207                          const uint8_t *data,
208                          size_t bytesPerRow);
209 
210     void replaceRegion(ContextMtl *context,
211                        const MTLRegion &region,
212                        const MipmapNativeLevel &mipmapLevel,
213                        uint32_t slice,
214                        const uint8_t *data,
215                        size_t bytesPerRow,
216                        size_t bytesPer2DImage);
217 
218     void getBytes(ContextMtl *context,
219                   size_t bytesPerRow,
220                   size_t bytesPer2DInage,
221                   const MTLRegion &region,
222                   const MipmapNativeLevel &mipmapLevel,
223                   uint32_t slice,
224                   uint8_t *dataOut);
225 
226     // Create 2d view of a cube face which full range of mip levels.
227     TextureRef createCubeFaceView(uint32_t face);
228     // Create a view of one slice at a level.
229     TextureRef createSliceMipView(uint32_t slice, const MipmapNativeLevel &level);
230     // Create a levels range view
231     TextureRef createMipsView(const MipmapNativeLevel &baseLevel, uint32_t levels);
232     // Create a view of a level.
233     TextureRef createMipView(const MipmapNativeLevel &level);
234     // Create a view with different format
235     TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
236     // Create a view for a shader image binding.
237     TextureRef createShaderImageView2D(const MipmapNativeLevel &level,
238                                        int layer,
239                                        MTLPixelFormat format);
240     // Same as above but the target format must be compatible, for example sRGB to linear. In
241     // this case texture doesn't need format view usage flag.
242     TextureRef createViewWithCompatibleFormat(MTLPixelFormat format);
243     // Create a swizzled view
244     TextureRef createMipsSwizzleView(const MipmapNativeLevel &baseLevel,
245                                      uint32_t levels,
246                                      MTLPixelFormat format,
247                                      const TextureSwizzleChannels &swizzle);
248 
249     MTLTextureType textureType() const;
250     MTLPixelFormat pixelFormat() const;
251 
252     uint32_t mipmapLevels() const;
253     uint32_t arrayLength() const;
254     uint32_t cubeFaces() const;
255     uint32_t cubeFacesOrArrayLength() const;
256 
257     uint32_t width(const MipmapNativeLevel &level) const;
258     uint32_t height(const MipmapNativeLevel &level) const;
259     uint32_t depth(const MipmapNativeLevel &level) const;
260 
261     gl::Extents size(const MipmapNativeLevel &level) const;
262     gl::Extents size(const ImageNativeIndex &index) const;
263 
widthAt0()264     uint32_t widthAt0() const { return width(kZeroNativeMipLevel); }
heightAt0()265     uint32_t heightAt0() const { return height(kZeroNativeMipLevel); }
depthAt0()266     uint32_t depthAt0() const { return depth(kZeroNativeMipLevel); }
sizeAt0()267     gl::Extents sizeAt0() const { return size(kZeroNativeMipLevel); }
268 
269     uint32_t samples() const;
270 
271     bool hasIOSurface() const;
272     bool sameTypeAndDimemsionsAs(const TextureRef &other) const;
273 
274     angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height);
275 
276     // For render target
getColorWritableMask()277     MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
setColorWritableMask(MTLColorWriteMask mask)278     void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
279 
280     // Get reading copy. Used for reading non-readable texture or reading stencil value from
281     // packed depth & stencil texture.
282     // NOTE: this only copies 1 depth slice of the 3D texture.
283     // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture.
284     // The returned pointer will be retained by the original texture object.
285     // Calling getReadableCopy() will overwrite previously returned texture.
286     TextureRef getReadableCopy(ContextMtl *context,
287                                mtl::BlitCommandEncoder *encoder,
288                                const uint32_t levelToCopy,
289                                const uint32_t sliceToCopy,
290                                const MTLRegion &areaToCopy);
291 
292     void releaseReadableCopy();
293 
294     // Get stencil view
295     TextureRef getStencilView();
296     // Get linear color
297     TextureRef getLinearColorView();
298 
299     TextureRef parentTexture();
300     MipmapNativeLevel parentRelativeLevel();
301     uint32_t parentRelativeSlice();
302 
303     // Change the wrapped metal object. Special case for swapchain image
304     void set(id<MTLTexture> metalTexture);
305 
306     // Explicitly sync content between CPU and GPU
307     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
setEstimatedByteSize(size_t bytes)308     void setEstimatedByteSize(size_t bytes) { mEstimatedByteSize = bytes; }
estimatedByteSize()309     size_t estimatedByteSize() const override { return mEstimatedByteSize; }
getID()310     id getID() const override { return get(); }
311 
312   private:
313     using ParentClass = WrappedObject<id<MTLTexture>>;
314 
315     static angle::Result MakeTexture(ContextMtl *context,
316                                      const Format &mtlFormat,
317                                      MTLTextureDescriptor *desc,
318                                      uint32_t mips,
319                                      bool renderTargetOnly,
320                                      bool allowFormatView,
321                                      TextureRef *refOut);
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                                      bool memoryLess,
330                                      TextureRef *refOut);
331 
332     static angle::Result MakeTexture(ContextMtl *context,
333                                      const Format &mtlFormat,
334                                      MTLTextureDescriptor *desc,
335                                      IOSurfaceRef surfaceRef,
336                                      NSUInteger slice,
337                                      bool renderTargetOnly,
338                                      TextureRef *refOut);
339 
340     Texture(id<MTLTexture> metalTexture);
341 
342     // Create a texture that shares ownership of usageRef, underlying MTLTexture and colorWriteMask
343     // with the original texture.
344     Texture(std::shared_ptr<UsageRef> usageRef,
345             id<MTLTexture> metalTexture,
346             std::shared_ptr<MTLColorWriteMask> colorWriteMask);
347 
348     Texture(ContextMtl *context,
349             MTLTextureDescriptor *desc,
350             uint32_t mips,
351             bool renderTargetOnly,
352             bool allowFormatView);
353     Texture(ContextMtl *context,
354             MTLTextureDescriptor *desc,
355             uint32_t mips,
356             bool renderTargetOnly,
357             bool allowFormatView,
358             bool memoryLess);
359 
360     Texture(ContextMtl *context,
361             MTLTextureDescriptor *desc,
362             IOSurfaceRef iosurface,
363             NSUInteger plane,
364             bool renderTargetOnly);
365 
366     // Create a texture view
367     Texture(Texture *original, MTLPixelFormat pixelFormat);
368     Texture(Texture *original,
369             MTLPixelFormat pixelFormat,
370             MTLTextureType textureType,
371             NSRange levels,
372             NSRange slices);
373     Texture(Texture *original,
374             MTLPixelFormat pixelFormat,
375             MTLTextureType textureType,
376             NSRange levels,
377             NSRange slices,
378             const TextureSwizzleChannels &swizzle);
379 
380     void syncContentIfNeeded(ContextMtl *context);
381 
382     AutoObjCObj<MTLTextureDescriptor> mCreationDesc;
383 
384     // This property is shared between this object and its views:
385     std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
386 
387     // Linear view of sRGB texture
388     TextureRef mLinearColorView;
389 
390     TextureRef mStencilView;
391     // Readable copy of texture
392     TextureRef mReadCopy;
393 
394     TextureRef mParentTexture;
395 
396     size_t mEstimatedByteSize = 0;
397 };
398 
399 class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
400 {
401   public:
402     static MTLStorageMode getStorageModeForSharedBuffer(ContextMtl *contextMtl);
403     using Usage = gl::BufferUsage;
404     static MTLStorageMode getStorageModeForUsage(ContextMtl *context, Usage usage);
405 
406     static angle::Result MakeBuffer(ContextMtl *context,
407                                     size_t size,
408                                     const uint8_t *data,
409                                     BufferRef *bufferOut);
410 
411     static angle::Result MakeBufferWithStorageMode(ContextMtl *context,
412                                                    MTLStorageMode storageMode,
413                                                    size_t size,
414                                                    const uint8_t *data,
415                                                    BufferRef *bufferOut);
416 
417     angle::Result reset(ContextMtl *context,
418                         MTLStorageMode storageMode,
419                         size_t size,
420                         const uint8_t *data);
421 
422     const uint8_t *mapReadOnly(ContextMtl *context);
423     uint8_t *map(ContextMtl *context);
424     uint8_t *mapWithOpt(ContextMtl *context, bool readonly, bool noSync);
425 
426     void unmap(ContextMtl *context);
427     // Same as unmap but do not do implicit flush()
428     void unmapNoFlush(ContextMtl *context);
429     void unmapAndFlushSubset(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
430     void flush(ContextMtl *context, size_t offsetWritten, size_t sizeWritten);
431 
432     size_t size() const;
433     MTLStorageMode storageMode() const;
434 
435     // Explicitly sync content between CPU and GPU
436     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
437 
estimatedByteSize()438     size_t estimatedByteSize() const override { return size(); }
getID()439     id getID() const override { return get(); }
440 
getNumContextSwitchesAtLastUse()441     size_t getNumContextSwitchesAtLastUse() { return mContextSwitchesAtLastUse; }
setNumContextSwitchesAtLastUse(size_t num)442     void setNumContextSwitchesAtLastUse(size_t num) { mContextSwitchesAtLastUse = num; }
getNumCommandBufferCommitsAtLastUse()443     size_t getNumCommandBufferCommitsAtLastUse() { return mCommandBufferCommitsAtLastUse; }
setNumCommandBufferCommitsAtLastUse(size_t num)444     void setNumCommandBufferCommitsAtLastUse(size_t num) { mCommandBufferCommitsAtLastUse = num; }
445 
446   private:
447     Buffer(ContextMtl *context, MTLStorageMode storageMode, size_t size, const uint8_t *data);
448 
449     bool mMapReadOnly = true;
450     // For garbage collecting shadow buffers in BufferManager.
451     size_t mContextSwitchesAtLastUse      = 0;
452     size_t mCommandBufferCommitsAtLastUse = 0;
453 };
454 
455 class NativeTexLevelArray
456 {
457   public:
at(const MipmapNativeLevel & level)458     TextureRef &at(const MipmapNativeLevel &level) { return mTexLevels.at(level.get()); }
at(const MipmapNativeLevel & level)459     const TextureRef &at(const MipmapNativeLevel &level) const
460     {
461         return mTexLevels.at(level.get());
462     }
463 
464     TextureRef &operator[](const MipmapNativeLevel &level) { return at(level); }
465     const TextureRef &operator[](const MipmapNativeLevel &level) const { return at(level); }
466 
begin()467     gl::TexLevelArray<TextureRef>::iterator begin() { return mTexLevels.begin(); }
begin()468     gl::TexLevelArray<TextureRef>::const_iterator begin() const { return mTexLevels.begin(); }
end()469     gl::TexLevelArray<TextureRef>::iterator end() { return mTexLevels.end(); }
end()470     gl::TexLevelArray<TextureRef>::const_iterator end() const { return mTexLevels.end(); }
471 
472   private:
473     gl::TexLevelArray<TextureRef> mTexLevels;
474 };
475 
476 }  // namespace mtl
477 }  // namespace rx
478 
479 #endif /* LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_ */
480