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