From feacfe58828d12ba8cbe0a4c37cb32149dcc34ac Mon Sep 17 00:00:00 2001 From: David Steele Date: Tue, 1 Jul 2014 17:56:08 +0100 Subject: [PATCH] Added metrics gathering for GL calls [solution] Added a gl proxy implementation class that overrides the methods that we're interested in gathering metrics on, and only use this proxy implementation if the DALI_GRAPHICS_STATUS_TIME environment variable is set. Added calls from RenderThread to use the new PreRender and PostRender methods in the GL abstraction -this enables the proxy implementation to count per-frame data. Change-Id: I25e09664f6b2f3fd9a6b33f99622d547362e2849 Signed-off-by: David Steele Signed-off-by: Adeel Kazmi --- adaptors/base/environment-options.cpp | 11 ++ adaptors/base/environment-options.h | 14 ++ adaptors/base/environment-variables.h | 2 + adaptors/base/render-thread.cpp | 11 +- adaptors/base/render-thread.h | 5 +- adaptors/tizen/internal/common/adaptor-impl.cpp | 16 +- adaptors/tizen/internal/common/file.list | 2 +- .../tizen/internal/common/gl/gl-implementation.h | 14 +- .../internal/common/gl/gl-proxy-implementation.cpp | 167 +++++++++++++++++++++ .../internal/common/gl/gl-proxy-implementation.h | 85 +++++++++++ .../dali-test-suite-utils/test-gl-abstraction.cpp | 8 + .../dali-test-suite-utils/test-gl-abstraction.h | 2 + 12 files changed, 327 insertions(+), 10 deletions(-) create mode 100644 adaptors/tizen/internal/common/gl/gl-proxy-implementation.cpp create mode 100644 adaptors/tizen/internal/common/gl/gl-proxy-implementation.h diff --git a/adaptors/base/environment-options.cpp b/adaptors/base/environment-options.cpp index 6ef540b..936c2f4 100644 --- a/adaptors/base/environment-options.cpp +++ b/adaptors/base/environment-options.cpp @@ -38,6 +38,7 @@ EnvironmentOptions::EnvironmentOptions() mPanGestureSmoothingAmount(-1.0f), mPanMinimumDistance(-1), mPanMinimumEvents(-1), + mGlesCallTime(0), mLogFunction( NULL ) { } @@ -149,6 +150,16 @@ void EnvironmentOptions::SetMinimumPanEvents( int events ) mPanMinimumEvents = events; } +void EnvironmentOptions::SetGlesCallTime( int time ) +{ + mGlesCallTime = time; +} + +int EnvironmentOptions::GetGlesCallTime() +{ + return mGlesCallTime; +} + } // Adaptor } // Internal diff --git a/adaptors/base/environment-options.h b/adaptors/base/environment-options.h index 2ba26d0..360cdfc 100644 --- a/adaptors/base/environment-options.h +++ b/adaptors/base/environment-options.h @@ -161,6 +161,19 @@ public: */ void SetMinimumPanEvents( int events ); + /** + * @brief Sets how often the gles call logging occurs + * + * @param[in] time the number of seconds between logging output + */ + void SetGlesCallTime( int time ); + + /** + * @brief Get the graphics status time + */ + int GetGlesCallTime(); + + private: unsigned int mFpsFrequency; ///< how often fps is logged out in seconds @@ -173,6 +186,7 @@ private: float mPanGestureSmoothingAmount; ///< prediction amount for pan gestures int mPanMinimumDistance; ///< minimum distance required before pan starts int mPanMinimumEvents; ///< minimum events required before pan starts + int mGlesCallTime; ///< time in seconds between status updates Dali::Integration::Log::LogFunction mLogFunction; diff --git a/adaptors/base/environment-variables.h b/adaptors/base/environment-variables.h index dbe7513..f5fb623 100644 --- a/adaptors/base/environment-variables.h +++ b/adaptors/base/environment-variables.h @@ -43,6 +43,8 @@ namespace Adaptor #define DALI_ENV_PAN_MINIMUM_EVENTS "DALI_PAN_MINIMUM_EVENTS" +#define DALI_GLES_CALL_TIME "DALI_GLES_CALL_TIME" + } // namespace Adaptor } // namespace Internal diff --git a/adaptors/base/render-thread.cpp b/adaptors/base/render-thread.cpp index 75dfe72..446cf1b 100644 --- a/adaptors/base/render-thread.cpp +++ b/adaptors/base/render-thread.cpp @@ -337,11 +337,20 @@ void RenderThread::ShutdownEgl() bool RenderThread::PreRender() { - return mCurrent.surface->PreRender( *mEGL, mGLES ); + bool success = mCurrent.surface->PreRender( *mEGL, mGLES ); + if( success ) + { + mGLES.PreRender(); + } + return success; } void RenderThread::PostRender( unsigned int timeDelta ) { + // Inform the gl implementation that rendering has finished before informing the surface + mGLES.PostRender(timeDelta); + + // Inform the surface that rendering this frame has finished. mCurrent.surface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplacing ? RenderSurface::SYNC_MODE_NONE : RenderSurface::SYNC_MODE_WAIT ); } diff --git a/adaptors/base/render-thread.h b/adaptors/base/render-thread.h index 27ce395..bedad6d 100644 --- a/adaptors/base/render-thread.h +++ b/adaptors/base/render-thread.h @@ -168,7 +168,7 @@ private: // Data UpdateRenderSynchronization& mUpdateRenderSync; ///< Used to synchronize the update & render threads Dali::Integration::Core& mCore; ///< Dali core reference - Integration::GlAbstraction& mGLES; ///< GL abstraction rerefence + Integration::GlAbstraction& mGLES; ///< GL abstraction reference EglFactoryInterface* mEglFactory; ///< Factory class to create EGL implementation EglInterface* mEGL; ///< Interface to EGL implementation @@ -178,7 +178,7 @@ private: // Data /** * Structure to hold values that are set by main thread and read in render thread - * There is two copies of this data to avoid locking and prevent concurrent access + * There are two copies of this data to avoid locking and prevent concurrent access */ struct RenderData { @@ -244,4 +244,3 @@ private: // Data } // namespace Dali #endif // __DALI_INTERNAL_RENDER_THREAD_H__ - diff --git a/adaptors/tizen/internal/common/adaptor-impl.cpp b/adaptors/tizen/internal/common/adaptor-impl.cpp index adfa42f..ad5f4b3 100644 --- a/adaptors/tizen/internal/common/adaptor-impl.cpp +++ b/adaptors/tizen/internal/common/adaptor-impl.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -179,6 +180,12 @@ void Adaptor::ParseEnvironmentOptions() mEnvironmentOptions.SetMinimumPanEvents( minimumEvents ); } + int glesCallTime(0); + if ( GetIntegerEnvironmentVariable(DALI_GLES_CALL_TIME, glesCallTime )) + { + mEnvironmentOptions.SetGlesCallTime( glesCallTime ); + } + mEnvironmentOptions.InstallLogFunction(); } @@ -199,7 +206,14 @@ void Adaptor::Initialize() mGestureManager = new GestureManager(*this, Vector2(size.width, size.height), mCallbackManager, mEnvironmentOptions); - mGLES = new GlImplementation; + if( mEnvironmentOptions.GetGlesCallTime() > 0 ) + { + mGLES = new GlProxyImplementation( mEnvironmentOptions ); + } + else + { + mGLES = new GlImplementation(); + } mEglFactory = new EglFactory(); diff --git a/adaptors/tizen/internal/common/file.list b/adaptors/tizen/internal/common/file.list index 6e93a70..a21e629 100644 --- a/adaptors/tizen/internal/common/file.list +++ b/adaptors/tizen/internal/common/file.list @@ -49,6 +49,7 @@ tizen_adaptor_internal_common_src_files = \ $(tizen_adaptor_internal_src_dir)/gl/egl-image-extensions.cpp \ $(tizen_adaptor_internal_src_dir)/gl/egl-implementation.cpp \ $(tizen_adaptor_internal_src_dir)/gl/egl-sync-implementation.cpp \ + $(tizen_adaptor_internal_src_dir)/gl/gl-proxy-implementation.cpp \ $(tizen_adaptor_internal_src_dir)/gl/gl-extensions.cpp \ \ $(tizen_adaptor_internal_src_dir)/ecore-x/pixmap-render-surface.cpp \ @@ -62,4 +63,3 @@ tizen_adaptor_internal_common_profile_src_files = \ $(tizen_adaptor_internal_src_dir)/color-controller-impl.cpp \ \ $(tizen_adaptor_internal_src_dir)/ecore-x/ecore-x-render-surface-factory.cpp - \ No newline at end of file diff --git a/adaptors/tizen/internal/common/gl/gl-implementation.h b/adaptors/tizen/internal/common/gl/gl-implementation.h index 29860ec..ca459d8 100644 --- a/adaptors/tizen/internal/common/gl/gl-implementation.h +++ b/adaptors/tizen/internal/common/gl/gl-implementation.h @@ -51,13 +51,19 @@ namespace Adaptor class GlImplementation: public Dali::Integration::GlAbstraction { -/* - * The class contents have been generated by a script which parses - * the file gl-abstraction.h - */ public: virtual ~GlImplementation() {} + void PreRender() + { + /* Do nothing in main implementation */ + } + + void PostRender( unsigned int timeDelta ) + { + /* Do nothing in main implementation */ + } + /* OpenGL ES 2.0 */ void ActiveTexture (GLenum texture) diff --git a/adaptors/tizen/internal/common/gl/gl-proxy-implementation.cpp b/adaptors/tizen/internal/common/gl/gl-proxy-implementation.cpp new file mode 100644 index 0000000..aff0d82 --- /dev/null +++ b/adaptors/tizen/internal/common/gl/gl-proxy-implementation.cpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// +// Licensed under the Flora License, Version 1.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://floralicense.org/license/ +// +// 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 "gl-proxy-implementation.h" + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +namespace +{ +const int NUM_FRAMES_PER_SECOND(60); +} + + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ + +Sampler::Sampler() +: mAccumulated(0.0f), + mAccumulatedSquare(0.0f), + mMin(0.0f), + mMax(0.0f), + mNumSamples(0) +{ +} + + +void Sampler::Reset() +{ + mAccumulated = 0.0f; + mAccumulatedSquare= 0.0f; + mMin = 0.0f; + mMax = 0.0f; + mNumSamples = 0; +} + +void Sampler::Accumulate(float value) +{ + if( mNumSamples == 0 ) + { + mMin = value; + mMax = value; + } + else + { + if(value < mMin) + { + mMin = value; + } + if(value > mMax) + { + mMax = value; + } + } + + mNumSamples++; + + mAccumulated += value; + mAccumulatedSquare += (value * value); +} + +float Sampler::GetMeanValue() +{ + float meanValue = 0; + if( mNumSamples > 0 ) + { + meanValue = mAccumulated / (float)mNumSamples; + } + return meanValue; +} + +float Sampler::GetStandardDeviation() +{ + float standardDeviation=0.0f; + if( mNumSamples > 0 ) + { + standardDeviation = sqrtf( mNumSamples * mAccumulatedSquare - (mAccumulated*mAccumulated)) / mNumSamples; + } + return standardDeviation; +} + +float Sampler::GetMin() +{ + return mMin; +} + +float Sampler::GetMax() +{ + return mMax; +} + +GlProxyImplementation::GlProxyImplementation(EnvironmentOptions& environmentOptions) +: mEnvironmentOptions(environmentOptions), + mDrawCount(0), + mFrameCount(0) +{ +} + +GlProxyImplementation::~GlProxyImplementation() +{ +} + +void GlProxyImplementation::PreRender() +{ +} + +void GlProxyImplementation::PostRender( unsigned int timeDelta ) +{ + // Accumulate counts in each sampler + mDrawSampler.Accumulate(mDrawCount); + mDrawCount=0; + + // When we reach the desired frame count, output the averages from the samples + mFrameCount++; + if( mFrameCount >= mEnvironmentOptions.GetGlesCallTime() * NUM_FRAMES_PER_SECOND ) + { + Debug::LogMessage( Debug::DebugInfo, "Mean number of draw calls per frame: %5.2f (Min:%5.2f, Max:%5.2f, StdDev:%5.2f sampled over %d frames\n", + mDrawSampler.GetMeanValue(), + mDrawSampler.GetMin(), + mDrawSampler.GetMax(), + mDrawSampler.GetStandardDeviation(), + mFrameCount ); + + mDrawSampler.Reset(); + mFrameCount = 0; + } +} + +void GlProxyImplementation::DrawArrays (GLenum mode, GLint first, GLsizei count) +{ + mDrawCount++; + GlImplementation::DrawArrays(mode,first,count); +} + +void GlProxyImplementation::DrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices) +{ + mDrawCount++; + GlImplementation::DrawElements(mode,count,type,indices); +} + +} // namespace Adaptor + +} // namespace Internal + +} // namespace Dali diff --git a/adaptors/tizen/internal/common/gl/gl-proxy-implementation.h b/adaptors/tizen/internal/common/gl/gl-proxy-implementation.h new file mode 100644 index 0000000..33897dc --- /dev/null +++ b/adaptors/tizen/internal/common/gl/gl-proxy-implementation.h @@ -0,0 +1,85 @@ +#ifndef __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__ +#define __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__ + +/* + * Copyright (c) 2014 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. + * + */ + +// EXTERNAL INCLUDES + +#include + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +class EnvironmentOptions; + + +class Sampler +{ +public: + Sampler(); + void Reset(); + void Accumulate(float value); + float GetMeanValue(); + float GetStandardDeviation(); + float GetMin(); + float GetMax(); + +private: + float mAccumulated; + float mAccumulatedSquare; + float mMin; + float mMax; + int mNumSamples; +}; + +/** + * GlProxyImplementation is a wrapper for the concrete implementation + * of GlAbstraction that also gathers statistical information. + */ +class GlProxyImplementation : public GlImplementation +{ +public: + GlProxyImplementation(EnvironmentOptions& environmentOptions); + + virtual ~GlProxyImplementation(); + + virtual void PreRender(); + + virtual void PostRender( unsigned int timeDelta ); + + virtual void DrawArrays (GLenum mode, GLint first, GLsizei count); + + virtual void DrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices); + +private: + EnvironmentOptions& mEnvironmentOptions; + Sampler mDrawSampler; + int mDrawCount; + int mFrameCount; +}; + +} // namespace Adaptor + +} // namespace Internal + +} // namespace Dali + +#endif // __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__ diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp index 3fa897a..49a49c5 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp @@ -72,6 +72,14 @@ void TestGlAbstraction::Initialize() mProgramUniforms4f.clear(); } +void TestGlAbstraction::PreRender() +{ +} + +void TestGlAbstraction::PostRender(unsigned int timeDelta) +{ +} + } // Namespace dali bool BlendEnabled(const Dali::TraceCallStack& callStack) diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h index 908034f..7cb21fb 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h @@ -50,6 +50,8 @@ public: TestGlAbstraction(); ~TestGlAbstraction(); void Initialize(); + void PreRender(); + void PostRender(unsigned int timeDelta); /* OpenGL ES 2.0 */ -- 2.7.4