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