mirror of https://github.com/bjornbytes/lovr.git
Use single pass stereo rendering when supported;
This commit is contained in:
parent
7d5f2ba75a
commit
2dc79a48a8
|
@ -121,13 +121,14 @@ void lovrGraphicsSetCamera(Camera* camera, bool clear) {
|
|||
if (!camera) {
|
||||
int width, height;
|
||||
lovrGraphicsGetDimensions(&width, &height);
|
||||
state.camera.stereo = false;
|
||||
state.camera.canvas = NULL;
|
||||
state.camera.viewport[0] = 0;
|
||||
state.camera.viewport[1] = 0;
|
||||
state.camera.viewport[2] = width;
|
||||
state.camera.viewport[3] = height;
|
||||
mat4_identity(state.camera.viewMatrix);
|
||||
mat4_perspective(state.camera.projection, .01f, 100.f, 67 * M_PI / 180., (float) width / height);
|
||||
state.camera.viewport[0][0] = 0;
|
||||
state.camera.viewport[0][1] = 0;
|
||||
state.camera.viewport[0][2] = width;
|
||||
state.camera.viewport[0][3] = height;
|
||||
mat4_identity(state.camera.viewMatrix[0]);
|
||||
mat4_perspective(state.camera.projection[0], .01f, 100.f, 67 * M_PI / 180., (float) width / height);
|
||||
} else {
|
||||
state.camera = *camera;
|
||||
}
|
||||
|
|
|
@ -81,10 +81,11 @@ typedef struct {
|
|||
} GraphicsStats;
|
||||
|
||||
typedef struct {
|
||||
bool stereo;
|
||||
Canvas* canvas;
|
||||
uint32_t viewport[4];
|
||||
float viewMatrix[16];
|
||||
float projection[16];
|
||||
float viewport[2][4];
|
||||
float viewMatrix[2][16];
|
||||
float projection[2][16];
|
||||
} Camera;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -57,8 +57,9 @@ static struct {
|
|||
Texture* textures[MAX_TEXTURES];
|
||||
uint32_t vertexArray;
|
||||
uint32_t vertexBuffer;
|
||||
uint32_t viewport[4];
|
||||
float viewport[4];
|
||||
bool srgb;
|
||||
bool supportsSinglepass;
|
||||
GraphicsLimits limits;
|
||||
GraphicsStats stats;
|
||||
} state;
|
||||
|
@ -371,9 +372,9 @@ static void lovrGpuBindVertexBuffer(uint32_t vertexBuffer) {
|
|||
}
|
||||
}
|
||||
|
||||
static void lovrGpuSetViewport(uint32_t viewport[4]) {
|
||||
if (memcmp(state.viewport, viewport, 4 * sizeof(uint32_t))) {
|
||||
memcpy(state.viewport, viewport, 4 * sizeof(uint32_t));
|
||||
static void lovrGpuSetViewport(float viewport[4]) {
|
||||
if (memcmp(state.viewport, viewport, 4 * sizeof(float))) {
|
||||
memcpy(state.viewport, viewport, 4 * sizeof(float));
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
}
|
||||
}
|
||||
|
@ -400,6 +401,7 @@ void lovrGpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) {
|
|||
glEnable(GL_BLEND);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
state.srgb = srgb;
|
||||
state.supportsSinglepass = GLAD_GL_ARB_viewport_array && GLAD_GL_NV_viewport_array2 && GLAD_GL_NV_stereo_view_rendering;
|
||||
state.blendMode = -1;
|
||||
state.blendAlphaMode = -1;
|
||||
state.culling = false;
|
||||
|
@ -626,28 +628,35 @@ void lovrGpuDraw(DrawCommand* command) {
|
|||
}
|
||||
|
||||
// Transform
|
||||
lovrShaderSetMatrix(shader, "lovrProjection", command->camera.projection, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrView", command->camera.viewMatrix, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrModel", command->transform, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrViews", command->camera.viewMatrix, 32);
|
||||
lovrShaderSetMatrix(shader, "lovrProjections", command->camera.projection, 32);
|
||||
|
||||
float modelView[16];
|
||||
mat4_multiply(mat4_set(modelView, command->camera.viewMatrix), command->transform);
|
||||
lovrShaderSetMatrix(shader, "lovrTransform", modelView, 16);
|
||||
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);
|
||||
lovrShaderSetMatrix(shader, "lovrTransforms", modelView, 32);
|
||||
|
||||
if (lovrShaderHasUniform(shader, "lovrNormalMatrix")) {
|
||||
if (mat4_invert(modelView)) {
|
||||
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 normalMatrix[9] = {
|
||||
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]
|
||||
};
|
||||
|
||||
lovrShaderSetMatrix(shader, "lovrNormalMatrix", normalMatrix, 9);
|
||||
lovrShaderSetMatrix(shader, "lovrNormalMatrices", normalMatrices, 18);
|
||||
}
|
||||
|
||||
// Pose
|
||||
|
@ -718,47 +727,55 @@ void lovrGpuDraw(DrawCommand* command) {
|
|||
}
|
||||
}
|
||||
|
||||
// Viewport
|
||||
if (pipeline->canvasCount > 0) {
|
||||
int width = lovrTextureGetWidth((Texture*) pipeline->canvas[0], 0);
|
||||
int height = lovrTextureGetHeight((Texture*) pipeline->canvas[0], 0);
|
||||
lovrGpuSetViewport((uint32_t[4]) { 0, 0, width, height });
|
||||
} else {
|
||||
lovrGpuSetViewport(command->camera.viewport);
|
||||
}
|
||||
|
||||
// Bind uniforms
|
||||
lovrShaderBind(shader);
|
||||
|
||||
// Bind attributes
|
||||
lovrMeshBind(mesh, shader);
|
||||
|
||||
// Draw (TODEW)
|
||||
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);
|
||||
}
|
||||
}
|
||||
bool stereo = pipeline->canvasCount == 0 && command->camera.stereo == true;
|
||||
int drawCount = 1 + (stereo == true && !state.supportsSinglepass);
|
||||
|
||||
state.stats.drawCalls++;
|
||||
// Draw (TODEW)
|
||||
for (int i = 0; i < drawCount; i++) {
|
||||
if (pipeline->canvasCount > 0) {
|
||||
int width = lovrTextureGetWidth((Texture*) pipeline->canvas[0], 0);
|
||||
int height = lovrTextureGetHeight((Texture*) pipeline->canvas[0], 0);
|
||||
lovrGpuSetViewport((float[4]) { 0, 0, width, height });
|
||||
} else if (state.supportsSinglepass) {
|
||||
glViewportArrayv(0, 2, command->camera.viewport);
|
||||
} else {
|
||||
lovrGpuSetViewport(command->camera.viewport[i]);
|
||||
}
|
||||
|
||||
// Bind uniforms
|
||||
int eye = (stereo && state.supportsSinglepass) ? -1 : i;
|
||||
lovrShaderSetInt(shader, "lovrEye", &eye, 1);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrGpuPresent() {
|
||||
|
|
|
@ -277,7 +277,6 @@ static ModelData* fakeControllerNewModelData(Controller* controller) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
static void fakeRenderTo(void (*callback)(void*), void* userdata) {
|
||||
if (!state.window || !state.mirrored) {
|
||||
return;
|
||||
|
@ -285,20 +284,24 @@ static void fakeRenderTo(void (*callback)(void*), void* userdata) {
|
|||
|
||||
int width, height;
|
||||
fakeGetDisplayDimensions(&width, &height);
|
||||
Camera camera = { .viewport = { 0, 0, width, height } };
|
||||
|
||||
mat4_perspective(camera.projection, state.clipNear, state.clipFar, 67 * M_PI / 180., (float) width / height);
|
||||
mat4_identity(camera.viewMatrix);
|
||||
mat4_translate(camera.viewMatrix, 0, state.offset, 0);
|
||||
mat4_multiply(camera.viewMatrix, state.transform);
|
||||
mat4_invert(camera.viewMatrix);
|
||||
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
camera.viewport[0] = width * eye;
|
||||
lovrGraphicsSetCamera(&camera, eye == 0);
|
||||
callback(userdata);
|
||||
}
|
||||
Camera camera = {
|
||||
.stereo = true,
|
||||
.canvas = NULL,
|
||||
.viewport = {
|
||||
{ 0, 0, width, height },
|
||||
{ width, 0, width, height }
|
||||
}
|
||||
};
|
||||
|
||||
mat4_perspective(camera.projection[0], state.clipNear, state.clipFar, 67 * M_PI / 180., (float) width / height);
|
||||
mat4_identity(camera.viewMatrix[0]);
|
||||
mat4_translate(camera.viewMatrix[0], 0, state.offset, 0);
|
||||
mat4_multiply(camera.viewMatrix[0], state.transform);
|
||||
mat4_invert(camera.viewMatrix[0]);
|
||||
mat4_set(camera.projection[1], camera.projection[0]);
|
||||
mat4_set(camera.viewMatrix[1], camera.viewMatrix[0]);
|
||||
lovrGraphicsSetCamera(&camera, true);
|
||||
callback(userdata);
|
||||
lovrGraphicsSetCamera(NULL, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -669,26 +669,30 @@ static void openvrRenderTo(void (*callback)(void*), void* userdata) {
|
|||
mat4_fromMat34(head, state.renderPoses[state.headsetIndex].mDeviceToAbsoluteTracking.m);
|
||||
|
||||
Camera camera = {
|
||||
.stereo = true,
|
||||
.canvas = state.canvas,
|
||||
.viewport = { 0, 0, state.renderWidth, state.renderHeight }
|
||||
.viewport = {
|
||||
{ 0, 0, state.renderWidth, state.renderHeight },
|
||||
{ state.renderWidth, 0, state.renderWidth, state.renderHeight }
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
EVREye vrEye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right;
|
||||
mat4_fromMat44(camera.projection, state.system->GetProjectionMatrix(vrEye, state.clipNear, state.clipFar).m);
|
||||
mat4_identity(camera.viewMatrix);
|
||||
mat4_translate(camera.viewMatrix, 0, state.offset, 0);
|
||||
mat4_multiply(camera.viewMatrix, head);
|
||||
mat4_multiply(camera.viewMatrix, mat4_fromMat34(eye, state.system->GetEyeToHeadTransform(vrEye).m));
|
||||
mat4_invert(camera.viewMatrix);
|
||||
|
||||
camera.viewport[0] = state.renderWidth * i;
|
||||
lovrGraphicsSetCamera(&camera, i == 0);
|
||||
callback(userdata);
|
||||
lovrGraphicsSetCanvas(NULL, 0);
|
||||
mat4_fromMat44(camera.projection[i], state.system->GetProjectionMatrix(vrEye, state.clipNear, state.clipFar).m);
|
||||
mat4_identity(camera.viewMatrix[i]);
|
||||
mat4_translate(camera.viewMatrix[i], 0, state.offset, 0);
|
||||
mat4_multiply(camera.viewMatrix[i], head);
|
||||
mat4_multiply(camera.viewMatrix[i], mat4_fromMat34(eye, state.system->GetEyeToHeadTransform(vrEye).m));
|
||||
mat4_invert(camera.viewMatrix[i]);
|
||||
}
|
||||
|
||||
lovrGraphicsSetCamera(&camera, true);
|
||||
callback(userdata);
|
||||
lovrGraphicsSetCamera(NULL, false);
|
||||
lovrGraphicsSetCanvas(NULL, 0);
|
||||
lovrCanvasResolve(state.canvas);
|
||||
state.isRendering = false;
|
||||
|
||||
// Submit
|
||||
uintptr_t texture = (uintptr_t) lovrTextureGetId((Texture*) state.canvas);
|
||||
|
@ -700,9 +704,6 @@ static void openvrRenderTo(void (*callback)(void*), void* userdata) {
|
|||
state.compositor->Submit(EVREye_Eye_Right, &eyeTexture, &right, EVRSubmitFlags_Submit_Default);
|
||||
lovrGpuDirtyTexture(0);
|
||||
|
||||
lovrGraphicsSetCamera(NULL, false);
|
||||
state.isRendering = false;
|
||||
|
||||
if (state.isMirrored) {
|
||||
lovrGraphicsPushPipeline();
|
||||
lovrGraphicsSetColor((Color) { 1, 1, 1, 1 });
|
||||
|
|
|
@ -89,14 +89,22 @@ static void onMountChanged(bool mounted) {
|
|||
static void onFrame(float* leftView, float* rightView, float* leftProjection, float* rightProjection, void* userdata) {
|
||||
int width, height;
|
||||
webvrGetDisplayDimensions(&width, &height);
|
||||
Camera camera = { .viewport = { 0, 0, width, height } };
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
camera.viewport[0] = width * eye;
|
||||
memcpy(camera.projection, eye == 0 ? leftProjection : rightProjection);
|
||||
memcpy(camera.viewMatrix, eye == 0 ? leftView : rightView);
|
||||
lovrGraphicsSetCamera(&camera, eye == 0);
|
||||
state.renderCallback(userdata);
|
||||
}
|
||||
|
||||
Camera camera = {
|
||||
.stereo = true,
|
||||
.canvas = NULL,
|
||||
.viewport = {
|
||||
{ 0, 0, width, height },
|
||||
{ width, 0, width, height }
|
||||
}
|
||||
};
|
||||
|
||||
memcpy(camera.projection[0], leftProjection);
|
||||
memcpy(camera.projection[1], rightProjection);
|
||||
memcpy(camera.viewMatrix[0], leftView);
|
||||
memcpy(camera.viewMatrix[1], rightView);
|
||||
lovrGraphicsSetCamera(&camera, true);
|
||||
state.renderCallback(userdata);
|
||||
lovrGraphicsSetCamera(NULL, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,15 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"precision mediump float; \n"
|
||||
#else
|
||||
"#version 150 \n"
|
||||
"#extension GL_NV_viewport_array2 : enable \n"
|
||||
"#extension GL_NV_stereo_view_rendering : enable \n"
|
||||
#endif
|
||||
"#define VERTEX VERTEX \n"
|
||||
"#define MAX_BONES 48 \n"
|
||||
"#define lovrView lovrViews[lovrEye] \n"
|
||||
"#define lovrProjection lovrProjections[lovrEye] \n"
|
||||
"#define lovrTransform lovrTransforms[lovrEye] \n"
|
||||
"#define lovrNormalMatrix lovrNormalMatrices[lovrEye] \n"
|
||||
"in vec3 lovrPosition; \n"
|
||||
"in vec3 lovrNormal; \n"
|
||||
"in vec2 lovrTexCoord; \n"
|
||||
|
@ -38,11 +44,12 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"in vec4 lovrBoneWeights; \n"
|
||||
"out vec2 texCoord; \n"
|
||||
"out vec4 vertexColor; \n"
|
||||
"uniform int lovrEye; \n"
|
||||
"uniform mat4 lovrModel; \n"
|
||||
"uniform mat4 lovrView; \n"
|
||||
"uniform mat4 lovrProjection; \n"
|
||||
"uniform mat4 lovrTransform; \n"
|
||||
"uniform mat3 lovrNormalMatrix; \n"
|
||||
"uniform mat4 lovrViews[2]; \n"
|
||||
"uniform mat4 lovrProjections[2]; \n"
|
||||
"uniform mat4 lovrTransforms[2]; \n"
|
||||
"uniform mat3 lovrNormalMatrices[2]; \n"
|
||||
"uniform mat3 lovrMaterialTransform; \n"
|
||||
"uniform float lovrPointSize; \n"
|
||||
"uniform mat4 lovrPose[MAX_BONES]; \n"
|
||||
|
@ -85,6 +92,15 @@ const char* lovrShaderVertexSuffix = ""
|
|||
" lovrPose[lovrBones[2]] * lovrBoneWeights[2] + \n"
|
||||
" lovrPose[lovrBones[3]] * lovrBoneWeights[3]; \n"
|
||||
" gl_PointSize = lovrPointSize; \n"
|
||||
"#if defined(GL_NV_viewport_array2) && defined(GL_NV_stereo_view_rendering) \n"
|
||||
" if (lovrEye < 0) { \n"
|
||||
" gl_Position = position(lovrProjections[0], lovrTransforms[0], pose * vec4(lovrPosition, 1.0)); \n"
|
||||
" gl_SecondaryPositionNV = position(lovrProjections[1], lovrTransforms[1], pose * vec4(lovrPosition, 1.0)); \n"
|
||||
" gl_ViewportMask[0] = (1 << 0); \n"
|
||||
" gl_SecondaryViewportMaskNV[0] = (1 << 1); \n"
|
||||
" return; \n"
|
||||
" }\n"
|
||||
"#endif \n"
|
||||
" gl_Position = position(lovrProjection, lovrTransform, pose * vec4(lovrPosition, 1.0)); \n"
|
||||
"}";
|
||||
|
||||
|
|
Loading…
Reference in New Issue