Skip to content

Commit

Permalink
Merge pull request #9350 from hrydgard/d3d11-postproc
Browse files Browse the repository at this point in the history
D3D11 postprocessing shaders
  • Loading branch information
hrydgard authored Feb 23, 2017
2 parents 79bd01e + 86f0be7 commit c355947
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 75 deletions.
132 changes: 127 additions & 5 deletions GPU/Common/ShaderTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@

#include <memory>
#include <vector>
#include <sstream>

// DbgNew is not compatible with Glslang
#ifdef DBG_NEW
#undef new
#endif

#include "base/logging.h"
#include "base/basictypes.h"
#include "base/stringutil.h"
#include "ShaderTranslation.h"
#include "ext/glslang/SPIRV/GlslangToSpv.h"
#include "thin3d/thin3d.h"
Expand All @@ -51,8 +54,117 @@ static EShLanguage GetLanguage(const Draw::ShaderStage stage) {
}
}

void ShaderTranslationInit() {
glslang::InitializeProcess();
}
void ShaderTranslationShutdown() {
glslang::FinalizeProcess();
}

std::string Preprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage stage) {
// This takes GL up to the version we need.
return code;
}

struct Builtin {
const char *needle;
const char *replacement;
};

// Workaround for deficiency in SPIRV-Cross
static const Builtin builtins[] = {
{"lessThan",
R"(
bool2 lessThan(float2 a, float2 b) { return bool2(a.x < b.x, a.y < b.y); }
bool3 lessThan(float3 a, float3 b) { return bool3(a.x < b.x, a.y < b.y, a.z < b.z); }
bool4 lessThan(float4 a, float4 b) { return bool4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w); }
)"},
{ "lessThanEqual",
R"(
bool2 lessThanEqual(float2 a, float2 b) { return bool2(a.x <= b.x, a.y <= b.y); }
bool3 lessThanEqual(float3 a, float3 b) { return bool3(a.x <= b.x, a.y <= b.y, a.z <= b.z); }
bool4 lessThanEqual(float4 a, float4 b) { return bool4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w); }
)" },
{ "greaterThan",
R"(
bool2 greaterThan(float2 a, float2 b) { return bool2(a.x > b.x, a.y > b.y); }
bool3 greaterThan(float3 a, float3 b) { return bool3(a.x > b.x, a.y > b.y, a.z > b.z); }
bool4 greaterThan(float4 a, float4 b) { return bool4(a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w); }
)" },
{ "greaterThanEqual",
R"(
bool2 greaterThanEqual(float2 a, float2 b) { return bool2(a.x >= b.x, a.y >= b.y); }
bool3 greaterThanEqual(float3 a, float3 b) { return bool3(a.x >= b.x, a.y >= b.y, a.z >= b.z); }
bool4 greaterThanEqual(float4 a, float4 b) { return bool4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w); }
)" },
{ "equal",
R"(
bool2 equal(float2 a, float2 b) { return bool2(a.x == b.x, a.y == b.y); }
bool3 equal(float3 a, float3 b) { return bool3(a.x == b.x, a.y == b.y, a.z == b.z); }
bool4 equal(float4 a, float4 b) { return bool4(a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w); }
)" },
{ "notEqual",
R"(
bool2 notEqual(float2 a, float2 b) { return bool2(a.x != b.x, a.y != b.y); }
bool3 notEqual(float3 a, float3 b) { return bool3(a.x != b.x, a.y != b.y, a.z != b.z); }
bool4 notEqual(float4 a, float4 b) { return bool4(a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w); }
)" },
};

static const Builtin replacements[] = {
{ "mix(", "lerp(" },
{ "fract(", "frac(" },
};

static const char *cbufferDecl = R"(
cbuffer data : register(b0) {
float2 u_texelDelta;
float2 u_pixelDelta;
float4 u_time;
};
)";

// SPIRV-Cross' HLSL output has some deficiencies we need to work around.
// Also we need to rip out single uniforms and replace them with blocks.
// Should probably do it in the source shader instead and then back translate to old style GLSL, but
// SPIRV-Cross currently won't compile with the Android NDK so I can't be bothered.
std::string Postprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage stage) {
if (lang != HLSL_D3D11)
return code;

std::stringstream out;

// Output the uniform buffer.
out << cbufferDecl;

// Add the builtins if required.
for (int i = 0; i < ARRAY_SIZE(builtins); i++) {
if (!builtins[i].needle)
continue;
if (code.find(builtins[i].needle) != std::string::npos) {
out << builtins[i].replacement;
}
}

// Perform some replacements
for (int i = 0; i < ARRAY_SIZE(replacements); i++) {
code = ReplaceAll(code, replacements[i].needle, replacements[i].replacement);
}

// Alright, now let's go through it line by line and zap the single uniforms.
std::string line;
std::stringstream instream(code);
while (std::getline(instream, line)) {
if (line.find("uniform float") != std::string::npos)
continue;
out << line << "\n";
}
std::string output = out.str();
return output;
}

bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShaderMetadata *destMetadata, std::string src, ShaderLanguage srcLang, Draw::ShaderStage stage, std::string *errorMessage) {
if (srcLang != GLSL_300)
if (srcLang != GLSL_300 && srcLang != GLSL_140)
return false;

glslang::TProgram program;
Expand All @@ -62,15 +174,16 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
init_resources(Resources);

// Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
EShMessages messages = EShMessages::EShMsgDefault; // (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);

EShLanguage shaderStage = GetLanguage(stage);
glslang::TShader shader(shaderStage);

std::string preprocessed = Preprocess(src, srcLang, stage);

shaderStrings[0] = src.c_str();
shader.setStrings(shaderStrings, 1);

if (!shader.parse(&Resources, 100, false, messages)) {
if (!shader.parse(&Resources, 100, EProfile::ECompatibilityProfile, false, false, messages)) {
ELOG("%s", shader.getInfoLog());
ELOG("%s", shader.getInfoDebugLog());
if (errorMessage) {
Expand Down Expand Up @@ -116,11 +229,20 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
case HLSL_D3D11:
{
spirv_cross::CompilerHLSL hlsl(spirv);
spirv_cross::ShaderResources resources = hlsl.get_shader_resources();

int i = 0;
for (auto &resource : resources.sampled_images) {
// int location = hlsl.get_decoration(resource.id, spv::DecorationLocation);
hlsl.set_decoration(resource.id, spv::DecorationLocation, i);
i++;
}
spirv_cross::CompilerHLSL::Options options{};
options.fixup_clipspace = true;
options.shader_model = 50;
hlsl.set_options(options);
*dest = hlsl.compile();
std::string raw = hlsl.compile();
*dest = Postprocess(raw, destLang, stage);
return true;
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions GPU/Common/ShaderTranslation.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ struct TranslatedShaderMetadata {

};

void ShaderTranslationInit();
void ShaderTranslationShutdown();

bool TranslateShader(std::string *dst, ShaderLanguage destLang, TranslatedShaderMetadata *destMetadata, std::string src, ShaderLanguage srcLang, Draw::ShaderStage stage, std::string *errorMessage);

#endif
28 changes: 19 additions & 9 deletions GPU/D3D11/D3D11Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

#include "D3D11Util.h"

static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t codeSize, const char *target) {
static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t codeSize, const char *target, UINT flags) {
ID3DBlob *compiledCode = nullptr;
ID3DBlob *errorMsgs = nullptr;
HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs);
HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs);
std::string errors;
if (errorMsgs) {
errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize());
Expand All @@ -26,12 +26,11 @@ static std::vector<uint8_t> CompileShaderToBytecode(const char *code, size_t cod
compiledCode->Release();
return compiled;
}
Crash();
return std::vector<uint8_t>();
}

ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "vs_5_0");
ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut, UINT flags) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "vs_5_0", flags);
if (byteCode.empty())
return nullptr;

Expand All @@ -42,8 +41,8 @@ ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *co
return vs;
}

ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "ps_5_0");
ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "ps_5_0", flags);
if (byteCode.empty())
return nullptr;

Expand All @@ -52,8 +51,8 @@ ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code
return ps;
}

ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "cs_5_0");
ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "cs_5_0", flags);
if (byteCode.empty())
return nullptr;

Expand All @@ -62,6 +61,17 @@ ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *
return cs;
}

ID3D11GeometryShader *CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags) {
std::vector<uint8_t> byteCode = CompileShaderToBytecode(code, codeSize, "gs_5_0", flags);
if (byteCode.empty())
return nullptr;

ID3D11GeometryShader *gs;
device->CreateGeometryShader(byteCode.data(), byteCode.size(), nullptr, &gs);
return gs;
}


void StockObjectsD3D11::Create(ID3D11Device *device) {
D3D11_BLEND_DESC blend_desc{};
blend_desc.RenderTarget[0].BlendEnable = false;
Expand Down
7 changes: 4 additions & 3 deletions GPU/D3D11/D3D11Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ class PushBufferD3D11 {
bool nextMapDiscard_ = false;
};

ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut);
ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize);
ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize);
ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector<uint8_t> *byteCodeOut, UINT flags = 0);
ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags = 0);
ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags = 0);
ID3D11GeometryShader *CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, UINT flags = 0);

class StockObjectsD3D11 {
public:
Expand Down
Loading

0 comments on commit c355947

Please sign in to comment.