2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/render/gl-resources/bitmap-texture.h>
26 #include <dali/public-api/math/rect.h>
27 #include <dali/public-api/math/math-utils.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/internal/render/common/vertex.h>
30 #include <dali/internal/render/common/performance-monitor.h>
31 #include <dali/internal/render/gl-resources/context.h>
39 BitmapTexture::BitmapTexture(
40 Integration::Bitmap* const bitmap,
41 const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixelsProfile,
43 ResourcePolicy::Discardable policy)
45 bitmapPackedPixelsProfile->GetBufferWidth(),
46 bitmapPackedPixelsProfile->GetBufferHeight(),
47 bitmap->GetImageWidth(),
48 bitmap->GetImageHeight(),
49 bitmap->GetPixelFormat()),
52 mDiscardPolicy(policy)
54 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
55 DALI_LOG_SET_OBJECT_STRING(this, DALI_LOG_GET_OBJECT_STRING(bitmap));
58 BitmapTexture::BitmapTexture(
61 Pixel::Format pixelFormat,
64 ResourcePolicy::Discardable policy)
70 mClearPixels(clearPixels),
71 mDiscardPolicy(policy)
73 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
76 BitmapTexture::~BitmapTexture()
78 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
80 // GlCleanup() should already have been called by TextureCache ensuring the resource is destroyed
81 // on the render thread. (And avoiding a potentially problematic virtual call in the destructor)
84 void BitmapTexture::UploadBitmapArray( const BitmapUploadArray& bitmapArray )
86 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
93 mContext.ActiveTexture(GL_TEXTURE7); // bind in unused unit so rebind works the first time
94 mContext.Bind2dTexture(mId);
95 mContext.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
97 GLenum pixelFormat = GL_RGBA;
98 GLenum pixelDataType = GL_UNSIGNED_BYTE;
100 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
102 // go through each bitmap uploading it
104 for( BitmapUploadArray::const_iterator iter = bitmapArray.begin(), endIter = bitmapArray.end(); iter != endIter ; ++iter)
106 const BitmapUpload& bitmapItem((*iter));
108 DALI_ASSERT_ALWAYS(bitmapItem.mPixelData);
110 const unsigned char* pixels = bitmapItem.mPixelData;
112 DALI_ASSERT_DEBUG( (pixels!=NULL) && "bitmap has no data \n");
114 unsigned int bitmapWidth(bitmapItem.mWidth);
115 unsigned int bitmapHeight(bitmapItem.mHeight);
117 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "upload bitmap to texture :%d y:%d w:%d h:%d\n",
123 mContext.TexSubImage2D(GL_TEXTURE_2D,
124 0, /* mip map level */
125 bitmapItem.mXpos, /* X pos */
126 bitmapItem.mYpos, /* Y pos */
127 bitmapWidth, /* width */
128 bitmapHeight, /* height */
129 pixelFormat, /* our bitmap format (should match internal format) */
130 pixelDataType, /* pixel data type */
131 pixels); /* texture data */
133 if( BitmapUpload::DISCARD_PIXEL_DATA == bitmapItem.mDiscard)
135 delete [] bitmapItem.mPixelData;
140 bool BitmapTexture::HasAlphaChannel() const
142 return Pixel::HasAlpha(mPixelFormat);
145 bool BitmapTexture::IsFullyOpaque() const
149 return mBitmap->IsFullyOpaque();
153 return ! HasAlphaChannel(); // Todo: amalgamate updated bitmap's IsFullyOpaque()
157 // Bitmap buffer has been changed. Upload changes to GPU.
158 void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char* pixels )
160 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
161 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AreaUpdated()\n");
163 GLenum pixelFormat = GL_RGBA;
164 GLenum pixelDataType = GL_UNSIGNED_BYTE;
165 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
167 mContext.ActiveTexture(GL_TEXTURE7); // bind in unused unit so rebind works the first time
169 mContext.Bind2dTexture(mId);
171 if( ! updateArea.IsEmpty() )
173 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
174 DALI_LOG_INFO( Debug::Filter::gImage, Debug::General, "Update x:%d y:%d w:%d h:%d\n",
175 updateArea.x, updateArea.y, updateArea.width ,updateArea.height );
177 // TODO: obtain pitch of source image, obtain pixel depth of source image.
178 const unsigned int pitchPixels = mImageWidth;
179 const unsigned int pixelDepth = sizeof(unsigned int);
181 // If the width of the source update area is the same as the pitch, then can
182 // copy the contents in a single contiguous TexSubImage call.
183 if(updateArea.x == 0 && updateArea.width == pitchPixels)
185 pixels += updateArea.y * pitchPixels * pixelDepth;
186 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, updateArea.y,
187 updateArea.width, updateArea.height,
188 pixelFormat, pixelDataType, pixels );
192 // Otherwise the source buffer needs to be copied line at a time, as OpenGL ES
193 // does not support source strides. (no GL_UNPACK_ROW_LENGTH supported)
194 unsigned int yBottom = updateArea.y + updateArea.height;
195 pixels += (updateArea.y * pitchPixels + updateArea.x) * pixelDepth;
197 for(unsigned int y = updateArea.y; y < yBottom; y++)
199 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, y,
201 pixelFormat, pixelDataType, pixels );
202 pixels += pitchPixels * pixelDepth;
206 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED,
207 updateArea.Area()* GetBytesPerPixel( mPixelFormat ));
212 void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pixels )
214 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
215 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AssignBitmap()\n");
217 GLenum pixelFormat = GL_RGBA;
218 GLenum pixelDataType = GL_UNSIGNED_BYTE;
220 if( generateTexture )
222 mContext.GenTextures(1, &mId);
224 DALI_ASSERT_DEBUG( mId != 0 );
226 mContext.ActiveTexture(GL_TEXTURE7); // bind in unused unit so rebind works the first time
227 mContext.Bind2dTexture(mId);
228 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
230 mContext.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
231 mContext.TexImage2D(GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, pixels);
232 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
233 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
235 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
238 void BitmapTexture::Update( Integration::Bitmap* bitmap )
240 DALI_LOG_INFO( Debug::Filter::gGLResource, Debug::General, "BitmapTexture::Update(bitmap:%p )\n", bitmap );
241 DALI_ASSERT_DEBUG( bitmap != 0 );
244 DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture." );
248 // Only Packed-pixel bitmaps are ever associated with BitmapTextures, so we should never be passed any other kind:
249 const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixels = bitmap->GetPackedPixelsProfile();
250 DALI_ASSERT_DEBUG(bitmapPackedPixels);
251 if( !bitmapPackedPixels )
253 ///! This should never happen.
254 DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.");
259 const unsigned char* pixels = mBitmap->GetBuffer();
261 // We should never have null pixel data here - resource manager has deliberately loaded/reloaded data
263 DALI_ASSERT_DEBUG( pixels != NULL );
267 DALI_LOG_ERROR("BitmapTexture::Upload() - Bitmap has no pixel data.\n");
271 if( mImageWidth == mBitmap->GetImageWidth() &&
272 mImageHeight == mBitmap->GetImageHeight() &&
273 mWidth == bitmapPackedPixels->GetBufferWidth() &&
274 mHeight == bitmapPackedPixels->GetBufferHeight() &&
275 mPixelFormat == mBitmap->GetPixelFormat() ) // and size hasn't changed
277 RectArea area(0, 0, mImageWidth, mImageHeight); // just update whole texture
278 AreaUpdated( area, pixels );
279 DiscardBitmapBuffer();
281 else // Otherwise, reload the pixel data
283 mImageWidth = mBitmap->GetImageWidth();
284 mImageHeight = mBitmap->GetImageHeight();
285 mWidth = bitmapPackedPixels->GetBufferWidth();
286 mHeight = bitmapPackedPixels->GetBufferHeight();
287 mPixelFormat = mBitmap->GetPixelFormat();
289 AssignBitmap( false, pixels );
294 void BitmapTexture::UpdateArea( const RectArea& updateArea )
296 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "BitmapTexture::UpdateArea()\n");
300 const unsigned char* pixels = mBitmap->GetBuffer();
302 // Pixel data could be null if we've uploaded to GL and discarded the data.
306 if( mId ) // If the texture is already bound
308 if( updateArea.IsEmpty() )
313 area.width = mImageWidth;
314 area.height = mImageHeight;
315 AreaUpdated( area, pixels );
319 AreaUpdated( updateArea, pixels );
326 void BitmapTexture::ClearAreas( const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
330 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
331 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AreaUpdated()\n");
333 GLenum pixelFormat = GL_RGBA;
334 GLenum pixelDataType = GL_UNSIGNED_BYTE;
335 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
337 mContext.ActiveTexture(GL_TEXTURE7); // bind in unused unit so rebind works the first time
338 mContext.Bind2dTexture(mId);
340 size_t numPixels = blockSize*blockSize;
341 size_t bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
342 char* clearPixels = (char*)malloc(numPixels * bytesPerPixel);
344 for(size_t i=0; i<numPixels; i++)
346 memcpy(&clearPixels[i*bytesPerPixel], &color, bytesPerPixel);
349 for( BitmapClearArray::const_iterator iter = areaArray.begin(), endIter = areaArray.end(); iter != endIter ; ++iter)
351 const Vector2& clearPos((*iter));
353 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
354 DALI_LOG_INFO( Debug::Filter::gImage, Debug::General, "Update x:%0.2f y:%0.2f w:%d h:%d\n",
355 clearPos.x, clearPos.y, blockSize, blockSize );
357 mContext.TexSubImage2D(GL_TEXTURE_2D,
363 pixelFormat, /* our bitmap format (should match internal format) */
364 pixelDataType, /* pixel data type */
365 clearPixels); /* texture data */
367 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, numPixels * bytesPerPixel );
373 bool BitmapTexture::UpdateOnCreate()
378 bool BitmapTexture::CreateGlTexture()
380 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
381 DALI_LOG_INFO(Debug::Filter::gImage, Debug::Verbose, "BitmapTexture::CreateGlTexture() Bitmap: %s\n", DALI_LOG_GET_OBJECT_C_STR(this));
385 const unsigned char* pixels = mBitmap->GetBuffer();
387 // pixel data could be NULL here if we've had a context loss and we previously discarded
388 // the pixel data on the previous upload. If it is null, then we shouldn't generate a
389 // new GL Texture; leaving mId as zero. Eventually, the bitmap will get reloaded,
390 // and pixels will become non-null.
394 AssignBitmap( true, pixels );
395 DiscardBitmapBuffer();
400 const unsigned char* pixels = NULL;
401 std::vector<unsigned char> pixelData;
402 if( ( NULL == pixels ) && ( true == mClearPixels ) )
404 unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel(mPixelFormat);
405 pixelData.resize(size, 0);
406 pixels = &pixelData[0];
408 AssignBitmap( true, pixels );
414 bool BitmapTexture::Init()
416 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
417 // mBitmap should be initialized by now
418 return (mBitmap != 0);
421 unsigned int BitmapTexture::GetWidth() const
423 unsigned int width = mWidth;
426 width = mBitmap->GetImageWidth();
431 unsigned int BitmapTexture::GetHeight() const
433 unsigned int height = mHeight;
436 height = mBitmap->GetImageHeight();
441 void BitmapTexture::DiscardBitmapBuffer()
443 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "BitmapTexture::DiscardBitmapBuffer() DiscardPolicy: %s\n", mDiscardPolicy == ResourcePolicy::DISCARD?"DISCARD":"RETAIN");
445 if( ResourcePolicy::DISCARD == mDiscardPolicy )
447 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, " Discarding bitmap\n");
448 mBitmap->DiscardBuffer();
453 } //namespace Internal