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