<!--
{
  "documentType" : "article",
  "framework" : "Metal",
  "identifier" : "/documentation/Metal/optimizing-texture-data",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Optimizing texture data"
}
-->

# Optimizing texture data

Optimize a texture’s data to improve GPU or CPU access.

## Discussion

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](/documentation/Metal/setting-resource-storage-modes).
For guidance on texture usage options, see [`MTLTextureUsage`](/documentation/Metal/MTLTextureUsage).

> Note:
> Metal may not be able to optimize some textures for specific hardware and ignores optimization API calls for those textures.

### 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`](/documentation/Metal/MTLStorageMode/private) mode.
- You create the texture with an [`renderTarget`](/documentation/Metal/MTLTextureUsage/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:)`](/documentation/Metal/MTLBlitCommandEncoder/optimizeContentsForGPUAccess(texture:)) or
[`optimizeContentsForGPUAccess(texture:slice:level:)`](/documentation/Metal/MTLBlitCommandEncoder/optimizeContentsForGPUAccess(texture:slice:level:)) command.

```objective-c
// Create the first texture.
id <MTLTexture> texture1GPUOptimized;
...

// Put content in the texture.
...

// Create a command buffer to submit work to the GPU.
id <MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];

// Optimize the texture for GPU access by encoding a blit command.
id <MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder optimizeContentsForGPUAccess:texture1GPUOptimized];

// End the encoding.
[blitEncoder endEncoding];

// Add a completion handler.
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer) {
    // The GPU can now optimally access the contents of texture 1.
    ...
}];

// Commit the command buffer to the command queue.
[commandBuffer commit];
```

To optimize a drawable from an
<doc://com.apple.documentation/documentation/MetalKit/MTKView> for GPU access, set the view’s
<doc://com.apple.documentation/documentation/MetalKit/MTKView/framebufferOnly> property to
<doc://com.apple.documentation/documentation/Swift/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`](/documentation/Metal/MTLStorageMode/shared) or [`MTLStorageMode.managed`](/documentation/Metal/MTLStorageMode/managed) mode.
- You write to the texture with the [`replace(region:mipmapLevel:withBytes:bytesPerRow:)`](/documentation/Metal/MTLTexture/replace(region:mipmapLevel:withBytes:bytesPerRow:)) or
  [`replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)`](/documentation/Metal/MTLTexture/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:)`](/documentation/Metal/MTLBlitCommandEncoder/optimizeContentsForCPUAccess(texture:)) or
[`optimizeContentsForCPUAccess(texture:slice:level:)`](/documentation/Metal/MTLBlitCommandEncoder/optimizeContentsForCPUAccess(texture:slice:level:)) command.

```objective-c
// Create a second texture.
id <MTLTexture> texture2CPUOptimized;
...

// Put content in the texture.
...

// Create a command buffer to submit work to the GPU.
id <MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];

// Optimize the texture for CPU access by encoding a blit command.
id <MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder optimizeContentsForCPUAccess:texture2CPUOptimized];

// End encoding and commit it to the command buffer with add a completion handler.
[blitEncoder endEncoding];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer) {
    // The CPU can now optimally access the contents of texture 2.
    ...
}];

// Commit the command buffer to the command queue.
[commandBuffer commit];
```

### 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`](/documentation/Metal/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`](/documentation/Metal/MTLTextureUsage/unknown),
  [`shaderWrite`](/documentation/Metal/MTLTextureUsage/shaderWrite), or
  [`pixelFormatView`](/documentation/Metal/MTLTextureUsage/pixelFormatView).
- The texture doesn’t use any underlying [`MTLBuffer`](/documentation/Metal/MTLBuffer) instance,
  such as a texture that comes from a buffer’s
  [`makeTexture(descriptor:offset:bytesPerRow:)`](/documentation/Metal/MTLBuffer/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`](/documentation/Metal/MTLStorageMode/shared) mode.
- You write to the texture with the [`replace(region:mipmapLevel:withBytes:bytesPerRow:)`](/documentation/Metal/MTLTexture/replace(region:mipmapLevel:withBytes:bytesPerRow:)) or [`replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)`](/documentation/Metal/MTLTexture/replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:)) method.

For guidance, see [Optimize texture data for GPU access](/documentation/Metal/optimizing-texture-data#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`](/documentation/Metal/MTLTextureDescriptor/allowGPUOptimizedContents) property to
<doc://com.apple.documentation/documentation/Swift/false>.

```objective-c
MTLTextureDescriptor *textureDescriptor =
 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
                                                    width:512
                                                   height:512
                                                mipmapped:NO];

// Don't allow the the GPU to optimize the texture.
textureDescriptor.allowGPUOptimizedContents = NO;
```

Then, set the texture descriptor’s [`storageMode`](/documentation/Metal/MTLTextureDescriptor/storageMode) property to
[`MTLStorageMode.shared`](/documentation/Metal/MTLStorageMode/shared) or [`MTLStorageMode.managed`](/documentation/Metal/MTLStorageMode/managed).

```objective-c
// Set the texture descriptor's storage mode to `shared` or `managed` based on the GPU family.

if ([device supportsFamily:MTLGPUFamilyApple1]) {
    textureDescriptor.storageMode = MTLStorageModeShared;
} else {
    textureDescriptor.storageMode = MTLStorageModeManaged;
}
```

Finally, create a texture from the texture descriptor.

```objective-c
// Create a texture using the texture descriptor.
id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
```

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)