One Logo Pool Ball
RealityFoundation · IOS API REFERENCE

LowLevelTexture

class · iOS 18.0+ · SDK 27.1

@MainActor class LowLevelTexture

A container for texture data allowing you to create and update textures using your own format. Use `LowLevelTexture` when you want to bring your own texture data to RealityKit, or update your data frequently. You update the data on the GPU with Metal compute shaders. This is ideal for bringing your own textures to RealityKit as-is, or when you intend to update your data frequently. - Note: For a simpler alternative, consider creating your ``TextureResource`` from a <doc://com.apple.documentation/documentation/coregraphics/cgimage> with ``TextureResource/init(image:withName:options:)-4qz9s``, ``TextureResource/texture2DArray(slices:named:options:)-50g10``, ``TextureResource/cube(slices:named:options:)-57yj1``, or ``TextureResource/texture3D(slices:named:options:)-6pude``. Express your texture by creating a ``LowLevelTexture/Descriptor-swift.struct`` that describes how the data is laid out, along with the size of the texture. This descriptor is similar to <doc://com.apple.documentation/documentation/metal/mtltexturedescriptor>. To use `LowLevelTexture`, first configure the descriptor with the desired characteristics of your texture. ```swift var textureDescriptor: LowLevelTexture.Descriptor { var desc = LowLevelTexture.Descriptor() desc.textureType = .type2D desc.arrayLength = 1 desc.width = 2048 desc.height = 2048 desc.depth = 1 desc.mipmapLevelCount = 1 desc.pixelFormat = .bgra8Unorm desc.textureUsage = [.shaderRead, .shaderWrite] desc.swizzle = .init(red: .red, green: .green, blue: .blue, alpha: .alpha) return desc } ``` Then, you can initialize the `LowLevelTexture` from its descriptor and provide it to a ``TextureResource``. ```swift let texture = try LowLevelTexture(descriptor: textureDescriptor) let resource = try TextureResource(from: texture) ``` You update the contents of a `LowLevelTexture` on the GPU, using a Metal Command Buffer and Compute Command Encoder. For example, you can write a compute kernel in Metal Shading Language to generate the color of each pixel: ```cpp kernel void lowLevelTextureKernel( texture2d<half, access::write> outTexture [[texture(0)]], uint2 gid [[thread_position_in_grid]]) { // Compute texture coordinate ranging from 0 to 1 along each axis. half2 texCoord { half(gid[0]) / (outTexture.get_width() - 1), half(gid[1]) / (outTexture.get_height() - 1) }; // Compute the color as a linear gradient from top to bottom. half3 color = mix( half3 { 0.2, 0.2, 0.8 }, half3 { 0.7, 0.7, 0.9 }, texCoord.y); // Specify an opacity of 1 if the pixel is within a circle // spanning the image bounds. half alpha = length(texCoord - 0.5) < 0.5 ? 1.0h : 0.0h; // Write the color and opacity to the texture. outTexture.write(half4(color, alpha), gid); } ``` You can use this compute kernel to populate the `LowLevelTexture`: ```swift func populate(texture: LowLevelTexture, device: MTLDevice) { // Set up the Metal command queue and compute command encoder, // or abort if that fails. guard let commandQueue = device.makeCommandQueue(), let commandBuffer = commandQueue.makeCommandBuffer(), let computeEncoder = commandBuffer.makeComputeCommandEncoder() else { return } // Load a Metal compute kernel written in Metal Shading Language, // or abort if that fails. guard let library = device.makeDefaultLibrary(), let function = library.makeFunction(name: "lowLevelTextureKernel"), let computePipelineState = try? device.makeComputePipelineState(function: function) else { return } // Enqueue the Metal command buffer. commandBuffer.enqueue() // Set up the Metal compute command encoder with the app's compute kernel. computeEncoder.setComputePipelineState(computePipelineState) // Retrieve a MTLTexture from LowLevelTexture. // This texture will be directly consumed by RealityKit's renderer. let outTexture: MTLTexture = texture.replace(using: commandBuffer) computeEncoder.setTexture(outTexture, index: 0) // Disptach the GPU compute work. // Note: threadGroupCount and threadGroupSize determined elsewhere. computeEncoder.dispatchThreadgroups( threadGroupCount, threadsPerThreadgroup: threadGroupSize) // End the encoding and commit the command buffer. // When the command buffer completes, RealityKit automatically applies the changes. computeEncoder.endEncoding() commandBuffer.commit() } ``` To finish, add your ``TextureResource`` to a ``Material`` and display it on an ``Entity``. ```swift func textureEntity(device: MTLDevice) throws -> Entity { // Create the LowLevelTexture and populate it on the GPU. let texture = try LowLevelTexture(descriptor: textureDescriptor) populate(texture: texture, device: device) // Create a TextureResource from the LowLevelTexture. let resource = try TextureResource(from: texture) // Create a material that uses the texture. var material = UnlitMaterial(texture: resource) material.opacityThreshold = 0.5 // Return an entity of a plane which uses the generated texture. return ModelEntity(mesh: .generatePlane(width: 1, depth: 1), materials: [material]) } ``` ![A screenshot of a circle. The color of the circle is a linear gradient; the top is light blue and the bottom is close to white.](lowleveltexture-circle-unlit) The ``TextureResource`` retains a reference to the `LowLevelTexture`, and presents changes made to the `LowLevelTexture` when the renderer updates.

Members (6)

init · iOS 18.0+

init

TypeScript
static initDescriptor(descriptor: LowLevelTexture_Descriptor): Promise<LowLevelTexture>
Swift declaration
@MainActor init(descriptor: LowLevelTexture.Descriptor) throws

Creates a low-level texture from a descriptor. - Parameter descriptor: An object that defines the structure of the low-level texture. - Throws: If the descriptor is invalid or if memory was not allocated successfully.

get · iOS 18.0+

descriptor

TypeScript
get descriptor(): Promise<LowLevelTexture_Descriptor>
Swift declaration
@MainActor final let descriptor: LowLevelTexture.Descriptor

The descriptor that you use to initialize the `LowLevelTexture`.

init · iOS 27.0+

init

TypeScript
static initDeviceResourceUsing(deviceResource: LowLevelDeviceResource, commandBuffer?: (SDKHandle) | null): Promise<LowLevelTexture>
Swift declaration
@MainActor convenience init(deviceResource: LowLevelDeviceResource, using commandBuffer: (any MTLCommandBuffer)? = nil) throws

Creates a low-level texture from an existing ``LowLevelDeviceResource`` created and managed by the application. - Parameter deviceResource: The underlying texture this object should refer to. - Parameter commandBuffer: The <doc://com.apple.documentation/documentation/metal/mtlcommandbuffer> you intend to use for texture modifications. RealityKit waits for the command buffer to complete before utilizing the texture for rendering.

method · iOS 18.0+

read

TypeScript
read(): Promise<SDKHandle>
Swift declaration
@MainActor func read() -> any MTLTexture

Retrieves the current texture for GPU reading.

method · iOS 27.0+

replace

TypeScript
replaceDeviceResourceUsing(deviceResource: LowLevelDeviceResource, commandBuffer?: (SDKHandle) | null): Promise<void>
Swift declaration
@MainActor func replace(deviceResource: LowLevelDeviceResource, using commandBuffer: (any MTLCommandBuffer)? = nil)

Replaces this object's underlying texture with an existing ``LowLevelDeviceResource`` created and managed by the application. While it's valid to replace a LowLevelTexture with an externally-managed texture having different dimensions, the LowLevelTexture will remember its initial size and calling replace(using:) to obtain a new MTLTexture will respect the initial size. - Parameter deviceResource: The underlying texture this object should refer to. - Parameter commandBuffer: The <doc://com.apple.documentation/documentation/metal/mtlcommandbuffer> you intend to use for texture modifications. RealityKit waits for the command buffer to complete before utilizing the texture for rendering.

method · iOS 18.0+

replace

TypeScript
replaceUsing(commandBuffer: SDKHandle): Promise<SDKHandle>
Swift declaration
@MainActor func replace(using commandBuffer: any MTLCommandBuffer) -> any MTLTexture

Retrieves a Metal texture that your app's shaders can write to when they run on a GPU. The buffer's contents are in an uninitialized state. - Parameter commandBuffer: The <doc://com.apple.documentation/documentation/metal/mtlcommandbuffer> you intend to use for texture modifications. RealityKit waits for the command buffer to complete before utilizing the texture for rendering.

Skipped declarations

No declarations were skipped in this snapshot.

All RealityFoundation types →