2015-05-05 25 views
1

我遇到了一個問題,它會在具有不同統一參數的不同對象上重複使用我的金屬像素和頂點着色器。我猜測它的錯誤使用我的命令緩衝區有問題。在iOS中重複使用具有不同統一參數的像素着色器金屬

當我跑我的金屬應用,幾何正確繪製,但只有工作服的最終調用

renderCommand setFragmentBuffer:uniform_info offset:0 atIndex:UNIFORM_INFO_BUFFER_INDEX];

似乎將數據寫入到像素着色器。

我在這裏剪切粘貼(並編輯)了我的渲染循環。在通過不同的制服一個渲染過程中我在尋找如何多次重複使用我的像素着色器的例子。

CAMetalLayer *metalLayer = [metal_info.g_iosMetalView getMetalLayer]; 

    id <CAMetalDrawable> frameDrawable; 
    while (!frameDrawable){ 
    frameDrawable = [metalLayer nextDrawable]; 
    } 
    MTLRenderPassDescriptor *mtlRenderPassDescriptor; 
    mtlRenderPassDescriptor = [MTLRenderPassDescriptor new]; 
    mtlRenderPassDescriptor.colorAttachments[0].texture = frameDrawable.texture; 
    mtlRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad; 
    mtlRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 1.0, 1.0); 

    mtlRenderPassDescriptor.depthAttachment.texture = metal_info.g_depthTexture; 
    mtlRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear; 
    mtlRenderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore; 
    mtlRenderPassDescriptor.depthAttachment.clearDepth = 1.0; 

    // Create My one and only command buffer 
    id <MTLCommandBuffer> mtlCommandBuffer = [metal_info.g_commandQueue commandBuffer]; 

    int n = RendererInfo.fact.GetActiveCount(); 

    // loop through all the objects I have (I'm having trouble with 2) 
    Object* curObj = NULL; 
    for (int obj_i = 0 ; obj_i < n ; ++obj_i) 
    { 
    // create one render encoder for each object 
    id <MTLRenderCommandEncoder> renderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor: mtlRenderPassDescriptor]; 

    memcpy([metal_info.g_projectionMatrix contents], &metal_info.g_Projection, sizeof(Matrix4f));   
    Matrix4f *view = RendererInfo.cam->GetViewMatrix(); 
    memcpy([metal_info.g_viewMatrix contents], view, sizeof(Matrix4f)); 

    [renderCommand setFrontFacingWinding:MTLWindingCounterClockwise]; 
    [renderCommand setCullMode:MTLCullModeBack]; 

    [renderCommand setViewport: (MTLViewport){ 0.0, 0.0, 
     (double)metal_info.g_metal_width, 
     (double)metal_info.g_metal_height, 
     0.0, 1.0 }]; 

    [renderCommand setRenderPipelineState:metal_info.g_pipelineState]; 
    [renderCommand setDepthStencilState:metal_info.g_depthState]; 


    curObj = RendererInfo.fact.GetObjectAtIndex(obj_i); 

    id<MTLBuffer> vertices = curObj->GetVertexBuffer(); 
    id<MTLBuffer> indicies = curObj->GetIndexBuffer();   
    int indexCount = curObj->GetIndexCount(); 

    id <MTLTexture> texture = objTexture->GetAsset(); 
    [renderCommand setFragmentTexture:texture atIndex:0];   

    memcpy([metal_info.g_shaderUniformInfo contents], curObj->GetUniformInfo(), curObj->curObj->GetUniformInfoSize()); 

    [renderCommand setVertexBuffer:vertices      offset:0 atIndex:VERTICES__INDEX]; 
    [renderCommand setVertexBuffer:metal_info.g_viewMatrix  offset:0 atIndex:VIEW_MATRIX_BUFFER_INDEX]; 
    [renderCommand setVertexBuffer:metal_info.g_projectionMatrix offset:0 atIndex:PROJECTION_MATRIX_BUFFER_INDEX]; 

    [renderCommand setFragmentBuffer:metal_info.g_shaderUniformInfo offset:0 atIndex:UNIFORM_INFO_BUFFER_INDEX]; 

    [renderCommand drawIndexedPrimitives:MTLPrimitiveTypeTriangle 
           indexCount:indexCount 
           indexType:MTLIndexTypeUInt32 
          indexBuffer:indicies 
         indexBufferOffset:0]; 

    [renderCommand endEncoding]; 
    } 
    [mtlCommandBuffer presentDrawable:frameDrawable]; 
    [mtlCommandBuffer commit]; 

我也可以,如果你想發佈的像素着色器,但是當我編碼爲一次只渲染一個對象,則着色器可正常工作。

+0

我在回答後查找了「g_」的含義;這實際上是你的問題的關鍵。 – Jessy

回答

2

MTLRenderCommandEncoder不編碼「memcpy」指令。您目前認爲每個memcpy([metal_info.g_shaderUniformInfo contents], curObj->GetUniformInfo(), curObj->curObj->GetUniformInfoSize());都與一個編碼器相關聯,但實際上,您只是將相同的metal_info.g_shaderUniformInfo與每個編碼器關聯起來,並且在提交命令緩衝區後,着色器都使用來自該緩衝區的數據 - 捕獲緩衝區的副本。你注意到的關鍵是,這個提交發生在你最後一次運行循環之後,此時g_shaderUniformInfo是唯一有價值的應用。

您需要爲每個對象使用不同的統一緩衝區,或者寫入同一緩衝區的不同部分,並從中適當地讀取它們。

0

正如@Jessy正確指出的那樣,Metal沒有複製您的數據,所以只有最後一次迭代中的數據纔會被使用。

我想補充一點,如果你的緩衝區小(< 4KB左右),你可以使用setVertexBytessetFragmentBytes確實複製字節的選擇,而不必應付創造一個MTLBuffer等。這是一個很好的方便方法。

相關問題