From f908a1a65874ce7e2e5959b1d04cf871c3bc49af Mon Sep 17 00:00:00 2001 From: "adam.b" Date: Thu, 4 Aug 2016 13:57:15 +0100 Subject: [PATCH] rendering to the texture as main framebuffer when vr mode on ( on by default now ) Change-Id: I00566fb271d020ae7826d842e0fc307c25fd50b6 --- dali/internal/render/common/render-manager.cpp | 301 ++++++++++++++++++++++++- dali/internal/render/common/render-manager.h | 3 + dali/internal/render/gl-resources/context.h | 68 ++++++ dali/public-api/actors/actor.h | 2 +- 4 files changed, 370 insertions(+), 4 deletions(-) diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index 497b0e5..cc8dc50 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -41,7 +41,7 @@ #include #include #include - +#include namespace Dali { @@ -74,6 +74,43 @@ typedef RenderTrackerContainer::Iterator RenderTrackerIter; typedef RenderTrackerContainer::ConstIterator RenderTrackerConstIter; /** + * Structure to contain VR rendering data + */ +struct VrImpl +{ + VrImpl() + : mainFrameBufferAttachments( ), + mainFrameBuffer( 0 ), + mainVRProgramGL( 0 ), + vrModeEnabled( true ) + { + } + + enum VrUniform + { + VR_UNIFORM_TEXTURE = 0, + VR_UNIFORM_MVP = 1, + VR_UNIFORM_MAX + }; + + struct Vertex + { + float aPosition[3]; + float aTexCoord[2]; + }; + + // in case of VR rendering to texture first then applying barrel distortion + unsigned int mainFrameBufferAttachments[2]; + unsigned int mainFrameBuffer; + unsigned int mainVRProgramGL; + unsigned int vertexBuffer; // contains 'cage' data, vec3, vec2 + Matrix MVP; + int uniformLocations[VR_UNIFORM_MAX]; + + bool vrModeEnabled; +}; + +/** * Structure to contain internal data */ struct RenderManager::Impl @@ -172,6 +209,8 @@ struct RenderManager::Impl ProgramController programController; ///< Owner of the GL programs SceneGraph::GeometryBatcher& geometryBatcher; ///< Instance of geometry batcher + + VrImpl vrImpl; }; RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, @@ -512,6 +551,8 @@ ProgramCache* RenderManager::GetProgramCache() return &(mImpl->programController); } +#define GL(x) { x; int err = mImpl->context.GetError(); if(err) { DALI_LOG_ERROR( "GL_ERROR: '%s', %x\n", #x, (unsigned)err);fflush(stderr);fflush(stdout);} else { DALI_LOG_ERROR("GL Call: %s\n", #x); fflush(stdout);} } + bool RenderManager::Render( Integration::RenderStatus& status ) { DALI_PRINT_RENDER_START( mImpl->renderBufferIndex ); @@ -525,12 +566,26 @@ bool RenderManager::Render( Integration::RenderStatus& status ) // Process messages queued during previous update mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex ); + VrImpl& vr = mImpl->vrImpl; + // No need to make any gl calls if we've done 1st glClear & don't have any renderers to render during startup. if( !mImpl->firstRenderCompleted || mImpl->renderersAdded ) { + // check if vr, if true create new main framebuffer, it's not the + // right place to do it, but will do for now + if( mImpl->vrImpl.vrModeEnabled ) + { + if( !vr.mainFrameBuffer ) + { + SetupVRMode(); + } + } + // switch rendering to adaptor provided (default) buffer - mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 ); + GL( mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, vr.vrModeEnabled ? vr.mainFrameBuffer : 0 ) ); + int err = mImpl->context.GetError(); + err = err; mImpl->context.Viewport( mImpl->defaultSurfaceRect.x, mImpl->defaultSurfaceRect.y, mImpl->defaultSurfaceRect.width, @@ -574,6 +629,13 @@ bool RenderManager::Render( Integration::RenderStatus& status ) mImpl->firstRenderCompleted = true; } + + if( vr.vrModeEnabled ) + { + RenderVR(); + } + + } //Notify RenderGeometries that rendering has finished @@ -653,8 +715,10 @@ void RenderManager::DoRender( RenderInstruction& instruction, Shader& defaultSha } else // !(instruction.mOffscreenTexture) { + + // switch rendering to adaptor provided (default) buffer - mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 ); + mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, mImpl->vrImpl.vrModeEnabled ? mImpl->vrImpl.mainFrameBuffer : 0 ); // Check whether a viewport is specified, otherwise the full surface size is used if ( instruction.mIsViewportSet ) @@ -709,6 +773,237 @@ void RenderManager::DoRender( RenderInstruction& instruction, Shader& defaultSha } } + + + + + + + + + + + + + + + + +namespace { +inline void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis) +{ + if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) ) + { + DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension.\n" ); + DALI_ASSERT_DEBUG( "Cannot create orthographic projection matrix with a zero dimension." ); + return; + } + + float deltaX = right - left; + float deltaY = invertYAxis ? bottom - top : top - bottom; + float deltaZ = far - near; + + float *m = result.AsFloat(); + m[0] = -2.0f / deltaX; + m[1] = 0.0f; + m[2] = 0.0f; + m[3] = 0.0f; + + m[4] = 0.0f; + m[5] = -2.0f / deltaY; + m[6] = 0.0f; + m[7] = 0.0f; + + m[8] = 0.0f; + m[9] = 0.0f; + m[10] = 2.0f / deltaZ; + m[11] = 0.0f; + m[12] = -(right + left) / deltaX; + m[13] = -(top + bottom) / deltaY; + m[14] = -(near + far) / deltaZ; + m[15] = 1.0f; +} + +void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up) +{ + Vector3 vZ = target - eye; + vZ.Normalize(); + + Vector3 vX = up.Cross(vZ); + vX.Normalize(); + + Vector3 vY = vZ.Cross(vX); + vY.Normalize(); + + result.SetInverseTransformComponents(vX, vY, vZ, eye); +} + +} + +void RenderManager::SetupVRMode() +{ + VrImpl& vr = mImpl->vrImpl; + Context& ctx =mImpl->context; + Integration::GlAbstraction& gl = ctx.GetAbstraction(); + + GL( ctx.GenFramebuffers( 1, &vr.mainFrameBuffer ) ); + GL( ctx.GenTextures( 1, &vr.mainFrameBufferAttachments[0] ) ); + GL( ctx.BindFramebuffer( GL_FRAMEBUFFER, vr.mainFrameBuffer ) ); + + // color attachment + GL( ctx.Bind2dTexture( vr.mainFrameBufferAttachments[0] ) ); + GL( ctx.TexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, + mImpl->defaultSurfaceRect.width, + mImpl->defaultSurfaceRect.height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 ) ); + GL( ctx.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ); + GL( ctx.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) ); + GL( ctx.FramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, vr.mainFrameBufferAttachments[0], 0 ) ); + + // depth/stencil attachment + // if gles3 render depth to the texture +#if 0 + GL( mImpl->context.GenTextures( 1, &mImpl->mainFrameBufferAttachments[1] ) ); + GL( mImpl->context.Bind2dTexture( mImpl->mainFrameBufferAttachments[1] ) ); + GL( mImpl->context.TexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, + mImpl->defaultSurfaceRect.width, + mImpl->defaultSurfaceRect.height, + 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0 ) ); + GL( mImpl->context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ); + GL( mImpl->context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) ); + GL( mImpl->context.FramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mImpl->mainFrameBufferAttachments[1], 0 ) ); +#else + GL( ctx.GenRenderbuffers( 1, &vr.mainFrameBufferAttachments[1] ) ); + GL( ctx.BindRenderbuffer( GL_RENDERBUFFER, vr.mainFrameBufferAttachments[1] ) ); + GL( ctx.RenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + mImpl->defaultSurfaceRect.width, + mImpl->defaultSurfaceRect.height ) ); + GL( ctx.FramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, vr.mainFrameBufferAttachments[1] ) ); +#endif + + GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 }; + gl.DrawBuffers( 1, drawBuffers ); + + // prepare shader and buffer to render barrel distortion in one go ( with time warp it may need to do with 2 goes ) + const char* shaderSource[2] = + { + // vertex shader + "attribute vec3 aPosition;\n" + "attribute vec2 aTexCoord;\n" + "uniform highp mat4 mvp;\n" + "varying mediump vec2 vTexCoord;\n" + "void main()\n" + "{" + " gl_Position = mvp * vec4( aPosition, 1.0 );\n" + " vTexCoord = aTexCoord;\n" + "}\n\0", + + // fragment shader + "uniform sampler2D texSampler;\n" + "\n" + "varying mediump vec2 vTexCoord;\n" + "void main()\n" + "{ \n" + " mediump vec4 mulcol = vec4( 1.0, 0.0, 0.0, 1.0 );\n" + " if(vTexCoord.y < 0.5 ) { mulcol = vec4(0.0, 1.0, 0.0, 1.0); }\n" + " gl_FragColor = texture2D( texSampler, vTexCoord ) * mulcol;\n" + "}\n\0", + }; + + // using GL explicitly in order to create shaders and program + GLuint shaders[2]; + GLuint program; + for( int i = 0; i < 2; ++i ) + { + GL( shaders[ i ] = ctx.CreateShader( i ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER ) ); + GL( ctx.ShaderSource( shaders[i], 1, &shaderSource[i], NULL ) ); + GL( ctx.CompileShader( shaders[i] ) ); + } + + GL( program = mImpl->context.CreateProgram() ); + GL( mImpl->context.AttachShader( program, shaders[0] ) ); + GL( mImpl->context.AttachShader( program, shaders[1] ) ); + GL( mImpl->context.LinkProgram( program) ); + + vr.mainVRProgramGL = program; + const float w = 1.0f;//(float)mImpl->defaultSurfaceRect.width; + const float h = 1.0f;//(float)mImpl->defaultSurfaceRect.height; + + // create vertex buffer + VrImpl::Vertex vertices[] = + { + { { -w, -h, 0.0f }, { 0.0f, 0.0f } }, + { { w, -h, 0.0f }, { 1.0f, 0.0f } }, + { { w, h, 0.0f }, { 1.0f, 1.0f } }, + { { -w, -h, 0.0f }, { 0.0f, 0.0f } }, + { { w, h, 0.0f }, { 1.0f, 1.0f } }, + { { -w, h, 0.0f }, { 0.0f, 1.0f } }, + }; + + GL( ctx.GenBuffers( 1, &vr.vertexBuffer ) ); + GL( ctx.BindArrayBuffer( vr.vertexBuffer ) ); + GL( ctx.BufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW ) ); + + GL( vr.uniformLocations[ VrImpl::VR_UNIFORM_MVP ] = ctx.GetUniformLocation( program, "mvp" ) ); + GL( vr.uniformLocations[ VrImpl::VR_UNIFORM_TEXTURE ] = ctx.GetUniformLocation( program, "texSampler" ) ); + + + // mvp + Matrix proj, view; + Orthographic( proj, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, false ); + //LookAt( view, Vector3( 0.0f, 0.0f, 0.0f ), Vector3( 0.0f, 0.0f, 1.0f ), Vector3( 0.0f, 1.0f, 0.0f ) ); + //mat.SetTranslation( Vector3(0.0f, 0.0f, 1.0f ) ); + Matrix::Multiply( vr.MVP, view, proj ); + vr.MVP = proj; + + //vr.MVP.Multiply( vr.MVP, vp, mat ); + return; +} + + +void RenderManager::RenderVR() +{ + static float f = 1.0f; + VrImpl& vr = mImpl->vrImpl; + Context& ctx = mImpl->context; + Integration::GlAbstraction& gl = ctx.GetAbstraction(); + GL( ctx.BindFramebuffer( GL_FRAMEBUFFER, 0 ) ); + gl.Viewport( 0, 0, mImpl->defaultSurfaceRect.width, mImpl->defaultSurfaceRect.height ); + //gl.Disable( GL_SCISSOR_TEST ); + //gl.Disable( GL_DEPTH_TEST ); + //gl.ClearColor( 0.0f, f, 0.0f, 1.0f ); + f -= 0.2f; + if( f < 0 ) + f = 1.0f; + //GL( gl.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ); + // store old program + Program* program = GetProgramCache()->GetCurrentProgram(); + GetProgramCache()->SetCurrentProgram( NULL ); + GL( ctx.UseProgram( vr.mainVRProgramGL ) ); + + // attributes + GL( ctx.BindArrayBuffer( vr.vertexBuffer ) ); + GL( ctx.VertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof(VrImpl::Vertex), 0 ) ); + GL( ctx.VertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, sizeof(VrImpl::Vertex), (const void*)(sizeof(float)*3)) ); + GL( gl.EnableVertexAttribArray( 0 ) ); + GL( gl.EnableVertexAttribArray( 1 ) ); + // uniforms + // texture + GL( ctx.ActiveTexture( TEXTURE_UNIT_IMAGE ) ); + GL( ctx.Bind2dTexture( vr.mainFrameBufferAttachments[0] ) ); + GL( gl.Uniform1i( vr.uniformLocations[ VrImpl::VR_UNIFORM_TEXTURE], 0 ) ); + + // matrix + GL( gl.UniformMatrix4fv( vr.uniformLocations[ VrImpl::VR_UNIFORM_MVP ], + 1, GL_FALSE, vr.MVP.AsFloat() ) ); + + GL( gl.DrawArrays( GL_TRIANGLES, 0, 6 ) ); + + if( program ) + program->Use(); + +} + } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/render/common/render-manager.h b/dali/internal/render/common/render-manager.h index 40cc7c1..f489876 100644 --- a/dali/internal/render/common/render-manager.h +++ b/dali/internal/render/common/render-manager.h @@ -359,6 +359,9 @@ private: */ void DoRender( RenderInstruction& instruction, Shader& defaultShader ); + void SetupVRMode(); + void RenderVR(); + private: /** diff --git a/dali/internal/render/gl-resources/context.h b/dali/internal/render/gl-resources/context.h index c2f11ac..3798b97 100644 --- a/dali/internal/render/gl-resources/context.h +++ b/dali/internal/render/gl-resources/context.h @@ -413,12 +413,14 @@ public: */ void Clear(GLbitfield mask, ClearMode mode ) { + DALI_LOG_ERROR("CLEARRRR\n"); bool forceClear = (mode == FORCE_CLEAR ); mask = mFrameBufferStateCache.GetClearMask( mask, forceClear , mScissorTestEnabled ); if( mask > 0 ) { LOG_GL("Clear %d\n", mask); + DALI_LOG_ERROR(" >>> CLEARRRR for sure\n"); CHECK_GL( mGlAbstraction, mGlAbstraction.Clear( mask ) ); } } @@ -1640,6 +1642,72 @@ public: } } + GLuint CreateShader( GLenum shaderType ) + { + GLuint value = 0; + CHECK_GL( mGlAbstraction, value = mGlAbstraction.CreateShader( shaderType ) ); + return value; + } + + GLuint CreateProgram() + { + GLuint value = 0; + CHECK_GL( mGlAbstraction, value = mGlAbstraction.CreateProgram() ); + return value; + } + + void ShaderSource( GLuint shader, GLsizei count, const GLchar **string, const GLint *length ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.ShaderSource( shader, count, string, length ) ); + } + + bool CompileShader( GLuint shader ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.CompileShader( shader ) ); + GLint status( 0 ); + mGlAbstraction.GetShaderiv( shader, GL_COMPILE_STATUS, &status ); + if( status != GL_TRUE ) + { + char buf[1024]; + mGlAbstraction.GetShaderInfoLog( shader, 1024, 0, buf ); + DALI_LOG_ERROR("CompileError: %s\n", buf); + } + return ( status == GL_TRUE ); + } + + void AttachShader( GLuint program, GLuint shader ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.AttachShader( program, shader ) ); + } + + void DetachShader( GLuint program, GLuint shader ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.DetachShader( program, shader ) ); + } + + void DeleteShader( GLuint shader ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteShader( shader ) ); + } + + bool LinkProgram( GLuint program ) + { + CHECK_GL( mGlAbstraction, mGlAbstraction.LinkProgram( program ) ); + GLint status( 0 ); + mGlAbstraction.GetProgramiv( program, GL_LINK_STATUS, &status ); + return ( status == GL_TRUE ); + } + + void UseProgram( GLuint program ) + { + mGlAbstraction.UseProgram( program ); + } + + GLint GetUniformLocation( GLuint program, const GLchar* name ) + { + return mGlAbstraction.GetUniformLocation( program, name ); + } + /** * Get the implementation defined MAX_TEXTURE_SIZE. This values is cached when the context is created * @return The implementation defined MAX_TEXTURE_SIZE diff --git a/dali/public-api/actors/actor.h b/dali/public-api/actors/actor.h index fda367b..78f19d7 100644 --- a/dali/public-api/actors/actor.h +++ b/dali/public-api/actors/actor.h @@ -308,7 +308,7 @@ public: MINIMUM_SIZE, ///< name "minimumSize", type Vector2 @SINCE_1_0.0 MAXIMUM_SIZE, ///< name "maximumSize", type Vector2 @SINCE_1_0.0 INHERIT_POSITION, ///< name "inheritPosition", type bool @SINCE_1_1.24 - BATCH_PARENT, ///< name "batchParent", type bool + BATCH_PARENT, ///< name "batchParent", type bool @SINCE_1_1.46 }; }; -- 2.7.4