Cleaning up some dead code with geometry scaling, rendering type declarations and...
[platform/core/uifw/dali-core.git] / dali / internal / render / gl-resources / bitmap-texture.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/render/gl-resources/bitmap-texture.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-vector.h>
23 #include <dali/integration-api/debug.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>
27
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 BitmapTexture::BitmapTexture(
36   Integration::Bitmap* const bitmap,
37   const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixelsProfile,
38   Context& context,
39   ResourcePolicy::Discardable policy)
40 : Texture( context,
41            bitmapPackedPixelsProfile->GetBufferWidth(),
42            bitmapPackedPixelsProfile->GetBufferHeight(),
43            bitmap->GetImageWidth(),
44            bitmap->GetImageHeight()),
45   mBitmap(bitmap),
46   mClearPixels(false),
47   mDiscardPolicy(policy),
48   mPixelFormat(bitmap->GetPixelFormat())
49 {
50   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
51   DALI_LOG_SET_OBJECT_STRING(this, DALI_LOG_GET_OBJECT_STRING(bitmap));
52 }
53
54 BitmapTexture::BitmapTexture(
55   unsigned int width,
56   unsigned int height,
57   Pixel::Format pixelFormat,
58   bool clearPixels,
59   Context& context,
60   ResourcePolicy::Discardable policy)
61 : Texture( context,
62            width, height,
63            width, height),
64   mBitmap(NULL),
65   mClearPixels(clearPixels),
66   mDiscardPolicy(policy),
67   mPixelFormat( pixelFormat )
68 {
69   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
70 }
71
72 BitmapTexture::~BitmapTexture()
73 {
74   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
75
76   // GlCleanup() should already have been called by TextureCache ensuring the resource is destroyed
77   // on the render thread. (And avoiding a potentially problematic virtual call in the destructor)
78 }
79
80 bool BitmapTexture::HasAlphaChannel() const
81 {
82   return Pixel::HasAlpha(mPixelFormat);
83 }
84
85 bool BitmapTexture::IsFullyOpaque() const
86 {
87   if( mBitmap )
88   {
89     return mBitmap->IsFullyOpaque();
90   }
91   else
92   {
93     return ! HasAlphaChannel(); // Todo: amalgamate updated bitmap's IsFullyOpaque()
94   }
95 }
96
97 // Bitmap buffer has been changed. Upload changes to GPU.
98 void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char* pixels )
99 {
100   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
101   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AreaUpdated()\n");
102
103   GLenum pixelFormat   = GL_RGBA;
104   GLenum pixelDataType = GL_UNSIGNED_BYTE;
105   Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
106
107   mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
108
109   mContext.Bind2dTexture(mId);
110
111   if( ! updateArea.IsEmpty() )
112   {
113     mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
114     DALI_LOG_INFO( Debug::Filter::gImage, Debug::General, "Update x:%d y:%d w:%d h:%d\n",
115                    updateArea.x, updateArea.y, updateArea.width ,updateArea.height );
116
117     const unsigned int pitchPixels = mWidth;
118     const unsigned int pixelDepth = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
119
120     // If the width of the source update area is the same as the pitch, then can
121     // copy the contents in a single contiguous TexSubImage call.
122     if(updateArea.x == 0 && updateArea.width == pitchPixels)
123     {
124       pixels += updateArea.y * pitchPixels * pixelDepth;
125       mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, updateArea.y,
126                               updateArea.width, updateArea.height,
127                               pixelFormat, pixelDataType, pixels );
128     }
129     else
130     {
131       // Otherwise the source buffer needs to be copied line at a time, as OpenGL ES
132       // does not support source strides. (no GL_UNPACK_ROW_LENGTH supported)
133       unsigned int yBottom = updateArea.y + updateArea.height;
134       pixels += (updateArea.y * pitchPixels + updateArea.x) * pixelDepth;
135
136       for(unsigned int y = updateArea.y; y < yBottom; y++)
137       {
138         mContext.TexSubImage2D( GL_TEXTURE_2D,0, updateArea.x, y,
139                                 updateArea.width, 1,
140                                 pixelFormat, pixelDataType, pixels );
141         pixels += pitchPixels * pixelDepth;
142       }
143     }
144
145     INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED,
146                  updateArea.Area()* GetBytesPerPixel( mPixelFormat ));
147   }
148 }
149
150 void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pixels )
151 {
152   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
153   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::Verbose, "BitmapTexture::AssignBitmap()\n");
154
155   GLenum pixelFormat = GL_RGBA;
156   GLenum pixelDataType = GL_UNSIGNED_BYTE;
157
158   if( generateTexture )
159   {
160     mContext.GenTextures(1, &mId);
161   }
162   DALI_ASSERT_DEBUG( mId != 0 );
163
164   mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
165   mContext.Bind2dTexture(mId);
166   Integration::ConvertToGlFormat(mPixelFormat, pixelDataType, pixelFormat);
167
168   mContext.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
169   mContext.TexImage2D(GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, pixels);
170   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
171   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
172
173   // If the resource policy is to discard on upload then release buffer
174   DiscardBitmapBuffer();
175
176   if( pixels != NULL )
177   {
178     INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
179   }
180 }
181
182 void BitmapTexture::Update( Integration::Bitmap* bitmap )
183 {
184   DALI_LOG_INFO( Debug::Filter::gGLResource, Debug::General, "BitmapTexture::Update(bitmap:%p )\n", bitmap );
185   DALI_ASSERT_DEBUG( bitmap != 0 );
186   if( !bitmap )
187   {
188     DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture." );
189     return;
190   }
191
192   // Only Packed-pixel bitmaps are ever associated with BitmapTextures, so we should never be passed any other kind:
193   const Integration::Bitmap::PackedPixelsProfile * const bitmapPackedPixels = bitmap->GetPackedPixelsProfile();
194   DALI_ASSERT_DEBUG(bitmapPackedPixels);
195   if( !bitmapPackedPixels )
196   {
197     ///! This should never happen.
198     DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.");
199     return;
200   }
201   mBitmap = bitmap;
202
203   const unsigned char* pixels = mBitmap->GetBuffer();
204
205   // We should never have null pixel data here - resource manager has deliberately loaded/reloaded data
206
207   DALI_ASSERT_DEBUG( pixels != NULL );
208
209   if( NULL == pixels )
210   {
211     DALI_LOG_ERROR("BitmapTexture::Upload() - Bitmap has no pixel data.\n");
212   }
213   else if( mId != 0 )
214   {
215     if( mImageWidth == mBitmap->GetImageWidth() &&
216         mImageHeight == mBitmap->GetImageHeight() &&
217         mWidth  == bitmapPackedPixels->GetBufferWidth() &&
218         mHeight == bitmapPackedPixels->GetBufferHeight() &&
219         mPixelFormat == mBitmap->GetPixelFormat() ) // and size hasn't changed
220     {
221       RectArea area(0, 0, mImageWidth, mImageHeight);  // just update whole texture
222       AreaUpdated( area, pixels );
223       DiscardBitmapBuffer();
224     }
225     else // Otherwise, reload the pixel data
226     {
227       mImageWidth  = mBitmap->GetImageWidth();
228       mImageHeight = mBitmap->GetImageHeight();
229       mWidth       = bitmapPackedPixels->GetBufferWidth();
230       mHeight      = bitmapPackedPixels->GetBufferHeight();
231       mPixelFormat = mBitmap->GetPixelFormat();
232
233       AssignBitmap( false, pixels );
234     }
235   }
236 }
237
238 void BitmapTexture::Update( Integration::Bitmap* srcBitmap, std::size_t xOffset, std::size_t yOffset )
239 {
240   if( NULL != srcBitmap )
241   {
242     Update( srcBitmap->GetBuffer(), srcBitmap->GetImageWidth(), srcBitmap->GetImageHeight(),
243             srcBitmap->GetPixelFormat(), xOffset, yOffset);
244   }
245 }
246
247 void BitmapTexture::Update( PixelData* srcPixelData, std::size_t xOffset, std::size_t yOffset )
248 {
249   if( NULL != srcPixelData )
250   {
251     Update( srcPixelData->GetBuffer(), srcPixelData->GetWidth(), srcPixelData->GetHeight(),
252             srcPixelData->GetPixelFormat(), xOffset, yOffset);
253   }
254 }
255
256 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 )
257 {
258
259   GLenum pixelGLFormat   = GL_RGBA;
260   GLenum pixelDataType = GL_UNSIGNED_BYTE;
261   Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelGLFormat );
262
263   if( !mId )
264   {
265     mContext.GenTextures( 1, &mId );
266
267     mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
268     mContext.Bind2dTexture( mId );
269     mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
270
271     mContext.TexImage2D( GL_TEXTURE_2D, 0, pixelGLFormat, mWidth, mHeight, 0, pixelGLFormat, pixelDataType, NULL );
272     mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
273     mContext.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
274   }
275   else
276   {
277     mContext.ActiveTexture( TEXTURE_UNIT_UPLOAD );
278     mContext.Bind2dTexture( mId );
279     mContext.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
280   }
281
282 #if DALI_GLES_VERSION >= 30
283 // for gles 3.0, uploading sub-image with different format is a valid operation
284   Integration::ConvertToGlFormat( srcBitmap->GetPixelFormat(), pixelDataType, pixelGLFormat );
285 #else
286   // allows RGB888 source bitmap to be added to RGBA8888 texture, need to convert the bitmap format manually
287   if(pixelFormat == Pixel::RGB888 && mPixelFormat == Pixel::RGBA8888 )
288   {
289     std::size_t size = width * height;
290
291     Vector<PixelBuffer> tempBuffer;
292     tempBuffer.Reserve( size*4u );
293     PixelBuffer* data = tempBuffer.Begin();
294
295     for( std::size_t i=0u; i<size; i++ )
296     {
297       data[i*4u] = pixels[i*3u];
298       data[i*4u+1] = pixels[i*3u+1];
299       data[i*4u+2] = pixels[i*3u+2];
300       data[i*4u+3] = 0xFF;
301     }
302
303     mContext.TexSubImage2D( GL_TEXTURE_2D, 0,
304                             xOffset, yOffset,
305                             width, height,
306                             pixelGLFormat, pixelDataType,
307                             data );
308
309     return;
310   }
311 #endif
312
313   mContext.TexSubImage2D( GL_TEXTURE_2D, 0,
314                           xOffset, yOffset,
315                           width, height,
316                           pixelGLFormat, pixelDataType,
317                           pixels );
318 }
319
320 void BitmapTexture::UpdateArea( const RectArea& updateArea )
321 {
322   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "BitmapTexture::UpdateArea()\n");
323
324   if( mBitmap != 0 )
325   {
326     const unsigned char* pixels = mBitmap->GetBuffer();
327
328     // Pixel data could be null if we've uploaded to GL and discarded the data.
329
330     if( NULL != pixels )
331     {
332       if( mId ) // If the texture is already bound
333       {
334         if( updateArea.IsEmpty() )
335         {
336           RectArea area;
337           area.x = 0;
338           area.y = 0;
339           area.width = mImageWidth;
340           area.height = mImageHeight;
341           AreaUpdated( area, pixels );
342         }
343         else
344         {
345           AreaUpdated( updateArea, pixels );
346         }
347       }
348     }
349   }
350 }
351
352 bool BitmapTexture::UpdateOnCreate()
353 {
354   return true;
355 }
356
357 bool BitmapTexture::CreateGlTexture()
358 {
359   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
360   DALI_LOG_INFO(Debug::Filter::gImage, Debug::Verbose, "BitmapTexture::CreateGlTexture() Bitmap: %s\n", DALI_LOG_GET_OBJECT_C_STR(this));
361
362   if( mBitmap )
363   {
364     const unsigned char* pixels = mBitmap->GetBuffer();
365
366     // pixel data could be NULL here if we've had a context loss and we previously discarded
367     // the pixel data on the previous upload. If it is null, then we shouldn't generate a
368     // new GL Texture; leaving mId as zero. Eventually, the bitmap will get reloaded,
369     // and pixels will become non-null.
370
371     if( NULL != pixels )
372     {
373       AssignBitmap( true, pixels );
374       DiscardBitmapBuffer();
375     }
376   }
377   else
378   {
379     const unsigned char* pixels = NULL;
380     Dali::Vector<unsigned char> pixelData; // Okay to create outside branch as empty vector has no heap allocation.
381     if( true == mClearPixels )
382     {
383       unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel( mPixelFormat );
384       pixelData.Resize( size, 0 );
385       pixels = &pixelData[0];
386     }
387     AssignBitmap( true, pixels );
388   }
389
390   return mId != 0;
391 }
392
393 bool BitmapTexture::Init()
394 {
395   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
396   // mBitmap should be initialized by now
397   return (mBitmap != 0);
398 }
399
400 unsigned int BitmapTexture::GetWidth() const
401 {
402   unsigned int width = mWidth;
403   if( mBitmap )
404   {
405     width = mBitmap->GetImageWidth();
406   }
407   return width;
408 }
409
410 unsigned int BitmapTexture::GetHeight() const
411 {
412   unsigned int height = mHeight;
413   if( mBitmap )
414   {
415     height = mBitmap->GetImageHeight();
416   }
417   return height;
418 }
419
420 void BitmapTexture::DiscardBitmapBuffer()
421 {
422   DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "BitmapTexture::DiscardBitmapBuffer() DiscardPolicy: %s\n", mDiscardPolicy == ResourcePolicy::OWNED_DISCARD?"DISCARD":"RETAIN");
423
424   if( ResourcePolicy::OWNED_DISCARD == mDiscardPolicy )
425   {
426     DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "  Discarding bitmap\n");
427     if ( mBitmap )
428     {
429       mBitmap->DiscardBuffer();
430     }
431   }
432 }
433
434
435 } //namespace Internal
436
437 } //namespace Dali