Search code examples
iosbuffermetalmtlbuffer

Changing values of MTLBuffer after created


I would like to be able to define a MTLBuffer and populate data directly to the buffer (or as efficiently as possible).

If I do the following, the values used in the shader are 1.0 and 2.0 (for X and Y respectively), not 3.0 and 4.0 which are set after the MTLBuffer is created.

int bufferLength = 128 * 128;

float pointBuffer[bufferLength * 2]; // 2 for X and Y

//Populate array with test values
for (int i = 0; i < (bufferLength * 2); i += 2) {
    pointBuffer[i] = 1.0;       //X
    pointBuffer[i + 1] = 2.0;   //Y
}

id<MTLBuffer> pointDataBuffer = [device newBufferWithBytes:&pointBuffer length:sizeof(pointBuffer) options:MTLResourceOptionCPUCacheModeDefault];

//Populate array with updated test values       
for (int i = 0; i < (bufferLength * 2); i += 2) {
    pointBuffer[i] = 3.0;       //X
    pointBuffer[i + 1] = 4.0;   //Y
}

//In the (Swift) class with the pipeline:
commandEncoder!.setBuffer(pointDataBuffer, offset: 0, index: 4)

Based on the docs, it seems like I need to call didModifyRange: but pointDataBuffer does not seem to recognize the selector.

Is there a way to update the array without having to recreate the MTLBuffer?


Solution

  • -newBufferWithBytes:... makes a copy of the passed in bytes. It does not keep referencing them. So, subsequent changes to pointBuffer do not affect it.

    However, buffers like this one (whose storage mode is not private) provide access to their storage through the -contents method. So, you could do something like this:

    float *points = pointDataBuffer.contents;
    for (int i = 0; i < (bufferLength * 2); i += 2) {
        points[i] = 3.0;       //X
        points[i + 1] = 4.0;   //Y
    }
    

    Be careful, though. The CPU and GPU operate asynchronously relative to each other. If there might be commands being processed by the GPU that reference the buffer, then modifying it from the CPU may interfere with the operation of those commands. So, you'll want to take steps to synchronize access to the buffer or otherwise avoid simultaneous CPU and GPU access.