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