summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-02-02 07:49:32 -0800
committerGitHub <noreply@github.com>2018-02-02 07:49:32 -0800
commitb034398ab12d3cc3a5fc04174688cb707404791d (patch)
treeffa3f01046a7dca55cf004855ca9424c82eaa46f /source/slang
parent652a3c987d2b42d069bf54ba251126208d00d9e7 (diff)
Initial work on getting render-test to support vulkan (#391)
* Basic fixes to gets some Vulkan GLSL out of the IR path We haven't been paying much attention to the Vulkan output from the IR path, but that needs to change ASAP. This commit really just implements quick fixes, without concern for whether they are a good fit in the long term. - Add some more mappings from D3D `SV_*` semantics to built-in GLSL variables, and stop redeclaring those built-in variables in our output GLSL. - Add custom output logic for HLSL `*StructuredBuffer<T>` types, so that they emit as `buffer` declarations with an unsized array inside. This has some real limitations: - What if the user passes the type into a function? The parameter should be typed as an (unsized) array, and not a buffer. - What happens if we have an array of structured buffers? We need to declare an array of blocks (which GLSL allows), but this changes the GLSL we should emit when indexing. - Customize the way that we emit entry point attributes (e.g., `[numthread(...)]`) to also support outputting equivalent GLSL `layout` qualifiers. In many of these cases, a better fix might involve doing more of this work in the IR as part of legalization (e.g., we already have a pass that deals with varying input/output for GLSL, so that should probalby be responsible for swapping the `SV_*` to `gl_*`, especially in cases where the types don't match perfectly across langauges). * Start adding Vulkan support to render-test - Add both Vulkan and D3D12 as nominally supported back-ends - Add a git submodule to pull in the Vulkan SDK dependencies - I don't want our users to have to install it manually, since the SDK is huge - Checking in the binaries to our main repository seems like a bad idea, but my hope is that we can prune the bloat using a subodule with the `shallow` cloning option - Implement enough logic for the Vulkan back-end to get a single test passing on Vulkan * Fix warning * Fixup: disable new compute tests for Linux * Fixup: ignore Vulkan tests on AppVeyor * Dynamically load Vulkan implementation Rather than statically link to the Vulkan library, we will dynamically load all of the required functions. This removes the need to have the stub libs involved at all. * Remove vulkan submodule I had set up a `vulkan` submodule to pull in the headers and stub libs, but now that we are going to dynamically load all the symbols anyway, the stub lib binaries aren't needed and we can just commit the headers. * Add Vulkan headers to external/
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/emit.cpp427
-rw-r--r--source/slang/type-defs.h10
2 files changed, 383 insertions, 54 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 18216de81..dd9830c24 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -4520,22 +4520,178 @@ emitDeclImpl(decl, nullptr);
}
String getGLSLSystemValueName(
+ IRValue* varDecl,
VarLayout* varLayout)
{
- auto semanticName = varLayout->systemValueSemantic;
- semanticName = semanticName.ToLower();
+ auto semanticNameSpelling = varLayout->systemValueSemantic;
+ auto semanticName = semanticNameSpelling.ToLower();
if(semanticName == "sv_position")
{
+ // TODO: need to pick between `gl_Position` and
+ // `gl_FragCoord` based on whether this is an input
+ // or an output.
return "gl_Position";
}
else if(semanticName == "sv_target")
{
+ // Note: we do *not* need to generate some kind of `gl_`
+ // builtin for fragment-shader outputs: they are just
+ // ordinary `out` variables, with ordinary `location`s,
+ // as far as GLSL is concerned.
return "";
}
+ else if(semanticName == "sv_clipdistance")
+ {
+ // TODO: type conversion is required here.
+ return "gl_ClipDistance";
+ }
+ else if(semanticName == "sv_culldistance")
+ {
+ requireGLSLExtension("ARB_cull_distance");
+
+ // TODO: type conversion is required here.
+ return "gl_CullDistance";
+ }
+ else if(semanticName == "sv_coverage")
+ {
+ // TODO: deal with `gl_SampleMaskIn` when used as an input.
+
+ // TODO: type conversion is required here.
+ return "gl_SampleMask";
+ }
+ else if(semanticName == "sv_depth")
+ {
+ return "gl_FragDepth";
+ }
+ else if(semanticName == "sv_depthgreaterequal")
+ {
+ // TODO: layout(depth_greater) out float gl_FragDepth;
+ return "gl_FragDepth";
+ }
+ else if(semanticName == "sv_depthlessequal")
+ {
+ // TODO: layout(depth_greater) out float gl_FragDepth;
+ return "gl_FragDepth";
+ }
+ else if(semanticName == "sv_dispatchthreadid")
+ {
+ return "gl_GlobalInvocationID";
+ }
+ else if(semanticName == "sv_domainlocation")
+ {
+ return "gl_TessCoord";
+ }
+ else if(semanticName == "sv_groupid")
+ {
+ return "gl_WorkGroupID";
+ }
+ else if(semanticName == "sv_groupindex")
+ {
+ return "gl_LocalInvocationIndex";
+ }
+ else if(semanticName == "sv_groupthreadid")
+ {
+ return "gl_LocalInvocationID";
+ }
+ else if(semanticName == "sv_gsinstanceid")
+ {
+ return "gl_InvocationID";
+ }
+ else if(semanticName == "sv_instanceid")
+ {
+ return "gl_InstanceIndex";
+ }
+ else if(semanticName == "sv_isfrontface")
+ {
+ return "gl_FrontFacing";
+ }
+ else if(semanticName == "sv_outputcontrolpointid")
+ {
+ return "gl_InvocationID";
+ }
+ else if(semanticName == "sv_primitiveid")
+ {
+ return "gl_PrimitiveID";
+ }
+ else if (semanticName == "sv_rendertargetarrayindex")
+ {
+ switch (context->shared->entryPoint->profile.GetStage())
+ {
+ case Stage::Geometry:
+ requireGLSLVersion(ProfileVersion::GLSL_150);
+ break;
+
+ case Stage::Fragment:
+ requireGLSLVersion(ProfileVersion::GLSL_430);
+ break;
+
+ default:
+ requireGLSLVersion(ProfileVersion::GLSL_450);
+ requireGLSLExtension("GL_ARB_shader_viewport_layer_array");
+ break;
+ }
+
+ return "gl_Layer";
+ }
+ else if (semanticName == "sv_sampleindex")
+ {
+ return "gl_SampleID";
+ }
+ else if (semanticName == "sv_stencilref")
+ {
+ requireGLSLExtension("ARB_shader_stencil_export");
+ return "gl_FragStencilRef";
+ }
+ else if (semanticName == "sv_tessfactor")
+ {
+ return "gl_TessLevelOuter";
+ }
+ else if (semanticName == "sv_vertexid")
+ {
+ return "gl_VertexIndex";
+ }
+ else if (semanticName == "sv_viewportarrayindex")
+ {
+ return "gl_ViewportIndex";
+ }
+ else if (semanticName == "nv_x_right")
+ {
+ requireGLSLVersion(ProfileVersion::GLSL_450);
+ requireGLSLExtension("GL_NVX_multiview_per_view_attributes");
+
+ // The actual output in GLSL is:
+ //
+ // vec4 gl_PositionPerViewNV[];
+ //
+ // and is meant to support an arbitrary number of views,
+ // while the HLSL case just defines a second position
+ // output.
+ //
+ // For now we will hack this by:
+ // 1. Mapping an `NV_X_Right` output to `gl_PositionPerViewNV[1]`
+ // (that is, just one element of the output array)
+ // 2. Adding logic to copy the traditional `gl_Position` output
+ // over to `gl_PositionPerViewNV[0]`
+ //
+
+ return "gl_PositionPerViewNV[1]";
+
+// shared->requiresCopyGLPositionToPositionPerView = true;
+ }
+ else if (semanticName == "nv_viewport_mask")
+ {
+ requireGLSLVersion(ProfileVersion::GLSL_450);
+ requireGLSLExtension("GL_NVX_multiview_per_view_attributes");
+
+ return "gl_ViewportMaskPerViewNV";
+// globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV",
+// getUnsizedArrayType(getIntType()));
+ }
else
{
- return "gl_Unknown";
+ getSink()->diagnose(varDecl->sourceLoc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling);
+ return semanticName;
}
}
@@ -4564,7 +4720,7 @@ emitDeclImpl(decl, nullptr);
{
if(varLayout->systemValueSemantic.Length() != 0)
{
- auto translated = getGLSLSystemValueName(varLayout);
+ auto translated = getGLSLSystemValueName(inst, varLayout);
if(translated.Length())
return translated;
}
@@ -4945,6 +5101,11 @@ emitDeclImpl(decl, nullptr);
if(getTarget(ctx) == CodeGenTarget::GLSL)
return true;
}
+ else if(type->As<HLSLStructuredBufferTypeBase>())
+ {
+ if(getTarget(ctx) == CodeGenTarget::GLSL)
+ return true;
+ }
// By default we will *not* fold things into their use sites.
return false;
@@ -6242,65 +6403,146 @@ emitDeclImpl(decl, nullptr);
}
}
- void emitIRSimpleFunc(
- EmitContext* ctx,
- IRFunc* func)
+ void emitIREntryPointAttributes_HLSL(
+ EmitContext* /*ctx*/,
+ EntryPointLayout* entryPointLayout)
{
- auto resultType = func->getResultType();
+ auto profile = entryPointLayout->profile;
+ auto stage = profile.GetStage();
- // Deal with decorations that need
- // to be emitted as attributes
- auto entryPointLayout = asEntryPoint(func);
- if (entryPointLayout)
+ switch (stage)
{
- auto profile = entryPointLayout->profile;
- auto stage = profile.GetStage();
-
- switch (stage)
+ case Stage::Compute:
{
- case Stage::Compute:
+ static const UInt kAxisCount = 3;
+ UInt sizeAlongAxis[kAxisCount];
+
+ // TODO: this is kind of gross because we are using a public
+ // reflection API function, rather than some kind of internal
+ // utility it forwards to...
+ spReflectionEntryPoint_getComputeThreadGroupSize(
+ (SlangReflectionEntryPoint*)entryPointLayout,
+ kAxisCount,
+ &sizeAlongAxis[0]);
+
+ emit("[numthreads(");
+ for (int ii = 0; ii < 3; ++ii)
{
- static const UInt kAxisCount = 3;
- UInt sizeAlongAxis[kAxisCount];
-
- // TODO: this is kind of gross because we are using a public
- // reflection API function, rather than some kind of internal
- // utility it forwards to...
- spReflectionEntryPoint_getComputeThreadGroupSize(
- (SlangReflectionEntryPoint*)entryPointLayout,
- kAxisCount,
- &sizeAlongAxis[0]);
-
- emit("[numthreads(");
- for (int ii = 0; ii < 3; ++ii)
- {
- if (ii != 0) emit(", ");
- Emit(sizeAlongAxis[ii]);
- }
- emit(")]\n");
+ if (ii != 0) emit(", ");
+ Emit(sizeAlongAxis[ii]);
}
- break;
- case Stage::Geometry:
+ emit(")]\n");
+ }
+ break;
+ case Stage::Geometry:
+ {
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>())
{
- if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>())
- {
- emit("[maxvertexcount(");
- Emit(attrib->value);
- emit(")]\n");
- }
- if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>())
+ emit("[maxvertexcount(");
+ Emit(attrib->value);
+ emit(")]\n");
+ }
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>())
+ {
+ emit("[instance(");
+ Emit(attrib->value);
+ emit(")]\n");
+ }
+ }
+ break;
+ // TODO: There are other stages that will need this kind of handling.
+ default:
+ break;
+ }
+ }
+
+ void emitIREntryPointAttributes_GLSL(
+ EmitContext* /*ctx*/,
+ EntryPointLayout* entryPointLayout)
+ {
+ auto profile = entryPointLayout->profile;
+ auto stage = profile.GetStage();
+
+ switch (stage)
+ {
+ case Stage::Compute:
+ {
+ static const UInt kAxisCount = 3;
+ UInt sizeAlongAxis[kAxisCount];
+
+ // TODO: this is kind of gross because we are using a public
+ // reflection API function, rather than some kind of internal
+ // utility it forwards to...
+ spReflectionEntryPoint_getComputeThreadGroupSize(
+ (SlangReflectionEntryPoint*)entryPointLayout,
+ kAxisCount,
+ &sizeAlongAxis[0]);
+
+ emit("layout(");
+ char const* axes[] = { "x", "y", "z" };
+ for (int ii = 0; ii < 3; ++ii)
{
- emit("[instance(");
- Emit(attrib->value);
- emit(")]\n");
+ if (ii != 0) emit(", ");
+ emit("local_size_");
+ emit(axes[ii]);
+ emit(" = ");
+ Emit(sizeAlongAxis[ii]);
}
+ emit(") in;");
}
break;
- // TODO: There are other stages that will need this kind of handling.
- default:
- break;
+ case Stage::Geometry:
+ {
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>())
+ {
+ // TODO: need to include primitive type
+ emit("layout(max_vertices = ");
+ Emit(attrib->value);
+ emit(") out;\n");
+ }
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>())
+ {
+ emit("layout(invocations = ");
+ Emit(attrib->value);
+ emit(") in;\n");
}
}
+ break;
+ // TODO: There are other stages that will need this kind of handling.
+ default:
+ break;
+ }
+ }
+
+ void emitIREntryPointAttributes(
+ EmitContext* ctx,
+ EntryPointLayout* entryPointLayout)
+ {
+ switch(getTarget(ctx))
+ {
+ case CodeGenTarget::HLSL:
+ emitIREntryPointAttributes_HLSL(ctx, entryPointLayout);
+ break;
+
+ case CodeGenTarget::GLSL:
+ emitIREntryPointAttributes_GLSL(ctx, entryPointLayout);
+ break;
+ }
+ }
+
+ void emitIRSimpleFunc(
+ EmitContext* ctx,
+ IRFunc* func)
+ {
+ auto resultType = func->getResultType();
+
+ // Deal with decorations that need
+ // to be emitted as attributes
+ auto entryPointLayout = asEntryPoint(func);
+ if (entryPointLayout)
+ {
+ emitIREntryPointAttributes(ctx, entryPointLayout);
+ }
auto name = getIRFuncName(func);
@@ -6922,6 +7164,52 @@ emitDeclImpl(decl, nullptr);
emit(";\n");
}
+ RefPtr<Type> unwrapArray(Type* type)
+ {
+ Type* t = type;
+ while( auto arrayType = t->As<ArrayExpressionType>() )
+ {
+ t = arrayType->baseType;
+ }
+ return t;
+ }
+
+ void emitIRStructuredBuffer_GLSL(
+ EmitContext* ctx,
+ IRGlobalVar* varDecl,
+ HLSLStructuredBufferTypeBase* structuredBufferType)
+ {
+ // Shader storage buffer is an OpenGL 430 feature
+ //
+ // TODO: we should require either the extension or the version...
+ requireGLSLVersion(430);
+
+ emit("layout(std430) buffer ");
+
+ // Generate a dummy name for the block
+ emit("_S");
+ Emit(ctx->shared->uniqueIDCounter++);
+
+ emit(" {\n");
+
+
+ auto elementType = structuredBufferType->getElementType();
+ emitIRType(ctx, elementType, getIRName(varDecl) + "[]");
+ emit(";\n");
+
+ emit("}");
+
+ // TODO: we need to consider the case where the type of the variable is
+ // an *array* of structured buffers, in which case we need to declare
+ // the block as an array too.
+ //
+ // The main challenge here is that then the block will have a name,
+ // and also the field inside the block will have a name, so that when
+ // the user had written `a[i][j]` we now need to emit `a[i].someName[j]`.
+
+ emit(";\n");
+ }
+
void emitIRGlobalVar(
EmitContext* ctx,
IRGlobalVar* varDecl)
@@ -6955,6 +7243,45 @@ emitDeclImpl(decl, nullptr);
return;
}
+ if(getTarget(ctx) == CodeGenTarget::GLSL)
+ {
+ // When outputting GLSL, we need to transform any declaration of
+ // a `*StructuredBuffer<T>` into an ordinary `buffer` declaration.
+ if( auto structuredBufferType = unwrapArray(varType)->As<HLSLStructuredBufferTypeBase>() )
+ {
+ emitIRStructuredBuffer_GLSL(
+ ctx,
+ varDecl,
+ structuredBufferType);
+ return;
+ }
+
+ // We want to skip the declaration of any system-value variables
+ // when outputting GLSL (well, except in the case where they
+ // actually *require* redeclaration...).
+
+ if(auto layoutMod = varDecl->findDecoration<IRLayoutDecoration>())
+ {
+ auto layout = layoutMod->layout;
+ if(auto varLayout = layout.As<VarLayout>())
+ {
+ if(varLayout->systemValueSemantic.Length() != 0)
+ {
+ auto translated = getGLSLSystemValueName(varDecl, varLayout);
+ if( translated.Length() )
+ {
+ // The variable seems to translate to an OpenGL
+ // system value, so we will assume that it doesn't
+ // need to be declared.
+ //
+ // TODO: handle case where we *should* declare the variable.
+ return;
+ }
+ }
+ }
+ }
+ }
+
// Need to emit appropriate modifiers here.
auto layout = getVarLayout(ctx, varDecl);
diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h
index db9630c0e..a5b9cd659 100644
--- a/source/slang/type-defs.h
+++ b/source/slang/type-defs.h
@@ -247,15 +247,17 @@ SIMPLE_SYNTAX_CLASS(PointerLikeType, BuiltinGenericType)
// HLSL buffer-type resources
-SIMPLE_SYNTAX_CLASS(HLSLStructuredBufferType, BuiltinGenericType)
-SIMPLE_SYNTAX_CLASS(HLSLRWStructuredBufferType, BuiltinGenericType)
+SIMPLE_SYNTAX_CLASS(HLSLStructuredBufferTypeBase, BuiltinGenericType)
+SIMPLE_SYNTAX_CLASS(HLSLStructuredBufferType, HLSLStructuredBufferTypeBase)
+SIMPLE_SYNTAX_CLASS(HLSLRWStructuredBufferType, HLSLStructuredBufferTypeBase)
+// TODO: need raster-ordered case here
SIMPLE_SYNTAX_CLASS(UntypedBufferResourceType, DeclRefType)
SIMPLE_SYNTAX_CLASS(HLSLByteAddressBufferType, UntypedBufferResourceType)
SIMPLE_SYNTAX_CLASS(HLSLRWByteAddressBufferType, UntypedBufferResourceType)
-SIMPLE_SYNTAX_CLASS(HLSLAppendStructuredBufferType, BuiltinGenericType)
-SIMPLE_SYNTAX_CLASS(HLSLConsumeStructuredBufferType, BuiltinGenericType)
+SIMPLE_SYNTAX_CLASS(HLSLAppendStructuredBufferType, HLSLStructuredBufferTypeBase)
+SIMPLE_SYNTAX_CLASS(HLSLConsumeStructuredBufferType, HLSLStructuredBufferTypeBase)
SYNTAX_CLASS(HLSLPatchType, DeclRefType)
RAW(