Refactor layers/displays;

This commit is contained in:
bjorn 2018-03-04 21:51:53 -08:00
parent 221015677f
commit 2def650abd
4 changed files with 84 additions and 90 deletions

View File

@ -58,14 +58,14 @@ void lovrGraphicsReset() {
int w = lovrGraphicsGetWidth(); int w = lovrGraphicsGetWidth();
int h = lovrGraphicsGetHeight(); int h = lovrGraphicsGetHeight();
state.transform = 0; state.transform = 0;
state.display = 0; state.layer = 0;
state.defaultShader = SHADER_DEFAULT; state.defaultShader = SHADER_DEFAULT;
mat4_perspective(state.displays[state.display].projections, .01f, 100.f, 67 * M_PI / 180., (float) w / h / 2.); mat4_perspective(state.layers[state.layer].projections, .01f, 100.f, 67 * M_PI / 180., (float) w / h / 2.);
mat4_perspective(state.displays[state.display].projections + 16, .01f, 100.f, 67 * M_PI / 180., (float) w / h / 2.); mat4_perspective(state.layers[state.layer].projections + 16, .01f, 100.f, 67 * M_PI / 180., (float) w / h / 2.);
state.displays[state.display].viewport[0] = 0; state.layers[state.layer].viewport[0] = 0;
state.displays[state.display].viewport[1] = 0; state.layers[state.layer].viewport[1] = 0;
state.displays[state.display].viewport[2] = w; state.layers[state.layer].viewport[2] = w;
state.displays[state.display].viewport[3] = h; state.layers[state.layer].viewport[3] = h;
lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 1. }); lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 1. });
lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY); lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY);
lovrGraphicsSetColor((Color) { 1., 1., 1., 1. }); lovrGraphicsSetColor((Color) { 1., 1., 1., 1. });
@ -118,7 +118,7 @@ void lovrGraphicsPrepare(Material* material, float* pose) {
mat4 model = state.transforms[state.transform][MATRIX_MODEL]; mat4 model = state.transforms[state.transform][MATRIX_MODEL];
lovrShaderSetMatrix(shader, "lovrModel", model, 16); lovrShaderSetMatrix(shader, "lovrModel", model, 16);
float* views = state.displays[state.display].views; float* views = state.layers[state.layer].views;
float transforms[32]; float transforms[32];
mat4_multiply(mat4_set(transforms + 0, views + 0), model); mat4_multiply(mat4_set(transforms + 0, views + 0), model);
mat4_multiply(mat4_set(transforms + 16, views + 16), model); mat4_multiply(mat4_set(transforms + 16, views + 16), model);
@ -371,8 +371,9 @@ void lovrGraphicsSetCanvas(Canvas** canvas, int count) {
} }
if (count == 0) { if (count == 0) {
lovrGraphicsBindFramebuffer(state.displays[state.display].framebuffer); Layer layer = state.layers[state.layer];
int* viewport = state.displays[state.display].viewport; int* viewport = layer.viewport;
lovrGraphicsBindFramebuffer(layer.canvas ? layer.canvas->texture.id : 0);
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]); lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
} else { } else {
memcpy(state.canvas, canvas, count * sizeof(Canvas*)); memcpy(state.canvas, canvas, count * sizeof(Canvas*));
@ -1143,41 +1144,32 @@ void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback
} }
// Internal State // Internal State
void lovrGraphicsPushDisplay(int framebuffer, float* projections, float* views, int* viewport) { void lovrGraphicsPushLayer(Layer layer) {
if (++state.display >= MAX_DISPLAYS) { if (++state.layer >= MAX_LAYERS) {
lovrThrow("Display overflow"); lovrThrow("Layer overflow");
} }
state.displays[state.display].framebuffer = framebuffer; memcpy(&state.layers[state.layer], &layer, sizeof(Layer));
memcpy(state.displays[state.display].projections, projections, 32 * sizeof(float));
memcpy(state.displays[state.display].views, views, 32 * sizeof(float));
memcpy(state.displays[state.display].viewport, viewport, 4 * sizeof(int));
struct {
float projections[32];
float views[32];
} cameraBlock;
memcpy(cameraBlock.projections, projections, 32 * sizeof(float));
memcpy(cameraBlock.views, views, 32 * sizeof(float));
glBindBuffer(GL_UNIFORM_BUFFER, state.cameraUBO); glBindBuffer(GL_UNIFORM_BUFFER, state.cameraUBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * 16 * sizeof(float), &cameraBlock); glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * 16 * sizeof(float), &layer);
if (state.canvasCount == 0) { if (state.canvasCount == 0) {
lovrGraphicsBindFramebuffer(framebuffer); int* viewport = layer.viewport;
lovrGraphicsBindFramebuffer(layer.canvas ? layer.canvas->texture.id : 0);
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]); lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
} }
} }
void lovrGraphicsPopDisplay() { void lovrGraphicsPopLayer() {
if (--state.display < 0) { if (--state.layer < 0) {
lovrThrow("Display underflow"); lovrThrow("Layer underflow");
} }
if (state.canvasCount == 0) { if (state.canvasCount == 0) {
lovrGraphicsBindFramebuffer(state.displays[state.display].framebuffer); Layer layer = state.layers[state.layer];
int* viewport = state.displays[state.display].viewport; int* viewport = layer.viewport;
lovrGraphicsBindFramebuffer(layer.canvas ? layer.canvas->texture.id : 0);
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]); lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
} }
} }

View File

@ -11,7 +11,7 @@
#pragma once #pragma once
#define MAX_CANVASES 4 #define MAX_CANVASES 4
#define MAX_DISPLAYS 4 #define MAX_LAYERS 4
#define MAX_TRANSFORMS 60 #define MAX_TRANSFORMS 60
#define INTERNAL_TRANSFORMS 4 #define INTERNAL_TRANSFORMS 4
#define DEFAULT_SHADER_COUNT 4 #define DEFAULT_SHADER_COUNT 4
@ -76,11 +76,11 @@ typedef enum {
} MatrixType; } MatrixType;
typedef struct { typedef struct {
int framebuffer;
float projections[32]; float projections[32];
float views[32]; float views[32];
Canvas* canvas;
int viewport[4]; int viewport[4];
} Display; } Layer;
typedef struct { typedef struct {
bool initialized; bool initialized;
@ -127,8 +127,8 @@ typedef struct {
bool wireframe; bool wireframe;
Mesh* mesh; Mesh* mesh;
uint32_t cameraUBO; uint32_t cameraUBO;
Display displays[MAX_DISPLAYS]; Layer layers[MAX_LAYERS];
int display; int layer;
Texture* textures[MAX_TEXTURES]; Texture* textures[MAX_TEXTURES];
bool stencilEnabled; bool stencilEnabled;
bool stencilWriting; bool stencilWriting;
@ -210,8 +210,8 @@ void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback
// Internal State // Internal State
VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity); VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity);
void lovrGraphicsPushDisplay(int framebuffer, float* projections, float* views, int* viewport); void lovrGraphicsPushLayer(Layer layer);
void lovrGraphicsPopDisplay(); void lovrGraphicsPopLayer();
void lovrGraphicsSetViewport(int x, int y, int w, int h); void lovrGraphicsSetViewport(int x, int y, int w, int h);
void lovrGraphicsBindFramebuffer(int framebuffer); void lovrGraphicsBindFramebuffer(int framebuffer);
Texture* lovrGraphicsGetTexture(int slot); Texture* lovrGraphicsGetTexture(int slot);

View File

@ -313,22 +313,21 @@ static void fakeRenderTo(headsetRenderCallback callback, void* userdata) {
int width, height; int width, height;
fakeGetDisplayDimensions(&width, &height); fakeGetDisplayDimensions(&width, &height);
float projections[32]; Layer layer = { .canvas = NULL, .viewport = { 0, 0, width, height } };
mat4_perspective(projections, state.clipNear, state.clipFar, 67 * M_PI / 180., (float) width / height / 2.);
mat4_set(projections + 16, projections);
float views[32]; mat4_perspective(layer.projections, state.clipNear, state.clipFar, 67 * M_PI / 180., (float) width / height / 2.);
mat4_identity(views); mat4_set(layer.projections + 16, layer.projections);
mat4_translate(views, 0, state.offset, 0);
mat4_multiply(views, state.transform);
mat4_invert(views);
mat4_set(views + 16, views);
int viewport[4] = { 0, 0, width, height }; mat4_identity(layer.views);
lovrGraphicsPushDisplay(0, projections, views, viewport); mat4_translate(layer.views, 0, state.offset, 0);
mat4_multiply(layer.views, state.transform);
mat4_invert(layer.views);
mat4_set(layer.views + 16, layer.views);
lovrGraphicsPushLayer(layer);
lovrGraphicsClear(true, true, true, lovrGraphicsGetBackgroundColor(), 1., 0); lovrGraphicsClear(true, true, true, lovrGraphicsGetBackgroundColor(), 1., 0);
callback(EYE_LEFT, userdata); callback(EYE_LEFT, userdata);
lovrGraphicsPopDisplay(); lovrGraphicsPopLayer();
} }
static void fakeUpdate(float dt) { static void fakeUpdate(float dt) {

View File

@ -247,7 +247,7 @@ static void ensureCanvas() {
int msaa = 0; int msaa = 0;
glGetIntegerv(GL_SAMPLES, &msaa); glGetIntegerv(GL_SAMPLES, &msaa);
state.system->GetRecommendedRenderTargetSize(&state.renderWidth, &state.renderHeight); state.system->GetRecommendedRenderTargetSize(&state.renderWidth, &state.renderHeight);
state.canvas = lovrCanvasCreate(state.renderWidth, state.renderHeight, FORMAT_RGB, msaa, true, true); state.canvas = lovrCanvasCreate(state.renderWidth * 2, state.renderHeight, FORMAT_RGB, msaa, true, true);
} }
static bool openvrInit(float offset) { static bool openvrInit(float offset) {
@ -311,7 +311,7 @@ static bool openvrInit(float offset) {
state.vsyncToPhotons = state.system->GetFloatTrackedDeviceProperty(state.headsetIndex, ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float, NULL); state.vsyncToPhotons = state.system->GetFloatTrackedDeviceProperty(state.headsetIndex, ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float, NULL);
state.isRendering = false; state.isRendering = false;
state.isMirrored = true; state.isMirrored = true;
state.offset = offset; state.offset = lovrHeadsetGetOriginType() == ORIGIN_HEAD ? offset : 0.;
state.canvas = NULL; state.canvas = NULL;
state.clipNear = 0.1f; state.clipNear = 0.1f;
state.clipFar = 30.f; state.clipFar = 30.f;
@ -672,55 +672,58 @@ static ModelData* openvrControllerNewModelData(Controller* controller) {
static void openvrRenderTo(headsetRenderCallback callback, void* userdata) { static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
ensureCanvas(); ensureCanvas();
float head[16], transform[16], projection[16];
float (*matrix)[4];
state.isRendering = true; state.isRendering = true;
state.compositor->WaitGetPoses(state.renderPoses, 16, NULL, 0); state.compositor->WaitGetPoses(state.renderPoses, 16, NULL, 0);
// Head transform // Layer setup
Layer layer = { .canvas = state.canvas, .viewport = { 0, 0, state.renderWidth * 2, state.renderHeight } };
float eye[16];
float head[16];
float (*matrix)[4];
matrix = state.renderPoses[state.headsetIndex].mDeviceToAbsoluteTracking.m; matrix = state.renderPoses[state.headsetIndex].mDeviceToAbsoluteTracking.m;
mat4_invert(mat4_fromMat34(head, matrix)); mat4_fromMat34(head, matrix);
for (HeadsetEye eye = EYE_LEFT; eye <= EYE_RIGHT; eye++) { for (HeadsetEye i = EYE_LEFT; i <= EYE_RIGHT; i++) {
EVREye vrEye = (i == EYE_LEFT) ? EVREye_Eye_Left : EVREye_Eye_Right;
// Eye transform
EVREye vrEye = (eye == EYE_LEFT) ? EVREye_Eye_Left : EVREye_Eye_Right;
matrix = state.system->GetEyeToHeadTransform(vrEye).m;
mat4_invert(mat4_fromMat34(transform, matrix));
mat4_multiply(transform, head);
// Projection // Projection
matrix = state.system->GetProjectionMatrix(vrEye, state.clipNear, state.clipFar).m; matrix = state.system->GetProjectionMatrix(vrEye, state.clipNear, state.clipFar).m;
mat4 projection = layer.projections + 16 * i;
mat4_fromMat44(projection, matrix); mat4_fromMat44(projection, matrix);
// Render // View
//int viewport[4] = { 0, 0, state.canvas->texture.width, state.canvas->texture.height }; matrix = state.system->GetEyeToHeadTransform(vrEye).m;
//lovrGraphicsPushDisplay(state.canvas->framebuffer, projection, viewport); mat4_fromMat34(eye, matrix);
lovrGraphicsPush(); mat4 view = layer.views + 16 * i;
lovrGraphicsMatrixTransform(MATRIX_VIEW, transform); mat4_identity(view);
lovrGraphicsClear(true, true, false, lovrGraphicsGetBackgroundColor(), 1., 0); mat4_translate(view, 0, state.offset, 0);
callback(eye, userdata); mat4_multiply(view, head);
lovrGraphicsPop(); mat4_multiply(view, eye);
//lovrGraphicsPopDisplay(); mat4_invert(view);
// OpenVR changes the OpenGL texture binding, so we reset it after rendering
glActiveTexture(GL_TEXTURE0);
Texture* oldTexture = lovrGraphicsGetTexture(0);
// Submit
uintptr_t texture = (uintptr_t) state.canvas->texture.id;
ETextureType textureType = ETextureType_TextureType_OpenGL;
EColorSpace colorSpace = lovrGraphicsIsGammaCorrect() ? EColorSpace_ColorSpace_Linear : EColorSpace_ColorSpace_Gamma;
Texture_t eyeTexture = { (void*) texture, textureType, colorSpace };
EVRSubmitFlags flags = EVRSubmitFlags_Submit_Default;
state.compositor->Submit(vrEye, &eyeTexture, NULL, flags);
// Reset to the correct texture
glBindTexture(GL_TEXTURE_2D, oldTexture->id);
} }
// Render
lovrGraphicsPushLayer(layer);
lovrGraphicsClear(true, true, false, lovrGraphicsGetBackgroundColor(), 1., 0);
callback(EYE_LEFT, userdata);
lovrGraphicsPopLayer();
// OpenVR changes the OpenGL texture binding, so we reset it after rendering
glActiveTexture(GL_TEXTURE0);
Texture* oldTexture = lovrGraphicsGetTexture(0);
// Submit
uintptr_t texture = (uintptr_t) state.canvas->texture.id;
EColorSpace colorSpace = lovrGraphicsIsGammaCorrect() ? EColorSpace_ColorSpace_Linear : EColorSpace_ColorSpace_Gamma;
Texture_t eyeTexture = { (void*) texture, ETextureType_TextureType_OpenGL, colorSpace };
VRTextureBounds_t left = { 0, 0, state.renderWidth, state.renderHeight };
VRTextureBounds_t right = { state.renderWidth, 0, state.renderWidth, state.renderHeight };
state.compositor->Submit(EVREye_Eye_Left, &eyeTexture, &left, EVRSubmitFlags_Submit_Default);
state.compositor->Submit(EVREye_Eye_Right, &eyeTexture, &right, EVRSubmitFlags_Submit_Default);
// Reset to the correct texture
glBindTexture(GL_TEXTURE_2D, oldTexture->id);
state.isRendering = false; state.isRendering = false;
if (state.isMirrored) { if (state.isMirrored) {