diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-10 08:34:52 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-10 08:34:52 -0700 |
| commit | 0e220da96b819f3a31635689f78ad20bd9a36d0b (patch) | |
| tree | 7728d25df51cb8488ac681715a82b359730b796d | |
| parent | 928cc86160644547decc49c72304549d9009a1af (diff) | |
More cross-compilation fixes
- Add GLSL mappings for more `Texture*` methods
- The annoying one here is `Texture*.Load()` because it doesn't take a sampler, but the GLSL equivalent needs one (while the SPIR-V does *not*). I've hacked this pretty seriously for now.
- Try to ensure that we add `uniform` to global declarations that need it in GLSL
- When outputting an `in` or `out` variable that might have been created from an `inout` shader parameter, filter the layout qualifiers that we output to only cover the appropriate resource kind.
| -rw-r--r-- | source/slang/emit.cpp | 125 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 20 | ||||
| -rw-r--r-- | source/slang/modifier-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 29 |
5 files changed, 172 insertions, 5 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index c135090c1..01b3e8cc2 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -48,6 +48,10 @@ struct SharedEmitContext StructTypeLayout* globalStructLayout; ProgramLayout* programLayout; + + ProgramSyntaxNode* program; + + bool needHackSamplerForTexelFetch = false; }; struct EmitContext @@ -1758,6 +1762,66 @@ struct EmitVisitor } break; + case 'P': + { + // Okay, we need a collosal hack to deal with the fact that GLSL `texelFetch()` + // for Vulkan seems to be completely broken by design. It's signature wants + // a `sampler2D` for consistency with its peers, but the actual SPIR-V operation + // ignores the sampler paart of it, and just used the `texture2D` part. + // + // The HLSL equivalent (e.g., `Texture2D.Load()`) doesn't provide a sampler + // argument, so we seemingly need to conjure one out of thin air. :( + // + // We are going to hack this *hard* for now. + + // Try to find a suitable sampler-type shader parameter in the global scope + // (fingers crossed) + RefPtr<VarDeclBase> samplerVar; + for (auto d : context->shared->program->Members) + { + if (auto varDecl = d.As<VarDeclBase>()) + { + if (auto samplerType = varDecl->Type.type->As<SamplerStateType>()) + { + samplerVar = varDecl; + break; + } + } + } + + if (auto memberExpr = callExpr->FunctionExpr.As<MemberExpressionSyntaxNode>()) + { + auto base = memberExpr->BaseExpression; + if (auto baseTextureType = base->Type->As<TextureType>()) + { + emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); + Emit("("); + EmitExpr(memberExpr->BaseExpression); + Emit(","); + if (samplerVar) + { + EmitDeclRef(makeDeclRef(samplerVar.Ptr())); + } + else + { + Emit("SLANG_hack_samplerForTexelFetch"); + context->shared->needHackSamplerForTexelFetch = true; + } + Emit(")"); + } + else + { + assert(!"unexpected"); + } + + } + else + { + assert(!"unexpected"); + } + } + break; + default: assert(!"unexpected"); break; @@ -2476,6 +2540,9 @@ struct EmitVisitor #define CASE(TYPE, KEYWORD) \ else if(auto mod_##TYPE = mod.As<TYPE>()) Emit(#KEYWORD " ") + #define CASE2(TYPE, HLSL_NAME, GLSL_NAME) \ + else if(auto mod_##TYPE = mod.As<TYPE>()) Emit((context->shared->target == CodeGenTarget::GLSL) ? GLSL_NAME : HLSL_NAME) + CASE(RowMajorLayoutModifier, row_major); CASE(ColumnMajorLayoutModifier, column_major); CASE(HLSLNoInterpolationModifier, nointerpolation); @@ -2502,6 +2569,7 @@ struct EmitVisitor CASE(ConstModifier, const); #undef CASE + #undef CASE2 else if (auto staticModifier = mod.As<HLSLStaticModifier>()) { @@ -2949,7 +3017,8 @@ struct EmitVisitor } void emitGLSLLayoutQualifiers( - RefPtr<VarLayout> layout) + RefPtr<VarLayout> layout, + LayoutResourceKind filter = LayoutResourceKind::None) { if(!layout) return; @@ -2964,6 +3033,13 @@ struct EmitVisitor for( auto info : layout->resourceInfos ) { + // Skip info that doesn't match our filter + if (filter != LayoutResourceKind::None + && filter != info.kind) + { + continue; + } + emitGLSLLayoutQualifier(info); } } @@ -3095,7 +3171,33 @@ struct EmitVisitor return; } - emitGLSLLayoutQualifiers(layout); + + if (context->shared->target == CodeGenTarget::GLSL) + { + if (decl->HasModifier<InModifier>()) + { + emitGLSLLayoutQualifiers(layout, LayoutResourceKind::VertexInput); + } + else if (decl->HasModifier<OutModifier>()) + { + emitGLSLLayoutQualifiers(layout, LayoutResourceKind::FragmentOutput); + } + else + { + emitGLSLLayoutQualifiers(layout); + } + + // If we have a uniform that wasn't tagged `uniform` in GLSL, then fix that here + if (layout + && !decl->HasModifier<HLSLUniformModifier>()) + { + if (layout->FindResourceInfo(LayoutResourceKind::Uniform) + || layout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) + { + Emit("uniform "); + } + } + } EmitVarDeclCommon(decl); @@ -3288,6 +3390,9 @@ String emitEntryPoint( // There may be global-scope modifiers that we should emit now visitor.emitGLSLPreprocessorDirectives(translationUnitSyntax); + String prefix = sharedContext.sb.ProduceString(); + sharedContext.sb.Clear(); + switch(target) { case CodeGenTarget::GLSL: @@ -3303,6 +3408,8 @@ String emitEntryPoint( auto lowered = lowerEntryPoint(entryPoint, programLayout, target); + sharedContext.program = lowered.program; + visitor.EmitDeclsInContainer(lowered.program.Ptr()); #if 0 @@ -3324,7 +3431,19 @@ String emitEntryPoint( String code = sharedContext.sb.ProduceString(); - return code; + StringBuilder finalResultBuilder; + finalResultBuilder << prefix; + + if (sharedContext.needHackSamplerForTexelFetch) + { + finalResultBuilder << "layout(set = 0, binding = 0) uniform sampler SLANG_hack_samplerForTexelFetch;\n"; + } + + finalResultBuilder << code; + + String finalResult = finalResultBuilder.ProduceString(); + + return finalResult; } } // namespace Slang diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 6c54d18b6..023c63591 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -194,6 +194,8 @@ public: struct SharedLoweringContext { + CompileRequest* compileRequest; + ProgramLayout* programLayout; // The target we are going to generate code for. @@ -1372,6 +1374,23 @@ struct LoweringVisitor return loweredDecl; } + SourceLanguage getSourceLanguage(ProgramSyntaxNode* moduleDecl) + { + for (auto translationUnit : shared->compileRequest->translationUnits) + { + if (moduleDecl == translationUnit->SyntaxNode) + return translationUnit->sourceLanguage; + } + + for (auto loadedModuleDecl : shared->compileRequest->loadedModulesList) + { + if (moduleDecl == loadedModuleDecl) + return SourceLanguage::Slang; + } + + return SourceLanguage::Unknown; + } + RefPtr<VarDeclBase> visitVariable( Variable* decl) { @@ -2022,6 +2041,7 @@ LoweredEntryPoint lowerEntryPoint( CodeGenTarget target) { SharedLoweringContext sharedContext; + sharedContext.compileRequest = entryPoint->compileRequest; sharedContext.programLayout = programLayout; sharedContext.target = target; diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h index e50288600..083da79f0 100644 --- a/source/slang/modifier-defs.h +++ b/source/slang/modifier-defs.h @@ -6,7 +6,6 @@ #define SIMPLE_MODIFIER(NAME) \ SIMPLE_SYNTAX_CLASS(NAME##Modifier, Modifier) -SIMPLE_MODIFIER(Uniform); SIMPLE_MODIFIER(In); SIMPLE_MODIFIER(Out); SIMPLE_MODIFIER(Const); diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 228af7d99..ec611f8b1 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -1045,7 +1045,7 @@ static void collectEntryPointParameters( // We have an entry-point parameter, and need to figure out what to do with it. // TODO: need to handle `uniform`-qualified parameters here - if (paramDecl->HasModifier<UniformModifier>()) + if (paramDecl->HasModifier<HLSLUniformModifier>()) continue; state.directionMask = 0; diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index e2d5829b4..23d66201a 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1431,6 +1431,22 @@ namespace Slang { int loadCoordCount = kBaseTextureTypes[tt].coordCount + isArray + (isMultisample?0:1); + // When translating to GLSL, we need to break apart the `location` argument. + // + // TODO: this should realy be handled by having this member actually get lowered! + int glslLoadCoordCount = kBaseTextureTypes[tt].coordCount + isArray; + static const char* kGLSLLoadCoordsSwizzle[] = { "", "", "x", "xy", "xyz", "xyzw" }; + static const char* kGLSLLoadLODSwizzle[] = { "", "", "y", "z", "w", "error" }; + + if (isMultisample) + { + sb << "__intrinsic(glsl, \"texelFetch($P, $0, $1)\")\n"; + } + else + { + sb << "__intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n"; + } + sb << "__intrinsic\n"; sb << "T Load("; sb << "int" << loadCoordCount << " location"; if(isMultisample) @@ -1439,6 +1455,15 @@ namespace Slang } sb << ");\n"; + if (isMultisample) + { + sb << "__intrinsic(glsl, \"texelFetchOffset($P, $0, $1, $2)\")\n"; + } + else + { + sb << "__intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $1)\")\n"; + } + sb << "__intrinsic\n"; sb << "T Load("; sb << "int" << loadCoordCount << " location"; if(isMultisample) @@ -1470,11 +1495,15 @@ namespace Slang { // `Sample()` + sb << "__intrinsic(glsl, \"texture($p, $1)\")\n"; + sb << "__intrinsic\n"; sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; if( baseShape != TextureType::ShapeCube ) { + sb << "__intrinsic(glsl, \"textureOffset($p, $1)\")\n"; + sb << "__intrinsic\n"; sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; |
