Uniform variable was overwritten?

Hi,


I am porting my OpenGL project to Metal, everything is done except a small issue.


I use a uniform variable as the mesh color, different meshes may have different colors.


First I use a single pass with a command encoder to call multiple drawPrimitives in a loop to draw all meshes, I assign color for every mesh, but only the last color take effect, all meshes have the last color.


Then I try to create a command encoder and call endEncoding in the loop to use multiple passes, but nothing improved, the result is the same as in a single pass.


I guess that when a command encoder calls drawPrimitives, it does not draw to the off-screen texture like OpenGL does, but it just records the drawPrimitives action for a batch commit, this is why the color was overwritten.


Do you have any suggestions?


Thank you.

Replies

Just figured out! I have to use multiple command buffers, use one command buffer for each mesh, but carefully set load actions and store actions to protect the middle result, call waitUntilCompleted is important, only call presentDrawable once before the last commit.

Source code:

---------------------------

void draw_all() {

before_draw();

for (int i=0; i<mesh_count; i++) {

draw(i);

}

after_draw();

}

void before_draw() {

// Create a new command buffer for each render pass to the current drawable

commandBuffer = [_commandQueue commandBuffer];

commandBuffer.label = @"MyClearCommand";

// Obtain a renderPassDescriptor generated from the view's drawable textures

renderPassDescriptor = metal_view.currentRenderPassDescriptor;

renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;

renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;

renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;

renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;

renderPassDescriptor.depthAttachment.clearDepth = 1.0;

// Create a render command encoder so we can render into something

renderEncoder =

[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

renderEncoder.label = @"MyClearEncoder";

[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];

[renderEncoder setDepthStencilState:_depthState];

[renderEncoder endEncoding];

[commandBuffer commit];

// block until command buffer complete.

[commandBuffer waitUntilCompleted];

}

void draw(const int mesh_index) {

// Create a new command buffer for each render pass to the current drawable

commandBuffer = [_commandQueue commandBuffer];

commandBuffer.label = @"MyRenderCommand";

// Obtain a renderPassDescriptor generated from the view's drawable textures

renderPassDescriptor = metal_view.currentRenderPassDescriptor;

renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;

renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;

renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionLoad;

renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;

renderPassDescriptor.depthAttachment.clearDepth = 1.0;

// Create a render command encoder so we can render into something

renderEncoder =

[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

renderEncoder.label = @"MyRenderEncoder";

[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];

[renderEncoder setDepthStencilState:_depthState];

// Draw the mesh ...

[renderEncoder endEncoding];

[commandBuffer commit];

// block until command buffer complete.

[commandBuffer waitUntilCompleted];

}

void after_draw() {

// Create a new command buffer for each render pass to the current drawable

commandBuffer = [_commandQueue commandBuffer];

commandBuffer.label = @"MyPresentCommand";

// Obtain a renderPassDescriptor generated from the view's drawable textures

renderPassDescriptor = metal_view.currentRenderPassDescriptor;

renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;

renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;

renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionDontCare;

renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;

renderPassDescriptor.depthAttachment.clearDepth = 1.0;

// Create a render command encoder so we can render into something

renderEncoder =

[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

renderEncoder.label = @"MyPresentEncoder";

[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];

[renderEncoder setDepthStencilState:_depthState];

[renderEncoder endEncoding];

// Schedule a present once the framebuffer is complete using the current drawable

[commandBuffer presentDrawable:metal_view.currentDrawable];

[commandBuffer commit];

// block until command buffer complete.

[commandBuffer waitUntilCompleted];

}

};

---------------------------