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