Happy little graphics refactors;

This commit is contained in:
bjorn 2018-08-31 06:03:35 -07:00
parent 0ce6e046a6
commit a5256aaa27
12 changed files with 368 additions and 412 deletions

View File

@ -342,27 +342,25 @@ int l_lovrGraphicsGetDimensions(lua_State* L) {
}
int l_lovrGraphicsGetSupported(lua_State* L) {
GraphicsFeatures features = lovrGraphicsGetSupported();
const GpuFeatures* features = lovrGraphicsGetSupported();
lua_newtable(L);
lua_pushboolean(L, features.computeShaders);
lua_pushboolean(L, features->computeShaders);
lua_setfield(L, -2, "computeshaders");
lua_pushboolean(L, features.writableBlocks);
lua_setfield(L, -2, "writableblocks");
lua_pushboolean(L, features.singlepass);
lua_pushboolean(L, features->singlepass);
lua_setfield(L, -2, "singlepass");
return 1;
}
int l_lovrGraphicsGetSystemLimits(lua_State* L) {
GraphicsLimits limits = lovrGraphicsGetLimits();
const GpuLimits* limits = lovrGraphicsGetLimits();
lua_newtable(L);
lua_pushnumber(L, limits.pointSizes[1]);
lua_pushnumber(L, limits->pointSizes[1]);
lua_setfield(L, -2, "pointsize");
lua_pushinteger(L, limits.textureSize);
lua_pushinteger(L, limits->textureSize);
lua_setfield(L, -2, "texturesize");
lua_pushinteger(L, limits.textureMSAA);
lua_pushinteger(L, limits->textureMSAA);
lua_setfield(L, -2, "texturemsaa");
lua_pushinteger(L, limits.textureAnisotropy);
lua_pushinteger(L, limits->textureAnisotropy);
lua_setfield(L, -2, "anisotropy");
return 1;
}
@ -375,14 +373,11 @@ int l_lovrGraphicsGetStats(lua_State* L) {
lua_createtable(L, 0, 2);
}
GraphicsStats stats = lovrGraphicsGetStats();
lua_pushinteger(L, stats.drawCalls);
const GpuStats* stats = lovrGraphicsGetStats();
lua_pushinteger(L, stats->drawCalls);
lua_setfield(L, 1, "drawcalls");
lua_pushinteger(L, stats.shaderSwitches);
lua_pushinteger(L, stats->shaderSwitches);
lua_setfield(L, 1, "shaderswitches");
return 1;
}

View File

@ -57,7 +57,7 @@ int l_lovrMeshDrawInstanced(lua_State* L) {
int instances = luaL_checkinteger(L, 2);
float transform[16];
luax_readtransform(L, 3, transform, 1);
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.mesh = mesh,
.material = lovrMeshGetMaterial(mesh),

View File

@ -30,7 +30,7 @@ Canvas* lovrCanvasCreate(int width, int height, CanvasFlags flags);
void lovrCanvasDestroy(void* ref);
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count);
void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count);
void lovrCanvasBind(Canvas* canvas);
void lovrCanvasBind(Canvas* canvas, bool willDraw);
void lovrCanvasResolve(Canvas* canvas);
void lovrCanvasBlit(Canvas* canvas);
bool lovrCanvasIsStereo(Canvas* canvas);

View File

@ -1,4 +1,5 @@
#include "graphics/graphics.h"
#include "resources/shaders.h"
#include "data/rasterizer.h"
#include "event/event.h"
#include "filesystem/filesystem.h"
@ -370,10 +371,7 @@ void lovrGraphicsClear(Color* color, float* depth, int* stencil) {
lovrGpuClear(canvas, color, depth, stencil);
}
void lovrGraphicsDraw(DrawOptions* draw) {
Shader* shader = state.pipelines[state.pipeline].shader ? state.pipelines[state.pipeline].shader : state.defaultShaders[draw->shader];
if (!shader) shader = state.defaultShaders[draw->shader] = lovrShaderCreateDefault(draw->shader);
void lovrGraphicsDraw(DrawCommand* draw) {
Mesh* mesh = draw->mesh;
if (!mesh) {
int drawCount = draw->range.count ? draw->range.count : (draw->index.count ? draw->index.count : draw->vertex.count);
@ -392,54 +390,126 @@ void lovrGraphicsDraw(DrawOptions* draw) {
}
}
Material* material = draw->material;
if (!material) {
if (!state.defaultMaterial) {
state.defaultMaterial = lovrMaterialCreate();
}
if (draw->transform) {
lovrGraphicsPush();
lovrGraphicsMatrixTransform(draw->transform);
}
material = state.defaultMaterial;
Pipeline* pipeline = &state.pipelines[state.pipeline];
Canvas* canvas = pipeline->canvas ? pipeline->canvas : state.camera.canvas;
bool stereo = !draw->forceMono && (canvas ? lovrCanvasIsStereo(canvas) : state.camera.stereo);
float w = (canvas ? lovrCanvasGetWidth(canvas) : state.width) >> stereo;
float h = canvas ? lovrCanvasGetHeight(canvas) : state.height;
float viewports[2][4] = { { 0, 0, w, h, }, { w, 0, w, h } };
int viewportCount = 1 + stereo;
Material* material = draw->material ? draw->material : state.defaultMaterial;
if (!material) material = state.defaultMaterial = lovrMaterialCreate();
if (!draw->material) {
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
lovrMaterialSetTexture(material, i, draw->textures[i]);
}
}
Canvas* canvas = state.pipelines[state.pipeline].canvas ? state.pipelines[state.pipeline].canvas : state.camera.canvas;
bool stereo = !draw->forceMono && (canvas ? lovrCanvasIsStereo(canvas) : state.camera.stereo);
float w = (canvas ? lovrCanvasGetWidth(canvas) : state.width) >> stereo;
float h = canvas ? lovrCanvasGetHeight(canvas) : state.height;
int viewportCount = 1 + stereo;
Shader* shader = pipeline->shader ? pipeline->shader : state.defaultShaders[draw->shader];
if (!shader) shader = state.defaultShaders[draw->shader] = lovrShaderCreateDefault(draw->shader);
DrawCommand command = {
.mesh = mesh,
.canvas = canvas,
.shader = shader,
.material = material,
.camera = state.camera,
.viewports = { { 0, 0, w, h }, { w, 0, w, h } },
.viewportCount = viewportCount,
.pipeline = state.pipelines[state.pipeline],
.instances = draw->instances
};
mat4 transform = state.transforms[state.transform];
lovrShaderSetMatrices(shader, "lovrModel", transform, 0, 16);
lovrShaderSetMatrices(shader, "lovrViews", state.camera.viewMatrix[0], 0, 32);
lovrShaderSetMatrices(shader, "lovrProjections", state.camera.projection[0], 0, 32);
mat4_init(command.transform, state.transforms[state.transform]);
if (draw->transform) {
mat4_multiply(command.transform, draw->transform);
float modelView[32];
mat4_multiply(mat4_set(modelView, state.camera.viewMatrix[0]), transform);
mat4_multiply(mat4_set(modelView + 16, state.camera.viewMatrix[1]), transform);
lovrShaderSetMatrices(shader, "lovrTransforms", modelView, 0, 32);
if (lovrShaderHasUniform(shader, "lovrNormalMatrices")) {
if (mat4_invert(modelView) && mat4_invert(modelView + 16)) {
mat4_transpose(modelView);
mat4_transpose(modelView + 16);
} else {
mat4_identity(modelView);
mat4_identity(modelView + 16);
}
float normalMatrices[18] = {
modelView[0], modelView[1], modelView[2],
modelView[4], modelView[5], modelView[6],
modelView[8], modelView[9], modelView[10],
modelView[16], modelView[17], modelView[18],
modelView[20], modelView[21], modelView[22],
modelView[24], modelView[25], modelView[26]
};
lovrShaderSetMatrices(shader, "lovrNormalMatrices", normalMatrices, 0, 18);
}
lovrGpuDraw(&command);
float* pose = lovrMeshGetPose(mesh);
if (pose) {
lovrShaderSetMatrices(shader, "lovrPose", pose, 0, MAX_BONES * 16);
} else {
float identity[16];
mat4_identity(identity);
lovrShaderSetMatrices(shader, "lovrPose", identity, 0, 16);
}
lovrShaderSetInts(shader, "lovrViewportCount", &viewportCount, 0, 1);
lovrShaderSetColor(shader, "lovrColor", pipeline->color);
lovrShaderSetFloats(shader, "lovrPointSize", &pipeline->pointSize, 0, 1);
for (int i = 0; i < MAX_MATERIAL_SCALARS; i++) {
float value = lovrMaterialGetScalar(material, i);
lovrShaderSetFloats(shader, lovrShaderScalarUniforms[i], &value, 0, 1);
}
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
lovrShaderSetColor(shader, lovrShaderColorUniforms[i], lovrMaterialGetColor(material, i));
}
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
Texture* texture = lovrMaterialGetTexture(material, i);
lovrShaderSetTextures(shader, lovrShaderTextureUniforms[i], &texture, 0, 1);
}
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
// Bind
lovrCanvasBind(canvas, true);
lovrGpuBindPipeline(pipeline);
lovrMeshBind(mesh, shader, viewportCount);
// Draw
if (lovrGpuGetSupported()->singlepass) {
int instances = MAX(draw->instances, 1) * viewportCount;
lovrGpuSetViewports(&viewports[0][0], viewportCount);
lovrShaderBind(shader);
lovrMeshDraw(mesh, instances);
} else {
for (int i = 0; i < viewportCount; i++) {
lovrGpuSetViewports(&viewports[i][0], 1);
lovrShaderSetInts(shader, "lovrViewportIndex", &i, 0, 1);
lovrShaderBind(shader);
lovrMeshDraw(mesh, draw->instances);
}
}
if (draw->transform) {
lovrGraphicsPop();
}
}
void lovrGraphicsPoints(uint32_t count) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.mode = MESH_POINTS,
.range = { 0, count }
});
}
void lovrGraphicsLine(uint32_t count) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.mode = MESH_LINE_STRIP,
.range = { 0, count }
});
@ -447,7 +517,7 @@ void lovrGraphicsLine(uint32_t count) {
void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]) {
if (mode == DRAW_MODE_LINE) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.material = material,
.mode = MESH_LINE_LOOP,
.vertex.count = 3,
@ -460,7 +530,7 @@ void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]) {
} else {
float normal[3];
vec3_cross(vec3_init(normal, &points[0]), &points[3]);
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.material = material,
.mode = MESH_TRIANGLES,
.vertex.count = 3,
@ -475,7 +545,7 @@ void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]) {
void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform) {
if (mode == DRAW_MODE_LINE) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = MESH_LINE_LOOP,
@ -488,7 +558,7 @@ void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform) {
}
});
} else if (mode == DRAW_MODE_FILL) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = MESH_TRIANGLE_STRIP,
@ -505,7 +575,7 @@ void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform) {
void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform) {
if (mode == DRAW_MODE_LINE) {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = MESH_LINES,
@ -531,7 +601,7 @@ void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform) {
}
});
} else {
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = MESH_TRIANGLE_STRIP,
@ -608,7 +678,7 @@ void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 tr
theta += angleShift;
}
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = mode == DRAW_MODE_LINE ? (arcMode == ARC_MODE_OPEN ? MESH_LINE_STRIP : MESH_LINE_LOOP) : MESH_TRIANGLE_FAN,
@ -710,7 +780,7 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa
#undef PUSH_CYLINDER_VERTEX
#undef PUSH_CYLINDER_TRIANGLE
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.material = material,
.mode = MESH_TRIANGLES,
.range = { 0, indexCount }
@ -745,7 +815,7 @@ void lovrGraphicsSphere(Material* material, mat4 transform, int segments) {
}
}
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = transform,
.material = material,
.mode = MESH_TRIANGLES,
@ -758,7 +828,7 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float
lovrAssert(type == TEXTURE_CUBE || type == TEXTURE_2D, "Only 2D and cube textures can be used as skyboxes");
lovrGraphicsPushPipeline();
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.shader = type == TEXTURE_CUBE ? SHADER_CUBE : SHADER_PANO,
.textures[TEXTURE_DIFFUSE] = type == TEXTURE_2D ? texture : NULL,
.textures[TEXTURE_ENVIRONMENT_MAP] = type == TEXTURE_CUBE ? texture : NULL,
@ -790,7 +860,7 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
lovrGraphicsTranslate(0, offsety, 0);
lovrGraphicsPushPipeline();
state.pipelines[state.pipeline].depthWrite = false;
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.shader = SHADER_FONT,
.textures[TEXTURE_DIFFUSE] = font->texture,
.mode = MESH_TRIANGLES,
@ -803,7 +873,7 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
void lovrGraphicsFill(Texture* texture) {
lovrGraphicsPushPipeline();
lovrGraphicsSetDepthTest(COMPARE_NONE, false);
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.forceMono = true,
.shader = SHADER_FILL,
.textures[TEXTURE_DIFFUSE] = texture,

View File

@ -22,15 +22,6 @@ typedef enum {
ARC_MODE_CLOSED
} ArcMode;
typedef enum {
BARRIER_BLOCK,
BARRIER_UNIFORM_TEXTURE,
BARRIER_UNIFORM_IMAGE,
BARRIER_TEXTURE,
BARRIER_CANVAS,
MAX_BARRIERS
} Barrier;
typedef enum {
BLEND_ALPHA,
BLEND_ADD,
@ -78,9 +69,8 @@ typedef enum {
typedef struct {
bool computeShaders;
bool writableBlocks;
bool singlepass;
} GraphicsFeatures;
} GpuFeatures;
typedef struct {
bool initialized;
@ -88,12 +78,12 @@ typedef struct {
int textureSize;
int textureMSAA;
float textureAnisotropy;
} GraphicsLimits;
} GpuLimits;
typedef struct {
int shaderSwitches;
int drawCalls;
} GraphicsStats;
} GpuStats;
typedef struct {
bool stereo;
@ -142,19 +132,6 @@ typedef struct {
mat4 transform;
bool forceMono;
int instances;
} DrawOptions;
typedef struct {
Mesh* mesh;
Canvas* canvas;
Shader* shader;
Material* material;
Camera camera;
float transform[16];
float viewports[2][4];
int viewportCount;
Pipeline pipeline;
int instances;
} DrawCommand;
typedef struct {
@ -185,9 +162,9 @@ int lovrGraphicsGetWidth();
int lovrGraphicsGetHeight();
int lovrGraphicsGetMSAA();
void lovrGraphicsSetCamera(Camera* camera, bool clear);
GraphicsFeatures lovrGraphicsGetSupported();
GraphicsLimits lovrGraphicsGetLimits();
GraphicsStats lovrGraphicsGetStats();
#define lovrGraphicsGetSupported lovrGpuGetSupported
#define lovrGraphicsGetLimits lovrGpuGetLimits
#define lovrGraphicsGetStats lovrGpuGetStats
// State
void lovrGraphicsReset();
@ -235,7 +212,7 @@ void lovrGraphicsMatrixTransform(mat4 transform);
// Rendering
VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity);
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
void lovrGraphicsDraw(DrawOptions* draw);
void lovrGraphicsDraw(DrawCommand* draw);
void lovrGraphicsPoints(uint32_t count);
void lovrGraphicsLine(uint32_t count);
void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]);
@ -247,9 +224,8 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa
void lovrGraphicsSphere(Material* material, mat4 transform, int segments);
void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az);
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata);
void lovrGraphicsFill(Texture* texture);
#define lovrGraphicsBlit lovrGpuBlit
#define lovrGraphicsStencil lovrGpuStencil
#define lovrGraphicsCompute lovrGpuCompute
// GPU
@ -258,10 +234,13 @@ typedef void (*gpuProc)(void);
void lovrGpuInit(bool srgb, gpuProc (*getProcAddress)(const char*));
void lovrGpuDestroy();
void lovrGpuBindPipeline(Pipeline* pipeline);
void lovrGpuSetViewports(float* viewports, int count);
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil);
void lovrGpuDraw(DrawCommand* command);
void lovrGpuBlit(Canvas* canvas);
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata);
void lovrGpuCompute(Shader* shader, int x, int y, int z);
void lovrGpuWait(uint8_t flags);
void lovrGpuPresent();
void lovrGpuDirtyTexture(int slot);
const GpuFeatures* lovrGpuGetSupported();
const GpuLimits* lovrGpuGetLimits();
const GpuStats* lovrGpuGetStats();

View File

@ -24,6 +24,7 @@ void lovrMeshDestroy(void* ref);
void lovrMeshAttachAttribute(Mesh* mesh, Mesh* other, const char* name, int divisor);
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
void lovrMeshBind(Mesh* mesh, Shader* shader);
void lovrMeshDraw(Mesh* mesh, int instances);
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh);
void lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode);

View File

@ -41,7 +41,7 @@ static void renderNode(Model* model, int nodeIndex, int instances) {
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
lovrMeshSetPose(model->mesh, (float*) model->pose);
lovrGraphicsDraw(&(DrawOptions) {
lovrGraphicsDraw(&(DrawCommand) {
.transform = model->nodeTransforms[nodeIndex],
.mesh = model->mesh,
.material = lovrMeshGetMaterial(model->mesh),

View File

@ -36,6 +36,15 @@
#define LOVR_SHADER_BONES 5
#define LOVR_SHADER_BONE_WEIGHTS 6
typedef enum {
BARRIER_BLOCK,
BARRIER_UNIFORM_TEXTURE,
BARRIER_UNIFORM_IMAGE,
BARRIER_TEXTURE,
BARRIER_CANVAS,
MAX_BARRIERS
} Barrier;
static struct {
Texture* defaultTexture;
BlendMode blendMode;
@ -63,9 +72,9 @@ static struct {
float viewports[2][4];
vec_void_t incoherents[MAX_BARRIERS];
bool srgb;
bool singlepass;
GraphicsLimits limits;
GraphicsStats stats;
GpuFeatures features;
GpuLimits limits;
GpuStats stats;
} state;
struct ShaderBlock {
@ -422,8 +431,52 @@ static Texture* lovrGpuGetDefaultTexture() {
return state.defaultTexture;
}
// TODO this is pretty slow
static void lovrGpuCleanupIncoherentResource(void* resource, uint8_t incoherent) {
// Syncing resources is only relevant for compute shaders
#ifndef EMSCRIPTEN
static void lovrGpuSync(uint8_t flags) {
if (!flags) {
return;
}
GLbitfield bits = 0;
for (int i = 0; i < MAX_BARRIERS; i++) {
if (!((flags >> i) & 1)) {
continue;
}
if (state.incoherents[i].length == 0) {
flags &= ~(1 << i);
continue;
}
if (i == BARRIER_BLOCK) {
for (int j = 0; j < state.incoherents[j].length; j++) {
ShaderBlock* block = state.incoherents[i].data[j];
block->incoherent &= ~(1 << i);
}
} else {
for (int j = 0; j < state.incoherents[j].length; j++) {
Texture* texture = state.incoherents[i].data[j];
texture->incoherent &= ~(1 << i);
}
}
switch (i) {
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
case BARRIER_UNIFORM_IMAGE: bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; break;
case BARRIER_UNIFORM_TEXTURE: bits |= GL_TEXTURE_FETCH_BARRIER_BIT; break;
case BARRIER_TEXTURE: bits |= GL_TEXTURE_UPDATE_BARRIER_BIT; break;
case BARRIER_CANVAS: bits |= GL_FRAMEBUFFER_BARRIER_BIT; break;
}
}
if (bits) {
glMemoryBarrier(bits);
}
}
#endif
static void lovrGpuDestroySyncResource(void* resource, uint8_t incoherent) {
if (!incoherent) {
return;
}
@ -440,8 +493,6 @@ static void lovrGpuCleanupIncoherentResource(void* resource, uint8_t incoherent)
}
}
// GPU
static void lovrGpuBindFramebuffer(uint32_t framebuffer) {
if (state.framebuffer != framebuffer) {
state.framebuffer = framebuffer;
@ -472,15 +523,9 @@ static void lovrGpuBindTexture(Texture* texture, int slot) {
}
}
void lovrGpuDirtyTexture(int slot) {
lovrAssert(slot >= 0 && slot < MAX_TEXTURES, "Invalid texture slot %d", slot);
state.textures[slot] = NULL;
}
#ifndef EMSCRIPTEN
static void lovrGpuBindImage(Image* image, int slot) {
#ifdef EMSCRIPTEN
lovrThrow("Shaders can not write to textures on this system");
#else
lovrAssert(slot >= 0 && slot < MAX_IMAGES, "Invalid image slot %d", slot);
// This is a risky way to compare the two structs
@ -499,8 +544,8 @@ static void lovrGpuBindImage(Image* image, int slot) {
glBindImageTexture(slot, texture->id, image->mipmap, image->slice == -1, image->slice, glAccess, glFormat);
memcpy(state.images + slot, image, sizeof(Image));
}
#endif
}
#endif
static void lovrGpuBindBlockBuffer(BlockType type, uint32_t buffer, int slot) {
#ifdef EMSCRIPTEN
@ -538,27 +583,13 @@ static void lovrGpuUseProgram(uint32_t program) {
}
}
static void lovrGpuSetViewports(float* viewport, int count) {
#ifndef EMSCRIPTEN
if (count > 1) {
if (memcmp(state.viewports, viewport, count * 4 * sizeof(float))) {
memcpy(state.viewports, viewport, count * 4 * sizeof(float));
glViewportArrayv(0, count, viewport);
}
} else {
#endif
if (memcmp(state.viewports, viewport, 4 * sizeof(float))) {
memcpy(state.viewports, viewport, 4 * sizeof(float));
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
#ifndef EMSCRIPTEN
}
#endif
}
// GPU
void lovrGpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) {
#ifndef EMSCRIPTEN
gladLoadGLLoader((GLADloadproc) getProcAddress);
state.features.computeShaders = GLAD_GL_ARB_compute_shader;
state.features.singlepass = GLAD_GL_ARB_viewport_array && GLAD_GL_AMD_vertex_shader_viewport_index && GLAD_GL_ARB_fragment_layer_viewport;
glEnable(GL_LINE_SMOOTH);
glEnable(GL_PROGRAM_POINT_SIZE);
if (srgb) {
@ -566,7 +597,13 @@ void lovrGpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) {
} else {
glDisable(GL_FRAMEBUFFER_SRGB);
}
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
#else
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, state.limits.pointSizes);
#endif
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
glEnable(GL_BLEND);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
state.srgb = srgb;
@ -601,76 +638,7 @@ void lovrGpuDestroy() {
}
}
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil) {
if (canvas) {
lovrCanvasBind(canvas);
canvas->needsResolve = true;
} else {
lovrGpuBindFramebuffer(0);
}
if (color) {
gammaCorrectColor(color);
int count = canvas ? canvas->count : 1;
for (int i = 0; i < count; i++) {
glClearBufferfv(GL_COLOR, i, (float[]) { color->r, color->g, color->b, color->a });
}
}
if (depth && !state.depthWrite) {
state.depthWrite = true;
glDepthMask(state.depthWrite);
}
if (depth && stencil) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, *depth, *stencil);
} else if (depth) {
glClearBufferfv(GL_DEPTH, 0, depth);
} else if (stencil) {
glClearBufferiv(GL_STENCIL, 0, stencil);
}
}
void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata) {
state.depthWrite = false;
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
if (!state.stencilEnabled) {
state.stencilEnabled = true;
glEnable(GL_STENCIL_TEST);
}
GLenum glAction;
switch (action) {
case STENCIL_REPLACE: glAction = GL_REPLACE; break;
case STENCIL_INCREMENT: glAction = GL_INCR; break;
case STENCIL_DECREMENT: glAction = GL_DECR; break;
case STENCIL_INCREMENT_WRAP: glAction = GL_INCR_WRAP; break;
case STENCIL_DECREMENT_WRAP: glAction = GL_DECR_WRAP; break;
case STENCIL_INVERT: glAction = GL_INVERT; break;
}
glStencilFunc(GL_ALWAYS, replaceValue, 0xff);
glStencilOp(GL_KEEP, GL_KEEP, glAction);
state.stencilWriting = true;
callback(userdata);
state.stencilWriting = false;
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
state.stencilMode = ~0; // Dirty
}
void lovrGpuDraw(DrawCommand* command) {
Mesh* mesh = command->mesh;
Canvas* canvas = command->canvas;
Shader* shader = command->shader;
Material* material = command->material;
Pipeline* pipeline = &command->pipeline;
int instances = command->instances;
// Bind shader
lovrGpuUseProgram(shader->program);
void lovrGpuBindPipeline(Pipeline* pipeline) {
// Blend mode
if (state.blendMode != pipeline->blendMode || state.blendAlphaMode != pipeline->blendAlphaMode) {
@ -804,130 +772,79 @@ void lovrGpuDraw(DrawCommand* command) {
glPolygonMode(GL_FRONT_AND_BACK, state.wireframe ? GL_LINE : GL_FILL);
}
#endif
}
// Uniforms
lovrShaderSetMatrices(shader, "lovrModel", command->transform, 0, 16);
lovrShaderSetMatrices(shader, "lovrViews", command->camera.viewMatrix[0], 0, 32);
lovrShaderSetMatrices(shader, "lovrProjections", command->camera.projection[0], 0, 32);
lovrShaderSetInts(shader, "lovrViewportCount", &command->viewportCount, 0, 1);
float modelView[32];
mat4_multiply(mat4_set(modelView, command->camera.viewMatrix[0]), command->transform);
mat4_multiply(mat4_set(modelView + 16, command->camera.viewMatrix[1]), command->transform);
lovrShaderSetMatrices(shader, "lovrTransforms", modelView, 0, 32);
if (lovrShaderHasUniform(shader, "lovrNormalMatrices")) {
if (mat4_invert(modelView) && mat4_invert(modelView + 16)) {
mat4_transpose(modelView);
mat4_transpose(modelView + 16);
} else {
mat4_identity(modelView);
mat4_identity(modelView + 16);
void lovrGpuSetViewports(float* viewport, int count) {
#ifndef EMSCRIPTEN
if (count > 1) {
if (memcmp(state.viewports, viewport, count * 4 * sizeof(float))) {
memcpy(state.viewports, viewport, count * 4 * sizeof(float));
glViewportArrayv(0, count, viewport);
}
float normalMatrices[18] = {
modelView[0], modelView[1], modelView[2],
modelView[4], modelView[5], modelView[6],
modelView[8], modelView[9], modelView[10],
modelView[16], modelView[17], modelView[18],
modelView[20], modelView[21], modelView[22],
modelView[24], modelView[25], modelView[26]
};
lovrShaderSetMatrices(shader, "lovrNormalMatrices", normalMatrices, 0, 18);
}
// Pose
float* pose = lovrMeshGetPose(mesh);
if (pose) {
lovrShaderSetMatrices(shader, "lovrPose", pose, 0, MAX_BONES * 16);
} else {
float identity[16];
mat4_identity(identity);
lovrShaderSetMatrices(shader, "lovrPose", identity, 0, 16);
}
// Point size
lovrShaderSetFloats(shader, "lovrPointSize", &pipeline->pointSize, 0, 1);
// Color
Color color = pipeline->color;
gammaCorrectColor(&color);
float data[4] = { color.r, color.g, color.b, color.a };
lovrShaderSetFloats(shader, "lovrColor", data, 0, 4);
// Material
for (int i = 0; i < MAX_MATERIAL_SCALARS; i++) {
float value = lovrMaterialGetScalar(material, i);
lovrShaderSetFloats(shader, lovrShaderScalarUniforms[i], &value, 0, 1);
}
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
Color color = lovrMaterialGetColor(material, i);
gammaCorrectColor(&color);
float data[4] = { color.r, color.g, color.b, color.a };
lovrShaderSetFloats(shader, lovrShaderColorUniforms[i], data, 0, 4);
}
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
Texture* texture = lovrMaterialGetTexture(material, i);
lovrShaderSetTextures(shader, lovrShaderTextureUniforms[i], &texture, 0, 1);
}
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
// Bind attributes
lovrMeshBind(mesh, shader, command->viewportCount);
// Canvas
if (canvas) {
lovrCanvasBind(canvas);
canvas->needsResolve = true;
} else {
lovrGpuBindFramebuffer(0);
}
// Draw
bool singlepass = lovrGraphicsGetSupported().singlepass;
int drawCount = singlepass ? 1 : command->viewportCount;
instances = MAX(instances, 1) * (singlepass ? command->viewportCount : 1);
for (int i = 0; i < drawCount; i++) {
lovrGpuSetViewports(&command->viewports[i][0], singlepass ? command->viewportCount : 1);
if (!singlepass) {
lovrShaderSetInts(shader, "lovrViewportIndex", &i, 0, 1);
#endif
if (memcmp(state.viewports, viewport, 4 * sizeof(float))) {
memcpy(state.viewports, viewport, 4 * sizeof(float));
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
lovrShaderBind(shader);
uint32_t rangeStart, rangeCount;
lovrMeshGetDrawRange(mesh, &rangeStart, &rangeCount);
uint32_t indexCount;
size_t indexSize;
lovrMeshReadIndices(mesh, &indexCount, &indexSize);
GLenum glDrawMode = convertMeshDrawMode(lovrMeshGetDrawMode(mesh));
if (indexCount > 0) {
size_t count = rangeCount ? rangeCount : indexCount;
GLenum indexType = indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
size_t offset = rangeStart * indexSize;
if (instances > 1) {
glDrawElementsInstanced(glDrawMode, count, indexType, (GLvoid*) offset, instances);
} else {
glDrawElements(glDrawMode, count, indexType, (GLvoid*) offset);
}
} else {
size_t count = rangeCount ? rangeCount : lovrMeshGetVertexCount(mesh);
if (instances > 1) {
glDrawArraysInstanced(glDrawMode, rangeStart, count, instances);
} else {
glDrawArrays(glDrawMode, rangeStart, count);
}
}
state.stats.drawCalls++;
#ifndef EMSCRIPTEN
}
#endif
}
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil) {
lovrCanvasBind(canvas, true);
if (color) {
gammaCorrectColor(color);
int count = canvas ? canvas->count : 1;
for (int i = 0; i < count; i++) {
glClearBufferfv(GL_COLOR, i, (float[]) { color->r, color->g, color->b, color->a });
}
}
if (depth && !state.depthWrite) {
state.depthWrite = true;
glDepthMask(state.depthWrite);
}
if (depth && stencil) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, *depth, *stencil);
} else if (depth) {
glClearBufferfv(GL_DEPTH, 0, depth);
} else if (stencil) {
glClearBufferiv(GL_STENCIL, 0, stencil);
}
}
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata) {
state.depthWrite = false;
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
if (!state.stencilEnabled) {
state.stencilEnabled = true;
glEnable(GL_STENCIL_TEST);
}
GLenum glAction;
switch (action) {
case STENCIL_REPLACE: glAction = GL_REPLACE; break;
case STENCIL_INCREMENT: glAction = GL_INCR; break;
case STENCIL_DECREMENT: glAction = GL_DECR; break;
case STENCIL_INCREMENT_WRAP: glAction = GL_INCR_WRAP; break;
case STENCIL_DECREMENT_WRAP: glAction = GL_DECR_WRAP; break;
case STENCIL_INVERT: glAction = GL_INVERT; break;
}
glStencilFunc(GL_ALWAYS, replaceValue, 0xff);
glStencilOp(GL_KEEP, GL_KEEP, glAction);
state.stencilWriting = true;
callback(userdata);
state.stencilWriting = false;
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
state.stencilMode = ~0; // Dirty
}
void lovrGpuCompute(Shader* shader, int x, int y, int z) {
@ -936,56 +853,11 @@ void lovrGpuCompute(Shader* shader, int x, int y, int z) {
#else
lovrAssert(GLAD_GL_ARB_compute_shader, "Compute shaders are not supported on this system");
lovrAssert(shader->type == SHADER_COMPUTE, "Attempt to use a non-compute shader for a compute operation");
lovrGpuUseProgram(shader->program);
lovrShaderBind(shader);
glDispatchCompute(x, y, z);
#endif
}
void lovrGpuWait(uint8_t flags) {
#ifndef EMSCRIPTEN
if (!GL_ARB_shader_image_load_store || !flags) {
return;
}
GLbitfield bits = 0;
for (int i = 0; i < MAX_BARRIERS; i++) {
if (!((flags >> i) & 1)) {
continue;
}
if (state.incoherents[i].length == 0) {
flags &= ~(1 << i);
continue;
}
if (i == BARRIER_BLOCK) {
for (int j = 0; j < state.incoherents[j].length; j++) {
ShaderBlock* block = state.incoherents[i].data[j];
block->incoherent &= ~(1 << i);
}
} else {
for (int j = 0; j < state.incoherents[j].length; j++) {
Texture* texture = state.incoherents[i].data[j];
texture->incoherent &= ~(1 << i);
}
}
switch (i) {
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
case BARRIER_UNIFORM_IMAGE: bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; break;
case BARRIER_UNIFORM_TEXTURE: bits |= GL_TEXTURE_FETCH_BARRIER_BIT; break;
case BARRIER_TEXTURE: bits |= GL_TEXTURE_UPDATE_BARRIER_BIT; break;
case BARRIER_CANVAS: bits |= GL_FRAMEBUFFER_BARRIER_BIT; break;
}
}
if (bits) {
glMemoryBarrier(bits);
}
#endif
}
void lovrGpuPresent() {
memset(&state.stats, 0, sizeof(state.stats));
#ifdef __APPLE__
@ -994,38 +866,21 @@ void lovrGpuPresent() {
#endif
}
GraphicsFeatures lovrGraphicsGetSupported() {
return (GraphicsFeatures) {
#ifdef EMSCRIPTEN
.computeShaders = false,
.writableBlocks = false,
.singlepass = false
#else
.computeShaders = GLAD_GL_ARB_compute_shader,
.writableBlocks = GLAD_GL_ARB_shader_storage_buffer_object,
.singlepass = GLAD_GL_ARB_viewport_array && GLAD_GL_AMD_vertex_shader_viewport_index
#endif
};
void lovrGpuDirtyTexture(int slot) {
lovrAssert(slot >= 0 && slot < MAX_TEXTURES, "Invalid texture slot %d", slot);
state.textures[slot] = NULL;
}
GraphicsLimits lovrGraphicsGetLimits() {
if (!state.limits.initialized) {
#ifdef EMSCRIPTEN
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, state.limits.pointSizes);
#else
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
#endif
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
state.limits.initialized = 1;
}
return state.limits;
const GpuFeatures* lovrGpuGetSupported() {
return &state.features;
}
GraphicsStats lovrGraphicsGetStats() {
return state.stats;
const GpuLimits* lovrGpuGetLimits() {
return &state.limits;
}
const GpuStats* lovrGpuGetStats() {
return &state.stats;
}
// Texture
@ -1070,12 +925,12 @@ void lovrTextureDestroy(void* ref) {
Texture* texture = ref;
glDeleteTextures(1, &texture->id);
glDeleteRenderbuffers(1, &texture->msaaId);
lovrGpuCleanupIncoherentResource(texture, texture->incoherent);
lovrGpuDestroySyncResource(texture, texture->incoherent);
free(texture);
}
void lovrTextureAllocate(Texture* texture, int width, int height, int depth, TextureFormat format) {
int maxSize = lovrGraphicsGetLimits().textureSize;
int maxSize = state.limits.textureSize;
lovrAssert(!texture->allocated, "Texture is already allocated");
lovrAssert(texture->type != TEXTURE_CUBE || width == height, "Cubemap images must be square");
lovrAssert(texture->type != TEXTURE_CUBE || depth == 6, "6 images are required for a cube texture\n");
@ -1101,7 +956,7 @@ void lovrTextureAllocate(Texture* texture, int width, int height, int depth, Tex
return;
}
bool srgb = lovrGraphicsIsGammaCorrect() && texture->srgb;
bool srgb = state.srgb && texture->srgb;
GLenum glFormat = convertTextureFormat(format);
GLenum internalFormat = convertTextureFormatInternal(format, srgb);
#ifndef EMSCRIPTEN
@ -1148,9 +1003,11 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x,
lovrAssert(texture->allocated, "Texture is not allocated");
lovrAssert(textureData->blob.data, "Trying to replace Texture pixels with empty pixel data");
#ifndef EMSCRIPTEN
if ((texture->incoherent >> BARRIER_TEXTURE) & 1) {
lovrGpuWait(1 << BARRIER_TEXTURE);
lovrGpuSync(1 << BARRIER_TEXTURE);
}
#endif
int maxWidth = lovrTextureGetWidth(texture, mipmap);
int maxHeight = lovrTextureGetHeight(texture, mipmap);
@ -1353,21 +1210,29 @@ void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count
canvas->needsAttach = true;
}
void lovrCanvasBind(Canvas* canvas) {
lovrGpuBindFramebuffer(canvas->framebuffer);
void lovrCanvasBind(Canvas* canvas, bool willDraw) {
if (canvas) {
lovrGpuBindFramebuffer(canvas->framebuffer);
canvas->needsResolve = willDraw;
} else {
lovrGpuBindFramebuffer(0);
return;
}
if (!canvas->needsAttach) {
return;
}
// We need to synchronize if any of the Canvas attachments have pending writes on them
#ifndef EMSCRIPTEN
for (int i = 0; i < canvas->count; i++) {
Texture* texture = canvas->attachments[i].texture;
if (texture->incoherent && (texture->incoherent >> BARRIER_CANVAS) & 1) {
lovrGpuWait(1 << BARRIER_CANVAS);
lovrGpuSync(1 << BARRIER_CANVAS);
break;
}
}
#endif
// Use the read framebuffer as a binding point to bind resolve textures
if (canvas->flags.msaa) {
@ -1475,12 +1340,14 @@ DepthFormat lovrCanvasGetDepthFormat(Canvas* canvas) {
}
TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
lovrCanvasBind(canvas);
lovrCanvasBind(canvas, false);
#ifndef EMSCRIPTEN
Texture* texture = canvas->attachments[index].texture;
if ((texture->incoherent >> BARRIER_TEXTURE) & 1) {
lovrGpuWait(1 << BARRIER_TEXTURE);
lovrGpuSync(1 << BARRIER_TEXTURE);
}
#endif
if (index != 0) {
glReadBuffer(index);
@ -1842,7 +1709,10 @@ void lovrShaderBind(Shader* shader) {
Uniform* uniform;
int i;
lovrGpuUseProgram(shader->program);
// Figure out if we need to wait for pending writes on resources to complete
#ifndef EMSCRIPTEN
uint8_t flags = 0;
vec_foreach_ptr(&shader->blocks[BLOCK_STORAGE], block, i) {
if (block->source && (block->source->incoherent >> BARRIER_BLOCK) & 1) {
@ -1875,7 +1745,8 @@ void lovrShaderBind(Shader* shader) {
}
}
lovrGpuWait(flags);
lovrGpuSync(flags);
#endif
// Bind uniforms
vec_foreach_ptr(&shader->uniforms, uniform, i) {
@ -1914,6 +1785,7 @@ void lovrShaderBind(Shader* shader) {
}
break;
#ifndef EMSCRIPTEN
case UNIFORM_IMAGE:
for (int i = 0; i < count; i++) {
Image* image = &uniform->value.images[i];
@ -1931,6 +1803,7 @@ void lovrShaderBind(Shader* shader) {
lovrGpuBindImage(image, uniform->baseSlot + i);
}
break;
#endif
case UNIFORM_SAMPLER:
for (int i = 0; i < count; i++) {
@ -2017,6 +1890,11 @@ void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int star
lovrShaderSetUniform(shader, name, UNIFORM_IMAGE, data, start, count, sizeof(Image), "image");
}
void lovrShaderSetColor(Shader* shader, const char* name, Color color) {
gammaCorrectColor(&color);
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, (float*) &color, 0, 4, sizeof(float), "float");
}
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* source, UniformAccess access) {
int* id = map_get(&shader->blockMap, name);
lovrAssert(id, "No shader block named '%s'", name);
@ -2052,7 +1930,7 @@ ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms, BlockType type, Buff
ShaderBlock* block = lovrAlloc(ShaderBlock, lovrShaderBlockDestroy);
if (!block) return NULL;
lovrAssert(type != BLOCK_STORAGE || lovrGraphicsGetSupported().writableBlocks, "Writable ShaderBlocks are not supported on this system");
lovrAssert(type != BLOCK_STORAGE || state.features.computeShaders, "Writable ShaderBlocks are not supported on this system");
vec_init(&block->uniforms);
vec_extend(&block->uniforms, uniforms);
@ -2098,7 +1976,7 @@ ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms, BlockType type, Buff
void lovrShaderBlockDestroy(void* ref) {
ShaderBlock* block = ref;
lovrGpuCleanupIncoherentResource(block, block->incoherent);
lovrGpuDestroySyncResource(block, block->incoherent);
glDeleteBuffers(1, &block->buffer);
vec_deinit(&block->uniforms);
map_deinit(&block->uniformMap);
@ -2315,6 +2193,30 @@ void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
}
}
void lovrMeshDraw(Mesh* mesh, int instances) {
GLenum glDrawMode = convertMeshDrawMode(lovrMeshGetDrawMode(mesh));
if (mesh->indexCount > 0) {
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->indexCount;
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
size_t offset = mesh->rangeStart * mesh->indexSize;
if (instances > 1) {
glDrawElementsInstanced(glDrawMode, count, indexType, (GLvoid*) offset, instances);
} else {
glDrawElements(glDrawMode, count, indexType, (GLvoid*) offset);
}
} else {
size_t count = mesh->rangeCount ? mesh->rangeCount : lovrMeshGetVertexCount(mesh);
if (instances > 1) {
glDrawArraysInstanced(glDrawMode, mesh->rangeStart, count, instances);
} else {
glDrawArrays(glDrawMode, mesh->rangeStart, count);
}
}
state.stats.drawCalls++;
}
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
return &mesh->format;
}

View File

@ -104,6 +104,7 @@ void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, i
void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count);
void lovrShaderSetTextures(Shader* shader, const char* name, Texture** data, int start, int count);
void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count);
void lovrShaderSetColor(Shader* shader, const char* name, Color color);
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* block, UniformAccess access);
ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms, BlockType type, BufferUsage usage);

View File

@ -1,6 +1,6 @@
/*
OpenGL loader generated by glad 0.1.27 on Thu Aug 30 09:12:15 2018.
OpenGL loader generated by glad 0.1.27 on Fri Aug 31 13:59:29 2018.
Language/Generator: C/C++
Specification: gl
@ -9,6 +9,7 @@
Extensions:
GL_AMD_vertex_shader_viewport_index,
GL_ARB_compute_shader,
GL_ARB_fragment_layer_viewport,
GL_ARB_program_interface_query,
GL_ARB_shader_image_load_store,
GL_ARB_shader_storage_buffer_object,
@ -22,9 +23,9 @@
Omit khrplatform: True
Commandline:
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --local-files --omit-khrplatform --extensions="GL_AMD_vertex_shader_viewport_index,GL_ARB_compute_shader,GL_ARB_program_interface_query,GL_ARB_shader_image_load_store,GL_ARB_shader_storage_buffer_object,GL_ARB_texture_storage,GL_ARB_viewport_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_sRGB"
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --local-files --omit-khrplatform --extensions="GL_AMD_vertex_shader_viewport_index,GL_ARB_compute_shader,GL_ARB_fragment_layer_viewport,GL_ARB_program_interface_query,GL_ARB_shader_image_load_store,GL_ARB_shader_storage_buffer_object,GL_ARB_texture_storage,GL_ARB_viewport_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_sRGB"
Online:
http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ARB_compute_shader&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_texture_storage&extensions=GL_ARB_viewport_array&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_sRGB
http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ARB_compute_shader&extensions=GL_ARB_fragment_layer_viewport&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_texture_storage&extensions=GL_ARB_viewport_array&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_sRGB
*/
#include <stdio.h>
@ -519,6 +520,7 @@ PFNGLVIEWPORTPROC glad_glViewport = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
int GLAD_GL_AMD_vertex_shader_viewport_index = 0;
int GLAD_GL_ARB_compute_shader = 0;
int GLAD_GL_ARB_fragment_layer_viewport = 0;
int GLAD_GL_ARB_program_interface_query = 0;
int GLAD_GL_ARB_shader_image_load_store = 0;
int GLAD_GL_ARB_shader_storage_buffer_object = 0;
@ -1010,6 +1012,7 @@ static int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_AMD_vertex_shader_viewport_index = has_ext("GL_AMD_vertex_shader_viewport_index");
GLAD_GL_ARB_compute_shader = has_ext("GL_ARB_compute_shader");
GLAD_GL_ARB_fragment_layer_viewport = has_ext("GL_ARB_fragment_layer_viewport");
GLAD_GL_ARB_program_interface_query = has_ext("GL_ARB_program_interface_query");
GLAD_GL_ARB_shader_image_load_store = has_ext("GL_ARB_shader_image_load_store");
GLAD_GL_ARB_shader_storage_buffer_object = has_ext("GL_ARB_shader_storage_buffer_object");

View File

@ -1,6 +1,6 @@
/*
OpenGL loader generated by glad 0.1.27 on Thu Aug 30 09:12:15 2018.
OpenGL loader generated by glad 0.1.27 on Fri Aug 31 13:59:29 2018.
Language/Generator: C/C++
Specification: gl
@ -9,6 +9,7 @@
Extensions:
GL_AMD_vertex_shader_viewport_index,
GL_ARB_compute_shader,
GL_ARB_fragment_layer_viewport,
GL_ARB_program_interface_query,
GL_ARB_shader_image_load_store,
GL_ARB_shader_storage_buffer_object,
@ -22,9 +23,9 @@
Omit khrplatform: True
Commandline:
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --local-files --omit-khrplatform --extensions="GL_AMD_vertex_shader_viewport_index,GL_ARB_compute_shader,GL_ARB_program_interface_query,GL_ARB_shader_image_load_store,GL_ARB_shader_storage_buffer_object,GL_ARB_texture_storage,GL_ARB_viewport_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_sRGB"
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --local-files --omit-khrplatform --extensions="GL_AMD_vertex_shader_viewport_index,GL_ARB_compute_shader,GL_ARB_fragment_layer_viewport,GL_ARB_program_interface_query,GL_ARB_shader_image_load_store,GL_ARB_shader_storage_buffer_object,GL_ARB_texture_storage,GL_ARB_viewport_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_sRGB"
Online:
http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ARB_compute_shader&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_texture_storage&extensions=GL_ARB_viewport_array&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_sRGB
http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ARB_compute_shader&extensions=GL_ARB_fragment_layer_viewport&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_texture_storage&extensions=GL_ARB_viewport_array&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_sRGB
*/
@ -2392,6 +2393,10 @@ typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);
GLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
#endif
#ifndef GL_ARB_fragment_layer_viewport
#define GL_ARB_fragment_layer_viewport 1
GLAPI int GLAD_GL_ARB_fragment_layer_viewport;
#endif
#ifndef GL_ARB_program_interface_query
#define GL_ARB_program_interface_query 1
GLAPI int GLAD_GL_ARB_program_interface_query;

View File

@ -83,7 +83,7 @@ const char* lovrShaderFragmentPrefix = ""
"precision mediump int; \n"
#else
"#version 150 \n"
"#extension GL_AMD_vertex_shader_viewport_index : enable \n"
"#extension GL_ARB_fragment_layer_viewport : enable \n"
"in vec4 gl_FragCoord; \n"
#endif
"#define PIXEL PIXEL \n"
@ -91,7 +91,7 @@ const char* lovrShaderFragmentPrefix = ""
"in vec2 texCoord; \n"
"in vec4 vertexColor; \n"
"out vec4 lovrCanvas[gl_MaxDrawBuffers]; \n"
"#ifdef GL_AMD_vertex_shader_viewport_index \n"
"#ifdef GL_ARB_fragment_layer_viewport \n"
"#define lovrViewportIndex gl_ViewportIndex \n"
"#else \n"
"uniform int lovrViewportIndex; \n"