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 MakeMemoryLess2DMSTexture(ContextMtl *context, 150 const Format &format, 151 uint32_t width, 152 uint32_t height, 153 uint32_t samples, 154 TextureRef *refOut); 155 156 static angle::Result MakeCubeTexture(ContextMtl *context, 157 const Format &format, 158 uint32_t size, 159 uint32_t mips /** use zero to create full mipmaps chain */, 160 bool renderTargetOnly, 161 bool allowFormatView, 162 TextureRef *refOut); 163 164 static angle::Result Make2DMSTexture(ContextMtl *context, 165 const Format &format, 166 uint32_t width, 167 uint32_t height, 168 uint32_t samples, 169 bool renderTargetOnly, 170 bool allowFormatView, 171 TextureRef *refOut); 172 173 static angle::Result Make2DArrayTexture(ContextMtl *context, 174 const Format &format, 175 uint32_t width, 176 uint32_t height, 177 uint32_t mips, 178 uint32_t arrayLength, 179 bool renderTargetOnly, 180 bool allowFormatView, 181 TextureRef *refOut); 182 183 static angle::Result Make3DTexture(ContextMtl *context, 184 const Format &format, 185 uint32_t width, 186 uint32_t height, 187 uint32_t depth, 188 uint32_t mips, 189 bool renderTargetOnly, 190 bool allowFormatView, 191 TextureRef *refOut); 192 static TextureRef MakeFromMetal(id<MTLTexture> metalTexture); 193 194 // Allow CPU to read & write data directly to this texture? 195 bool isCPUAccessible() const; 196 // Allow shaders to read/sample this texture? 197 // Texture created with renderTargetOnly flag won't be readable 198 bool isShaderReadable() const; 199 // Allow shaders to write this texture? 200 bool isShaderWritable() const; 201 202 bool supportFormatView() const; 203 204 void replace2DRegion(ContextMtl *context, 205 const MTLRegion ®ion, 206 const MipmapNativeLevel &mipmapLevel, 207 uint32_t slice, 208 const uint8_t *data, 209 size_t bytesPerRow); 210 211 void replaceRegion(ContextMtl *context, 212 const MTLRegion ®ion, 213 const MipmapNativeLevel &mipmapLevel, 214 uint32_t slice, 215 const uint8_t *data, 216 size_t bytesPerRow, 217 size_t bytesPer2DImage); 218 219 void getBytes(ContextMtl *context, 220 size_t bytesPerRow, 221 size_t bytesPer2DInage, 222 const MTLRegion ®ion, 223 const MipmapNativeLevel &mipmapLevel, 224 uint32_t slice, 225 uint8_t *dataOut); 226 227 // Create 2d view of a cube face which full range of mip levels. 228 TextureRef createCubeFaceView(uint32_t face); 229 // Create a view of one slice at a level. 230 TextureRef createSliceMipView(uint32_t slice, const MipmapNativeLevel &level); 231 // Create a levels range view 232 TextureRef createMipsView(const MipmapNativeLevel &baseLevel, uint32_t levels); 233 // Create a view of a level. 234 TextureRef createMipView(const MipmapNativeLevel &level); 235 // Create a view with different format 236 TextureRef createViewWithDifferentFormat(MTLPixelFormat format); 237 // Create a view for a shader image binding. 238 TextureRef createShaderImageView2D(const MipmapNativeLevel &level, 239 int layer, 240 MTLPixelFormat format); 241 // Same as above but the target format must be compatible, for example sRGB to linear. In 242 // this case texture doesn't need format view usage flag. 243 TextureRef createViewWithCompatibleFormat(MTLPixelFormat format); 244 // Create a swizzled view 245 TextureRef createMipsSwizzleView(const MipmapNativeLevel &baseLevel, 246 uint32_t levels, 247 MTLPixelFormat format, 248 const MTLTextureSwizzleChannels &swizzle); 249 250 MTLTextureType textureType() const; 251 MTLPixelFormat pixelFormat() const; 252 253 uint32_t mipmapLevels() const; 254 uint32_t arrayLength() const; 255 uint32_t cubeFaces() const; 256 uint32_t cubeFacesOrArrayLength() const; 257 258 uint32_t width(const MipmapNativeLevel &level) const; 259 uint32_t height(const MipmapNativeLevel &level) const; 260 uint32_t depth(const MipmapNativeLevel &level) const; 261 262 gl::Extents size(const MipmapNativeLevel &level) const; 263 gl::Extents size(const ImageNativeIndex &index) const; 264 widthAt0()265 uint32_t widthAt0() const { return width(kZeroNativeMipLevel); } heightAt0()266 uint32_t heightAt0() const { return height(kZeroNativeMipLevel); } depthAt0()267 uint32_t depthAt0() const { return depth(kZeroNativeMipLevel); } sizeAt0()268 gl::Extents sizeAt0() const { return size(kZeroNativeMipLevel); } 269 270 uint32_t samples() const; 271 272 bool hasIOSurface() const; 273 bool sameTypeAndDimemsionsAs(const TextureRef &other) const; 274 275 angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height); 276 277 // Get the color write mask to restrict writing to certain color channels in this texture. It's 278 // used for textures having emulated mtl::Format such as RGB which should always have alpha 279 // value being one. getColorWritableMask()280 MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; } setColorWritableMask(MTLColorWriteMask mask)281 void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; } 282 283 // Get reading copy. Used for reading non-readable texture or reading stencil value from 284 // packed depth & stencil texture. 285 // NOTE: this only copies 1 depth slice of the 3D texture. 286 // The texels will be copied to region(0, 0, 0, areaToCopy.size) of the returned texture. 287 // The returned pointer will be retained by the original texture object. 288 // Calling getReadableCopy() will overwrite previously returned texture. 289 TextureRef getReadableCopy(ContextMtl *context, 290 mtl::BlitCommandEncoder *encoder, 291 const uint32_t levelToCopy, 292 const uint32_t sliceToCopy, 293 const MTLRegion &areaToCopy); 294 295 void releaseReadableCopy(); 296 297 // Get stencil view 298 TextureRef getStencilView(); 299 // Get linear color 300 TextureRef getLinearColorView(); 301 302 TextureRef parentTexture(); 303 MipmapNativeLevel parentRelativeLevel(); 304 uint32_t parentRelativeSlice(); 305 306 // Change the wrapped metal object. Special case for swapchain image 307 void set(id<MTLTexture> metalTexture); 308 309 // Explicitly sync content between CPU and GPU 310 void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder); setEstimatedByteSize(size_t bytes)311 void setEstimatedByteSize(size_t bytes) { mEstimatedByteSize = bytes; } estimatedByteSize()312 size_t estimatedByteSize() const override { return mEstimatedByteSize; } getID()313 id getID() const override { return get(); } 314 315 // Should we disable MTLLoadActionLoad & MTLStoreActionStore when using this texture 316 // as render pass' attachment. This is usually used for memoryless textures and 317 // EXT_multisampled_render_to_texture. shouldNotLoadStore()318 bool shouldNotLoadStore() const { return mShouldNotLoadStore; } 319 320 private: 321 using ParentClass = WrappedObject<id<MTLTexture>>; 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 TextureRef *refOut); 330 331 static angle::Result MakeTexture(ContextMtl *context, 332 const Format &mtlFormat, 333 MTLTextureDescriptor *desc, 334 uint32_t mips, 335 bool renderTargetOnly, 336 bool allowFormatView, 337 bool memoryLess, 338 TextureRef *refOut); 339 340 static angle::Result MakeTexture(ContextMtl *context, 341 const Format &mtlFormat, 342 MTLTextureDescriptor *desc, 343 IOSurfaceRef surfaceRef, 344 NSUInteger slice, 345 bool renderTargetOnly, 346 TextureRef *refOut); 347 348 Texture(id<MTLTexture> metalTexture); 349 350 // Create a texture that shares ownership of usageRef, underlying MTLTexture and colorWriteMask 351 // with the original texture. 352 Texture(std::shared_ptr<UsageRef> usageRef, 353 id<MTLTexture> metalTexture, 354 std::shared_ptr<MTLColorWriteMask> colorWriteMask); 355 356 Texture(ContextMtl *context, 357 MTLTextureDescriptor *desc, 358 uint32_t mips, 359 bool renderTargetOnly, 360 bool allowFormatView); 361 Texture(ContextMtl *context, 362 MTLTextureDescriptor *desc, 363 uint32_t mips, 364 bool renderTargetOnly, 365 bool allowFormatView, 366 bool memoryLess); 367 368 Texture(ContextMtl *context, 369 MTLTextureDescriptor *desc, 370 IOSurfaceRef iosurface, 371 NSUInteger plane, 372 bool renderTargetOnly); 373 374 // Create a texture view 375 Texture(Texture *original, MTLPixelFormat pixelFormat); 376 Texture(Texture *original, 377 MTLPixelFormat pixelFormat, 378 MTLTextureType textureType, 379 NSRange levels, 380 NSRange slices); 381 Texture(Texture *original, 382 MTLPixelFormat pixelFormat, 383 MTLTextureType textureType, 384 NSRange levels, 385 NSRange slices, 386 const MTLTextureSwizzleChannels &swizzle); 387 388 void syncContentIfNeeded(ContextMtl *context); 389 390 AutoObjCObj<MTLTextureDescriptor> mCreationDesc; 391 392 // This property is shared between this object and its views: 393 std::shared_ptr<MTLColorWriteMask> mColorWritableMask; 394 395 // Linear view of sRGB texture 396 TextureRef mLinearColorView; 397 398 TextureRef mStencilView; 399 // Readable copy of texture 400 TextureRef mReadCopy; 401 402 TextureRef mParentTexture; 403 404 size_t mEstimatedByteSize = 0; 405 406 bool mShouldNotLoadStore = false; 407 }; 408 409 class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>> 410 { 411 public: 412 static MTLStorageMode getStorageModeForSharedBuffer(ContextMtl *contextMtl); 413 using Usage = gl::BufferUsage; 414 static MTLStorageMode getStorageModeForUsage(ContextMtl *context, Usage usage); 415 416 static angle::Result MakeBuffer(ContextMtl *context, 417 size_t size, 418 const uint8_t *data, 419 BufferRef *bufferOut); 420 421 static angle::Result MakeBufferWithStorageMode(ContextMtl *context, 422 MTLStorageMode storageMode, 423 size_t size, 424 const uint8_t *data, 425 BufferRef *bufferOut); 426 427 angle::Result reset(ContextMtl *context, 428 MTLStorageMode storageMode, 429 size_t size, 430 const uint8_t *data); 431 432 const uint8_t *mapReadOnly(ContextMtl *context); 433 uint8_t *map(ContextMtl *context); 434 uint8_t *mapWithOpt(ContextMtl *context, bool readonly, bool noSync); 435 436 void unmap(ContextMtl *context); 437 // Same as unmap but do not do implicit flush() 438 void unmapNoFlush(ContextMtl *context); 439 void unmapAndFlushSubset(ContextMtl *context, size_t offsetWritten, size_t sizeWritten); 440 void flush(ContextMtl *context, size_t offsetWritten, size_t sizeWritten); 441 442 size_t size() const; 443 MTLStorageMode storageMode() const; 444 445 // Explicitly sync content between CPU and GPU 446 void syncContent(ContextMtl *context, mtl::BlitCommandEncoder *encoder); 447 estimatedByteSize()448 size_t estimatedByteSize() const override { return size(); } getID()449 id getID() const override { return get(); } 450 getNumContextSwitchesAtLastUse()451 size_t getNumContextSwitchesAtLastUse() { return mContextSwitchesAtLastUse; } setNumContextSwitchesAtLastUse(size_t num)452 void setNumContextSwitchesAtLastUse(size_t num) { mContextSwitchesAtLastUse = num; } getNumCommandBufferCommitsAtLastUse()453 size_t getNumCommandBufferCommitsAtLastUse() { return mCommandBufferCommitsAtLastUse; } setNumCommandBufferCommitsAtLastUse(size_t num)454 void setNumCommandBufferCommitsAtLastUse(size_t num) { mCommandBufferCommitsAtLastUse = num; } 455 456 private: 457 Buffer(ContextMtl *context, MTLStorageMode storageMode, size_t size, const uint8_t *data); 458 459 bool mMapReadOnly = true; 460 // For garbage collecting shadow buffers in BufferManager. 461 size_t mContextSwitchesAtLastUse = 0; 462 size_t mCommandBufferCommitsAtLastUse = 0; 463 }; 464 465 class NativeTexLevelArray 466 { 467 public: at(const MipmapNativeLevel & level)468 TextureRef &at(const MipmapNativeLevel &level) { return mTexLevels.at(level.get()); } at(const MipmapNativeLevel & level)469 const TextureRef &at(const MipmapNativeLevel &level) const 470 { 471 return mTexLevels.at(level.get()); 472 } 473 474 TextureRef &operator[](const MipmapNativeLevel &level) { return at(level); } 475 const TextureRef &operator[](const MipmapNativeLevel &level) const { return at(level); } 476 begin()477 gl::TexLevelArray<TextureRef>::iterator begin() { return mTexLevels.begin(); } begin()478 gl::TexLevelArray<TextureRef>::const_iterator begin() const { return mTexLevels.begin(); } end()479 gl::TexLevelArray<TextureRef>::iterator end() { return mTexLevels.end(); } end()480 gl::TexLevelArray<TextureRef>::const_iterator end() const { return mTexLevels.end(); } 481 482 private: 483 gl::TexLevelArray<TextureRef> mTexLevels; 484 }; 485 486 } // namespace mtl 487 } // namespace rx 488 489 #endif /* LIBANGLE_RENDERER_METAL_MTL_RESOURCES_H_ */ 490