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