1 // SwiftShader Software Renderer
\r
3 // Copyright(c) 2005-2013 TransGaming Inc.
\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
\r
6 // transcribed, stored in a retrieval system, translated into any human or computer
\r
7 // language by any means, or disclosed to third parties without the explicit written
\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
\r
9 // or implied, including but not limited to any patent rights, are granted to you.
\r
12 // Texture.cpp: Implements the Texture class and its derived classes
\r
13 // Texture2D, TextureCubeMap, Texture3D and Texture2DArray. Implements GL texture objects
\r
14 // and related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
\r
16 #include "Texture.h"
\r
19 #include "mathutil.h"
\r
20 #include "Framebuffer.h"
\r
21 #include "Device.hpp"
\r
22 #include "libEGL/Display.h"
\r
23 #include "libEGL/Surface.h"
\r
24 #include "common/debug.h"
\r
26 #include <algorithm>
\r
31 Texture::Texture(GLuint name) : egl::Texture(name)
\r
33 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
\r
34 mMagFilter = GL_LINEAR;
\r
38 mMaxAnisotropy = 1.0f;
\r
40 mCompareFunc = GL_LEQUAL;
\r
41 mCompareMode = GL_NONE;
\r
42 mImmutableFormat = GL_FALSE;
\r
47 mSwizzleG = GL_GREEN;
\r
48 mSwizzleB = GL_BLUE;
\r
49 mSwizzleA = GL_ALPHA;
\r
51 resource = new sw::Resource(0);
\r
56 resource->destruct();
\r
59 sw::Resource *Texture::getResource() const
\r
64 // Returns true on successful filter state update (valid enum parameter)
\r
65 bool Texture::setMinFilter(GLenum filter)
\r
69 case GL_NEAREST_MIPMAP_NEAREST:
\r
70 case GL_LINEAR_MIPMAP_NEAREST:
\r
71 case GL_NEAREST_MIPMAP_LINEAR:
\r
72 case GL_LINEAR_MIPMAP_LINEAR:
\r
73 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
80 mMinFilter = filter;
\r
87 // Returns true on successful filter state update (valid enum parameter)
\r
88 bool Texture::setMagFilter(GLenum filter)
\r
94 mMagFilter = filter;
\r
101 // Returns true on successful wrap state update (valid enum parameter)
\r
102 bool Texture::setWrapS(GLenum wrap)
\r
107 case GL_MIRRORED_REPEAT:
\r
108 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
113 case GL_CLAMP_TO_EDGE:
\r
121 // Returns true on successful wrap state update (valid enum parameter)
\r
122 bool Texture::setWrapT(GLenum wrap)
\r
127 case GL_MIRRORED_REPEAT:
\r
128 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
133 case GL_CLAMP_TO_EDGE:
\r
141 // Returns true on successful wrap state update (valid enum parameter)
\r
142 bool Texture::setWrapR(GLenum wrap)
\r
147 case GL_MIRRORED_REPEAT:
\r
148 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
153 case GL_CLAMP_TO_EDGE:
\r
161 // Returns true on successful max anisotropy update (valid anisotropy value)
\r
162 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
\r
164 textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
\r
166 if(textureMaxAnisotropy < 1.0f)
\r
171 if(mMaxAnisotropy != textureMaxAnisotropy)
\r
173 mMaxAnisotropy = textureMaxAnisotropy;
\r
179 bool Texture::setBaseLevel(GLint baseLevel)
\r
181 mBaseLevel = baseLevel;
\r
185 bool Texture::setCompareFunc(GLenum compareFunc)
\r
187 switch(compareFunc)
\r
197 mCompareFunc = compareFunc;
\r
204 bool Texture::setCompareMode(GLenum compareMode)
\r
206 switch(compareMode)
\r
208 case GL_COMPARE_REF_TO_TEXTURE:
\r
210 mCompareMode = compareMode;
\r
217 bool Texture::setImmutableFormat(GLboolean immutableFormat)
\r
219 mImmutableFormat = immutableFormat;
\r
223 bool Texture::setMaxLevel(GLint maxLevel)
\r
225 mMaxLevel = maxLevel;
\r
229 bool Texture::setMaxLOD(GLfloat maxLOD)
\r
235 bool Texture::setMinLOD(GLfloat minLOD)
\r
241 bool Texture::setSwizzleR(GLenum swizzleR)
\r
251 mSwizzleR = swizzleR;
\r
258 bool Texture::setSwizzleG(GLenum swizzleG)
\r
268 mSwizzleG = swizzleG;
\r
275 bool Texture::setSwizzleB(GLenum swizzleB)
\r
285 mSwizzleB = swizzleB;
\r
292 bool Texture::setSwizzleA(GLenum swizzleA)
\r
302 mSwizzleA = swizzleA;
\r
309 GLenum Texture::getMinFilter() const
\r
314 GLenum Texture::getMagFilter() const
\r
319 GLenum Texture::getWrapS() const
\r
324 GLenum Texture::getWrapT() const
\r
329 GLenum Texture::getWrapR() const
\r
334 GLfloat Texture::getMaxAnisotropy() const
\r
336 return mMaxAnisotropy;
\r
339 GLint Texture::getBaseLevel() const
\r
343 GLenum Texture::getCompareFunc() const
\r
345 return mCompareFunc;
\r
347 GLenum Texture::getCompareMode() const
\r
349 return mCompareMode;
\r
351 GLboolean Texture::getImmutableFormat() const
\r
353 return mImmutableFormat;
\r
355 GLint Texture::getMaxLevel() const
\r
359 GLfloat Texture::getMaxLOD() const
\r
363 GLfloat Texture::getMinLOD() const
\r
367 GLenum Texture::getSwizzleR() const
\r
371 GLenum Texture::getSwizzleG() const
\r
375 GLenum Texture::getSwizzleB() const
\r
379 GLenum Texture::getSwizzleA() const
\r
384 GLsizei Texture::getDepth(GLenum target, GLint level) const
\r
389 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
\r
391 egl::Image *image = getRenderTarget(target, level); // Increments reference count
\r
395 image->markShared();
\r
401 void Texture::setImage(GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
\r
403 if(pixels && image)
\r
405 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
\r
406 image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackInfo, pixels);
\r
410 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
\r
412 if(pixels && image)
\r
414 GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
\r
415 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
\r
419 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)
\r
423 return error(GL_INVALID_OPERATION);
\r
426 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
\r
428 return error(GL_INVALID_VALUE);
\r
431 if(IsCompressed(image->getFormat(), egl::getClientVersion()))
\r
433 return error(GL_INVALID_OPERATION);
\r
436 if(format != image->getFormat())
\r
438 return error(GL_INVALID_OPERATION);
\r
443 image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels);
\r
447 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)
\r
451 return error(GL_INVALID_OPERATION);
\r
454 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
\r
456 return error(GL_INVALID_VALUE);
\r
459 if(format != image->getFormat())
\r
461 return error(GL_INVALID_OPERATION);
\r
466 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
\r
470 bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
\r
472 Device *device = getDevice();
\r
474 sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
\r
475 bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);
\r
479 return error(GL_OUT_OF_MEMORY, false);
\r
485 bool Texture::isMipmapFiltered() const
\r
492 case GL_NEAREST_MIPMAP_NEAREST:
\r
493 case GL_LINEAR_MIPMAP_NEAREST:
\r
494 case GL_NEAREST_MIPMAP_LINEAR:
\r
495 case GL_LINEAR_MIPMAP_LINEAR:
\r
497 default: UNREACHABLE(mMinFilter);
\r
503 Texture2D::Texture2D(GLuint name) : Texture(name)
\r
505 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
512 mColorbufferProxy = NULL;
\r
516 Texture2D::~Texture2D()
\r
518 resource->lock(sw::DESTRUCT);
\r
520 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
524 image[i]->unbind(this);
\r
529 resource->unlock();
\r
533 mSurface->setBoundTexture(NULL);
\r
537 mColorbufferProxy = NULL;
\r
540 // We need to maintain a count of references to renderbuffers acting as
\r
541 // proxies for this texture, so that we do not attempt to use a pointer
\r
542 // to a renderbuffer proxy which has been deleted.
\r
543 void Texture2D::addProxyRef(const Renderbuffer *proxy)
\r
548 void Texture2D::releaseProxy(const Renderbuffer *proxy)
\r
555 if(mProxyRefs == 0)
\r
557 mColorbufferProxy = NULL;
\r
561 GLenum Texture2D::getTarget() const
\r
563 return GL_TEXTURE_2D;
\r
566 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
\r
568 ASSERT(target == GL_TEXTURE_2D);
\r
569 return image[level] ? image[level]->getWidth() : 0;
\r
572 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
\r
574 ASSERT(target == GL_TEXTURE_2D);
\r
575 return image[level] ? image[level]->getHeight() : 0;
\r
578 GLenum Texture2D::getFormat(GLenum target, GLint level) const
\r
580 ASSERT(target == GL_TEXTURE_2D);
\r
581 return image[level] ? image[level]->getFormat() : 0;
\r
584 GLenum Texture2D::getType(GLenum target, GLint level) const
\r
586 ASSERT(target == GL_TEXTURE_2D);
\r
587 return image[level] ? image[level]->getType() : 0;
\r
590 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
\r
592 ASSERT(target == GL_TEXTURE_2D);
\r
593 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
\r
596 int Texture2D::getLevelCount() const
\r
598 ASSERT(isSamplerComplete());
\r
601 while(levels < MIPMAP_LEVELS && image[levels])
\r
609 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
\r
613 image[level]->unbind(this);
\r
616 image[level] = new egl::Image(this, width, height, format, type);
\r
620 return error(GL_OUT_OF_MEMORY);
\r
623 Texture::setImage(format, type, unpackInfo, pixels, image[level]);
\r
626 void Texture2D::bindTexImage(egl::Surface *surface)
\r
630 switch(surface->getInternalFormat())
\r
632 case sw::FORMAT_A8R8G8B8:
\r
633 format = GL_BGRA_EXT;
\r
635 case sw::FORMAT_A8B8G8R8:
\r
638 case sw::FORMAT_X8B8G8R8:
\r
639 case sw::FORMAT_X8R8G8B8:
\r
647 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
651 image[level]->unbind(this);
\r
656 image[0] = surface->getRenderTarget();
\r
658 mSurface = surface;
\r
659 mSurface->setBoundTexture(this);
\r
662 void Texture2D::releaseTexImage()
\r
664 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
668 image[level]->unbind(this);
\r
674 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
\r
678 image[level]->unbind(this);
\r
681 image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
685 return error(GL_OUT_OF_MEMORY);
\r
688 Texture::setCompressedImage(imageSize, pixels, image[level]);
\r
691 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)
\r
693 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
\r
696 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
\r
698 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
\r
701 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
703 egl::Image *renderTarget = source->getRenderTarget(0);
\r
707 ERR("Failed to retrieve the render target.");
\r
708 return error(GL_OUT_OF_MEMORY);
\r
713 image[level]->unbind(this);
\r
716 image[level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
720 return error(GL_OUT_OF_MEMORY);
\r
723 if(width != 0 && height != 0)
\r
725 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
729 ERR("Failed to retrieve the source colorbuffer.");
\r
733 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
\r
734 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
736 copy(renderTarget, sourceRect, format, 0, 0, 0, image[level]);
\r
739 renderTarget->release();
\r
742 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
746 return error(GL_INVALID_OPERATION);
\r
749 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)
\r
751 return error(GL_INVALID_VALUE);
\r
754 egl::Image *renderTarget = source->getRenderTarget(0);
\r
758 ERR("Failed to retrieve the render target.");
\r
759 return error(GL_OUT_OF_MEMORY);
\r
762 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
766 ERR("Failed to retrieve the source colorbuffer.");
\r
770 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
\r
771 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
773 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
\r
775 renderTarget->release();
\r
778 void Texture2D::setImage(egl::Image *sharedImage)
\r
780 if (sharedImage == image[0])
\r
785 sharedImage->addRef();
\r
789 image[0]->unbind(this);
\r
792 image[0] = sharedImage;
\r
795 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
\r
796 bool Texture2D::isSamplerComplete() const
\r
803 GLsizei width = image[0]->getWidth();
\r
804 GLsizei height = image[0]->getHeight();
\r
806 if(width <= 0 || height <= 0)
\r
811 if(isMipmapFiltered())
\r
813 if(!isMipmapComplete())
\r
822 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
\r
823 bool Texture2D::isMipmapComplete() const
\r
825 GLsizei width = image[0]->getWidth();
\r
826 GLsizei height = image[0]->getHeight();
\r
828 int q = log2(std::max(width, height));
\r
830 for(int level = 1; level <= q; level++)
\r
837 if(image[level]->getFormat() != image[0]->getFormat())
\r
842 if(image[level]->getType() != image[0]->getType())
\r
847 if(image[level]->getWidth() != std::max(1, width >> level))
\r
852 if(image[level]->getHeight() != std::max(1, height >> level))
\r
861 bool Texture2D::isCompressed(GLenum target, GLint level) const
\r
863 return IsCompressed(getFormat(target, level), egl::getClientVersion());
\r
866 bool Texture2D::isDepth(GLenum target, GLint level) const
\r
868 return IsDepthTexture(getFormat(target, level));
\r
871 void Texture2D::generateMipmaps()
\r
875 return; // FIXME: error?
\r
878 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
\r
880 for(unsigned int i = 1; i <= q; i++)
\r
884 image[i]->unbind(this);
\r
887 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());
\r
891 return error(GL_OUT_OF_MEMORY);
\r
894 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
\r
898 egl::Image *Texture2D::getImage(unsigned int level)
\r
900 return image[level];
\r
903 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
\r
905 if(target != GL_TEXTURE_2D)
\r
907 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
\r
910 if(mColorbufferProxy == NULL)
\r
912 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
\r
915 return mColorbufferProxy;
\r
918 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
\r
920 ASSERT(target == GL_TEXTURE_2D);
\r
921 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
925 image[level]->addRef();
\r
928 return image[level];
\r
931 bool Texture2D::isShared(GLenum target, unsigned int level) const
\r
933 ASSERT(target == GL_TEXTURE_2D);
\r
934 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
936 if(mSurface) // Bound to an EGLSurface
\r
946 return image[level]->isShared();
\r
949 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
\r
951 for(int f = 0; f < 6; f++)
\r
953 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
959 for(int f = 0; f < 6; f++)
\r
961 mFaceProxies[f] = NULL;
\r
962 mFaceProxyRefs[f] = 0;
\r
966 TextureCubeMap::~TextureCubeMap()
\r
968 resource->lock(sw::DESTRUCT);
\r
970 for(int f = 0; f < 6; f++)
\r
972 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
976 image[f][i]->unbind(this);
\r
982 resource->unlock();
\r
984 for(int i = 0; i < 6; i++)
\r
986 mFaceProxies[i] = NULL;
\r
990 // We need to maintain a count of references to renderbuffers acting as
\r
991 // proxies for this texture, so that the texture is not deleted while
\r
992 // proxy references still exist. If the reference count drops to zero,
\r
993 // we set our proxy pointer NULL, so that a new attempt at referencing
\r
994 // will cause recreation.
\r
995 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
\r
997 for(int f = 0; f < 6; f++)
\r
999 if(mFaceProxies[f] == proxy)
\r
1001 mFaceProxyRefs[f]++;
\r
1006 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
\r
1008 for(int f = 0; f < 6; f++)
\r
1010 if(mFaceProxies[f] == proxy)
\r
1012 if(mFaceProxyRefs[f] > 0)
\r
1014 mFaceProxyRefs[f]--;
\r
1017 if(mFaceProxyRefs[f] == 0)
\r
1019 mFaceProxies[f] = NULL;
\r
1025 GLenum TextureCubeMap::getTarget() const
\r
1027 return GL_TEXTURE_CUBE_MAP;
\r
1030 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
\r
1032 int face = CubeFaceIndex(target);
\r
1033 return image[face][level] ? image[face][level]->getWidth() : 0;
\r
1036 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
\r
1038 int face = CubeFaceIndex(target);
\r
1039 return image[face][level] ? image[face][level]->getHeight() : 0;
\r
1042 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
\r
1044 int face = CubeFaceIndex(target);
\r
1045 return image[face][level] ? image[face][level]->getFormat() : 0;
\r
1048 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
\r
1050 int face = CubeFaceIndex(target);
\r
1051 return image[face][level] ? image[face][level]->getType() : 0;
\r
1054 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
\r
1056 int face = CubeFaceIndex(target);
\r
1057 return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
\r
1060 int TextureCubeMap::getLevelCount() const
\r
1062 ASSERT(isSamplerComplete());
\r
1065 while(levels < MIPMAP_LEVELS && image[0][levels])
\r
1073 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
\r
1075 int face = CubeFaceIndex(target);
\r
1077 if(image[face][level])
\r
1079 image[face][level]->unbind(this);
\r
1082 image[face][level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
1084 if(!image[face][level])
\r
1086 return error(GL_OUT_OF_MEMORY);
\r
1089 Texture::setCompressedImage(imageSize, pixels, image[face][level]);
\r
1092 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)
\r
1094 Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
\r
1097 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
\r
1099 Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
\r
1102 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
\r
1103 bool TextureCubeMap::isSamplerComplete() const
\r
1105 for(int face = 0; face < 6; face++)
\r
1107 if(!image[face][0])
\r
1113 int size = image[0][0]->getWidth();
\r
1120 if(!isMipmapFiltered())
\r
1122 if(!isCubeComplete())
\r
1129 if(!isMipmapCubeComplete()) // Also tests for isCubeComplete()
\r
1138 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
\r
1139 bool TextureCubeMap::isCubeComplete() const
\r
1141 if(image[0][0]->getWidth() <= 0 || image[0][0]->getHeight() != image[0][0]->getWidth())
\r
1146 for(unsigned int face = 1; face < 6; face++)
\r
1148 if(image[face][0]->getWidth() != image[0][0]->getWidth() ||
\r
1149 image[face][0]->getWidth() != image[0][0]->getHeight() ||
\r
1150 image[face][0]->getFormat() != image[0][0]->getFormat() ||
\r
1151 image[face][0]->getType() != image[0][0]->getType())
\r
1160 bool TextureCubeMap::isMipmapCubeComplete() const
\r
1162 if(!isCubeComplete())
\r
1167 GLsizei size = image[0][0]->getWidth();
\r
1168 int q = log2(size);
\r
1170 for(int face = 0; face < 6; face++)
\r
1172 for(int level = 1; level <= q; level++)
\r
1174 if(!image[face][level])
\r
1179 if(image[face][level]->getFormat() != image[0][0]->getFormat())
\r
1184 if(image[face][level]->getType() != image[0][0]->getType())
\r
1189 if(image[face][level]->getWidth() != std::max(1, size >> level))
\r
1199 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
\r
1201 return IsCompressed(getFormat(target, level), egl::getClientVersion());
\r
1204 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
\r
1206 return IsDepthTexture(getFormat(target, level));
\r
1209 void TextureCubeMap::releaseTexImage()
\r
1211 UNREACHABLE(0); // Cube maps cannot have an EGL surface bound as an image
\r
1214 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
\r
1216 int face = CubeFaceIndex(target);
\r
1218 if(image[face][level])
\r
1220 image[face][level]->unbind(this);
\r
1223 image[face][level] = new egl::Image(this, width, height, format, type);
\r
1225 if(!image[face][level])
\r
1227 return error(GL_OUT_OF_MEMORY);
\r
1230 Texture::setImage(format, type, unpackInfo, pixels, image[face][level]);
\r
1233 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
1235 egl::Image *renderTarget = source->getRenderTarget(0);
\r
1239 ERR("Failed to retrieve the render target.");
\r
1240 return error(GL_OUT_OF_MEMORY);
\r
1243 int face = CubeFaceIndex(target);
\r
1245 if(image[face][level])
\r
1247 image[face][level]->unbind(this);
\r
1250 image[face][level] = new egl::Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
1252 if(!image[face][level])
\r
1254 return error(GL_OUT_OF_MEMORY);
\r
1257 if(width != 0 && height != 0)
\r
1259 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
1263 ERR("Failed to retrieve the source colorbuffer.");
\r
1267 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
\r
1268 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
1270 copy(renderTarget, sourceRect, format, 0, 0, 0, image[face][level]);
\r
1273 renderTarget->release();
\r
1276 egl::Image *TextureCubeMap::getImage(int face, unsigned int level)
\r
1278 return image[face][level];
\r
1281 egl::Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
\r
1283 return image[CubeFaceIndex(face)][level];
\r
1286 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
1288 int face = CubeFaceIndex(target);
\r
1290 if(!image[face][level])
\r
1292 return error(GL_INVALID_OPERATION);
\r
1295 GLsizei size = image[face][level]->getWidth();
\r
1297 if(xoffset + width > size || yoffset + height > size || zoffset != 0)
\r
1299 return error(GL_INVALID_VALUE);
\r
1302 egl::Image *renderTarget = source->getRenderTarget(0);
\r
1306 ERR("Failed to retrieve the render target.");
\r
1307 return error(GL_OUT_OF_MEMORY);
\r
1310 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
1314 ERR("Failed to retrieve the source colorbuffer.");
\r
1318 sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
\r
1319 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
1321 copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
\r
1323 renderTarget->release();
\r
1326 void TextureCubeMap::generateMipmaps()
\r
1328 if(!isCubeComplete())
\r
1330 return error(GL_INVALID_OPERATION);
\r
1333 unsigned int q = log2(image[0][0]->getWidth());
\r
1335 for(unsigned int f = 0; f < 6; f++)
\r
1337 for(unsigned int i = 1; i <= q; i++)
\r
1341 image[f][i]->unbind(this);
\r
1344 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());
\r
1348 return error(GL_OUT_OF_MEMORY);
\r
1351 getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
\r
1356 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
\r
1358 if(!IsCubemapTextureTarget(target))
\r
1360 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
\r
1363 int face = CubeFaceIndex(target);
\r
1365 if(mFaceProxies[face] == NULL)
\r
1367 mFaceProxies[face] = new Renderbuffer(name, new RenderbufferTextureCubeMap(this, target, level));
\r
1370 return mFaceProxies[face];
\r
1373 egl::Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
\r
1375 ASSERT(IsCubemapTextureTarget(target));
\r
1376 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1378 int face = CubeFaceIndex(target);
\r
1380 if(image[face][level])
\r
1382 image[face][level]->addRef();
\r
1385 return image[face][level];
\r
1388 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
\r
1390 ASSERT(IsCubemapTextureTarget(target));
\r
1391 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1393 int face = CubeFaceIndex(target);
\r
1395 if(!image[face][level])
\r
1400 return image[face][level]->isShared();
\r
1403 Texture3D::Texture3D(GLuint name) : Texture(name)
\r
1405 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
1412 mColorbufferProxy = NULL;
\r
1416 Texture3D::~Texture3D()
\r
1418 resource->lock(sw::DESTRUCT);
\r
1420 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
1424 image[i]->unbind(this);
\r
1429 resource->unlock();
\r
1433 mSurface->setBoundTexture(NULL);
\r
1437 mColorbufferProxy = NULL;
\r
1440 // We need to maintain a count of references to renderbuffers acting as
\r
1441 // proxies for this texture, so that we do not attempt to use a pointer
\r
1442 // to a renderbuffer proxy which has been deleted.
\r
1443 void Texture3D::addProxyRef(const Renderbuffer *proxy)
\r
1448 void Texture3D::releaseProxy(const Renderbuffer *proxy)
\r
1450 if(mProxyRefs > 0)
\r
1455 if(mProxyRefs == 0)
\r
1457 mColorbufferProxy = NULL;
\r
1461 GLenum Texture3D::getTarget() const
\r
1463 return GL_TEXTURE_3D_OES;
\r
1466 GLsizei Texture3D::getWidth(GLenum target, GLint level) const
\r
1468 ASSERT(target == getTarget());
\r
1469 return image[level] ? image[level]->getWidth() : 0;
\r
1472 GLsizei Texture3D::getHeight(GLenum target, GLint level) const
\r
1474 ASSERT(target == getTarget());
\r
1475 return image[level] ? image[level]->getHeight() : 0;
\r
1478 GLsizei Texture3D::getDepth(GLenum target, GLint level) const
\r
1480 ASSERT(target == getTarget());
\r
1481 return image[level] ? image[level]->getDepth() : 0;
\r
1484 GLenum Texture3D::getFormat(GLenum target, GLint level) const
\r
1486 ASSERT(target == getTarget());
\r
1487 return image[level] ? image[level]->getFormat() : 0;
\r
1490 GLenum Texture3D::getType(GLenum target, GLint level) const
\r
1492 ASSERT(target == getTarget());
\r
1493 return image[level] ? image[level]->getType() : 0;
\r
1496 sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
\r
1498 ASSERT(target == getTarget());
\r
1499 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
\r
1502 int Texture3D::getLevelCount() const
\r
1504 ASSERT(isSamplerComplete());
\r
1507 while(levels < MIPMAP_LEVELS && image[levels])
\r
1515 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
\r
1519 image[level]->unbind(this);
\r
1522 image[level] = new egl::Image(this, width, height, depth, format, type);
\r
1526 return error(GL_OUT_OF_MEMORY);
\r
1529 Texture::setImage(format, type, unpackInfo, pixels, image[level]);
\r
1532 void Texture3D::bindTexImage(egl::Surface *surface)
\r
1536 switch(surface->getInternalFormat())
\r
1538 case sw::FORMAT_A8R8G8B8:
\r
1541 case sw::FORMAT_X8R8G8B8:
\r
1549 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
1553 image[level]->unbind(this);
\r
1558 image[0] = surface->getRenderTarget();
\r
1560 mSurface = surface;
\r
1561 mSurface->setBoundTexture(this);
\r
1564 void Texture3D::releaseTexImage()
\r
1566 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
1570 image[level]->unbind(this);
\r
1576 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
\r
1580 image[level]->unbind(this);
\r
1583 image[level] = new egl::Image(this, width, height, depth, format, GL_UNSIGNED_BYTE);
\r
1587 return error(GL_OUT_OF_MEMORY);
\r
1590 Texture::setCompressedImage(imageSize, pixels, image[level]);
\r
1593 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)
\r
1595 Texture::subImage(xoffset, yoffset, zoffset, width, height, format, depth, type, unpackInfo, pixels, image[level]);
\r
1598 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
\r
1600 Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
\r
1603 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
\r
1605 egl::Image *renderTarget = source->getRenderTarget(0);
\r
1609 ERR("Failed to retrieve the render target.");
\r
1610 return error(GL_OUT_OF_MEMORY);
\r
1615 image[level]->unbind(this);
\r
1618 image[level] = new egl::Image(this, width, height, depth, format, GL_UNSIGNED_BYTE);
\r
1622 return error(GL_OUT_OF_MEMORY);
\r
1625 if(width != 0 && height != 0 && depth != 0)
\r
1627 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
1631 ERR("Failed to retrieve the source colorbuffer.");
\r
1635 sw::SliceRect sourceRect(x, y, x + width, y + height, z);
\r
1636 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
1637 for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
\r
1639 copy(renderTarget, sourceRect, format, 0, 0, sliceZ, image[level]);
\r
1643 renderTarget->release();
\r
1646 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
1650 return error(GL_INVALID_OPERATION);
\r
1653 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())
\r
1655 return error(GL_INVALID_VALUE);
\r
1658 egl::Image *renderTarget = source->getRenderTarget(0);
\r
1662 ERR("Failed to retrieve the render target.");
\r
1663 return error(GL_OUT_OF_MEMORY);
\r
1666 Renderbuffer* renderbuffer = source->getReadColorbuffer();
\r
1670 ERR("Failed to retrieve the source colorbuffer.");
\r
1674 sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
\r
1675 sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
\r
1677 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
\r
1679 renderTarget->release();
\r
1682 void Texture3D::setImage(egl::Image *sharedImage)
\r
1684 sharedImage->addRef();
\r
1688 image[0]->unbind(this);
\r
1691 image[0] = sharedImage;
\r
1694 // Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
\r
1695 bool Texture3D::isSamplerComplete() const
\r
1702 GLsizei width = image[0]->getWidth();
\r
1703 GLsizei height = image[0]->getHeight();
\r
1704 GLsizei depth = image[0]->getDepth();
\r
1706 if(width <= 0 || height <= 0 || depth <= 0)
\r
1711 if(isMipmapFiltered())
\r
1713 if(!isMipmapComplete())
\r
1722 // Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
\r
1723 bool Texture3D::isMipmapComplete() const
\r
1725 GLsizei width = image[0]->getWidth();
\r
1726 GLsizei height = image[0]->getHeight();
\r
1727 GLsizei depth = image[0]->getDepth();
\r
1729 int q = log2(std::max(std::max(width, height), depth));
\r
1731 for(int level = 1; level <= q; level++)
\r
1738 if(image[level]->getFormat() != image[0]->getFormat())
\r
1743 if(image[level]->getType() != image[0]->getType())
\r
1748 if(image[level]->getWidth() != std::max(1, width >> level))
\r
1753 if(image[level]->getHeight() != std::max(1, height >> level))
\r
1758 if(image[level]->getDepth() != std::max(1, depth >> level))
\r
1767 bool Texture3D::isCompressed(GLenum target, GLint level) const
\r
1769 return IsCompressed(getFormat(target, level), egl::getClientVersion());
\r
1772 bool Texture3D::isDepth(GLenum target, GLint level) const
\r
1774 return IsDepthTexture(getFormat(target, level));
\r
1777 void Texture3D::generateMipmaps()
\r
1781 return; // FIXME: error?
\r
1784 unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
\r
1786 for(unsigned int i = 1; i <= q; i++)
\r
1790 image[i]->unbind(this);
\r
1793 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());
\r
1797 return error(GL_OUT_OF_MEMORY);
\r
1800 getDevice()->stretchCube(image[i - 1], image[i]);
\r
1804 egl::Image *Texture3D::getImage(unsigned int level)
\r
1806 return image[level];
\r
1809 Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
\r
1811 if(target != getTarget())
\r
1813 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
\r
1816 if(mColorbufferProxy == NULL)
\r
1818 mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
\r
1821 return mColorbufferProxy;
\r
1824 egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
\r
1826 ASSERT(target == getTarget());
\r
1827 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1831 image[level]->addRef();
\r
1834 return image[level];
\r
1837 bool Texture3D::isShared(GLenum target, unsigned int level) const
\r
1839 ASSERT(target == getTarget());
\r
1840 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1842 if(mSurface) // Bound to an EGLSurface
\r
1852 return image[level]->isShared();
\r
1855 Texture2DArray::Texture2DArray(GLuint name) : Texture3D(name)
\r
1859 Texture2DArray::~Texture2DArray()
\r
1863 GLenum Texture2DArray::getTarget() const
\r
1865 return GL_TEXTURE_2D_ARRAY;
\r
1868 void Texture2DArray::generateMipmaps()
\r
1873 TextureExternal::TextureExternal(GLuint name) : Texture2D(name)
\r
1875 mMinFilter = GL_LINEAR;
\r
1876 mMagFilter = GL_LINEAR;
\r
1877 mWrapS = GL_CLAMP_TO_EDGE;
\r
1878 mWrapT = GL_CLAMP_TO_EDGE;
\r
1879 mWrapR = GL_CLAMP_TO_EDGE;
\r
1882 TextureExternal::~TextureExternal()
\r
1886 GLenum TextureExternal::getTarget() const
\r
1888 return GL_TEXTURE_EXTERNAL_OES;
\r
1893 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
\r
1897 return new egl::Image(width, height, config->mRenderTargetFormat, 1, false, true);
\r
1903 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
\r
1905 if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
\r
1907 ERR("Invalid parameters: %dx%d", width, height);
\r
1911 bool lockable = true;
\r
1915 // case sw::FORMAT_D15S1:
\r
1916 case sw::FORMAT_D24S8:
\r
1917 case sw::FORMAT_D24X8:
\r
1918 // case sw::FORMAT_D24X4S4:
\r
1919 case sw::FORMAT_D24FS8:
\r
1920 case sw::FORMAT_D32:
\r
1921 case sw::FORMAT_D16:
\r
1924 // case sw::FORMAT_S8_LOCKABLE:
\r
1925 // case sw::FORMAT_D16_LOCKABLE:
\r
1926 case sw::FORMAT_D32F_LOCKABLE:
\r
1927 // case sw::FORMAT_D32_LOCKABLE:
\r
1928 case sw::FORMAT_DF24S8:
\r
1929 case sw::FORMAT_DF16S8:
\r
1933 UNREACHABLE(format);
\r
1936 egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable, true);
\r
1940 ERR("Out of memory");
\r