Skip to content

Commit

Permalink
shaderpipeline: cleanup of glslang front-end, flesh out Cg preamble
Browse files Browse the repository at this point in the history
Support for cube maps is commented out for now pending KhronosGroup/glslang#2265
  • Loading branch information
rdb committed Jun 10, 2020
1 parent ae30b2b commit 194bd47
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 55 deletions.
132 changes: 132 additions & 0 deletions src/shaderpipeline/cg_preamble.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cg_preamble.hlsl
* @author rdb
* @date 2020-06-10
*/

/**
* This file gets loaded as preamble to any Cg shader to be able to compile it
* through the HLSL front-end of the glslang compiler. It defines functions
* and types that were supported in Cg but are not available in HLSL.
*/

typedef sampler2D sampler2DShadow;

float4 shadow2D(sampler2D samp, float3 s) {
return tex2D(samp, s.xy).r > s.z;
}

float4 shadow2DProj(sampler2D samp, float4 s) {
return tex2Dproj(samp, s).r > s.z / s.w;
}

float4 f4tex1D(sampler1D samp, float s) {
return tex1D(samp, s);
}

float4 f4tex1D(sampler1D samp, float2 s) {
return tex1D(samp, s.x).r > s.y;
}

float4 f4tex1D(sampler1D samp, float s, float dx, float dy) {
return tex1D(samp, s, dx, dy);
}

float4 f4tex1D(sampler1D samp, float2 s, float dx, float dy) {
return tex1D(samp, s.x, dx, dy).r > s.y;
}

float4 f4tex1Dproj(sampler1D samp, float2 s) {
return tex1Dproj(samp, s.xxxy);
}

float4 f4tex1Dproj(sampler1D samp, float3 s) {
return tex1Dproj(samp, s.xxxz).r > s.y / s.z;
}

float4 f4tex1Dproj(sampler1D samp, float2 s, float dx, float dy) {
return tex1D(samp, s.x / s.y, dx, dy);
}

float4 f4tex1Dproj(sampler1D samp, float3 s, float dx, float dy) {
return tex1D(samp, s.x / s.z).r > s.y / s.z;
}

float4 f4tex2D(sampler2D samp, float2 s) {
return tex2D(samp, s.xy);
}

float4 f4tex2D(sampler2D samp, float3 s) {
return tex2D(samp, s.xy).r > s.z;
}

float4 f4tex2D(sampler2D samp, float2 s, float2 dx, float2 dy) {
return tex2D(samp, s.xy, dx, dy);
}

float4 f4tex2D(sampler2D samp, float3 s, float2 dx, float2 dy) {
return tex2D(samp, s.xy, dx, dy).r > s.z;
}

float4 f4tex2Dproj(sampler2D samp, float3 s) {
return tex2Dproj(samp, s.xyzz);
}

float4 f4tex2Dproj(sampler2D samp, float4 s) {
return tex2Dproj(samp, s).r > s.z / s.w;
}

float4 f4tex2Dproj(sampler2D samp, float3 s, float2 dx, float2 dy) {
return tex2D(samp, s.xyyz, dx, dy);
}

float4 f4tex2Dproj(sampler2D samp, float4 s, float2 dx, float2 dy) {
return tex2D(samp, s.xy / s.w, dx, dy).r > s.z / s.w;
}

/*
float4 f4texCUBE(samplerCUBE samp, float3 s) {
return texCUBE(samp, s);
}
float4 f4texCUBE(samplerCUBE samp, float4 s) {
return texCUBE(samp, s.xyz).r > s.w;
}
float4 f4texCUBE(samplerCUBE samp, float3 s, float3 dx, float3 dy) {
return texCUBE(samp, s, dx, dy);
}
float4 f4texCUBE(samplerCUBE samp, float4 s, float3 dx, float3 dy) {
return texCUBE(samp, s.xyz, dx, dy).r > s.w;
}
*/

#define f1tex1D(x, y) (f4tex1D((x), (y)).r)
#define f3tex1D(x, y) (f4tex1D((x), (y)).rgb)
#define tex1D f4tex1D

#define f1tex1Dproj(x, y) (f4tex1Dproj((x), (y)).r)
#define f3tex1Dproj(x, y) (f4tex1Dproj((x), (y)).rgb)
#define tex1Dproj f4tex1Dproj

#define f1tex2D(x, y) (f4tex2D((x), (y)).r)
#define f3tex2D(x, y) (f4tex2D((x), (y)).rgb)
#define tex2D f4tex2D

#define f1tex2Dproj(x, y) (f4tex2Dproj((x), (y)).r)
#define f3tex2Dproj(x, y) (f4tex2Dproj((x), (y)).rgb)
#define tex2Dproj f4tex2Dproj

/*
#define f1texCUBE(x, y) (f4texCUBE((x), (y)).r)
#define f3texCUBE(x, y) (f4texCUBE((x), (y)).rgb)
#define texCUBE f4texCUBE
*/
134 changes: 79 additions & 55 deletions src/shaderpipeline/shaderCompilerGlslang.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
int glsl_version = 110;

// Is this a Cg shader or a GLSL shader?
if (code.size() >= 5 && strncmp((const char *)&code[0], "//Cg\n", 5) == 0) {
if (code.size() >= 5 &&
strncmp((const char *)&code[0], "//Cg", 4) == 0 && isspace(code[4])) {
is_cg = true;
}
else if (!preprocess_glsl(code, glsl_version, add_include_directive)) {
Expand All @@ -298,94 +299,123 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
is_initialized = true;
}

EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules);
EShLanguage language;
switch (stage) {
case ShaderModule::Stage::vertex:
language = EShLangVertex;
break;
case ShaderModule::Stage::tess_control:
language = EShLangTessControl;
break;
case ShaderModule::Stage::tess_evaluation:
language = EShLangTessEvaluation;
break;
case ShaderModule::Stage::geometry:
language = EShLangGeometry;
break;
case ShaderModule::Stage::fragment:
language = EShLangFragment;
break;
default:
shader_cat.error()
<< "glslang compiler does not support " << stage << " shaders.\n";
return nullptr;
}

glslang::TShader shader(language);

const char *string = (const char *)code.data();
const int length = (int)code.size();
const char *fname = filename.c_str();

EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules);

glslang::TShader *shader = new glslang::TShader((EShLanguage)stage);
shader->setStringsWithLengthsAndNames(&string, &length, &fname, 1);
shader->setEntryPoint("main");
shader.setStringsWithLengthsAndNames(&string, &length, &fname, 1);
shader.setEntryPoint("main");

// If it's marked as a Cg shader, we compile it with the HLSL front-end.
if (is_cg) {
shader->setEnvInput(glslang::EShSource::EShSourceHlsl, (EShLanguage)stage, glslang::EShClient::EShClientOpenGL, 120);
messages = (EShMessages)(messages | EShMsgHlslDX9Compatible | EShMsgHlslLegalization);

const char *source_entry_point;
switch (stage) {
case ShaderModule::Stage::vertex:
shader->setSourceEntryPoint("vshader");
source_entry_point = "vshader";
break;
case ShaderModule::Stage::geometry:
shader->setSourceEntryPoint("gshader");
source_entry_point = "gshader";
break;
case ShaderModule::Stage::fragment:
shader->setSourceEntryPoint("fshader");
source_entry_point = "fshader";
break;
default:
shader_cat.error()
<< "Cg does not support " << stage << " shaders.\n";
return nullptr;
}
shader.setSourceEntryPoint(source_entry_point);

shader->setPreamble(
"#define f1tex2D(x, y) (tex2D(x, y).r)\n"
"#define sampler2DShadow sampler2D\n"
"#define shadow2D(s, tc) (float4(tex2D(s, tc) > tc.z))\n"
"#define shadow2DProj(s, tc) (float4(tex2Dproj(s, tc) > tc.z / tc.w))\n"
);
messages = (EShMessages)(messages | EShMsgHlslDX9Compatible | EShMsgHlslLegalization);
// Generate a special preamble to define some functions that Cg defines but
// HLSL doesn't. This is sourced from cg_preamble.hlsl.
extern const char cg_preamble[];
shader.setPreamble(cg_preamble);

shader.setEnvInput(glslang::EShSource::EShSourceHlsl, (EShLanguage)stage, glslang::EShClient::EShClientOpenGL, 120);
} else {
shader->setEnvInput(glslang::EShSource::EShSourceGlsl, (EShLanguage)stage, glslang::EShClient::EShClientOpenGL, 450);
shader.setEnvInput(glslang::EShSource::EShSourceGlsl, (EShLanguage)stage, glslang::EShClient::EShClientOpenGL, 450);

if (add_include_directive) {
shader->setPreamble(
shader.setPreamble(
"#extension GL_GOOGLE_include_directive : require\n"
);
}
}
shader->setEnvClient(glslang::EShClient::EShClientOpenGL, glslang::EShTargetOpenGL_450);
shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
shader.setEnvClient(glslang::EShClient::EShClientOpenGL, glslang::EShTargetOpenGL_450);
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);

// This will squelch the warnings about missing bindings and locations, since
// we can assign those ourselves.
shader->setAutoMapBindings(true);
shader->setAutoMapLocations(true);
shader.setAutoMapBindings(true);
shader.setAutoMapLocations(true);

Includer includer(record);
if (!shader->parse(&resource_limits, 110, false, messages, includer)) {
std::cerr << "failed to parse " << filename << ":\n";
std::cerr << shader->getInfoLog() << "\n";
std::cerr << shader->getInfoDebugLog() << "\n";
if (!shader.parse(&resource_limits, 110, false, messages, includer)) {
shader_cat.error()
<< "Failed to parse " << filename << ":\n"
<< shader.getInfoLog();
return nullptr;
}

// I don't know why we need to pretend to link it into a program. One would
// think one can just do shader->getIntermediate() and convert that to SPIR-V,
// but that generates shaders that are ever-so-subtly wrong.
glslang::TProgram program;
program.addShader(shader);
ShaderModuleSpirV::InstructionStream stream;
{
glslang::TProgram program;
program.addShader(&shader);
if (!program.link(messages)) {
shader_cat.error()
<< "Failed to link " << filename << "\n";
return nullptr;
}

if (!program.link(messages)) {
std::cerr << "failed to link " << filename << "\n";
return nullptr;
}
glslang::TIntermediate *ir = program.getIntermediate((EShLanguage)stage);
nassertr(ir != nullptr, nullptr);

glslang::TIntermediate *ir = program.getIntermediate((EShLanguage)stage);
if (!ir) {
std::cerr << "failed to obtain IR " << filename << ":\n";
return nullptr;
}
spv::SpvBuildLogger logger;
glslang::SpvOptions spvOptions;
spvOptions.generateDebugInfo = true;
spvOptions.disableOptimizer = false;
spvOptions.optimizeSize = false;
spvOptions.disassemble = false;
spvOptions.validate = true;
glslang::GlslangToSpv(*ir, stream, &logger, &spvOptions);

ShaderModuleSpirV::InstructionStream stream;
std::string warningsErrors;
spv::SpvBuildLogger logger;
glslang::SpvOptions spvOptions;
spvOptions.generateDebugInfo = true;
spvOptions.disableOptimizer = false;
spvOptions.optimizeSize = false;
spvOptions.disassemble = false;
spvOptions.validate = true;
glslang::GlslangToSpv(*ir, stream, &logger, &spvOptions);
std::string messages = logger.getAllMessages();
if (!messages.empty()) {
shader_cat.warning()
<< "Compilation to SPIR-V produced the following messages:\n"
<< messages;
}
}

if (!stream.validate_header()) {
return nullptr;
Expand All @@ -396,12 +426,6 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
return nullptr;
}

printf("%s", logger.getAllMessages().c_str());
/*if (Options & EOptionOutputHexadecimal) {
} else {
glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
}*/

// Run it through the optimizer.
spvtools::Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.SetMessageConsumer(log_message);
Expand Down

0 comments on commit 194bd47

Please sign in to comment.