From: Andrew Cox Date: Fri, 12 Jun 2015 19:23:55 +0000 (+0100) Subject: Shader binary synchronous simplified IO X-Git-Tag: dali_1.0.49~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F87%2F42487%2F14;p=platform%2Fcore%2Fuifw%2Fdali-core.git Shader binary synchronous simplified IO Loading shader binaries synchronously on event thread. Saving shader binaries from ShaderFactory on event thread. Deleted old resource sytem based shader binary loading. Change-Id: I38a79a7b4e9eb33d9a5059f1c43d9e8c892b0867 Signed-off-by: Andrew Cox --- diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp index a0aecc6..3ea4b7f 100644 --- a/automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp @@ -801,57 +801,6 @@ int UtcDaliInternalRequestResourceTicket02(void) END_TEST; } -int UtcDaliInternalLoadShaderRequest01(void) -{ - TestApplication application; - tet_infoline("Testing LoadShader() success"); - testTicketObserver.Reset(); - - // Clear through all of the outstanding shader load requests from the default shader effect - std::vector< unsigned char > buffer; - for( int i=0; i<10; i++ ) - { - buffer.push_back((unsigned char)i); - } - application.GetPlatform().SetLoadFileResult( true, buffer ); - application.GetGlAbstraction().SetLinkStatus(1); - application.SendNotification(); // Flush update messages - application.Render(); // Process load shader request (immediately) - application.SendNotification(); - application.Render(); - application.SendNotification(); - application.Render(); - application.SendNotification(); - - Internal::ResourceClient& resourceClient = Internal::ThreadLocalStorage::Get().GetResourceClient(); - - Integration::ShaderResourceType shaderRequest(123, "vertex src", "frag src"); - std::string shaderBinaryFile("shader.bin"); - Internal::ResourceTicketPtr ticket = resourceClient.LoadShader(shaderRequest, shaderBinaryFile); - DALI_TEST_CHECK( ticket ); - - application.GetPlatform().SetLoadFileResult( true, buffer ); - application.GetGlAbstraction().EnableShaderCallTrace( true ); - application.GetGlAbstraction().SetLinkStatus(1); - - application.SendNotification(); // Flush update messages - application.Render(); // Process load shader request (immediately) - - application.SendNotification(); - application.Render(); - - application.SendNotification(); - application.Render(); - - // If shader program loads OK, we shouldn't see any calls to CompileShader or SaveResource - TraceCallStack& shaderTrace = application.GetGlAbstraction().GetShaderTrace(); - DALI_TEST_CHECK( ! shaderTrace.FindMethod("CompileShader") ); - - // Ensure no request sent to platform abstraction - DALI_TEST_CHECK( ! application.GetPlatform().WasCalled(TestPlatformAbstraction::SaveResourceFunc ) ); - END_TEST; -} - int UtcDaliInternalAllocateBitmapImage01(void) { TestApplication application; diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.cpp index 51edfdd..fb31688 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.cpp @@ -208,7 +208,7 @@ void TestPlatformAbstraction::SetDpi (unsigned int dpiHorizontal, unsigned int d /** * @copydoc PlatformAbstraction::LoadFile() */ -bool TestPlatformAbstraction::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const +bool TestPlatformAbstraction::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const { mTrace.PushCall("LoadFile", ""); if( mLoadFileResult.loadResult ) @@ -220,11 +220,11 @@ bool TestPlatformAbstraction::LoadFile( const std::string& filename, std::vector } /** - * @copydoc PlatformAbstraction::LoadShaderBinFile() + * @copydoc PlatformAbstraction::LoadShaderBinaryFile() */ -bool TestPlatformAbstraction::LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const +bool TestPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const { - mTrace.PushCall("LoadShaderBinFile", ""); + mTrace.PushCall("LoadShaderBinaryFile", ""); if( mLoadFileResult.loadResult ) { buffer = mLoadFileResult.buffer; @@ -236,7 +236,7 @@ bool TestPlatformAbstraction::LoadShaderBinFile( const std::string& filename, st /** * @copydoc PlatformAbstraction::SaveFile() */ -bool TestPlatformAbstraction::SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const +bool TestPlatformAbstraction::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const { mTrace.PushCall("SaveFile", ""); return false; @@ -359,7 +359,7 @@ void TestPlatformAbstraction::SetClosestImageSize(const Vector2& size) mClosestSize = size; } -void TestPlatformAbstraction::SetLoadFileResult( bool result, std::vector< unsigned char >& buffer ) +void TestPlatformAbstraction::SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer ) { mLoadFileResult.loadResult = result; if( result ) diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.h b/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.h index 6c525fc..fc66701 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.h +++ b/automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.h @@ -68,7 +68,7 @@ public: } bool loadResult; - std::vector< unsigned char> buffer; + Dali::Vector< unsigned char> buffer; }; /** @@ -153,17 +153,22 @@ public: /** * @copydoc PlatformAbstraction::LoadFile() */ - virtual bool LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const; + virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const; /** - * @copydoc PlatformAbstraction::LoadShaderBinFile() + * @copydoc PlatformAbstraction::LoadShaderBinaryFile() */ - virtual bool LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const; + virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const; /** * @copydoc PlatformAbstraction::SaveFile() */ - virtual bool SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const; + virtual bool SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const; + + /** + * @copydoc PlatformAbstraction::SaveShaderBinaryFile() + */ + virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const { return false; } virtual void JoinLoaderThreads(); @@ -222,7 +227,7 @@ public: // TEST FUNCTIONS void SetClosestImageSize(const Vector2& size); - void SetLoadFileResult( bool result, std::vector< unsigned char >& buffer ); + void SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer ); void SetSaveFileResult( bool result ); diff --git a/dali/integration-api/file.list b/dali/integration-api/file.list index 8158523..5c03098 100644 --- a/dali/integration-api/file.list +++ b/dali/integration-api/file.list @@ -7,6 +7,7 @@ platform_abstraction_src_files = \ $(platform_abstraction_src_dir)/debug.cpp \ $(platform_abstraction_src_dir)/profiling.cpp \ $(platform_abstraction_src_dir)/input-options.cpp \ + $(platform_abstraction_src_dir)/shader-data.cpp \ $(platform_abstraction_src_dir)/system-overlay.cpp \ $(platform_abstraction_src_dir)/lockless-buffer.cpp \ $(platform_abstraction_src_dir)/events/event.cpp \ diff --git a/dali/integration-api/platform-abstraction.h b/dali/integration-api/platform-abstraction.h index f2875c5..59a5cbb 100644 --- a/dali/integration-api/platform-abstraction.h +++ b/dali/integration-api/platform-abstraction.h @@ -23,6 +23,7 @@ #include #include ///@todo Remove this include (a bunch of stuff needs to include it though) #include +#include namespace Dali { @@ -212,16 +213,16 @@ public: * @param[out] buffer A buffer to receive the file. * @result true if the file is loaded. */ - virtual bool LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const = 0; + virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const = 0; /** * Load a file into a buffer * @param[in] filename The filename to save * @param[out] buffer A buffer containing some data - * The buffer is implemeneted with a std::vector. The size() member specifies the buffer length. + * The buffer is implemeneted with a Dali::Vector. The size() member specifies the buffer length. * @result true if the file is saved. */ - virtual bool SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const = 0; + virtual bool SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const = 0; /** * Load a shader binary file into a buffer @@ -229,7 +230,16 @@ public: * @param[out] buffer A buffer to receive the file. * @result true if the file is loaded. */ - virtual bool LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const = 0; + virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const = 0; + + /** + * Save a shader binary file to the resource file system. + * @param[in] filename The shader binary filename to save to. + * @param[in] buffer A buffer to write the file from. + * @param[in] numbytes Size of the buffer. + * @result true if the file is saved, else false. + */ + virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const = 0; }; // class PlatformAbstraction diff --git a/dali/integration-api/resource-types.h b/dali/integration-api/resource-types.h index 911da94..1d5182e 100644 --- a/dali/integration-api/resource-types.h +++ b/dali/integration-api/resource-types.h @@ -47,8 +47,7 @@ enum ResourceTypeId { ResourceBitmap, ResourceNativeImage, - ResourceTargetImage, - ResourceShader + ResourceTargetImage }; /** @@ -233,52 +232,6 @@ private: RenderTargetResourceType& operator=(const RenderTargetResourceType& rhs); }; -/** - * ShaderResourceType describes a shader program resource, which can be requested - * from PlatformAbstraction::LoadResource() - */ -struct ShaderResourceType : public ResourceType -{ - /** - * Constructor. - */ - ShaderResourceType(size_t shaderHash, const std::string& vertexSource, const std::string& fragmentSource) - : ResourceType(ResourceShader), - hash(shaderHash), - vertexShader(vertexSource), - fragmentShader(fragmentSource) - { - } - - /** - * Destructor. - */ - virtual ~ShaderResourceType() - { - } - - /** - * @copydoc ResourceType::Clone - */ - virtual ResourceType* Clone() const - { - return new ShaderResourceType(hash, vertexShader, fragmentShader); - } - -public: // Attributes - size_t hash; ///< Hash of the vertex/fragment sources - const std::string vertexShader; ///< source code for vertex program - const std::string fragmentShader; ///< source code for fragment program - -private: - - // Undefined copy constructor. - ShaderResourceType(const ShaderResourceType& typePath); - - // Undefined assignment operator. - ShaderResourceType& operator=(const ShaderResourceType& rhs); -}; - } // namespace Integration } // namespace Dali diff --git a/dali/integration-api/shader-data.cpp b/dali/integration-api/shader-data.cpp new file mode 100644 index 0000000..6bab886 --- /dev/null +++ b/dali/integration-api/shader-data.cpp @@ -0,0 +1,30 @@ +/* + * 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 + +namespace Dali +{ + +namespace Integration +{ + +const size_t ShaderData::UNINITIALISED_HASH_VALUE = size_t(0) - 1; + +} +} diff --git a/dali/integration-api/shader-data.h b/dali/integration-api/shader-data.h index 1775204..b047650 100644 --- a/dali/integration-api/shader-data.h +++ b/dali/integration-api/shader-data.h @@ -2,7 +2,7 @@ #define __DALI_INTEGRATION_SHADER_DATA_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * 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. @@ -23,7 +23,7 @@ // INTERNAL INCLUDES #include -#include +#include #include namespace Dali @@ -38,21 +38,23 @@ typedef IntrusivePtr ShaderDataPtr; /** * ShaderData class. - * A container for shader source code and compiled binary byte code + * A container for shader source code and compiled binary byte code. */ class ShaderData : public Dali::RefObject { public: + + static const size_t UNINITIALISED_HASH_VALUE; + /** * Constructor * @param[in] vertexSource Source code for vertex program * @param[in] fragmentSource Source code for fragment program */ ShaderData(const std::string& vertexSource, const std::string& fragmentSource) - : mShaderHash( 0 ), + : mShaderHash( UNINITIALISED_HASH_VALUE ), mVertexShader(vertexSource), - mFragmentShader(fragmentSource), - mResourceId( 0 ) + mFragmentShader(fragmentSource) { } protected: @@ -73,6 +75,7 @@ public: // API */ void SetHashValue(size_t shaderHash) { + DALI_ASSERT_DEBUG( shaderHash != 0 ); mShaderHash = shaderHash; } @@ -80,15 +83,16 @@ public: // API * Get hash value which is created with vertex and fragment shader code * @return shaderHash hash key created with vertex and fragment shader code */ - size_t GetHashValue() + size_t GetHashValue() const { + DALI_ASSERT_DEBUG( mShaderHash != UNINITIALISED_HASH_VALUE ); return mShaderHash; } /** * @return the vertex shader */ - const char* GetVertexShader() + const char* GetVertexShader() const { return mVertexShader.c_str(); } @@ -96,7 +100,7 @@ public: // API /** * @return the vertex shader */ - const char* GetFragmentShader() + const char* GetFragmentShader() const { return mFragmentShader.c_str(); } @@ -107,7 +111,7 @@ public: // API */ bool HasBinary() const { - return 0 != mBuffer.size(); + return 0 != mBuffer.Size(); } /** @@ -116,19 +120,16 @@ public: // API */ void AllocateBuffer( size_t size ) { - if( size > mBuffer.size() ) - { - mBuffer.resize( size ); - } + mBuffer.Resize( size ); } /** * Get the program buffer * @return reference to the buffer */ - size_t GetBufferSize() + size_t GetBufferSize() const { - return mBuffer.size(); + return mBuffer.Size(); } /** @@ -137,38 +138,19 @@ public: // API */ unsigned char* GetBufferData() { - DALI_ASSERT_DEBUG( mBuffer.size() > 0 ); + DALI_ASSERT_DEBUG( mBuffer.Size() > 0 ); return &mBuffer[0]; } /** * Get the data that the buffer points to - * @TODO TO BE REMOVED WHEN PLATFORM ABSTRACTION FOR SHADER LOAD/STORE IS FIXED * @return raw pointer to the buffer data */ - std::vector& GetBuffer() + Dali::Vector& GetBuffer() { return mBuffer; } - /** - * Set the resource id - * @param resourceId - */ - void SetResourceId( ResourceId resourceId ) - { - mResourceId = resourceId; - } - - /** - * Get the resource id - * @return resourceId - */ - ResourceId GetResourceId() - { - return mResourceId; - } - private: // Not implemented ShaderData(const ShaderData& other); ///< no copying of this object @@ -179,9 +161,7 @@ private: // Data size_t mShaderHash; ///< hash key created with vertex and fragment shader code std::string mVertexShader; ///< source code for vertex program std::string mFragmentShader; ///< source code for fragment program - std::vector mBuffer; ///< buffer containing compiled binary bytecode - ResourceId mResourceId; ///< resource id - + Dali::Vector mBuffer; ///< buffer containing compiled binary bytecode }; } // namespace Integration diff --git a/dali/internal/common/core-impl.cpp b/dali/internal/common/core-impl.cpp index 5d11734..1e9f06c 100644 --- a/dali/internal/common/core-impl.cpp +++ b/dali/internal/common/core-impl.cpp @@ -148,6 +148,8 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform, textureCache, *mTouchResampler ); + mRenderManager->SetShaderSaver( *mUpdateManager ); + mStage = IntrusivePtr( Stage::New( *mAnimationPlaylist, *mPropertyNotificationManager, *mUpdateManager, *mNotificationManager ) ); // This must be called after stage is created but before stage initialization @@ -161,7 +163,8 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform, mEventProcessor = new EventProcessor(*mStage, *mNotificationManager, *mGestureEventProcessor); mImageFactory = new ImageFactory( *mResourceClient ); - mShaderFactory = new ShaderFactory(*mResourceClient); + mShaderFactory = new ShaderFactory(); + mUpdateManager->SetShaderSaver( *mShaderFactory ); mShaderFactory->LoadDefaultShaders(); GetImplementation(Dali::TypeRegistry::Get()).CallInitFunctions(); diff --git a/dali/internal/common/shader-saver.h b/dali/internal/common/shader-saver.h new file mode 100644 index 0000000..1083282 --- /dev/null +++ b/dali/internal/common/shader-saver.h @@ -0,0 +1,64 @@ +#ifndef __DALI_INTERNAL_SHADER_DISPATCHER_H__ +#define __DALI_INTERNAL_SHADER_DISPATCHER_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 + +// EXTERNAL INCLUDES + + +namespace Dali +{ + +namespace Integration +{ +class ShaderData; +typedef IntrusivePtr ShaderDataPtr; +} + +namespace Internal +{ + +/** + * Abstract interface for passing a ShaderData object towards being saved. + */ +class ShaderSaver +{ +public: + + /** + * A function saving the binary from a ShaderDataPtr or passing it on to where it can be saved. + * @param[in] shaderData A smart pointer to a ShaderData for which the program binary should be saved. + */ + virtual void SaveBinary( Integration::ShaderDataPtr shaderData ) = 0; + +protected: + /** + * Destructor. Protected as no derived class should ever be deleted + * through a reference to this pure abstract interface. + */ + virtual ~ShaderSaver(){} +}; + +} // namespace Internal + +} // namespace Dali + +#endif // __DALI_INTERNAL_SHADER_DISPATCHER_H__ diff --git a/dali/internal/event/effects/shader-effect-impl.cpp b/dali/internal/event/effects/shader-effect-impl.cpp index 0d4dae5..688196b 100644 --- a/dali/internal/event/effects/shader-effect-impl.cpp +++ b/dali/internal/event/effects/shader-effect-impl.cpp @@ -292,14 +292,11 @@ void ShaderEffect::SendProgramMessage( const string& vertexSource, const string& ShaderFactory& shaderFactory = tls.GetShaderFactory(); size_t shaderHash; - ResourceTicketPtr ticket( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) ); - - DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(ticket.id:%d)\n", ticket->GetId() ); + Integration::ShaderDataPtr shaderData = shaderFactory.Load( vertexSource, fragmentSource, shaderHash ); + DALI_ASSERT_DEBUG( shaderHash != 0U ); // Add shader program to scene-object using a message to the UpdateManager - SetShaderProgramMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject, ticket->GetId(), shaderHash, modifiesGeometry ); - - mTickets.push_back(ticket); // add ticket to collection to keep it alive. + SetShaderProgramMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject, shaderData, false ); } void ShaderEffect::Connect() diff --git a/dali/internal/event/effects/shader-effect-impl.h b/dali/internal/event/effects/shader-effect-impl.h index 9f80091..2ccc768 100644 --- a/dali/internal/event/effects/shader-effect-impl.h +++ b/dali/internal/event/effects/shader-effect-impl.h @@ -207,7 +207,6 @@ private: // Data EventThreadServices& mEventThreadServices; ///< Event thread services, for sending messages SceneGraph::Shader* mSceneObject; ///< pointer to the scene shader, should not be changed on this thread Dali::Image mImage; ///< Client-side handle for the effect image - std::vector mTickets; ///< Collection of shader program tickets unsigned int mConnectionCount; ///< number of on-stage ImageActors using this shader effect Dali::ShaderEffect::GeometryHints mGeometryHints; ///< shader geometry hints for building the geometry Dali::Vector< UniformCoordinateType > mCoordinateTypes; ///< cached to avoid sending tons of unnecessary messages diff --git a/dali/internal/event/effects/shader-factory.cpp b/dali/internal/event/effects/shader-factory.cpp index f276ef6..88ef6ed 100644 --- a/dali/internal/event/effects/shader-factory.cpp +++ b/dali/internal/event/effects/shader-factory.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -52,66 +54,104 @@ namespace Dali namespace Internal { -ShaderFactory::ShaderFactory(ResourceClient& resourceClient) -: mResourceClient(resourceClient) +namespace { + +/** + * @brief Generates a filename for a shader binary based on the hash value passed in. + * @param[in] shaderHash A hash over shader sources. + * @param[out] filename A string to overwrite with the filename. + */ +void shaderBinaryFilename( size_t shaderHash, std::string& filename ) +{ + std::stringstream binaryShaderFilenameBuilder( std::ios_base::out ); + binaryShaderFilenameBuilder << CORE_MAJOR_VERSION << VERSION_SEPARATOR << CORE_MINOR_VERSION << VERSION_SEPARATOR << CORE_MICRO_VERSION << VERSION_SEPARATOR + << shaderHash + << SHADER_SUFFIX; + filename = binaryShaderFilenameBuilder.str(); } -ShaderFactory::~ShaderFactory() +} + +ShaderFactory::ShaderFactory() { } -ResourceTicketPtr ShaderFactory::Load(const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash) +ShaderFactory::~ShaderFactory() { - ResourceTicketPtr ticket; - - shaderHash = CalculateHash(vertexSource, fragmentSource); - std::stringstream stringHash; - stringHash << CORE_MAJOR_VERSION << VERSION_SEPARATOR << CORE_MINOR_VERSION << VERSION_SEPARATOR << CORE_MICRO_VERSION << VERSION_SEPARATOR; - stringHash << shaderHash; - std::string filename; - filename.append( stringHash.str() ); - filename.append( SHADER_SUFFIX ); - - ShaderResourceType resourceType(shaderHash, vertexSource, fragmentSource); - ResourceTypePath typePath(resourceType, filename); - - // Search for a matching resource - ResourceTypePathIdIter iter = mResourceTypePathIdMap.end(); - if ( !mResourceTypePathIdMap.empty() ) + // Let all the cached objects destroy themselves: + for( int i = 0, cacheSize = mShaderBinaryCache.Size(); i < cacheSize; ++i ) { - iter = mResourceTypePathIdMap.find( typePath ); + if( mShaderBinaryCache[i] ) + { + mShaderBinaryCache[i]->Unreference(); + } } +} - if ( mResourceTypePathIdMap.end() != iter ) - { - // The resource was previously requested - unsigned int resourceId = iter->second; +ShaderDataPtr ShaderFactory::Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash ) +{ + // Work out the filename for the binary that the glsl source will be compiled and linked to: + shaderHash = CalculateHash( vertexSource.c_str(), fragmentSource.c_str() ); + std::string binaryShaderFilename; + shaderBinaryFilename( shaderHash, binaryShaderFilename ); - // The ticket may still be alive, request another copy - ticket = mResourceClient.RequestResourceTicket( resourceId ); + ShaderDataPtr shaderData; - // Clean-up the map of resource IDs, if the ticket has been discarded - if ( !ticket ) - { - mResourceTypePathIdMap.erase( iter ); - } - else + /// Check a cache of previously loaded shaders: + for( int i = 0, cacheSize = mShaderBinaryCache.Size(); i < cacheSize; ++i ) + { + if( mShaderBinaryCache[i]->GetHashValue() == shaderHash ) { - DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ShaderFactory::Load filename= %s already requested to Load\n", filename.c_str()); + shaderData = mShaderBinaryCache[i]; + + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Mem cache hit on path: \"%s\"\n", binaryShaderFilename.c_str() ); + break; } } - if ( !ticket ) + // If memory cache failed check the file system for a binary or return a source-only ShaderData: + if( shaderData.Get() == NULL ) { - // Load the shader (loaded synchronously in Update thread so its ready by the time the set shader message is processed) - ticket = mResourceClient.LoadShader(resourceType, filename); - DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ShaderFactory::Load Ticket ID:%d, path: \"%s\"\n", ticket->GetId(), filename.c_str()); + // Allocate the structure that returns the loaded shader: + shaderData = new ShaderData( vertexSource, fragmentSource ); + shaderData->SetHashValue( shaderHash ); + shaderData->GetBuffer().Clear(); - mResourceTypePathIdMap.insert( ResourceTypePathIdPair( typePath, ticket->GetId() ) ); + // Try to load the binary (this will fail if the shader source has never been compiled before): + ThreadLocalStorage& tls = ThreadLocalStorage::Get(); + Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction(); + const bool loaded = platformAbstraction.LoadShaderBinaryFile( binaryShaderFilename, shaderData->GetBuffer() ); + + if( loaded ) + { + MemoryCacheInsert( *shaderData ); + } + + DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, loaded ? + "loaded on path: \"%s\"\n" : + "failed to load on path: \"%s\"\n", + binaryShaderFilename.c_str()); } - return ticket; + return shaderData; +} + +void ShaderFactory::SaveBinary( Integration::ShaderDataPtr shaderData ) +{ + // Save the binary to the file system: + std::string binaryShaderFilename; + shaderBinaryFilename( shaderData->GetHashValue(), binaryShaderFilename ); + + ThreadLocalStorage& tls = ThreadLocalStorage::Get(); + Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction(); + const bool saved = platformAbstraction.SaveShaderBinaryFile( binaryShaderFilename, &shaderData->GetBuffer()[0], shaderData->GetBufferSize() ); + + // Save the binary into to memory cache: + MemoryCacheInsert( *shaderData ); + + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, saved ? "Saved to file: %s\n" : "Save to file failed: %s\n", binaryShaderFilename.c_str() ); + if( saved ) {} // Avoid unused variable warning in release builds } void ShaderFactory::LoadDefaultShaders() @@ -121,6 +161,20 @@ void ShaderFactory::LoadDefaultShaders() mDefaultShader->SendProgramMessage( ImageVertex, ImageFragment, false ); } +void ShaderFactory::MemoryCacheInsert( ShaderData& shaderData ) +{ + DALI_ASSERT_DEBUG( shaderData.GetBufferSize() > 0 ); + + // Save the binary into to memory cache: + if( shaderData.GetBufferSize() > 0 ) + { + mShaderBinaryCache.Reserve( mShaderBinaryCache.Size() + 1 ); // Make sure the push won't throw after we inc the ref count. + shaderData.Reference(); + mShaderBinaryCache.PushBack( &shaderData ); + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "CACHED BINARY FOR HASH: %u\n", shaderData.GetHashValue() ); + } +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/effects/shader-factory.h b/dali/internal/event/effects/shader-factory.h index fd5a07f..29fd221 100644 --- a/dali/internal/event/effects/shader-factory.h +++ b/dali/internal/event/effects/shader-factory.h @@ -19,12 +19,21 @@ */ // INTERNAL INCLUDES +#include #include -#include #include +#include +#include namespace Dali { +namespace Integration +{ + +class ShaderData; +typedef IntrusivePtr ShaderDataPtr; + +} namespace Internal { @@ -33,35 +42,49 @@ class ResourceClient; class MessageController; /** - * ShaderFactory is an object that manages shader binary resource load requests, + * ShaderFactory is an object which manages shader binary resource load requests, * It triggers the load requests during core initialization and sends a message to the - * render manager with information about all the requested shader binaries and their - * request Id. + * render manager with information about all the requested shader binaries. */ -class ShaderFactory +class ShaderFactory : public ShaderSaver { public: /** * Default constructor */ - ShaderFactory(ResourceClient& resourceClient); + ShaderFactory(); /** * Destructor */ - ~ShaderFactory(); + virtual ~ShaderFactory(); /** - * Issues a request to load a binary version of a shader program, and returns a resource ticket - * If a request for an identical shader has already been made, the ticket for the older request - * is shared. + * @brief Looks for precompiled binary version of shader program in memory and file caches. + * + * Tries to load a binary version of a shader program identified by a hash over the two source + * files, checking an in-memory cache first. + * If the cache hits or the load succeeds, the buffer member of the returned ShaderData will + * contain a precompiled shader binary program which can be uploaded directly to GLES. + * * @param [in] vertexSource The vertex shader source code * @param [in] fragmentSource The fragment shader source code - * @param [out] shaderHash hash key created with vertex and fragment shader code - * @return A ticket for the resource + * @param [out] shaderHash Hash key created from vertex and fragment shader code + * @return ShaderData containing the source and hash value, and additionally, + * a compiled shader program binary if one could be found, else an + * empty binary buffer cleared to size zero. */ - ResourceTicketPtr Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash ); + Integration::ShaderDataPtr Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash ); + + /** + * @brief Saves shader to memory cache and filesystem. + * This is called when a shader binary is ready to be saved to the memory cache file system. + * Shaders that pass through here become available to subsequent invocations of Load. + * @param[in] shader The data to be saved. + * @sa Load + */ + virtual void SaveBinary( Integration::ShaderDataPtr shader ); /** * Called during Core initialization to load the default shader. @@ -70,6 +93,8 @@ public: private: + void MemoryCacheInsert( Integration::ShaderData& shaderData ); + // Undefined ShaderFactory( const ShaderFactory& ); @@ -77,12 +102,18 @@ private: ShaderFactory& operator=( const ShaderFactory& rhs ); private: - ResourceClient& mResourceClient; - ResourceTypePathIdMap mResourceTypePathIdMap; ///< A map of resource IDs sorted by ResourceTypePath - ShaderEffectPtr mDefaultShader; + ShaderEffectPtr mDefaultShader; + Dali::Vector< Integration::ShaderData* > mShaderBinaryCache; ///< Cache of pre-compiled shaders. }; // class ShaderFactory +inline MessageBase* ShaderCompiledMessage( ShaderSaver& factory, Integration::ShaderDataPtr shaderData ) +{ + return new MessageValue1< ShaderSaver, Integration::ShaderDataPtr >( &factory, + &ShaderSaver::SaveBinary, + shaderData ); +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/images/image-factory.h b/dali/internal/event/images/image-factory.h index a72016f..4f235ed 100644 --- a/dali/internal/event/images/image-factory.h +++ b/dali/internal/event/images/image-factory.h @@ -20,7 +20,6 @@ // INTERNAL INCLUDES #include -#include #include #include #include diff --git a/dali/internal/event/rendering/shader-impl.cpp b/dali/internal/event/rendering/shader-impl.cpp index 4760d5f..d9398bd 100644 --- a/dali/internal/event/rendering/shader-impl.cpp +++ b/dali/internal/event/rendering/shader-impl.cpp @@ -272,20 +272,19 @@ void Shader::Initialize( } Dali::ShaderEffect::GeometryHints shaderEffectHint = static_cast( effectHint ); - mSceneObject = new SceneGraph::Shader(shaderEffectHint); + mSceneObject = new SceneGraph::Shader( shaderEffectHint ); // Add to update manager AddShaderMessage( updateManager, *mSceneObject ); + // Try to load a precompiled shader binary for the source pair: ThreadLocalStorage& tls = ThreadLocalStorage::Get(); ShaderFactory& shaderFactory = tls.GetShaderFactory(); size_t shaderHash; - - mTicket = ResourceTicketPtr( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) ); + Integration::ShaderDataPtr shaderData = shaderFactory.Load( vertexSource, fragmentSource, shaderHash ); // Add shader program to scene-object using a message to the UpdateManager - SetShaderProgramMessage( updateManager, *mSceneObject, mTicket->GetId(), shaderHash, false ); - + SetShaderProgramMessage( updateManager, *mSceneObject, shaderData, false ); eventThreadServices.RegisterObject( this ); } diff --git a/dali/internal/event/rendering/shader-impl.h b/dali/internal/event/rendering/shader-impl.h index d70992f..f71289d 100644 --- a/dali/internal/event/rendering/shader-impl.h +++ b/dali/internal/event/rendering/shader-impl.h @@ -179,7 +179,6 @@ private: // unimplemented methods private: SceneGraph::Shader* mSceneObject; - ResourceTicketPtr mTicket; bool mOnStage; }; diff --git a/dali/internal/event/resources/resource-client.cpp b/dali/internal/event/resources/resource-client.cpp index 31c8f9f..c5ec4da 100644 --- a/dali/internal/event/resources/resource-client.cpp +++ b/dali/internal/event/resources/resource-client.cpp @@ -119,7 +119,6 @@ ResourceTicketPtr ResourceClient::RequestResource( break; } case ResourceTargetImage: - case ResourceShader: { newTicket = new ResourceTicket(*this, newId, typePath); break; @@ -165,7 +164,6 @@ ResourceTicketPtr ResourceClient::DecodeResource( // FALLTHROUGH: case ResourceNativeImage: case ResourceTargetImage: - case ResourceShader: { DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." ); } @@ -182,24 +180,6 @@ ResourceTicketPtr ResourceClient::DecodeResource( return newTicket; } -ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type, - const std::string& path ) -{ - ResourceTicketPtr newTicket; - - const ResourceId newId = ++(mImpl->mNextId); - - ResourceTypePath typePath(type, path); - newTicket = new ResourceTicket(*this, newId, typePath); - - mImpl->mTickets.insert(TicketPair(newId, newTicket.Get())); - - DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId); - - RequestLoadShaderMessage( mEventThreadServices, mResourceManager, newId, typePath ); - return newTicket; -} - bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority ) { DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id); diff --git a/dali/internal/event/resources/resource-client.h b/dali/internal/event/resources/resource-client.h index 303fa44..c4b7123 100644 --- a/dali/internal/event/resources/resource-client.h +++ b/dali/internal/event/resources/resource-client.h @@ -121,14 +121,6 @@ public: Integration::LoadResourcePriority priority = Integration::LoadPriorityNormal ); /** - * Load a shader program from a file - * @param[in] type A ResourceType specialization describing a shader program resource - * @param[in] filename The file's full path/file name - * @return A ref-counted request object. Keep a copy until the resource is no longer required. - */ - ResourceTicketPtr LoadShader(Integration::ShaderResourceType& type, const std::string& filename); - - /** * Request reloading a resource from the native filesystem. * If the resource is still loading, this request is ignored. * The ticket observer will be notified of completion with ResourceLoadingSucceeded() or @@ -143,7 +135,7 @@ public: /** * Save a resource to the given url. - * If the resource type is saveable (model or shader), then the ticket observer will get + * If the resource type is saveable (model), then the ticket observer will get * notified with ResourceSavingSucceeded() or ResourceSavingFailed(), otherwise there * will be no response. * @param[in] ticket The ticket of the resource to save diff --git a/dali/internal/event/resources/resource-type-path-id-map.h b/dali/internal/event/resources/resource-type-path-id-map.h deleted file mode 100644 index 8c8bab3..0000000 --- a/dali/internal/event/resources/resource-type-path-id-map.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__ -#define __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_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. - * - */ - -// INTERNAL INCLUDES -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -///< A map of resource IDs sorted by ResourceTypePath -typedef std::map ResourceTypePathIdMap; -typedef ResourceTypePathIdMap::iterator ResourceTypePathIdIter; -typedef ResourceTypePathIdMap::size_type ResourceTypePathIdSize; -typedef std::pair ResourceTypePathIdPair; - -} // namespace Internal - -} // namespace Dali - -#endif // __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__ diff --git a/dali/internal/event/resources/resource-type-path.cpp b/dali/internal/event/resources/resource-type-path.cpp index e856895..1204e81 100644 --- a/dali/internal/event/resources/resource-type-path.cpp +++ b/dali/internal/event/resources/resource-type-path.cpp @@ -116,23 +116,6 @@ int ResourceTypeCompare(const ResourceType& lhs, const ResourceType& rhs) // else result = 0 break; } - - case ResourceShader: - { - // compare shader source hashes - const ShaderResourceType& lhsShader = static_cast(lhs); - const ShaderResourceType& rhsShader = static_cast(rhs); - - if (lhsShader.hash != rhsShader.hash) - { - result = lhsShader.hash < rhsShader.hash ? -1 : 1; - } - // else result = 0 - break; - } - - - } } return result; diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index 8d6446d..35954a9 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -102,7 +102,7 @@ struct RenderManager::Impl renderersAdded( false ), firstRenderCompleted( false ), defaultShader( NULL ), - programController( postProcessDispatcher, glAbstraction ) + programController( glAbstraction ) { } @@ -232,6 +232,11 @@ void RenderManager::DispatchPostProcessRequest(ResourcePostProcessRequest& reque mImpl->resourcePostProcessQueue[ mImpl->renderBufferIndex ].push_back( request ); } +void RenderManager::SetShaderSaver( ShaderSaver& upstream ) +{ + mImpl->programController.SetShaderSaver( upstream ); +} + RenderInstructionContainer& RenderManager::GetRenderInstructionContainer() { return mImpl->instructions; diff --git a/dali/internal/render/common/render-manager.h b/dali/internal/render/common/render-manager.h index 5ec8b0d..d716d43 100644 --- a/dali/internal/render/common/render-manager.h +++ b/dali/internal/render/common/render-manager.h @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -39,6 +40,7 @@ namespace Internal { class Context; class ProgramCache; +class ShaderSaver; namespace SceneGraph { @@ -99,7 +101,15 @@ public: * Dispatch requests onto the postProcessResourcesQueue * @param[in] request The request to dispatch */ - virtual void DispatchPostProcessRequest(ResourcePostProcessRequest& request); + virtual void DispatchPostProcessRequest( ResourcePostProcessRequest& request ); + + /** + * Set the upstream interface for compiled shader binaries to be sent back to for eventual + * caching and saving. + * @param[in] upstream The abstract interface to send any received ShaderDatas onwards to.. + * @note This should be called during core initialisation if shader binaries are to be used. + */ + void SetShaderSaver( ShaderSaver& upstream ); /** * Retrieve the render instructions; these should be set during each "update" traversal. diff --git a/dali/internal/render/gl-resources/bitmap-texture.cpp b/dali/internal/render/gl-resources/bitmap-texture.cpp index cd17e17..cbabab6 100644 --- a/dali/internal/render/gl-resources/bitmap-texture.cpp +++ b/dali/internal/render/gl-resources/bitmap-texture.cpp @@ -169,7 +169,10 @@ void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pix mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight ); + if( pixels != NULL ) + { + INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight ); + } } void BitmapTexture::Update( Integration::Bitmap* bitmap ) @@ -322,11 +325,11 @@ bool BitmapTexture::CreateGlTexture() else { const unsigned char* pixels = NULL; - std::vector pixelData; - if( ( NULL == pixels ) && ( true == mClearPixels ) ) + Dali::Vector pixelData; // Okay to create outside branch as empty vector has no heap allocation. + if( true == mClearPixels ) { - unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel(mPixelFormat); - pixelData.resize(size, 0); + unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel( mPixelFormat ); + pixelData.Resize( size, 0 ); pixels = &pixelData[0]; } AssignBitmap( true, pixels ); diff --git a/dali/internal/render/shaders/program-controller.cpp b/dali/internal/render/shaders/program-controller.cpp index 949e2d4..e4163db 100644 --- a/dali/internal/render/shaders/program-controller.cpp +++ b/dali/internal/render/shaders/program-controller.cpp @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -31,8 +32,8 @@ namespace Dali namespace Internal { -ProgramController::ProgramController( SceneGraph::PostProcessResourceDispatcher& postProcessDispatcher, Integration::GlAbstraction& glAbstraction ) -: mPostProcessDispatcher( postProcessDispatcher ), +ProgramController::ProgramController( Integration::GlAbstraction& glAbstraction ) +: mShaderSaver( 0 ), mGlAbstraction( glAbstraction ), mCurrentProgram( NULL ), mProgramBinaryFormat( 0 ), @@ -142,8 +143,19 @@ unsigned int ProgramController::ProgramBinaryFormat() void ProgramController::StoreBinary( Integration::ShaderDataPtr programData ) { - ResourcePostProcessRequest request( programData->GetResourceId(), ResourcePostProcessRequest::SAVE ); - mPostProcessDispatcher.DispatchPostProcessRequest( request ); + DALI_ASSERT_DEBUG( programData->GetBufferSize() > 0 ); + DALI_ASSERT_DEBUG( programData->GetHashValue() != 0 ); + DALI_ASSERT_DEBUG( mShaderSaver && "SetShaderSaver() should have been called during startup." ); + + if( mShaderSaver != NULL ) + { + mShaderSaver->SaveBinary( programData ); + } +} + +void ProgramController::SetShaderSaver( ShaderSaver& shaderSaver ) +{ + mShaderSaver = &shaderSaver; } } // namespace Internal diff --git a/dali/internal/render/shaders/program-controller.h b/dali/internal/render/shaders/program-controller.h index 6ce57f9..8dedd95 100644 --- a/dali/internal/render/shaders/program-controller.h +++ b/dali/internal/render/shaders/program-controller.h @@ -29,10 +29,7 @@ namespace Dali namespace Internal { -namespace SceneGraph -{ -class PostProcessResourceDispatcher; -} +class ShaderSaver; /** * This class is the owner of GL shader programs @@ -96,7 +93,7 @@ public: * Constructor * @param postProcessDispatcher to send save binary message back to update */ - ProgramController( SceneGraph::PostProcessResourceDispatcher& postProcessDispatcher, Integration::GlAbstraction& glAbstraction ); + ProgramController( Integration::GlAbstraction& glAbstraction ); /** * Destructor, non virtual as not a base class @@ -120,6 +117,12 @@ public: // API */ void GlContextDestroyed(); + /** + * Set the destination for compiler shader binaries so they can be saved. + * @note Must be called during initialisation. + */ + void SetShaderSaver( ShaderSaver& shaderSaver ); + private: // From ProgramCache /** @@ -169,7 +172,7 @@ private: // not implemented as non-copyable private: // Data - SceneGraph::PostProcessResourceDispatcher& mPostProcessDispatcher; + ShaderSaver* mShaderSaver; Integration::GlAbstraction& mGlAbstraction; Program* mCurrentProgram; diff --git a/dali/internal/render/shaders/program.cpp b/dali/internal/render/shaders/program.cpp index dbfc298..6957698 100644 --- a/dali/internal/render/shaders/program.cpp +++ b/dali/internal/render/shaders/program.cpp @@ -486,6 +486,7 @@ Program::~Program() void Program::Load() { DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" ); + DALI_ASSERT_DEBUG( mProgramId == 0 && "mProgramId != 0, so about to leak a GL resource by overwriting it." ); LOG_GL( "CreateProgram()\n" ); mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() ); @@ -527,6 +528,7 @@ void Program::Load() else { mLinked = true; + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Reused binary.\n" ); } } @@ -544,6 +546,7 @@ void Program::Load() { GLint binaryLength = 0; GLenum binaryFormat; + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Compiled and linked.\n\nVS:\n%s\nFS:\n%s\n", mProgramData->GetVertexShader(), mProgramData->GetFragmentShader() ); CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) ); DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength); @@ -554,6 +557,7 @@ void Program::Load() // Copy the bytecode to ShaderData CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) ); mCache.StoreBinary( mProgramData ); + DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Saved binary.\n" ); } } } diff --git a/dali/internal/render/shaders/scene-graph-shader.cpp b/dali/internal/render/shaders/scene-graph-shader.cpp index 74f78a4..e9b5c14 100644 --- a/dali/internal/render/shaders/scene-graph-shader.cpp +++ b/dali/internal/render/shaders/scene-graph-shader.cpp @@ -214,6 +214,16 @@ void Shader::SetProgram( Integration::ResourceId resourceId, // The program cache owns the Program object so we don't need to worry here. } +void Shader::SetProgram( Integration::ShaderDataPtr shaderData, + ProgramCache* programCache, + bool modifiesGeometry ) +{ + DALI_LOG_TRACE_METHOD_FMT( Debug::Filter::gShader, "%d\n", shaderData->GetHashValue() ); + + mProgram = Program::New( *programCache, shaderData, modifiesGeometry ); + // The program cache owns the Program object so we don't need to worry about this raw allocation here. +} + Program* Shader::GetProgram() { return mProgram; diff --git a/dali/internal/render/shaders/scene-graph-shader.h b/dali/internal/render/shaders/scene-graph-shader.h index 83a65b0..7a21a71 100644 --- a/dali/internal/render/shaders/scene-graph-shader.h +++ b/dali/internal/render/shaders/scene-graph-shader.h @@ -48,7 +48,6 @@ typedef unsigned int ResourceId; namespace Internal { -class ProgramController; class Program; namespace SceneGraph @@ -238,10 +237,10 @@ public: void SetCoordinateTypeInRender( unsigned int index, Dali::ShaderEffect::UniformCoordinateType type ); /** - * @brief Set the program for a geometry type. + * @brief Set the program for this shader. * @param[in] resourceId The resource ID for the program. - * @param[in] shaderData The program's vertex/fragment source and optionally compiled bytecode - * @param[in] programCache Owner of the Programs + * @param[in] shaderData The program's vertex/fragment source and optionally precompiled shader binary. + * @param[in] programCache Owner of the Programs. * @param[in] modifiesGeometry True if the vertex shader changes the positions of vertexes such that * they might exceed the bounding box of vertexes passing through the default transformation. */ @@ -251,6 +250,17 @@ public: bool modifiesGeometry ); /** + * @brief Set the program for this shader. + * @param[in] shaderData The program's vertex/fragment source and optionally precompiled shader binary. + * @param[in] programCache Owner of the Programs. + * @param[in] modifiesGeometry True if the vertex shader changes the positions of vertexes such that + * they might exceed the bounding box of vertexes passing through the default transformation. + */ + void SetProgram( Integration::ShaderDataPtr shaderData, + ProgramCache* programCache, + bool modifiesGeometry ); + + /** * Get the program built for this shader * @return The program built from the shader sources. */ diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 866f4bc..bdae788 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -130,6 +131,9 @@ typedef OwnerContainer< Shader* > ShaderContainer; typedef ShaderContainer::Iterator ShaderIter; typedef ShaderContainer::ConstIterator ShaderConstIter; +typedef std::vector ShaderDataBatchedQueue; +typedef ShaderDataBatchedQueue::iterator ShaderDataBatchedQueueIterator; + typedef OwnerContainer GestureContainer; typedef GestureContainer::Iterator GestureIter; typedef GestureContainer::ConstIterator GestureConstIter; @@ -157,6 +161,7 @@ struct UpdateManager::Impl notificationManager( notificationManager ), animationFinishedNotifier( animationFinishedNotifier ), propertyNotifier( propertyNotifier ), + shaderSaver( NULL ), resourceManager( resourceManager ), discardQueue( discardQueue ), renderController( renderController ), @@ -238,6 +243,7 @@ struct UpdateManager::Impl NotificationManager& notificationManager; ///< Queues notification messages for the event-thread. CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished. PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified. + ShaderSaver* shaderSaver; ///< Saves shader binaries. ResourceManager& resourceManager; ///< resource manager DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph. RenderController& renderController; ///< render controller @@ -275,6 +281,7 @@ struct UpdateManager::Impl ShaderContainer shaders; ///< A container of owned shaders MessageQueue messageQueue; ///< The messages queued from the event-thread + ShaderDataBatchedQueue compiledShaders[2]; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread. float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update() @@ -603,28 +610,28 @@ void UpdateManager::RemoveShader( Shader* shader ) } void UpdateManager::SetShaderProgram( Shader* shader, - ResourceId resourceId, size_t shaderHash, bool modifiesGeometry ) + Integration::ShaderDataPtr shaderData, bool modifiesGeometry ) { - DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, " - (id:%d hash:%d)\n", resourceId, shaderHash); - - DALI_ASSERT_ALWAYS( NULL != shader && "shader is uninitialized" ); - - Integration::ShaderDataPtr shaderData( mImpl->resourceManager.GetShaderData(resourceId) ); if( shaderData ) { - shaderData->SetHashValue( shaderHash ); - shaderData->SetResourceId( resourceId ); - typedef MessageValue4< Shader, Integration::ResourceId, Integration::ShaderDataPtr, ProgramCache*, bool> DerivedType; + typedef MessageValue3< Shader, Integration::ShaderDataPtr, ProgramCache*, bool> DerivedType; // Reserve some memory inside the render queue unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) ); // Construct message in the render queue memory; note that delete should not be called on the return value - new (slot) DerivedType( shader, &Shader::SetProgram, resourceId, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry ); + new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry ); } } +void UpdateManager::SaveBinary( Integration::ShaderDataPtr shaderData ) +{ + DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." ); + DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." ); + mImpl->compiledShaders[mSceneGraphBuffers.GetUpdateBufferIndex() > 0 ? 0 : 1].push_back( shaderData ); +} + RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel ) { if ( !systemLevel ) @@ -907,6 +914,25 @@ void UpdateManager::ProcessPropertyNotifications() } } +void UpdateManager::ForwardCompiledShadersToEventThread() +{ + DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." ); + if( mImpl->shaderSaver ) + { + ShaderDataBatchedQueue& compiledShaders = mImpl->compiledShaders[mSceneGraphBuffers.GetUpdateBufferIndex()]; + if( compiledShaders.size() > 0 ) + { + ShaderSaver& factory = *mImpl->shaderSaver; + ShaderDataBatchedQueueIterator i = compiledShaders.begin(); + ShaderDataBatchedQueueIterator end = compiledShaders.end(); + for( ; i != end; ++i ) + { + mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) ); + } + } + } +} + void UpdateManager::UpdateNodes() { mImpl->nodeDirtyFlags = NothingFlag; @@ -983,6 +1009,9 @@ unsigned int UpdateManager::Update( float elapsedSeconds, // 6) Post Process Ids of resources updated by renderer mImpl->resourceManager.PostProcessResources( bufferIndex ); + // 6.1) Forward a batch of compiled shader programs to event thread for saving + ForwardCompiledShadersToEventThread(); + // Although the scene-graph may not require an update, we still need to synchronize double-buffered // renderer lists if the scene was updated in the previous frame. // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes @@ -1174,6 +1203,11 @@ void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool syst } } +void UpdateManager::SetShaderSaver( ShaderSaver& upstream ) +{ + mImpl->shaderSaver = &upstream; +} + } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 1f6e632..10bbfcf 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -84,7 +85,7 @@ class RendererAttachment; * It also maintains the lifecycle of nodes and other property owners that are * disconnected from the scene graph. */ -class UpdateManager +class UpdateManager : public ShaderSaver { public: @@ -115,9 +116,9 @@ public: TouchResampler& touchResampler ); /** - * Destructor. Not virtual as this is not a base class + * Destructor. */ - ~UpdateManager(); + virtual ~UpdateManager(); // Node connection methods @@ -305,11 +306,25 @@ public: /** * Set the shader program for a Shader object * @param[in] shader The shader to modify - * @param[in] resourceId A ResourceManager ticket ID for the program data (source and compiled binary) - * @param[in] shaderHash hash key created with vertex and fragment shader code + * @param[in] shaderData Source code, hash over source, and optional compiled binary for the shader program * @param[in] modifiesGeometry True if the vertex shader modifies geometry */ - void SetShaderProgram( Shader* shader, Integration::ResourceId resourceId, size_t shaderHash, bool modifiesGeometry ); + void SetShaderProgram( Shader* shader, Integration::ShaderDataPtr shaderData, bool modifiesGeometry ); + + /** + * @brief Accept compiled shaders passed back on render thread for saving. + * @param[in] shaderData Source code, hash over source, and corresponding compiled binary to be saved. + */ + virtual void SaveBinary( Integration::ShaderDataPtr shaderData ); + + /** + * @brief Set the destination for compiled shader binaries to be passed on to. + * The dispatcher passed in will be called from the update thread. + * @param[in] upstream A sink for ShaderDatas to be passed into. + */ + void SetShaderSaver( ShaderSaver& upstream ); + + // Gestures /** * Add a newly created gesture. @@ -461,6 +476,11 @@ private: void ProcessPropertyNotifications(); /** + * Pass shader binaries queued here on to event thread. + */ + void ForwardCompiledShadersToEventThread(); + + /** * Update the default camera. * This must be altered to match the root Node for 2D layouting. * @param[in] updateBuffer The buffer to read the root node size from. @@ -678,8 +698,6 @@ inline void PropertyNotificationSetNotifyModeMessage( UpdateManager& manager, new (slot) LocalType( &manager, &UpdateManager::PropertyNotificationSetNotify, propertyNotification, notifyMode ); } - - // The render thread can safely change the Shader inline void AddShaderMessage( UpdateManager& manager, Shader& shader ) { @@ -706,17 +724,16 @@ inline void RemoveShaderMessage( UpdateManager& manager, Shader& shader ) inline void SetShaderProgramMessage( UpdateManager& manager, Shader& shader, - Integration::ResourceId resourceId, - size_t shaderHash, + Integration::ShaderDataPtr shaderData, bool modifiesGeometry ) { - typedef MessageValue4< UpdateManager, Shader*, Integration::ResourceId, size_t, bool > LocalType; + typedef MessageValue3< UpdateManager, Shader*, Integration::ShaderDataPtr, bool > LocalType; // Reserve some memory inside the message queue unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) ); // Construct message in the message queue memory; note that delete should not be called on the return value - new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, resourceId, shaderHash, modifiesGeometry ); + new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, shaderData, modifiesGeometry ); } inline void SetBackgroundColorMessage( UpdateManager& manager, const Vector4& color ) diff --git a/dali/internal/update/resources/resource-manager.cpp b/dali/internal/update/resources/resource-manager.cpp index acbb558..5c558de 100644 --- a/dali/internal/update/resources/resource-manager.cpp +++ b/dali/internal/update/resources/resource-manager.cpp @@ -69,10 +69,6 @@ typedef std::map BitmapMetadataCache; typedef BitmapMetadataCache::iterator BitmapMetadataIter; typedef std::pair BitmapMetadataPair; -typedef std::map ShaderCache; -typedef ShaderCache::iterator ShaderCacheIter; -typedef ShaderCache::size_type ShaderCacheSize; -typedef std::pair ShaderDataPair; static inline bool RemoveId( LiveRequestContainer& container, ResourceId id ) { @@ -141,7 +137,6 @@ struct ResourceManager::ResourceManagerImpl * This is the resource cache. It's filled/emptied from within Core::Update() */ BitmapMetadataCache mBitmapMetadata; - ShaderCache mShaders; }; ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction, @@ -339,30 +334,6 @@ void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ ); } -void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath ) -{ - DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str()); - - const ShaderResourceType* shaderType = dynamic_cast(typePath.type); - DALI_ASSERT_DEBUG(shaderType); - - if( shaderType ) - { - ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader)); - - mImpl->mPlatformAbstraction.LoadShaderBinFile(typePath.path, shaderData->GetBuffer()); - - // Add the ID to the completed set - mImpl->newCompleteRequests.insert(id); - - // Cache the resource - mImpl->mShaders.insert(ShaderDataPair(id, shaderData)); - - // Let NotificationManager know that the resource manager needs to do some processing - NotifyTickets(); - } -} - void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area ) { if( textureId ) @@ -459,11 +430,6 @@ void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTy { break; } - case ResourceShader: - { - resource = GetShaderData(id); - break; - } } @@ -621,17 +587,6 @@ BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id) return metadata; } -ShaderDataPtr ResourceManager::GetShaderData(ResourceId id) -{ - ShaderDataPtr shaderData; - ShaderCacheIter iter = mImpl->mShaders.find(id); - if(iter != mImpl->mShaders.end()) - { - shaderData = iter->second; - } - return shaderData; -} - /******************************************************************************** ************************* ResourceCache Implementation ************************ ********************************************************************************/ @@ -710,13 +665,6 @@ void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, Resource { break; } - - case ResourceShader: - { - mImpl->mShaders.insert(ShaderDataPair(id, static_cast(resource.Get()))); - break; - } - } // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about: @@ -865,15 +813,6 @@ void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex ) case ResourceNativeImage: case ResourceTargetImage: break; - - case ResourceShader: - { - ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first); - DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter ); - // shader data is owned through intrusive pointers so no need for discard queue - mImpl->mShaders.erase( shaderIter ); - break; - } } // Erase the item and increment the iterator diff --git a/dali/internal/update/resources/resource-manager.h b/dali/internal/update/resources/resource-manager.h index 131c45c..6c91394 100644 --- a/dali/internal/update/resources/resource-manager.h +++ b/dali/internal/update/resources/resource-manager.h @@ -31,13 +31,12 @@ #include #include #include -#include #include #include #include +#include #include -#include #include #include @@ -239,14 +238,6 @@ public: // Used by ResourceClient */ void HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat ); - - /** - * Load a shader program from a file - * @param[in] id The resource id - * @param[in] typePath The type & path of the resource - */ - void HandleLoadShaderRequest(ResourceId id, const ResourceTypePath& typePath ); - /** * Update bitmap area request * @param[in] textureId The resource ID of a bitmap-texture to remove. @@ -323,14 +314,7 @@ public: // Used by ResourceClient */ BitmapMetadata GetBitmapMetadata(ResourceId id); - /** - * Returns the shader resource corresponding to the Id - * @param[in] id - the id of a shader binary resource. - * @return the shader binary resource data or NULL if it has not been loaded. - */ - Integration::ShaderDataPtr GetShaderData(ResourceId id); - - /******************************************************************************** + /******************************************************************************** ************************* ResourceCache Implementation ************************ ********************************************************************************/ public: @@ -503,21 +487,6 @@ inline void RequestAllocateTextureMessage( EventThreadServices& eventThreadServi new (slot) LocalType( &manager, &ResourceManager::HandleAllocateTextureRequest, id, width, height, pixelFormat ); } - -inline void RequestLoadShaderMessage( EventThreadServices& eventThreadServices, - ResourceManager& manager, - ResourceId id, - const ResourceTypePath& typePath ) -{ - typedef MessageValue2< ResourceManager, ResourceId, ResourceTypePath > LocalType; - - // Reserve some memory inside the message queue - unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) ); - - // Construct message in the message queue memory; note that delete should not be called on the return value - new (slot) LocalType( &manager, &ResourceManager::HandleLoadShaderRequest, id, typePath ); -} - inline void RequestUpdateBitmapAreaMessage( EventThreadServices& eventThreadServices, ResourceManager& manager, ResourceId id,