BRingin back the stereo code path

This commit is contained in:
samcake 2016-10-26 18:35:47 -07:00
parent 15ee56a50f
commit 5bdfceebc5
9 changed files with 225 additions and 34 deletions

View file

@ -306,11 +306,20 @@ void GLBackend::render(const Batch& batch) {
renderPassTransfer(batch);
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
if (_stereo._enable) {
glEnable(GL_CLIP_DISTANCE0);
}
#endif
{
PROFILE_RANGE(_stereo._enable ? "Render Stereo" : "Render");
renderPassDraw(batch);
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
if (_stereo._enable) {
glDisable(GL_CLIP_DISTANCE0);
}
#endif
// Restore the saved stereo state for the next batch
_stereo._enable = savedStereo;
}
@ -325,6 +334,23 @@ void GLBackend::syncCache() {
glEnable(GL_LINE_SMOOTH);
}
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
void GLBackend::setupStereoSide(int side) {
ivec4 vp = _transform._viewport;
vp.z /= 2;
glViewport(vp.x + side * vp.z, vp.y, vp.z, vp.w);
#ifdef GPU_STEREO_CAMERA_BUFFER
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
glVertexAttribI1i(14, side);
#endif
#else
_transform.bindCurrentCamera(side);
#endif
}
#else
void GLBackend::setupStereoSide(int side) {
ivec4 vp = _transform._viewport;
vp.z /= 2;
@ -332,6 +358,7 @@ void GLBackend::setupStereoSide(int side) {
_transform.bindCurrentCamera(side);
}
#endif
void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
resetStages();
@ -384,8 +411,11 @@ void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) {
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
// As long as we don;t use several versions of shaders we can avoid this more complex code path
// #define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc, isStereo());
#ifdef GPU_STEREO_CAMERA_BUFFER
#define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc, isStereo())
#else
#define GET_UNIFORM_LOCATION(shaderUniformLoc) shaderUniformLoc
#endif
void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {

View file

@ -29,6 +29,28 @@
#include "GLShared.h"
// Pick one from the 3: THis version is the most efficient as of now
#define GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
//#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER
//#define GPU_STEREO_TECHNIQUE_INSTANCED
// Let these be configured by the one define picked above
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
#define GPU_STEREO_DRAWCALL_DOUBLED
#endif
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER
#define GPU_STEREO_DRAWCALL_DOUBLED
#define GPU_STEREO_CAMERA_BUFFER
#endif
#ifdef GPU_STEREO_TECHNIQUE_INSTANCED
#define GPU_STEREO_DRAWCALL_INSTANCED
#define GPU_STEREO_CAMERA_BUFFER
#endif
namespace gpu { namespace gl {
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
@ -202,7 +224,10 @@ protected:
void renderPassTransfer(const Batch& batch);
void renderPassDraw(const Batch& batch);
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
void setupStereoSide(int side);
#endif
virtual void initInput() final;
virtual void killInput() final;
@ -260,7 +285,19 @@ protected:
};
struct TransformStageState {
#ifdef GPU_STEREO_CAMERA_BUFFER
struct Cameras {
TransformCamera _cams[2];
Cameras() {};
Cameras(const TransformCamera& cam) { memcpy(_cams, &cam, sizeof(TransformCamera)); };
Cameras(const TransformCamera& camL, const TransformCamera& camR) { memcpy(_cams, &camL, sizeof(TransformCamera)); memcpy(_cams + 1, &camR, sizeof(TransformCamera)); };
};
using CameraBufferElement = Cameras;
#else
using CameraBufferElement = TransformCamera;
#endif
using TransformCameras = std::vector<CameraBufferElement>;
TransformCamera _camera;

View file

@ -187,7 +187,11 @@ void GLBackend::updateInput() {
glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize);
glVertexAttribBinding(slot + locNum, attrib._channel);
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexBindingDivisor(attrib._channel, attrib._frequency * (isStereo() ? 2 : 1));
#else
glVertexBindingDivisor(attrib._channel, attrib._frequency);
#endif
}
(void)CHECK_GL_ERROR();
}
@ -306,7 +310,11 @@ void GLBackend::updateInput() {
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency);
#endif
}
// TODO: Support properly the IAttrib version

View file

@ -48,7 +48,13 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
// check the program cache
// pick the program version
// check the program cache
// pick the program version
#ifdef GPU_STEREO_CAMERA_BUFFER
GLuint glprogram = pipelineObject->_program->getProgram(isStereo());
#else
GLuint glprogram = pipelineObject->_program->getProgram();
#endif
if (_pipeline._program != glprogram) {
_pipeline._program = glprogram;

View file

@ -31,10 +31,25 @@ void GLBackend::do_setProjectionTransform(const Batch& batch, size_t paramOffset
void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset) {
memcpy(&_transform._viewport, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
{
ivec4& vp = _transform._viewport;
glViewport(vp.x, vp.y, vp.z, vp.w);
// Where we assign the GL viewport
if (_stereo._enable) {
vp.z /= 2;
if (_stereo._pass) {
vp.x += vp.z;
}
}
}
#else
if (!_inRenderTransferPass && !isStereo()) {
ivec4& vp = _transform._viewport;
glViewport(vp.x, vp.y, vp.z, vp.w);
}
#endif
// The Viewport is tagged invalid because the CameraTransformUBO is not up to date and will need update on next drawcall
_transform._invalidViewport = true;
@ -100,13 +115,21 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
if (_invalidView || _invalidProj || _invalidViewport) {
size_t offset = _cameraUboSize * _cameras.size();
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
if (stereo._enable) {
_cameras.push_back((_camera.getEyeCamera(0, stereo, _view)));
_cameras.push_back((_camera.getEyeCamera(1, stereo, _view)));
} else {
_cameras.push_back((_camera.recomputeDerived(_view)));
}
if (stereo._enable) {
#ifdef GPU_STEREO_CAMERA_BUFFER
_cameras.push_back(CameraBufferElement(_camera.getEyeCamera(0, stereo, _view), _camera.getEyeCamera(1, stereo, _view)));
#else
_cameras.push_back((_camera.getEyeCamera(0, stereo, _view)));
_cameras.push_back((_camera.getEyeCamera(1, stereo, _view)));
#endif
} else {
#ifdef GPU_STEREO_CAMERA_BUFFER
_cameras.push_back(CameraBufferElement(_camera.recomputeDerived(_view)));
#else
_cameras.push_back((_camera.recomputeDerived(_view)));
#endif
}
}
// Flags are clean
@ -122,9 +145,13 @@ void GLBackend::TransformStageState::update(size_t commandIndex, const StereoSta
}
if (offset != INVALID_OFFSET) {
#ifdef GPU_STEREO_CAMERA_BUFFER
bindCurrentCamera(0);
#else
if (!stereo._enable) {
bindCurrentCamera(0);
}
#endif
}
(void)CHECK_GL_ERROR();
}
@ -148,7 +175,11 @@ void GLBackend::updateTransform(const Batch& batch) {
glBindBuffer(GL_ARRAY_BUFFER, _transform._drawCallInfoBuffer);
glVertexAttribIPointer(gpu::Stream::DRAW_CALL_INFO, 2, GL_UNSIGNED_SHORT, 0,
_transform._drawCallInfoOffsets[batch._currentNamedCall]);
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, (isStereo() ? 2 : 1));
#else
glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, 1);
#endif
}
(void)CHECK_GL_ERROR();

View file

@ -54,9 +54,24 @@ static const std::array<std::string, NUM_SHADER_DOMAINS> DOMAIN_DEFINES { {
"#define GPU_GEOMETRY_SHADER",
} };
// Stereo specific defines
static const std::string stereoVersion {
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN"
#endif
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
#ifdef GPU_STEREO_CAMERA_BUFFER
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED"
#else
"#define GPU_TRANSFORM_IS_STEREO"
#endif
#endif
};
// Versions specific of the shader
static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
""
"",
stereoVersion
} };
GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) {

View file

@ -19,6 +19,8 @@ public:
enum Version {
Mono = 0,
Stereo,
NumVersions
};

View file

@ -25,10 +25,14 @@ void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) {
uint32 startVertex = batch._params[paramOffset + 0]._uint;
if (isStereo()) {
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glDrawArraysInstanced(mode, startVertex, numVertices, 2);
#else
setupStereoSide(0);
glDrawArrays(mode, startVertex, numVertices);
setupStereoSide(1);
glDrawArrays(mode, startVertex, numVertices);
#endif
_stats._DSNumTriangles += 2 * numVertices / 3;
_stats._DSNumDrawcalls += 2;
@ -55,11 +59,14 @@ void GL45Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
if (isStereo()) {
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, 2);
#else
setupStereoSide(0);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
setupStereoSide(1);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
#endif
_stats._DSNumTriangles += 2 * numIndices / 3;
_stats._DSNumDrawcalls += 2;
} else {
@ -83,10 +90,14 @@ void GL45Backend::do_drawInstanced(const Batch& batch, size_t paramOffset) {
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glDrawArraysInstanced(mode, startVertex, numVertices, trueNumInstances);
#else
setupStereoSide(0);
glDrawArraysInstanced(mode, startVertex, numVertices, numInstances);
setupStereoSide(1);
glDrawArraysInstanced(mode, startVertex, numVertices, numInstances);
#endif
_stats._DSNumTriangles += (trueNumInstances * numVertices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
@ -112,10 +123,15 @@ void GL45Backend::do_drawIndexedInstanced(const Batch& batch, size_t paramOffset
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, trueNumInstances, 0, startInstance);
#else
setupStereoSide(0);
glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
setupStereoSide(1);
glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
#endif
_stats._DSNumTriangles += (trueNumInstances * numIndices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
} else {

View file

@ -18,30 +18,60 @@ struct TransformCamera {
mat4 _projection;
mat4 _projectionInverse;
vec4 _viewport;
vec4 _stereoInfo;
};
layout(std140) uniform transformCameraBuffer {
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
TransformCamera _camera[2];
#else
TransformCamera _camera;
#endif
#else
TransformCamera _camera;
#endif
};
#ifdef VERTEX_SHADER
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
#ifdef GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED
layout(location=14) in int _inStereoSide;
#endif
flat out int _stereoSide;
#endif
#endif
#endif
#ifdef PIXEL_SHADER
#ifdef GPU_TRANSFORM_STEREO_CAMERA
flat in int _stereoSide;
#endif
#endif
TransformCamera getTransformCamera() {
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
#ifdef VERTEX_SHADER
#ifdef GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED
_stereoSide = _inStereoSide;
#endif
#ifdef GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
_stereoSide = gl_InstanceID % 2;
#endif
#endif
return _camera[_stereoSide];
#else
return _camera;
#endif
#else
return _camera;
#endif
}
vec3 getEyeWorldPos() {
return _camera._viewInverse[3].xyz;
}
bool cam_isStereo() {
return _camera._stereoInfo.x > 0.0;
}
float cam_getStereoSide() {
return _camera._stereoInfo.y;
}
<@endfunc@>
@ -92,6 +122,25 @@ TransformObject getTransformObject() {
<$viewport$> = <$cameraTransform$>._viewport;
<@endfunc@>
<@func transformStereoClipsSpace(cameraTransform, clipPos)@>
{
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN
vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1));
vec2 eyeOffsetScale = vec2(-0.5, +0.5);
uint eyeIndex = _stereoSide;
gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]);
float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w;
<$clipPos$>.x = newClipPosX;
#endif
#else
#endif
}
<@endfunc@>
<@func transformModelToEyeWorldAlignedPos(cameraTransform, objectTransform, modelPos, eyeWorldAlignedPos)@>
<!// Bring the model pos in the world aligned space centered on the eye axis !>
{ // _transformModelToEyeWorldAlignedPos
@ -108,6 +157,8 @@ TransformObject getTransformObject() {
<$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$>
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos;
<$transformStereoClipsSpace($cameraTransform$, $clipPos$)$>
}
<@endfunc@>
@ -117,6 +168,8 @@ TransformObject getTransformObject() {
<$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$>
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos;
<$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0);
<$transformStereoClipsSpace($cameraTransform$, $clipPos$)$>
}
<@endfunc@>
@ -134,15 +187,6 @@ TransformObject getTransformObject() {
}
<@endfunc@>
<@func transformModelToWorldDir(cameraTransform, objectTransform, modelDir, worldDir)@>
{ // transformModelToEyeDir
vec3 mr0 = <$objectTransform$>._modelInverse[0].xyz;
vec3 mr1 = <$objectTransform$>._modelInverse[1].xyz;
vec3 mr2 = <$objectTransform$>._modelInverse[2].xyz;
<$worldDir$> = vec3(dot(mr0, <$modelDir$>), dot(mr1, <$modelDir$>), dot(mr2, <$modelDir$>));
}
<@endfunc@>
<@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@>
{ // transformModelToEyeDir
@ -173,6 +217,8 @@ TransformObject getTransformObject() {
<@func transformEyeToClipPos(cameraTransform, eyePos, clipPos)@>
{ // transformEyeToClipPos
<$clipPos$> = <$cameraTransform$>._projection * vec4(<$eyePos$>.xyz, 1.0);
<$transformStereoClipsSpace($cameraTransform$, $clipPos$)$>
}
<@endfunc@>