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