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>
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/render/common/vertex.h>
24 #include <dali/internal/render/common/performance-monitor.h>
25 #include <dali/internal/render/gl-resources/context.h>
26 #include <dali/internal/render/gl-resources/texture-units.h>
34 BitmapTexture::BitmapTexture(
35 Integration::Bitmap* const bitmap,
36 const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixelsProfile,
38 ResourcePolicy::Discardable policy)
40 bitmapPackedPixelsProfile->GetBufferWidth(),
41 bitmapPackedPixelsProfile->GetBufferHeight(),
42 bitmap->GetImageWidth(),
43 bitmap->GetImageHeight()),
46 mDiscardPolicy(policy),
47 mPixelFormat(bitmap->GetPixelFormat())
49 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
50 DALI_LOG_SET_OBJECT_STRING(this, DALI_LOG_GET_OBJECT_STRING(bitmap));
53 BitmapTexture::BitmapTexture(
56 Pixel::Format pixelFormat,
59 ResourcePolicy::Discardable policy)
64 mClearPixels(clearPixels),
65 mDiscardPolicy(policy),
66 mPixelFormat( pixelFormat )
68 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
71 BitmapTexture::~BitmapTexture()
73 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
75 // GlCleanup() should already have been called by TextureCache ensuring the resource is destroyed
76 // on the render thread. (And avoiding a potentially problematic virtual call in the destructor)
79 bool BitmapTexture::HasAlphaChannel() const
81 return Pixel::HasAlpha(mPixelFormat);
84 bool BitmapTexture::IsFullyOpaque() const
88 return mBitmap->IsFullyOpaque();
92 return ! HasAlphaChannel(); // Todo: amalgamate updated bitmap's IsFullyOpaque()
96 // Bitmap buffer has been changed. Upload changes to GPU.
97 void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char* pixels )
99 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
100 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AreaUpdated()\n");
102 GLenum pixelFormat = GL_RGBA;
103 GLenum pixelDataType = GL_UNSIGNED_BYTE;
104 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
106 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
108 mContext.Bind2dTexture(mId);
110 if( ! updateArea.IsEmpty() )
112 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
113 DALI_LOG_INFO( Debug::Filter::gImage, Debug::General, "Update x:%d y:%d w:%d h:%d\n",
114 updateArea.x, updateArea.y, updateArea.width ,updateArea.height );
116 const unsigned int pitchPixels = mWidth;
117 const unsigned int pixelDepth = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
119 // If the width of the source update area is the same as the pitch, then can
120 // copy the contents in a single contiguous TexSubImage call.
121 if(updateArea.x == 0 && updateArea.width == pitchPixels)
123 pixels += updateArea.y * pitchPixels * pixelDepth;
124 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, updateArea.y,
125 updateArea.width, updateArea.height,
126 pixelFormat, pixelDataType, pixels );
130 // Otherwise the source buffer needs to be copied line at a time, as OpenGL ES
131 // does not support source strides. (no GL_UNPACK_ROW_LENGTH supported)
132 unsigned int yBottom = updateArea.y + updateArea.height;
133 pixels += (updateArea.y * pitchPixels + updateArea.x) * pixelDepth;
135 for(unsigned int y = updateArea.y; y < yBottom; y++)
137 mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, y,
139 pixelFormat, pixelDataType, pixels );
140 pixels += pitchPixels * pixelDepth;
144 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED,
145 updateArea.Area()* GetBytesPerPixel( mPixelFormat ));
149 void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pixels )
151 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
152 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AssignBitmap()\n");
154 GLenum pixelFormat = GL_RGBA;
155 GLenum pixelDataType = GL_UNSIGNED_BYTE;
157 if( generateTexture )
159 mContext.GenTextures(1, &mId);
161 DALI_ASSERT_DEBUG( mId != 0 );
163 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
164 mContext.Bind2dTexture(mId);
165 Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
167 mContext.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
168 mContext.TexImage2D(GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, pixels);
169 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
170 mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
172 // If the resource policy is to discard on upload then release buffer
173 DiscardBitmapBuffer();
177 INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
181 void BitmapTexture::Update( Integration::Bitmap* bitmap )
183 DALI_LOG_INFO( Debug::Filter::gGLResource, Debug::General, "BitmapTexture::Update(bitmap:%p )\n", bitmap );
184 DALI_ASSERT_DEBUG( bitmap != 0 );
187 DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture." );
191 // Only Packed-pixel bitmaps are ever associated with BitmapTextures, so we should never be passed any other kind:
192 const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixels = bitmap->GetPackedPixelsProfile();
193 DALI_ASSERT_DEBUG(bitmapPackedPixels);
194 if( !bitmapPackedPixels )
196 ///! This should never happen.
197 DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.");
202 const unsigned char* pixels = mBitmap->GetBuffer();
204 // We should never have null pixel data here - resource manager has deliberately loaded/reloaded data
206 DALI_ASSERT_DEBUG( pixels != NULL );
210 DALI_LOG_ERROR("BitmapTexture::Upload() - Bitmap has no pixel data.\n");
214 if( mImageWidth == mBitmap->GetImageWidth() &&
215 mImageHeight == mBitmap->GetImageHeight() &&
216 mWidth == bitmapPackedPixels->GetBufferWidth() &&
217 mHeight == bitmapPackedPixels->GetBufferHeight() &&
218 mPixelFormat == mBitmap->GetPixelFormat() ) // and size hasn't changed
220 RectArea area(0, 0, mImageWidth, mImageHeight); // just update whole texture
221 AreaUpdated( area, pixels );
222 DiscardBitmapBuffer();
224 else // Otherwise, reload the pixel data
226 mImageWidth = mBitmap->GetImageWidth();
227 mImageHeight = mBitmap->GetImageHeight();
228 mWidth = bitmapPackedPixels->GetBufferWidth();
229 mHeight = bitmapPackedPixels->GetBufferHeight();
230 mPixelFormat = mBitmap->GetPixelFormat();
232 AssignBitmap( false, pixels );
237 void BitmapTexture::Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset )
239 if( NULL != srcBitmap )
241 GLenum pixelFormat = GL_RGBA;
242 GLenum pixelDataType = GL_UNSIGNED_BYTE;
243 Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelFormat );
247 mContext.GenTextures( 1, &mId );
249 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
250 mContext.Bind2dTexture( mId );
251 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
253 mContext.TexImage2D( GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, NULL );
254 mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
255 mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
259 mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
260 mContext.Bind2dTexture( mId );
261 mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
264 mContext.TexSubImage2D( GL_TEXTURE_2D, 0,
266 srcBitmap->GetImageWidth(), srcBitmap->GetImageHeight(),
267 pixelFormat, pixelDataType, srcBitmap->GetBuffer() );
271 void BitmapTexture::UpdateArea( const RectArea& updateArea )
273 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "BitmapTexture::UpdateArea()\n");
277 const unsigned char* pixels = mBitmap->GetBuffer();
279 // Pixel data could be null if we've uploaded to GL and discarded the data.
283 if( mId ) // If the texture is already bound
285 if( updateArea.IsEmpty() )
290 area.width = mImageWidth;
291 area.height = mImageHeight;
292 AreaUpdated( area, pixels );
296 AreaUpdated( updateArea, pixels );
303 bool BitmapTexture::UpdateOnCreate()
308 bool BitmapTexture::CreateGlTexture()
310 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
311 DALI_LOG_INFO(Debug::Filter::gImage, Debug::Verbose, "BitmapTexture::CreateGlTexture() Bitmap: %s\n", DALI_LOG_GET_OBJECT_C_STR(this));
315 const unsigned char* pixels = mBitmap->GetBuffer();
317 // pixel data could be NULL here if we've had a context loss and we previously discarded
318 // the pixel data on the previous upload. If it is null, then we shouldn't generate a
319 // new GL Texture; leaving mId as zero. Eventually, the bitmap will get reloaded,
320 // and pixels will become non-null.
324 AssignBitmap( true, pixels );
325 DiscardBitmapBuffer();
330 const unsigned char* pixels = NULL;
331 Dali::Vector<unsigned char> pixelData; // Okay to create outside branch as empty vector has no heap allocation.
332 if( true == mClearPixels )
334 unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel( mPixelFormat );
335 pixelData.Resize( size, 0 );
336 pixels = &pixelData[0];
338 AssignBitmap( true, pixels );
344 bool BitmapTexture::Init()
346 DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
347 // mBitmap should be initialized by now
348 return (mBitmap != 0);
351 unsigned int BitmapTexture::GetWidth() const
353 unsigned int width = mWidth;
356 width = mBitmap->GetImageWidth();
361 unsigned int BitmapTexture::GetHeight() const
363 unsigned int height = mHeight;
366 height = mBitmap->GetImageHeight();
371 void BitmapTexture::DiscardBitmapBuffer()
373 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "BitmapTexture::DiscardBitmapBuffer() DiscardPolicy: %s\n", mDiscardPolicy == ResourcePolicy::OWNED_DISCARD?"DISCARD":"RETAIN");
375 if( ResourcePolicy::OWNED_DISCARD == mDiscardPolicy )
377 DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, " Discarding bitmap\n");
380 mBitmap->DiscardBuffer();
386 } //namespace Internal