• 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/ImageIndex.h"
23 #include "libANGLE/angletypes.h"
24 #include "libANGLE/renderer/metal/mtl_common.h"
25 #include "libANGLE/renderer/metal/mtl_format_utils.h"
26 
27 namespace rx
28 {
29 
30 class ContextMtl;
31 
32 namespace mtl
33 {
34 
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     bool isBeingUsedByGPU(Context *context) const;
53 
54     void setUsedByCommandBufferWithQueueSerial(uint64_t serial, bool writing);
55 
getCommandBufferQueueSerial()56     const std::atomic<uint64_t> &getCommandBufferQueueSerial() const
57     {
58         return mUsageRef->cmdBufferQueueSerial;
59     }
60 
61     // Flag indicate whether we should synchornize the content to CPU after GPU changed this
62     // resource's content.
isCPUReadMemDirty()63     bool isCPUReadMemDirty() const { return mUsageRef->cpuReadMemDirty; }
resetCPUReadMemDirty()64     void resetCPUReadMemDirty() { mUsageRef->cpuReadMemDirty = false; }
65 
66   protected:
67     Resource();
68     // Share the GPU usage ref with other resource
69     Resource(Resource *other);
70 
71   private:
72     struct UsageRef
73     {
74         // The id of the last command buffer that is using this resource.
75         std::atomic<uint64_t> cmdBufferQueueSerial{0};
76 
77         // NOTE(hqle): resource dirty handle is not threadsafe.
78         // This flag means the resource was issued to be modified by GPU, if CPU wants to read
79         // its content, explicit synchornization call must be invoked.
80         bool cpuReadMemDirty = false;
81     };
82 
83     // One resource object might just be a view of another resource. For example, a texture 2d
84     // object might be a view of one face of a cube texture object. Another example is one texture
85     // object of size 2x2 might be a mipmap view of a texture object size 4x4. Thus, if one object
86     // is being used by a command buffer, it means the other object is being used also. In this
87     // case, the two objects must share the same UsageRef property.
88     std::shared_ptr<UsageRef> mUsageRef;
89 };
90 
91 class Texture final : public Resource,
92                       public WrappedObject<id<MTLTexture>>,
93                       public std::enable_shared_from_this<Texture>
94 {
95   public:
96     static angle::Result Make2DTexture(ContextMtl *context,
97                                        const Format &format,
98                                        uint32_t width,
99                                        uint32_t height,
100                                        uint32_t mips /** use zero to create full mipmaps chain */,
101                                        bool renderTargetOnly,
102                                        bool allowTextureView,
103                                        TextureRef *refOut);
104 
105     static angle::Result MakeCubeTexture(ContextMtl *context,
106                                          const Format &format,
107                                          uint32_t size,
108                                          uint32_t mips /** use zero to create full mipmaps chain */,
109                                          bool renderTargetOnly,
110                                          bool allowTextureView,
111                                          TextureRef *refOut);
112 
113     static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
114 
115     // Allow CPU to read & write data directly to this texture?
116     bool isCPUAccessible() const;
117 
118     void replaceRegion(ContextMtl *context,
119                        MTLRegion region,
120                        uint32_t mipmapLevel,
121                        uint32_t slice,
122                        const uint8_t *data,
123                        size_t bytesPerRow);
124 
125     // read pixel data from slice 0
126     void getBytes(ContextMtl *context,
127                   size_t bytesPerRow,
128                   MTLRegion region,
129                   uint32_t mipmapLevel,
130                   uint8_t *dataOut);
131 
132     // Create 2d view of a cube face which full range of mip levels.
133     TextureRef createCubeFaceView(uint32_t face);
134     // Create a view of one slice at a level.
135     TextureRef createSliceMipView(uint32_t slice, uint32_t level);
136     // Create a view with different format
137     TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
138 
139     MTLTextureType textureType() const;
140     MTLPixelFormat pixelFormat() const;
141 
142     uint32_t mipmapLevels() const;
143 
144     uint32_t width(uint32_t level = 0) const;
145     uint32_t height(uint32_t level = 0) const;
146 
147     gl::Extents size(uint32_t level = 0) const;
148     gl::Extents size(const gl::ImageIndex &index) const;
149 
150     // For render target
getColorWritableMask()151     MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
setColorWritableMask(MTLColorWriteMask mask)152     void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
153 
154     // Change the wrapped metal object. Special case for swapchain image
155     void set(id<MTLTexture> metalTexture);
156 
157     // sync content between CPU and GPU
158     void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder);
159 
160   private:
161     using ParentClass = WrappedObject<id<MTLTexture>>;
162 
163     Texture(id<MTLTexture> metalTexture);
164     Texture(ContextMtl *context,
165             MTLTextureDescriptor *desc,
166             uint32_t mips,
167             bool renderTargetOnly,
168             bool supportTextureView);
169 
170     // Create a texture view
171     Texture(Texture *original, MTLPixelFormat format);
172     Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, uint32_t slice);
173 
174     void syncContent(ContextMtl *context);
175 
176     // This property is shared between this object and its views:
177     std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
178 };
179 
180 class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
181 {
182   public:
183     static angle::Result MakeBuffer(ContextMtl *context,
184                                     size_t size,
185                                     const uint8_t *data,
186                                     BufferRef *bufferOut);
187 
188     angle::Result reset(ContextMtl *context, size_t size, const uint8_t *data);
189 
190     uint8_t *map(ContextMtl *context);
191     void unmap(ContextMtl *context);
192 
193     size_t size() const;
194 
195   private:
196     Buffer(ContextMtl *context, size_t size, const uint8_t *data);
197 };
198 
199 }  // namespace mtl
200 }  // namespace rx
201 
202 #endif /* LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_ */
203