From 5bdfceebc58a7fa5ffa2e154bcb5c69029d9b157 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 26 Oct 2016 18:35:47 -0700 Subject: [PATCH] BRingin back the stereo code path --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 34 ++++++- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 37 ++++++++ .../gpu-gl/src/gpu/gl/GLBackendInput.cpp | 8 ++ .../gpu-gl/src/gpu/gl/GLBackendPipeline.cpp | 6 ++ .../gpu-gl/src/gpu/gl/GLBackendTransform.cpp | 43 +++++++-- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 17 +++- libraries/gpu-gl/src/gpu/gl/GLShader.h | 2 + libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 18 +++- libraries/gpu/src/gpu/Transform.slh | 94 ++++++++++++++----- 9 files changed, 225 insertions(+), 34 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 2e1084e581..7f0a33aef4 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -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) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index f99d34393c..bc96cf8bb6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -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 { @@ -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; TransformCamera _camera; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp index 9256a42b80..618988a217 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp @@ -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(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 diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index ed0b9607e6..aa23b3a4dc 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -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; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp index 7f821078cd..eb53f5d45b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp @@ -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(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index f8d493c25b..9903d0e3b3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -54,9 +54,24 @@ static const std::array 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 VERSION_DEFINES { { - "" + "", + stereoVersion } }; GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index e75e96cf16..3c8a0f9b63 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -19,6 +19,8 @@ public: enum Version { Mono = 0, + Stereo, + NumVersions }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index bae6326e8f..d7dde8b7d6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -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(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 { diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 12a1cd10f1..ba006d5c73 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -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)@> { // _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@>