gl_shader_gen: accept an option to generate separable shaders

This commit is contained in:
wwylele 2018-04-10 00:30:35 +03:00
parent bdab18d2d9
commit 36bc92273b
2 changed files with 70 additions and 32 deletions

View file

@ -61,6 +61,37 @@ layout (std140) uniform shader_data {
}; };
)"; )";
static std::string GetVertexInterfaceDeclaration(bool is_output, bool separable_shader) {
std::string out;
auto append_variable = [&](const char* var, int location) {
if (separable_shader) {
out += "layout (location=" + std::to_string(location) + ") ";
}
out += std::string(is_output ? "out " : "in ") + var + ";\n";
};
append_variable("vec4 primary_color", ATTRIBUTE_COLOR);
append_variable("vec2 texcoord0", ATTRIBUTE_TEXCOORD0);
append_variable("vec2 texcoord1", ATTRIBUTE_TEXCOORD1);
append_variable("vec2 texcoord2", ATTRIBUTE_TEXCOORD2);
append_variable("float texcoord0_w", ATTRIBUTE_TEXCOORD0_W);
append_variable("vec4 normquat", ATTRIBUTE_NORMQUAT);
append_variable("vec3 view", ATTRIBUTE_VIEW);
if (is_output && separable_shader) {
// gl_PerVertex redeclaration is required for separate shader object
out += R"(
out gl_PerVertex {
vec4 gl_Position;
float gl_ClipDistance[2];
};
)";
}
return out;
}
PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) {
PicaShaderConfig res; PicaShaderConfig res;
@ -206,11 +237,11 @@ static std::string SampleTexture(const PicaShaderConfig& config, unsigned textur
// Only unit 0 respects the texturing type // Only unit 0 respects the texturing type
switch (state.texture0_type) { switch (state.texture0_type) {
case TexturingRegs::TextureConfig::Texture2D: case TexturingRegs::TextureConfig::Texture2D:
return "texture(tex[0], texcoord[0])"; return "texture(tex0, texcoord0)";
case TexturingRegs::TextureConfig::Projection2D: case TexturingRegs::TextureConfig::Projection2D:
return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; return "textureProj(tex0, vec3(texcoord0, texcoord0_w))";
case TexturingRegs::TextureConfig::TextureCube: case TexturingRegs::TextureConfig::TextureCube:
return "texture(tex_cube, vec3(texcoord[0], texcoord0_w))"; return "texture(tex_cube, vec3(texcoord0, texcoord0_w))";
case TexturingRegs::TextureConfig::Shadow2D: case TexturingRegs::TextureConfig::Shadow2D:
case TexturingRegs::TextureConfig::ShadowCube: case TexturingRegs::TextureConfig::ShadowCube:
NGLOG_CRITICAL(HW_GPU, "Unhandled shadow texture"); NGLOG_CRITICAL(HW_GPU, "Unhandled shadow texture");
@ -220,15 +251,15 @@ static std::string SampleTexture(const PicaShaderConfig& config, unsigned textur
LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", LOG_CRITICAL(HW_GPU, "Unhandled texture type %x",
static_cast<int>(state.texture0_type)); static_cast<int>(state.texture0_type));
UNIMPLEMENTED(); UNIMPLEMENTED();
return "texture(tex[0], texcoord[0])"; return "texture(tex0, texcoord0)";
} }
case 1: case 1:
return "texture(tex[1], texcoord[1])"; return "texture(tex1, texcoord1)";
case 2: case 2:
if (state.texture2_use_coord1) if (state.texture2_use_coord1)
return "texture(tex[2], texcoord[1])"; return "texture(tex2, texcoord1)";
else else
return "texture(tex[2], texcoord[2])"; return "texture(tex2, texcoord2)";
case 3: case 3:
if (state.proctex.enable) { if (state.proctex.enable) {
return "ProcTex()"; return "ProcTex()";
@ -1019,7 +1050,12 @@ float ProcTexNoiseCoef(vec2 x) {
} }
out += "vec4 ProcTex() {\n"; out += "vec4 ProcTex() {\n";
out += "vec2 uv = abs(texcoord[" + std::to_string(config.state.proctex.coord) + "]);\n"; if (config.state.proctex.coord < 3) {
out += "vec2 uv = abs(texcoord" + std::to_string(config.state.proctex.coord) + ");\n";
} else {
NGLOG_CRITICAL(Render_OpenGL, "Unexpected proctex.coord >= 3");
out += "vec2 uv = abs(texcoord0);\n";
}
// Get shift offset before noise generation // Get shift offset before noise generation
out += "float u_shift = "; out += "float u_shift = ";
@ -1084,23 +1120,24 @@ float ProcTexNoiseCoef(vec2 x) {
} }
} }
std::string GenerateFragmentShader(const PicaShaderConfig& config) { std::string GenerateFragmentShader(const PicaShaderConfig& config, bool separable_shader) {
const auto& state = config.state; const auto& state = config.state;
std::string out = R"( std::string out = "#version 330 core\n";
#version 330 core if (separable_shader) {
out += "#extension GL_ARB_separate_shader_objects : enable\n";
}
in vec4 primary_color; out += GetVertexInterfaceDeclaration(false, separable_shader);
in vec2 texcoord[3];
in float texcoord0_w;
in vec4 normquat;
in vec3 view;
out += R"(
in vec4 gl_FragCoord; in vec4 gl_FragCoord;
out vec4 color; out vec4 color;
uniform sampler2D tex[3]; uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform samplerCube tex_cube; uniform samplerCube tex_cube;
uniform samplerBuffer lighting_lut; uniform samplerBuffer lighting_lut;
uniform samplerBuffer fog_lut; uniform samplerBuffer fog_lut;
@ -1228,8 +1265,11 @@ vec4 secondary_fragment_color = vec4(0.0);
return out; return out;
} }
std::string GenerateVertexShader() { std::string GenerateTrivialVertexShader(bool separable_shader) {
std::string out = "#version 330 core\n"; std::string out = "#version 330 core\n";
if (separable_shader) {
out += "#extension GL_ARB_separate_shader_objects : enable\n";
}
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) +
") in vec4 vert_position;\n"; ") in vec4 vert_position;\n";
@ -1246,14 +1286,7 @@ std::string GenerateVertexShader() {
") in vec4 vert_normquat;\n"; ") in vec4 vert_normquat;\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
out += R"( out += GetVertexInterfaceDeclaration(true, separable_shader);
out vec4 primary_color;
out vec2 texcoord[3];
out float texcoord0_w;
out vec4 normquat;
out vec3 view;
)";
out += UniformBlockDef; out += UniformBlockDef;
@ -1261,9 +1294,9 @@ out vec3 view;
void main() { void main() {
primary_color = vert_color; primary_color = vert_color;
texcoord[0] = vert_texcoord0; texcoord0 = vert_texcoord0;
texcoord[1] = vert_texcoord1; texcoord1 = vert_texcoord1;
texcoord[2] = vert_texcoord2; texcoord2 = vert_texcoord2;
texcoord0_w = vert_texcoord0_w; texcoord0_w = vert_texcoord0_w;
normquat = vert_normquat; normquat = vert_normquat;
view = vert_view; view = vert_view;

View file

@ -9,7 +9,9 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "common/hash.h"
#include "video_core/regs.h" #include "video_core/regs.h"
#include "video_core/shader/shader.h"
namespace GLShader { namespace GLShader {
@ -132,18 +134,21 @@ struct PicaShaderConfig : Common::HashableStruct<PicaShaderConfigState> {
}; };
/** /**
* Generates the GLSL vertex shader program source code for the current Pica state * Generates the GLSL vertex shader program source code that accepts vertices from software shader
* and directly passes them to the fragment shader.
* @param separable_shader generates shader that can be used for separate shader object
* @returns String of the shader source code * @returns String of the shader source code
*/ */
std::string GenerateVertexShader(); std::string GenerateTrivialVertexShader(bool separable_shader);
/** /**
* Generates the GLSL fragment shader program source code for the current Pica state * Generates the GLSL fragment shader program source code for the current Pica state
* @param config ShaderCacheKey object generated for the current Pica state, used for the shader * @param config ShaderCacheKey object generated for the current Pica state, used for the shader
* configuration (NOTE: Use state in this struct only, not the Pica registers!) * configuration (NOTE: Use state in this struct only, not the Pica registers!)
* @param separable_shader generates shader that can be used for separate shader object
* @returns String of the shader source code * @returns String of the shader source code
*/ */
std::string GenerateFragmentShader(const PicaShaderConfig& config); std::string GenerateFragmentShader(const PicaShaderConfig& config, bool separable_shader);
} // namespace GLShader } // namespace GLShader