Custom argument buffers on Metal vertex and fragment shader functions

  Kiến thức lập trình

I am going to start with admitting that I’ve got no idea what I am talking about.

I have only been coding shaders for a week and three of those days I tried to figure out how, if possible, I can provide another buffer to the vertex shader that isn’t directly related to rendering. For example, in my vertex shader function I’d like to know the time from start in a uint, but the specifics are not too important here.

That’s easy with a usual Metal function:

  • Create the buffer
  • Run setBuffer() on the compute command encoder
  • Include it as an argument on the function

In a fragment shader and the vertex shader, I couldn’t find a way to set a custom buffer, like a buffer containing a list of Integers, or a custom struct.

To make sure I didn’t get anything wrong previously and to clarify what I’m talking about, here is my code:

Shader:
`#include <metal_stdlib>
#include “Loki-master/Loki/loki_header.metal”
#include “Definitions.h”

using namespace metal;


struct Fragment {
    float4 position [[position]];
    float4 color;
};

vertex Fragment vertexShader(const device Vertex *vertexArray[[buffer(0)]], unsigned int vid [[vertex_id]]){
    Vertex input = vertexArray[vid];

    Fragment output;
    output.position = float4(input.position.x, input.position.y, 1, 1);
    output.color = float4(0, 0, 0, 0);
    return output;
};

fragment float4 fragmentShader(Fragment input [[stage_in]]){
    float4 outputColor = input.color;
    Loki rng = Loki(input.position.x, input.position.y, 1);
    float color1 = rng.rand();
    rng = Loki(input.position.x, input.position.y, 2);
    float color2 = rng.rand();
    rng = Loki(input.position.x, input.position.y, 3);
    float color3 = rng.rand();
    outputColor[0] = color1;
    outputColor[1] = color2;
    outputColor[2] = color3;
    return outputColor;
};`

Note: Loki is a project for generating random numbers on the GPU.

Definitions.h (my Objective-C bridging header):
`#ifndef Definitions_h
#define Definitions_h

#include <simd/simd.h>
struct Vertex {
    vector_float2 position;
    vector_float4 color;
};
#endif /* Definitions_h */`

**My rendering function (written in Swift):

` let commandBuffer = metalCommandQueue.makeCommandBuffer()
let renderPassDescriptor = view.currentRenderPassDescriptor!
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: clearColor[0], green: clearColor[1], blue: clearColor[2], alpha: clearColor[3])
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].storeAction = .store

let renderEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor)

renderEncoder?.setRenderPipelineState(pipelineState)
renderEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder?.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3)

renderEncoder?.endEncoding()

commandBuffer?.present(drawable)
commandBuffer?.commit()`

The current result is (as expect) a triangle with noise triangle and my goal would be to include something like device MyStruct* data in the fragmentShader and/or the vertex shader function. I get it if it may not be possible, but couldn’t really find any existing information online.

LEAVE A COMMENT