1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
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.
23 #include "Framebuffer.h"
25 #include "libEGL/Display.h"
26 #include "libEGL/Surface.h"
27 #include "common/debug.h"
34 Texture::Texture(GLuint name) : egl::Texture(name)
36 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
37 mMagFilter = GL_LINEAR;
41 mMaxAnisotropy = 1.0f;
43 mCompareFunc = GL_LEQUAL;
44 mCompareMode = GL_NONE;
45 mImmutableFormat = GL_FALSE;
55 resource = new sw::Resource(0);
63 sw::Resource *Texture::getResource() const
68 // Returns true on successful filter state update (valid enum parameter)
69 bool Texture::setMinFilter(GLenum filter)
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)
91 // Returns true on successful filter state update (valid enum parameter)
92 bool Texture::setMagFilter(GLenum filter)
105 // Returns true on successful wrap state update (valid enum parameter)
106 bool Texture::setWrapS(GLenum wrap)
111 case GL_MIRRORED_REPEAT:
112 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
117 case GL_CLAMP_TO_EDGE:
125 // Returns true on successful wrap state update (valid enum parameter)
126 bool Texture::setWrapT(GLenum wrap)
131 case GL_MIRRORED_REPEAT:
132 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
137 case GL_CLAMP_TO_EDGE:
145 // Returns true on successful wrap state update (valid enum parameter)
146 bool Texture::setWrapR(GLenum wrap)
151 case GL_MIRRORED_REPEAT:
152 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
157 case GL_CLAMP_TO_EDGE:
165 // Returns true on successful max anisotropy update (valid anisotropy value)
166 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
168 textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
170 if(textureMaxAnisotropy < 1.0f)
175 if(mMaxAnisotropy != textureMaxAnisotropy)
177 mMaxAnisotropy = textureMaxAnisotropy;
183 bool Texture::setBaseLevel(GLint baseLevel)
185 mBaseLevel = baseLevel;
189 bool Texture::setCompareFunc(GLenum compareFunc)
201 mCompareFunc = compareFunc;
208 bool Texture::setCompareMode(GLenum compareMode)
212 case GL_COMPARE_REF_TO_TEXTURE:
214 mCompareMode = compareMode;
221 void Texture::makeImmutable(GLsizei levels)
223 mImmutableFormat = GL_TRUE;
224 mImmutableLevels = levels;
227 bool Texture::setMaxLevel(GLint maxLevel)
229 mMaxLevel = maxLevel;
233 bool Texture::setMaxLOD(GLfloat maxLOD)
239 bool Texture::setMinLOD(GLfloat minLOD)
245 bool Texture::setSwizzleR(GLenum swizzleR)
255 mSwizzleR = swizzleR;
262 bool Texture::setSwizzleG(GLenum swizzleG)
272 mSwizzleG = swizzleG;
279 bool Texture::setSwizzleB(GLenum swizzleB)
289 mSwizzleB = swizzleB;
296 bool Texture::setSwizzleA(GLenum swizzleA)
306 mSwizzleA = swizzleA;
313 GLenum Texture::getMinFilter() const
318 GLenum Texture::getMagFilter() const
323 GLenum Texture::getWrapS() const
328 GLenum Texture::getWrapT() const
333 GLenum Texture::getWrapR() const
338 GLfloat Texture::getMaxAnisotropy() const
340 return mMaxAnisotropy;
343 GLint Texture::getBaseLevel() const
347 GLenum Texture::getCompareFunc() const
351 GLenum Texture::getCompareMode() const
355 GLboolean Texture::getImmutableFormat() const
357 return mImmutableFormat;
359 GLsizei Texture::getImmutableLevels() const
361 return mImmutableLevels;
363 GLint Texture::getMaxLevel() const
367 GLfloat Texture::getMaxLOD() const
371 GLfloat Texture::getMinLOD() const
375 GLenum Texture::getSwizzleR() const
379 GLenum Texture::getSwizzleG() const
383 GLenum Texture::getSwizzleB() const
387 GLenum Texture::getSwizzleA() const
392 GLsizei Texture::getDepth(GLenum target, GLint level) const
397 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
399 egl::Image *image = getRenderTarget(target, level); // Increments reference count
409 void Texture::setImage(GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
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);
418 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
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);
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)
431 return error(GL_INVALID_OPERATION);
434 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
436 return error(GL_INVALID_VALUE);
439 if(IsCompressed(image->getFormat(), egl::getClientVersion()))
441 return error(GL_INVALID_OPERATION);
444 if(format != image->getFormat())
446 return error(GL_INVALID_OPERATION);
451 image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels);
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)
459 return error(GL_INVALID_OPERATION);
462 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
464 return error(GL_INVALID_VALUE);
467 if(format != image->getFormat())
469 return error(GL_INVALID_OPERATION);
474 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
478 bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
480 Device *device = getDevice();
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);
487 return error(GL_OUT_OF_MEMORY, false);
493 bool Texture::isMipmapFiltered() const
500 case GL_NEAREST_MIPMAP_NEAREST:
501 case GL_LINEAR_MIPMAP_NEAREST:
502 case GL_NEAREST_MIPMAP_LINEAR:
503 case GL_LINEAR_MIPMAP_LINEAR:
505 default: UNREACHABLE(mMinFilter);
511 Texture2D::Texture2D(GLuint name) : Texture(name)
513 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
520 mColorbufferProxy = nullptr;
524 Texture2D::~Texture2D()
526 resource->lock(sw::DESTRUCT);
528 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
532 image[i]->unbind(this);
541 mSurface->setBoundTexture(nullptr);
545 mColorbufferProxy = nullptr;
548 // We need to maintain a count of references to renderbuffers acting as
549 // proxies for this texture, so that we do not attempt to use a pointer
550 // to a renderbuffer proxy which has been deleted.
551 void Texture2D::addProxyRef(const Renderbuffer *proxy)
556 void Texture2D::releaseProxy(const Renderbuffer *proxy)
565 mColorbufferProxy = nullptr;
569 void Texture2D::sweep()
573 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
575 if(image[i] && image[i]->isChildOf(this))
577 if(!image[i]->hasSingleReference())
586 if(imageCount == referenceCount)
592 GLenum Texture2D::getTarget() const
594 return GL_TEXTURE_2D;
597 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
599 ASSERT(target == GL_TEXTURE_2D);
600 return image[level] ? image[level]->getWidth() : 0;
603 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
605 ASSERT(target == GL_TEXTURE_2D);
606 return image[level] ? image[level]->getHeight() : 0;
609 GLenum Texture2D::getFormat(GLenum target, GLint level) const
611 ASSERT(target == GL_TEXTURE_2D);
612 return image[level] ? image[level]->getFormat() : GL_NONE;
615 GLenum Texture2D::getType(GLenum target, GLint level) const
617 ASSERT(target == GL_TEXTURE_2D);
618 return image[level] ? image[level]->getType() : GL_NONE;
621 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
623 ASSERT(target == GL_TEXTURE_2D);
624 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
627 int Texture2D::getLevelCount() const
629 ASSERT(isSamplerComplete());
632 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
640 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
644 image[level]->release();
647 image[level] = new egl::Image(this, width, height, format, type);
651 return error(GL_OUT_OF_MEMORY);
654 Texture::setImage(format, type, unpackInfo, pixels, image[level]);
657 void Texture2D::bindTexImage(egl::Surface *surface)
661 switch(surface->getInternalFormat())
663 case sw::FORMAT_A8R8G8B8:
664 case sw::FORMAT_SRGB8_A8:
665 format = GL_BGRA_EXT;
667 case sw::FORMAT_A8B8G8R8:
670 case sw::FORMAT_X8B8G8R8:
671 case sw::FORMAT_X8R8G8B8:
672 case sw::FORMAT_SRGB8_X8:
680 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
684 image[level]->release();
685 image[level] = nullptr;
689 image[0] = surface->getRenderTarget();
692 mSurface->setBoundTexture(this);
695 void Texture2D::releaseTexImage()
697 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
701 image[level]->release();
702 image[level] = nullptr;
707 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
711 image[level]->release();
714 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
715 image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
719 return error(GL_OUT_OF_MEMORY);
722 Texture::setCompressedImage(imageSize, pixels, image[level]);
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)
727 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
730 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
732 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
735 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
737 egl::Image *renderTarget = source->getRenderTarget(0);
741 ERR("Failed to retrieve the render target.");
742 return error(GL_OUT_OF_MEMORY);
747 image[level]->release();
750 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
751 image[level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
755 return error(GL_OUT_OF_MEMORY);
758 if(width != 0 && height != 0)
760 Renderbuffer* renderbuffer = source->getReadColorbuffer();
764 ERR("Failed to retrieve the source colorbuffer.");
768 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
769 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
771 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
774 renderTarget->release();
777 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
781 return error(GL_INVALID_OPERATION);
784 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
786 return error(GL_INVALID_VALUE);
789 egl::Image *renderTarget = source->getRenderTarget(0);
793 ERR("Failed to retrieve the render target.");
794 return error(GL_OUT_OF_MEMORY);
797 Renderbuffer* renderbuffer = source->getReadColorbuffer();
801 ERR("Failed to retrieve the source colorbuffer.");
805 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
806 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
808 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
810 renderTarget->release();
813 void Texture2D::setImage(egl::Image *sharedImage)
815 if(sharedImage == image[0])
820 sharedImage->addRef();
827 image[0] = sharedImage;
830 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
831 bool Texture2D::isSamplerComplete() const
838 GLsizei width = image[0]->getWidth();
839 GLsizei height = image[0]->getHeight();
841 if(width <= 0 || height <= 0)
846 if(isMipmapFiltered())
848 if(!isMipmapComplete())
857 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
858 bool Texture2D::isMipmapComplete() const
860 GLsizei width = image[mBaseLevel]->getWidth();
861 GLsizei height = image[mBaseLevel]->getHeight();
863 int q = std::min(log2(std::max(width, height)), mMaxLevel);
865 for(int level = mBaseLevel + 1; level <= q; level++)
872 if(image[level]->getFormat() != image[0]->getFormat())
877 if(image[level]->getType() != image[0]->getType())
882 if(image[level]->getWidth() != std::max(1, width >> level))
887 if(image[level]->getHeight() != std::max(1, height >> level))
896 bool Texture2D::isCompressed(GLenum target, GLint level) const
898 return IsCompressed(getFormat(target, level), egl::getClientVersion());
901 bool Texture2D::isDepth(GLenum target, GLint level) const
903 return IsDepthTexture(getFormat(target, level));
906 void Texture2D::generateMipmaps()
910 return; // FIXME: error?
913 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
915 for(unsigned int i = 1; i <= q; i++)
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());
926 return error(GL_OUT_OF_MEMORY);
929 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
933 egl::Image *Texture2D::getImage(unsigned int level)
938 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
940 if(target != GL_TEXTURE_2D)
942 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
945 if(!mColorbufferProxy)
947 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
951 mColorbufferProxy->setLevel(level);
954 return mColorbufferProxy;
957 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
959 ASSERT(target == GL_TEXTURE_2D);
960 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
964 image[level]->addRef();
970 bool Texture2D::isShared(GLenum target, unsigned int level) const
972 ASSERT(target == GL_TEXTURE_2D);
973 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
975 if(mSurface) // Bound to an EGLSurface
985 return image[level]->isShared();
988 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
990 for(int f = 0; f < 6; f++)
992 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
994 image[f][i] = nullptr;
998 for(int f = 0; f < 6; f++)
1000 mFaceProxies[f] = nullptr;
1001 mFaceProxyRefs[f] = 0;
1005 TextureCubeMap::~TextureCubeMap()
1007 resource->lock(sw::DESTRUCT);
1009 for(int f = 0; f < 6; f++)
1011 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1015 image[f][i]->unbind(this);
1016 image[f][i] = nullptr;
1023 for(int i = 0; i < 6; i++)
1025 mFaceProxies[i] = nullptr;
1029 // We need to maintain a count of references to renderbuffers acting as
1030 // proxies for this texture, so that the texture is not deleted while
1031 // proxy references still exist. If the reference count drops to zero,
1032 // we set our proxy pointer null, so that a new attempt at referencing
1033 // will cause recreation.
1034 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1036 for(int f = 0; f < 6; f++)
1038 if(mFaceProxies[f] == proxy)
1040 mFaceProxyRefs[f]++;
1045 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1047 for(int f = 0; f < 6; f++)
1049 if(mFaceProxies[f] == proxy)
1051 if(mFaceProxyRefs[f] > 0)
1053 mFaceProxyRefs[f]--;
1056 if(mFaceProxyRefs[f] == 0)
1058 mFaceProxies[f] = nullptr;
1064 void TextureCubeMap::sweep()
1068 for(int f = 0; f < 6; f++)
1070 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1072 if(image[f][i] && image[f][i]->isChildOf(this))
1074 if(!image[f][i]->hasSingleReference())
1084 if(imageCount == referenceCount)
1090 GLenum TextureCubeMap::getTarget() const
1092 return GL_TEXTURE_CUBE_MAP;
1095 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1097 int face = CubeFaceIndex(target);
1098 return image[face][level] ? image[face][level]->getWidth() : 0;
1101 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1103 int face = CubeFaceIndex(target);
1104 return image[face][level] ? image[face][level]->getHeight() : 0;
1107 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
1109 int face = CubeFaceIndex(target);
1110 return image[face][level] ? image[face][level]->getFormat() : 0;
1113 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
1115 int face = CubeFaceIndex(target);
1116 return image[face][level] ? image[face][level]->getType() : 0;
1119 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1121 int face = CubeFaceIndex(target);
1122 return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
1125 int TextureCubeMap::getLevelCount() const
1127 ASSERT(isSamplerComplete());
1130 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
1138 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1140 int face = CubeFaceIndex(target);
1142 if(image[face][level])
1144 image[face][level]->release();
1147 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1148 image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1150 if(!image[face][level])
1152 return error(GL_OUT_OF_MEMORY);
1155 Texture::setCompressedImage(imageSize, pixels, image[face][level]);
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)
1160 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
1163 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1165 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1168 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1169 bool TextureCubeMap::isSamplerComplete() const
1171 for(int face = 0; face < 6; face++)
1179 int size = image[0][0]->getWidth();
1186 if(!isMipmapFiltered())
1188 if(!isCubeComplete())
1195 if(!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1204 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1205 bool TextureCubeMap::isCubeComplete() const
1207 if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1212 for(unsigned int face = 1; face < 6; face++)
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())
1226 bool TextureCubeMap::isMipmapCubeComplete() const
1228 if(!isCubeComplete())
1233 GLsizei size = image[0][mBaseLevel]->getWidth();
1234 int q = std::min(log2(size), mMaxLevel);
1236 for(int face = 0; face < 6; face++)
1238 for(int level = mBaseLevel + 1; level <= q; level++)
1240 if(!image[face][level])
1245 if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1250 if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
1255 if(image[face][level]->getWidth() != std::max(1, size >> level))
1265 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1267 return IsCompressed(getFormat(target, level), egl::getClientVersion());
1270 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1272 return IsDepthTexture(getFormat(target, level));
1275 void TextureCubeMap::releaseTexImage()
1277 UNREACHABLE(0); // Cube maps cannot have an EGL surface bound as an image
1280 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1282 int face = CubeFaceIndex(target);
1284 if(image[face][level])
1286 image[face][level]->release();
1289 image[face][level] = new egl::Image(this, width, height, format, type);
1291 if(!image[face][level])
1293 return error(GL_OUT_OF_MEMORY);
1296 Texture::setImage(format, type, unpackInfo, pixels, image[face][level]);
1299 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1301 egl::Image *renderTarget = source->getRenderTarget(0);
1305 ERR("Failed to retrieve the render target.");
1306 return error(GL_OUT_OF_MEMORY);
1309 int face = CubeFaceIndex(target);
1311 if(image[face][level])
1313 image[face][level]->release();
1316 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1317 image[face][level] = new egl::Image(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1319 if(!image[face][level])
1321 return error(GL_OUT_OF_MEMORY);
1324 if(width != 0 && height != 0)
1326 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1330 ERR("Failed to retrieve the source colorbuffer.");
1334 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1335 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1337 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
1340 renderTarget->release();
1343 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1345 return image[face][level];
1348 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1350 return image[CubeFaceIndex(face)][level];
1353 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1355 int face = CubeFaceIndex(target);
1357 if(!image[face][level])
1359 return error(GL_INVALID_OPERATION);
1362 GLsizei size = image[face][level]->getWidth();
1364 if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1366 return error(GL_INVALID_VALUE);
1369 egl::Image *renderTarget = source->getRenderTarget(0);
1373 ERR("Failed to retrieve the render target.");
1374 return error(GL_OUT_OF_MEMORY);
1377 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1381 ERR("Failed to retrieve the source colorbuffer.");
1385 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1386 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1388 copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
1390 renderTarget->release();
1393 void TextureCubeMap::generateMipmaps()
1395 if(!isCubeComplete())
1397 return error(GL_INVALID_OPERATION);
1400 unsigned int q = log2(image[0][0]->getWidth());
1402 for(unsigned int f = 0; f < 6; f++)
1404 for(unsigned int i = 1; i <= q; i++)
1408 image[f][i]->release();
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());
1415 return error(GL_OUT_OF_MEMORY);
1418 getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
1423 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
1425 if(!IsCubemapTextureTarget(target))
1427 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1430 int face = CubeFaceIndex(target);
1432 if(!mFaceProxies[face])
1434 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1438 mFaceProxies[face]->setLevel(level);
1441 return mFaceProxies[face];
1444 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1446 ASSERT(IsCubemapTextureTarget(target));
1447 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1449 int face = CubeFaceIndex(target);
1451 if(image[face][level])
1453 image[face][level]->addRef();
1456 return image[face][level];
1459 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1461 ASSERT(IsCubemapTextureTarget(target));
1462 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1464 int face = CubeFaceIndex(target);
1466 if(!image[face][level])
1471 return image[face][level]->isShared();
1474 Texture3D::Texture3D(GLuint name) : Texture(name)
1476 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1483 mColorbufferProxy = nullptr;
1487 Texture3D::~Texture3D()
1489 resource->lock(sw::DESTRUCT);
1491 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1495 image[i]->unbind(this);
1504 mSurface->setBoundTexture(nullptr);
1508 mColorbufferProxy = nullptr;
1511 // We need to maintain a count of references to renderbuffers acting as
1512 // proxies for this texture, so that we do not attempt to use a pointer
1513 // to a renderbuffer proxy which has been deleted.
1514 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1519 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1528 mColorbufferProxy = nullptr;
1532 void Texture3D::sweep()
1536 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1538 if(image[i] && image[i]->isChildOf(this))
1540 if(!image[i]->hasSingleReference())
1549 if(imageCount == referenceCount)
1555 GLenum Texture3D::getTarget() const
1557 return GL_TEXTURE_3D_OES;
1560 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1562 ASSERT(target == getTarget());
1563 return image[level] ? image[level]->getWidth() : 0;
1566 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1568 ASSERT(target == getTarget());
1569 return image[level] ? image[level]->getHeight() : 0;
1572 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1574 ASSERT(target == getTarget());
1575 return image[level] ? image[level]->getDepth() : 0;
1578 GLenum Texture3D::getFormat(GLenum target, GLint level) const
1580 ASSERT(target == getTarget());
1581 return image[level] ? image[level]->getFormat() : GL_NONE;
1584 GLenum Texture3D::getType(GLenum target, GLint level) const
1586 ASSERT(target == getTarget());
1587 return image[level] ? image[level]->getType() : GL_NONE;
1590 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
1592 ASSERT(target == getTarget());
1593 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
1596 int Texture3D::getLevelCount() const
1598 ASSERT(isSamplerComplete());
1601 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
1609 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1613 image[level]->release();
1616 image[level] = new egl::Image(this, width, height, depth, format, type);
1620 return error(GL_OUT_OF_MEMORY);
1623 Texture::setImage(format, type, unpackInfo, pixels, image[level]);
1626 void Texture3D::bindTexImage(egl::Surface *surface)
1630 switch(surface->getInternalFormat())
1632 case sw::FORMAT_A8R8G8B8:
1635 case sw::FORMAT_X8R8G8B8:
1643 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1647 image[level]->release();
1648 image[level] = nullptr;
1652 image[0] = surface->getRenderTarget();
1655 mSurface->setBoundTexture(this);
1658 void Texture3D::releaseTexImage()
1660 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1664 image[level]->release();
1665 image[level] = nullptr;
1670 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1674 image[level]->release();
1677 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1678 image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1682 return error(GL_OUT_OF_MEMORY);
1685 Texture::setCompressedImage(imageSize, pixels, image[level]);
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)
1690 Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
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)
1695 Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1698 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
1700 egl::Image *renderTarget = source->getRenderTarget(0);
1704 ERR("Failed to retrieve the render target.");
1705 return error(GL_OUT_OF_MEMORY);
1710 image[level]->release();
1713 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1714 image[level] = new egl::Image(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1718 return error(GL_OUT_OF_MEMORY);
1721 if(width != 0 && height != 0 && depth != 0)
1723 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1727 ERR("Failed to retrieve the source colorbuffer.");
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)
1735 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
1739 renderTarget->release();
1742 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1746 return error(GL_INVALID_OPERATION);
1749 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1751 return error(GL_INVALID_VALUE);
1754 egl::Image *renderTarget = source->getRenderTarget(0);
1758 ERR("Failed to retrieve the render target.");
1759 return error(GL_OUT_OF_MEMORY);
1762 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1766 ERR("Failed to retrieve the source colorbuffer.");
1770 sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1771 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1773 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
1775 renderTarget->release();
1778 void Texture3D::setImage(egl::Image *sharedImage)
1780 sharedImage->addRef();
1784 image[0]->release();
1787 image[0] = sharedImage;
1790 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1791 bool Texture3D::isSamplerComplete() const
1798 GLsizei width = image[0]->getWidth();
1799 GLsizei height = image[0]->getHeight();
1800 GLsizei depth = image[0]->getDepth();
1802 if(width <= 0 || height <= 0 || depth <= 0)
1807 if(isMipmapFiltered())
1809 if(!isMipmapComplete())
1818 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1819 bool Texture3D::isMipmapComplete() const
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;
1826 int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
1827 std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
1829 for(int level = mBaseLevel + 1; level <= q; level++)
1836 if(image[level]->getFormat() != image[0]->getFormat())
1841 if(image[level]->getType() != image[0]->getType())
1846 if(image[level]->getWidth() != std::max(1, width >> level))
1851 if(image[level]->getHeight() != std::max(1, height >> level))
1856 int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
1857 if(image[level]->getDepth() != levelDepth)
1866 bool Texture3D::isCompressed(GLenum target, GLint level) const
1868 return IsCompressed(getFormat(target, level), egl::getClientVersion());
1871 bool Texture3D::isDepth(GLenum target, GLint level) const
1873 return IsDepthTexture(getFormat(target, level));
1876 void Texture3D::generateMipmaps()
1880 return; // FIXME: error?
1883 unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
1885 for(unsigned int i = 1; i <= q; i++)
1889 image[i]->release();
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());
1896 return error(GL_OUT_OF_MEMORY);
1899 getDevice()->stretchCube(image[i - 1], image[i]);
1903 egl::Image *Texture3D::getImage(unsigned int level)
1905 return image[level];
1908 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
1910 if(target != getTarget())
1912 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1915 if(!mColorbufferProxy)
1917 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
1921 mColorbufferProxy->setLevel(level);
1922 mColorbufferProxy->setLayer(layer);
1925 return mColorbufferProxy;
1928 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1930 ASSERT(target == getTarget());
1931 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1935 image[level]->addRef();
1938 return image[level];
1941 bool Texture3D::isShared(GLenum target, unsigned int level) const
1943 ASSERT(target == getTarget());
1944 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1946 if(mSurface) // Bound to an EGLSurface
1956 return image[level]->isShared();
1959 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1963 Texture2DArray::~Texture2DArray()
1967 GLenum Texture2DArray::getTarget() const
1969 return GL_TEXTURE_2D_ARRAY;
1972 void Texture2DArray::generateMipmaps()
1974 int depth = image[0] ? image[0]->getDepth() : 0;
1977 return; // FIXME: error?
1980 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
1982 for(unsigned int i = 1; i <= q; i++)
1986 image[i]->release();
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());
1995 return error(GL_OUT_OF_MEMORY);
1998 GLsizei srcw = image[i - 1]->getWidth();
1999 GLsizei srch = image[i - 1]->getHeight();
2000 for(int z = 0; z < depth; ++z)
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);
2009 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
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;
2018 TextureExternal::~TextureExternal()
2022 GLenum TextureExternal::getTarget() const
2024 return GL_TEXTURE_EXTERNAL_OES;
2029 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
2033 return new egl::Image(width, height, config->mRenderTargetFormat, config->mSamples, false);
2039 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
2041 if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION)
2043 ERR("Invalid parameters: %dx%d", width, height);
2047 bool lockable = true;
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:
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:
2069 UNREACHABLE(format);
2072 egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
2076 ERR("Out of memory");