mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
OpenXR - Integrate multiview into system
This commit is contained in:
parent
47349b2c0d
commit
ab6c91c203
@ -110,6 +110,21 @@ static std::string GetInfoLog(GLuint name, Getiv getiv, GetLog getLog) {
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
int GLQueueRunner::GetStereoBufferIndex(const char *uniformName) {
|
||||
if (strcmp(uniformName, "u_view") == 0) return 0;
|
||||
else if (strcmp(uniformName, "u_proj") == 0) return 1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
std::string GLQueueRunner::GetStereoBufferLayout(const char *uniformName) {
|
||||
if (strcmp(uniformName, "u_view") == 0) return "ViewMatrices";
|
||||
else if (strcmp(uniformName, "u_proj") == 0) return "ProjectionMatrix";
|
||||
|
||||
//undefined
|
||||
assert(false);
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps, bool skipGLCalls) {
|
||||
if (skipGLCalls) {
|
||||
// Some bookkeeping still needs to be done.
|
||||
@ -263,7 +278,25 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps, bool ski
|
||||
for (size_t j = 0; j < program->queries_.size(); j++) {
|
||||
auto &query = program->queries_[j];
|
||||
_dbg_assert_(query.name);
|
||||
#ifdef OPENXR
|
||||
int location = -1;
|
||||
int index = GetStereoBufferIndex(query.name);
|
||||
if (index) {
|
||||
std::string layout = GetStereoBufferLayout(query.name);
|
||||
glUniformBlockBinding(program->program, glGetUniformBlockIndex(program->program, layout.c_str()), index);
|
||||
|
||||
GLuint buffer = 0;
|
||||
glGenBuffers(1, &buffer);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, location);
|
||||
glBufferData(GL_UNIFORM_BUFFER,2 * 16 * sizeof(float),NULL, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
location = buffer;
|
||||
} else {
|
||||
location = glGetUniformLocation(program->program, query.name);
|
||||
}
|
||||
#else
|
||||
int location = glGetUniformLocation(program->program, query.name);
|
||||
#endif
|
||||
if (location < 0 && query.required) {
|
||||
WARN_LOG(G3D, "Required uniform query for '%s' failed", query.name);
|
||||
}
|
||||
@ -997,6 +1030,26 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::UNIFORMSTEREOMATRIX:
|
||||
{
|
||||
_dbg_assert_(curProgram);
|
||||
int loc = c.uniformMatrix4.loc ? *c.uniformMatrix4.loc : -1;
|
||||
if (c.uniformMatrix4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniformMatrix4.name);
|
||||
}
|
||||
if (loc >= 0) {
|
||||
int size = 2 * 16 * sizeof(float);
|
||||
GLuint layout = GetStereoBufferIndex(c.uniformMatrix4.name);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, layout, loc);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, loc);
|
||||
void *viewMatrices = glMapBufferRange(GL_UNIFORM_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
memcpy(viewMatrices, c.uniformMatrix4.m, size);
|
||||
glUnmapBuffer(GL_UNIFORM_BUFFER);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::UNIFORMMATRIX:
|
||||
{
|
||||
_dbg_assert_(curProgram);
|
||||
|
@ -47,6 +47,7 @@ enum class GLRRenderCommand : uint8_t {
|
||||
UNIFORM4UI,
|
||||
UNIFORM4F,
|
||||
UNIFORMMATRIX,
|
||||
UNIFORMSTEREOMATRIX,
|
||||
TEXTURESAMPLER,
|
||||
TEXTURELOD,
|
||||
VIEWPORT,
|
||||
@ -128,7 +129,7 @@ struct GLRRenderData {
|
||||
struct {
|
||||
const char *name; // if null, use loc
|
||||
const GLint *loc;
|
||||
float m[16];
|
||||
float m[32];
|
||||
} uniformMatrix4;
|
||||
struct {
|
||||
uint32_t clearColor;
|
||||
@ -356,6 +357,9 @@ public:
|
||||
caps_ = caps;
|
||||
}
|
||||
|
||||
int GetStereoBufferIndex(const char *uniformName);
|
||||
std::string GetStereoBufferLayout(const char *uniformName);
|
||||
|
||||
void RunInitSteps(const std::vector<GLRInitStep> &steps, bool skipGLCalls);
|
||||
|
||||
void RunSteps(const std::vector<GLRStep *> &steps, bool skipGLCalls);
|
||||
|
@ -742,6 +742,18 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformM4x4Stereo(const GLint *loc, const float *left, const float *right) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
#ifdef _DEBUG
|
||||
_dbg_assert_(curProgram_);
|
||||
#endif
|
||||
GLRRenderData data{ GLRRenderCommand::UNIFORMSTEREOMATRIX };
|
||||
data.uniformMatrix4.loc = loc;
|
||||
memcpy(&data.uniformMatrix4.m[0], left, sizeof(float) * 16);
|
||||
memcpy(&data.uniformMatrix4.m[16], right, sizeof(float) * 16);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformM4x4(const char *name, const float *udata) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
#ifdef _DEBUG
|
||||
|
@ -421,6 +421,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
} else {
|
||||
#ifdef OPENXR
|
||||
WRITE(p, "#define NUM_VIEWS 2\n");
|
||||
WRITE(p, "#extension GL_OVR_multiview2 : enable\n");
|
||||
#endif
|
||||
if (enableBones) {
|
||||
const char * const * boneWeightDecl = boneWeightAttrDecl;
|
||||
if (!strcmp(compat.attribute, "in")) {
|
||||
@ -469,7 +473,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
WRITE(p, "uniform mat4 u_proj_through;\n");
|
||||
*uniformMask |= DIRTY_PROJTHROUGHMATRIX;
|
||||
} else if (useHWTransform) {
|
||||
#ifdef OPENXR
|
||||
WRITE(p, "layout(shared) uniform ProjectionMatrix { uniform mat4 u_proj; };\n");
|
||||
#else
|
||||
WRITE(p, "uniform mat4 u_proj;\n");
|
||||
#endif
|
||||
*uniformMask |= DIRTY_PROJMATRIX;
|
||||
}
|
||||
|
||||
@ -477,7 +485,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
// When transforming by hardware, we need a great deal more uniforms...
|
||||
// TODO: Use 4x3 matrices where possible. Though probably doesn't matter much.
|
||||
WRITE(p, "uniform mat4 u_world;\n");
|
||||
#ifdef OPENXR
|
||||
WRITE(p, "layout(shared) uniform ViewMatrices { uniform mat4 u_view; };\n");
|
||||
#else
|
||||
WRITE(p, "uniform mat4 u_view;\n");
|
||||
#endif
|
||||
*uniformMask |= DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX;
|
||||
if (doTextureTransform) {
|
||||
WRITE(p, "uniform mediump mat4 u_texmtx;\n");
|
||||
@ -900,13 +912,18 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(skinnednormal, 0.0), u_world).xyz);\n");
|
||||
}
|
||||
|
||||
WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view).xyz, 1.0);\n");
|
||||
std::string matrixPostfix;
|
||||
#ifdef OPENXR
|
||||
matrixPostfix = "[gl_ViewID_OVR]";
|
||||
#endif
|
||||
|
||||
WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view%s).xyz, 1.0);\n", matrixPostfix.c_str());
|
||||
|
||||
// Final view and projection transforms.
|
||||
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n");
|
||||
WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj%s, viewPos));\n", matrixPostfix.c_str());
|
||||
} else {
|
||||
WRITE(p, " vec4 outPos = mul(u_proj, viewPos);\n");
|
||||
WRITE(p, " vec4 outPos = mul(u_proj%s, viewPos);\n", matrixPostfix.c_str());
|
||||
}
|
||||
|
||||
// TODO: Declare variables for dots for shade mapping if needed.
|
||||
|
@ -299,6 +299,56 @@ static inline void ScaleProjMatrix(Matrix4x4 &in, bool useBufferedRendering) {
|
||||
in.translateAndScale(trans, scale);
|
||||
}
|
||||
|
||||
static inline void FlipProjMatrix(Matrix4x4 &in, bool useBufferedRendering) {
|
||||
|
||||
const bool invertedY = useBufferedRendering ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0);
|
||||
if (invertedY) {
|
||||
in[1] = -in[1];
|
||||
in[5] = -in[5];
|
||||
in[9] = -in[9];
|
||||
in[13] = -in[13];
|
||||
}
|
||||
const bool invertedX = gstate_c.vpWidth < 0;
|
||||
if (invertedX) {
|
||||
in[0] = -in[0];
|
||||
in[4] = -in[4];
|
||||
in[8] = -in[8];
|
||||
in[12] = -in[12];
|
||||
}
|
||||
|
||||
// In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0,
|
||||
// causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it.
|
||||
if (gstate_c.Supports(GPU_USE_DEPTH_RANGE_HACK)) {
|
||||
float zScale = gstate.getViewportZScale() / 65535.0f;
|
||||
float zCenter = gstate.getViewportZCenter() / 65535.0f;
|
||||
|
||||
// if far depth range < 0
|
||||
if (zCenter + zScale < 0.0f) {
|
||||
// if perspective projection
|
||||
if (in[11] < 0.0f) {
|
||||
float depthMax = gstate.getDepthRangeMax() / 65535.0f;
|
||||
float depthMin = gstate.getDepthRangeMin() / 65535.0f;
|
||||
|
||||
float a = in[10];
|
||||
float b = in[14];
|
||||
|
||||
float n = b / (a - 1.0f);
|
||||
float f = b / (a + 1.0f);
|
||||
|
||||
f = (n * f) / (n + ((zCenter + zScale) * (n - f) / (depthMax - depthMin)));
|
||||
|
||||
a = (n + f) / (n - f);
|
||||
b = (2.0f * n * f) / (n - f);
|
||||
|
||||
if (!my_isnan(a) && !my_isnan(b)) {
|
||||
in[10] = a;
|
||||
in[14] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkedShader::use(const ShaderID &VSID) {
|
||||
render_->BindProgram(program);
|
||||
// Note that we no longer track attr masks here - we do it for the input layouts instead.
|
||||
@ -355,68 +405,32 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
|
||||
|
||||
// Update any dirty uniforms before we draw
|
||||
if (dirty & DIRTY_PROJMATRIX) {
|
||||
Matrix4x4 flippedMatrix;
|
||||
#ifdef OPENXR
|
||||
Matrix4x4 leftEyeMatrix, rightEyeMatrix;
|
||||
if (flatScreen || is2D) {
|
||||
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
|
||||
memcpy(&leftEyeMatrix, gstate.projMatrix, 16 * sizeof(float));
|
||||
memcpy(&rightEyeMatrix, gstate.projMatrix, 16 * sizeof(float));
|
||||
} else {
|
||||
VR_TweakProjection(gstate.projMatrix, flippedMatrix.m, VR_PROJECTION_MATRIX_LEFT_EYE);
|
||||
VR_TweakProjection(gstate.projMatrix, leftEyeMatrix.m, VR_PROJECTION_MATRIX_LEFT_EYE);
|
||||
VR_TweakProjection(gstate.projMatrix, rightEyeMatrix.m, VR_PROJECTION_MATRIX_RIGHT_EYE);
|
||||
VR_TweakMirroring(gstate.projMatrix);
|
||||
}
|
||||
|
||||
FlipProjMatrix(leftEyeMatrix, useBufferedRendering);
|
||||
FlipProjMatrix(rightEyeMatrix, useBufferedRendering);
|
||||
ScaleProjMatrix(leftEyeMatrix, useBufferedRendering);
|
||||
ScaleProjMatrix(rightEyeMatrix, useBufferedRendering);
|
||||
|
||||
render_->SetUniformM4x4Stereo(&u_proj, leftEyeMatrix.m, rightEyeMatrix.m);
|
||||
#else
|
||||
Matrix4x4 flippedMatrix;
|
||||
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
|
||||
#endif
|
||||
|
||||
const bool invertedY = useBufferedRendering ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0);
|
||||
if (invertedY) {
|
||||
flippedMatrix[1] = -flippedMatrix[1];
|
||||
flippedMatrix[5] = -flippedMatrix[5];
|
||||
flippedMatrix[9] = -flippedMatrix[9];
|
||||
flippedMatrix[13] = -flippedMatrix[13];
|
||||
}
|
||||
const bool invertedX = gstate_c.vpWidth < 0;
|
||||
if (invertedX) {
|
||||
flippedMatrix[0] = -flippedMatrix[0];
|
||||
flippedMatrix[4] = -flippedMatrix[4];
|
||||
flippedMatrix[8] = -flippedMatrix[8];
|
||||
flippedMatrix[12] = -flippedMatrix[12];
|
||||
}
|
||||
|
||||
// In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0,
|
||||
// causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it.
|
||||
if (gstate_c.Supports(GPU_USE_DEPTH_RANGE_HACK)) {
|
||||
float zScale = gstate.getViewportZScale() / 65535.0f;
|
||||
float zCenter = gstate.getViewportZCenter() / 65535.0f;
|
||||
|
||||
// if far depth range < 0
|
||||
if (zCenter + zScale < 0.0f) {
|
||||
// if perspective projection
|
||||
if (flippedMatrix[11] < 0.0f) {
|
||||
float depthMax = gstate.getDepthRangeMax() / 65535.0f;
|
||||
float depthMin = gstate.getDepthRangeMin() / 65535.0f;
|
||||
|
||||
float a = flippedMatrix[10];
|
||||
float b = flippedMatrix[14];
|
||||
|
||||
float n = b / (a - 1.0f);
|
||||
float f = b / (a + 1.0f);
|
||||
|
||||
f = (n * f) / (n + ((zCenter + zScale) * (n - f) / (depthMax - depthMin)));
|
||||
|
||||
a = (n + f) / (n - f);
|
||||
b = (2.0f * n * f) / (n - f);
|
||||
|
||||
if (!my_isnan(a) && !my_isnan(b)) {
|
||||
flippedMatrix[10] = a;
|
||||
flippedMatrix[14] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlipProjMatrix(flippedMatrix, useBufferedRendering);
|
||||
ScaleProjMatrix(flippedMatrix, useBufferedRendering);
|
||||
|
||||
render_->SetUniformM4x4(&u_proj, flippedMatrix.m);
|
||||
#endif
|
||||
render_->SetUniformF1(&u_rotation, useBufferedRendering ? 0 : (float)g_display_rotation);
|
||||
}
|
||||
if (dirty & DIRTY_PROJTHROUGHMATRIX)
|
||||
@ -523,14 +537,15 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
|
||||
}
|
||||
if (dirty & DIRTY_VIEWMATRIX) {
|
||||
#ifdef OPENXR
|
||||
if (flatScreen || is2D) {
|
||||
SetMatrix4x3(render_, &u_view, gstate.viewMatrix);
|
||||
} else {
|
||||
float m4x4[16];
|
||||
ConvertMatrix4x3To4x4Transposed(m4x4, gstate.viewMatrix);
|
||||
VR_TweakView(m4x4, gstate.projMatrix, VR_VIEW_MATRIX_LEFT_EYE);
|
||||
render_->SetUniformM4x4(&u_view, m4x4);
|
||||
float leftEyeView[16];
|
||||
float rightEyeView[16];
|
||||
ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix);
|
||||
ConvertMatrix4x3To4x4Transposed(rightEyeView, gstate.viewMatrix);
|
||||
if (!flatScreen && !is2D) {
|
||||
VR_TweakView(leftEyeView, gstate.projMatrix, VR_VIEW_MATRIX_LEFT_EYE);
|
||||
VR_TweakView(rightEyeView, gstate.projMatrix, VR_VIEW_MATRIX_RIGHT_EYE);
|
||||
}
|
||||
render_->SetUniformM4x4Stereo(&u_view, leftEyeView, rightEyeView);
|
||||
#else
|
||||
SetMatrix4x3(render_, &u_view, gstate.viewMatrix);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user