diff --git a/GPU/Common/ColorReinterpret.cpp b/GPU/Common/ColorReinterpret.cpp new file mode 100644 index 0000000000..3699d2f8aa --- /dev/null +++ b/GPU/Common/ColorReinterpret.cpp @@ -0,0 +1,49 @@ +#include + +#include "GPU/Common/ColorReinterpret.h" +#include "GPU/Common/ShaderWriter.h" + +// TODO: We could have an option to preserve any extra color precision. But gonna start without it. +// Requires full size integer math. +bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) { + if (!lang.bitwiseOps) { + return false; + } + ShaderWriter writer(buffer, lang, ShaderStage::Fragment); + + switch (from) { + case GE_FORMAT_4444: + writer.W(" uint color = uint(in.r * 15.99) | (uint(in.g * 15.99) << 4) | (uint(in.b * 15.99) << 8) | (uint(in.a * 15.99) << 12);\n"); + break; + case GE_FORMAT_5551: + writer.W(" uint color = uint(in.r * 31.99) | (uint(in.g * 31.99) << 5) | (uint(in.b * 31.99) << 10);\n"); + writer.W(" if (in.a > 128.0) color |= 0x8000;\n"); + break; + case GE_FORMAT_565: + writer.W(" uint color = uint(in.r * 31.99) | (uint(in.g * 63.99) << 5) | (uint(in.b * 31.99) << 11);\n"); + break; + default: _assert_(false); + } + + switch (to) { + case GE_FORMAT_4444: + writer.W(" vec4 output = vec4(float(color & 0xF), float((color >> 4) & 0xF), float((color >> 8) & 0xF), float((color >> 12) & 0xF));\n"); + writer.W(" output *= 1.0 / 15.0;\n"); + break; + case GE_FORMAT_5551: + writer.W(" vec4 output = vec4(float(color & 0x1F), float((color >> 5) & 0x1F), float((color >> 10) & 0x1F), 0.0);\n"); + writer.W(" output.rgb *= 1.0 / 31.0;\n"); + writer.W(" output.a = float(color >> 15);\n"); + break; + case GE_FORMAT_565: + writer.W(" vec4 output = vec4(float(color & 0x1F), float((color >> 5) & 0x3F), float((color >> 11) & 0x1F), 1.0);\n"); + writer.W(" output.rb *= 1.0 / 31.0;\n"); + writer.W(" output.g *= 1.0 / 63.0;\n"); + break; + default: _assert_(false); + } + + writer.W("}"); + + return true; +} diff --git a/GPU/Common/ColorReinterpret.h b/GPU/Common/ColorReinterpret.h new file mode 100644 index 0000000000..c1ff33226a --- /dev/null +++ b/GPU/Common/ColorReinterpret.h @@ -0,0 +1,6 @@ +#pragma once + +#include "Common/Log.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUCommon.h" +#include "GPU/Common/ShaderWriter.h" diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index bb51a14c36..612d9f6c7d 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -27,44 +27,11 @@ #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderUniforms.h" #include "GPU/Common/FragmentShaderGenerator.h" +#include "GPU/Common/ShaderWriter.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" -#define WRITE p+=sprintf - -const char *vulkan_glsl_preamble_fs = -"#version 450\n" -"#extension GL_ARB_separate_shader_objects : enable\n" -"#extension GL_ARB_shading_language_420pack : enable\n" -"#extension GL_ARB_conservative_depth : enable\n" -"#extension GL_ARB_shader_image_load_store : enable\n" -"#define splat3(x) vec3(x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"#define DISCARD discard\n" -"\n"; - -const char *hlsl_preamble_fs = -"#define vec2 float2\n" -"#define vec3 float3\n" -"#define vec4 float4\n" -"#define uvec3 uint3\n" -"#define ivec3 int3\n" -"#define ivec4 int4\n" -"#define mat4 float4x4\n" -"#define mat3x4 float4x3\n" // note how the conventions are backwards -"#define splat3(x) float3(x, x, x)\n" -"#define mix lerp\n" -"#define mod(x, y) fmod(x, y)\n"; - -const char *hlsl_d3d11_preamble_fs = -"#define DISCARD discard\n" -"#define DISCARD_BELOW(x) clip(x);\n"; -const char *hlsl_d3d9_preamble_fs = -"#define DISCARD clip(-1)\n" -"#define DISCARD_BELOW(x) clip(x)\n"; - +#define WRITE(p, ...) p.W(__VA_ARGS__) bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint64_t *uniformMask, std::string *errorString) { *uniformMask = 0; @@ -83,45 +50,21 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); - char *p = buffer; - - switch (compat.shaderLanguage) { - case ShaderLanguage::GLSL_VULKAN: - WRITE(p, "%s", vulkan_glsl_preamble_fs); - break; - case ShaderLanguage::HLSL_D3D11: - WRITE(p, "%s", hlsl_preamble_fs); - WRITE(p, "%s", hlsl_d3d11_preamble_fs); - break; - case ShaderLanguage::HLSL_D3D9: - WRITE(p, "%s", hlsl_preamble_fs); - WRITE(p, "%s", hlsl_d3d9_preamble_fs); - break; - default: - // OpenGL - WRITE(p, "#version %d%s\n", compat.glslVersionNumber, compat.gles && compat.glslES30 ? " es" : ""); - WRITE(p, "#define DISCARD discard\n"); - + std::vector gl_exts; + if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { - WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); + gl_exts.push_back("#extension GL_EXT_blend_func_extended : require"); } if (gl_extensions.EXT_gpu_shader4) { - WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); + gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable"); } if (compat.framebufferFetchExtension) { - WRITE(p, "%s\n", compat.framebufferFetchExtension); + gl_exts.push_back(compat.framebufferFetchExtension); } - if (!compat.gles) { - WRITE(p, "#define lowp\n"); - WRITE(p, "#define mediump\n"); - WRITE(p, "#define highp\n"); - } else { - WRITE(p, "precision lowp float;\n"); - } - - WRITE(p, "#define splat3(x) vec3(x)\n"); } + ShaderWriter p(buffer, compat, ShaderStage::Fragment, gl_exts.data(), gl_exts.size()); + bool lmode = id.Bit(FS_BIT_LMODE); bool doTexture = id.Bit(FS_BIT_DO_TEXTURE); bool enableFog = id.Bit(FS_BIT_ENABLE_FOG); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index ab92f4df23..ca3b69f5cb 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -424,4 +424,9 @@ protected: FBO_OLD_AGE = 5, FBO_OLD_USAGE_FLAG = 15, }; + + // Thin3D stuff for reinterpreting image data between the various 16-bit formats. + // Safe, not optimal - there might be input attachment tricks, etc, but we can't use them + // since we don't want N different implementations. + Draw::Pipeline *reinterpretFromTo_[3][3]; }; diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 34594dfba7..e238bd9dc6 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -52,6 +52,11 @@ enum DebugShaderStringType { SHADER_STRING_STATS = 2, }; +enum class ShaderStage { + Vertex, + Fragment +}; + // Shared between the backends. Not all are necessarily used by each backend, but this lets us share // more code than before. enum : uint64_t { diff --git a/GPU/Common/ShaderWriter.cpp b/GPU/Common/ShaderWriter.cpp new file mode 100644 index 0000000000..5251515352 --- /dev/null +++ b/GPU/Common/ShaderWriter.cpp @@ -0,0 +1,118 @@ +#include "GPU/Common/ShaderWriter.h" + +const char *vulkan_glsl_preamble_fs = +"#version 450\n" +"#extension GL_ARB_separate_shader_objects : enable\n" +"#extension GL_ARB_shading_language_420pack : enable\n" +"#extension GL_ARB_conservative_depth : enable\n" +"#extension GL_ARB_shader_image_load_store : enable\n" +"#define splat3(x) vec3(x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"#define DISCARD discard\n" +"\n"; + +const char *hlsl_preamble_fs = +"#define vec2 float2\n" +"#define vec3 float3\n" +"#define vec4 float4\n" +"#define uvec3 uint3\n" +"#define ivec3 int3\n" +"#define ivec4 int4\n" +"#define mat4 float4x4\n" +"#define mat3x4 float4x3\n" // note how the conventions are backwards +"#define splat3(x) float3(x, x, x)\n" +"#define mix lerp\n" +"#define mod(x, y) fmod(x, y)\n"; + +const char *hlsl_d3d11_preamble_fs = +"#define DISCARD discard\n" +"#define DISCARD_BELOW(x) clip(x);\n"; +const char *hlsl_d3d9_preamble_fs = +"#define DISCARD clip(-1)\n" +"#define DISCARD_BELOW(x) clip(x)\n"; + +const char *vulkan_glsl_preamble_vs = +"#version 450\n" +"#extension GL_ARB_separate_shader_objects : enable\n" +"#extension GL_ARB_shading_language_420pack : enable\n" +"#define mul(x, y) ((x) * (y))\n" +"#define splat3(x) vec3(x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"\n"; + +const char *hlsl_preamble_vs = +"#define vec2 float2\n" +"#define vec3 float3\n" +"#define vec4 float4\n" +"#define ivec2 int2\n" +"#define ivec4 int4\n" +"#define mat4 float4x4\n" +"#define mat3x4 float4x3\n" // note how the conventions are backwards +"#define splat3(x) vec3(x, x, x)\n" +"#define lowp\n" +"#define mediump\n" +"#define highp\n" +"\n"; + +// Unsafe. But doesn't matter, we'll use big buffers for shader gen. +void ShaderWriter::W(char *format, ...) { + va_list args; + va_start(args, format); + p_ += vsprintf(p_, format, args); + va_end(args); +} + +void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) { + switch (lang_.shaderLanguage) { + case GLSL_VULKAN: + switch (stage_) { + case ShaderStage::Vertex: + W(vulkan_glsl_preamble_vs); + break; + case ShaderStage::Fragment: + W(vulkan_glsl_preamble_fs); + break; + } + break; + case HLSL_D3D11: + case HLSL_D3D9: + switch (stage_) { + case ShaderStage::Vertex: + W(hlsl_preamble_vs); + break; + case ShaderStage::Fragment: + W(hlsl_preamble_fs); + if (lang_.shaderLanguage == HLSL_D3D9) { + W(hlsl_d3d9_preamble_fs); + } else { + W(hlsl_d3d11_preamble_fs); + } + break; + } + break; + default: // OpenGL + W("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : ""); + switch (stage_) { + case ShaderStage::Fragment: + W("#define DISCARD discard\n"); + if (lang_.gles) { + W("precision lowp float;\n"); + } + break; + } + for (size_t i = 0; i < num_gl_extensions; i++) { + W("%s\n", gl_extensions[i]); + } + if (!lang_.gles) { + W("#define lowp\n"); + W("#define mediump\n"); + W("#define highp\n"); + } + W("#define splat3(x) vec3(x)\n"); + break; + } +} diff --git a/GPU/Common/ShaderWriter.h b/GPU/Common/ShaderWriter.h new file mode 100644 index 0000000000..25f24e8e5d --- /dev/null +++ b/GPU/Common/ShaderWriter.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Common/Log.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUCommon.h" +#include "GPU/Common/ShaderCommon.h" + +// Helps generate a shader compatible with all backends. +// Using #defines and magic in this class, we partially define our own shader language that basically looks +// like GLSL, but has a few little oddities like splat3. + +class ShaderWriter { +public: + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) { + Preamble(gl_extensions, num_gl_extensions); + } + + // Assumes the input is zero-terminated. + template + void W(const char(&text)[T]) { + memcpy(p_, text, T); + p_ += T; + } + void W(const char *text) { + size_t len = strlen(text); + memcpy(p_, text, len + 1); + p_ += len; + } + + // Formats into the buffer. + void W(char *format, ...); + + // void BeginMain(); + // void EndMain(); + + char *GetPos() { + return p_; + } + +private: + void Preamble(const char **gl_extensions, size_t num_gl_extensions); + + char *p_; + const ShaderLanguageDesc &lang_; + const ShaderStage stage_; +}; diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 598c0ddbb8..ba45b4c555 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -122,30 +122,8 @@ static const char * const boneWeightDecl[9] = { "layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n", }; -const char *vulkan_glsl_preamble_vs = -"#version 450\n" -"#extension GL_ARB_separate_shader_objects : enable\n" -"#extension GL_ARB_shading_language_420pack : enable\n" -"#define mul(x, y) ((x) * (y))\n" -"#define splat3(x) vec3(x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"\n"; - -const char *hlsl_preamble_vs = -"#define vec2 float2\n" -"#define vec3 float3\n" -"#define vec4 float4\n" -"#define ivec2 int2\n" -"#define ivec4 int4\n" -"#define mat4 float4x4\n" -"#define mat3x4 float4x3\n" // note how the conventions are backwards -"#define splat3(x) vec3(x, x, x)\n" -"#define lowp\n" -"#define mediump\n" -"#define highp\n" -"\n"; +extern const char *vulkan_glsl_preamble_vs; +extern const char *hlsl_preamble_vs; bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { *attrMask = 0; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 675602d6d5..bb7bb6980f 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -351,6 +351,7 @@ + @@ -488,6 +489,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 509e962588..c19594763f 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -270,6 +270,9 @@ Common + + Common + @@ -539,5 +542,8 @@ Common + + Common + \ No newline at end of file