Optimizing texture data
Optimize a texture’s data to improve GPU or CPU access.
Overview
By default, Metal attempts to optimize a texture’s data for both GPU and CPU memory operations based on the texture’s storage mode and usage options. You can improve a texture’s performance on the GPU or CPU by optimizing the texture’s data for either use case. You can also opt out of optimization altogether. Optimizing a texture’s performance for one use can decrease that texture’s performance for another.
Before optimizing texture data, carefully consider the storage modes and usage options for your textures. For guidance on resource storage modes, see Setting resource storage modes. For guidance on texture usage options, see MTLTextureUsage.
Optimize texture data for GPU access
By default, Metal attempts to optimize texture data for GPU access if it meets any of these conditions:
You create the texture with an MTLStorageMode.private mode.
You create the texture with an renderTarget option.
If the texture doesn’t meet any of these conditions, you can optimize your texture data explicitly. After you create your texture and populate its contents, encode and commit an optimizeContentsForGPUAccess(texture:) or optimizeContentsForGPUAccess(texture:slice:level:) command.
To optimize a drawable from an MTKView for GPU access, set the view’s framebufferOnly property to true. This property configures the texture exclusively as a render target and displayable resource.
Optimize texture data for CPU access
By default, Metal attempts to optimize texture data for CPU access if it meets both of these conditions:
You create the texture with an MTLStorageMode.shared or MTLStorageMode.managed mode.
You write to the texture with the replace(region:mipmapLevel:withBytes:bytesPerRow:) or replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:) method.
If you don’t meet both of these conditions, you can optimize your texture data explicitly. After you create your texture and populate its contents, encode and commit an optimizeContentsForCPUAccess(texture:) or optimizeContentsForCPUAccess(texture:slice:level:) command.
Apply lossless compression to a texture on Apple GPUs
Lossless compression is a specific form of GPU optimization that Metal applies to a texture without discarding any of its data. Memory operations with textures that apply lossless compression typically need less memory bandwidth than equivalent memory operations with the same texture without compression. However, the overall memory footprint of a texture with lossless compression might increase slightly because it needs to store compression metadata. On devices that support MTLGPUFamily.apple5, Metal attempts to apply lossless compression to a texture if it meets the following conditions:
The texture’s pixel format doesn’t apply block-compression, such as PVRTC, ASTC, or BC.
The texture’s usage options don’t include unknown, shaderWrite, or pixelFormatView.
The texture doesn’t use any underlying MTLBuffer instance, such as a texture that comes from a buffer’s makeTexture(descriptor:offset:bytesPerRow:) method.
Additionally, if you meet both of the following conditions, you can optimize your texture data explicitly so Metal can apply lossless compression:
You create the texture with an MTLStorageMode.shared mode.
You write to the texture with the replace(region:mipmapLevel:withBytes:bytesPerRow:) or replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:) method.
For guidance, see Optimize texture data for GPU access.
Opt out of texture data optimization for GPU access
In some cases, your texture data may benefit from opting out of optimization for GPU access, for example, when optimization regresses your app’s performance (particularly for render target read-backs on the CPU).
First, create a texture descriptor and set its allowGPUOptimizedContents property to false.
Then, set the texture descriptor’s storageMode property to MTLStorageMode.shared or MTLStorageMode.managed.
Finally, create a texture from the texture descriptor.