1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 
29 #include "OgreGLES2HardwareBufferManager.h"
30 #include "OgreGLES2HardwarePixelBuffer.h"
31 #include "OgreGLES2PixelFormat.h"
32 #include "OgreGLES2FBORenderTexture.h"
33 #include "OgreGLES2GpuProgram.h"
34 #include "OgreGLES2Util.h"
35 #include "OgreGLES2RenderSystem.h"
36 #include "OgreGLES2StateCacheManager.h"
37 #include "OgreRoot.h"
38 #include "OgreGLSLESLinkProgramManager.h"
39 #include "OgreGLSLESLinkProgram.h"
40 #include "OgreGLSLESProgramPipelineManager.h"
41 #include "OgreGLSLESProgramPipeline.h"
42 
computeLog(GLuint value)43 static int computeLog(GLuint value)
44 {
45     int i;
46 
47     i = 0;
48 
49     /* Error! */
50     if (value == 0) return -1;
51 
52     for (;;)
53     {
54         if (value & 1)
55         {
56             /* Error! */
57             if (value != 1) return -1;
58                 return i;
59         }
60         value = value >> 1;
61         i++;
62     }
63 }
64 
65 namespace Ogre {
GLES2HardwarePixelBuffer(uint32 width,uint32 height,uint32 depth,PixelFormat format,HardwareBuffer::Usage usage)66     GLES2HardwarePixelBuffer::GLES2HardwarePixelBuffer(uint32 width, uint32 height,
67                                                      uint32 depth, PixelFormat format,
68                                                      HardwareBuffer::Usage usage)
69         : HardwarePixelBuffer(width, height, depth, format, usage, false, false),
70           mBuffer(width, height, depth, format),
71           mGLInternalFormat(GL_NONE)
72     {
73     }
74 
~GLES2HardwarePixelBuffer()75     GLES2HardwarePixelBuffer::~GLES2HardwarePixelBuffer()
76     {
77         // Force free buffer
78         delete [] (uint8*)mBuffer.data;
79     }
80 
allocateBuffer()81     void GLES2HardwarePixelBuffer::allocateBuffer()
82     {
83         if (mBuffer.data)
84             // Already allocated
85             return;
86 
87         mBuffer.data = new uint8[mSizeInBytes];
88         // TODO use PBO if we're HBU_DYNAMIC
89     }
90 
freeBuffer()91     void GLES2HardwarePixelBuffer::freeBuffer()
92     {
93         // Free buffer if we're STATIC to save memory
94         if (mUsage & HBU_STATIC)
95         {
96             delete [] (uint8*)mBuffer.data;
97             mBuffer.data = 0;
98         }
99     }
100 
lockImpl(const Image::Box lockBox,LockOptions options)101     PixelBox GLES2HardwarePixelBuffer::lockImpl(const Image::Box lockBox,  LockOptions options)
102     {
103         allocateBuffer();
104         if (options != HardwareBuffer::HBL_DISCARD)
105         {
106             // Download the old contents of the texture
107             download(mBuffer);
108         }
109         mCurrentLockOptions = options;
110         mLockedBox = lockBox;
111         return mBuffer.getSubVolume(lockBox);
112     }
113 
unlockImpl(void)114     void GLES2HardwarePixelBuffer::unlockImpl(void)
115     {
116         if (mCurrentLockOptions != HardwareBuffer::HBL_READ_ONLY)
117         {
118             // From buffer to card, only upload if was locked for writing
119             upload(mCurrentLock, mLockedBox);
120         }
121         freeBuffer();
122     }
123 
blitFromMemory(const PixelBox & src,const Image::Box & dstBox)124     void GLES2HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
125     {
126         if (!mBuffer.contains(dstBox))
127         {
128             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
129                         "Destination box out of range",
130                         "GLES2HardwarePixelBuffer::blitFromMemory");
131         }
132 
133         PixelBox scaled;
134 
135         if (src.getWidth() != dstBox.getWidth() ||
136             src.getHeight() != dstBox.getHeight() ||
137             src.getDepth() != dstBox.getDepth())
138         {
139             // Scale to destination size.
140             // This also does pixel format conversion if needed
141             allocateBuffer();
142             scaled = mBuffer.getSubVolume(dstBox);
143             Image::scale(src, scaled, Image::FILTER_BILINEAR);
144         }
145 #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
146         else if ((src.format != mFormat) ||
147                  ((GLES2PixelUtil::getGLOriginFormat(src.format) == 0) && (src.format != PF_R8G8B8)))
148 #else
149         else if (GLES2PixelUtil::getGLOriginFormat(src.format) == 0)
150 #endif
151         {
152             // Extents match, but format is not accepted as valid source format for GL
153             // do conversion in temporary buffer
154             allocateBuffer();
155             scaled = mBuffer.getSubVolume(dstBox);
156             PixelUtil::bulkPixelConversion(src, scaled);
157         }
158         else
159         {
160             allocateBuffer();
161 
162             // No scaling or conversion needed
163             scaled = PixelBox(src.getWidth(), src.getHeight(), src.getDepth(), src.format, src.data);
164 
165             if (src.format == PF_R8G8B8)
166             {
167                 size_t srcSize = PixelUtil::getMemorySize(src.getWidth(), src.getHeight(), src.getDepth(), src.format);
168                 scaled.format = PF_B8G8R8;
169                 scaled.data = new uint8[srcSize];
170                 memcpy(scaled.data, src.data, srcSize);
171                 PixelUtil::bulkPixelConversion(src, scaled);
172             }
173 #if OGRE_PLATFORM == OGRE_PLATFORM_NACL
174             if (src.format == PF_A8R8G8B8)
175             {
176                 scaled.format = PF_A8B8G8R8;
177                 PixelUtil::bulkPixelConversion(src, scaled);
178             }
179 #endif
180         }
181 
182         upload(scaled, dstBox);
183         freeBuffer();
184     }
185 
blitToMemory(const Image::Box & srcBox,const PixelBox & dst)186     void GLES2HardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst)
187     {
188         if (!mBuffer.contains(srcBox))
189         {
190             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
191                         "source box out of range",
192                         "GLES2HardwarePixelBuffer::blitToMemory");
193         }
194 
195         if (srcBox.left == 0 && srcBox.right == getWidth() &&
196             srcBox.top == 0 && srcBox.bottom == getHeight() &&
197             srcBox.front == 0 && srcBox.back == getDepth() &&
198             dst.getWidth() == getWidth() &&
199             dst.getHeight() == getHeight() &&
200             dst.getDepth() == getDepth() &&
201             GLES2PixelUtil::getGLOriginFormat(dst.format) != 0)
202         {
203             // The direct case: the user wants the entire texture in a format supported by GL
204             // so we don't need an intermediate buffer
205             download(dst);
206         }
207         else
208         {
209             // Use buffer for intermediate copy
210             allocateBuffer();
211             // Download entire buffer
212             download(mBuffer);
213             if(srcBox.getWidth() != dst.getWidth() ||
214                 srcBox.getHeight() != dst.getHeight() ||
215                 srcBox.getDepth() != dst.getDepth())
216             {
217                 // We need scaling
218                 Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR);
219             }
220             else
221             {
222                 // Just copy the bit that we need
223                 PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst);
224             }
225             freeBuffer();
226         }
227     }
228 
upload(const PixelBox & data,const Image::Box & dest)229     void GLES2HardwarePixelBuffer::upload(const PixelBox &data, const Image::Box &dest)
230     {
231         OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
232                     "Upload not possible for this pixelbuffer type",
233                     "GLES2HardwarePixelBuffer::upload");
234     }
235 
download(const PixelBox & data)236     void GLES2HardwarePixelBuffer::download(const PixelBox &data)
237     {
238         OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
239                     "Download not possible for this pixelbuffer type",
240                     "GLES2HardwarePixelBuffer::download");
241     }
242 
bindToFramebuffer(GLenum attachment,size_t zoffset)243     void GLES2HardwarePixelBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
244     {
245         OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
246                     "Framebuffer bind not possible for this pixelbuffer type",
247                     "GLES2HardwarePixelBuffer::bindToFramebuffer");
248     }
249 
250     // TextureBuffer
GLES2TextureBuffer(const String & baseName,GLenum target,GLuint id,GLint width,GLint height,GLint depth,GLint internalFormat,GLint format,GLint face,GLint level,Usage usage,bool crappyCard,bool writeGamma,uint fsaa)251     GLES2TextureBuffer::GLES2TextureBuffer(const String &baseName, GLenum target, GLuint id,
252                                            GLint width, GLint height, GLint depth, GLint internalFormat, GLint format,
253                                            GLint face, GLint level, Usage usage, bool crappyCard,
254                                            bool writeGamma, uint fsaa)
255     : GLES2HardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
256         mTarget(target), mTextureID(id), mBufferId(0), mFace(face), mLevel(level), mSoftwareMipmap(crappyCard)
257     {
258         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
259 
260         // Get face identifier
261         mFaceTarget = mTarget;
262         if(mTarget == GL_TEXTURE_CUBE_MAP)
263             mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
264 
265         // Calculate the width and height of the texture at this mip level
266         mWidth = mLevel == 0 ? width : width / static_cast<size_t>(pow(2.0f, level));
267         mHeight = mLevel == 0 ? height : height / static_cast<size_t>(pow(2.0f, level));
268         if(mWidth < 1)
269             mWidth = 1;
270         if(mHeight < 1)
271             mHeight = 1;
272 
273 #if OGRE_NO_GLES3_SUPPORT == 0
274         if(target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY)
275             mDepth = 1; // Depth always 1 for non-3D textures
276         else
277             mDepth = depth;
278 #else
279         // Only 2D is supported so depth is always 1
280         mDepth = 1;
281 #endif
282 
283         mGLInternalFormat = internalFormat;
284         mFormat = GLES2PixelUtil::getClosestOGREFormat(internalFormat, format);
285 
286         mRowPitch = mWidth;
287         mSlicePitch = mHeight*mWidth;
288         mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
289 
290 #if OGRE_DEBUG_MODE
291         // Log a message
292         std::stringstream str;
293         str << "GLES2HardwarePixelBuffer constructed for texture " << baseName
294             << " id " << mTextureID << " face " << mFace << " level " << mLevel << ":"
295             << " width=" << mWidth << " height="<< mHeight << " depth=" << mDepth
296             << " format=" << PixelUtil::getFormatName(mFormat);
297         LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
298 #endif
299 
300         // Set up a pixel box
301         mBuffer = PixelBox(mWidth, mHeight, mDepth, mFormat);
302 
303         if (mWidth==0 || mHeight==0 || mDepth==0)
304             // We are invalid, do not allocate a buffer
305             return;
306 
307         // Is this a render target?
308         if (mUsage & TU_RENDERTARGET)
309         {
310             // Create render target for each slice
311             mSliceTRT.reserve(mDepth);
312             for(size_t zoffset=0; zoffset<mDepth; ++zoffset)
313             {
314                 String name;
315                 name = "rtt/" + StringConverter::toString((size_t)this) + "/" + baseName;
316                 GLES2SurfaceDesc surface;
317                 surface.buffer = this;
318                 surface.zoffset = zoffset;
319                 RenderTexture *trt = GLES2RTTManager::getSingleton().createRenderTexture(name, surface, writeGamma, fsaa);
320                 mSliceTRT.push_back(trt);
321                 Root::getSingleton().getRenderSystem()->attachRenderTarget(*mSliceTRT[zoffset]);
322             }
323         }
324     }
325 
~GLES2TextureBuffer()326     GLES2TextureBuffer::~GLES2TextureBuffer()
327     {
328         if (mUsage & TU_RENDERTARGET)
329         {
330             // Delete all render targets that are not yet deleted via _clearSliceRTT because the rendertarget
331             // was deleted by the user.
332             for (SliceTRT::const_iterator it = mSliceTRT.begin(); it != mSliceTRT.end(); ++it)
333             {
334                 Root::getSingleton().getRenderSystem()->destroyRenderTarget((*it)->getName());
335             }
336         }
337     }
338 
339 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
updateTextureId(GLuint textureID)340     void GLES2TextureBuffer::updateTextureId(GLuint textureID)
341     {
342         mTextureID = textureID;
343     }
344 #endif
345 
346 #if OGRE_NO_GLES3_SUPPORT == 0
upload(const PixelBox & data,const Image::Box & dest)347     void GLES2TextureBuffer::upload(const PixelBox &data, const Image::Box &dest)
348     {
349         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
350 
351         OGRE_CHECK_GL_ERROR(glGenBuffers(1, &mBufferId));
352 
353         // Upload data to PBO
354         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mBufferId));
355 
356         // Calculate size for all mip levels of the texture
357         size_t dataSize = 0;
358         if(mTarget == GL_TEXTURE_2D_ARRAY)
359         {
360             dataSize = PixelUtil::getMemorySize(dest.getWidth(), dest.getHeight(), dest.getDepth(), data.format);
361         }
362         else
363         {
364             dataSize = PixelUtil::getMemorySize(data.getWidth(), data.getHeight(), mDepth, data.format);
365         }
366         OGRE_CHECK_GL_ERROR(glBufferData(GL_PIXEL_UNPACK_BUFFER, dataSize, NULL,
367                                          GLES2HardwareBufferManager::getGLUsage(mUsage)));
368 
369 #if OGRE_DEBUG_MODE
370         std::stringstream str;
371         str << "GLES2TextureBuffer::upload: " << mTextureID
372         << " pixel buffer: " << mBufferId
373         << " bytes: " << mSizeInBytes
374         << " dest depth: " << dest.getDepth()
375         << " dest front: " << dest.front
376         << " datasize: " << dataSize
377         << " face: " << mFace << " level: " << mLevel
378         << " width: " << mWidth << " height: "<< mHeight << " depth: " << mDepth
379         << " format: " << PixelUtil::getFormatName(mFormat)
380         << " data format: " << PixelUtil::getFormatName(data.format);
381         LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
382 #endif
383         void* pBuffer = 0;
384         OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, dataSize, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT));
385 
386         if(pBuffer == 0)
387         {
388             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
389                         "Texture Buffer: Out of memory",
390                         "GLES2TextureBuffer::upload");
391         }
392 
393         // Copy to destination buffer
394         memcpy(pBuffer, data.data, dataSize);
395         GLboolean mapped = false;
396         OGRE_CHECK_GL_ERROR(mapped = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));
397         if(!mapped)
398         {
399             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
400                         "Buffer data corrupted, please reload",
401                         "GLES2TextureBuffer::upload");
402         }
403 
404         if (PixelUtil::isCompressed(data.format))
405         {
406             if(data.format != mFormat || !data.isConsecutive())
407                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
408                             "Compressed images must be consecutive, in the source format",
409                             "GLES2TextureBuffer::upload");
410 
411             GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(mFormat);
412             // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
413             // for compressed formats
414             switch(mTarget) {
415                 case GL_TEXTURE_2D:
416                 case GL_TEXTURE_CUBE_MAP:
417                         OGRE_CHECK_GL_ERROR(glCompressedTexSubImage2D(mFaceTarget, mLevel,
418                                                   dest.left, dest.top,
419                                                   dest.getWidth(), dest.getHeight(),
420                                                   format, data.getConsecutiveSize(),
421                                                   NULL));
422                     break;
423                 case GL_TEXTURE_3D:
424                 case GL_TEXTURE_2D_ARRAY:
425                     OGRE_CHECK_GL_ERROR(glCompressedTexSubImage3D(mTarget, mLevel,
426                                               dest.left, dest.top, dest.front,
427                                               dest.getWidth(), dest.getHeight(), dest.getDepth(),
428                                               format, data.getConsecutiveSize(),
429                                               NULL));
430                     break;
431             }
432 
433         }
434         else
435         {
436             if(data.getWidth() != data.rowPitch)
437                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch));
438             if(data.getHeight()*data.getWidth() != data.slicePitch)
439                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth())));
440             if(data.left > 0 || data.top > 0 || data.front > 0)
441                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front));
442             if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
443                 // Standard alignment of 4 is not right
444                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
445             }
446 #if OGRE_DEBUG_MODE
447             LogManager::getSingleton().logMessage("GLES2TextureBuffer::upload - ID: " + StringConverter::toString(mTextureID) +
448                                                   " Target: " + StringConverter::toString(mTarget) +
449                                                   " Format: " + PixelUtil::getFormatName(data.format) +
450                                                   " Origin format: " + StringConverter::toString(GLES2PixelUtil::getGLOriginFormat(data.format), 0, std::ios::hex) +
451                                                   " Data type: " + StringConverter::toString(GLES2PixelUtil::getGLOriginDataType(data.format), 0, ' ', std::ios::hex));
452 #endif
453             switch(mTarget) {
454                 case GL_TEXTURE_2D:
455                 case GL_TEXTURE_CUBE_MAP:
456                     OGRE_CHECK_GL_ERROR(glTexSubImage2D(mFaceTarget, mLevel,
457                                     dest.left, dest.top,
458                                     dest.getWidth(), dest.getHeight(),
459                                     GLES2PixelUtil::getGLOriginFormat(data.format), GLES2PixelUtil::getGLOriginDataType(data.format),
460                                     NULL));
461                     break;
462                 case GL_TEXTURE_3D:
463                 case GL_TEXTURE_2D_ARRAY:
464                     OGRE_CHECK_GL_ERROR(glTexSubImage3D(
465                                     mTarget, mLevel,
466                                     dest.left, dest.top, dest.front,
467                                     dest.getWidth(), dest.getHeight(), dest.getDepth(),
468                                     GLES2PixelUtil::getGLOriginFormat(data.format), GLES2PixelUtil::getGLOriginDataType(data.format),
469                                     NULL));
470                     break;
471             }
472             if (mUsage & TU_AUTOMIPMAP && (mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_3D))
473             {
474                 OGRE_CHECK_GL_ERROR(glGenerateMipmap(mTarget));
475             }
476         }
477 
478         // Delete PBO
479         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
480         OGRE_CHECK_GL_ERROR(glDeleteBuffers(1, &mBufferId));
481         mBufferId = 0;
482 
483         // Restore defaults
484         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
485         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0));
486         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0));
487         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
488     }
489 
490     //-----------------------------------------------------------------------------
download(const PixelBox & data)491     void GLES2TextureBuffer::download(const PixelBox &data)
492     {
493         if(data.getWidth() != getWidth() ||
494            data.getHeight() != getHeight() ||
495            data.getDepth() != getDepth())
496             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL",
497                         "GLES2TextureBuffer::download");
498 
499         // Upload data to PBO
500         OGRE_CHECK_GL_ERROR(glGenBuffers(1, &mBufferId));
501         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_PIXEL_PACK_BUFFER, mBufferId));
502 
503         OGRE_CHECK_GL_ERROR(glBufferData(GL_PIXEL_PACK_BUFFER, mSizeInBytes, NULL,
504                                          GLES2HardwareBufferManager::getGLUsage(mUsage)));
505 
506 #if OGRE_DEBUG_MODE
507         std::stringstream str;
508         str << "GLES2TextureBuffer::download: " << mTextureID
509         << " pixel buffer: " << mBufferId
510         << " bytes: " << mSizeInBytes
511         << " face: " << mFace << " level: " << mLevel
512         << " width: " << mWidth << " height: "<< mHeight << " depth: " << mDepth
513         << " format: " << PixelUtil::getFormatName(mFormat);
514         LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
515 #endif
516         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
517         if(PixelUtil::isCompressed(data.format))
518         {
519             if(data.format != mFormat || !data.isConsecutive())
520                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
521                             "Compressed images must be consecutive, in the source format",
522                             "GLES2TextureBuffer::download");
523         }
524         else
525         {
526             if(data.getWidth() != data.rowPitch)
527                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)data.rowPitch));
528             if(data.left > 0 || data.top > 0 || data.front > 0)
529                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, (GLint)(data.left + data.rowPitch * data.top + data.slicePitch * data.front)));
530             if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
531                 // Standard alignment of 4 is not right
532                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1));
533             }
534 
535             // Restore defaults
536             OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, 0));
537             OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, 0));
538             OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 4));
539         }
540 
541         GLint offsetInBytes = 0;
542         size_t width = mWidth;
543         size_t height = mHeight;
544         size_t depth = mDepth;
545         for(GLint i = 0; i < mLevel; i++)
546         {
547             offsetInBytes += PixelUtil::getMemorySize(width, height, depth, data.format);
548 
549             if(width > 1)
550                 width = width / 2;
551             if(height > 1)
552                 height = height / 2;
553             if(depth > 1)
554                 depth = depth / 2;
555         }
556 
557         void* pBuffer;
558         OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRange(GL_PIXEL_PACK_BUFFER, offsetInBytes, mSizeInBytes, GL_MAP_READ_BIT));
559 
560         if(pBuffer == 0)
561         {
562             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
563                         "Texture Buffer: Out of memory",
564                         "GLES2TextureBuffer::download");
565         }
566 
567         // Copy to destination buffer
568         memcpy(data.data, pBuffer, mSizeInBytes);
569 
570         GLboolean mapped;
571         OGRE_CHECK_GL_ERROR(mapped = glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
572         if(!mapped)
573         {
574             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
575                         "Buffer data corrupted, please reload",
576                         "GLES2TextureBuffer::download");
577         }
578 
579         // Delete PBO
580         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
581         OGRE_CHECK_GL_ERROR(glDeleteBuffers(1, &mBufferId));
582         mBufferId = 0;
583     }
584 #else
upload(const PixelBox & data,const Image::Box & dest)585     void GLES2TextureBuffer::upload(const PixelBox &data, const Image::Box &dest)
586     {
587 #if OGRE_DEBUG_MODE
588         LogManager::getSingleton().logMessage("GLES2TextureBuffer::upload - ID: " + StringConverter::toString(mTextureID) +
589                                               " Target: " + StringConverter::toString(mTarget) +
590                                               " Format: " + PixelUtil::getFormatName(data.format) +
591                                               " Origin format: " + StringConverter::toString(GLES2PixelUtil::getGLOriginFormat(data.format), 0, std::ios::hex) +
592                                               " Data type: " + StringConverter::toString(GLES2PixelUtil::getGLOriginDataType(data.format), 0, ' ', std::ios::hex));
593 #endif
594         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
595 
596         if (PixelUtil::isCompressed(data.format))
597         {
598             if(data.format != mFormat || !data.isConsecutive())
599                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
600                             "Compressed images must be consecutive, in the source format",
601                             "GLES2TextureBuffer::upload");
602 
603             GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(mFormat);
604             // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
605             // for compressed formats
606             if (dest.left == 0 && dest.top == 0)
607             {
608                 OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(mFaceTarget, mLevel,
609                                        format,
610                                        dest.getWidth(),
611                                        dest.getHeight(),
612                                        0,
613                                        data.getConsecutiveSize(),
614                                        data.data));
615             }
616             else
617             {
618                 OGRE_CHECK_GL_ERROR(glCompressedTexSubImage2D(mFaceTarget, mLevel,
619                                           dest.left, dest.top,
620                                           dest.getWidth(), dest.getHeight(),
621                                           format, data.getConsecutiveSize(),
622                                           data.data));
623             }
624         }
625         else if (mSoftwareMipmap)
626         {
627             if (data.getWidth() != data.rowPitch)
628             {
629                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
630                             "Unsupported texture format",
631                             "GLES2TextureBuffer::upload");
632             }
633 
634             if (data.getHeight() * data.getWidth() != data.slicePitch)
635             {
636                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
637                             "Unsupported texture format",
638                             "GLES2TextureBuffer::upload");
639             }
640 
641             OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
642             buildMipmaps(data);
643         }
644         else
645         {
646             if (data.getWidth() != data.rowPitch)
647             {
648                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
649                             "Unsupported texture format",
650                             "GLES2TextureBuffer::upload");
651             }
652 
653             if (data.getHeight() * data.getWidth() != data.slicePitch)
654             {
655                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
656                             "Unsupported texture format",
657                             "GLES2TextureBuffer::upload");
658             }
659 
660             if ((data.getWidth() * PixelUtil::getNumElemBytes(data.format)) & 3) {
661                 // Standard alignment of 4 is not right
662                 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
663             }
664 
665             switch(mTarget)
666             {
667                 case GL_TEXTURE_2D:
668         		case GL_TEXTURE_CUBE_MAP:
669                     OGRE_CHECK_GL_ERROR(glTexSubImage2D(mFaceTarget,
670                                     mLevel,
671                                     dest.left, dest.top,
672                                     dest.getWidth(), dest.getHeight(),
673                                     GLES2PixelUtil::getGLOriginFormat(data.format),
674                                     GLES2PixelUtil::getGLOriginDataType(data.format),
675                                     data.data));
676                 break;
677             }
678         }
679 
680         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
681     }
682 
683     //-----------------------------------------------------------------------------
download(const PixelBox & data)684     void GLES2TextureBuffer::download(const PixelBox &data)
685     {
686         if(data.getWidth() != getWidth() ||
687            data.getHeight() != getHeight() ||
688            data.getDepth() != getDepth())
689             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL ES",
690                         "GLES2TextureBuffer::download");
691 
692         if(PixelUtil::isCompressed(data.format))
693         {
694             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
695                         "Compressed images cannot be downloaded by GL ES",
696                         "GLES2TextureBuffer::download");
697         }
698 
699         if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
700             // Standard alignment of 4 is not right
701             OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1));
702         }
703 
704         GLint currentFBO = 0;
705         GLuint tempFBO = 0;
706         OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFBO));
707         OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &tempFBO));
708         OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, tempFBO));
709 
710         // Construct a temp PixelBox that is RGBA because GL_RGBA/GL_UNSIGNED_BYTE is the only combination that is
711         // guaranteed to work on all platforms.
712         int sizeInBytes = PixelUtil::getMemorySize(data.getWidth(), data.getHeight(), data.getDepth(), PF_A8B8G8R8);
713         PixelBox tempBox = PixelBox(data.getWidth(), data.getHeight(), data.getDepth(), PF_A8B8G8R8);
714         tempBox.data = new uint8[sizeInBytes];
715 
716         switch (mTarget)
717         {
718             case GL_TEXTURE_2D:
719             case GL_TEXTURE_CUBE_MAP:
720                 OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureID, 0));
721                 OGRE_CHECK_GL_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
722                 OGRE_CHECK_GL_ERROR(glReadPixels(0, 0, data.getWidth(), data.getHeight(),
723                                                  GL_RGBA,
724                                                  GL_UNSIGNED_BYTE,
725                                                  tempBox.data));
726                 break;
727         }
728 
729         PixelUtil::bulkPixelConversion(tempBox, data);
730 
731         delete[] (uint8*) tempBox.data;
732         tempBox.data = 0;
733 
734         // Restore defaults
735         OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 4));
736         OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, currentFBO));
737         OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &tempFBO));
738     }
739 #endif
740     //-----------------------------------------------------------------------------
bindToFramebuffer(GLenum attachment,size_t zoffset)741     void GLES2TextureBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
742     {
743         assert(zoffset < mDepth);
744         OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
745                                                    mFaceTarget, mTextureID, mLevel));
746     }
747 
copyFromFramebuffer(size_t zoffset)748     void GLES2TextureBuffer::copyFromFramebuffer(size_t zoffset)
749     {
750         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
751         OGRE_CHECK_GL_ERROR(glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight));
752     }
753 
754     //-----------------------------------------------------------------------------
blit(const HardwarePixelBufferSharedPtr & src,const Image::Box & srcBox,const Image::Box & dstBox)755     void GLES2TextureBuffer::blit(const HardwarePixelBufferSharedPtr &src, const Image::Box &srcBox, const Image::Box &dstBox)
756     {
757         GLES2TextureBuffer *srct = static_cast<GLES2TextureBuffer *>(src.getPointer());
758         // TODO: Check for FBO support first
759         // Destination texture must be 2D or Cube
760         // Source texture must be 2D
761         if(((src->getUsage() & TU_RENDERTARGET) == 0 && (srct->mTarget == GL_TEXTURE_2D))
762 #if OGRE_NO_GLES3_SUPPORT == 0
763         || ((srct->mTarget == GL_TEXTURE_3D) && (mTarget != GL_TEXTURE_2D_ARRAY))
764 #endif
765         )
766         {
767             blitFromTexture(srct, srcBox, dstBox);
768         }
769         else
770         {
771             GLES2HardwarePixelBuffer::blit(src, srcBox, dstBox);
772         }
773     }
774 
775     //-----------------------------------------------------------------------------
776     // Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO
777     // Destination texture must be 1D, 2D, 3D, or Cube
778     // Source texture must be 1D, 2D or 3D
779     // Supports compressed formats as both source and destination format, it will use the hardware DXT compressor
780     // if available.
781     // @author W.J. van der Laan
blitFromTexture(GLES2TextureBuffer * src,const Image::Box & srcBox,const Image::Box & dstBox)782     void GLES2TextureBuffer::blitFromTexture(GLES2TextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox)
783     {
784 		return; // todo - add a shader attach...
785 //        std::cerr << "GLES2TextureBuffer::blitFromTexture " <<
786 //        src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " <<
787 //        mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl;
788 
789         // Store reference to FBO manager
790         GLES2FBOManager *fboMan = static_cast<GLES2FBOManager *>(GLES2RTTManager::getSingletonPtr());
791 
792         RenderSystem* rsys = Root::getSingleton().getRenderSystem();
793         rsys->_disableTextureUnitsFrom(0);
794 		glActiveTexture(GL_TEXTURE0);
795 
796         // Disable alpha, depth and scissor testing, disable blending,
797         // and disable culling
798         glDisable(GL_DEPTH_TEST);
799         glDisable(GL_SCISSOR_TEST);
800         glDisable(GL_BLEND);
801         glDisable(GL_CULL_FACE);
802 
803         // Set up source texture
804         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(src->mTarget, src->mTextureID);
805 
806         // Set filtering modes depending on the dimensions and source
807         if(srcBox.getWidth() == dstBox.getWidth() &&
808            srcBox.getHeight() == dstBox.getHeight() &&
809            srcBox.getDepth() == dstBox.getDepth())
810         {
811             // Dimensions match -- use nearest filtering (fastest and pixel correct)
812             if(src->mUsage & TU_AUTOMIPMAP)
813             {
814                 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST));
815             }
816             else
817             {
818                 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
819             }
820             OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
821         }
822         else
823         {
824             // Dimensions don't match -- use bi or trilinear filtering depending on the
825             // source texture.
826             if(src->mUsage & TU_AUTOMIPMAP)
827             {
828                 // Automatic mipmaps, we can safely use trilinear filter which
829                 // brings greatly improved quality for minimisation.
830                 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
831             }
832             else
833             {
834                 // Manual mipmaps, stay safe with bilinear filtering so that no
835                 // intermipmap leakage occurs.
836                 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
837             }
838             OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
839         }
840         // Clamp to edge (fastest)
841         OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
842         OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
843 #if OGRE_NO_GLES3_SUPPORT == 0
844         OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
845 
846         // Set origin base level mipmap to make sure we source from the right mip
847         // level.
848         OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, src->mLevel));
849 #endif
850         // Store old binding so it can be restored later
851         GLint oldfb;
852         OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb));
853 
854         // Set up temporary FBO
855         OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fboMan->getTemporaryFBO()));
856 
857         GLuint tempTex = 0;
858         if(!fboMan->checkFormat(mFormat))
859         {
860             // If target format not directly supported, create intermediate texture
861             GLenum tempFormat = GLES2PixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat));
862             OGRE_CHECK_GL_ERROR(glGenTextures(1, &tempTex));
863             getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(GL_TEXTURE_2D, tempTex);
864 
865             if(getGLES2SupportRef()->checkExtension("GL_APPLE_texture_max_level") || gleswIsSupported(3, 0))
866                 getGLES2SupportRef()->getStateCacheManager()->setTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL_APPLE, 0);
867 
868             // Allocate temporary texture of the size of the destination area
869             OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, tempFormat,
870                          GLES2PixelUtil::optionalPO2(dstBox.getWidth()), GLES2PixelUtil::optionalPO2(dstBox.getHeight()),
871                          0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
872             OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
873                                       GL_TEXTURE_2D, tempTex, 0));
874             // Set viewport to size of destination slice
875             OGRE_CHECK_GL_ERROR(glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight()));
876         }
877         else
878         {
879             // We are going to bind directly, so set viewport to size and position of destination slice
880             OGRE_CHECK_GL_ERROR(glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight()));
881         }
882 
883         // Process each destination slice
884         for(size_t slice = dstBox.front; slice < dstBox.back; ++slice)
885         {
886             if(!tempTex)
887             {
888                 // Bind directly
889                 bindToFramebuffer(GL_COLOR_ATTACHMENT0, slice);
890             }
891 
892             // Calculate source texture coordinates
893             float u1 = (float)srcBox.left / (float)src->mWidth;
894             float v1 = (float)srcBox.top / (float)src->mHeight;
895             float u2 = (float)srcBox.right / (float)src->mWidth;
896             float v2 = (float)srcBox.bottom / (float)src->mHeight;
897             // Calculate source slice for this destination slice
898             float w = (float)(slice - dstBox.front) / (float)dstBox.getDepth();
899             // Get slice # in source
900             w = w * (float)srcBox.getDepth() + srcBox.front;
901             // Normalise to texture coordinate in 0.0 .. 1.0
902             w = (w+0.5f) / (float)src->mDepth;
903 
904             // Finally we're ready to rumble
905             getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(src->mTarget, src->mTextureID);
906             OGRE_CHECK_GL_ERROR(glEnable(src->mTarget));
907 
908             GLfloat squareVertices[] = {
909                -1.0f, -1.0f,
910                 1.0f, -1.0f,
911                -1.0f,  1.0f,
912                 1.0f,  1.0f,
913             };
914             GLfloat texCoords[] = {
915                 u1, v1, w,
916                 u2, v1, w,
917                 u2, v2, w,
918                 u1, v2, w
919             };
920 
921             GLuint posAttrIndex = 0;
922             GLuint texAttrIndex = 0;
923             if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS))
924             {
925                 GLSLESProgramPipeline* programPipeline = GLSLESProgramPipelineManager::getSingleton().getActiveProgramPipeline();
926                 posAttrIndex = (GLuint)programPipeline->getAttributeIndex(VES_POSITION, 0);
927                 texAttrIndex = (GLuint)programPipeline->getAttributeIndex(VES_TEXTURE_COORDINATES, 0);
928             }
929             else
930             {
931                 GLSLESLinkProgram* linkProgram = GLSLESLinkProgramManager::getSingleton().getActiveLinkProgram();
932                 posAttrIndex = (GLuint)linkProgram->getAttributeIndex(VES_POSITION, 0);
933                 texAttrIndex = (GLuint)linkProgram->getAttributeIndex(VES_TEXTURE_COORDINATES, 0);
934             }
935 
936             // Draw the textured quad
937             OGRE_CHECK_GL_ERROR(glVertexAttribPointer(posAttrIndex,
938                                   2,
939                                   GL_FLOAT,
940                                   0,
941                                   0,
942                                   squareVertices));
943             OGRE_CHECK_GL_ERROR(glEnableVertexAttribArray(posAttrIndex));
944             OGRE_CHECK_GL_ERROR(glVertexAttribPointer(texAttrIndex,
945                                   3,
946                                   GL_FLOAT,
947                                   0,
948                                   0,
949                                   texCoords));
950             OGRE_CHECK_GL_ERROR(glEnableVertexAttribArray(texAttrIndex));
951 
952             OGRE_CHECK_GL_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
953 
954             OGRE_CHECK_GL_ERROR(glDisable(src->mTarget));
955 
956             if(tempTex)
957             {
958                 // Copy temporary texture
959                 getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
960                 switch(mTarget)
961                 {
962                     case GL_TEXTURE_2D:
963                     case GL_TEXTURE_CUBE_MAP:
964                         OGRE_CHECK_GL_ERROR(glCopyTexSubImage2D(mFaceTarget, mLevel,
965                                             dstBox.left, dstBox.top,
966                                             0, 0, dstBox.getWidth(), dstBox.getHeight()));
967                         break;
968                 }
969             }
970         }
971         // Finish up
972         if(!tempTex)
973         {
974             // Generate mipmaps
975             if(mUsage & TU_AUTOMIPMAP)
976             {
977                 getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(mTarget, mTextureID);
978                 OGRE_CHECK_GL_ERROR(glGenerateMipmap(mTarget));
979             }
980         }
981 
982         // Reset source texture to sane state
983         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(src->mTarget, src->mTextureID);
984 
985 #if OGRE_NO_GLES3_SUPPORT == 0
986         OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, 0));
987 
988         // Detach texture from temporary framebuffer
989         if(mFormat == PF_DEPTH)
990         {
991             OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
992                                                           GL_RENDERBUFFER, 0));
993         }
994         else
995 #endif
996         {
997             OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
998                                                           GL_RENDERBUFFER, 0));
999         }
1000         // Restore old framebuffer
1001         OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, oldfb));
1002         OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &tempTex));
1003     }
1004     //-----------------------------------------------------------------------------
1005     // blitFromMemory doing hardware trilinear scaling
blitFromMemory(const PixelBox & src_orig,const Image::Box & dstBox)1006     void GLES2TextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox)
1007     {
1008         // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case
1009         // - FBO is not supported
1010         // - Either source or target is luminance due doesn't looks like supported by hardware
1011         // - the source dimensions match the destination ones, in which case no scaling is needed
1012         // TODO: Check that extension is NOT available
1013         if(PixelUtil::isLuminance(src_orig.format) ||
1014            PixelUtil::isLuminance(mFormat) ||
1015            (src_orig.getWidth() == dstBox.getWidth() &&
1016             src_orig.getHeight() == dstBox.getHeight() &&
1017             src_orig.getDepth() == dstBox.getDepth()))
1018         {
1019             GLES2HardwarePixelBuffer::blitFromMemory(src_orig, dstBox);
1020             return;
1021         }
1022         if(!mBuffer.contains(dstBox))
1023             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range",
1024                         "GLES2TextureBuffer::blitFromMemory");
1025         // For scoped deletion of conversion buffer
1026         MemoryDataStreamPtr buf;
1027         PixelBox src;
1028 
1029         // First, convert the srcbox to a OpenGL compatible pixel format
1030         if(GLES2PixelUtil::getGLOriginFormat(src_orig.format) == 0)
1031         {
1032             // Convert to buffer internal format
1033             buf.bind(OGRE_NEW MemoryDataStream(PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(),
1034                                                                         src_orig.getDepth(), mFormat)));
1035             src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr());
1036             PixelUtil::bulkPixelConversion(src_orig, src);
1037         }
1038         else
1039         {
1040             // No conversion needed
1041             src = src_orig;
1042         }
1043 
1044         // Create temporary texture to store source data
1045         GLuint id = 0;
1046         GLenum target =
1047 #if OGRE_NO_GLES3_SUPPORT == 0
1048         (src.getDepth() != 1) ? GL_TEXTURE_3D :
1049 #endif
1050             GL_TEXTURE_2D;
1051 
1052         GLsizei width = (GLsizei)GLES2PixelUtil::optionalPO2(src.getWidth());
1053         GLsizei height = (GLsizei)GLES2PixelUtil::optionalPO2(src.getHeight());
1054         GLsizei depth = (GLsizei)GLES2PixelUtil::optionalPO2(src.getDepth());
1055         GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(src.format);
1056 
1057         // Generate texture name
1058         OGRE_CHECK_GL_ERROR(glGenTextures(1, &id));
1059 
1060         // Set texture type
1061         getGLES2SupportRef()->getStateCacheManager()->bindGLTexture(target, id);
1062 
1063         if(getGLES2SupportRef()->checkExtension("GL_APPLE_texture_max_level") || gleswIsSupported(3, 0))
1064             getGLES2SupportRef()->getStateCacheManager()->setTexParameteri(target, GL_TEXTURE_MAX_LEVEL_APPLE, 1000);
1065 
1066         // Allocate texture memory
1067 #if OGRE_NO_GLES3_SUPPORT == 0
1068         if(src.getDepth() != 1)
1069         {
1070             OGRE_CHECK_GL_ERROR(glTexStorage3D(GL_TEXTURE_3D, 1, format, GLsizei(width), GLsizei(height), GLsizei(depth)));
1071         }
1072         else
1073         {
1074             OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_2D, 1, format, GLsizei(width), GLsizei(height)));
1075         }
1076 #else
1077         GLenum datatype = (GLsizei)GLES2PixelUtil::getGLOriginDataType(src.format);
1078         OGRE_CHECK_GL_ERROR(glTexImage2D(target, 0, format, width, height, 0, format, datatype, 0));
1079 #endif
1080 
1081         // GL texture buffer
1082         GLES2TextureBuffer tex(StringUtil::BLANK, target, id, width, height, depth, format, src.format,
1083                               0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false, false, 0);
1084 
1085         // Upload data to 0,0,0 in temporary texture
1086         Image::Box tempTarget(0, 0, 0, src.getWidth(), src.getHeight(), src.getDepth());
1087         tex.upload(src, tempTarget);
1088 
1089         // Blit
1090         blitFromTexture(&tex, tempTarget, dstBox);
1091 
1092         // Delete temp texture
1093         OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &id));
1094     }
1095 
getRenderTarget(size_t zoffset)1096     RenderTexture *GLES2TextureBuffer::getRenderTarget(size_t zoffset)
1097     {
1098         assert(mUsage & TU_RENDERTARGET);
1099         assert(zoffset < mDepth);
1100         return mSliceTRT[zoffset];
1101     }
1102 
buildMipmaps(const PixelBox & data)1103     void GLES2TextureBuffer::buildMipmaps(const PixelBox &data)
1104     {
1105         GLsizei width;
1106         GLsizei height;
1107         GLsizei depth;
1108         int logW;
1109         int logH;
1110         int level;
1111         PixelBox scaled = data;
1112         scaled.data = data.data;
1113         scaled.left = data.left;
1114         scaled.right = data.right;
1115         scaled.top = data.top;
1116         scaled.bottom = data.bottom;
1117         scaled.front = data.front;
1118         scaled.back = data.back;
1119 
1120         width = (GLsizei)data.getWidth();
1121         height = (GLsizei)data.getHeight();
1122         depth = (GLsizei)data.getDepth();
1123 
1124         logW = computeLog(width);
1125         logH = computeLog(height);
1126         level = (logW > logH ? logW : logH);
1127 
1128         for (int mip = 0; mip <= level; mip++)
1129         {
1130             GLenum glFormat = GLES2PixelUtil::getGLOriginFormat(scaled.format);
1131             GLenum dataType = GLES2PixelUtil::getGLOriginDataType(scaled.format);
1132             GLenum internalFormat = glFormat;
1133 #if OGRE_NO_GLES3_SUPPORT == 0
1134             // In GL ES 3, the internalformat and format parameters do not need to be identical
1135             internalFormat = GLES2PixelUtil::getClosestGLInternalFormat(scaled.format);
1136 #endif
1137             switch(mTarget)
1138             {
1139                 case GL_TEXTURE_2D:
1140                 case GL_TEXTURE_CUBE_MAP:
1141                     OGRE_CHECK_GL_ERROR(glTexImage2D(mFaceTarget,
1142                                                      mip,
1143                                                      internalFormat,
1144                                                      width, height,
1145                                                      0,
1146                                                      glFormat,
1147                                                      dataType,
1148                                                      scaled.data));
1149                     break;
1150 #if OGRE_NO_GLES3_SUPPORT == 0
1151                 case GL_TEXTURE_3D:
1152                 case GL_TEXTURE_2D_ARRAY:
1153                     OGRE_CHECK_GL_ERROR(glTexImage3D(mFaceTarget,
1154                                                      mip,
1155                                                      internalFormat,
1156                                                      width, height, depth,
1157                                                      0,
1158                                                      glFormat,
1159                                                      dataType,
1160                                                      scaled.data));
1161                     break;
1162 #endif
1163             }
1164 
1165             if (mip != 0)
1166             {
1167                 OGRE_DELETE[] (uint8*) scaled.data;
1168                 scaled.data = 0;
1169             }
1170 
1171             if (width > 1)
1172             {
1173                 width = width / 2;
1174             }
1175 
1176             if (height > 1)
1177             {
1178                 height = height / 2;
1179             }
1180 
1181             size_t sizeInBytes = PixelUtil::getMemorySize(width, height, 1,
1182                                                        data.format);
1183             scaled = PixelBox(width, height, 1, data.format);
1184             scaled.data = new uint8[sizeInBytes];
1185             Image::scale(data, scaled, Image::FILTER_LINEAR);
1186         }
1187 
1188         // Delete the scaled data for the last level
1189         if (level > 0)
1190         {
1191             delete[] (uint8*) scaled.data;
1192             scaled.data = 0;
1193         }
1194     }
1195 
1196     //********* GLES2RenderBuffer
1197     //-----------------------------------------------------------------------------
GLES2RenderBuffer(GLenum format,size_t width,size_t height,GLsizei numSamples)1198     GLES2RenderBuffer::GLES2RenderBuffer(GLenum format, size_t width, size_t height, GLsizei numSamples):
1199     GLES2HardwarePixelBuffer(width, height, 1, GLES2PixelUtil::getClosestOGREFormat(format, GL_RGBA), HBU_WRITE_ONLY)
1200     {
1201         mGLInternalFormat = format;
1202         mNumSamples = numSamples;
1203 
1204         // Generate renderbuffer
1205         OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mRenderbufferID));
1206 
1207         // Bind it to FBO
1208         OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID));
1209 
1210         // Allocate storage for depth buffer
1211         if (mNumSamples > 0)
1212         {
1213             if(getGLES2SupportRef()->checkExtension("GL_APPLE_framebuffer_multisample") || gleswIsSupported(3, 0))
1214             {
1215                 OGRE_CHECK_GL_ERROR(glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER,
1216                                                                           mNumSamples, mGLInternalFormat, mWidth, mHeight));
1217             }
1218         }
1219         else
1220         {
1221             OGRE_CHECK_GL_ERROR(glRenderbufferStorage(GL_RENDERBUFFER, mGLInternalFormat,
1222                                                       mWidth, mHeight));
1223         }
1224     }
1225     //-----------------------------------------------------------------------------
~GLES2RenderBuffer()1226     GLES2RenderBuffer::~GLES2RenderBuffer()
1227     {
1228         OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mRenderbufferID));
1229     }
1230     //-----------------------------------------------------------------------------
bindToFramebuffer(GLenum attachment,size_t zoffset)1231     void GLES2RenderBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
1232     {
1233         assert(zoffset < mDepth);
1234         OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
1235                                                       GL_RENDERBUFFER, mRenderbufferID));
1236     }
1237 }
1238