Refactor graphics state, especially shaders;

This should improve performance, if not then I have failed.
This commit is contained in:
bjorn 2016-11-14 15:48:17 -08:00
parent c2feb24118
commit 954592d8bd
6 changed files with 68 additions and 70 deletions

View File

@ -13,12 +13,8 @@ static GraphicsState state;
void lovrGraphicsInit() {
vec_init(&state.transforms);
state.projection = mat4_init();
state.lastTransform = mat4_init();
state.lastProjection = mat4_init();
state.defaultShader = lovrShaderCreate(lovrDefaultVertexShader, lovrDefaultFragmentShader);
state.skyboxShader = lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader);
state.lastShader = NULL;
state.lastColor = 0;
glGenBuffers(1, &state.shapeBuffer);
glGenBuffers(1, &state.shapeIndexBuffer);
glGenVertexArrays(1, &state.shapeArray);
@ -30,8 +26,6 @@ void lovrGraphicsInit() {
void lovrGraphicsDestroy() {
vec_deinit(&state.transforms);
mat4_deinit(state.projection);
mat4_deinit(state.lastTransform);
mat4_deinit(state.lastProjection);
lovrShaderDestroy(state.defaultShader);
lovrShaderDestroy(state.skyboxShader);
glDeleteBuffers(1, &state.shapeBuffer);
@ -52,9 +46,6 @@ void lovrGraphicsReset() {
vec_clear(&state.transforms);
vec_push(&state.transforms, mat4_init());
memset(state.lastTransform, 0, 16);
memset(state.lastProjection, 0, 16);
lovrGraphicsSetProjection(.1f, 100.f, 67 * M_PI / 180); // TODO customize via lovr.conf
lovrGraphicsSetShader(state.defaultShader);
lovrGraphicsSetBackgroundColor(0, 0, 0, 0);
@ -87,43 +78,7 @@ void lovrGraphicsPresent() {
void lovrGraphicsPrepare() {
Shader* shader = lovrGraphicsGetShader();
if (!shader) {
return;
}
int shaderChanged = shader != state.lastShader;
state.lastShader = shader;
mat4 transform = vec_last(&state.transforms);
mat4 lastTransform = state.lastTransform;
if (shaderChanged || memcmp(transform, lastTransform, 16 * sizeof(float))) {
int uniformId = lovrShaderGetUniformId(shader, "lovrTransform");
lovrShaderSendFloatMat4(shader, uniformId, transform);
memcpy(lastTransform, transform, 16 * sizeof(float));
}
mat4 projection = state.projection;
mat4 lastProjection = state.lastProjection;
if (shaderChanged || memcmp(projection, lastProjection, 16 * sizeof(float))) {
int uniformId = lovrShaderGetUniformId(shader, "lovrProjection");
lovrShaderSendFloatMat4(shader, uniformId, projection);
memcpy(lastProjection, projection, 16 * sizeof(float));
}
if (shaderChanged || state.lastColor != state.color) {
int uniformId = lovrShaderGetUniformId(shader, "lovrColor");
float color[4] = {
LOVR_COLOR_R(state.color) / 255.f,
LOVR_COLOR_G(state.color) / 255.f,
LOVR_COLOR_B(state.color) / 255.f,
LOVR_COLOR_A(state.color) / 255.f
};
lovrShaderSendFloatVec4(shader, uniformId, color);
state.lastColor = state.color;
}
lovrShaderBind(shader, vec_last(&state.transforms), state.projection, state.color, 0);
}
void lovrGraphicsGetBackgroundColor(float* r, float* g, float* b, float* a) {
@ -203,7 +158,6 @@ void lovrGraphicsSetShader(Shader* shader) {
}
state.activeShader = shader;
glUseProgram(shader->id);
}
void lovrGraphicsSetProjection(float near, float far, float fov) {

View File

@ -7,12 +7,6 @@
#ifndef LOVR_GRAPHICS_TYPES
#define LOVR_GRAPHICS_TYPES
#define LOVR_COLOR(r, g, b, a) ((a << 0) | (b << 8) | (g << 16) | (r << 24))
#define LOVR_COLOR_R(c) (c >> 24 & 0xff)
#define LOVR_COLOR_G(c) (c >> 16 & 0xff)
#define LOVR_COLOR_B(c) (c >> 8 & 0xff)
#define LOVR_COLOR_A(c) (c >> 0 & 0xff)
typedef struct {
int x;
int y;
@ -32,15 +26,11 @@ typedef enum {
typedef struct {
Shader* activeShader;
Shader* lastShader;
Shader* defaultShader;
Shader* skyboxShader;
vec_mat4_t transforms;
mat4 lastTransform;
mat4 projection;
mat4 lastProjection;
unsigned int color;
unsigned int lastColor;
char colorMask;
char isScissorEnabled;
ScissorRectangle scissor;

View File

@ -99,27 +99,29 @@ GLuint linkShaders(GLuint vertexShader, GLuint fragmentShader) {
}
Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
Shader* shader = (Shader*) malloc(sizeof(Shader));
if (!shader) return NULL;
// Vertex
vertexSource = vertexSource == NULL ? lovrDefaultVertexShader : vertexSource;
char fullVertexSource[1024];
snprintf(fullVertexSource, sizeof(fullVertexSource), "%s\n%s", lovrShaderVertexPrefix, vertexSource);
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, fullVertexSource);
// Fragment
fragmentSource = fragmentSource == NULL ? lovrDefaultFragmentShader : fragmentSource;
char fullFragmentSource[1024];
snprintf(fullFragmentSource, sizeof(fullFragmentSource), "%s\n%s", lovrShaderFragmentPrefix, fragmentSource);
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fullFragmentSource);
// Link
GLuint id = linkShaders(vertexShader, fragmentShader);
Shader* shader = (Shader*) malloc(sizeof(Shader));
if (!shader) return NULL;
shader->id = id;
// Compute information about uniforms
GLint uniformCount;
GLsizei bufferSize = LOVR_MAX_UNIFORM_LENGTH / sizeof(GLchar);
map_init(&shader->uniforms);
glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount);
for (int i = 0; i < uniformCount; i++) {
Uniform uniform;
glGetActiveUniform(id, i, bufferSize, NULL, &uniform.count, &uniform.type, uniform.name);
@ -128,6 +130,15 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
map_set(&shader->uniforms, uniform.name, uniform);
}
// Initial state
shader->id = id;
shader->transform = mat4_init();
shader->projection = mat4_init();
shader->color = 0;
// Send initial uniform values to shader
lovrShaderBind(shader, shader->transform, shader->projection, shader->color, 1);
return shader;
}
@ -136,6 +147,43 @@ void lovrShaderDestroy(Shader* shader) {
free(shader);
}
void lovrShaderBind(Shader* shader, mat4 transform, mat4 projection, unsigned int color, int force) {
// Bind shader if necessary
int program;
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
if (program != shader->id) {
glUseProgram(shader->id);
}
// Update transform if necessary
if (force || memcmp(shader->transform, transform, 16 * sizeof(float))) {
int uniformId = lovrShaderGetUniformId(shader, "lovrTransform");
lovrShaderSendFloatMat4(shader, uniformId, transform);
memcpy(shader->transform, transform, 16 * sizeof(float));
}
// Update projection if necessary
if (force || memcmp(shader->projection, projection, 16 * sizeof(float))) {
int uniformId = lovrShaderGetUniformId(shader, "lovrProjection");
lovrShaderSendFloatMat4(shader, uniformId, projection);
memcpy(shader->projection, projection, 16 * sizeof(float));
}
// Update color if necessary
if (force || shader->color != color) {
int uniformId = lovrShaderGetUniformId(shader, "lovrColor");
float c[4] = {
LOVR_COLOR_R(color) / 255.f,
LOVR_COLOR_G(color) / 255.f,
LOVR_COLOR_B(color) / 255.f,
LOVR_COLOR_A(color) / 255.f
};
lovrShaderSendFloatVec4(shader, uniformId, c);
shader->color = color;
}
}
int lovrShaderGetAttributeId(Shader* shader, const char* name) {
if (!shader) {
return -1;
@ -146,12 +194,7 @@ int lovrShaderGetAttributeId(Shader* shader, const char* name) {
int lovrShaderGetUniformId(Shader* shader, const char* name) {
Uniform* uniform = map_get(&shader->uniforms, name);
if (!uniform) {
return -1;
}
return uniform->location;
return uniform ? uniform->location : -1;
}
int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count) {

View File

@ -1,5 +1,6 @@
#include "../glfw.h"
#include "../vendor/map/map.h"
#include "../matrix.h"
#ifndef LOVR_SHADER_TYPES
#define LOVR_SHADER_TYPES
@ -20,8 +21,11 @@ typedef struct {
typedef map_t(Uniform) map_uniform_t;
typedef struct {
GLuint id;
int id;
map_uniform_t uniforms;
mat4 transform;
mat4 projection;
unsigned int color;
} Shader;
#endif
@ -37,6 +41,7 @@ GLuint linkShaders(GLuint vertexShader, GLuint fragmentShader);
Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource);
void lovrShaderDestroy(Shader* shader);
void lovrShaderBind(Shader* shader, mat4 transform, mat4 projection, unsigned int color, int force);
int lovrShaderGetAttributeId(Shader* shader, const char* name);
int lovrShaderGetUniformId(Shader* shader, const char* name);
int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count);

View File

@ -39,7 +39,7 @@ int l_lovrShaderSend(lua_State* L) {
GLenum type;
int size;
lovrShaderGetUniformType(shader, name, &type, &size);
lovrShaderBind(shader, shader->transform, shader->projection, shader->color, 0); // Hmm
float data[16];
switch (type) {

View File

@ -9,6 +9,12 @@
#define MAX(a, b) a > b ? a : b
#define MIN(a, b) a < b ? a : b
#define LOVR_COLOR(r, g, b, a) ((a << 0) | (b << 8) | (g << 16) | (r << 24))
#define LOVR_COLOR_R(c) (c >> 24 & 0xff)
#define LOVR_COLOR_G(c) (c >> 16 & 0xff)
#define LOVR_COLOR_B(c) (c >> 8 & 0xff)
#define LOVR_COLOR_A(c) (c >> 0 & 0xff)
typedef vec_t(unsigned int) vec_uint_t;
#endif