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