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