mirror of https://github.com/bjornbytes/lovr.git
Happy little graphics refactors;
This commit is contained in:
parent
0ce6e046a6
commit
a5256aaa27
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue