I would like to use a fragment shader to render to a texture offscreen. Once this is done I want to use the result of that as the input for another fragment shader.
I create a texture and clear it with red (to know it is set). I use the render pass that is connected to my target texture and draw. I then use a blit command encoder to transfer the contents of that target texture to a buffer. The buffer contains red so I know it is reading the texture correctly but the drawing should make the texture green so something is wrong.
let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.textureType = MTLTextureType.type2D
textureDescriptor.width = 2048
textureDescriptor.height = 1024
textureDescriptor.pixelFormat = .rgba8Unorm
textureDescriptor.storageMode = .shared
textureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite]
bakeTexture = device.makeTexture(descriptor: textureDescriptor)
bakeRenderPass = MTLRenderPassDescriptor()
bakeRenderPass.colorAttachments[0].texture = bakeTexture
bakeRenderPass.colorAttachments[0].loadAction = .clear
bakeRenderPass.colorAttachments[0].clearColor = MTLClearColor(red:1.0,green:0.0,blue:0.0,alpha:1.0)
bakeRenderPass.colorAttachments[0].storeAction = .store
for drawing I do this:
let bakeCommandEncoder = commandBuffer.makeRenderCommandEncode(descriptor: bakeRenderPass)
let vp = MTLViewport(originX:0, originY:0, width:2048, height:1024,znear:0.0,zfar:1.0)
bakeCommandEncoder.setViewport(vp)
bakeCommandEncoder.setCullMode(.none) // disable culling
// draw here. Fragment shader sets final color to float4(0.0,1.0,0.0,1.0);
bakeCommandEncoder.endEncoding()
let blitEncoder = commandBuffer.makeBlitCommandEncoder()
blitEncoder!.copy(...) // this works as my buffer is all red
blitEncoder.endEncoding()
Here is the vertex shader - it is based on an OpenGL vertex shader to dump out the uv-layout of the texture:
struct VertexOutBake {
float4 position [[position]];
float3 normal;
float3 tangent;
float3 binormal;
float3 worldPosition;
float2 texCoords;
};
vertex VertexOutBake vertex_main_bake(VertexInBake vertexIn [[stage_in]],
constant VertexUniforms &uniforms [[buffer(1)]])
{
VertexOutBake vertexOut;
float4 worldPosition = uniforms.modelMatrix * float4(vertexIn.position, 1);
vertexOut.worldPosition = worldPosition.xyz;
vertexOut.normal = normalize(vertexIn.normal);
vertexOut.tangent = normalize(vertexIn.tangent);
vertexOut.binormal = normalize(vertexIn.binormal);
vertexOut.texCoords = vertexIn.texCoords;
vertexOut.texCoords.y = 1.0 - vertexOut.texCoords.y; // flip image
// now use uv coordinates instead of 3D positions
vertexOut.position.x = vertexOut.texCoords.x * 2.0 - 1.0;
vertexOut.position.y = 1.0 - vertexOut.texCoords.y * 2.0;
vertexOut.position.z = 1.0;
vertexOut.position.w = 1.0;
return vertexOut;
}
The buffer that gets filled as a result of the blit copy should be green but it is red. This seems to mean that either the bakeTexture is not being written to in the fragment shader or that it is, but there is some synchronization missing to make the content available at the time I am doing the copy.