From 30915d55652783138e1020eee210eba0e207efd2 Mon Sep 17 00:00:00 2001 From: Paul Wisbey Date: Mon, 19 Jan 2015 10:32:12 +0000 Subject: [PATCH] Minimal Atlas API Change-Id: If43e6762a0b402fd522cda80a04e44cb2a8cf09b --- automated-tests/src/dali/CMakeLists.txt | 1 + automated-tests/src/dali/utc-Dali-Atlas.cpp | 146 +++++++++++++++++++ dali/internal/event/images/atlas-impl.cpp | 158 +++++++++++++++++++++ dali/internal/event/images/atlas-impl.h | 153 ++++++++++++++++++++ dali/internal/event/resources/resource-client.cpp | 10 ++ dali/internal/event/resources/resource-client.h | 9 ++ dali/internal/file.list | 1 + .../render/common/texture-cache-dispatcher.h | 10 ++ .../render/gl-resources/bitmap-texture.cpp | 46 +++++- dali/internal/render/gl-resources/bitmap-texture.h | 15 ++ .../internal/render/gl-resources/texture-cache.cpp | 57 +++++++- dali/internal/render/gl-resources/texture-cache.h | 23 +++ dali/internal/render/gl-resources/texture.h | 8 ++ .../internal/update/resources/resource-manager.cpp | 8 ++ dali/internal/update/resources/resource-manager.h | 25 ++++ dali/public-api/dali-core.h | 1 + dali/public-api/file.list | 2 + dali/public-api/images/atlas.cpp | 74 ++++++++++ dali/public-api/images/atlas.h | 118 +++++++++++++++ 19 files changed, 863 insertions(+), 2 deletions(-) create mode 100644 automated-tests/src/dali/utc-Dali-Atlas.cpp create mode 100644 dali/internal/event/images/atlas-impl.cpp create mode 100644 dali/internal/event/images/atlas-impl.h create mode 100644 dali/public-api/images/atlas.cpp create mode 100644 dali/public-api/images/atlas.h diff --git a/automated-tests/src/dali/CMakeLists.txt b/automated-tests/src/dali/CMakeLists.txt index b023c1d..5388963 100644 --- a/automated-tests/src/dali/CMakeLists.txt +++ b/automated-tests/src/dali/CMakeLists.txt @@ -13,6 +13,7 @@ SET(TC_SOURCES utc-Dali-AnimatableMesh.cpp utc-Dali-Animation.cpp utc-Dali-Any.cpp + utc-Dali-Atlas.cpp utc-Dali-BaseHandle.cpp utc-Dali-BitmapImage.cpp utc-Dali-CameraActor.cpp diff --git a/automated-tests/src/dali/utc-Dali-Atlas.cpp b/automated-tests/src/dali/utc-Dali-Atlas.cpp new file mode 100644 index 0000000..e10032f --- /dev/null +++ b/automated-tests/src/dali/utc-Dali-Atlas.cpp @@ -0,0 +1,146 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +using namespace Dali; + +void utc_dali_atlas_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_atlas_cleanup(void) +{ + test_return_value = TET_PASS; +} + +// 1.1 +int UtcDaliAtlasNew01(void) +{ + TestApplication application; + + // invoke default handle constructor + Atlas atlas; + + DALI_TEST_CHECK( !atlas ); + + // initialise handle + atlas = Atlas::New( 16, 16 ); + + DALI_TEST_CHECK( atlas ); + END_TEST; +} + +// 1.2 +int UtcDaliAtlasUpload01(void) +{ + TestApplication application; + + Atlas atlas = Atlas::New( 16, 16, Pixel::RGBA8888 ); + DALI_TEST_CHECK( atlas ); + + // Using correct pixel format + PixelBuffer* buffer = new PixelBuffer[16 * 16]; + BitmapImage image = BitmapImage::New( buffer, 16, 16, Pixel::RGBA8888 ); + + DALI_TEST_CHECK( atlas.Upload( image, 0, 0 ) ); + + END_TEST; +} + +// 1.3 +int UtcDaliAtlasUpload02(void) +{ + TestApplication application; + + Atlas atlas = Atlas::New( 10, 10, Pixel::RGBA8888 ); + DALI_TEST_CHECK( atlas ); + + // Using INCORRECT pixel format + PixelBuffer* buffer = new PixelBuffer[16 * 16]; + BitmapImage image = BitmapImage::New( buffer, 16, 16, Pixel::A8 ); + + DALI_TEST_CHECK( !atlas.Upload( image, 0, 0 ) ); + + END_TEST; +} + +// 1.4 +int UtcDaliAtlasUpload03(void) +{ + TestApplication application; + + Atlas atlas = Atlas::New( 10, 10, Pixel::RGBA8888 ); + DALI_TEST_CHECK( atlas ); + + // Using image too big for atlas + PixelBuffer* buffer = new PixelBuffer[16 * 16]; + BitmapImage image = BitmapImage::New( buffer, 16, 16, Pixel::RGBA8888 ); + + DALI_TEST_CHECK( !atlas.Upload( image, 0, 0 ) ); + + END_TEST; +} + +// 1.5 +int UtcDaliAtlasUpload04(void) +{ + TestApplication application; + + Atlas atlas = Atlas::New( 32, 32, Pixel::RGBA8888 ); + DALI_TEST_CHECK( atlas ); + + // Using valid offsets + PixelBuffer* buffer = new PixelBuffer[16 * 16]; + BitmapImage image = BitmapImage::New( buffer, 16, 16, Pixel::RGBA8888 ); + + DALI_TEST_CHECK( atlas.Upload( image, 0, 0 ) ); + DALI_TEST_CHECK( atlas.Upload( image, 16, 0 ) ); + DALI_TEST_CHECK( atlas.Upload( image, 0, 16 ) ); + DALI_TEST_CHECK( atlas.Upload( image, 16, 16 ) ); + + END_TEST; +} + +// 1.6 +int UtcDaliAtlasUpload05(void) +{ + TestApplication application; + + Atlas atlas = Atlas::New( 32, 32, Pixel::RGBA8888 ); + DALI_TEST_CHECK( atlas ); + + // Using invalid offsets + PixelBuffer* buffer = new PixelBuffer[16 * 16]; + BitmapImage image = BitmapImage::New( buffer, 16, 16, Pixel::RGBA8888 ); + + DALI_TEST_CHECK( !atlas.Upload( image, 0, 17 ) ); + DALI_TEST_CHECK( !atlas.Upload( image, 17, 0 ) ); + DALI_TEST_CHECK( !atlas.Upload( image, 17, 17 ) ); + DALI_TEST_CHECK( !atlas.Upload( image, 99, 0 ) ); + DALI_TEST_CHECK( !atlas.Upload( image, 0, 99 ) ); + DALI_TEST_CHECK( !atlas.Upload( image, 99, 99 ) ); + + END_TEST; +} + diff --git a/dali/internal/event/images/atlas-impl.cpp b/dali/internal/event/images/atlas-impl.cpp new file mode 100644 index 0000000..7ad423f --- /dev/null +++ b/dali/internal/event/images/atlas-impl.cpp @@ -0,0 +1,158 @@ +/* + * 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 + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Internal +{ + +namespace +{ +TypeRegistration mType( typeid( Dali::Atlas ), typeid( Dali::Image ), NULL ); +} + +Atlas* Atlas::New( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat ) +{ + return new Atlas( width, height, pixelFormat ); +} + +bool Atlas::Upload( const BitmapImage& bitmapImage, + std::size_t xOffset, + std::size_t yOffset ) +{ + bool uploadSuccess( false ); + + if( IsWithin(bitmapImage, xOffset, yOffset) ) + { + ResourceId destId = GetResourceId(); + ResourceId srcId = bitmapImage.GetResourceId(); + + if( destId && srcId ) + { + mResourceClient.UploadBitmap( destId, srcId, xOffset, yOffset ); + uploadSuccess = true; + } + } + + return uploadSuccess; +} + +Atlas::~Atlas() +{ + ReleaseAtlas(); +} + +Atlas::Atlas( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat ) +: mResourceClient( ThreadLocalStorage::Get().GetResourceClient() ), + mPixelFormat( pixelFormat ) +{ + mWidth = width; + mHeight = height; + + if( Dali::Image::Immediate == mLoadPolicy ) + { + AllocateAtlas(); + } +} + +void Atlas::Connect() +{ + ++mConnectionCount; + + if( Dali::Image::OnDemand == mLoadPolicy && + mConnectionCount == 1 ) + { + AllocateAtlas(); + } +} + +void Atlas::Disconnect() +{ + if( mConnectionCount ) + { + --mConnectionCount; + + if ( Dali::Image::Unused == mReleasePolicy && + mConnectionCount == 0 ) + { + ReleaseAtlas(); + } + } +} + +bool Atlas::IsWithin( const BitmapImage& bitmapImage, + std::size_t xOffset, + std::size_t yOffset ) +{ + bool within(false); + + if( mPixelFormat != bitmapImage.GetPixelFormat() ) + { + DALI_LOG_ERROR( "Pixel format %d does not match Atlas format %d\n", bitmapImage.GetPixelFormat(), mPixelFormat ); + } + else + { + const unsigned int width = bitmapImage.GetWidth(); + const unsigned int height = bitmapImage.GetHeight(); + + if( xOffset < mWidth && + yOffset < mHeight && + xOffset+width <= mWidth && + yOffset+height <= mHeight ) + { + within = true; + } + else + { + DALI_LOG_ERROR( "%dx%d image does not fit at offset %d,%d\n", width, height, xOffset, yOffset ); + } + } + + return within; +} + +void Atlas::AllocateAtlas() +{ + if( !mTicket ) + { + mTicket = mResourceClient.AllocateTexture( mWidth, mHeight, mPixelFormat ); + } +} + +void Atlas::ReleaseAtlas() +{ + mTicket.Reset(); +} + +} // namespace Internal + +} // namespace Dali diff --git a/dali/internal/event/images/atlas-impl.h b/dali/internal/event/images/atlas-impl.h new file mode 100644 index 0000000..6dddead --- /dev/null +++ b/dali/internal/event/images/atlas-impl.h @@ -0,0 +1,153 @@ +#ifndef __DALI_INTERNAL_ATLAS_H__ +#define __DALI_INTERNAL_ATLAS_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 +#include + +namespace Dali +{ + +namespace Internal +{ + +class ResourceClient; + +/** + * @brief An Atlas is a large image containing multiple smaller images. + * + * Bitmap images must be uploaded at a specified position, to populate the Atlas. + * The client is reponsible for generating the appropriate geometry (UV coordinates), + * needed to draw images within the Atlas. + */ +class Atlas : public Image +{ +public: + + /** + * @brief Create a new Atlas. + * + * @pre width & height are greater than zero. + * The maximum size of the atlas is limited by GL_MAX_TEXTURE_SIZE. + * @param [in] width The atlas width in pixels. + * @param [in] height The atlas height in pixels. + * @param [in] pixelFormat The pixel format (rgba 32 bit by default). + * @return A pointer to a new Atlas. + */ + static Atlas* New( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat = Pixel::RGBA8888 ); + + /** + * @brief Upload a bitmap to the atlas. + * + * @pre The bitmap pixel format must match the Atlas format. + * @param [in] bitmap The bitmap to upload. + * @param [in] xOffset Specifies an offset in the x direction within the atlas. + * @param [in] yOffset Specifies an offset in the y direction within the atlas. + * @return True if the bitmap fits within the atlas at the specified offset. + */ + bool Upload( const BitmapImage& bitmap, + std::size_t xOffset, + std::size_t yOffset ); + +protected: + + /** + * @brief Protected constructor. + * + * @pre width & height are greater than zero. + * The maximum size of the atlas is limited by GL_MAX_TEXTURE_SIZE. + * @param [in] width The atlas width in pixels. + * @param [in] height The atlas height in pixels. + * @param [in] pixelFormat The pixel format (rgba 32 bit by default). + */ + Atlas( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat ); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + virtual ~Atlas(); + + /** + * @copydoc Dali::Internal::Image::Connect + */ + virtual void Connect(); + + /** + * @copydoc Dali::Internal::Image::Disconnect + */ + virtual void Disconnect(); + +private: + + /** + * Helper for Upload methods + * @return True if the bitmap fits within the atlas at the specified offset + */ + bool IsWithin( const BitmapImage& bitmapImage, + std::size_t xOffset, + std::size_t yOffset ); + + /** + * Helper to create the Atlas resource + */ + void AllocateAtlas(); + + /** + * Helper to release the Atlas resource + */ + void ReleaseAtlas(); + +private: + + ResourceClient& mResourceClient; + + Pixel::Format mPixelFormat; +}; + +} // namespace Internal + +/** + * Helper methods for public API. + */ +inline Internal::Atlas& GetImplementation(Dali::Atlas& image) +{ + DALI_ASSERT_ALWAYS( image && "Atlas handle is empty" ); + + BaseObject& handle = image.GetBaseObject(); + + return static_cast(handle); +} + +inline const Internal::Atlas& GetImplementation(const Dali::Atlas& image) +{ + DALI_ASSERT_ALWAYS( image && "Atlas handle is empty" ); + + const BaseObject& handle = image.GetBaseObject(); + + return static_cast(handle); +} + +} // namespace Dali + +#endif // __DALI_INTERNAL_ATLAS_H__ diff --git a/dali/internal/event/resources/resource-client.cpp b/dali/internal/event/resources/resource-client.cpp index b8dd6cf..d82be43 100644 --- a/dali/internal/event/resources/resource-client.cpp +++ b/dali/internal/event/resources/resource-client.cpp @@ -437,6 +437,16 @@ void ResourceClient::UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updat RequestUpdateBitmapAreaMessage( mUpdateManager.GetEventToUpdate(), mResourceManager, ticket->GetId(), updateArea ); } +void ResourceClient::UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ) +{ + RequestUploadBitmapMessage( mUpdateManager.GetEventToUpdate(), + mResourceManager, + destId, + srcId, + xOffset, + yOffset ); +} + void ResourceClient::UpdateMesh( ResourceTicketPtr ticket, const Dali::MeshData& meshData ) { DALI_ASSERT_DEBUG( ticket ); diff --git a/dali/internal/event/resources/resource-client.h b/dali/internal/event/resources/resource-client.h index 923e73f..1b5ec87 100644 --- a/dali/internal/event/resources/resource-client.h +++ b/dali/internal/event/resources/resource-client.h @@ -249,6 +249,15 @@ public: void UpdateBitmapArea( ResourceTicketPtr ticket, RectArea& updateArea ); /** + * Upload a bitmap to a texture + * @param[in] destId The destination texture ID + * @param[in] srcId The resource ID of the bitmap to upload + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + void UploadBitmap( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ); + + /** * Update the mesh used by ticket * @note Should use same mechanism as update manager * @param[in] ticket The ticket holding the mesh data diff --git a/dali/internal/file.list b/dali/internal/file.list index 904d7b6..fd31a2b 100644 --- a/dali/internal/file.list +++ b/dali/internal/file.list @@ -68,6 +68,7 @@ internal_src_files = \ $(internal_src_dir)/event/events/tap-gesture-detector-impl.cpp \ $(internal_src_dir)/event/events/tap-gesture-processor.cpp \ $(internal_src_dir)/event/events/touch-event-processor.cpp \ + $(internal_src_dir)/event/images/atlas-impl.cpp \ $(internal_src_dir)/event/images/bitmap-external.cpp \ $(internal_src_dir)/event/images/bitmap-packed-pixel.cpp \ $(internal_src_dir)/event/images/bitmap-compressed.cpp \ diff --git a/dali/internal/render/common/texture-cache-dispatcher.h b/dali/internal/render/common/texture-cache-dispatcher.h index 26d337a..1ea5f80 100644 --- a/dali/internal/render/common/texture-cache-dispatcher.h +++ b/dali/internal/render/common/texture-cache-dispatcher.h @@ -128,6 +128,16 @@ public: virtual void DispatchUpdateTexture( ResourceId id, Integration::Bitmap* bitmap ) = 0; /** + * Update the part of a texture with a newly loaded bitmap + * May be called from Update thread + * @param[in] destId The ID of the texture to update + * @param[in] srcId The resource ID of the source bitmap + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + virtual void DispatchUpdateTexture( ResourceId destId, ResourceId srcId,std::size_t xOffset, std::size_t yOffset ) = 0; + + /** * Dispatch a message to update the texture area * May be called from the Update thread * @param[in] id Resource Id of the texture diff --git a/dali/internal/render/gl-resources/bitmap-texture.cpp b/dali/internal/render/gl-resources/bitmap-texture.cpp index e6967ce..c001da8 100644 --- a/dali/internal/render/gl-resources/bitmap-texture.cpp +++ b/dali/internal/render/gl-resources/bitmap-texture.cpp @@ -203,7 +203,6 @@ void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char } } - void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pixels ) { DALI_LOG_TRACE_METHOD(Debug::Filter::gImage); @@ -286,6 +285,51 @@ void BitmapTexture::Update( Integration::Bitmap* bitmap ) } } +void BitmapTexture::Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset ) +{ + if( NULL != srcBitmap ) + { + GLenum pixelFormat = GL_RGBA; + GLenum pixelDataType = GL_UNSIGNED_BYTE; + Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelFormat ); + + if( !mId ) + { + mContext.GenTextures( 1, &mId ); + + mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD ); + mContext.Bind2dTexture( mId ); + mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + mContext.TexImage2D( GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, NULL ); + 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 ); + } + else + { + mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD ); + mContext.Bind2dTexture( mId ); + mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + } + + const unsigned char* pixels = srcBitmap->GetBuffer(); + unsigned int srcWidth = srcBitmap->GetImageWidth(); + const unsigned int pixelDepth = Pixel::GetBytesPerPixel( mPixelFormat ); + + unsigned int yBottom = yOffset + srcBitmap->GetImageHeight(); + + for( unsigned int y = yOffset; y < yBottom; y++ ) + { + mContext.TexSubImage2D( GL_TEXTURE_2D, 0, + xOffset, y, + srcWidth, 1, + pixelFormat, pixelDataType, pixels ); + + pixels += srcWidth * pixelDepth; + } + } +} + void BitmapTexture::UpdateArea( const RectArea& updateArea ) { DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "BitmapTexture::UpdateArea()\n"); diff --git a/dali/internal/render/gl-resources/bitmap-texture.h b/dali/internal/render/gl-resources/bitmap-texture.h index 46073c8..7cbdfbc 100644 --- a/dali/internal/render/gl-resources/bitmap-texture.h +++ b/dali/internal/render/gl-resources/bitmap-texture.h @@ -90,7 +90,14 @@ public: // Message interface */ void ClearAreas( const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color ); + /** + * Retrieve the bitmap + * @return The bitmap or NULL if already discarded + */ + Integration::Bitmap* GetBitmap() { return mBitmap.Get(); } + public: + /** * @copydoc Texture::Init */ @@ -124,6 +131,14 @@ public: virtual void Update( Integration::Bitmap* bitmap ); /** + * Update part of the texture with a different bitmap + * @param[in] srcBitmap The bitmap to copy from + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + virtual void Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset ); + + /** * Bitmap area has been modified - update the texture appropriately. * @pre The bitmap hasn't been discarded (should be external type) * @param[in] area The updated area diff --git a/dali/internal/render/gl-resources/texture-cache.cpp b/dali/internal/render/gl-resources/texture-cache.cpp index db4f027..bfa9185 100644 --- a/dali/internal/render/gl-resources/texture-cache.cpp +++ b/dali/internal/render/gl-resources/texture-cache.cpp @@ -137,6 +137,30 @@ void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap ) } } +void TextureCache::UpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ) +{ + DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(destId=%i srcId=%i )\n", destId, srcId ); + + BitmapTexture* srcTexture = TextureCache::GetBitmapTexture( srcId ); + Integration::Bitmap* srcBitmap = ( srcTexture != NULL ) ? srcTexture->GetBitmap() : NULL; + + if( srcBitmap ) + { + TextureIter textureIter = mTextures.find( destId ); + if( textureIter != mTextures.end() ) + { + TexturePointer texturePtr = textureIter->second; + if( texturePtr ) + { + texturePtr->Update( srcBitmap, xOffset, yOffset ); + + ResourcePostProcessRequest ppRequest( srcId, ResourcePostProcessRequest::UPLOADED ); + mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest); + } + } + } +} + void TextureCache::UpdateTextureArea( ResourceId id, const Dali::RectArea& area ) { DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id ); @@ -264,7 +288,6 @@ void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, } } - Texture* TextureCache::GetTexture(ResourceId id) { Texture* texture = NULL; @@ -297,6 +320,23 @@ Texture* TextureCache::GetTexture(ResourceId id) return texture; } +BitmapTexture* TextureCache::GetBitmapTexture(ResourceId id) +{ + BitmapTexture* texture = NULL; + TextureIter iter = mTextures.find( id ); + + if( iter != mTextures.end() ) + { + TexturePointer texturePtr = iter->second; + if( texturePtr ) + { + texture = dynamic_cast< BitmapTexture* >( texturePtr.Get() ); + } + } + + return texture; +} + FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id) { FrameBufferTexture* offscreen = NULL; @@ -492,6 +532,21 @@ void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap ) } } +void TextureCache::DispatchUpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ) +{ + // NULL, means being shutdown, so ignore msgs + if( mSceneGraphBuffers != NULL ) + { + typedef MessageValue4< TextureCache, ResourceId, ResourceId, std::size_t, std::size_t > DerivedType; + + // Reserve some memory inside the render queue + unsigned int* slot = mRenderQueue.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( this, &TextureCache::UpdateTexture, destId, srcId, xOffset, yOffset ); + } +} + void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area ) { // NULL, means being shutdown, so ignore msgs diff --git a/dali/internal/render/gl-resources/texture-cache.h b/dali/internal/render/gl-resources/texture-cache.h index 656d103..1bbc7f9 100644 --- a/dali/internal/render/gl-resources/texture-cache.h +++ b/dali/internal/render/gl-resources/texture-cache.h @@ -52,6 +52,7 @@ namespace Internal { class Context; class Texture; +class BitmapTexture; class FrameBufferTexture; class TextureObserver; @@ -136,6 +137,16 @@ public: */ void UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap ); + /** + * Update the part of a texture with a newly loaded bitmap + * May be called from Update thread + * @param[in] destId The ID of the texture to update + * @param[in] srcId The resource ID of the source bitmap + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + void UpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ); + /** * Add an array of bitmaps to an existing texture used as an Atlas * @param[in] id Resource id of the texture @@ -191,6 +202,13 @@ public: Texture* GetTexture( ResourceId id ); /** + * Get the bitmaptexture associated with the resource ID + * @param[in] id Resource Id of the texture + * @return The texture or NULL + */ + BitmapTexture* GetBitmapTexture(ResourceId id); + + /** * Get the framebuffer texture associated with the resource ID * Used for writing to the framebuffer * @param[in] id Resource Id of the framebuffer @@ -267,6 +285,11 @@ protected: // Implements TextureCacheDispatcher virtual void DispatchUpdateTexture( ResourceId id, Integration::Bitmap* bitmap ); /** + * @copydoc TextureCacheDispatcher::DispatchUpdateTexture() + */ + virtual void DispatchUpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ); + + /** * @copydoc TextureCacheDispatcher::DispatchUpdateTextureArea() */ virtual void DispatchUpdateTextureArea( ResourceId id, const RectArea& area ); diff --git a/dali/internal/render/gl-resources/texture.h b/dali/internal/render/gl-resources/texture.h index 5c0b182..0479f01 100644 --- a/dali/internal/render/gl-resources/texture.h +++ b/dali/internal/render/gl-resources/texture.h @@ -80,6 +80,14 @@ public: virtual void UpdateArea( const RectArea& area ); /** + * Update part of the texture with a different bitmap + * @param[in] srcBitmap The bitmap to copy from + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + virtual void Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset ) {} + + /** * @return Return true if the texture should be updated on GL texture creation. */ virtual bool UpdateOnCreate(); diff --git a/dali/internal/update/resources/resource-manager.cpp b/dali/internal/update/resources/resource-manager.cpp index 0464aa0..82b7e53 100644 --- a/dali/internal/update/resources/resource-manager.cpp +++ b/dali/internal/update/resources/resource-manager.cpp @@ -428,6 +428,14 @@ void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const } } +void ResourceManager::HandleUploadBitmapRequest( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ) +{ + if( destId && srcId ) + { + mImpl->mTextureCacheDispatcher.DispatchUpdateTexture( destId, srcId, xOffset, yOffset ); + } +} + void ResourceManager::HandleUpdateMeshRequest( BufferIndex updateBufferIndex, ResourceId id, MeshData* meshData ) { DALI_ASSERT_DEBUG( mImpl->mResourceClient != NULL ); diff --git a/dali/internal/update/resources/resource-manager.h b/dali/internal/update/resources/resource-manager.h index 2a2a947..43bab93 100644 --- a/dali/internal/update/resources/resource-manager.h +++ b/dali/internal/update/resources/resource-manager.h @@ -273,6 +273,15 @@ public: // Used by ResourceClient void HandleUpdateBitmapAreaRequest( ResourceId textureId, const Dali::RectArea& area ); /** + * Upload a bitmap to a position within a specified texture + * @param[in] destId The destination texture ID + * @param[in] srcId The resource ID of the bitmap to upload + * @param [in] xOffset Specifies an offset in the x direction within the texture + * @param [in] yOffset Specifies an offset in the y direction within the texture + */ + void HandleUploadBitmapRequest( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset ); + + /** * Upload mesh buffer changes. * @param[in] updateBufferIndex The current update buffer index. * @param[in] id The ID of a Mesh resource. @@ -630,6 +639,22 @@ inline void RequestUpdateBitmapAreaMessage( EventToUpdate& eventToUpdate, new (slot) LocalType( &manager, &ResourceManager::HandleUpdateBitmapAreaRequest, id, area ); } +inline void RequestUploadBitmapMessage( EventToUpdate& eventToUpdate, + ResourceManager& manager, + ResourceId destId, + ResourceId srcId, + std::size_t xOffset, + std::size_t yOffset ) +{ + typedef MessageValue4< ResourceManager, ResourceId, ResourceId, std::size_t, std::size_t > LocalType; + + // Reserve some memory inside the message queue + unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ), false ); + + // Construct message in the message queue memory; note that delete should not be called on the return value + new (slot) LocalType( &manager, &ResourceManager::HandleUploadBitmapRequest, destId, srcId, xOffset, yOffset ); +} + inline void RequestUpdateMeshMessage( EventToUpdate& eventToUpdate, ResourceManager& manager, ResourceId id, diff --git a/dali/public-api/dali-core.h b/dali/public-api/dali-core.h index 2408982..a4d8ec2 100644 --- a/dali/public-api/dali-core.h +++ b/dali/public-api/dali-core.h @@ -90,6 +90,7 @@ #include #include +#include #include #include #include diff --git a/dali/public-api/file.list b/dali/public-api/file.list index 5629dcc..b6f4c16 100644 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -57,6 +57,7 @@ public_api_src_files = \ $(public_api_src_dir)/geometry/mesh-factory.cpp \ $(public_api_src_dir)/geometry/mesh.cpp \ $(public_api_src_dir)/geometry/spline.cpp \ + $(public_api_src_dir)/images/atlas.cpp \ $(public_api_src_dir)/images/distance-field.cpp \ $(public_api_src_dir)/images/image.cpp \ $(public_api_src_dir)/images/image-attributes.cpp \ @@ -208,6 +209,7 @@ public_api_core_geometry_header_files = \ $(public_api_src_dir)/geometry/spline.h public_api_core_images_header_files = \ + $(public_api_src_dir)/images/atlas.h \ $(public_api_src_dir)/images/bitmap-image.h \ $(public_api_src_dir)/images/distance-field.h \ $(public_api_src_dir)/images/encoded-buffer-image.h \ diff --git a/dali/public-api/images/atlas.cpp b/dali/public-api/images/atlas.cpp new file mode 100644 index 0000000..b41c00c --- /dev/null +++ b/dali/public-api/images/atlas.cpp @@ -0,0 +1,74 @@ +/* + * 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 + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +Atlas Atlas::New( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat ) +{ + DALI_ASSERT_ALWAYS( 0u != width && "Invalid Atlas width requested" ); + DALI_ASSERT_ALWAYS( 0u != height && "Invalid Atlas height requested" ); + + return Atlas( Internal::Atlas::New( width, height, pixelFormat ) ); +} + +Atlas::Atlas() +{ +} + +bool Atlas::Upload( const BitmapImage& bitmap, + std::size_t xOffset, + std::size_t yOffset ) +{ + return GetImplementation(*this).Upload( GetImplementation(bitmap), xOffset, yOffset ); +} + +Atlas Atlas::DownCast( BaseHandle handle ) +{ + return Atlas( dynamic_cast(handle.GetObjectPtr()) ); +} + +Atlas::~Atlas() +{ +} + +Atlas::Atlas( const Atlas& handle ) +: Image( handle ) +{ +} + +Atlas& Atlas::operator=( const Atlas& rhs ) +{ + BaseHandle::operator=(rhs); + return *this; +} + +Atlas::Atlas( Internal::Atlas* internal ) +: Image( internal ) +{ +} + +} // namespace Dali diff --git a/dali/public-api/images/atlas.h b/dali/public-api/images/atlas.h new file mode 100644 index 0000000..9719635 --- /dev/null +++ b/dali/public-api/images/atlas.h @@ -0,0 +1,118 @@ +#ifndef __DALI_ATLAS_H__ +#define __DALI_ATLAS_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. + * + */ + +#include +#include +#include + +namespace Dali +{ + +namespace Internal DALI_INTERNAL +{ +class Atlas; +} + +/** + * @brief An Atlas is a large image containing multiple smaller images. + * + * Bitmap images must be uploaded at a specified position, to populate the Atlas. + * The client is reponsible for generating the appropriate geometry (UV coordinates), + * needed to draw images within the Atlas. + */ +class DALI_IMPORT_API Atlas : public Image +{ +public: + + /** + * @brief Create a new Atlas. + * + * @pre width & height are greater than zero. + * The maximum size of the atlas is limited by GL_MAX_TEXTURE_SIZE. + * @param [in] width The atlas width in pixels. + * @param [in] height The atlas height in pixels. + * @param [in] pixelFormat The pixel format (rgba 32 bit by default). + * @return A handle to a new Atlas. + */ + static Atlas New( std::size_t width, + std::size_t height, + Pixel::Format pixelFormat = Pixel::RGBA8888 ); + + /** + * @brief Create an empty handle. + * + * Calling member functions of an empty handle is not allowed. + */ + Atlas(); + + /** + * @brief Upload a bitmap to the atlas. + * + * @pre The bitmap pixel format must match the Atlas format. + * @param [in] bitmap The bitmap to upload. + * @param [in] xOffset Specifies an offset in the x direction within the atlas. + * @param [in] yOffset Specifies an offset in the y direction within the atlas. + * @return True if the bitmap fits within the atlas at the specified offset. + */ + bool Upload( const BitmapImage& bitmap, + std::size_t xOffset, + std::size_t yOffset ); + + /** + * @brief Downcast an Object handle to Atlas. + * + * If handle points to a Atlas the downcast produces valid + * handle. If not the returned handle is left uninitialized. + * + * @param[in] handle to An object + * @return handle to a Atlas or an empty handle + */ + static Atlas DownCast( BaseHandle handle ); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~Atlas(); + + /** + * @brief This copy constructor is required for (smart) pointer semantics. + * + * @param [in] handle A reference to the copied handle + */ + Atlas( const Atlas& handle ); + + /** + * @brief This assignment operator is required for (smart) pointer semantics. + * + * @param [in] rhs A reference to the copied handle + * @return A reference to this + */ + Atlas& operator=( const Atlas& rhs); + +public: // Not intended for application developers + + explicit DALI_INTERNAL Atlas( Internal::Atlas* ); +}; + +} // namespace Dali + +#endif // __DALI_ATLAS_H__ -- 2.7.4