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 <andrew.cox@partner.samsung.com>
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;
/**
* @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 )
}
/**
- * @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;
/**
* @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;
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 )
}
bool loadResult;
- std::vector< unsigned char> buffer;
+ Dali::Vector< unsigned char> buffer;
};
/**
/**
* @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();
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 );
$(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 \
#include <dali/integration-api/resource-cache.h>
#include <dali/integration-api/bitmap.h> ///@todo Remove this include (a bunch of stuff needs to include it though)
#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/common/dali-vector.h>
namespace Dali
{
* @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
* @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
{
ResourceBitmap,
ResourceNativeImage,
- ResourceTargetImage,
- ResourceShader
+ ResourceTargetImage
};
/**
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
--- /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 <dali/integration-api/shader-data.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+const size_t ShaderData::UNINITIALISED_HASH_VALUE = size_t(0) - 1;
+
+}
+}
#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.
// INTERNAL INCLUDES
#include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/dali-vector.h>
#include <dali/integration-api/resource-declarations.h>
namespace Dali
/**
* 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:
*/
void SetHashValue(size_t shaderHash)
{
+ DALI_ASSERT_DEBUG( shaderHash != 0 );
mShaderHash = shaderHash;
}
* 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();
}
/**
* @return the vertex shader
*/
- const char* GetFragmentShader()
+ const char* GetFragmentShader() const
{
return mFragmentShader.c_str();
}
*/
bool HasBinary() const
{
- return 0 != mBuffer.size();
+ return 0 != mBuffer.Size();
}
/**
*/
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();
}
/**
*/
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<unsigned char>& GetBuffer()
+ Dali::Vector<unsigned char>& 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
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<unsigned char> mBuffer; ///< buffer containing compiled binary bytecode
- ResourceId mResourceId; ///< resource id
-
+ Dali::Vector<unsigned char> mBuffer; ///< buffer containing compiled binary bytecode
};
} // namespace Integration
textureCache,
*mTouchResampler );
+ mRenderManager->SetShaderSaver( *mUpdateManager );
+
mStage = IntrusivePtr<Stage>( Stage::New( *mAnimationPlaylist, *mPropertyNotificationManager, *mUpdateManager, *mNotificationManager ) );
// This must be called after stage is created but before stage initialization
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();
--- /dev/null
+#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 <dali/public-api/common/intrusive-ptr.h>
+
+// EXTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Integration
+{
+class ShaderData;
+typedef IntrusivePtr<ShaderData> 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__
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()
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<ResourceTicketPtr> 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
#include <dali/public-api/common/dali-common.h>
#include <dali/devel-api/common/hash.h>
#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/event/common/thread-local-storage.h>
#include <dali/internal/event/resources/resource-client.h>
#include <dali/internal/event/effects/shader-effect-impl.h>
#include <dali/internal/event/effects/shader-declarations.h>
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()
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
*/
// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
#include <dali/internal/event/resources/resource-ticket.h>
-#include <dali/internal/event/resources/resource-type-path-id-map.h>
#include <dali/internal/event/effects/shader-declarations.h>
+#include <dali/internal/common/message.h>
+#include <dali/internal/common/shader-saver.h>
namespace Dali
{
+namespace Integration
+{
+
+class ShaderData;
+typedef IntrusivePtr<ShaderData> ShaderDataPtr;
+
+}
namespace Internal
{
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.
private:
+ void MemoryCacheInsert( Integration::ShaderData& shaderData );
+
// Undefined
ShaderFactory( const ShaderFactory& );
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
// INTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
-#include <dali/internal/event/resources/resource-type-path-id-map.h>
#include <dali/internal/event/resources/resource-ticket.h>
#include <dali/internal/event/images/context-recovery-interface.h>
#include <dali/internal/event/images/image-factory-cache.h>
}
Dali::ShaderEffect::GeometryHints shaderEffectHint = static_cast<Dali::ShaderEffect::GeometryHints>( 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 );
}
private:
SceneGraph::Shader* mSceneObject;
- ResourceTicketPtr mTicket;
bool mOnStage;
};
break;
}
case ResourceTargetImage:
- case ResourceShader:
{
newTicket = new ResourceTicket(*this, newId, typePath);
break;
// FALLTHROUGH:
case ResourceNativeImage:
case ResourceTargetImage:
- case ResourceShader:
{
DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
}
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);
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
/**
* 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
+++ /dev/null
-#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 <dali/devel-api/common/map-wrapper.h>
-#include <dali/internal/event/resources/resource-type-path.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-///< A map of resource IDs sorted by ResourceTypePath
-typedef std::map<ResourceTypePath, unsigned int> ResourceTypePathIdMap;
-typedef ResourceTypePathIdMap::iterator ResourceTypePathIdIter;
-typedef ResourceTypePathIdMap::size_type ResourceTypePathIdSize;
-typedef std::pair<ResourceTypePath, unsigned int> ResourceTypePathIdPair;
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__
// else result = 0
break;
}
-
- case ResourceShader:
- {
- // compare shader source hashes
- const ShaderResourceType& lhsShader = static_cast<const ShaderResourceType&>(lhs);
- const ShaderResourceType& rhsShader = static_cast<const ShaderResourceType&>(rhs);
-
- if (lhsShader.hash != rhsShader.hash)
- {
- result = lhsShader.hash < rhsShader.hash ? -1 : 1;
- }
- // else result = 0
- break;
- }
-
-
-
}
}
return result;
renderersAdded( false ),
firstRenderCompleted( false ),
defaultShader( NULL ),
- programController( postProcessDispatcher, glAbstraction )
+ programController( glAbstraction )
{
}
mImpl->resourcePostProcessQueue[ mImpl->renderBufferIndex ].push_back( request );
}
+void RenderManager::SetShaderSaver( ShaderSaver& upstream )
+{
+ mImpl->programController.SetShaderSaver( upstream );
+}
+
RenderInstructionContainer& RenderManager::GetRenderInstructionContainer()
{
return mImpl->instructions;
// INTERNAL INCLUDES
#include <dali/public-api/math/rect.h>
+#include <dali/internal/common/shader-saver.h>
#include <dali/internal/render/common/post-process-resource-dispatcher.h>
#include <dali/internal/update/resources/resource-manager-declarations.h>
#include <dali/internal/render/gl-resources/gpu-buffer.h>
{
class Context;
class ProgramCache;
+class ShaderSaver;
namespace SceneGraph
{
* 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.
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 )
else
{
const unsigned char* pixels = NULL;
- std::vector<unsigned char> pixelData;
- if( ( NULL == pixels ) && ( true == mClearPixels ) )
+ Dali::Vector<unsigned char> 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 );
// INTERNAL INCLUDES
#include <dali/integration-api/gl-defines.h>
+#include <dali/internal/common/shader-saver.h>
#include <dali/internal/update/resources/resource-manager-declarations.h>
#include <dali/internal/render/shaders/program.h>
#include <dali/internal/render/common/post-process-resource-dispatcher.h>
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 ),
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
namespace Internal
{
-namespace SceneGraph
-{
-class PostProcessResourceDispatcher;
-}
+class ShaderSaver;
/**
* This class is the owner of GL shader programs
* 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
*/
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
/**
private: // Data
- SceneGraph::PostProcessResourceDispatcher& mPostProcessDispatcher;
+ ShaderSaver* mShaderSaver;
Integration::GlAbstraction& mGlAbstraction;
Program* mCurrentProgram;
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() );
else
{
mLinked = true;
+ DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Reused binary.\n" );
}
}
{
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);
// 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" );
}
}
}
// 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;
namespace Internal
{
-class ProgramController;
class Program;
namespace SceneGraph
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.
*/
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.
*/
#include <dali/internal/event/common/notification-manager.h>
#include <dali/internal/event/common/property-notification-impl.h>
#include <dali/internal/event/common/property-notifier.h>
+#include <dali/internal/event/effects/shader-factory.h>
#include <dali/internal/update/animation/scene-graph-animator.h>
#include <dali/internal/update/animation/scene-graph-animation.h>
typedef ShaderContainer::Iterator ShaderIter;
typedef ShaderContainer::ConstIterator ShaderConstIter;
+typedef std::vector<Integration::ShaderDataPtr> ShaderDataBatchedQueue;
+typedef ShaderDataBatchedQueue::iterator ShaderDataBatchedQueueIterator;
+
typedef OwnerContainer<PanGesture*> GestureContainer;
typedef GestureContainer::Iterator GestureIter;
typedef GestureContainer::ConstIterator GestureConstIter;
notificationManager( notificationManager ),
animationFinishedNotifier( animationFinishedNotifier ),
propertyNotifier( propertyNotifier ),
+ shaderSaver( NULL ),
resourceManager( resourceManager ),
discardQueue( discardQueue ),
renderController( renderController ),
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
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()
}
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 )
}
}
+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;
// 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
}
}
+void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
+{
+ mImpl->shaderSaver = &upstream;
+}
+
} // namespace SceneGraph
} // namespace Internal
#include <dali/internal/common/message.h>
#include <dali/internal/common/type-abstraction-enums.h>
+#include <dali/internal/common/shader-saver.h>
#include <dali/internal/event/common/event-thread-services.h>
#include <dali/internal/update/animation/scene-graph-animation.h>
#include <dali/internal/update/common/scene-graph-buffers.h>
* 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:
TouchResampler& touchResampler );
/**
- * Destructor. Not virtual as this is not a base class
+ * Destructor.
*/
- ~UpdateManager();
+ virtual ~UpdateManager();
// Node connection methods
/**
* 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.
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.
new (slot) LocalType( &manager, &UpdateManager::PropertyNotificationSetNotify, propertyNotification, notifyMode );
}
-
-
// The render thread can safely change the Shader
inline void AddShaderMessage( 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 )
typedef BitmapMetadataCache::iterator BitmapMetadataIter;
typedef std::pair<ResourceId, BitmapMetadata> BitmapMetadataPair;
-typedef std::map<ResourceId, ShaderDataPtr> ShaderCache;
-typedef ShaderCache::iterator ShaderCacheIter;
-typedef ShaderCache::size_type ShaderCacheSize;
-typedef std::pair<ResourceId, ShaderDataPtr> ShaderDataPair;
static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
{
* This is the resource cache. It's filled/emptied from within Core::Update()
*/
BitmapMetadataCache mBitmapMetadata;
- ShaderCache mShaders;
};
ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
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<const ShaderResourceType*>(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 )
{
break;
}
- case ResourceShader:
- {
- resource = GetShaderData(id);
- break;
- }
}
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 ************************
********************************************************************************/
{
break;
}
-
- case ResourceShader:
- {
- mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
- break;
- }
-
}
// Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
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
#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/platform-abstraction.h>
#include <dali/integration-api/resource-cache.h>
-#include <dali/integration-api/shader-data.h>
#include <dali/internal/common/message.h>
#include <dali/internal/event/common/event-thread-services.h>
#include <dali/internal/event/common/thread-local-storage.h>
+#include <dali/internal/event/resources/resource-type-path.h>
#include <dali/internal/event/resources/resource-client-declarations.h>
-#include <dali/internal/event/effects/shader-factory.h>
#include <dali/internal/update/resources/resource-manager-declarations.h>
#include <dali/internal/update/resources/bitmap-metadata.h>
*/
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.
*/
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:
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,