GL: Compute "availableUniform" when generating shaders instead of by querying.

This commit is contained in:
Henrik Rydgård 2017-11-19 11:23:16 +01:00
parent 32df9e25da
commit 33d3d2f178
6 changed files with 56 additions and 70 deletions

View File

@ -36,9 +36,10 @@
// #define DEBUG_SHADER
// Missing: Z depth range
bool GenerateFragmentShader(const ShaderID &id, char *buffer) {
bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformMask) {
char *p = buffer;
*uniformMask = 0;
// In GLSL ES 3.0, you use "in" variables instead of varying.
bool glslES30 = false;
@ -180,6 +181,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer) {
WRITE(p, "uniform sampler2D tex;\n");
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
*uniformMask |= DIRTY_SHADERBLEND;
if (!gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) && replaceBlend == REPLACE_BLEND_COPY_FBO) {
if (!texelFetch) {
WRITE(p, "uniform vec2 u_fbotexSize;\n");
@ -195,6 +197,7 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer) {
}
if (needShaderTexClamp && doTexture) {
*uniformMask |= DIRTY_TEXCLAMP;
WRITE(p, "uniform vec4 u_texclamp;\n");
if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) {
WRITE(p, "uniform vec2 u_texclampoff;\n");
@ -205,8 +208,10 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer) {
if (g_Config.bFragmentTestCache) {
WRITE(p, "uniform sampler2D testtex;\n");
} else {
*uniformMask |= DIRTY_ALPHACOLORREF;
WRITE(p, "uniform vec4 u_alphacolorref;\n");
if (bitwiseOps && ((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) {
*uniformMask |= DIRTY_ALPHACOLORMASK;
WRITE(p, "uniform ivec4 u_alphacolormask;\n");
}
}
@ -214,15 +219,19 @@ bool GenerateFragmentShader(const ShaderID &id, char *buffer) {
StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4);
if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) {
*uniformMask |= DIRTY_STENCILREPLACEVALUE;
WRITE(p, "uniform float u_stencilReplaceValue;\n");
}
if (doTexture && texFunc == GE_TEXFUNC_BLEND)
if (doTexture && texFunc == GE_TEXFUNC_BLEND) {
*uniformMask |= DIRTY_TEXENV;
WRITE(p, "uniform vec3 u_texenv;\n");
}
WRITE(p, "%s %s vec4 v_color0;\n", shading, varying);
if (lmode)
WRITE(p, "%s %s vec3 v_color1;\n", shading, varying);
if (enableFog) {
*uniformMask |= DIRTY_FOGCOLOR;
WRITE(p, "uniform vec3 u_fogcolor;\n");
WRITE(p, "%s %s float v_fogdepth;\n", varying, highpFog ? "highp" : "mediump");
}

View File

@ -19,4 +19,4 @@
struct ShaderID;
bool GenerateFragmentShader(const ShaderID &id, char *buffer);
bool GenerateFragmentShader(const ShaderID &id, char *buffer, uint64_t *uniformMask);

View File

@ -43,8 +43,8 @@
#include "GPU/GLES/DrawEngineGLES.h"
#include "FramebufferManagerGLES.h"
Shader::Shader(const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask)
: failed_(false), useHWTransform_(useHWTransform), attrMask_(attrMask) {
Shader::Shader(const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask)
: failed_(false), useHWTransform_(useHWTransform), attrMask_(attrMask), uniformMask_(uniformMask) {
PROFILE_THIS_SCOPE("shadercomp");
isFragment_ = glShaderType == GL_FRAGMENT_SHADER;
source_ = code;
@ -242,54 +242,7 @@ LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs,
u_spline_type_v = glGetUniformLocation(program, "u_spline_type_v");
attrMask = vs->GetAttrMask();
availableUniforms = 0;
if (u_proj != -1) availableUniforms |= DIRTY_PROJMATRIX;
if (u_proj_through != -1) availableUniforms |= DIRTY_PROJTHROUGHMATRIX;
if (u_texenv != -1) availableUniforms |= DIRTY_TEXENV;
if (u_alphacolorref != -1) availableUniforms |= DIRTY_ALPHACOLORREF;
if (u_alphacolormask != -1) availableUniforms |= DIRTY_ALPHACOLORMASK;
if (u_fogcolor != -1) availableUniforms |= DIRTY_FOGCOLOR;
if (u_fogcoef != -1) availableUniforms |= DIRTY_FOGCOEF;
if (u_texenv != -1) availableUniforms |= DIRTY_TEXENV;
if (u_uvscaleoffset != -1) availableUniforms |= DIRTY_UVSCALEOFFSET;
if (u_texclamp != -1) availableUniforms |= DIRTY_TEXCLAMP;
if (u_world != -1) availableUniforms |= DIRTY_WORLDMATRIX;
if (u_view != -1) availableUniforms |= DIRTY_VIEWMATRIX;
if (u_texmtx != -1) availableUniforms |= DIRTY_TEXMATRIX;
if (u_stencilReplaceValue != -1) availableUniforms |= DIRTY_STENCILREPLACEVALUE;
if (u_blendFixA != -1 || u_blendFixB != -1 || u_fbotexSize != -1) availableUniforms |= DIRTY_SHADERBLEND;
if (u_depthRange != -1)
availableUniforms |= DIRTY_DEPTHRANGE;
// Looping up to numBones lets us avoid checking u_bone[i]
#ifdef USE_BONE_ARRAY
if (u_bone != -1) {
for (int i = 0; i < numBones; i++) {
availableUniforms |= DIRTY_BONEMATRIX0 << i;
}
}
#else
for (int i = 0; i < numBones; i++) {
if (u_bone[i] != -1)
availableUniforms |= DIRTY_BONEMATRIX0 << i;
}
#endif
if (u_ambient != -1) availableUniforms |= DIRTY_AMBIENT;
if (u_matambientalpha != -1) availableUniforms |= DIRTY_MATAMBIENTALPHA;
if (u_matdiffuse != -1) availableUniforms |= DIRTY_MATDIFFUSE;
if (u_matemissive != -1) availableUniforms |= DIRTY_MATEMISSIVE;
if (u_matspecular != -1) availableUniforms |= DIRTY_MATSPECULAR;
for (int i = 0; i < 4; i++) {
if (u_lightdir[i] != -1 ||
u_lightspecular[i] != -1 ||
u_lightpos[i] != -1)
availableUniforms |= DIRTY_LIGHT0 << i;
}
if (u_spline_count_u != -1) availableUniforms |= DIRTY_BEZIERSPLINE;
if (u_spline_count_v != -1) availableUniforms |= DIRTY_BEZIERSPLINE;
if (u_spline_type_u != -1) availableUniforms |= DIRTY_BEZIERSPLINE;
if (u_spline_type_v != -1) availableUniforms |= DIRTY_BEZIERSPLINE;
availableUniforms = vs->GetUniformMask() | fs->GetUniformMask();
glUseProgram(program);
@ -297,7 +250,6 @@ LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs,
glUniform1i(u_tex, 0);
glUniform1i(u_fbotex, 1);
glUniform1i(u_testtex, 2);
if (u_tess_pos_tex != -1)
glUniform1i(u_tess_pos_tex, 4); // Texture unit 4
@ -782,17 +734,19 @@ void ShaderManagerGLES::DirtyLastShader() { // disables vertex arrays
}
Shader *ShaderManagerGLES::CompileFragmentShader(ShaderID FSID) {
if (!GenerateFragmentShader(FSID, codeBuffer_)) {
uint64_t uniformMask;
if (!GenerateFragmentShader(FSID, codeBuffer_, &uniformMask)) {
return nullptr;
}
return new Shader(codeBuffer_, GL_FRAGMENT_SHADER, false);
return new Shader(codeBuffer_, GL_FRAGMENT_SHADER, false, 0, uniformMask);
}
Shader *ShaderManagerGLES::CompileVertexShader(ShaderID VSID) {
bool useHWTransform = VSID.Bit(VS_BIT_USE_HW_TRANSFORM);
uint32_t attrMask;
GenerateVertexShader(VSID, codeBuffer_, &attrMask);
return new Shader(codeBuffer_, GL_VERTEX_SHADER, useHWTransform, attrMask);
uint64_t uniformMask;
GenerateVertexShader(VSID, codeBuffer_, &attrMask, &uniformMask);
return new Shader(codeBuffer_, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask);
}
Shader *ShaderManagerGLES::ApplyVertexShader(int prim, u32 vertType, ShaderID *VSID) {
@ -841,8 +795,9 @@ Shader *ShaderManagerGLES::ApplyVertexShader(int prim, u32 vertType, ShaderID *V
ShaderID vsidTemp;
ComputeVertexShaderID(&vsidTemp, vertType, false);
uint32_t attrMask;
GenerateVertexShader(vsidTemp, codeBuffer_, &attrMask);
vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, false, attrMask);
uint64_t uniformMask;
GenerateVertexShader(vsidTemp, codeBuffer_, &attrMask, &uniformMask);
vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, false, attrMask, uniformMask);
}
vsCache_.Insert(*VSID, vs);

View File

@ -124,7 +124,7 @@ public:
class Shader {
public:
Shader(const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask = 0);
Shader(const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask);
~Shader();
uint32_t shader;
@ -134,6 +134,7 @@ public:
std::string GetShaderString(DebugShaderStringType type, ShaderID id) const;
uint32_t GetAttrMask() const { return attrMask_; }
uint64_t GetUniformMask() const { return uniformMask_; }
private:
std::string source_;
@ -141,6 +142,7 @@ private:
bool useHWTransform_;
bool isFragment_;
uint32_t attrMask_; // only used in vertex shaders
uint64_t uniformMask_;
};
class ShaderManagerGLES : public ShaderManagerCommon {

View File

@ -95,9 +95,10 @@ enum DoLightComputation {
// is a bit of a rare configuration, although quite common on mobile.
void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask) {
void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask) {
char *p = buffer;
*attrMask = 0;
*uniformMask = 0;
// #define USE_FOR_LOOP
// In GLSL ES 3.0, you use "out" variables instead.
@ -250,10 +251,12 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask)
}
}
if (isModeThrough) {
if (isModeThrough) {
WRITE(p, "uniform mat4 u_proj_through;\n");
*uniformMask |= DIRTY_PROJTHROUGHMATRIX;
} else {
WRITE(p, "uniform mat4 u_proj;\n");
*uniformMask |= DIRTY_PROJMATRIX;
// Add all the uniforms we'll need to transform properly.
}
@ -263,28 +266,36 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask)
// When transforming by hardware, we need a great deal more uniforms...
WRITE(p, "uniform mat4 u_world;\n");
WRITE(p, "uniform mat4 u_view;\n");
if (doTextureProjection)
*uniformMask |= DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX;
if (doTextureProjection) {
WRITE(p, "uniform mediump mat4 u_texmtx;\n");
*uniformMask |= DIRTY_TEXMATRIX;
}
if (enableBones) {
#ifdef USE_BONE_ARRAY
WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBoneWeights);
*uniformMask |= DIRTY_BONE_UNIFORMS;
#else
for (int i = 0; i < numBoneWeights; i++) {
WRITE(p, "uniform mat4 u_bone%i;\n", i);
*uniformMask |= DIRTY_BONEMATRIX0 << i;
}
#endif
}
if (doTexture) {
WRITE(p, "uniform vec4 u_uvscaleoffset;\n");
*uniformMask |= DIRTY_UVSCALEOFFSET;
}
for (int i = 0; i < 4; i++) {
if (doLight[i] != LIGHT_OFF) {
// This is needed for shade mapping
WRITE(p, "uniform vec3 u_lightpos%i;\n", i);
*uniformMask |= DIRTY_LIGHT0 << i;
}
if (doLight[i] == LIGHT_FULL) {
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4*i, 2));
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4*i, 2));
*uniformMask |= DIRTY_LIGHT0 << i;
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
if (type != GE_LIGHTTYPE_DIRECTIONAL)
WRITE(p, "uniform mediump vec3 u_lightatt%i;\n", i);
@ -304,22 +315,29 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask)
}
if (enableLighting) {
WRITE(p, "uniform lowp vec4 u_ambient;\n");
if ((matUpdate & 2) == 0 || !hasColor)
*uniformMask |= DIRTY_AMBIENT;
if ((matUpdate & 2) == 0 || !hasColor) {
WRITE(p, "uniform lowp vec3 u_matdiffuse;\n");
*uniformMask |= DIRTY_MATDIFFUSE;
}
WRITE(p, "uniform lowp vec4 u_matspecular;\n"); // Specular coef is contained in alpha
WRITE(p, "uniform lowp vec3 u_matemissive;\n");
*uniformMask |= DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE;
}
}
if (useHWTransform || !hasColor)
if (useHWTransform || !hasColor) {
WRITE(p, "uniform lowp vec4 u_matambientalpha;\n"); // matambient + matalpha
*uniformMask |= DIRTY_MATAMBIENTALPHA;
}
if (enableFog) {
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
*uniformMask |= DIRTY_FOGCOEF;
}
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, "uniform highp vec4 u_depthRange;\n");
*uniformMask |= DIRTY_DEPTHRANGE;
}
WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, varying);
@ -354,6 +372,8 @@ void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask)
// Hardware tessellation
if (doBezier || doSpline) {
*uniformMask |= DIRTY_BEZIERSPLINE;
const char *sampler = !isAllowTexture1D ? "sampler2D" : "sampler1D";
WRITE(p, "uniform %s u_tess_pos_tex;\n", sampler);
WRITE(p, "uniform %s u_tess_tex_tex;\n", sampler);

View File

@ -23,4 +23,4 @@
struct ShaderID;
void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask);
void GenerateVertexShader(const ShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask);