I am presenting a MTLTexture to the display with the following code. It is a large (~12k) texture that is taking about 10ms to draw. Since I need to render at least 30FPS (33ms/frame) it is taking nearly one third of my computing time just to display the texture.
Are there any tricks to increase performance and draw the texture faster? In the GPU Frame Capture it shows a lot of time for culling. I tried enabling/disabling culling but I still see the same time being used for culling.
vertex TextureMappingVertex mapTexture(unsigned int vertex_id [[ vertex_id ]], constant Uniforms& uniforms [[ buffer(0) ]]) {
float4x4 renderedCoordinates = float4x4(float4( -1.f, -1.f, 0.f, 1.f ),
float4( 1.f, -1.f, 0.f, 1.f ),
float4( -1.f, 1.f, 0.f, 1.f ),
float4( 1.f, 1.f, 0.f, 1.f ));
float4x2 textureCoordinates = float4x2(float2( 0.f, 1.f ),
float2( 1.f, 1.f ),
float2( 0.f, 0.f ),
float2( 1.f, 0.f ));
TextureMappingVertex outVertex;
outVertex.renderedCoordinate = uniforms.mvp_matrix * renderedCoordinates[vertex_id];
outVertex.textureCoordinate = textureCoordinates[vertex_id];
return outVertex;
}
fragment half4 displayTexture(TextureMappingVertex mappingVertex [[ stage_in ]],
texture2d<half, access::sample> texture [[ texture(0) ]]) {
constexpr sampler s(address::clamp_to_edge, filter::nearest);
return half4(texture.sample(s, mappingVertex.textureCoordinate));
}
func draw(in view: MTKView) {
guard let commandBuffer = commandQueue.makeCommandBuffer() else { return }
guard let descriptor = view.currentRenderPassDescriptor else {return}
let render = commandBuffer.makeRenderCommandEncoder(descriptor: descriptor)
render?.pushDebugGroup("Render to Screen")
render?.setRenderPipelineState(renderCanvasPipelineState)
render?.setFragmentTexture(canvasTexture, index: 0)
render?.setVertexBuffer(uniformBuffer, offset: 0, index: 0)
render?.setCullMode(.none)
render?.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4, instanceCount: 1)
render?.popDebugGroup()
render?.endEncoding()
guard let drawable = view.currentDrawable else { return }
commandBuffer.present(drawable)
commandBuffer.commit()
}
func initializeCanvasRenderPipelineState() {
let library = Renderer.device.makeDefaultLibrary()
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.sampleCount = 1
pipelineDescriptor.rasterSampleCount = 1
pipelineDescriptor.colorAttachments[0].pixelFormat = .rgba8Unorm
pipelineDescriptor.depthAttachmentPixelFormat = .invalid
pipelineDescriptor.vertexFunction = library?.makeFunction(name: "mapTexture")
pipelineDescriptor.fragmentFunction = library?.makeFunction(name: "displayTexture")
pipelineDescriptor.colorAttachments[0].isBlendingEnabled = false
do {
try renderCanvasPipelineState = Renderer.device.makeRenderPipelineState(descriptor: pipelineDescriptor)
}
catch {
assertionFailure("Failed creating a render state pipeline. Can't render the texture without one.")
return
}
}