2 * Copyright (c) 2016 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>
25 #include <dali/public-api/common/dali-vector.h>
26 #include <dali/public-api/images/buffer-image.h> // For PixelBuffer
27 #include <dali/integration-api/debug.h>
28 #include <dali/internal/render/common/performance-monitor.h>
29 #include <dali/internal/render/gl-resources/context.h>
30 #include <dali/internal/render/gl-resources/texture-units.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()),
50 mPixelFormat(bitmap->GetPixelFormat()),
51 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)
69 mPixelFormat( pixelFormat ),
70 mDiscardPolicy(policy),
71 mClearPixels(clearPixels)
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 bool BitmapTexture::HasAlphaChannel() const
86 return Pixel::HasAlpha(mPixelFormat);
89 bool BitmapTexture::IsFullyOpaque() const
93 return mBitmap->IsFullyOpaque();
97 return ! HasAlphaChannel(); // Todo: amalgamate updated bitmap's IsFullyOpaque()
101 // Bitmap buffer has been changed. Upload changes to GPU.
102 void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char* pixels )
104 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
105 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AreaUpdated()\n");
107 GLenum pixelFormat = GL_RGBA;
108 GLenum pixelDataType = GL_UNSIGNED_BYTE;
109 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
111 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
113 mContext.Bind2dTexture(mId);
115 if( ! updateArea.IsEmpty() )
117 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
118 DALI_LOG_INFO( Debug::Filter::gImage, Debug::General, "Update x:%d y:%d w:%d h:%d\n",
119 updateArea.x, updateArea.y, updateArea.width ,updateArea.height );
121 const unsigned int pitchPixels = mWidth;
122 const unsigned int pixelDepth = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
124 // If the width of the source update area is the same as the pitch, then can
125 // copy the contents in a single contiguous TexSubImage call.
126 if(updateArea.x == 0 && updateArea.width == pitchPixels)
128 pixels += updateArea.y * pitchPixels * pixelDepth;
129 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, updateArea.y,
130 updateArea.width, updateArea.height,
131 pixelFormat, pixelDataType, pixels );
135 // Otherwise the source buffer needs to be copied line at a time, as OpenGL ES
136 // does not support source strides. (no GL_UNPACK_ROW_LENGTH supported)
137 unsigned int yBottom = updateArea.y + updateArea.height;
138 pixels += (updateArea.y * pitchPixels + updateArea.x) * pixelDepth;
140 for(unsigned int y = updateArea.y; y < yBottom; y++)
142 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, y,
144 pixelFormat, pixelDataType, pixels );
145 pixels += pitchPixels * pixelDepth;
149 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED,
150 updateArea.Area()* GetBytesPerPixel( mPixelFormat ));
154 void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pixels )
156 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
157 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AssignBitmap()\n");
159 GLenum pixelFormat = GL_RGBA;
160 GLenum pixelDataType = GL_UNSIGNED_BYTE;
162 if( generateTexture )
164 mContext.GenTextures(1, &mId);
166 DALI_ASSERT_DEBUG( mId != 0 );
168 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
169 mContext.Bind2dTexture(mId);
170 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
172 mContext.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
173 mContext.TexImage2D(GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, pixels);
174 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
175 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
177 // If the resource policy is to discard on upload then release buffer
178 DiscardBitmapBuffer();
182 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
186 void BitmapTexture::Update( Integration::Bitmap* bitmap )
188 DALI_LOG_INFO( Debug::Filter::gGLResource, Debug::General, "BitmapTexture::Update(bitmap:%p )\n", bitmap );
189 DALI_ASSERT_DEBUG( bitmap != 0 );
192 DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture.\n" );
196 // Only Packed-pixel bitmaps are ever associated with BitmapTextures, so we should never be passed any other kind:
197 const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixels = bitmap->GetPackedPixelsProfile();
198 DALI_ASSERT_DEBUG(bitmapPackedPixels);
199 if( !bitmapPackedPixels )
201 ///! This should never happen.
202 DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.\n");
207 const unsigned char* pixels = mBitmap->GetBuffer();
209 // We should never have null pixel data here - resource manager has deliberately loaded/reloaded data
211 DALI_ASSERT_DEBUG( pixels != NULL );
215 DALI_LOG_ERROR("BitmapTexture::Upload() - Bitmap has no pixel data.\n");
219 if( mImageWidth == mBitmap->GetImageWidth() &&
220 mImageHeight == mBitmap->GetImageHeight() &&
221 mWidth == bitmapPackedPixels->GetBufferWidth() &&
222 mHeight == bitmapPackedPixels->GetBufferHeight() &&
223 mPixelFormat == mBitmap->GetPixelFormat() ) // and size hasn't changed
225 RectArea area(0, 0, mImageWidth, mImageHeight); // just update whole texture
226 AreaUpdated( area, pixels );
227 DiscardBitmapBuffer();
229 else // Otherwise, reload the pixel data
231 mImageWidth = mBitmap->GetImageWidth();
232 mImageHeight = mBitmap->GetImageHeight();
233 mWidth = bitmapPackedPixels->GetBufferWidth();
234 mHeight = bitmapPackedPixels->GetBufferHeight();
235 mPixelFormat = mBitmap->GetPixelFormat();
237 AssignBitmap( false, pixels );
242 void BitmapTexture::Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset )
244 if( NULL != srcBitmap )
246 Update( srcBitmap->GetBuffer(), srcBitmap->GetImageWidth(), srcBitmap->GetImageHeight(),
247 srcBitmap->GetPixelFormat(), xOffset, yOffset);
251 void BitmapTexture::Update( PixelData* srcPixelData, std::size_t xOffset, std::size_t yOffset )
253 if( NULL != srcPixelData )
255 Update( srcPixelData->GetBuffer(), srcPixelData->GetWidth(), srcPixelData->GetHeight(),
256 srcPixelData->GetPixelFormat(), xOffset, yOffset);
260 void BitmapTexture::Update( const unsigned char* pixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat, std::size_t xOffset, std::size_t yOffset )
263 GLenum pixelGLFormat = GL_RGBA;
264 GLenum pixelDataType = GL_UNSIGNED_BYTE;
265 Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelGLFormat );
269 mContext.GenTextures( 1, &mId );
271 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
272 mContext.Bind2dTexture( mId );
273 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
275 mContext.TexImage2D( GL_TEXTURE_2D, 0, pixelGLFormat, mWidth, mHeight, 0, pixelGLFormat, pixelDataType, NULL );
276 mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
277 mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
281 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
282 mContext.Bind2dTexture( mId );
283 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
286 #if DALI_GLES_VERSION >= 30
287 // For GLES 3.0, uploading sub-image with different format is a valid operation.
288 Integration::ConvertToGlFormat( pixelFormat, pixelDataType, pixelGLFormat );
290 // Allows RGB888 source bitmap to be added to RGBA8888 texture, need to convert the bitmap format manually.
291 if(pixelFormat == Pixel::RGB888 && mPixelFormat == Pixel::RGBA8888 )
293 std::size_t size = width * height;
295 Vector<PixelBuffer> tempBuffer;
296 tempBuffer.Reserve( size*4u );
297 PixelBuffer* data = tempBuffer.Begin();
299 for( std::size_t i=0u; i<size; i++ )
301 data[i*4u] = pixels[i*3u];
302 data[i*4u+1] = pixels[i*3u+1];
303 data[i*4u+2] = pixels[i*3u+2];
307 mContext.TexSubImage2D( GL_TEXTURE_2D, 0,
310 pixelGLFormat, pixelDataType,
317 mContext.TexSubImage2D( GL_TEXTURE_2D, 0,
320 pixelGLFormat, pixelDataType,
324 void BitmapTexture::UpdateArea( const RectArea& updateArea )
326 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "BitmapTexture::UpdateArea()\n");
330 const unsigned char* pixels = mBitmap->GetBuffer();
332 // Pixel data could be null if we've uploaded to GL and discarded the data.
336 if( mId ) // If the texture is already bound
338 if( updateArea.IsEmpty() )
343 area.width = mImageWidth;
344 area.height = mImageHeight;
345 AreaUpdated( area, pixels );
349 AreaUpdated( updateArea, pixels );
356 bool BitmapTexture::UpdateOnCreate()
361 bool BitmapTexture::CreateGlTexture()
363 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
364 DALI_LOG_INFO(Debug::Filter::gImage, Debug::Verbose, "BitmapTexture::CreateGlTexture() Bitmap: %s\n", DALI_LOG_GET_OBJECT_C_STR(this));
368 const unsigned char* pixels = mBitmap->GetBuffer();
370 // pixel data could be NULL here if we've had a context loss and we previously discarded
371 // the pixel data on the previous upload. If it is null, then we shouldn't generate a
372 // new GL Texture; leaving mId as zero. Eventually, the bitmap will get reloaded,
373 // and pixels will become non-null.
377 AssignBitmap( true, pixels );
378 DiscardBitmapBuffer();
383 const unsigned char* pixels = NULL;
384 Dali::Vector<unsigned char> pixelData; // Okay to create outside branch as empty vector has no heap allocation.
385 if( true == mClearPixels )
387 unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel( mPixelFormat );
388 pixelData.Resize( size, 0 );
389 pixels = &pixelData[0];
391 AssignBitmap( true, pixels );
397 bool BitmapTexture::Init()
399 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
400 // mBitmap should be initialized by now
401 return (mBitmap != 0);
404 unsigned int BitmapTexture::GetWidth() const
406 unsigned int width = mWidth;
409 width = mBitmap->GetImageWidth();
414 unsigned int BitmapTexture::GetHeight() const
416 unsigned int height = mHeight;
419 height = mBitmap->GetImageHeight();
424 void BitmapTexture::DiscardBitmapBuffer()
426 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "BitmapTexture::DiscardBitmapBuffer() DiscardPolicy: %s\n", mDiscardPolicy == ResourcePolicy::OWNED_DISCARD?"DISCARD":"RETAIN");
428 if( ResourcePolicy::OWNED_DISCARD == mDiscardPolicy )
430 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, " Discarding bitmap\n");
433 mBitmap->DiscardBuffer();
439 } //namespace Internal