Use single pass stereo rendering when supported;

This commit is contained in:
bjorn 2018-07-21 05:30:13 -07:00
parent 7d5f2ba75a
commit 2dc79a48a8
7 changed files with 147 additions and 100 deletions

View File

@ -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;
}

View File

@ -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 {

View File

@ -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() {

View File

@ -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);
}

View File

@ -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 });

View File

@ -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);
}

View File

@ -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"
"}";