diff --git a/src/graphics/canvas.c b/src/graphics/canvas.c index 2ff8f9c5..d794792a 100644 --- a/src/graphics/canvas.c +++ b/src/graphics/canvas.c @@ -1,4 +1,5 @@ #include "graphics/canvas.h" +#include "graphics/gpu.h" #include "graphics/graphics.h" #include "data/blob.h" #include "util.h" @@ -30,7 +31,7 @@ Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, CanvasFlag // Framebuffer glGenFramebuffers(1, &canvas->framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, canvas->framebuffer); + gpuBindFramebuffer(canvas->framebuffer); // Color attachment if (flags.msaa > 0) { @@ -66,15 +67,15 @@ Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, CanvasFlag // Resolve framebuffer if (flags.msaa > 0) { glGenFramebuffers(1, &canvas->resolveFramebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, canvas->resolveFramebuffer); + gpuBindFramebuffer(canvas->resolveFramebuffer); glBindTexture(GL_TEXTURE_2D, canvas->texture.id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, canvas->texture.id, 0); - glBindFramebuffer(GL_FRAMEBUFFER, canvas->framebuffer); + gpuBindFramebuffer(canvas->framebuffer); } lovrAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Error creating Canvas"); lovrGraphicsClear(true, true, true, (Color) { 0, 0, 0, 0 }, 1., 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + gpuBindFramebuffer(0); return canvas; } @@ -121,7 +122,7 @@ TextureData* lovrCanvasNewTextureData(Canvas* canvas) { TextureData* textureData = lovrTextureDataGetBlank(canvas->texture.width, canvas->texture.height, 0, FORMAT_RGBA); if (!textureData) return NULL; - lovrGraphicsBindFramebuffer(canvas->framebuffer); + gpuBindFramebuffer(canvas->framebuffer); glReadPixels(0, 0, canvas->texture.width, canvas->texture.height, GL_RGBA, GL_UNSIGNED_BYTE, textureData->blob.data); return textureData; diff --git a/src/graphics/gpu.h b/src/graphics/gpu.h new file mode 100644 index 00000000..d12f7084 --- /dev/null +++ b/src/graphics/gpu.h @@ -0,0 +1,26 @@ +#include +#include + +#ifdef EMSCRIPTEN +#include +#include +#else +#include "lib/glad/glad.h" +#endif + +#pragma once + +typedef struct { + uint32_t shaderSwitches; +} GpuStats; + +typedef void (*gpuProc)(void); + +void gpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)); +void gpuPresent(); +void gpuBindFramebuffer(uint32_t framebuffer); +void gpuBindIndexBuffer(uint32_t indexBuffer); +void gpuBindVertexArray(uint32_t vertexArray); +void gpuBindVertexBuffer(uint32_t vertexBuffer); +void gpuSetViewport(uint32_t viewport[4]); +void gpuUseProgram(uint32_t program); diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 9a71eb87..b51c09f8 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -110,7 +110,7 @@ void lovrGraphicsReset() { void lovrGraphicsClear(bool clearColor, bool clearDepth, bool clearStencil, Color color, float depth, int stencil) { Layer layer = state.layers[state.layer]; Canvas* canvas = state.canvasCount > 0 ? state.canvas[0] : layer.canvas; - lovrGraphicsBindFramebuffer(canvas ? canvas->framebuffer : 0); + gpuBindFramebuffer(canvas ? canvas->framebuffer : 0); if (clearColor) { gammaCorrectColor(&color); @@ -134,7 +134,7 @@ void lovrGraphicsPresent() { glfwSwapBuffers(state.window); state.stats.drawCalls = 0; state.stats.shaderSwitches = 0; - state.program = -1; // Fixes a driver bug with instancing seen on macOS + gpuPresent(); } void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const char* title, const char* icon) { @@ -184,19 +184,9 @@ void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const cha #ifndef EMSCRIPTEN } - gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); glfwSwapInterval(0); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_PROGRAM_POINT_SIZE); - if (state.gammaCorrect) { - glEnable(GL_FRAMEBUFFER_SRGB); - } else { - glDisable(GL_FRAMEBUFFER_SRGB); - } #endif - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + gpuInit(state.gammaCorrect, glfwGetProcAddress); VertexFormat format; vertexFormatInit(&format); vertexFormatAppend(&format, "lovrPosition", ATTR_FLOAT, 3); @@ -316,7 +306,7 @@ void lovrGraphicsSetCanvas(Canvas** canvas, int count) { if (count > 0) { memcpy(state.canvas, canvas, count * sizeof(Canvas*)); - lovrGraphicsBindFramebuffer(canvas[0]->framebuffer); + gpuBindFramebuffer(canvas[0]->framebuffer); GLenum buffers[MAX_CANVASES]; for (int i = 0; i < count; i++) { @@ -1039,25 +1029,11 @@ void lovrGraphicsDraw(Mesh* mesh, mat4 transform, DefaultShader defaultShader, i // Layer Layer layer = state.layers[state.layer]; Canvas* canvas = state.canvasCount > 0 ? state.canvas[0] : layer.canvas; - lovrGraphicsBindFramebuffer(canvas ? canvas->framebuffer : 0); - - uint32_t viewport[4]; - if (state.canvasCount > 0) { - viewport[0] = 0; - viewport[1] = 0; - viewport[2] = state.canvas[0]->texture.width; - viewport[3] = state.canvas[0]->texture.height; - } else { - viewport[0] = layer.viewport[0]; - viewport[1] = layer.viewport[1]; - viewport[2] = layer.viewport[2]; - viewport[3] = layer.viewport[3]; - } - - if (memcmp(state.viewport, viewport, 4 * sizeof(uint32_t))) { - memcpy(state.viewport, viewport, 4 * sizeof(uint32_t)); - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - } + gpuBindFramebuffer(canvas ? canvas->framebuffer : 0); + gpuSetViewport(state.canvasCount > 0 ? + (uint32_t[4]) { 0, 0, state.canvas[0]->texture.width, state.canvas[0]->texture.height } : + layer.viewport + ); // Transforms if (transform) { @@ -1140,7 +1116,7 @@ void lovrGraphicsDraw(Mesh* mesh, mat4 transform, DefaultShader defaultShader, i lovrShaderSetTexture(shader, lovrShaderTextureUniforms[i], &texture, 1); } - lovrGraphicsUseProgram(shader->program); + gpuUseProgram(shader->program); lovrShaderBind(shader); lovrMeshBind(mesh, shader); @@ -1231,39 +1207,3 @@ Material* lovrGraphicsGetDefaultMaterial() { return state.defaultMaterial; } - -void lovrGraphicsUseProgram(uint32_t program) { - if (state.program != program) { - state.program = program; - glUseProgram(program); - state.stats.shaderSwitches++; - } -} - -void lovrGraphicsBindFramebuffer(uint32_t framebuffer) { - if (state.framebuffer != framebuffer) { - state.framebuffer = framebuffer; - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - } -} - -void lovrGraphicsBindVertexArray(uint32_t vertexArray) { - if (state.vertexArray != vertexArray) { - state.vertexArray = vertexArray; - glBindVertexArray(vertexArray); - } -} - -void lovrGraphicsBindVertexBuffer(uint32_t vertexBuffer) { - if (state.vertexBuffer != vertexBuffer) { - state.vertexBuffer = vertexBuffer; - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - } -} - -void lovrGraphicsBindIndexBuffer(uint32_t indexBuffer) { - if (state.indexBuffer != indexBuffer) { - state.indexBuffer = indexBuffer; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - } -} diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 0fc54ca6..8e66d837 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -1,3 +1,4 @@ +#include "graphics/gpu.h" #include "graphics/canvas.h" #include "graphics/font.h" #include "graphics/material.h" @@ -75,7 +76,7 @@ typedef struct { float projection[16]; float view[16]; Canvas* canvas; - int viewport[4]; + uint32_t viewport[4]; } Layer; typedef struct { @@ -126,12 +127,6 @@ typedef struct { Texture* textures[MAX_TEXTURES]; bool stencilEnabled; bool stencilWriting; - uint32_t program; - uint32_t framebuffer; - uint32_t viewport[4]; - uint32_t vertexArray; - uint32_t vertexBuffer; - uint32_t indexBuffer; GraphicsStats stats; } GraphicsState; @@ -213,8 +208,3 @@ void lovrGraphicsSetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t he Texture* lovrGraphicsGetTexture(int slot); void lovrGraphicsBindTexture(Texture* texture, GLenum type, int slot); Material* lovrGraphicsGetDefaultMaterial(); -void lovrGraphicsUseProgram(uint32_t program); -void lovrGraphicsBindFramebuffer(uint32_t framebuffer); -void lovrGraphicsBindVertexArray(uint32_t vao); -void lovrGraphicsBindVertexBuffer(uint32_t vbo); -void lovrGraphicsBindIndexBuffer(uint32_t ibo); diff --git a/src/graphics/mesh.c b/src/graphics/mesh.c index 80f77e1f..59bca978 100644 --- a/src/graphics/mesh.c +++ b/src/graphics/mesh.c @@ -1,4 +1,5 @@ #include "graphics/mesh.h" +#include "graphics/gpu.h" #include "graphics/graphics.h" #include "math/math.h" #include @@ -25,7 +26,7 @@ Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, glGenBuffers(1, &mesh->vbo); glGenBuffers(1, &mesh->ibo); - lovrGraphicsBindVertexBuffer(mesh->vbo); + gpuBindVertexBuffer(mesh->vbo); glBufferData(GL_ARRAY_BUFFER, count * format.stride, NULL, mesh->usage); glGenVertexArrays(1, &mesh->vao); @@ -87,11 +88,11 @@ void lovrMeshBind(Mesh* mesh, Shader* shader) { MeshAttachment layout[MAX_ATTACHMENTS]; memset(layout, 0, MAX_ATTACHMENTS * sizeof(MeshAttachment)); - lovrGraphicsBindVertexArray(mesh->vao); + gpuBindVertexArray(mesh->vao); lovrMeshUnmapVertices(mesh); lovrMeshUnmapIndices(mesh); if (mesh->indexCount > 0) { - lovrGraphicsBindIndexBuffer(mesh->ibo); + gpuBindIndexBuffer(mesh->ibo); } while ((key = map_next(&mesh->attachments, &iter)) != NULL) { @@ -128,7 +129,7 @@ void lovrMeshBind(Mesh* mesh, Shader* shader) { } if (previous.mesh != current.mesh || previous.attributeIndex != current.attributeIndex) { - lovrGraphicsBindVertexBuffer(current.mesh->vbo); + gpuBindVertexBuffer(current.mesh->vbo); VertexFormat* format = ¤t.mesh->format; Attribute attribute = format->attributes[current.attributeIndex]; switch (attribute.type) { @@ -225,7 +226,7 @@ void lovrMeshUnmapVertices(Mesh* mesh) { } size_t stride = mesh->format.stride; - lovrGraphicsBindVertexBuffer(mesh->vbo); + gpuBindVertexBuffer(mesh->vbo); if (mesh->usage == MESH_STREAM) { glBufferData(GL_ARRAY_BUFFER, mesh->count * stride, mesh->data.bytes, mesh->usage); } else { @@ -263,8 +264,8 @@ IndexPointer lovrMeshWriteIndices(Mesh* mesh, uint32_t count, size_t size) { return (IndexPointer) { .raw = NULL }; } - lovrGraphicsBindVertexArray(mesh->vao); - lovrGraphicsBindIndexBuffer(mesh->ibo); + gpuBindVertexArray(mesh->vao); + gpuBindIndexBuffer(mesh->ibo); mesh->mappedIndices = true; if (mesh->indexCapacity < size * count) { @@ -282,14 +283,14 @@ void lovrMeshUnmapIndices(Mesh* mesh) { } mesh->mappedIndices = false; - lovrGraphicsBindIndexBuffer(mesh->ibo); + gpuBindIndexBuffer(mesh->ibo); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->indexCount * mesh->indexSize, mesh->indices.raw); } void lovrMeshResize(Mesh* mesh, uint32_t count) { if (mesh->count < count) { mesh->count = nextPo2(count); - lovrGraphicsBindVertexBuffer(mesh->vbo); + gpuBindVertexBuffer(mesh->vbo); mesh->data.raw = realloc(mesh->data.raw, count * mesh->format.stride); glBufferData(GL_ARRAY_BUFFER, count * mesh->format.stride, mesh->data.raw, mesh->usage); } diff --git a/src/graphics/mesh.h b/src/graphics/mesh.h index 9231fff8..e3cdecda 100644 --- a/src/graphics/mesh.h +++ b/src/graphics/mesh.h @@ -1,7 +1,7 @@ +#include "graphics/gpu.h" #include "graphics/material.h" #include "graphics/shader.h" #include "data/vertexData.h" -#include "lib/glfw.h" #include "lib/map/map.h" #include "util.h" #include diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c new file mode 100644 index 00000000..2b3c27fc --- /dev/null +++ b/src/graphics/opengl.c @@ -0,0 +1,75 @@ +#include "graphics/gpu.h" +#include + +static struct { + uint32_t framebuffer; + uint32_t indexBuffer; + uint32_t program; + uint32_t vertexArray; + uint32_t vertexBuffer; + uint32_t viewport[4]; + GpuStats stats; +} state; + +void gpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) { +#ifndef EMSCRIPTEN + gladLoadGLLoader((GLADloadproc) getProcAddress); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_PROGRAM_POINT_SIZE); + if (srgb) { + glEnable(GL_FRAMEBUFFER_SRGB); + } else { + glDisable(GL_FRAMEBUFFER_SRGB); + } +#endif + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +void gpuPresent() { + memset(&state.stats, 0, sizeof(state.stats)); +} + +void gpuBindFramebuffer(uint32_t framebuffer) { + if (state.framebuffer != framebuffer) { + state.framebuffer = framebuffer; + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + } +} + +void gpuBindIndexBuffer(uint32_t indexBuffer) { + if (state.indexBuffer != indexBuffer) { + state.indexBuffer = indexBuffer; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); + } +} + +void gpuBindVertexArray(uint32_t vertexArray) { + if (state.vertexArray != vertexArray) { + state.vertexArray = vertexArray; + glBindVertexArray(vertexArray); + } +} + +void gpuBindVertexBuffer(uint32_t vertexBuffer) { + if (state.vertexBuffer != vertexBuffer) { + state.vertexBuffer = vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); + } +} + +void gpuSetViewport(uint32_t viewport[4]) { + if (memcmp(state.viewport, viewport, 4 * sizeof(uint32_t))) { + memcpy(state.viewport, viewport, 4 * sizeof(uint32_t)); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + } +} + +void gpuUseProgram(uint32_t program) { + if (state.program != program) { + state.program = program; + glUseProgram(program); + state.stats.shaderSwitches++; + } +} diff --git a/src/graphics/shader.c b/src/graphics/shader.c index d0eb6705..7ee20382 100644 --- a/src/graphics/shader.c +++ b/src/graphics/shader.c @@ -1,4 +1,5 @@ #include "graphics/shader.h" +#include "graphics/gpu.h" #include "graphics/graphics.h" #include "math/math.h" #include "resources/shaders.h" @@ -146,7 +147,7 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) { uint32_t program = linkShaders(vertexShader, fragmentShader); shader->program = program; - lovrGraphicsUseProgram(program); + gpuUseProgram(program); glVertexAttrib4fv(LOVR_SHADER_VERTEX_COLOR, (float[4]) { 1., 1., 1., 1. }); glVertexAttribI4iv(LOVR_SHADER_BONES, (int[4]) { 0., 0., 0., 0. }); glVertexAttrib4fv(LOVR_SHADER_BONE_WEIGHTS, (float[4]) { 1., 0., 0., 0. }); diff --git a/src/graphics/shader.h b/src/graphics/shader.h index ddbfb889..ef61f183 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -1,6 +1,6 @@ #include "graphics/texture.h" +#include "graphics/gpu.h" #include "lib/map/map.h" -#include "lib/glfw.h" #include "util.h" #include diff --git a/src/graphics/texture.h b/src/graphics/texture.h index 219bc8c8..1c442d06 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -1,5 +1,5 @@ +#include "graphics/gpu.h" #include "data/textureData.h" -#include "lib/glfw.h" #include "util.h" #include diff --git a/src/lib/glfw.h b/src/lib/glfw.h index c23be6e7..4c774291 100644 --- a/src/lib/glfw.h +++ b/src/lib/glfw.h @@ -1,16 +1,8 @@ #pragma once -#if EMSCRIPTEN -#define GLFW_INCLUDE_ES3 -#define GLFW_INCLUDE_GLEXT -#elif __APPLE__ -#define GLFW_INCLUDE_GLCOREARB -#elif _WIN32 +#ifdef _WIN32 #define APIENTRY __stdcall #endif -#ifndef EMSCRIPTEN -#include "glad/glad.h" -#endif - +#include "graphics/gpu.h" #include