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