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