mLastProgramIdUsed = 0;
mLastUniformIdUsed = 0;
mLastShaderCompiled = 0;
+ mLastClearBitMask = 0;
+ mClearCount = 0;
mLastBlendEquationRgb = 0;
mLastBlendEquationAlpha = 0;
inline void Clear(GLbitfield mask)
{
+ mClearCount++;
+ mLastClearBitMask = mask;
}
inline void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
return mLastProgramIdUsed;
}
+ inline GLbitfield GetLastClearMask() const
+ {
+ return mLastClearBitMask;
+ }
+
enum AttribType
{
ATTRIB_UNKNOWN = -1,
inline bool GetProgramBinaryCalled() const { return mGetProgramBinaryCalled; }
+ inline unsigned int GetClearCountCalled() const { return mClearCount; }
+
private:
GLuint mCurrentProgram;
GLuint mCompileStatus;
typedef std::map< GLuint, std::string> ShaderSourceMap;
ShaderSourceMap mShaderSources;
GLuint mLastShaderCompiled;
+ GLbitfield mLastClearBitMask;
+ unsigned int mClearCount;
Vector4 mLastBlendColor;
GLenum mLastBlendEquationRgb;
END_TEST;
}
+int UtcDaliRenderableActorTestClearCache01(void)
+{
+ // Testing the framebuffer state caching in frame-buffer-state-caching.cpp
+ TestApplication application;
+
+ tet_infoline("Testing Dali::RenderableActor::ClearCache01()");
+
+ BufferImage img = BufferImage::New( 1,1 );
+ ImageActor actor = ImageActor::New( img );
+
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ actor.SetAnchorPoint(AnchorPoint::CENTER);
+
+ Stage::GetCurrent().Add(actor);
+
+ /**************************************************************/
+ // Flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // There should be a single call to Clear
+ DALI_TEST_EQUALS( application.GetGlAbstraction().GetClearCountCalled() , 1u, TEST_LOCATION );
+
+ // the last set clear mask should be COLOR, DEPTH & STENCIL which occurs at the start of each frame
+ GLbitfield mask = application.GetGlAbstraction().GetLastClearMask();
+ DALI_TEST_CHECK( mask & GL_DEPTH_BUFFER_BIT );
+ DALI_TEST_CHECK( mask & GL_STENCIL_BUFFER_BIT );
+ DALI_TEST_CHECK( mask & GL_COLOR_BUFFER_BIT );
+
+ END_TEST;
+}
+
+int UtcDaliRenderableActorTestClearCache02(void)
+{
+ // Testing the framebuffer state caching in frame-buffer-state-caching.cpp
+ TestApplication application;
+
+ tet_infoline("Testing Dali::RenderableActor::ClearCache02()");
+
+ // use RGB so alpha is disabled and the actors are drawn opaque
+ BufferImage img = BufferImage::New( 10,10 ,Pixel::RGB888 );
+
+ // Without caching DALi perform clears in the following places
+ // Root
+ // | glClear #1 ( everything at start of frame )
+ // |
+ // |
+ // | glClear #2 ( start of layer with opaque actors )
+ // | ----> Layer1
+ // | -> Actor 1 ( opaque )
+ // | -> Actor 2 ( opaque )
+ // |
+ // |
+ // | glClear #3 ( start of layer with opaque actors )
+ // |----> Layer 2
+ // | -> Actor 3 ( opaque )
+ // | -> Actor 4 ( opaque )
+ //
+ // With caching enabled glClear should only be called twice, at points #1 and #3.
+ // At #1 with depth, color and stencil cleared
+ // At #3 with depth cleared
+ // #2 is not required because the buffer has already been cleared at #1
+
+ Layer layer1 = Layer::New();
+ layer1.Add( ImageActor::New( img ) );
+ layer1.Add( ImageActor::New( img ) );
+
+ Layer layer2 = Layer::New();
+ layer2.Add( ImageActor::New( img ) );
+ layer2.Add( ImageActor::New( img ) );
+
+ Stage::GetCurrent().Add( layer1 );
+ Stage::GetCurrent().Add( layer2 );
+
+ /**************************************************************/
+
+ // Flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // There should be a 2 calls to Clear
+ DALI_TEST_EQUALS( application.GetGlAbstraction().GetClearCountCalled() , 2u, TEST_LOCATION );
+
+ // the last set clear mask should be DEPTH & STENCIL & COLOR
+ GLbitfield mask = application.GetGlAbstraction().GetLastClearMask();
+
+ tet_printf(" clear count = %d \n", application.GetGlAbstraction().GetClearCountCalled() );
+
+ // The last clear should just be DEPTH BUFFER, not color and stencil which were cleared at the start of the frame
+ DALI_TEST_CHECK( mask & GL_DEPTH_BUFFER_BIT );
+ DALI_TEST_CHECK( ! ( mask & GL_COLOR_BUFFER_BIT ) );
+ DALI_TEST_CHECK( ! ( mask & GL_STENCIL_BUFFER_BIT ) );
+
+ END_TEST;
+}
+
+int UtcDaliRenderableActorTestClearCache03(void)
+{
+ // Testing the framebuffer state caching in frame-buffer-state-caching.cpp
+ TestApplication application;
+
+ tet_infoline("Testing Dali::RenderableActor::ClearCache03()");
+
+ // use RGB so alpha is disabled and the actors are drawn opaque
+ BufferImage img = BufferImage::New( 10,10 ,Pixel::RGB888 );
+
+ // Without caching DALi perform clears in the following places
+ // Root
+ // | 1-## glClear ( COLOR, DEPTH, STENCIL )
+ // |
+ // | ----> Layer1
+ // | 2-## glClear ( STENCIL )
+ // | -> Actor 1 ( stencil )
+ // | 3-## glClear ( DEPTH )
+ // | -> Actor 2 ( opaque ) // need 2 opaque actors to bypass optimisation of turning off depth test
+ // | -> Actor 3 ( opaque )
+ // |
+ // |
+ // |----> Layer 2
+ // | 4-## glClear ( STENCIL )
+ // | -> Actor 4 ( stencil )
+ // | 5-## glClear ( DEPTH )
+ // | -> Actor 5 ( opaque ) // need 2 opaque actors to bypass optimisation of turning off depth test
+ // | -> Actor 6 ( opaque )
+ //
+ // With caching enabled glClear will not be called at ## 2 and ## 3 ( because those buffers are already clear).
+ //
+ // @TODO Add further optimisation to look-ahead in the render-list to see if
+ // When performing STENCIL clear, check if there another layer after it.
+ // If there is, combine the STENCIL with a DEPTH clear.
+ //
+
+ Layer layer1 = Layer::New();
+ ImageActor actor1 = ImageActor::New( img );
+ ImageActor actor2 = ImageActor::New( img );
+ ImageActor actor3 = ImageActor::New( img );
+
+ actor2.SetDrawMode( DrawMode::STENCIL );
+
+ layer1.Add( actor1 );
+ layer1.Add( actor2 );
+ layer1.Add( actor3 );
+
+ Layer layer2 = Layer::New();
+ ImageActor actor4 = ImageActor::New( img );
+ ImageActor actor5 = ImageActor::New( img );
+ ImageActor actor6 = ImageActor::New( img );
+
+ actor4.SetDrawMode( DrawMode::STENCIL );
+
+ layer2.Add( actor4 );
+ layer2.Add( actor5 );
+ layer2.Add( actor6 );
+
+ Stage::GetCurrent().Add( layer1 );
+ Stage::GetCurrent().Add( layer2 );
+
+
+ /**************************************************************/
+
+ // Flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // There should be a 3 calls to Clear ( one for everything, one for stencil, one for depth buffer).
+ DALI_TEST_EQUALS( application.GetGlAbstraction().GetClearCountCalled() , 3u, TEST_LOCATION );
+
+ // the last set clear mask should be DEPTH & STENCIL & COLOR
+ GLbitfield mask = application.GetGlAbstraction().GetLastClearMask();
+
+ tet_printf(" clear count = %d \n", application.GetGlAbstraction().GetClearCountCalled() );
+ tet_printf(" clear mask = %x \n", mask);
+
+ // The last clear should just be DEPTH BUFFER and stencil
+ DALI_TEST_CHECK( !( mask & GL_COLOR_BUFFER_BIT ) );
+ DALI_TEST_CHECK( !( mask & GL_STENCIL_BUFFER_BIT ) );
+ DALI_TEST_CHECK( mask & GL_DEPTH_BUFFER_BIT );
+
+
+ END_TEST;
+}
$(internal_src_dir)/render/common/texture-cache-dispatcher.cpp \
$(internal_src_dir)/render/gl-resources/bitmap-texture.cpp \
$(internal_src_dir)/render/gl-resources/context.cpp \
+ $(internal_src_dir)/render/gl-resources/frame-buffer-state-cache.cpp \
$(internal_src_dir)/render/gl-resources/compressed-bitmap-texture.cpp \
$(internal_src_dir)/render/gl-resources/frame-buffer-texture.cpp \
$(internal_src_dir)/render/gl-resources/gl-call-debug.cpp \
const unsigned int renderFlags = renderList.GetFlags();
- bool setDepthTest = ( ( renderFlags & RenderList::DEPTH_TEST ) != 0u );
- bool depthMask = ( ( renderFlags & RenderList::DEPTH_WRITE ) != 0u );
+ bool enableDepthBuffer = ( ( renderFlags & RenderList::DEPTH_BUFFER_ENABLED ) != 0u );
+ bool depthMask = ( ( renderFlags & RenderList::DEPTH_WRITE ) != 0u );
- GLbitfield clearMask = ( renderFlags & RenderList::DEPTH_CLEAR ) ? GL_DEPTH_BUFFER_BIT : 0u;
+ GLbitfield clearMask = ( renderFlags & RenderList::DEPTH_CLEAR ) ? GL_DEPTH_BUFFER_BIT : 0u;
- context.SetDepthTest( setDepthTest );
+ context.EnableDepthBuffer( enableDepthBuffer );
context.DepthMask( depthMask );
- // Stencil testing, writing, and clearing...
- const bool enableStencilTest( renderFlags & RenderList::STENCIL_TEST );
+ // Stencil enabled, writing, and clearing...
+ const bool enableStencilBuffer( renderFlags & RenderList::STENCIL_BUFFER_ENABLED );
const bool enableStencilWrite( renderFlags & RenderList::STENCIL_WRITE );
- context.SetStencilTest( enableStencilTest );
+ context.EnableStencilBuffer( enableStencilBuffer );
- if( enableStencilTest )
+ if( enableStencilBuffer )
{
context.StencilFunc( (enableStencilWrite ? GL_ALWAYS : GL_EQUAL), 1, 0xFF );
context.StencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
// Clear depth and/or stencil buffer.
if( clearMask )
{
- context.Clear( clearMask );
+ // only clear if the depth and/or stencil buffer have been written to after a previous clear
+ context.Clear( clearMask, Context::CHECK_CACHED_VALUES );
}
size_t count = renderList.Count();
{
debugStream << " with:";
- if( flags & RenderList::DEPTH_TEST )
+ if( flags & RenderList::DEPTH_BUFFER_ENABLED )
{
debugStream << " DEPTH_TEST";
}
debugStream << " DEPTH_CLEAR";
}
- if( flags & RenderList::STENCIL_TEST )
+ if( flags & RenderList::STENCIL_BUFFER_ENABLED )
{
debugStream << " STENCIL_TEST";
}
public:
/**
- * The RenderFlags describe how the objects are rendered using the depth buffer.
+ * The RenderFlags describe how the objects are rendered using the depth and stencil buffer.
+ *
+ * The flags which relate to GL_DEPTH_TEST and GL_STENCIL_TEST are called
+ * DEPTH_BUFFER_ENABLED and STENCIL_BUFFER_ENABLED to avoid any confusion.
+ * E.g. if GL_DEPTH_TEST is not enabled you can't write to the depth buffer, which can cause confusion.
+ *
*/
enum RenderFlags
{
- DEPTH_TEST = 0x01, ///< If depth testing should be used
- DEPTH_WRITE = 0x02, ///< If the depth buffer is writable
- DEPTH_CLEAR = 0x04, ///< If the depth buffer should first be cleared
- STENCIL_TEST = 0x08, ///< If stencil testing should be used
- STENCIL_WRITE = 0x10, ///< If the stencil buffer is writable
- STENCIL_CLEAR = 0x20 ///< If the stencil buffer should first be cleared
+ DEPTH_BUFFER_ENABLED = 1 << 0, ///< If depth buffer should be used for writing / test operations
+ DEPTH_WRITE = 1 << 1, ///< If the depth buffer is writable
+ DEPTH_CLEAR = 1 << 2, ///< If the depth buffer should first be cleared
+ STENCIL_BUFFER_ENABLED = 1 << 3, ///< If stencil buffer should be used for writing / test operation
+ STENCIL_WRITE = 1 << 4, ///< If the stencil buffer is writable
+ STENCIL_CLEAR = 1 << 5, ///< If the stencil buffer should first be cleared
+
};
/**
mImpl->context.ColorMask( true );
mImpl->context.DepthMask( true );
mImpl->context.StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
- mImpl->context.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+ mImpl->context.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, Context::FORCE_CLEAR );
// reset the program matrices for all programs once per frame
// this ensures we will set view and projection matrix once per program per camera
mImpl->context.SetScissorTest( true );
mImpl->context.Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
mImpl->context.ColorMask( true );
- mImpl->context.Clear( GL_COLOR_BUFFER_BIT );
+ mImpl->context.Clear( GL_COLOR_BUFFER_BIT , Context::CHECK_CACHED_VALUES );
mImpl->context.SetScissorTest( false );
}
mColorMask(true),
mStencilMask(0xFF),
mBlendEnabled(false),
- mDepthTestEnabled(false),
+ mDepthBufferEnabled(false),
mDepthMaskEnabled(false),
mDitherEnabled(true), // This the only GL capability which defaults to true
mPolygonOffsetFillEnabled(false),
mSampleAlphaToCoverageEnabled(false),
mSampleCoverageEnabled(false),
mScissorTestEnabled(false),
- mStencilTestEnabled(false),
+ mStencilBufferEnabled(false),
mClearColorSet(false),
mBoundArrayBufferId(0),
mBoundElementArrayBufferId(0),
mBlendEnabled = false;
mGlAbstraction.Disable(GL_BLEND);
- mDepthTestEnabled = false;
+ mDepthBufferEnabled = false;
mGlAbstraction.Disable(GL_DEPTH_TEST);
mDepthMaskEnabled = false;
mScissorTestEnabled = false;
mGlAbstraction.Disable(GL_SCISSOR_TEST);
- mStencilTestEnabled = false;
+ mStencilBufferEnabled = false;
mGlAbstraction.Disable(GL_STENCIL_TEST);
mBoundArrayBufferId = 0;
mViewPort.x = mViewPort.y = mViewPort.width = mViewPort.height = 0;
ResetVertexAttributeState();
+
+ mFrameBufferStateCache.Reset();
}
#ifdef DEBUG_ENABLED
"----------------- Context State END -----------------\n",
mBlendEnabled ? "Enabled" : "Disabled",
cullFaceModes[ mCullFaceMode ],
- mDepthTestEnabled ? "Enabled" : "Disabled",
+ mDepthBufferEnabled ? "Enabled" : "Disabled",
mDepthMaskEnabled ? "Enabled" : "Disabled",
mDitherEnabled ? "Enabled" : "Disabled",
mPolygonOffsetFillEnabled ? "Enabled" : "Disabled",
mSampleAlphaToCoverageEnabled ? "Enabled" : "Disabled",
mSampleCoverageEnabled ? "Enabled" : "Disabled",
mScissorTestEnabled ? "Enabled" : "Disabled",
- mStencilTestEnabled ? "Enabled" : "Disabled");
+ mStencilBufferEnabled ? "Enabled" : "Disabled");
}
#endif // DALI_CONTEXT_LOGGING
#include <dali/integration-api/gl-defines.h>
#include <dali/internal/render/common/performance-monitor.h>
#include <dali/internal/render/gl-resources/texture-units.h>
+#include <dali/internal/render/gl-resources/frame-buffer-state-cache.h>
#include <dali/internal/render/gl-resources/gl-call-debug.h>
namespace Dali
class Context
{
public:
+
+ /**
+ * FrameBuffer Clear mode
+ */
+ enum ClearMode
+ {
+ FORCE_CLEAR, ///< always perform the glClear regardless of current state
+ CHECK_CACHED_VALUES ///< check the Frame buffers cached state to see if a clear is required
+ };
+
/**
* Size of the VertexAttributeArray enables
* GLES specification states that there's minimum of 8
*/
void BindFramebuffer(GLenum target, GLuint framebuffer)
{
+ mFrameBufferStateCache.SetCurrentFrameBuffer( framebuffer );
+
LOG_GL("BindFramebuffer %d %d\n", target, framebuffer);
CHECK_GL( mGlAbstraction, mGlAbstraction.BindFramebuffer(target, framebuffer) );
}
/**
* Wrapper for OpenGL ES 2.0 glClear()
*/
- void Clear(GLbitfield mask)
+ void Clear(GLbitfield mask, ClearMode mode )
{
- LOG_GL("Clear %d\n", mask);
- CHECK_GL( mGlAbstraction, mGlAbstraction.Clear(mask) );
+ bool forceClear = (mode == FORCE_CLEAR );
+ mask = mFrameBufferStateCache.GetClearMask( mask, forceClear , mScissorTestEnabled );
+
+ if( mask > 0 )
+ {
+ LOG_GL("Clear %d\n", mask);
+ CHECK_GL( mGlAbstraction, mGlAbstraction.Clear( mask ) );
+ }
}
/**
*/
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
{
+ mFrameBufferStateCache.FrameBuffersDeleted( n, framebuffers );
+
LOG_GL("DeleteFramebuffers %d %p\n", n, framebuffers);
CHECK_GL( mGlAbstraction, mGlAbstraction.DeleteFramebuffers(n, framebuffers) );
}
*/
void DrawArrays(GLenum mode, GLint first, GLsizei count)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
FlushVertexAttributeLocations();
LOG_GL("DrawArrays %x %d %d\n", mode, first, count);
*/
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
FlushVertexAttributeLocations();
LOG_GL("DrawArraysInstanced %x %d %d %d\n", mode, first, count, instanceCount);
*/
void DrawBuffers(GLsizei n, const GLenum* bufs)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
LOG_GL("DrawBuffers %d %p\n", n, bufs);
CHECK_GL( mGlAbstraction, mGlAbstraction.DrawBuffers(n, bufs) );
}
*/
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
+
FlushVertexAttributeLocations();
LOG_GL("DrawElements %x %d %d %p\n", mode, count, type, indices);
*/
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instanceCount)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
+
FlushVertexAttributeLocations();
LOG_GL("DrawElementsInstanced %x %d %d %p %d\n", mode, count, type, indices, instanceCount);
*/
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices)
{
+ mFrameBufferStateCache.DrawOperation( mColorMask, DepthBufferWriteEnabled(), StencilBufferWriteEnabled() );
FlushVertexAttributeLocations();
LOG_GL("DrawRangeElements %x %u %u %d %d %p\n", mode, start, end, count, type, indices);
/**
* This method replaces glEnable(GL_DEPTH_TEST) and glDisable(GL_DEPTH_TEST).
+ * Note GL_DEPTH_TEST means enable the depth buffer for writing and or testing.
+ * glDepthMask is used to enable / disable writing to depth buffer.
+ * glDepthFunc us used to control if testing is enabled and how it is performed ( default GL_LESS)
+ *
* @param[in] enable True if GL_DEPTH_TEST should be enabled.
*/
- void SetDepthTest(bool enable)
+ void EnableDepthBuffer( bool enable )
{
// Avoid unecessary calls to glEnable/glDisable
- if (enable != mDepthTestEnabled)
+ if( enable != mDepthBufferEnabled )
{
- mDepthTestEnabled = enable;
+ mDepthBufferEnabled = enable;
if (enable)
{
/**
* This method replaces glEnable(GL_STENCIL_TEST) and glDisable(GL_STENCIL_TEST).
+ * Note GL_STENCIL_TEST means enable the stencil buffer for writing and or testing.
+ * glStencilMask is used to control how bits are written to the stencil buffer.
+ * glStencilFunc is used to control if testing is enabled and how it is performed ( default GL_ALWAYS )
* @param[in] enable True if GL_STENCIL_TEST should be enabled.
*/
- void SetStencilTest(bool enable)
+ void EnableStencilBuffer(bool enable)
{
// Avoid unecessary calls to glEnable/glDisable
- if (enable != mStencilTestEnabled)
+ if( enable != mStencilBufferEnabled )
{
- mStencilTestEnabled = enable;
+ mStencilBufferEnabled = enable;
if (enable)
{
{
LOG_GL("GenFramebuffers %d %p\n", n, framebuffers);
CHECK_GL( mGlAbstraction, mGlAbstraction.GenFramebuffers(n, framebuffers) );
+
+ mFrameBufferStateCache.FrameBuffersCreated( n, framebuffers );
}
/**
*/
void StencilFunc(GLenum func, GLint ref, GLuint mask)
{
+
+
LOG_GL("StencilFunc %x %d %d\n", func, ref, mask);
CHECK_GL( mGlAbstraction, mGlAbstraction.StencilFunc(func, ref, mask) );
}
return mRendererCount;
}
-
private: // Implementation
/**
+ * @return true if next draw operation will write to depth buffer
+ */
+ bool DepthBufferWriteEnabled() const
+ {
+ return mDepthBufferEnabled && mDepthMaskEnabled;
+ }
+
+ /**
+ * @return true if next draw operation will write to stencil buffer
+ */
+ bool StencilBufferWriteEnabled() const
+ {
+ return mStencilBufferEnabled && ( mStencilMask > 0 );
+ }
+
+ /**
* Flushes vertex attribute location changes to the driver
*/
void FlushVertexAttributeLocations();
bool mColorMask;
GLuint mStencilMask;
bool mBlendEnabled;
- bool mDepthTestEnabled;
+ bool mDepthBufferEnabled;
bool mDepthMaskEnabled;
bool mDitherEnabled;
bool mPolygonOffsetFillEnabled;
bool mSampleAlphaToCoverageEnabled;
bool mSampleCoverageEnabled;
bool mScissorTestEnabled;
- bool mStencilTestEnabled;
+ bool mStencilBufferEnabled;
bool mClearColorSet;
// glBindBuffer() state
unsigned int mFrameCount; ///< Number of render frames
unsigned int mCulledCount; ///< Number of culled renderers per frame
unsigned int mRendererCount; ///< Number of image renderers per frame
+ FrameBufferStateCache mFrameBufferStateCache; ///< frame buffer state cache
};
} // namespace Internal
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "frame-buffer-state-cache.h"
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/gl-defines.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+FrameBufferStateCache::FrameBufferStateCache()
+:mCurrentFrameBufferId(0)
+{
+}
+
+FrameBufferStateCache::~FrameBufferStateCache()
+{
+}
+
+GLbitfield FrameBufferStateCache::GetClearMask( GLbitfield mask, bool forceClear, bool scissorTestEnabled )
+{
+ if( scissorTestEnabled )
+ {
+ // don't do anything if scissor test is enabled, in the future we could
+ // potentially keep track of frame buffer size vs scissor test size to see if the entire
+ // buffer is cleared or not.
+ return mask;
+ }
+ FrameBufferState* state = GetFrameBufferState( mCurrentFrameBufferId );
+ if( !state )
+ {
+ DALI_LOG_ERROR("FrameBuffer not found %d \n", mCurrentFrameBufferId);
+ return mask;
+ }
+
+ // if we are forcing the clear operation, then just update the internal cached values
+ if( forceClear )
+ {
+ SetClearState( state, mask );
+ return mask;
+ }
+
+ // use the cached values
+ if( mask & GL_COLOR_BUFFER_BIT)
+ {
+ // check if color buffer is currently clean
+ if( state->mState & COLOR_BUFFER_CLEAN )
+ {
+ // remove clear color buffer flag from bitmask, no need to clear twice
+ mask&= ~GL_COLOR_BUFFER_BIT;
+ }
+ }
+ if( mask & GL_DEPTH_BUFFER_BIT)
+ {
+ // check if depth buffer is currently clean
+ if( state->mState & DEPTH_BUFFER_CLEAN )
+ {
+ // remove clear depth buffer flag from bitmask, no need to clear twice
+ mask&= ~GL_DEPTH_BUFFER_BIT;
+ }
+ }
+ if( mask & GL_STENCIL_BUFFER_BIT)
+ {
+ // check if stencil buffer is currently clean
+ if( state->mState & STENCIL_BUFFER_CLEAN )
+ {
+ // remove clear stencil buffer flag from bitmask, no need to clear twice
+
+ mask&= ~GL_STENCIL_BUFFER_BIT;
+ }
+ }
+
+ // set the clear state based, what's about to be cleared
+ SetClearState( state, mask );
+
+ return mask;
+}
+
+void FrameBufferStateCache::SetCurrentFrameBuffer( GLuint frameBufferId )
+{
+ mCurrentFrameBufferId = frameBufferId;
+}
+
+void FrameBufferStateCache::FrameBuffersDeleted( GLsizei count, const GLuint* const frameBuffers )
+{
+ for( GLsizei i = 0; i < count; ++i )
+ {
+ DeleteFrameBuffer( frameBuffers[i] );
+ }
+}
+void FrameBufferStateCache::FrameBuffersCreated( GLsizei count, const GLuint* const frameBuffers )
+{
+ for( GLsizei i = 0; i < count; ++i )
+ {
+ // check the frame buffer doesn't exist already
+ GLuint id = frameBuffers[i];
+
+ FrameBufferState* state = GetFrameBufferState( id );
+ if( state )
+ {
+ DALI_LOG_ERROR("FrameBuffer already exists%d \n", id );
+ // reset its state
+ state->mState = GetInitialFrameBufferState();
+ continue;
+ }
+
+ FrameBufferState newFrameBuffer( frameBuffers[i], GetInitialFrameBufferState() );
+ mFrameBufferStates.PushBack( newFrameBuffer );
+ }
+}
+
+void FrameBufferStateCache::DrawOperation( bool colorBuffer, bool depthBuffer, bool stencilBuffer )
+{
+ FrameBufferState* state = GetFrameBufferState( mCurrentFrameBufferId );
+ if( !state )
+ {
+ // an error will have already been logged by the clear operation
+ return;
+ }
+
+ if( colorBuffer )
+ {
+ // un-set the clean bit
+ state->mState &= ~COLOR_BUFFER_CLEAN;
+ }
+ if( depthBuffer )
+ {
+ // un-set the clean bit
+ state->mState &= ~DEPTH_BUFFER_CLEAN;
+ }
+ if( stencilBuffer )
+ {
+ // un-set the clean bit
+ state->mState &= ~STENCIL_BUFFER_CLEAN;
+ }
+
+}
+
+void FrameBufferStateCache::Reset()
+{
+ mFrameBufferStates.Clear();
+
+ // create the default frame buffer
+ GLuint id = 0; // 0 == default frame buffer id
+ FrameBuffersCreated( 1, &id );
+}
+
+void FrameBufferStateCache::SetClearState( FrameBufferState* state, GLbitfield mask )
+{
+ if( mask & GL_COLOR_BUFFER_BIT)
+ {
+ // set the color buffer to clean
+ state->mState |= COLOR_BUFFER_CLEAN;
+ }
+ if( mask & GL_DEPTH_BUFFER_BIT)
+ {
+ // set the depth buffer to clean
+ state->mState |= DEPTH_BUFFER_CLEAN;
+ }
+ if( mask & GL_STENCIL_BUFFER_BIT)
+ {
+ // set the stencil buffer to clean
+ state->mState |= STENCIL_BUFFER_CLEAN;
+ }
+}
+
+FrameBufferStateCache::FrameBufferState* FrameBufferStateCache::GetFrameBufferState( GLuint frameBufferId )
+{
+ for( FrameBufferStateVector::SizeType i = 0; i < mFrameBufferStates.Count(); ++i )
+ {
+ FrameBufferState& state = mFrameBufferStates[i];
+ if( state.mId == frameBufferId )
+ {
+ return &state;
+ }
+ }
+ return NULL;
+}
+
+void FrameBufferStateCache::DeleteFrameBuffer( GLuint frameBufferId )
+{
+ FrameBufferStateVector::Iterator iter = mFrameBufferStates.Begin();
+ FrameBufferStateVector::Iterator endIter = mFrameBufferStates.End();
+
+ for( ; iter != endIter ; ++iter )
+ {
+ if( (*iter).mId == frameBufferId )
+ {
+ mFrameBufferStates.Erase( iter);
+ return;
+ }
+ }
+ DALI_LOG_ERROR("FrameBuffer not found %d \n", frameBufferId);
+}
+
+unsigned int FrameBufferStateCache::GetInitialFrameBufferState()
+{
+ return COLOR_BUFFER_CLEAN | DEPTH_BUFFER_CLEAN | STENCIL_BUFFER_CLEAN;
+}
+
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_INTERNAL_CONTEXT_FRAME_BUFFER_STATE_CACHE_H__
+#define __DALI_INTERNAL_CONTEXT_FRAME_BUFFER_STATE_CACHE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Keeps track of color, depth and stencil buffer state within each frame buffer.
+ * Used to avoid redundant glClear calls.
+ *
+ */
+class FrameBufferStateCache
+{
+public:
+
+
+ /**
+ * @brief Constructor
+ */
+ FrameBufferStateCache();
+
+ /**
+ * @brief non-virtual destructor
+ */
+ ~FrameBufferStateCache();
+
+ /**
+ * @brief Get the bitmask to pass to glClear based on the mask requested
+ * and the current state of the frame buffer
+ * @param[in] mask glClear bit mask
+ * @param[in] forceClear whether to force the clear ( ignore cached state)
+ * @param[in] scissorTestEnabled whether scissor test is enabled
+ * @return new bitmask to pass to glClear
+ */
+ GLbitfield GetClearMask( GLbitfield mask, bool forceClear, bool scissorTestEnabled );
+
+ /**
+ * @brief Set the current bound frame buffer
+ * @param[in] frameBufferId frame buffer id
+ */
+ void SetCurrentFrameBuffer( GLuint frameBufferId );
+
+ /**
+ * @brief Called when frame buffers are deleted
+ * @param[in] count number of frame buffers
+ * @param[in] framebuffers array of frame buffer ids
+ */
+ void FrameBuffersDeleted( GLsizei count, const GLuint* const frameBuffers );
+
+ /**
+ * @brief Called when frame buffers are created
+ * @param[in] count number of frame buffers
+ * @param[in] framebuffers array of frame buffer ids
+ */
+ void FrameBuffersCreated( GLsizei count, const GLuint* const frameBuffers );
+
+ /**
+ * @brief Draw operation performed on the current frame buffer
+ * @param[in] colorBufferUsed whether the color buffer is being written to (glColorMask )
+ * @param[in] depthBufferUsed whether the depth buffer is being written to (glDepthMask )
+ * @param[in] stencilBufferUsed whether the stencil buffer is being written to (glStencilMask )
+ */
+ void DrawOperation( bool colorBufferUsed, bool depthBufferUsed, bool stencilBufferUsed );
+
+ /**
+ * Reset the cache
+ */
+ void Reset();
+
+private:
+
+ /**
+ * Current status of the frame buffer
+ */
+ enum FrameBufferStatus
+ {
+ COLOR_BUFFER_CLEAN = 1 << 0, ///< color buffer clean
+ DEPTH_BUFFER_CLEAN = 1 << 1, ///< depth buffer clean
+ STENCIL_BUFFER_CLEAN = 1 << 2, ///< stencil buffer clean
+ };
+
+ /**
+ * POD to store the status of frame buffer regarding color,depth and stencil buffers
+ */
+ struct FrameBufferState
+ {
+ /**
+ * Constructor
+ */
+ FrameBufferState( GLuint id, unsigned int state)
+ :mId( id ),
+ mState( state )
+ {
+ }
+ GLuint mId; ///< Frame buffer id
+ unsigned int mState; ///< State, bitmask of FrameBufferStatus flags
+ };
+
+ typedef Dali::Vector< FrameBufferState > FrameBufferStateVector;
+
+ /**
+ * @brief Set the clear state
+ * @param[in] pointer to frame buffer state object
+ * @param[in] mask clear mask
+ */
+ void SetClearState( FrameBufferState* state, GLbitfield mask );
+
+ /**
+ * @brief Helper
+ * @param[in] frameBufferId frame buffer id
+ * @return pointer to frame buffer state object ( NULL if it doesn't exist)
+ */
+ FrameBufferState* GetFrameBufferState( GLuint frameBufferId );
+
+ /**
+ * @brief Helper to delete a frame buffer state object
+ * @param[in] frameBufferId frame buffer id
+ */
+ void DeleteFrameBuffer( GLuint frameBufferId );
+
+ /**
+ * @brief Get the default state of a frame buffer, before it's used
+ * @return initial state
+ */
+ unsigned int GetInitialFrameBufferState();
+
+ FrameBufferStateCache( const FrameBufferStateCache& ); ///< undefined copy constructor
+
+ FrameBufferStateCache& operator=( const FrameBufferStateCache& ); ///< undefined assignment operator
+
+private: // data
+
+ FrameBufferStateVector mFrameBufferStates; ///< state of the frame buffers
+ GLuint mCurrentFrameBufferId; ///< currently bound frame buffer
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CONTEXT_FRAME_BUFFER_STATE_CACHE_H__
else
{
// Prepare for rendering multiple opaque objects
- unsigned int flags = RenderList::DEPTH_TEST | RenderList::DEPTH_WRITE | RenderList::DEPTH_CLEAR; // clear depth buffer, draw over the previously rendered layers;
+ unsigned int flags = RenderList::DEPTH_BUFFER_ENABLED | RenderList::DEPTH_WRITE | RenderList::DEPTH_CLEAR; // clear depth buffer, draw over the previously rendered layers;
renderList.ClearFlags();
renderList.SetFlags(flags);
if( stencilRenderablesExist )
{
- renderList.SetFlags( RenderList::STENCIL_TEST );
+ renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
}
}
// objects should be rendered with depth test on to avoid background objects
// appearing in front of opaque foreground objects.
- renderList.SetFlags( RenderList::DEPTH_TEST );
+ renderList.SetFlags( RenderList::DEPTH_BUFFER_ENABLED );
}
if( stencilRenderablesExist )
{
- renderList.SetFlags( RenderList::STENCIL_TEST );
+ renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
}
}
{
if(stencilRenderablesExist)
{
- renderList.SetFlags(RenderList::STENCIL_TEST);
+ renderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
}
}
inline void SetStencilRenderFlags( RenderList& renderList )
{
renderList.ClearFlags();
- renderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_TEST);
+ renderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
}
/**