Change the internal constant color from a (per-draw) vertex attribute to a uniform. Pack most built-in uniforms into a single vec4 array and update them all with a single glUniform call.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2019-11-18 21:13:54 -04:00
parent 37c579929b
commit 3435a6bcbf
10 changed files with 98 additions and 172 deletions
+3 -5
View File
@@ -309,7 +309,7 @@ void Graphics::setActive(bool enable)
void Graphics::draw(const DrawCommand &cmd)
{
gl.prepareDraw();
gl.prepareDraw(this);
gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
gl.bindTextureToUnit(cmd.texture, 0, false);
gl.setCullMode(cmd.cullMode);
@@ -326,7 +326,7 @@ void Graphics::draw(const DrawCommand &cmd)
void Graphics::draw(const DrawIndexedCommand &cmd)
{
gl.prepareDraw();
gl.prepareDraw(this);
gl.setVertexAttributes(*cmd.attributes, *cmd.buffers);
gl.bindTextureToUnit(cmd.texture, 0, false);
gl.setCullMode(cmd.cullMode);
@@ -373,7 +373,7 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu
const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
gl.prepareDraw();
gl.prepareDraw(this);
gl.bindTextureToUnit(texture, 0, false);
gl.setCullMode(CULL_NONE);
@@ -1223,8 +1223,6 @@ void Graphics::setColor(Colorf c)
c.b = std::min(std::max(c.b, 0.0f), 1.0f);
c.a = std::min(std::max(c.a, 0.0f), 1.0f);
gl.setConstantColor(c);
states.back().color = c;
}
+3 -23
View File
@@ -110,10 +110,6 @@ OpenGL::OpenGL()
, vendor(VENDOR_UNKNOWN)
, state()
{
state.constantColor = Colorf(1.0f, 1.0f, 1.0f, 1.0f);
float nan = std::numeric_limits<float>::quiet_NaN();
state.lastConstantColor = Colorf(nan, nan, nan, nan);
}
bool OpenGL::initContext()
@@ -183,7 +179,6 @@ void OpenGL::setupContext()
GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
glVertexAttrib4fv(ATTRIB_CONSTANTCOLOR, glcolor);
GLint maxvertexattribs = 1;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxvertexattribs);
@@ -553,20 +548,15 @@ void OpenGL::createDefaultTexture()
}
}
void OpenGL::prepareDraw()
void OpenGL::prepareDraw(love::graphics::Graphics *gfx)
{
TempDebugGroup debuggroup("Prepare OpenGL draw");
// Make sure the active shader's love-provided uniforms are up to date.
if (Shader::current != nullptr)
((Shader *)Shader::current)->updateBuiltinUniforms();
if (state.constantColor != state.lastConstantColor)
{
state.lastConstantColor = state.constantColor;
Colorf c = state.constantColor;
gammaCorrectColor(c);
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, c.r, c.g, c.b, c.a);
Rect viewport = getViewport();
((Shader *)Shader::current)->updateBuiltinUniforms(gfx, viewport.w, viewport.h);
}
}
@@ -801,16 +791,6 @@ void OpenGL::setScissor(const Rect &v, bool canvasActive)
state.scissor = v;
}
void OpenGL::setConstantColor(const Colorf &color)
{
state.constantColor = color;
}
const Colorf &OpenGL::getConstantColor() const
{
return state.constantColor;
}
void OpenGL::setPointSize(float size)
{
if (GLAD_VERSION_1_0)
+1 -11
View File
@@ -220,7 +220,7 @@ public:
* Set up necessary state (LOVE-provided shader uniforms, etc.) for drawing.
* This *MUST* be called directly before OpenGL drawing functions.
**/
void prepareDraw();
void prepareDraw(love::graphics::Graphics *gfx);
/**
* State-tracked glBindBuffer.
@@ -262,13 +262,6 @@ public:
**/
void setScissor(const Rect &v, bool canvasActive);
/**
* Sets the constant color (vertex attribute). This may be applied
* internally at draw-time. This gets gamma-corrected internally as well.
**/
void setConstantColor(const Colorf &color);
const Colorf &getConstantColor() const;
/**
* Sets the global point size.
**/
@@ -473,9 +466,6 @@ private:
uint32 enabledAttribArrays;
uint32 instancedAttribArrays;
Colorf constantColor;
Colorf lastConstantColor;
Rect viewport;
Rect scissor;
+40 -96
View File
@@ -42,8 +42,6 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
, builtinUniforms()
, builtinUniformInfo()
, builtinAttributes()
, canvasWasActive(false)
, lastViewport()
, lastPointSize(0.0f)
{
// load shader source and create program object
@@ -297,17 +295,8 @@ bool Shader::loadVolatile()
{
OpenGL::TempDebugGroup debuggroup("Shader load");
// Recreating the shader program will invalidate uniforms that rely on these.
canvasWasActive = false;
lastViewport = Rect();
lastPointSize = -1.0f;
// Invalidate the cached matrices by setting some elements to NaN.
float nan = std::numeric_limits<float>::quiet_NaN();
lastProjectionMatrix.setTranslation(nan, nan);
lastTransformMatrix.setTranslation(nan, nan);
// zero out active texture list
textureUnits.clear();
textureUnits.push_back(TextureUnit());
@@ -367,7 +356,6 @@ bool Shader::loadVolatile()
// make sure glUseProgram gets called.
current = nullptr;
attach();
updateBuiltinUniforms();
}
return true;
@@ -701,46 +689,6 @@ void Shader::setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *cr
}
}
void Shader::updateScreenParams()
{
Rect view = gl.getViewport();
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
bool canvasActive = gfx->isCanvasActive();
if ((view == lastViewport && canvasWasActive == canvasActive) || current != this)
return;
// In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
// This lets us flip pixcoord.y when needed, to be consistent (drawing with
// no Canvas active makes the y-values for pixel coordinates flipped.)
GLfloat params[] = {
(GLfloat) view.w, (GLfloat) view.h,
0.0f, 0.0f,
};
if (canvasActive)
{
// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
params[2] = 1.0f;
params[3] = 0.0f;
}
else
{
// gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
// pixcoord.y = gl_FragCoord.y * -1.0 + height.
params[2] = -1.0f;
params[3] = (GLfloat) view.h;
}
GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
if (location >= 0)
glUniform4fv(location, 1, params);
canvasWasActive = canvasActive;
lastViewport = view;
}
void Shader::updatePointSize(float size)
{
if (size == lastPointSize || current != this)
@@ -753,63 +701,59 @@ void Shader::updatePointSize(float size)
lastPointSize = size;
}
void Shader::updateBuiltinUniforms()
void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH)
{
if (current != this)
return;
updateScreenParams();
if (GLAD_ES_VERSION_2_0)
updatePointSize(gl.getPointSize());
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
BuiltinUniformData data;
const Matrix4 &curproj = gfx->getProjection();
const Matrix4 &curxform = gfx->getTransform();
data.transformMatrix = gfx->getTransform();
data.projectionMatrix = gfx->getProjection();
bool tpmatrixneedsupdate = false;
// Only upload the matrices if they've changed.
if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
// The normal matrix is the transpose of the inverse of the rotation portion
// (top-left 3x3) of the transform matrix.
{
GLint location = builtinUniforms[BUILTIN_MATRIX_VIEW_FROM_LOCAL];
if (location >= 0)
glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
// Also upload the re-calculated normal matrix, if possible. The normal
// matrix is the transpose of the inverse of the rotation portion
// (top-left 3x3) of the transform matrix.
location = builtinUniforms[BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL];
if (location >= 0)
Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse();
const float *e = normalmatrix.getElements();
for (int i = 0; i < 3; i++)
{
Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
}
tpmatrixneedsupdate = true;
lastTransformMatrix = curxform;
}
if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
{
GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_VIEW];
if (location >= 0)
glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
tpmatrixneedsupdate = true;
lastProjectionMatrix = curproj;
}
if (tpmatrixneedsupdate)
{
GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_LOCAL];
if (location >= 0)
{
Matrix4 tp_matrix(curproj, curxform);
glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
data.normalMatrix[i].x = e[i * 3 + 0];
data.normalMatrix[i].y = e[i * 3 + 1];
data.normalMatrix[i].z = e[i * 3 + 2];
data.normalMatrix[i].w = 0.0f;
}
}
data.screenSizeParams.x = viewportW;
data.screenSizeParams.y = viewportH;
// The shader does pixcoord.y = gl_FragCoord.y * params.z + params.w.
// This lets us flip pixcoord.y when needed, to be consistent (drawing
// with no Canvas active makes the pixel coordinates y-flipped.)
if (gfx->isCanvasActive())
{
// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
data.screenSizeParams.z = 1.0f;
data.screenSizeParams.w = 0.0f;
}
else
{
// gl_FragCoord.y is flipped when drawing to the screen, so we
// un-flip: pixcoord.y = gl_FragCoord.y * -1.0 + height.
data.screenSizeParams.z = -1.0f;
data.screenSizeParams.w = viewportH;
}
data.constantColor = gfx->getColor();
gammaCorrectColor(data.constantColor);
GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW];
if (location >= 0)
glUniform4fv(location, 13, (const GLfloat *) &data);
}
std::string Shader::getGLSLVersion()
+1 -8
View File
@@ -66,9 +66,8 @@ public:
ptrdiff_t getHandle() const override;
void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override;
void updateScreenParams();
void updatePointSize(float size);
void updateBuiltinUniforms();
void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH);
static std::string getGLSLVersion();
static bool isSupported();
@@ -119,14 +118,8 @@ private:
std::vector<std::pair<const UniformInfo *, int>> pendingUniformUpdates;
bool canvasWasActive;
Rect lastViewport;
float lastPointSize;
Matrix4 lastTransformMatrix;
Matrix4 lastProjectionMatrix;
}; // Shader
} // opengl