diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 96c095b42..ee580cd53 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -89,7 +89,12 @@ static const char render_uniforms[] = R"( // According to the GLSL ES 1.0 spec, uniform precision must match between stages, // but we can't guarantee that highp is always supported in fragment shaders... // We *really* don't want to use mediump for these in vertex shaders though. +#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[12]; +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw2[1]; +#else uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; +#endif // Older GLSL doesn't support preprocessor line continuations... #define TransformMatrix mat4(love_UniformsPerDraw[0], love_UniformsPerDraw[1], love_UniformsPerDraw[2], love_UniformsPerDraw[3]) @@ -100,8 +105,13 @@ uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; #define CurrentDPIScale (love_UniformsPerDraw[8].w) #define ConstantPointSize (love_UniformsPerDraw[9].w) -#define ConstantColor (love_UniformsPerDraw[12]) -#define love_ScreenSize (love_UniformsPerDraw[11]) +#define ConstantColor (love_UniformsPerDraw[11]) + +#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW +#define love_ScreenSize (love_UniformsPerDraw2[0]) +#else +#define love_ScreenSize (love_UniformsPerDraw[12]) +#endif // Alternate names #define ViewSpaceFromLocal TransformMatrix @@ -538,6 +548,11 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (info.usesMRT) ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n"; + // Note: backends are expected to handle this situation if highp is ever + // conditional in that backend. + if (!gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]) + ss << "#define LOVE_SPLIT_UNIFORMS_PER_DRAW 1"; + for (const auto &def : options.defines) ss << "#define " + def.first + " " + def.second + "\n"; @@ -1164,11 +1179,12 @@ static StringMap languages(language static StringMap::Entry builtinNameEntries[] = { - { "MainTex", Shader::BUILTIN_TEXTURE_MAIN }, - { "love_VideoYChannel", Shader::BUILTIN_TEXTURE_VIDEO_Y }, - { "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB }, - { "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR }, - { "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW }, + { "MainTex", Shader::BUILTIN_TEXTURE_MAIN }, + { "love_VideoYChannel", Shader::BUILTIN_TEXTURE_VIDEO_Y }, + { "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB }, + { "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR }, + { "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW }, + { "love_UniformsPerDraw2", Shader::BUILTIN_UNIFORMS_PER_DRAW_2 }, }; static StringMap builtinNames(builtinNameEntries, sizeof(builtinNameEntries)); diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 862e9f268..579ca3a10 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -64,6 +64,7 @@ public: BUILTIN_TEXTURE_VIDEO_CB, BUILTIN_TEXTURE_VIDEO_CR, BUILTIN_UNIFORMS_PER_DRAW, + BUILTIN_UNIFORMS_PER_DRAW_2, BUILTIN_MAX_ENUM }; @@ -176,8 +177,10 @@ public: Matrix4 transformMatrix; Matrix4 projectionMatrix; Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s. - Vector4 screenSizeParams; Colorf constantColor; + + // Pixel shader-centric variables past this point. + Vector4 screenSizeParams; }; // Pointer to currently active Shader. diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index bdcc4d8ab..ee75d0c8c 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -46,6 +46,7 @@ static bool isBuffer(Shader::UniformType utype) Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]) : love::graphics::Shader(stages) , program(0) + , splitUniformsPerDraw(false) , builtinUniforms() , builtinUniformInfo() { @@ -486,6 +487,11 @@ bool Shader::loadVolatile() { OpenGL::TempDebugGroup debuggroup("Shader load"); + // love::graphics::Shader sets up the shader code-side of this. + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + splitUniformsPerDraw = gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]; + // zero out active texture list textureUnits.clear(); textureUnits.push_back(TextureUnit()); @@ -1014,9 +1020,27 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, data.constantColor = gfx->getColor(); gammaCorrectColor(data.constantColor); - GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; - if (location >= 0) - glUniform4fv(location, 13, (const GLfloat *) &data); + // This branch is to avoid always declaring the whole array as highp in the + // vertex shader and mediump in the pixel shader for love's default shaders, + // on systems that don't support highp in pixel shaders. The default shaders + // use the transform matrices in vertex shaders and screen size params in + // pixel shaders. If there's a single array containing both and each shader + // stage declares a different precision, that's a compile error. + if (splitUniformsPerDraw) + { + GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; + if (location >= 0) + glUniform4fv(location, 12, (const GLfloat *) &data); + GLint location2 = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW_2]; + if (location2 >= 0) + glUniform4fv(location2, 1, (const GLfloat *) &data.screenSizeParams); + } + else + { + GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; + if (location >= 0) + glUniform4fv(location, 13, (const GLfloat *) &data); + } } int Shader::getUniformTypeComponents(GLenum type) const diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 40545a2a2..12ae79ae6 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -112,6 +112,8 @@ private: // volatile GLuint program; + bool splitUniformsPerDraw; + // Location values for any built-in uniform variables. GLint builtinUniforms[BUILTIN_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];