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 "common/Surface.hpp"
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(egl::Context *context, 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(context, 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(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)
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(context, 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, Device::ALL_BUFFERS);
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 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
530 image[i]->unbind(this);
537 mSurface->setBoundTexture(nullptr);
541 mColorbufferProxy = nullptr;
544 // We need to maintain a count of references to renderbuffers acting as
545 // proxies for this texture, so that we do not attempt to use a pointer
546 // to a renderbuffer proxy which has been deleted.
547 void Texture2D::addProxyRef(const Renderbuffer *proxy)
552 void Texture2D::releaseProxy(const Renderbuffer *proxy)
561 mColorbufferProxy = nullptr;
565 void Texture2D::sweep()
569 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
571 if(image[i] && image[i]->isChildOf(this))
573 if(!image[i]->hasSingleReference())
582 if(imageCount == referenceCount)
588 GLenum Texture2D::getTarget() const
590 return GL_TEXTURE_2D;
593 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
595 ASSERT(target == GL_TEXTURE_2D);
596 return image[level] ? image[level]->getWidth() : 0;
599 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
601 ASSERT(target == GL_TEXTURE_2D);
602 return image[level] ? image[level]->getHeight() : 0;
605 GLenum Texture2D::getFormat(GLenum target, GLint level) const
607 ASSERT(target == GL_TEXTURE_2D);
608 return image[level] ? image[level]->getFormat() : GL_NONE;
611 GLenum Texture2D::getType(GLenum target, GLint level) const
613 ASSERT(target == GL_TEXTURE_2D);
614 return image[level] ? image[level]->getType() : GL_NONE;
617 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
619 ASSERT(target == GL_TEXTURE_2D);
620 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
623 int Texture2D::getLevelCount() const
625 ASSERT(isSamplerComplete());
628 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
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)
640 image[level]->release();
643 image[level] = egl::Image::create(this, width, height, format, type);
647 return error(GL_OUT_OF_MEMORY);
650 Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
653 void Texture2D::bindTexImage(gl::Surface *surface)
657 switch(surface->getInternalFormat())
659 case sw::FORMAT_A8R8G8B8:
660 case sw::FORMAT_SRGB8_A8:
661 format = GL_BGRA_EXT;
663 case sw::FORMAT_A8B8G8R8:
666 case sw::FORMAT_X8B8G8R8:
667 case sw::FORMAT_X8R8G8B8:
668 case sw::FORMAT_SRGB8_X8:
676 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
680 image[level]->release();
681 image[level] = nullptr;
685 image[0] = surface->getRenderTarget();
688 mSurface->setBoundTexture(this);
691 void Texture2D::releaseTexImage()
693 for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
697 image[level]->release();
698 image[level] = nullptr;
703 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
707 image[level]->release();
710 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
711 image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
715 return error(GL_OUT_OF_MEMORY);
718 Texture::setCompressedImage(imageSize, pixels, image[level]);
721 void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
723 Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
726 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
728 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
731 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
733 egl::Image *renderTarget = source->getRenderTarget(0);
737 ERR("Failed to retrieve the render target.");
738 return error(GL_OUT_OF_MEMORY);
743 image[level]->release();
746 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
747 image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
751 return error(GL_OUT_OF_MEMORY);
754 if(width != 0 && height != 0)
756 Renderbuffer* renderbuffer = source->getReadColorbuffer();
760 ERR("Failed to retrieve the source colorbuffer.");
764 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
765 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
767 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
770 renderTarget->release();
773 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
777 return error(GL_INVALID_OPERATION);
780 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
782 return error(GL_INVALID_VALUE);
785 egl::Image *renderTarget = source->getRenderTarget(0);
789 ERR("Failed to retrieve the render target.");
790 return error(GL_OUT_OF_MEMORY);
793 Renderbuffer* renderbuffer = source->getReadColorbuffer();
797 ERR("Failed to retrieve the source colorbuffer.");
801 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
802 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
804 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
806 renderTarget->release();
809 void Texture2D::setSharedImage(egl::Image *sharedImage)
811 if(sharedImage == image[0])
816 sharedImage->addRef();
823 image[0] = sharedImage;
826 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
827 bool Texture2D::isSamplerComplete() const
834 GLsizei width = image[0]->getWidth();
835 GLsizei height = image[0]->getHeight();
837 if(width <= 0 || height <= 0)
842 if(isMipmapFiltered())
844 if(!isMipmapComplete())
853 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
854 bool Texture2D::isMipmapComplete() const
856 GLsizei width = image[mBaseLevel]->getWidth();
857 GLsizei height = image[mBaseLevel]->getHeight();
859 int q = std::min(log2(std::max(width, height)), mMaxLevel);
861 for(int level = mBaseLevel + 1; level <= q; level++)
868 if(image[level]->getFormat() != image[0]->getFormat())
873 if(image[level]->getType() != image[0]->getType())
878 if(image[level]->getWidth() != std::max(1, width >> level))
883 if(image[level]->getHeight() != std::max(1, height >> level))
892 bool Texture2D::isCompressed(GLenum target, GLint level) const
894 return IsCompressed(getFormat(target, level), egl::getClientVersion());
897 bool Texture2D::isDepth(GLenum target, GLint level) const
899 return IsDepthTexture(getFormat(target, level));
902 void Texture2D::generateMipmaps()
906 return; // FIXME: error?
909 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
911 for(unsigned int i = 1; i <= q; i++)
918 image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
922 return error(GL_OUT_OF_MEMORY);
925 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
929 egl::Image *Texture2D::getImage(unsigned int level)
934 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
936 if(target != GL_TEXTURE_2D)
938 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
941 if(!mColorbufferProxy)
943 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
947 mColorbufferProxy->setLevel(level);
950 return mColorbufferProxy;
953 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
955 ASSERT(target == GL_TEXTURE_2D);
956 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
960 image[level]->addRef();
966 bool Texture2D::isShared(GLenum target, unsigned int level) const
968 ASSERT(target == GL_TEXTURE_2D);
969 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
971 if(mSurface) // Bound to an EGLSurface
981 return image[level]->isShared();
984 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
986 for(int f = 0; f < 6; f++)
988 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
990 image[f][i] = nullptr;
994 for(int f = 0; f < 6; f++)
996 mFaceProxies[f] = nullptr;
997 mFaceProxyRefs[f] = 0;
1001 TextureCubeMap::~TextureCubeMap()
1003 for(int f = 0; f < 6; f++)
1005 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1009 image[f][i]->unbind(this);
1010 image[f][i] = nullptr;
1015 for(int i = 0; i < 6; i++)
1017 mFaceProxies[i] = nullptr;
1021 // We need to maintain a count of references to renderbuffers acting as
1022 // proxies for this texture, so that the texture is not deleted while
1023 // proxy references still exist. If the reference count drops to zero,
1024 // we set our proxy pointer null, so that a new attempt at referencing
1025 // will cause recreation.
1026 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1028 for(int f = 0; f < 6; f++)
1030 if(mFaceProxies[f] == proxy)
1032 mFaceProxyRefs[f]++;
1037 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1039 for(int f = 0; f < 6; f++)
1041 if(mFaceProxies[f] == proxy)
1043 if(mFaceProxyRefs[f] > 0)
1045 mFaceProxyRefs[f]--;
1048 if(mFaceProxyRefs[f] == 0)
1050 mFaceProxies[f] = nullptr;
1056 void TextureCubeMap::sweep()
1060 for(int f = 0; f < 6; f++)
1062 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1064 if(image[f][i] && image[f][i]->isChildOf(this))
1066 if(!image[f][i]->hasSingleReference())
1076 if(imageCount == referenceCount)
1082 GLenum TextureCubeMap::getTarget() const
1084 return GL_TEXTURE_CUBE_MAP;
1087 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1089 int face = CubeFaceIndex(target);
1090 return image[face][level] ? image[face][level]->getWidth() : 0;
1093 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1095 int face = CubeFaceIndex(target);
1096 return image[face][level] ? image[face][level]->getHeight() : 0;
1099 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
1101 int face = CubeFaceIndex(target);
1102 return image[face][level] ? image[face][level]->getFormat() : 0;
1105 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
1107 int face = CubeFaceIndex(target);
1108 return image[face][level] ? image[face][level]->getType() : 0;
1111 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1113 int face = CubeFaceIndex(target);
1114 return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
1117 int TextureCubeMap::getLevelCount() const
1119 ASSERT(isSamplerComplete());
1122 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
1130 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1132 int face = CubeFaceIndex(target);
1134 if(image[face][level])
1136 image[face][level]->release();
1139 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1140 image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1142 if(!image[face][level])
1144 return error(GL_OUT_OF_MEMORY);
1147 Texture::setCompressedImage(imageSize, pixels, image[face][level]);
1150 void TextureCubeMap::subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1152 Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
1155 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1157 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
1160 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1161 bool TextureCubeMap::isSamplerComplete() const
1163 for(int face = 0; face < 6; face++)
1171 int size = image[0][0]->getWidth();
1178 if(!isMipmapFiltered())
1180 if(!isCubeComplete())
1187 if(!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1196 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1197 bool TextureCubeMap::isCubeComplete() const
1199 if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
1204 for(unsigned int face = 1; face < 6; face++)
1206 if(image[face][mBaseLevel]->getWidth() != image[0][mBaseLevel]->getWidth() ||
1207 image[face][mBaseLevel]->getWidth() != image[0][mBaseLevel]->getHeight() ||
1208 image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
1209 image[face][mBaseLevel]->getType() != image[0][mBaseLevel]->getType())
1218 bool TextureCubeMap::isMipmapCubeComplete() const
1220 if(!isCubeComplete())
1225 GLsizei size = image[0][mBaseLevel]->getWidth();
1226 int q = std::min(log2(size), mMaxLevel);
1228 for(int face = 0; face < 6; face++)
1230 for(int level = mBaseLevel + 1; level <= q; level++)
1232 if(!image[face][level])
1237 if(image[face][level]->getFormat() != image[0][mBaseLevel]->getFormat())
1242 if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
1247 if(image[face][level]->getWidth() != std::max(1, size >> level))
1257 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1259 return IsCompressed(getFormat(target, level), egl::getClientVersion());
1262 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1264 return IsDepthTexture(getFormat(target, level));
1267 void TextureCubeMap::releaseTexImage()
1269 UNREACHABLE(0); // Cube maps cannot have an EGL surface bound as an image
1272 void TextureCubeMap::setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1274 int face = CubeFaceIndex(target);
1276 if(image[face][level])
1278 image[face][level]->release();
1281 image[face][level] = egl::Image::create(this, width, height, format, type);
1283 if(!image[face][level])
1285 return error(GL_OUT_OF_MEMORY);
1288 Texture::setImage(context, format, type, unpackInfo, pixels, image[face][level]);
1291 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1293 egl::Image *renderTarget = source->getRenderTarget(0);
1297 ERR("Failed to retrieve the render target.");
1298 return error(GL_OUT_OF_MEMORY);
1301 int face = CubeFaceIndex(target);
1303 if(image[face][level])
1305 image[face][level]->release();
1308 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1309 image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
1311 if(!image[face][level])
1313 return error(GL_OUT_OF_MEMORY);
1316 if(width != 0 && height != 0)
1318 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1322 ERR("Failed to retrieve the source colorbuffer.");
1326 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1327 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1329 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
1332 renderTarget->release();
1335 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
1337 return image[face][level];
1340 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
1342 return image[CubeFaceIndex(face)][level];
1345 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1347 int face = CubeFaceIndex(target);
1349 if(!image[face][level])
1351 return error(GL_INVALID_OPERATION);
1354 GLsizei size = image[face][level]->getWidth();
1356 if(xoffset + width > size || yoffset + height > size || zoffset != 0)
1358 return error(GL_INVALID_VALUE);
1361 egl::Image *renderTarget = source->getRenderTarget(0);
1365 ERR("Failed to retrieve the render target.");
1366 return error(GL_OUT_OF_MEMORY);
1369 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1373 ERR("Failed to retrieve the source colorbuffer.");
1377 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
1378 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1380 copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
1382 renderTarget->release();
1385 void TextureCubeMap::generateMipmaps()
1387 if(!isCubeComplete())
1389 return error(GL_INVALID_OPERATION);
1392 unsigned int q = log2(image[0][0]->getWidth());
1394 for(unsigned int f = 0; f < 6; f++)
1396 for(unsigned int i = 1; i <= q; i++)
1400 image[f][i]->release();
1403 image[f][i] = egl::Image::create(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType());
1407 return error(GL_OUT_OF_MEMORY);
1410 getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
1415 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
1417 if(!IsCubemapTextureTarget(target))
1419 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1422 int face = CubeFaceIndex(target);
1424 if(!mFaceProxies[face])
1426 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
1430 mFaceProxies[face]->setLevel(level);
1433 return mFaceProxies[face];
1436 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
1438 ASSERT(IsCubemapTextureTarget(target));
1439 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1441 int face = CubeFaceIndex(target);
1443 if(image[face][level])
1445 image[face][level]->addRef();
1448 return image[face][level];
1451 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
1453 ASSERT(IsCubemapTextureTarget(target));
1454 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1456 int face = CubeFaceIndex(target);
1458 if(!image[face][level])
1463 return image[face][level]->isShared();
1466 Texture3D::Texture3D(GLuint name) : Texture(name)
1468 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1475 mColorbufferProxy = nullptr;
1479 Texture3D::~Texture3D()
1481 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1485 image[i]->unbind(this);
1492 mSurface->setBoundTexture(nullptr);
1496 mColorbufferProxy = nullptr;
1499 // We need to maintain a count of references to renderbuffers acting as
1500 // proxies for this texture, so that we do not attempt to use a pointer
1501 // to a renderbuffer proxy which has been deleted.
1502 void Texture3D::addProxyRef(const Renderbuffer *proxy)
1507 void Texture3D::releaseProxy(const Renderbuffer *proxy)
1516 mColorbufferProxy = nullptr;
1520 void Texture3D::sweep()
1524 for(int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1526 if(image[i] && image[i]->isChildOf(this))
1528 if(!image[i]->hasSingleReference())
1537 if(imageCount == referenceCount)
1543 GLenum Texture3D::getTarget() const
1545 return GL_TEXTURE_3D_OES;
1548 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
1550 ASSERT(target == getTarget());
1551 return image[level] ? image[level]->getWidth() : 0;
1554 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
1556 ASSERT(target == getTarget());
1557 return image[level] ? image[level]->getHeight() : 0;
1560 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
1562 ASSERT(target == getTarget());
1563 return image[level] ? image[level]->getDepth() : 0;
1566 GLenum Texture3D::getFormat(GLenum target, GLint level) const
1568 ASSERT(target == getTarget());
1569 return image[level] ? image[level]->getFormat() : GL_NONE;
1572 GLenum Texture3D::getType(GLenum target, GLint level) const
1574 ASSERT(target == getTarget());
1575 return image[level] ? image[level]->getType() : GL_NONE;
1578 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
1580 ASSERT(target == getTarget());
1581 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
1584 int Texture3D::getLevelCount() const
1586 ASSERT(isSamplerComplete());
1589 while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
1597 void Texture3D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1601 image[level]->release();
1604 image[level] = egl::Image::create(this, width, height, depth, format, type);
1608 return error(GL_OUT_OF_MEMORY);
1611 Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
1614 void Texture3D::releaseTexImage()
1616 UNREACHABLE(0); // 3D textures cannot have an EGL surface bound as an image
1619 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1623 image[level]->release();
1626 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1627 image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1631 return error(GL_OUT_OF_MEMORY);
1634 Texture::setCompressedImage(imageSize, pixels, image[level]);
1637 void Texture3D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
1639 Texture::subImage(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
1642 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1644 Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
1647 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
1649 egl::Image *renderTarget = source->getRenderTarget(0);
1653 ERR("Failed to retrieve the render target.");
1654 return error(GL_OUT_OF_MEMORY);
1659 image[level]->release();
1662 GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1663 image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
1667 return error(GL_OUT_OF_MEMORY);
1670 if(width != 0 && height != 0 && depth != 0)
1672 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1676 ERR("Failed to retrieve the source colorbuffer.");
1680 sw::SliceRect sourceRect(x, y, x + width, y + height, z);
1681 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1682 for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
1684 copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
1688 renderTarget->release();
1691 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1695 return error(GL_INVALID_OPERATION);
1698 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
1700 return error(GL_INVALID_VALUE);
1703 egl::Image *renderTarget = source->getRenderTarget(0);
1707 ERR("Failed to retrieve the render target.");
1708 return error(GL_OUT_OF_MEMORY);
1711 Renderbuffer* renderbuffer = source->getReadColorbuffer();
1715 ERR("Failed to retrieve the source colorbuffer.");
1719 sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
1720 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
1722 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
1724 renderTarget->release();
1727 void Texture3D::setSharedImage(egl::Image *sharedImage)
1729 sharedImage->addRef();
1733 image[0]->release();
1736 image[0] = sharedImage;
1739 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1740 bool Texture3D::isSamplerComplete() const
1747 GLsizei width = image[0]->getWidth();
1748 GLsizei height = image[0]->getHeight();
1749 GLsizei depth = image[0]->getDepth();
1751 if(width <= 0 || height <= 0 || depth <= 0)
1756 if(isMipmapFiltered())
1758 if(!isMipmapComplete())
1767 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1768 bool Texture3D::isMipmapComplete() const
1770 GLsizei width = image[mBaseLevel]->getWidth();
1771 GLsizei height = image[mBaseLevel]->getHeight();
1772 GLsizei depth = image[mBaseLevel]->getDepth();
1773 bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
1775 int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
1776 std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
1778 for(int level = mBaseLevel + 1; level <= q; level++)
1785 if(image[level]->getFormat() != image[0]->getFormat())
1790 if(image[level]->getType() != image[0]->getType())
1795 if(image[level]->getWidth() != std::max(1, width >> level))
1800 if(image[level]->getHeight() != std::max(1, height >> level))
1805 int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
1806 if(image[level]->getDepth() != levelDepth)
1815 bool Texture3D::isCompressed(GLenum target, GLint level) const
1817 return IsCompressed(getFormat(target, level), egl::getClientVersion());
1820 bool Texture3D::isDepth(GLenum target, GLint level) const
1822 return IsDepthTexture(getFormat(target, level));
1825 void Texture3D::generateMipmaps()
1829 return; // FIXME: error?
1832 unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
1834 for(unsigned int i = 1; i <= q; i++)
1838 image[i]->release();
1841 image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), std::max(image[0]->getDepth() >> i, 1), image[0]->getFormat(), image[0]->getType());
1845 return error(GL_OUT_OF_MEMORY);
1848 getDevice()->stretchCube(image[i - 1], image[i]);
1852 egl::Image *Texture3D::getImage(unsigned int level)
1854 return image[level];
1857 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
1859 if(target != getTarget())
1861 return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
1864 if(!mColorbufferProxy)
1866 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
1870 mColorbufferProxy->setLevel(level);
1871 mColorbufferProxy->setLayer(layer);
1874 return mColorbufferProxy;
1877 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
1879 ASSERT(target == getTarget());
1880 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1884 image[level]->addRef();
1887 return image[level];
1890 bool Texture3D::isShared(GLenum target, unsigned int level) const
1892 ASSERT(target == getTarget());
1893 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1895 if(mSurface) // Bound to an EGLSurface
1905 return image[level]->isShared();
1908 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
1912 Texture2DArray::~Texture2DArray()
1916 GLenum Texture2DArray::getTarget() const
1918 return GL_TEXTURE_2D_ARRAY;
1921 void Texture2DArray::generateMipmaps()
1923 int depth = image[0] ? image[0]->getDepth() : 0;
1926 return; // FIXME: error?
1929 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
1931 for(unsigned int i = 1; i <= q; i++)
1935 image[i]->release();
1938 GLsizei w = std::max(image[0]->getWidth() >> i, 1);
1939 GLsizei h = std::max(image[0]->getHeight() >> i, 1);
1940 image[i] = egl::Image::create(this, w, h, depth, image[0]->getFormat(), image[0]->getType());
1944 return error(GL_OUT_OF_MEMORY);
1947 GLsizei srcw = image[i - 1]->getWidth();
1948 GLsizei srch = image[i - 1]->getHeight();
1949 for(int z = 0; z < depth; ++z)
1951 sw::SliceRect srcRect(0, 0, srcw, srch, z);
1952 sw::SliceRect dstRect(0, 0, w, h, z);
1953 getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
1958 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
1960 mMinFilter = GL_LINEAR;
1961 mMagFilter = GL_LINEAR;
1962 mWrapS = GL_CLAMP_TO_EDGE;
1963 mWrapT = GL_CLAMP_TO_EDGE;
1964 mWrapR = GL_CLAMP_TO_EDGE;
1967 TextureExternal::~TextureExternal()
1971 GLenum TextureExternal::getTarget() const
1973 return GL_TEXTURE_EXTERNAL_OES;
1978 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
1982 return egl::Image::create(width, height, config->mRenderTargetFormat, config->mSamples, false);
1988 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
1990 if(width == 0 || height == 0 || height > sw::OUTLINE_RESOLUTION)
1992 ERR("Invalid parameters: %dx%d", width, height);
1996 bool lockable = true;
2000 // case sw::FORMAT_D15S1:
2001 case sw::FORMAT_D24S8:
2002 case sw::FORMAT_D24X8:
2003 // case sw::FORMAT_D24X4S4:
2004 case sw::FORMAT_D24FS8:
2005 case sw::FORMAT_D32:
2006 case sw::FORMAT_D16:
2009 // case sw::FORMAT_S8_LOCKABLE:
2010 // case sw::FORMAT_D16_LOCKABLE:
2011 case sw::FORMAT_D32F_LOCKABLE:
2012 // case sw::FORMAT_D32_LOCKABLE:
2013 case sw::FORMAT_DF24S8:
2014 case sw::FORMAT_DF16S8:
2018 UNREACHABLE(format);
2021 egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
2025 ERR("Out of memory");