Creating globally accessible constant buffer in Metal Shading Language

谁都会走 提交于 2019-12-12 18:25:35

问题



I've got a question about constant buffers in Metal. Let's assume, that I've got something like:

...list of includes goes here...

using namespace metal; 

struct ConstantBuffer {
     float ANY_VALUE;
};

struct VS_INPUTS { 
    float4 i_pos_ms [ [ attribute ( 0 ) ] ] ; 
} ; 

struct V2P_STRUCT { 
    float4 v_pos_out [ [ position ] ] ;  
} ; 

float3 CalcSomething() {
    return float3(ANY_VALUE, ANY_VALUE, ANY_VALUE); // !!!!!!!!
}

vertex V2P_STRUCT VertexFunc(VS_INPUTS vs_inputs [ [ stage_in ] ] , 
                             constant ConstantBuffer& cb [ [ buffer (1) ] ] )
{
    V2P_STRUCT vs_outputs;

    vs_outputs.v_pos_out.xyz = CalcSomething();
    vs_outputs.v_pos_out.w = cb.ANY_VALUE; // that's OK

    return vs_outputs;
}

Is it possible to call CalcSomething() without passing ANY_VALUE as input argument?
For example in DX11 or in OpenGL you create constant buffer, which can be accessed from every place in shader code.

I think about copying content of "cb" to temporary global object but I have no idea how to do it (because of constant address space).

Another idea is to somehow declare "cb" in global scope (but unfortunately [[buffer]] is designed only for arguments). Is there any trick for that?


回答1:


Solution to my issue:

#include <metal_stdlib> 
#include <metal_graphics> 
#include <metal_texture> 
#include <metal_matrix> 
#include <metal_math> 
#include <metal_geometric> 
#include <metal_common> 

using namespace metal; 

constant float MyVariable = 4;

struct ConstantBuffer 
{
    float ANY_VALUE;
};

struct VS_INPUTS { 
    float4 i_pos_ms [ [ attribute ( 0 ) ] ] ; 
}; 

struct V2P_STRUCT { 
    float4 v_pos_out [ [ position ] ] ;  
}; 

struct VertexShader 
{
    thread VS_INPUTS& vs_inputs;
    thread texture2d<float> img;

    constant ConstantBuffer& cb;

    VertexShader(thread VS_INPUTS& inputs, constant ConstantBuffer& b, thread texture2d<float>& texture) 
        : cb(b) 
        , vs_inputs(inputs)
        , img(texture)
    {}

    float3 CalcSomething() {
        return float3(cb.ANY_VALUE, cb.ANY_VALUE, cb.ANY_VALUE); // !!!!!!!!
    }

    V2P_STRUCT majn()
    { 
        V2P_STRUCT vs_outputs;

        vs_outputs.v_pos_out.xyz = CalcSomething();
        vs_outputs.v_pos_out.w = cb.ANY_VALUE * vs_inputs.i_pos_ms.x * MyVariable; // that's OK

        return vs_outputs;
    }
};

vertex V2P_STRUCT VertexFunc(VS_INPUTS vs_inputs [ [ stage_in ] ] , 
                         constant ConstantBuffer& cb [ [ buffer (1) ] ] ,
                         texture2d<float> img [[ texture(0) ]]
                         )
{
    VertexShader vs(vs_inputs, cb, img);
    return vs.majn();
}

I create one struct which contains my whole original shader. Arguments are passed as references to the constructor. Any function can read from constant buffer without receiving tons of arguments. To fix problem with ANY_VALUE which is now part of cb I use macro:

#define ANY_VALUE cb.ANY_VALUE.



回答2:


There are many questions here. I think it would be best if you provided us a problem to solve, instead of trying to shoehorn concepts from other platforms into metal. For now, here are some ideas.

Is it possible to call CalcSomething() without passing ANY_VALUE as input argument?

struct ConstantBuffer {
   const float ANY_VALUE;
};
constant const ConstantBuffer constantBuffer = {1};

static float3 CalcSomething() {
    return float3(constantBuffer.ANY_VALUE);
}

Are you sure CalcSomething shouldn't be a method?

struct ConstantBuffer {
   ConstantBuffer(const float value): value(value) {}

   float3 calculateSomething() const {
      return float3(value);
   }

   const float value;
};

vertex V2P_STRUCT VertexFunc(
   constant const ConstantBuffer& _constantBuffer [[buffer(1)]]
) {
   // Metal can't currently deal with methods without this.
   const auto constantBuffer = _constantBuffer;

Another idea is to somehow declare "cb" in global scope (but unfortunately [[buffer]] is designed only for arguments). Is there any trick for that?

The "trick", in my mind, is to create the buffer in Swift, not the Metal shading language.



来源:https://stackoverflow.com/questions/32135788/creating-globally-accessible-constant-buffer-in-metal-shading-language

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!