OSDN Git Service

glBlitFramebuffer support for depth/stencil formats
[android-x86/external-swiftshader.git] / src / OpenGL / libGLESv2 / Texture.cpp
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Texture.cpp: Implements the Texture class and its derived classes
16 // Texture2D, TextureCubeMap, Texture3D and Texture2DArray. Implements GL texture objects
17 // and related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
18
19 #include "Texture.h"
20
21 #include "main.h"
22 #include "mathutil.h"
23 #include "Framebuffer.h"
24 #include "Device.hpp"
25 #include "libEGL/Display.h"
26 #include "libEGL/Surface.h"
27 #include "common/debug.h"
28
29 #include <algorithm>
30
31 namespace es2
32 {
33
34 Texture::Texture(GLuint name) : egl::Texture(name)
35 {
36         mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
37         mMagFilter = GL_LINEAR;
38         mWrapS = GL_REPEAT;
39         mWrapT = GL_REPEAT;
40         mWrapR = GL_REPEAT;
41         mMaxAnisotropy = 1.0f;
42         mBaseLevel = 0;
43         mCompareFunc = GL_LEQUAL;
44         mCompareMode = GL_NONE;
45         mImmutableFormat = GL_FALSE;
46         mImmutableLevels = 0;
47         mMaxLevel = 1000;
48         mMaxLOD = 1000;
49         mMinLOD = -1000;
50         mSwizzleR = GL_RED;
51         mSwizzleG = GL_GREEN;
52         mSwizzleB = GL_BLUE;
53         mSwizzleA = GL_ALPHA;
54
55         resource = new sw::Resource(0);
56 }
57
58 Texture::~Texture()
59 {
60         resource->destruct();
61 }
62
63 sw::Resource *Texture::getResource() const
64 {
65         return resource;
66 }
67
68 // Returns true on successful filter state update (valid enum parameter)
69 bool Texture::setMinFilter(GLenum filter)
70 {
71         switch(filter)
72         {
73         case GL_NEAREST_MIPMAP_NEAREST:
74         case GL_LINEAR_MIPMAP_NEAREST:
75         case GL_NEAREST_MIPMAP_LINEAR:
76         case GL_LINEAR_MIPMAP_LINEAR:
77                 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
78                 {
79                         return false;
80                 }
81                 // Fall through
82         case GL_NEAREST:
83         case GL_LINEAR:
84                 mMinFilter = filter;
85                 return true;
86         default:
87                 return false;
88         }
89 }
90
91 // Returns true on successful filter state update (valid enum parameter)
92 bool Texture::setMagFilter(GLenum filter)
93 {
94         switch(filter)
95         {
96         case GL_NEAREST:
97         case GL_LINEAR:
98                 mMagFilter = filter;
99                 return true;
100         default:
101                 return false;
102         }
103 }
104
105 // Returns true on successful wrap state update (valid enum parameter)
106 bool Texture::setWrapS(GLenum wrap)
107 {
108         switch(wrap)
109         {
110         case GL_REPEAT:
111         case GL_MIRRORED_REPEAT:
112                 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
113                 {
114                         return false;
115                 }
116                 // Fall through
117         case GL_CLAMP_TO_EDGE:
118                 mWrapS = wrap;
119                 return true;
120         default:
121                 return false;
122         }
123 }
124
125 // Returns true on successful wrap state update (valid enum parameter)
126 bool Texture::setWrapT(GLenum wrap)
127 {
128         switch(wrap)
129         {
130         case GL_REPEAT:
131         case GL_MIRRORED_REPEAT:
132                 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
133                 {
134                         return false;
135                 }
136                 // Fall through
137         case GL_CLAMP_TO_EDGE:
138                 mWrapT = wrap;
139                 return true;
140         default:
141                 return false;
142         }
143 }
144
145 // Returns true on successful wrap state update (valid enum parameter)
146 bool Texture::setWrapR(GLenum wrap)
147 {
148         switch(wrap)
149         {
150         case GL_REPEAT:
151         case GL_MIRRORED_REPEAT:
152                 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
153                 {
154                         return false;
155                 }
156                 // Fall through
157         case GL_CLAMP_TO_EDGE:
158                 mWrapR = wrap;
159                 return true;
160         default:
161                 return false;
162         }
163 }
164
165 // Returns true on successful max anisotropy update (valid anisotropy value)
166 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
167 {
168         textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
169
170         if(textureMaxAnisotropy < 1.0f)
171         {
172                 return false;
173         }
174
175         if(mMaxAnisotropy != textureMaxAnisotropy)
176         {
177                 mMaxAnisotropy = textureMaxAnisotropy;
178         }
179
180         return true;
181 }
182
183 bool Texture::setBaseLevel(GLint baseLevel)
184 {
185         mBaseLevel = baseLevel;
186         return true;
187 }
188
189 bool Texture::setCompareFunc(GLenum compareFunc)
190 {
191         switch(compareFunc)
192         {
193         case GL_LEQUAL:
194         case GL_GEQUAL:
195         case GL_LESS:
196         case GL_GREATER:
197         case GL_EQUAL:
198         case GL_NOTEQUAL:
199         case GL_ALWAYS:
200         case GL_NEVER:
201                 mCompareFunc = compareFunc;
202                 return true;
203         default:
204                 return false;
205         }
206 }
207
208 bool Texture::setCompareMode(GLenum compareMode)
209 {
210         switch(compareMode)
211         {
212         case GL_COMPARE_REF_TO_TEXTURE:
213         case GL_NONE:
214                 mCompareMode = compareMode;
215                 return true;
216         default:
217                 return false;
218         }
219 }
220
221 void Texture::makeImmutable(GLsizei levels)
222 {
223         mImmutableFormat = GL_TRUE;
224         mImmutableLevels = levels;
225 }
226
227 bool Texture::setMaxLevel(GLint maxLevel)
228 {
229         mMaxLevel = maxLevel;
230         return true;
231 }
232
233 bool Texture::setMaxLOD(GLfloat maxLOD)
234 {
235         mMaxLOD = maxLOD;
236         return true;
237 }
238
239 bool Texture::setMinLOD(GLfloat minLOD)
240 {
241         mMinLOD = minLOD;
242         return true;
243 }
244
245 bool Texture::setSwizzleR(GLenum swizzleR)
246 {
247         switch(swizzleR)
248         {
249         case GL_RED:
250         case GL_GREEN:
251         case GL_BLUE:
252         case GL_ALPHA:
253         case GL_ZERO:
254         case GL_ONE:
255                 mSwizzleR = swizzleR;
256                 return true;
257         default:
258                 return false;
259         }
260 }
261
262 bool Texture::setSwizzleG(GLenum swizzleG)
263 {
264         switch(swizzleG)
265         {
266         case GL_RED:
267         case GL_GREEN:
268         case GL_BLUE:
269         case GL_ALPHA:
270         case GL_ZERO:
271         case GL_ONE:
272                 mSwizzleG = swizzleG;
273                 return true;
274         default:
275                 return false;
276         }
277 }
278
279 bool Texture::setSwizzleB(GLenum swizzleB)
280 {
281         switch(swizzleB)
282         {
283         case GL_RED:
284         case GL_GREEN:
285         case GL_BLUE:
286         case GL_ALPHA:
287         case GL_ZERO:
288         case GL_ONE:
289                 mSwizzleB = swizzleB;
290                 return true;
291         default:
292                 return false;
293         }
294 }
295
296 bool Texture::setSwizzleA(GLenum swizzleA)
297 {
298         switch(swizzleA)
299         {
300         case GL_RED:
301         case GL_GREEN:
302         case GL_BLUE:
303         case GL_ALPHA:
304         case GL_ZERO:
305         case GL_ONE:
306                 mSwizzleA = swizzleA;
307                 return true;
308         default:
309                 return false;
310         }
311 }
312
313 GLenum Texture::getMinFilter() const
314 {
315         return mMinFilter;
316 }
317
318 GLenum Texture::getMagFilter() const
319 {
320         return mMagFilter;
321 }
322
323 GLenum Texture::getWrapS() const
324 {
325         return mWrapS;
326 }
327
328 GLenum Texture::getWrapT() const
329 {
330         return mWrapT;
331 }
332
333 GLenum Texture::getWrapR() const
334 {
335         return mWrapR;
336 }
337
338 GLfloat Texture::getMaxAnisotropy() const
339 {
340         return mMaxAnisotropy;
341 }
342
343 GLint Texture::getBaseLevel() const
344 {
345         return mBaseLevel;
346 }
347 GLenum Texture::getCompareFunc() const
348 {
349         return mCompareFunc;
350 }
351 GLenum Texture::getCompareMode() const
352 {
353         return mCompareMode;
354 }
355 GLboolean Texture::getImmutableFormat() const
356 {
357         return mImmutableFormat;
358 }
359 GLsizei Texture::getImmutableLevels() const
360 {
361         return mImmutableLevels;
362 }
363 GLint Texture::getMaxLevel() const
364 {
365         return mMaxLevel;
366 }
367 GLfloat Texture::getMaxLOD() const
368 {
369         return mMaxLOD;
370 }
371 GLfloat Texture::getMinLOD() const
372 {
373         return mMinLOD;
374 }
375 GLenum Texture::getSwizzleR() const
376 {
377         return mSwizzleR;
378 }
379 GLenum Texture::getSwizzleG() const
380 {
381         return mSwizzleG;
382 }
383 GLenum Texture::getSwizzleB() const
384 {
385         return mSwizzleB;
386 }
387 GLenum Texture::getSwizzleA() const
388 {
389         return mSwizzleA;
390 }
391
392 GLsizei Texture::getDepth(GLenum target, GLint level) const
393 {
394         return 1;
395 }
396
397 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
398 {
399         egl::Image *image = getRenderTarget(target, level);   // Increments reference count
400
401         if(image)
402         {
403                 image->markShared();
404         }
405
406         return image;
407 }
408
409 void Texture::setImage(GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
410 {
411         if(pixels && image)
412         {
413                 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
414                 image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackInfo, pixels);
415         }
416 }
417
418 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
419 {
420         if(pixels && image)
421         {
422                 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
423                 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
424         }
425 }
426
427 void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
428 {
429         if(!image)
430         {
431                 return error(GL_INVALID_OPERATION);
432         }
433
434         if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
435         {
436                 return error(GL_INVALID_VALUE);
437         }
438
439         if(IsCompressed(image->getFormat(), egl::getClientVersion()))
440         {
441                 return error(GL_INVALID_OPERATION);
442         }
443
444         if(format != image->getFormat())
445         {
446                 return error(GL_INVALID_OPERATION);
447         }
448
449         if(pixels)
450         {
451                 image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels);
452         }
453 }
454
455 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
456 {
457         if(!image)
458         {
459                 return error(GL_INVALID_OPERATION);
460         }
461
462         if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
463         {
464                 return error(GL_INVALID_VALUE);
465         }
466
467         if(format != image->getFormat())
468         {
469                 return error(GL_INVALID_OPERATION);
470         }
471
472         if(pixels)
473         {
474                 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
475         }
476 }
477
478 bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
479 {
480         Device *device = getDevice();
481
482         sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
483         bool success = device->stretchRect(source, &sourceRect, dest, &destRect, Device::ALL_BUFFERS);
484
485         if(!success)
486         {
487                 return error(GL_OUT_OF_MEMORY, false);
488         }
489
490         return true;
491 }
492
493 bool Texture::isMipmapFiltered() const
494 {
495         switch(mMinFilter)
496         {
497         case GL_NEAREST:
498         case GL_LINEAR:
499                 return false;
500         case GL_NEAREST_MIPMAP_NEAREST:
501         case GL_LINEAR_MIPMAP_NEAREST:
502         case GL_NEAREST_MIPMAP_LINEAR:
503         case GL_LINEAR_MIPMAP_LINEAR:
504                 return true;
505         default: UNREACHABLE(mMinFilter);
506         }
507
508         return false;
509 }
510
511 Texture2D::Texture2D(GLuint name) : Texture(name)
512 {
513         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
514         {
515                 image[i] = nullptr;
516         }
517
518         mSurface = nullptr;
519
520         mColorbufferProxy = nullptr;
521         mProxyRefs = 0;
522 }
523
524 Texture2D::~Texture2D()
525 {
526         resource->lock(sw::DESTRUCT);
527
528         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
529         {
530                 if(image[i])
531                 {
532                         image[i]->unbind(this);
533                         image[i] = nullptr;
534                 }
535         }
536
537         resource->unlock();
538
539         if(mSurface)
540         {
541                 mSurface->setBoundTexture(nullptr);
542                 mSurface = nullptr;
543         }
544
545         mColorbufferProxy = nullptr;
546 }
547
548 // We need to maintain a count of references to renderbuffers acting as
549 // proxies for this texture, so that we do not attempt to use a pointer
550 // to a renderbuffer proxy which has been deleted.
551 void Texture2D::addProxyRef(const Renderbuffer *proxy)
552 {
553         mProxyRefs++;
554 }
555
556 void Texture2D::releaseProxy(const Renderbuffer *proxy)
557 {
558         if(mProxyRefs > 0)
559         {
560                 mProxyRefs--;
561         }
562
563         if(mProxyRefs == 0)
564         {
565                 mColorbufferProxy = nullptr;
566         }
567 }
568
569 void Texture2D::sweep()
570 {
571         int imageCount = 0;
572
573         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
574         {
575                 if(image[i] && image[i]->isChildOf(this))
576                 {
577                         if(!image[i]->hasSingleReference())
578                         {
579                                 return;
580                         }
581
582                         imageCount++;
583                 }
584         }
585
586         if(imageCount == referenceCount)
587         {
588                 destroy();
589         }
590 }
591
592 GLenum Texture2D::getTarget() const
593 {
594         return GL_TEXTURE_2D;
595 }
596
597 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
598 {
599         ASSERT(target == GL_TEXTURE_2D);
600         return image[level] ? image[level]->getWidth() : 0;
601 }
602
603 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
604 {
605         ASSERT(target == GL_TEXTURE_2D);
606         return image[level] ? image[level]->getHeight() : 0;
607 }
608
609 GLenum Texture2D::getFormat(GLenum target, GLint level) const
610 {
611         ASSERT(target == GL_TEXTURE_2D);
612         return image[level] ? image[level]->getFormat() : GL_NONE;
613 }
614
615 GLenum Texture2D::getType(GLenum target, GLint level) const
616 {
617         ASSERT(target == GL_TEXTURE_2D);
618         return image[level] ? image[level]->getType() : GL_NONE;
619 }
620
621 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
622 {
623         ASSERT(target == GL_TEXTURE_2D);
624         return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
625 }
626
627 int Texture2D::getLevelCount() const
628 {
629         ASSERT(isSamplerComplete());
630         int levels = 0;
631
632         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
633         {
634                 levels++;
635         }
636
637         return levels;
638 }
639
640 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
641 {
642         if(image[level])
643         {
644                 image[level]->release();
645         }
646
647         image[level] = new egl::Image(this, width, height, format, type);
648
649         if(!image[level])
650         {
651                 return error(GL_OUT_OF_MEMORY);
652         }
653
654         Texture::setImage(format, type, unpackInfo, pixels, image[level]);
655 }
656
657 void Texture2D::bindTexImage(egl::Surface *surface)
658 {
659         GLenum format;
660
661         switch(surface->getInternalFormat())
662         {
663         case sw::FORMAT_A8R8G8B8:
664         case sw::FORMAT_SRGB8_A8:
665                 format = GL_BGRA_EXT;
666                 break;
667         case sw::FORMAT_A8B8G8R8:
668                 format = GL_RGBA;
669                 break;
670         case sw::FORMAT_X8B8G8R8:
671         case sw::FORMAT_X8R8G8B8:
672         case sw::FORMAT_SRGB8_X8:
673                 format = GL_RGB;
674                 break;
675         default:
676                 UNIMPLEMENTED();
677                 return;
678         }
679
680         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
681         {
682                 if(image[level])
683                 {
684                         image[level]->release();
685                         image[level] = nullptr;
686                 }
687         }
688
689         image[0] = surface->getRenderTarget();
690
691         mSurface = surface;
692         mSurface->setBoundTexture(this);
693 }
694
695 void Texture2D::releaseTexImage()
696 {
697         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
698         {
699                 if(image[level])
700                 {
701                         image[level]->release();
702                         image[level] = nullptr;
703                 }
704         }
705 }
706
707 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
708 {
709         if(image[level])
710         {
711                 image[level]->release();
712         }
713
714         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
715         image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
716
717         if(!image[level])
718         {
719                 return error(GL_OUT_OF_MEMORY);
720         }
721
722         Texture::setCompressedImage(imageSize, pixels, image[level]);
723 }
724
725 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
726 {
727         Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
728 }
729
730 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
731 {
732         Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
733 }
734
735 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
736 {
737         egl::Image *renderTarget = source->getRenderTarget(0);
738
739         if(!renderTarget)
740         {
741                 ERR("Failed to retrieve the render target.");
742                 return error(GL_OUT_OF_MEMORY);
743         }
744
745         if(image[level])
746         {
747                 image[level]->release();
748         }
749
750         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
751         image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
752
753         if(!image[level])
754         {
755                 return error(GL_OUT_OF_MEMORY);
756         }
757
758         if(width != 0 && height != 0)
759         {
760                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
761
762                 if(!renderbuffer)
763                 {
764                         ERR("Failed to retrieve the source colorbuffer.");
765                         return;
766                 }
767
768                 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
769                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
770
771                 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
772         }
773
774         renderTarget->release();
775 }
776
777 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
778 {
779         if(!image[level])
780         {
781                 return error(GL_INVALID_OPERATION);
782         }
783
784         if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
785         {
786                 return error(GL_INVALID_VALUE);
787         }
788
789         egl::Image *renderTarget = source->getRenderTarget(0);
790
791         if(!renderTarget)
792         {
793                 ERR("Failed to retrieve the render target.");
794                 return error(GL_OUT_OF_MEMORY);
795         }
796
797         Renderbuffer* renderbuffer = source->getReadColorbuffer();
798
799         if(!renderbuffer)
800         {
801                 ERR("Failed to retrieve the source colorbuffer.");
802                 return;
803         }
804
805         sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
806         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
807
808         copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
809
810         renderTarget->release();
811 }
812
813 void Texture2D::setSharedImage(egl::Image *sharedImage)
814 {
815         if(sharedImage == image[0])
816         {
817                 return;
818         }
819
820         sharedImage->addRef();
821
822         if(image[0])
823         {
824                 image[0]->release();
825         }
826
827         image[0] = sharedImage;
828 }
829
830 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
831 bool Texture2D::isSamplerComplete() const
832 {
833         if(!image[0])
834         {
835                 return false;
836         }
837
838         GLsizei width = image[0]->getWidth();
839         GLsizei height = image[0]->getHeight();
840
841         if(width <= 0 || height <= 0)
842         {
843                 return false;
844         }
845
846         if(isMipmapFiltered())
847         {
848                 if(!isMipmapComplete())
849                 {
850                         return false;
851                 }
852         }
853
854         return true;
855 }
856
857 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
858 bool Texture2D::isMipmapComplete() const
859 {
860         GLsizei width = image[mBaseLevel]->getWidth();
861         GLsizei height = image[mBaseLevel]->getHeight();
862
863         int q = std::min(log2(std::max(width, height)), mMaxLevel);
864
865         for(int level = mBaseLevel + 1; level <= q; level++)
866         {
867                 if(!image[level])
868                 {
869                         return false;
870                 }
871
872                 if(image[level]->getFormat() != image[0]->getFormat())
873                 {
874                         return false;
875                 }
876
877                 if(image[level]->getType() != image[0]->getType())
878                 {
879                         return false;
880                 }
881
882                 if(image[level]->getWidth() != std::max(1, width >> level))
883                 {
884                         return false;
885                 }
886
887                 if(image[level]->getHeight() != std::max(1, height >> level))
888                 {
889                         return false;
890                 }
891         }
892
893         return true;
894 }
895
896 bool Texture2D::isCompressed(GLenum target, GLint level) const
897 {
898         return IsCompressed(getFormat(target, level), egl::getClientVersion());
899 }
900
901 bool Texture2D::isDepth(GLenum target, GLint level) const
902 {
903         return IsDepthTexture(getFormat(target, level));
904 }
905
906 void Texture2D::generateMipmaps()
907 {
908         if(!image[0])
909         {
910                 return;   // FIXME: error?
911         }
912
913         unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
914
915         for(unsigned int i = 1; i <= q; i++)
916         {
917                 if(image[i])
918                 {
919                         image[i]->release();
920                 }
921
922                 image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
923
924                 if(!image[i])
925                 {
926                         return error(GL_OUT_OF_MEMORY);
927                 }
928
929                 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
930         }
931 }
932
933 egl::Image *Texture2D::getImage(unsigned int level)
934 {
935         return image[level];
936 }
937
938 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
939 {
940         if(target != GL_TEXTURE_2D)
941         {
942                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
943         }
944
945         if(!mColorbufferProxy)
946         {
947                 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
948         }
949         else
950         {
951                 mColorbufferProxy->setLevel(level);
952         }
953
954         return mColorbufferProxy;
955 }
956
957 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
958 {
959         ASSERT(target == GL_TEXTURE_2D);
960         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
961
962         if(image[level])
963         {
964                 image[level]->addRef();
965         }
966
967         return image[level];
968 }
969
970 bool Texture2D::isShared(GLenum target, unsigned int level) const
971 {
972         ASSERT(target == GL_TEXTURE_2D);
973         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
974
975         if(mSurface)   // Bound to an EGLSurface
976         {
977                 return true;
978         }
979
980         if(!image[level])
981         {
982                 return false;
983         }
984
985         return image[level]->isShared();
986 }
987
988 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
989 {
990         for(int f = 0; f < 6; f++)
991         {
992                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
993                 {
994                         image[f][i] = nullptr;
995                 }
996         }
997
998         for(int f = 0; f < 6; f++)
999         {
1000                 mFaceProxies[f] = nullptr;
1001                 mFaceProxyRefs[f] = 0;
1002         }
1003 }
1004
1005 TextureCubeMap::~TextureCubeMap()
1006 {
1007         resource->lock(sw::DESTRUCT);
1008
1009         for(int f = 0; f < 6; f++)
1010         {
1011                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1012                 {
1013                         if(image[f][i])
1014                         {
1015                                 image[f][i]->unbind(this);
1016                                 image[f][i] = nullptr;
1017                         }
1018                 }
1019         }
1020
1021         resource->unlock();
1022
1023         for(int i = 0; i < 6; i++)
1024         {
1025                 mFaceProxies[i] = nullptr;
1026         }
1027 }
1028
1029 // We need to maintain a count of references to renderbuffers acting as
1030 // proxies for this texture, so that the texture is not deleted while
1031 // proxy references still exist. If the reference count drops to zero,
1032 // we set our proxy pointer null, so that a new attempt at referencing
1033 // will cause recreation.
1034 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1035 {
1036         for(int f = 0; f < 6; f++)
1037         {
1038                 if(mFaceProxies[f] == proxy)
1039                 {
1040                         mFaceProxyRefs[f]++;
1041                 }
1042         }
1043 }
1044
1045 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1046 {
1047         for(int f = 0; f < 6; f++)
1048         {
1049                 if(mFaceProxies[f] == proxy)
1050                 {
1051                         if(mFaceProxyRefs[f] > 0)
1052                         {
1053                                 mFaceProxyRefs[f]--;
1054                         }
1055
1056                         if(mFaceProxyRefs[f] == 0)
1057                         {
1058                                 mFaceProxies[f] = nullptr;
1059                         }
1060                 }
1061         }
1062 }
1063
1064 void TextureCubeMap::sweep()
1065 {
1066         int imageCount = 0;
1067
1068         for(int f = 0; f < 6; f++)
1069         {
1070                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1071                 {
1072                         if(image[f][i] && image[f][i]->isChildOf(this))
1073                         {
1074                                 if(!image[f][i]->hasSingleReference())
1075                                 {
1076                                         return;
1077                                 }
1078
1079                                 imageCount++;
1080                         }
1081                 }
1082         }
1083
1084         if(imageCount == referenceCount)
1085         {
1086                 destroy();
1087         }
1088 }
1089
1090 GLenum TextureCubeMap::getTarget() const
1091 {
1092         return GL_TEXTURE_CUBE_MAP;
1093 }
1094
1095 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1096 {
1097         int face = CubeFaceIndex(target);
1098         return image[face][level] ? image[face][level]->getWidth() : 0;
1099 }
1100
1101 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1102 {
1103         int face = CubeFaceIndex(target);
1104         return image[face][level] ? image[face][level]->getHeight() : 0;
1105 }
1106
1107 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
1108 {
1109         int face = CubeFaceIndex(target);
1110         return image[face][level] ? image[face][level]->getFormat() : 0;
1111 }
1112
1113 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
1114 {
1115         int face = CubeFaceIndex(target);
1116         return image[face][level] ? image[face][level]->getType() : 0;
1117 }
1118
1119 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1120 {
1121         int face = CubeFaceIndex(target);
1122         return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
1123 }
1124
1125 int TextureCubeMap::getLevelCount() const
1126 {
1127         ASSERT(isSamplerComplete());
1128         int levels = 0;
1129
1130         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
1131         {
1132                 levels++;
1133         }
1134
1135         return levels;
1136 }
1137
1138 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1139 {
1140         int face = CubeFaceIndex(target);
1141
1142         if(image[face][level])
1143         {
1144                 image[face][level]->release();
1145         }
1146
1147         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1148         image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1149
1150         if(!image[face][level])
1151         {
1152                 return error(GL_OUT_OF_MEMORY);
1153         }
1154
1155         Texture::setCompressedImage(imageSize, pixels, image[face][level]);
1156 }
1157
1158 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1159 {
1160         Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
1161 }
1162
1163 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1164 {
1165         Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1166 }
1167
1168 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1169 bool TextureCubeMap::isSamplerComplete() const
1170 {
1171         for(int face = 0; face < 6; face++)
1172         {
1173                 if(!image[face][0])
1174                 {
1175                         return false;
1176                 }
1177         }
1178
1179         int size = image[0][0]->getWidth();
1180
1181         if(size <= 0)
1182         {
1183                 return false;
1184         }
1185
1186         if(!isMipmapFiltered())
1187         {
1188                 if(!isCubeComplete())
1189                 {
1190                         return false;
1191                 }
1192         }
1193         else
1194         {
1195                 if(!isMipmapCubeComplete())   // Also tests for isCubeComplete()
1196                 {
1197                         return false;
1198                 }
1199         }
1200
1201         return true;
1202 }
1203
1204 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1205 bool TextureCubeMap::isCubeComplete() const
1206 {
1207         if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1208         {
1209                 return false;
1210         }
1211
1212         for(unsigned int face = 1; face < 6; face++)
1213         {
1214                 if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
1215                    image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
1216                    image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
1217                    image[face][mBaseLevel]->getType()   != image[0][mBaseLevel]->getType())
1218                 {
1219                         return false;
1220                 }
1221         }
1222
1223         return true;
1224 }
1225
1226 bool TextureCubeMap::isMipmapCubeComplete() const
1227 {
1228         if(!isCubeComplete())
1229         {
1230                 return false;
1231         }
1232
1233         GLsizei size = image[0][mBaseLevel]->getWidth();
1234         int q = std::min(log2(size), mMaxLevel);
1235
1236         for(int face = 0; face < 6; face++)
1237         {
1238                 for(int level = mBaseLevel + 1; level <= q; level++)
1239                 {
1240                         if(!image[face][level])
1241                         {
1242                                 return false;
1243                         }
1244
1245                         if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1246                         {
1247                                 return false;
1248                         }
1249
1250                         if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
1251                         {
1252                                 return false;
1253                         }
1254
1255                         if(image[face][level]->getWidth() != std::max(1, size >> level))
1256                         {
1257                                 return false;
1258                         }
1259                 }
1260         }
1261
1262         return true;
1263 }
1264
1265 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1266 {
1267         return IsCompressed(getFormat(target, level), egl::getClientVersion());
1268 }
1269
1270 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1271 {
1272         return IsDepthTexture(getFormat(target, level));
1273 }
1274
1275 void TextureCubeMap::releaseTexImage()
1276 {
1277         UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
1278 }
1279
1280 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1281 {
1282         int face = CubeFaceIndex(target);
1283
1284         if(image[face][level])
1285         {
1286                 image[face][level]->release();
1287         }
1288
1289         image[face][level] = new egl::Image(this, width, height, format, type);
1290
1291         if(!image[face][level])
1292         {
1293                 return error(GL_OUT_OF_MEMORY);
1294         }
1295
1296         Texture::setImage(format, type, unpackInfo, pixels, image[face][level]);
1297 }
1298
1299 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1300 {
1301         egl::Image *renderTarget = source->getRenderTarget(0);
1302
1303         if(!renderTarget)
1304         {
1305                 ERR("Failed to retrieve the render target.");
1306                 return error(GL_OUT_OF_MEMORY);
1307         }
1308
1309         int face = CubeFaceIndex(target);
1310
1311         if(image[face][level])
1312         {
1313                 image[face][level]->release();
1314         }
1315
1316         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1317         image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1318
1319         if(!image[face][level])
1320         {
1321                 return error(GL_OUT_OF_MEMORY);
1322         }
1323
1324         if(width != 0 && height != 0)
1325         {
1326                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1327
1328                 if(!renderbuffer)
1329                 {
1330                         ERR("Failed to retrieve the source colorbuffer.");
1331                         return;
1332                 }
1333
1334                 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1335                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1336
1337                 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
1338         }
1339
1340         renderTarget->release();
1341 }
1342
1343 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1344 {
1345         return image[face][level];
1346 }
1347
1348 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1349 {
1350         return image[CubeFaceIndex(face)][level];
1351 }
1352
1353 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1354 {
1355         int face = CubeFaceIndex(target);
1356
1357         if(!image[face][level])
1358         {
1359                 return error(GL_INVALID_OPERATION);
1360         }
1361
1362         GLsizei size = image[face][level]->getWidth();
1363
1364         if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1365         {
1366                 return error(GL_INVALID_VALUE);
1367         }
1368
1369         egl::Image *renderTarget = source->getRenderTarget(0);
1370
1371         if(!renderTarget)
1372         {
1373                 ERR("Failed to retrieve the render target.");
1374                 return error(GL_OUT_OF_MEMORY);
1375         }
1376
1377         Renderbuffer* renderbuffer = source->getReadColorbuffer();
1378
1379         if(!renderbuffer)
1380         {
1381                 ERR("Failed to retrieve the source colorbuffer.");
1382                 return;
1383         }
1384
1385         sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1386         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1387
1388         copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
1389
1390         renderTarget->release();
1391 }
1392
1393 void TextureCubeMap::generateMipmaps()
1394 {
1395         if(!isCubeComplete())
1396         {
1397                 return error(GL_INVALID_OPERATION);
1398         }
1399
1400         unsigned int q = log2(image[0][0]->getWidth());
1401
1402         for(unsigned int f = 0; f < 6; f++)
1403         {
1404                 for(unsigned int i = 1; i <= q; i++)
1405                 {
1406                         if(image[f][i])
1407                         {
1408                                 image[f][i]->release();
1409                         }
1410
1411                         image[f][i] = new egl::Image(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType());
1412
1413                         if(!image[f][i])
1414                         {
1415                                 return error(GL_OUT_OF_MEMORY);
1416                         }
1417
1418                         getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
1419                 }
1420         }
1421 }
1422
1423 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
1424 {
1425         if(!IsCubemapTextureTarget(target))
1426         {
1427                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1428         }
1429
1430         int face = CubeFaceIndex(target);
1431
1432         if(!mFaceProxies[face])
1433         {
1434                 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1435         }
1436         else
1437         {
1438                 mFaceProxies[face]->setLevel(level);
1439         }
1440
1441         return mFaceProxies[face];
1442 }
1443
1444 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1445 {
1446         ASSERT(IsCubemapTextureTarget(target));
1447         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1448
1449         int face = CubeFaceIndex(target);
1450
1451         if(image[face][level])
1452         {
1453                 image[face][level]->addRef();
1454         }
1455
1456         return image[face][level];
1457 }
1458
1459 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1460 {
1461         ASSERT(IsCubemapTextureTarget(target));
1462         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1463
1464         int face = CubeFaceIndex(target);
1465
1466         if(!image[face][level])
1467         {
1468                 return false;
1469         }
1470
1471         return image[face][level]->isShared();
1472 }
1473
1474 Texture3D::Texture3D(GLuint name) : Texture(name)
1475 {
1476         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1477         {
1478                 image[i] = nullptr;
1479         }
1480
1481         mSurface = nullptr;
1482
1483         mColorbufferProxy = nullptr;
1484         mProxyRefs = 0;
1485 }
1486
1487 Texture3D::~Texture3D()
1488 {
1489         resource->lock(sw::DESTRUCT);
1490
1491         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1492         {
1493                 if(image[i])
1494                 {
1495                         image[i]->unbind(this);
1496                         image[i] = nullptr;
1497                 }
1498         }
1499
1500         resource->unlock();
1501
1502         if(mSurface)
1503         {
1504                 mSurface->setBoundTexture(nullptr);
1505                 mSurface = nullptr;
1506         }
1507
1508         mColorbufferProxy = nullptr;
1509 }
1510
1511 // We need to maintain a count of references to renderbuffers acting as
1512 // proxies for this texture, so that we do not attempt to use a pointer
1513 // to a renderbuffer proxy which has been deleted.
1514 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1515 {
1516         mProxyRefs++;
1517 }
1518
1519 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1520 {
1521         if(mProxyRefs > 0)
1522         {
1523                 mProxyRefs--;
1524         }
1525
1526         if(mProxyRefs == 0)
1527         {
1528                 mColorbufferProxy = nullptr;
1529         }
1530 }
1531
1532 void Texture3D::sweep()
1533 {
1534         int imageCount = 0;
1535
1536         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1537         {
1538                 if(image[i] && image[i]->isChildOf(this))
1539                 {
1540                         if(!image[i]->hasSingleReference())
1541                         {
1542                                 return;
1543                         }
1544
1545                         imageCount++;
1546                 }
1547         }
1548
1549         if(imageCount == referenceCount)
1550         {
1551                 destroy();
1552         }
1553 }
1554
1555 GLenum Texture3D::getTarget() const
1556 {
1557         return GL_TEXTURE_3D_OES;
1558 }
1559
1560 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1561 {
1562         ASSERT(target == getTarget());
1563         return image[level] ? image[level]->getWidth() : 0;
1564 }
1565
1566 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1567 {
1568         ASSERT(target == getTarget());
1569         return image[level] ? image[level]->getHeight() : 0;
1570 }
1571
1572 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1573 {
1574         ASSERT(target == getTarget());
1575         return image[level] ? image[level]->getDepth() : 0;
1576 }
1577
1578 GLenum Texture3D::getFormat(GLenum target, GLint level) const
1579 {
1580         ASSERT(target == getTarget());
1581         return image[level] ? image[level]->getFormat() : GL_NONE;
1582 }
1583
1584 GLenum Texture3D::getType(GLenum target, GLint level) const
1585 {
1586         ASSERT(target == getTarget());
1587         return image[level] ? image[level]->getType() : GL_NONE;
1588 }
1589
1590 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
1591 {
1592         ASSERT(target == getTarget());
1593         return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
1594 }
1595
1596 int Texture3D::getLevelCount() const
1597 {
1598         ASSERT(isSamplerComplete());
1599         int levels = 0;
1600
1601         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
1602         {
1603                 levels++;
1604         }
1605
1606         return levels;
1607 }
1608
1609 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1610 {
1611         if(image[level])
1612         {
1613                 image[level]->release();
1614         }
1615
1616         image[level] = new egl::Image(this, width, height, depth, format, type);
1617
1618         if(!image[level])
1619         {
1620                 return error(GL_OUT_OF_MEMORY);
1621         }
1622
1623         Texture::setImage(format, type, unpackInfo, pixels, image[level]);
1624 }
1625
1626 void Texture3D::bindTexImage(egl::Surface *surface)
1627 {
1628         GLenum format;
1629
1630         switch(surface->getInternalFormat())
1631         {
1632         case sw::FORMAT_A8R8G8B8:
1633                 format = GL_RGBA;
1634                 break;
1635         case sw::FORMAT_X8R8G8B8:
1636                 format = GL_RGB;
1637                 break;
1638         default:
1639                 UNIMPLEMENTED();
1640                 return;
1641         }
1642
1643         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1644         {
1645                 if(image[level])
1646                 {
1647                         image[level]->release();
1648                         image[level] = nullptr;
1649                 }
1650         }
1651
1652         image[0] = surface->getRenderTarget();
1653
1654         mSurface = surface;
1655         mSurface->setBoundTexture(this);
1656 }
1657
1658 void Texture3D::releaseTexImage()
1659 {
1660         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1661         {
1662                 if(image[level])
1663                 {
1664                         image[level]->release();
1665                         image[level] = nullptr;
1666                 }
1667         }
1668 }
1669
1670 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1671 {
1672         if(image[level])
1673         {
1674                 image[level]->release();
1675         }
1676
1677         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1678         image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1679
1680         if(!image[level])
1681         {
1682                 return error(GL_OUT_OF_MEMORY);
1683         }
1684
1685         Texture::setCompressedImage(imageSize, pixels, image[level]);
1686 }
1687
1688 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1689 {
1690         Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
1691 }
1692
1693 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1694 {
1695         Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1696 }
1697
1698 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
1699 {
1700         egl::Image *renderTarget = source->getRenderTarget(0);
1701
1702         if(!renderTarget)
1703         {
1704                 ERR("Failed to retrieve the render target.");
1705                 return error(GL_OUT_OF_MEMORY);
1706         }
1707
1708         if(image[level])
1709         {
1710                 image[level]->release();
1711         }
1712
1713         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1714         image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1715
1716         if(!image[level])
1717         {
1718                 return error(GL_OUT_OF_MEMORY);
1719         }
1720
1721         if(width != 0 && height != 0 && depth != 0)
1722         {
1723                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1724
1725                 if(!renderbuffer)
1726                 {
1727                         ERR("Failed to retrieve the source colorbuffer.");
1728                         return;
1729                 }
1730
1731                 sw::SliceRect sourceRect(x, y, x + width, y + height, z);
1732                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1733                 for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
1734                 {
1735                         copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
1736                 }
1737         }
1738
1739         renderTarget->release();
1740 }
1741
1742 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1743 {
1744         if(!image[level])
1745         {
1746                 return error(GL_INVALID_OPERATION);
1747         }
1748
1749         if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1750         {
1751                 return error(GL_INVALID_VALUE);
1752         }
1753
1754         egl::Image *renderTarget = source->getRenderTarget(0);
1755
1756         if(!renderTarget)
1757         {
1758                 ERR("Failed to retrieve the render target.");
1759                 return error(GL_OUT_OF_MEMORY);
1760         }
1761
1762         Renderbuffer* renderbuffer = source->getReadColorbuffer();
1763
1764         if(!renderbuffer)
1765         {
1766                 ERR("Failed to retrieve the source colorbuffer.");
1767                 return;
1768         }
1769
1770         sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1771         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1772
1773         copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
1774
1775         renderTarget->release();
1776 }
1777
1778 void Texture3D::setSharedImage(egl::Image *sharedImage)
1779 {
1780         sharedImage->addRef();
1781
1782         if(image[0])
1783         {
1784                 image[0]->release();
1785         }
1786
1787         image[0] = sharedImage;
1788 }
1789
1790 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1791 bool Texture3D::isSamplerComplete() const
1792 {
1793         if(!image[0])
1794         {
1795                 return false;
1796         }
1797
1798         GLsizei width = image[0]->getWidth();
1799         GLsizei height = image[0]->getHeight();
1800         GLsizei depth = image[0]->getDepth();
1801
1802         if(width <= 0 || height <= 0 || depth <= 0)
1803         {
1804                 return false;
1805         }
1806
1807         if(isMipmapFiltered())
1808         {
1809                 if(!isMipmapComplete())
1810                 {
1811                         return false;
1812                 }
1813         }
1814
1815         return true;
1816 }
1817
1818 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1819 bool Texture3D::isMipmapComplete() const
1820 {
1821         GLsizei width = image[mBaseLevel]->getWidth();
1822         GLsizei height = image[mBaseLevel]->getHeight();
1823         GLsizei depth = image[mBaseLevel]->getDepth();
1824         bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
1825
1826         int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
1827                 std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
1828
1829         for(int level = mBaseLevel + 1; level <= q; level++)
1830         {
1831                 if(!image[level])
1832                 {
1833                         return false;
1834                 }
1835
1836                 if(image[level]->getFormat() != image[0]->getFormat())
1837                 {
1838                         return false;
1839                 }
1840
1841                 if(image[level]->getType() != image[0]->getType())
1842                 {
1843                         return false;
1844                 }
1845
1846                 if(image[level]->getWidth() != std::max(1, width >> level))
1847                 {
1848                         return false;
1849                 }
1850
1851                 if(image[level]->getHeight() != std::max(1, height >> level))
1852                 {
1853                         return false;
1854                 }
1855
1856                 int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
1857                 if(image[level]->getDepth() != levelDepth)
1858                 {
1859                         return false;
1860                 }
1861         }
1862
1863         return true;
1864 }
1865
1866 bool Texture3D::isCompressed(GLenum target, GLint level) const
1867 {
1868         return IsCompressed(getFormat(target, level), egl::getClientVersion());
1869 }
1870
1871 bool Texture3D::isDepth(GLenum target, GLint level) const
1872 {
1873         return IsDepthTexture(getFormat(target, level));
1874 }
1875
1876 void Texture3D::generateMipmaps()
1877 {
1878         if(!image[0])
1879         {
1880                 return;   // FIXME: error?
1881         }
1882
1883         unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
1884
1885         for(unsigned int i = 1; i <= q; i++)
1886         {
1887                 if(image[i])
1888                 {
1889                         image[i]->release();
1890                 }
1891
1892                 image[i] = new egl::Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), std::max(image[0]->getDepth() >> i, 1), image[0]->getFormat(), image[0]->getType());
1893
1894                 if(!image[i])
1895                 {
1896                         return error(GL_OUT_OF_MEMORY);
1897                 }
1898
1899                 getDevice()->stretchCube(image[i - 1], image[i]);
1900         }
1901 }
1902
1903 egl::Image *Texture3D::getImage(unsigned int level)
1904 {
1905         return image[level];
1906 }
1907
1908 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
1909 {
1910         if(target != getTarget())
1911         {
1912                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1913         }
1914
1915         if(!mColorbufferProxy)
1916         {
1917                 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
1918         }
1919         else
1920         {
1921                 mColorbufferProxy->setLevel(level);
1922                 mColorbufferProxy->setLayer(layer);
1923         }
1924
1925         return mColorbufferProxy;
1926 }
1927
1928 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1929 {
1930         ASSERT(target == getTarget());
1931         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1932
1933         if(image[level])
1934         {
1935                 image[level]->addRef();
1936         }
1937
1938         return image[level];
1939 }
1940
1941 bool Texture3D::isShared(GLenum target, unsigned int level) const
1942 {
1943         ASSERT(target == getTarget());
1944         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1945
1946         if(mSurface)   // Bound to an EGLSurface
1947         {
1948                 return true;
1949         }
1950
1951         if(!image[level])
1952         {
1953                 return false;
1954         }
1955
1956         return image[level]->isShared();
1957 }
1958
1959 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1960 {
1961 }
1962
1963 Texture2DArray::~Texture2DArray()
1964 {
1965 }
1966
1967 GLenum Texture2DArray::getTarget() const
1968 {
1969         return GL_TEXTURE_2D_ARRAY;
1970 }
1971
1972 void Texture2DArray::generateMipmaps()
1973 {
1974         int depth = image[0] ? image[0]->getDepth() : 0;
1975         if(!depth)
1976         {
1977                 return;   // FIXME: error?
1978         }
1979
1980         unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
1981
1982         for(unsigned int i = 1; i <= q; i++)
1983         {
1984                 if(image[i])
1985                 {
1986                         image[i]->release();
1987                 }
1988
1989                 GLsizei w = std::max(image[0]->getWidth() >> i, 1);
1990                 GLsizei h = std::max(image[0]->getHeight() >> i, 1);
1991                 image[i] = new egl::Image(this, w, h, depth, image[0]->getFormat(), image[0]->getType());
1992
1993                 if(!image[i])
1994                 {
1995                         return error(GL_OUT_OF_MEMORY);
1996                 }
1997
1998                 GLsizei srcw = image[i - 1]->getWidth();
1999                 GLsizei srch = image[i - 1]->getHeight();
2000                 for(int z = 0; z < depth; ++z)
2001                 {
2002                         sw::SliceRect srcRect(0, 0, srcw, srch, z);
2003                         sw::SliceRect dstRect(0, 0, w, h, z);
2004                         getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
2005                 }
2006         }
2007 }
2008
2009 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
2010 {
2011         mMinFilter = GL_LINEAR;
2012         mMagFilter = GL_LINEAR;
2013         mWrapS = GL_CLAMP_TO_EDGE;
2014         mWrapT = GL_CLAMP_TO_EDGE;
2015         mWrapR = GL_CLAMP_TO_EDGE;
2016 }
2017
2018 TextureExternal::~TextureExternal()
2019 {
2020 }
2021
2022 GLenum TextureExternal::getTarget() const
2023 {
2024         return GL_TEXTURE_EXTERNAL_OES;
2025 }
2026
2027 }
2028
2029 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
2030 {
2031         if(config)
2032         {
2033                 return new egl::Image(width, height, config->mRenderTargetFormat, config->mSamples, false);
2034         }
2035
2036         return nullptr;
2037 }
2038
2039 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
2040 {
2041         if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION)
2042         {
2043                 ERR("Invalid parameters: %dx%d", width, height);
2044                 return nullptr;
2045         }
2046
2047         bool lockable = true;
2048
2049         switch(format)
2050         {
2051 //      case sw::FORMAT_D15S1:
2052         case sw::FORMAT_D24S8:
2053         case sw::FORMAT_D24X8:
2054 //      case sw::FORMAT_D24X4S4:
2055         case sw::FORMAT_D24FS8:
2056         case sw::FORMAT_D32:
2057         case sw::FORMAT_D16:
2058                 lockable = false;
2059                 break;
2060 //      case sw::FORMAT_S8_LOCKABLE:
2061 //      case sw::FORMAT_D16_LOCKABLE:
2062         case sw::FORMAT_D32F_LOCKABLE:
2063 //      case sw::FORMAT_D32_LOCKABLE:
2064         case sw::FORMAT_DF24S8:
2065         case sw::FORMAT_DF16S8:
2066                 lockable = true;
2067                 break;
2068         default:
2069                 UNREACHABLE(format);
2070         }
2071
2072         egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
2073
2074         if(!surface)
2075         {
2076                 ERR("Out of memory");
2077                 return nullptr;
2078         }
2079
2080         return surface;
2081 }