I've been trying to get a gui library named Colibrigui working with metal on MacOS. I'm getting stuck with some problem relating to shader genaration.
Firstly, this library already has support for ogre 2.2 with glsl and hlsl. I actually got really far, and by writing a work around for this problem I got it working with metal rendering text and widgets. The problem itself is relating to clipdistance.
Hlms/Unlit/Metal/VertexShader_vs.metal contains the following:
Code: Select all
@foreach( hlms_pso_clip_distances, n )
float gl_ClipDistance@n [[clip_distance]];
@end
Code: Select all
float gl_ClipDistance0 [[clip_distance]];
float gl_ClipDistance1 [[clip_distance]];
float gl_ClipDistance2 [[clip_distance]];
float gl_ClipDistance3 [[clip_distance]];
Code: Select all
setProperty( HlmsBaseProp::PsoClipDistances, 4 );
Code: Select all
Metal SL Compiler Error in 300000001VertexShader_vs:
Compilation failed:
program_source:149:9: error: declaration with attribute 'clip_distance' already specified
float gl_ClipDistance1 [[clip_distance]];
~~~~~~^~~~~~~~~~~~~~~~
program_source:147:9: note: previous declaration with attribute 'clip_distance' here
float gl_ClipDistance0 [[clip_distance]];
^
program_source:151:9: error: declaration with attribute 'clip_distance' already specified
float gl_ClipDistance2 [[clip_distance]];
~~~~~~^~~~~~~~~~~~~~~~
program_source:147:9: note: previous declaration with attribute 'clip_distance' here
float gl_ClipDistance0 [[clip_distance]];
^
program_source:153:9: error: declaration with attribute 'clip_distance' already specified
float gl_ClipDistance3 [[clip_distance]];
~~~~~~^~~~~~~~~~~~~~~~
program_source:147:9: note: previous declaration with attribute 'clip_distance' here
float gl_ClipDistance0 [[clip_distance]];
So if anyone knows about Ogre's metal implementation, I'd like to know what the purpose of the for loop in the base shader is? It seems to me like if hlms_pso_clip_distances was ever anything greater than 1 it would crash.
The complete generated shader is below. It does have some of the gui specific stuff in it as well as the unlit stuff.
Code: Select all
#include <metal_stdlib>
using namespace metal;
struct float1
{
float x;
float1() {}
float1( float _x ) : x( _x ) {}
};
inline float3x3 toMat3x3( float4x4 m )
{
return float3x3( m[0].xyz, m[1].xyz, m[2].xyz );
}
inline float3x3 toMat3x3( float3x4 m )
{
return float3x3( m[0].xyz, m[1].xyz, m[2].xyz );
}
#define ogre_float4x3 float3x4
//Short used for read operations. It's an int in GLSL & HLSL. An ushort in Metal
#define rshort2 ushort2
#define rint uint
//Short used for write operations. It's an int in GLSL. An ushort in HLSL & Metal
#define wshort2 ushort2
#define wshort3 ushort3
#define toFloat3x3( x ) toMat3x3( x )
#define buildFloat3x3( row0, row1, row2 ) float3x3( row0, row1, row2 )
#define min3( a, b, c ) min( a, min( b, c ) )
#define max3( a, b, c ) max( a, max( b, c ) )
#define mul( x, y ) ((x) * (y))
#define lerp mix
#define INLINE inline
#define NO_INTERPOLATION_PREFIX
#define NO_INTERPOLATION_SUFFIX [[flat]]
#define finalDrawId drawId
#define floatBitsToUint(x) as_type<uint>(x)
#define uintBitsToFloat(x) as_type<float>(x)
#define floatBitsToInt(x) as_type<int>(x)
#define lessThan( a, b ) (a < b)
#define discard discard_fragment()
#define inVs_vertex input.position
#define inVs_blendWeights input.blendWeights
#define inVs_blendIndices input.blendIndices
#define inVs_qtangent input.qtangent
#define inVs_drawId input.drawId
#define inVs_uv0 input.uv0
#define outVs_Position outVs.gl_Position
#define outVs_viewportIndex outVs.gl_ViewportIndex
#define outVs_clipDistance0 outVs.gl_ClipDistance0
#define gl_SampleMaskIn0 gl_SampleMask
//#define interpolateAtSample( interp, subsample ) interpolateAtSample( interp, subsample )
#define findLSB ctz
#define outPs_colour0 outPs.colour0
#define OGRE_Sample( tex, sampler, uv ) tex.sample( sampler, uv )
#define OGRE_SampleLevel( tex, sampler, uv, lod ) tex.sample( sampler, uv, level( lod ) )
#define OGRE_SampleArray2D( tex, sampler, uv, arrayIdx ) tex.sample( sampler, float2( uv ), arrayIdx )
#define OGRE_SampleArray2DLevel( tex, sampler, uv, arrayIdx, lod ) tex.sample( sampler, float2( uv ), ushort( arrayIdx ), level( lod ) )
#define OGRE_SampleArrayCubeLevel( tex, sampler, uv, arrayIdx, lod ) tex.sample( sampler, float3( uv ), ushort( arrayIdx ), level( lod ) )
#define OGRE_SampleGrad( tex, sampler, uv, ddx, ddy ) tex.sample( sampler, uv, gradient2d( ddx, ddy ) )
#define OGRE_SampleArray2DGrad( tex, sampler, uv, arrayIdx, ddx, ddy ) tex.sample( sampler, uv, ushort( arrayIdx ), gradient2d( ddx, ddy ) )
#define OGRE_ddx( val ) dfdx( val )
#define OGRE_ddy( val ) dfdy( val )
#define OGRE_Load2D( tex, iuv, lod ) tex.read( iuv, lod )
#define OGRE_Load2DMS( tex, iuv, subsample ) tex.read( iuv, subsample )
#define OGRE_Load3D( tex, iuv, lod ) tex.read( ushort3( iuv ), lod )
#define bufferFetch( buffer, idx ) buffer[idx]
#define bufferFetch1( buffer, idx ) buffer[idx]
#define structuredBufferFetch( buffer, idx ) buffer[idx]
#define OGRE_Texture3D_float4 texture3d<float>
#define OGRE_SAMPLER_ARG_DECL( samplerName ) , sampler samplerName
#define OGRE_SAMPLER_ARG( samplerName ) , samplerName
#define CONST_BUFFER_STRUCT_BEGIN( structName, bindingPoint ) struct structName
#define CONST_BUFFER_STRUCT_END( variableName )
#define FLAT_INTERPOLANT( decl, bindingPoint ) decl [[flat]]
#define INTERPOLANT( decl, bindingPoint ) decl
#define OGRE_OUT_REF( declType, variableName ) thread declType &variableName
#define OGRE_INOUT_REF( declType, variableName ) thread declType &variableName
#define OGRE_ARRAY_START( type ) {
#define OGRE_ARRAY_END }
// START UNIFORM STRUCT DECLARATION
//Uniforms that change per pass
struct PassData
{
//Vertex shader
float4x4 viewProj[2];
//Pixel Shader
float4 invWindowSize;
};
// END UNIFORM STRUCT DECLARATION
struct VS_INPUT
{
float4 position [[attribute(VES_POSITION)]];
float4 colour [[attribute(VES_DIFFUSE)]];
float2 uv0 [[attribute(VES_TEXTURE_COORDINATES0)]];
ushort drawId [[attribute(15)]];
float4 normal [[attribute(VES_NORMAL)]];
};
struct PS_INPUT
{
ushort materialId [[flat]];
float4 colour;
float2 uv0;
float4 gl_Position [[position]];
float gl_ClipDistance0 [[clip_distance]];
float gl_ClipDistance1 [[clip_distance]];
float gl_ClipDistance2 [[clip_distance]];
float gl_ClipDistance3 [[clip_distance]];
};
vertex PS_INPUT main_metal
(
VS_INPUT input [[stage_in]]
// START UNIFORM DECLARATION
, constant PassData &passBuf [[buffer(CONST_SLOT_START+0)]]
//Uniforms that change per Item/Entity
//.x =
//Contains the material's start index.
//
//.y =
//shadowConstantBias. Send the bias directly to avoid an
//unnecessary indirection during the shadow mapping pass.
//Must be loaded with uintBitsToFloat
//
//.z =
//Contains 0 or 1 to index into passBuf.viewProj[]. Only used
//if hlms_identity_viewproj_dynamic is set.
, constant uint4 *worldMaterialIdx [[buffer(CONST_SLOT_START+2)]]
, device const float4x4 *worldMatBuf [[buffer(TEX_SLOT_START+0)]]
, uint gl_VertexID [[vertex_id]]
// END UNIFORM DECLARATION
)
{
ushort drawId = input.drawId;
PS_INPUT outVs;
uint colibriDrawId = drawId + ((uint(gl_VertexID) - worldMaterialIdx[drawId].w) / 54u);
#undef finalDrawId
#define finalDrawId colibriDrawId
#define worldViewProj 1.0f
outVs.gl_ClipDistance0 = input.normal.x;
outVs.gl_ClipDistance1 = input.normal.y;
outVs.gl_ClipDistance2 = input.normal.z;
outVs.gl_ClipDistance3 = input.normal.w;
outVs.gl_Position = input.position * passBuf.viewProj[1];
outVs.colour = input.colour;
outVs.uv0.xy = input.uv0.xy;
outVs.materialId = (ushort)worldMaterialIdx[finalDrawId].x;
return outVs;
}