【问题标题】:Rendering 2 separate MtkView with 1 Draw call使用 1 个 Draw 调用渲染 2 个单独的 MtkView
【发布时间】:2019-03-28 09:57:33
【问题描述】:

两个 不同(不相互重叠)MtkViews 正常运行。每个都有不同的统一、顶点和不同的原始类型。已经使用一个 RenderCommandEncoder 将两个视图中的一个组合成不同的管道渲染。工作正常。 为了降低对 iOS 设备的能源影响,我减少了每个视图上的 mtkview.preferredFramesPerSecond = 24;

有没有办法在 GPU 上并行处理它们,这样它们就不会相互累加渲染?

假设我必须使用

id<MTLParallelRenderCommandEncoder> renderEncoder = 
[commandBuffer parallelRenderCommandEncoderWithDescriptor:renderPassDescriptor];

但是这个编码器确实知道...

[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];

...我当然使用普通的 RenderCommandEncoder。

那么如何正确设置MTLParallelRenderCommandEncoder

- (void)drawInMTKView:(nonnull MTKView *)view {
    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    //commandBuffer.label = @"CombiCommand";

    MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
    if(renderPassDescriptor != nil) {
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);


        id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
        //renderEncoder.label = @"CombiRenderEncoder";
        [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];


        //----CHART----
        [renderEncoder setRenderPipelineState:_chartPipelineState];
        if (_pat->infoCC.needsDisplay ) {
            [CCChartMetalRenderer changeChartDataWithBuffer:_chartVertexBuffer];
            _chartUniform.statisch = somedata.isStatic;
            _pat->infoCC.needsDisplay=false;
        }
        [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:IndexViewportSize];
        [renderEncoder setVertexBytes:&_chartUniform length:sizeof(_chartUniform) atIndex:IndexUniforms];
        [renderEncoder setVertexBuffer:_chartVertexBuffer offset:0 atIndex:IndexVertices];
        [renderEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:_chartVerticesCount];


        //----NOTE----
        [renderEncoder setRenderPipelineState:_notePipelineState];
        if (_pat->infoNotePatch.needsDisplay ) {
            [NoteMetalRenderer changeVertexDataWithMtlBuffer:_noteVertexBuffer];
            _noteUniform.color = simd_make_float4(1.0, 0.0, 1.0, 1.0);
            _noteUniform.isOn = somedata.isOn;
            _pat->infoNotePatch.needsDisplay=false;
        }
        [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:IndexViewportSize];
        [renderEncoder setVertexBytes:&_noteUniform length:sizeof(_noteUniform) atIndex:IndexUniforms];
        [renderEncoder setVertexBuffer:_noteVertexBuffer offset:0 atIndex:IndexVertices];
        [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_notesCount * sizeof(NoteVertex)];


        //----POS----
        [renderEncoder setRenderPipelineState:_posPipelineState];
        _posUniform.statischValue = somedata.value;
        _posUniform.statisch = somedata.isStatic;
        [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:IndexViewportSize];
        [renderEncoder setVertexBytes:&_posUniform length:sizeof(_posUniform) atIndex:IndexUniforms];
        [renderEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:16];

        //---ENDENCODIG---
        [renderEncoder endEncoding];
        [commandBuffer presentDrawable:view.currentDrawable];
    }
    [commandBuffer commit];
}

和第二个 mtkView

- (void)drawInMTKView:(nonnull MTKView *)view {
    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    //commandBuffer.label = @"CCTableCommand";

    MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
    if(renderPassDescriptor != nil) {
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);

        id<MTLRenderCommandEncoder> renderEncoder =
        [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
        //renderEncoder.label = @"CCTableRenderEncoder";
        [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];

        [renderEncoder setRenderPipelineState:_pipelineState];
        [self.class changeVertexDataWithPatch:_pat Ch:_viewCH Quantize:_quantized mtlBuffer:_vertexBuffer];
        _tableUniform.isOn = somedata.isOn;
        [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:IndexViewportSize];
        [renderEncoder setVertexBytes:&_tableUniform length:sizeof(_tableUniform) atIndex:IndexUniforms];
        [renderEncoder setVertexBuffer:_vertexBuffer offset:0 atIndex:IndexVertices];

        [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_numVertices];

        [renderEncoder endEncoding];
        [commandBuffer presentDrawable:view.currentDrawable];
    }
    [commandBuffer commit];
}

【问题讨论】:

    标签: ios objective-c metal metalkit


    【解决方案1】:

    您是如何得出并行命令编码是一种解决方案的结论?

    并行命令编码的目的是跨线程分配 CPU 端的编码工作。它与最终如何在 GPU 上安排和执行该工作无关。如果您受 CPU 限制,您可能需要使用并行编码,但每个并行渲染命令编码器只能对影响一个视图的命令进行编码。

    不可能通过一个绘图调用同时渲染到两个MTKViews,因为每个绘图调用都使用与其对应视图的当前可绘制对象关联的渲染命令编码器进行编码。

    您似乎误解了您编码的工作必须在 GPU 上按顺序执行。事实并非如此。如果可以安排独立的工作同时执行,GPU 驱动程序会这样做,但这不在您的控制范围内。

    【讨论】:

      【解决方案2】:

      巧妙地使用每个 Encoder 的 ViewportSize 和 UIView 分层使得“一次”渲染成为可能。

      - (void)drawInMTKView:(nonnull MTKView *)view {
          id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
      
          MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
          if(renderPassDescriptor != nil) {
      
              // allows for transparent layering
              renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);
      
              // allowes the encoders to work on different threads
              id<MTLParallelRenderCommandEncoder> parallelRenderEnc = [commandBuffer parallelRenderCommandEncoderWithDescriptor:renderPassDescriptor];
      
              // so we need to get the renderEncoders from the parallelRenderEncoder
              id<MTLRenderCommandEncoder> renderEncoder1 = [parallelRenderEnc renderCommandEncoder];
              id<MTLRenderCommandEncoder> renderEncoder2 = [parallelRenderEnc renderCommandEncoder];
      
              // each of which need their own viewport settings, they dont need to be equaly
              [renderEncoder1 setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];
              [renderEncoder2 setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];
      
              [renderEncoder1 setRenderPipelineState:_renderPipeLine1];
              //do your Metal SharedBuffer stuff for encoder1 here
              //renderEncoder1 set uniform buffer/bytes
              //renderEncoder1 set vertex buffer/bytes
              //renderEncoder1 drawPrimitives with the MTLPrimitiveType you want
      
              [renderEncoder2 setRenderPipelineState:_renderPipeLine2];
              //do your Metal SharedBuffer stuff for encoder2 here
              //renderEncoder2 set uniform buffer/bytes
              //renderEncoder2 set vertex buffer/bytes
              //renderEncoder2 drawPrimitives with the MTLPrimitiveType you want
      
              [renderEncoder1 endEncoding];
              [renderEncoder2 endEncoding];
      
             [parallelRenderEnc endEncoding]
             [commandBuffer presentDrawable:view.currentDrawable];
          }
          [commandBuffer commit];
      }
      

      您可以决定允许哪些 commandEncoder 在同一线程或它们自己的线程上运行。 现在您可以使用tripleBuffering 来让CPU 和GPU 不在同一个缓冲区上同时工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-28
        • 1970-01-01
        • 1970-01-01
        • 2019-05-14
        • 1970-01-01
        • 2020-02-11
        • 1970-01-01
        • 2021-12-20
        相关资源
        最近更新 更多