OSDN Git Service

Make Blitter part of Renderer.
[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 "common/Surface.hpp"
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(egl::Context *context, 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(context, 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(egl::Context *context, 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(context, 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         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
527         {
528                 if(image[i])
529                 {
530                         image[i]->unbind(this);
531                         image[i] = nullptr;
532                 }
533         }
534
535         if(mSurface)
536         {
537                 mSurface->setBoundTexture(nullptr);
538                 mSurface = nullptr;
539         }
540
541         mColorbufferProxy = nullptr;
542 }
543
544 // We need to maintain a count of references to renderbuffers acting as
545 // proxies for this texture, so that we do not attempt to use a pointer
546 // to a renderbuffer proxy which has been deleted.
547 void Texture2D::addProxyRef(const Renderbuffer *proxy)
548 {
549         mProxyRefs++;
550 }
551
552 void Texture2D::releaseProxy(const Renderbuffer *proxy)
553 {
554         if(mProxyRefs > 0)
555         {
556                 mProxyRefs--;
557         }
558
559         if(mProxyRefs == 0)
560         {
561                 mColorbufferProxy = nullptr;
562         }
563 }
564
565 void Texture2D::sweep()
566 {
567         int imageCount = 0;
568
569         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
570         {
571                 if(image[i] && image[i]->isChildOf(this))
572                 {
573                         if(!image[i]->hasSingleReference())
574                         {
575                                 return;
576                         }
577
578                         imageCount++;
579                 }
580         }
581
582         if(imageCount == referenceCount)
583         {
584                 destroy();
585         }
586 }
587
588 GLenum Texture2D::getTarget() const
589 {
590         return GL_TEXTURE_2D;
591 }
592
593 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
594 {
595         ASSERT(target == GL_TEXTURE_2D);
596         return image[level] ? image[level]->getWidth() : 0;
597 }
598
599 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
600 {
601         ASSERT(target == GL_TEXTURE_2D);
602         return image[level] ? image[level]->getHeight() : 0;
603 }
604
605 GLenum Texture2D::getFormat(GLenum target, GLint level) const
606 {
607         ASSERT(target == GL_TEXTURE_2D);
608         return image[level] ? image[level]->getFormat() : GL_NONE;
609 }
610
611 GLenum Texture2D::getType(GLenum target, GLint level) const
612 {
613         ASSERT(target == GL_TEXTURE_2D);
614         return image[level] ? image[level]->getType() : GL_NONE;
615 }
616
617 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
618 {
619         ASSERT(target == GL_TEXTURE_2D);
620         return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
621 }
622
623 int Texture2D::getLevelCount() const
624 {
625         ASSERT(isSamplerComplete());
626         int levels = 0;
627
628         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
629         {
630                 levels++;
631         }
632
633         return levels;
634 }
635
636 void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
637 {
638         if(image[level])
639         {
640                 image[level]->release();
641         }
642
643         image[level] = egl::Image::create(this, width, height, format, type);
644
645         if(!image[level])
646         {
647                 return error(GL_OUT_OF_MEMORY);
648         }
649
650         Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
651 }
652
653 void Texture2D::bindTexImage(gl::Surface *surface)
654 {
655         GLenum format;
656
657         switch(surface->getInternalFormat())
658         {
659         case sw::FORMAT_A8R8G8B8:
660         case sw::FORMAT_SRGB8_A8:
661                 format = GL_BGRA_EXT;
662                 break;
663         case sw::FORMAT_A8B8G8R8:
664                 format = GL_RGBA;
665                 break;
666         case sw::FORMAT_X8B8G8R8:
667         case sw::FORMAT_X8R8G8B8:
668         case sw::FORMAT_SRGB8_X8:
669                 format = GL_RGB;
670                 break;
671         default:
672                 UNIMPLEMENTED();
673                 return;
674         }
675
676         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
677         {
678                 if(image[level])
679                 {
680                         image[level]->release();
681                         image[level] = nullptr;
682                 }
683         }
684
685         image[0] = surface->getRenderTarget();
686
687         mSurface = surface;
688         mSurface->setBoundTexture(this);
689 }
690
691 void Texture2D::releaseTexImage()
692 {
693         for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
694         {
695                 if(image[level])
696                 {
697                         image[level]->release();
698                         image[level] = nullptr;
699                 }
700         }
701 }
702
703 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
704 {
705         if(image[level])
706         {
707                 image[level]->release();
708         }
709
710         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
711         image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
712
713         if(!image[level])
714         {
715                 return error(GL_OUT_OF_MEMORY);
716         }
717
718         Texture::setCompressedImage(imageSize, pixels, image[level]);
719 }
720
721 void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
722 {
723         Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
724 }
725
726 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
727 {
728         Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
729 }
730
731 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
732 {
733         egl::Image *renderTarget = source->getRenderTarget(0);
734
735         if(!renderTarget)
736         {
737                 ERR("Failed to retrieve the render target.");
738                 return error(GL_OUT_OF_MEMORY);
739         }
740
741         if(image[level])
742         {
743                 image[level]->release();
744         }
745
746         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
747         image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
748
749         if(!image[level])
750         {
751                 return error(GL_OUT_OF_MEMORY);
752         }
753
754         if(width != 0 && height != 0)
755         {
756                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
757
758                 if(!renderbuffer)
759                 {
760                         ERR("Failed to retrieve the source colorbuffer.");
761                         return;
762                 }
763
764                 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
765                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
766
767                 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
768         }
769
770         renderTarget->release();
771 }
772
773 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
774 {
775         if(!image[level])
776         {
777                 return error(GL_INVALID_OPERATION);
778         }
779
780         if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
781         {
782                 return error(GL_INVALID_VALUE);
783         }
784
785         egl::Image *renderTarget = source->getRenderTarget(0);
786
787         if(!renderTarget)
788         {
789                 ERR("Failed to retrieve the render target.");
790                 return error(GL_OUT_OF_MEMORY);
791         }
792
793         Renderbuffer* renderbuffer = source->getReadColorbuffer();
794
795         if(!renderbuffer)
796         {
797                 ERR("Failed to retrieve the source colorbuffer.");
798                 return;
799         }
800
801         sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
802         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
803
804         copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
805
806         renderTarget->release();
807 }
808
809 void Texture2D::setSharedImage(egl::Image *sharedImage)
810 {
811         if(sharedImage == image[0])
812         {
813                 return;
814         }
815
816         sharedImage->addRef();
817
818         if(image[0])
819         {
820                 image[0]->release();
821         }
822
823         image[0] = sharedImage;
824 }
825
826 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
827 bool Texture2D::isSamplerComplete() const
828 {
829         if(!image[0])
830         {
831                 return false;
832         }
833
834         GLsizei width = image[0]->getWidth();
835         GLsizei height = image[0]->getHeight();
836
837         if(width <= 0 || height <= 0)
838         {
839                 return false;
840         }
841
842         if(isMipmapFiltered())
843         {
844                 if(!isMipmapComplete())
845                 {
846                         return false;
847                 }
848         }
849
850         return true;
851 }
852
853 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
854 bool Texture2D::isMipmapComplete() const
855 {
856         GLsizei width = image[mBaseLevel]->getWidth();
857         GLsizei height = image[mBaseLevel]->getHeight();
858
859         int q = std::min(log2(std::max(width, height)), mMaxLevel);
860
861         for(int level = mBaseLevel + 1; level <= q; level++)
862         {
863                 if(!image[level])
864                 {
865                         return false;
866                 }
867
868                 if(image[level]->getFormat() != image[0]->getFormat())
869                 {
870                         return false;
871                 }
872
873                 if(image[level]->getType() != image[0]->getType())
874                 {
875                         return false;
876                 }
877
878                 if(image[level]->getWidth() != std::max(1, width >> level))
879                 {
880                         return false;
881                 }
882
883                 if(image[level]->getHeight() != std::max(1, height >> level))
884                 {
885                         return false;
886                 }
887         }
888
889         return true;
890 }
891
892 bool Texture2D::isCompressed(GLenum target, GLint level) const
893 {
894         return IsCompressed(getFormat(target, level), egl::getClientVersion());
895 }
896
897 bool Texture2D::isDepth(GLenum target, GLint level) const
898 {
899         return IsDepthTexture(getFormat(target, level));
900 }
901
902 void Texture2D::generateMipmaps()
903 {
904         if(!image[0])
905         {
906                 return;   // FIXME: error?
907         }
908
909         unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
910
911         for(unsigned int i = 1; i <= q; i++)
912         {
913                 if(image[i])
914                 {
915                         image[i]->release();
916                 }
917
918                 image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
919
920                 if(!image[i])
921                 {
922                         return error(GL_OUT_OF_MEMORY);
923                 }
924
925                 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
926         }
927 }
928
929 egl::Image *Texture2D::getImage(unsigned int level)
930 {
931         return image[level];
932 }
933
934 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
935 {
936         if(target != GL_TEXTURE_2D)
937         {
938                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
939         }
940
941         if(!mColorbufferProxy)
942         {
943                 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
944         }
945         else
946         {
947                 mColorbufferProxy->setLevel(level);
948         }
949
950         return mColorbufferProxy;
951 }
952
953 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
954 {
955         ASSERT(target == GL_TEXTURE_2D);
956         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
957
958         if(image[level])
959         {
960                 image[level]->addRef();
961         }
962
963         return image[level];
964 }
965
966 bool Texture2D::isShared(GLenum target, unsigned int level) const
967 {
968         ASSERT(target == GL_TEXTURE_2D);
969         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
970
971         if(mSurface)   // Bound to an EGLSurface
972         {
973                 return true;
974         }
975
976         if(!image[level])
977         {
978                 return false;
979         }
980
981         return image[level]->isShared();
982 }
983
984 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
985 {
986         for(int f = 0; f < 6; f++)
987         {
988                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
989                 {
990                         image[f][i] = nullptr;
991                 }
992         }
993
994         for(int f = 0; f < 6; f++)
995         {
996                 mFaceProxies[f] = nullptr;
997                 mFaceProxyRefs[f] = 0;
998         }
999 }
1000
1001 TextureCubeMap::~TextureCubeMap()
1002 {
1003         for(int f = 0; f < 6; f++)
1004         {
1005                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1006                 {
1007                         if(image[f][i])
1008                         {
1009                                 image[f][i]->unbind(this);
1010                                 image[f][i] = nullptr;
1011                         }
1012                 }
1013         }
1014
1015         for(int i = 0; i < 6; i++)
1016         {
1017                 mFaceProxies[i] = nullptr;
1018         }
1019 }
1020
1021 // We need to maintain a count of references to renderbuffers acting as
1022 // proxies for this texture, so that the texture is not deleted while
1023 // proxy references still exist. If the reference count drops to zero,
1024 // we set our proxy pointer null, so that a new attempt at referencing
1025 // will cause recreation.
1026 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1027 {
1028         for(int f = 0; f < 6; f++)
1029         {
1030                 if(mFaceProxies[f] == proxy)
1031                 {
1032                         mFaceProxyRefs[f]++;
1033                 }
1034         }
1035 }
1036
1037 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1038 {
1039         for(int f = 0; f < 6; f++)
1040         {
1041                 if(mFaceProxies[f] == proxy)
1042                 {
1043                         if(mFaceProxyRefs[f] > 0)
1044                         {
1045                                 mFaceProxyRefs[f]--;
1046                         }
1047
1048                         if(mFaceProxyRefs[f] == 0)
1049                         {
1050                                 mFaceProxies[f] = nullptr;
1051                         }
1052                 }
1053         }
1054 }
1055
1056 void TextureCubeMap::sweep()
1057 {
1058         int imageCount = 0;
1059
1060         for(int f = 0; f < 6; f++)
1061         {
1062                 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1063                 {
1064                         if(image[f][i] && image[f][i]->isChildOf(this))
1065                         {
1066                                 if(!image[f][i]->hasSingleReference())
1067                                 {
1068                                         return;
1069                                 }
1070
1071                                 imageCount++;
1072                         }
1073                 }
1074         }
1075
1076         if(imageCount == referenceCount)
1077         {
1078                 destroy();
1079         }
1080 }
1081
1082 GLenum TextureCubeMap::getTarget() const
1083 {
1084         return GL_TEXTURE_CUBE_MAP;
1085 }
1086
1087 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1088 {
1089         int face = CubeFaceIndex(target);
1090         return image[face][level] ? image[face][level]->getWidth() : 0;
1091 }
1092
1093 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1094 {
1095         int face = CubeFaceIndex(target);
1096         return image[face][level] ? image[face][level]->getHeight() : 0;
1097 }
1098
1099 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
1100 {
1101         int face = CubeFaceIndex(target);
1102         return image[face][level] ? image[face][level]->getFormat() : 0;
1103 }
1104
1105 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
1106 {
1107         int face = CubeFaceIndex(target);
1108         return image[face][level] ? image[face][level]->getType() : 0;
1109 }
1110
1111 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1112 {
1113         int face = CubeFaceIndex(target);
1114         return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
1115 }
1116
1117 int TextureCubeMap::getLevelCount() const
1118 {
1119         ASSERT(isSamplerComplete());
1120         int levels = 0;
1121
1122         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
1123         {
1124                 levels++;
1125         }
1126
1127         return levels;
1128 }
1129
1130 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1131 {
1132         int face = CubeFaceIndex(target);
1133
1134         if(image[face][level])
1135         {
1136                 image[face][level]->release();
1137         }
1138
1139         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1140         image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1141
1142         if(!image[face][level])
1143         {
1144                 return error(GL_OUT_OF_MEMORY);
1145         }
1146
1147         Texture::setCompressedImage(imageSize, pixels, image[face][level]);
1148 }
1149
1150 void TextureCubeMap::subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1151 {
1152         Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
1153 }
1154
1155 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1156 {
1157         Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1158 }
1159
1160 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1161 bool TextureCubeMap::isSamplerComplete() const
1162 {
1163         for(int face = 0; face < 6; face++)
1164         {
1165                 if(!image[face][0])
1166                 {
1167                         return false;
1168                 }
1169         }
1170
1171         int size = image[0][0]->getWidth();
1172
1173         if(size <= 0)
1174         {
1175                 return false;
1176         }
1177
1178         if(!isMipmapFiltered())
1179         {
1180                 if(!isCubeComplete())
1181                 {
1182                         return false;
1183                 }
1184         }
1185         else
1186         {
1187                 if(!isMipmapCubeComplete())   // Also tests for isCubeComplete()
1188                 {
1189                         return false;
1190                 }
1191         }
1192
1193         return true;
1194 }
1195
1196 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1197 bool TextureCubeMap::isCubeComplete() const
1198 {
1199         if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1200         {
1201                 return false;
1202         }
1203
1204         for(unsigned int face = 1; face < 6; face++)
1205         {
1206                 if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
1207                    image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
1208                    image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
1209                    image[face][mBaseLevel]->getType()   != image[0][mBaseLevel]->getType())
1210                 {
1211                         return false;
1212                 }
1213         }
1214
1215         return true;
1216 }
1217
1218 bool TextureCubeMap::isMipmapCubeComplete() const
1219 {
1220         if(!isCubeComplete())
1221         {
1222                 return false;
1223         }
1224
1225         GLsizei size = image[0][mBaseLevel]->getWidth();
1226         int q = std::min(log2(size), mMaxLevel);
1227
1228         for(int face = 0; face < 6; face++)
1229         {
1230                 for(int level = mBaseLevel + 1; level <= q; level++)
1231                 {
1232                         if(!image[face][level])
1233                         {
1234                                 return false;
1235                         }
1236
1237                         if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1238                         {
1239                                 return false;
1240                         }
1241
1242                         if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
1243                         {
1244                                 return false;
1245                         }
1246
1247                         if(image[face][level]->getWidth() != std::max(1, size >> level))
1248                         {
1249                                 return false;
1250                         }
1251                 }
1252         }
1253
1254         return true;
1255 }
1256
1257 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1258 {
1259         return IsCompressed(getFormat(target, level), egl::getClientVersion());
1260 }
1261
1262 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1263 {
1264         return IsDepthTexture(getFormat(target, level));
1265 }
1266
1267 void TextureCubeMap::releaseTexImage()
1268 {
1269         UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
1270 }
1271
1272 void TextureCubeMap::setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1273 {
1274         int face = CubeFaceIndex(target);
1275
1276         if(image[face][level])
1277         {
1278                 image[face][level]->release();
1279         }
1280
1281         image[face][level] = egl::Image::create(this, width, height, format, type);
1282
1283         if(!image[face][level])
1284         {
1285                 return error(GL_OUT_OF_MEMORY);
1286         }
1287
1288         Texture::setImage(context, format, type, unpackInfo, pixels, image[face][level]);
1289 }
1290
1291 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1292 {
1293         egl::Image *renderTarget = source->getRenderTarget(0);
1294
1295         if(!renderTarget)
1296         {
1297                 ERR("Failed to retrieve the render target.");
1298                 return error(GL_OUT_OF_MEMORY);
1299         }
1300
1301         int face = CubeFaceIndex(target);
1302
1303         if(image[face][level])
1304         {
1305                 image[face][level]->release();
1306         }
1307
1308         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1309         image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1310
1311         if(!image[face][level])
1312         {
1313                 return error(GL_OUT_OF_MEMORY);
1314         }
1315
1316         if(width != 0 && height != 0)
1317         {
1318                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1319
1320                 if(!renderbuffer)
1321                 {
1322                         ERR("Failed to retrieve the source colorbuffer.");
1323                         return;
1324                 }
1325
1326                 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1327                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1328
1329                 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
1330         }
1331
1332         renderTarget->release();
1333 }
1334
1335 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1336 {
1337         return image[face][level];
1338 }
1339
1340 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1341 {
1342         return image[CubeFaceIndex(face)][level];
1343 }
1344
1345 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1346 {
1347         int face = CubeFaceIndex(target);
1348
1349         if(!image[face][level])
1350         {
1351                 return error(GL_INVALID_OPERATION);
1352         }
1353
1354         GLsizei size = image[face][level]->getWidth();
1355
1356         if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1357         {
1358                 return error(GL_INVALID_VALUE);
1359         }
1360
1361         egl::Image *renderTarget = source->getRenderTarget(0);
1362
1363         if(!renderTarget)
1364         {
1365                 ERR("Failed to retrieve the render target.");
1366                 return error(GL_OUT_OF_MEMORY);
1367         }
1368
1369         Renderbuffer* renderbuffer = source->getReadColorbuffer();
1370
1371         if(!renderbuffer)
1372         {
1373                 ERR("Failed to retrieve the source colorbuffer.");
1374                 return;
1375         }
1376
1377         sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1378         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1379
1380         copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
1381
1382         renderTarget->release();
1383 }
1384
1385 void TextureCubeMap::generateMipmaps()
1386 {
1387         if(!isCubeComplete())
1388         {
1389                 return error(GL_INVALID_OPERATION);
1390         }
1391
1392         unsigned int q = log2(image[0][0]->getWidth());
1393
1394         for(unsigned int f = 0; f < 6; f++)
1395         {
1396                 for(unsigned int i = 1; i <= q; i++)
1397                 {
1398                         if(image[f][i])
1399                         {
1400                                 image[f][i]->release();
1401                         }
1402
1403                         image[f][i] = egl::Image::create(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());
1404
1405                         if(!image[f][i])
1406                         {
1407                                 return error(GL_OUT_OF_MEMORY);
1408                         }
1409
1410                         getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
1411                 }
1412         }
1413 }
1414
1415 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
1416 {
1417         if(!IsCubemapTextureTarget(target))
1418         {
1419                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1420         }
1421
1422         int face = CubeFaceIndex(target);
1423
1424         if(!mFaceProxies[face])
1425         {
1426                 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1427         }
1428         else
1429         {
1430                 mFaceProxies[face]->setLevel(level);
1431         }
1432
1433         return mFaceProxies[face];
1434 }
1435
1436 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1437 {
1438         ASSERT(IsCubemapTextureTarget(target));
1439         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1440
1441         int face = CubeFaceIndex(target);
1442
1443         if(image[face][level])
1444         {
1445                 image[face][level]->addRef();
1446         }
1447
1448         return image[face][level];
1449 }
1450
1451 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1452 {
1453         ASSERT(IsCubemapTextureTarget(target));
1454         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1455
1456         int face = CubeFaceIndex(target);
1457
1458         if(!image[face][level])
1459         {
1460                 return false;
1461         }
1462
1463         return image[face][level]->isShared();
1464 }
1465
1466 Texture3D::Texture3D(GLuint name) : Texture(name)
1467 {
1468         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1469         {
1470                 image[i] = nullptr;
1471         }
1472
1473         mSurface = nullptr;
1474
1475         mColorbufferProxy = nullptr;
1476         mProxyRefs = 0;
1477 }
1478
1479 Texture3D::~Texture3D()
1480 {
1481         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1482         {
1483                 if(image[i])
1484                 {
1485                         image[i]->unbind(this);
1486                         image[i] = nullptr;
1487                 }
1488         }
1489
1490         if(mSurface)
1491         {
1492                 mSurface->setBoundTexture(nullptr);
1493                 mSurface = nullptr;
1494         }
1495
1496         mColorbufferProxy = nullptr;
1497 }
1498
1499 // We need to maintain a count of references to renderbuffers acting as
1500 // proxies for this texture, so that we do not attempt to use a pointer
1501 // to a renderbuffer proxy which has been deleted.
1502 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1503 {
1504         mProxyRefs++;
1505 }
1506
1507 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1508 {
1509         if(mProxyRefs > 0)
1510         {
1511                 mProxyRefs--;
1512         }
1513
1514         if(mProxyRefs == 0)
1515         {
1516                 mColorbufferProxy = nullptr;
1517         }
1518 }
1519
1520 void Texture3D::sweep()
1521 {
1522         int imageCount = 0;
1523
1524         for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1525         {
1526                 if(image[i] && image[i]->isChildOf(this))
1527                 {
1528                         if(!image[i]->hasSingleReference())
1529                         {
1530                                 return;
1531                         }
1532
1533                         imageCount++;
1534                 }
1535         }
1536
1537         if(imageCount == referenceCount)
1538         {
1539                 destroy();
1540         }
1541 }
1542
1543 GLenum Texture3D::getTarget() const
1544 {
1545         return GL_TEXTURE_3D_OES;
1546 }
1547
1548 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1549 {
1550         ASSERT(target == getTarget());
1551         return image[level] ? image[level]->getWidth() : 0;
1552 }
1553
1554 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1555 {
1556         ASSERT(target == getTarget());
1557         return image[level] ? image[level]->getHeight() : 0;
1558 }
1559
1560 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1561 {
1562         ASSERT(target == getTarget());
1563         return image[level] ? image[level]->getDepth() : 0;
1564 }
1565
1566 GLenum Texture3D::getFormat(GLenum target, GLint level) const
1567 {
1568         ASSERT(target == getTarget());
1569         return image[level] ? image[level]->getFormat() : GL_NONE;
1570 }
1571
1572 GLenum Texture3D::getType(GLenum target, GLint level) const
1573 {
1574         ASSERT(target == getTarget());
1575         return image[level] ? image[level]->getType() : GL_NONE;
1576 }
1577
1578 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
1579 {
1580         ASSERT(target == getTarget());
1581         return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
1582 }
1583
1584 int Texture3D::getLevelCount() const
1585 {
1586         ASSERT(isSamplerComplete());
1587         int levels = 0;
1588
1589         while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
1590         {
1591                 levels++;
1592         }
1593
1594         return levels;
1595 }
1596
1597 void Texture3D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1598 {
1599         if(image[level])
1600         {
1601                 image[level]->release();
1602         }
1603
1604         image[level] = egl::Image::create(this, width, height, depth, format, type);
1605
1606         if(!image[level])
1607         {
1608                 return error(GL_OUT_OF_MEMORY);
1609         }
1610
1611         Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
1612 }
1613
1614 void Texture3D::releaseTexImage()
1615 {
1616         UNREACHABLE(0);   // 3D textures cannot have an EGL surface bound as an image
1617 }
1618
1619 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1620 {
1621         if(image[level])
1622         {
1623                 image[level]->release();
1624         }
1625
1626         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1627         image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1628
1629         if(!image[level])
1630         {
1631                 return error(GL_OUT_OF_MEMORY);
1632         }
1633
1634         Texture::setCompressedImage(imageSize, pixels, image[level]);
1635 }
1636
1637 void Texture3D::subImage(egl::Context *context, 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)
1638 {
1639         Texture::subImage(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
1640 }
1641
1642 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1643 {
1644         Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1645 }
1646
1647 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
1648 {
1649         egl::Image *renderTarget = source->getRenderTarget(0);
1650
1651         if(!renderTarget)
1652         {
1653                 ERR("Failed to retrieve the render target.");
1654                 return error(GL_OUT_OF_MEMORY);
1655         }
1656
1657         if(image[level])
1658         {
1659                 image[level]->release();
1660         }
1661
1662         GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1663         image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1664
1665         if(!image[level])
1666         {
1667                 return error(GL_OUT_OF_MEMORY);
1668         }
1669
1670         if(width != 0 && height != 0 && depth != 0)
1671         {
1672                 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1673
1674                 if(!renderbuffer)
1675                 {
1676                         ERR("Failed to retrieve the source colorbuffer.");
1677                         return;
1678                 }
1679
1680                 sw::SliceRect sourceRect(x, y, x + width, y + height, z);
1681                 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1682                 for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
1683                 {
1684                         copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
1685                 }
1686         }
1687
1688         renderTarget->release();
1689 }
1690
1691 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1692 {
1693         if(!image[level])
1694         {
1695                 return error(GL_INVALID_OPERATION);
1696         }
1697
1698         if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1699         {
1700                 return error(GL_INVALID_VALUE);
1701         }
1702
1703         egl::Image *renderTarget = source->getRenderTarget(0);
1704
1705         if(!renderTarget)
1706         {
1707                 ERR("Failed to retrieve the render target.");
1708                 return error(GL_OUT_OF_MEMORY);
1709         }
1710
1711         Renderbuffer* renderbuffer = source->getReadColorbuffer();
1712
1713         if(!renderbuffer)
1714         {
1715                 ERR("Failed to retrieve the source colorbuffer.");
1716                 return;
1717         }
1718
1719         sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1720         sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1721
1722         copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
1723
1724         renderTarget->release();
1725 }
1726
1727 void Texture3D::setSharedImage(egl::Image *sharedImage)
1728 {
1729         sharedImage->addRef();
1730
1731         if(image[0])
1732         {
1733                 image[0]->release();
1734         }
1735
1736         image[0] = sharedImage;
1737 }
1738
1739 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1740 bool Texture3D::isSamplerComplete() const
1741 {
1742         if(!image[0])
1743         {
1744                 return false;
1745         }
1746
1747         GLsizei width = image[0]->getWidth();
1748         GLsizei height = image[0]->getHeight();
1749         GLsizei depth = image[0]->getDepth();
1750
1751         if(width <= 0 || height <= 0 || depth <= 0)
1752         {
1753                 return false;
1754         }
1755
1756         if(isMipmapFiltered())
1757         {
1758                 if(!isMipmapComplete())
1759                 {
1760                         return false;
1761                 }
1762         }
1763
1764         return true;
1765 }
1766
1767 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1768 bool Texture3D::isMipmapComplete() const
1769 {
1770         GLsizei width = image[mBaseLevel]->getWidth();
1771         GLsizei height = image[mBaseLevel]->getHeight();
1772         GLsizei depth = image[mBaseLevel]->getDepth();
1773         bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
1774
1775         int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
1776                 std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
1777
1778         for(int level = mBaseLevel + 1; level <= q; level++)
1779         {
1780                 if(!image[level])
1781                 {
1782                         return false;
1783                 }
1784
1785                 if(image[level]->getFormat() != image[0]->getFormat())
1786                 {
1787                         return false;
1788                 }
1789
1790                 if(image[level]->getType() != image[0]->getType())
1791                 {
1792                         return false;
1793                 }
1794
1795                 if(image[level]->getWidth() != std::max(1, width >> level))
1796                 {
1797                         return false;
1798                 }
1799
1800                 if(image[level]->getHeight() != std::max(1, height >> level))
1801                 {
1802                         return false;
1803                 }
1804
1805                 int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
1806                 if(image[level]->getDepth() != levelDepth)
1807                 {
1808                         return false;
1809                 }
1810         }
1811
1812         return true;
1813 }
1814
1815 bool Texture3D::isCompressed(GLenum target, GLint level) const
1816 {
1817         return IsCompressed(getFormat(target, level), egl::getClientVersion());
1818 }
1819
1820 bool Texture3D::isDepth(GLenum target, GLint level) const
1821 {
1822         return IsDepthTexture(getFormat(target, level));
1823 }
1824
1825 void Texture3D::generateMipmaps()
1826 {
1827         if(!image[0])
1828         {
1829                 return;   // FIXME: error?
1830         }
1831
1832         unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
1833
1834         for(unsigned int i = 1; i <= q; i++)
1835         {
1836                 if(image[i])
1837                 {
1838                         image[i]->release();
1839                 }
1840
1841                 image[i] = egl::Image::create(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());
1842
1843                 if(!image[i])
1844                 {
1845                         return error(GL_OUT_OF_MEMORY);
1846                 }
1847
1848                 getDevice()->stretchCube(image[i - 1], image[i]);
1849         }
1850 }
1851
1852 egl::Image *Texture3D::getImage(unsigned int level)
1853 {
1854         return image[level];
1855 }
1856
1857 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
1858 {
1859         if(target != getTarget())
1860         {
1861                 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1862         }
1863
1864         if(!mColorbufferProxy)
1865         {
1866                 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
1867         }
1868         else
1869         {
1870                 mColorbufferProxy->setLevel(level);
1871                 mColorbufferProxy->setLayer(layer);
1872         }
1873
1874         return mColorbufferProxy;
1875 }
1876
1877 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1878 {
1879         ASSERT(target == getTarget());
1880         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1881
1882         if(image[level])
1883         {
1884                 image[level]->addRef();
1885         }
1886
1887         return image[level];
1888 }
1889
1890 bool Texture3D::isShared(GLenum target, unsigned int level) const
1891 {
1892         ASSERT(target == getTarget());
1893         ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1894
1895         if(mSurface)   // Bound to an EGLSurface
1896         {
1897                 return true;
1898         }
1899
1900         if(!image[level])
1901         {
1902                 return false;
1903         }
1904
1905         return image[level]->isShared();
1906 }
1907
1908 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1909 {
1910 }
1911
1912 Texture2DArray::~Texture2DArray()
1913 {
1914 }
1915
1916 GLenum Texture2DArray::getTarget() const
1917 {
1918         return GL_TEXTURE_2D_ARRAY;
1919 }
1920
1921 void Texture2DArray::generateMipmaps()
1922 {
1923         int depth = image[0] ? image[0]->getDepth() : 0;
1924         if(!depth)
1925         {
1926                 return;   // FIXME: error?
1927         }
1928
1929         unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
1930
1931         for(unsigned int i = 1; i <= q; i++)
1932         {
1933                 if(image[i])
1934                 {
1935                         image[i]->release();
1936                 }
1937
1938                 GLsizei w = std::max(image[0]->getWidth() >> i, 1);
1939                 GLsizei h = std::max(image[0]->getHeight() >> i, 1);
1940                 image[i] = egl::Image::create(this, w, h, depth, image[0]->getFormat(), image[0]->getType());
1941
1942                 if(!image[i])
1943                 {
1944                         return error(GL_OUT_OF_MEMORY);
1945                 }
1946
1947                 GLsizei srcw = image[i - 1]->getWidth();
1948                 GLsizei srch = image[i - 1]->getHeight();
1949                 for(int z = 0; z < depth; ++z)
1950                 {
1951                         sw::SliceRect srcRect(0, 0, srcw, srch, z);
1952                         sw::SliceRect dstRect(0, 0, w, h, z);
1953                         getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
1954                 }
1955         }
1956 }
1957
1958 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
1959 {
1960         mMinFilter = GL_LINEAR;
1961         mMagFilter = GL_LINEAR;
1962         mWrapS = GL_CLAMP_TO_EDGE;
1963         mWrapT = GL_CLAMP_TO_EDGE;
1964         mWrapR = GL_CLAMP_TO_EDGE;
1965 }
1966
1967 TextureExternal::~TextureExternal()
1968 {
1969 }
1970
1971 GLenum TextureExternal::getTarget() const
1972 {
1973         return GL_TEXTURE_EXTERNAL_OES;
1974 }
1975
1976 }
1977
1978 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
1979 {
1980         if(config)
1981         {
1982                 return egl::Image::create(width, height, config->mRenderTargetFormat, config->mSamples, false);
1983         }
1984
1985         return nullptr;
1986 }
1987
1988 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
1989 {
1990         if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION)
1991         {
1992                 ERR("Invalid parameters: %dx%d", width, height);
1993                 return nullptr;
1994         }
1995
1996         bool lockable = true;
1997
1998         switch(format)
1999         {
2000 //      case sw::FORMAT_D15S1:
2001         case sw::FORMAT_D24S8:
2002         case sw::FORMAT_D24X8:
2003 //      case sw::FORMAT_D24X4S4:
2004         case sw::FORMAT_D24FS8:
2005         case sw::FORMAT_D32:
2006         case sw::FORMAT_D16:
2007                 lockable = false;
2008                 break;
2009 //      case sw::FORMAT_S8_LOCKABLE:
2010 //      case sw::FORMAT_D16_LOCKABLE:
2011         case sw::FORMAT_D32F_LOCKABLE:
2012 //      case sw::FORMAT_D32_LOCKABLE:
2013         case sw::FORMAT_DF24S8:
2014         case sw::FORMAT_DF16S8:
2015                 lockable = true;
2016                 break;
2017         default:
2018                 UNREACHABLE(format);
2019         }
2020
2021         egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
2022
2023         if(!surface)
2024         {
2025                 ERR("Out of memory");
2026                 return nullptr;
2027         }
2028
2029         return surface;
2030 }