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 and TextureCubeMap. Implements GL texture objects and related
\r
14 // 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 id) : RefCountObject(id)
\r
33 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
\r
34 mMagFilter = GL_LINEAR;
\r
37 mMaxAnisotropy = 1.0f;
\r
39 resource = new sw::Resource(0);
\r
44 resource->destruct();
\r
47 sw::Resource *Texture::getResource() const
\r
52 // Returns true on successful filter state update (valid enum parameter)
\r
53 bool Texture::setMinFilter(GLenum filter)
\r
57 case GL_NEAREST_MIPMAP_NEAREST:
\r
58 case GL_LINEAR_MIPMAP_NEAREST:
\r
59 case GL_NEAREST_MIPMAP_LINEAR:
\r
60 case GL_LINEAR_MIPMAP_LINEAR:
\r
61 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
68 mMinFilter = filter;
\r
75 // Returns true on successful filter state update (valid enum parameter)
\r
76 bool Texture::setMagFilter(GLenum filter)
\r
82 mMagFilter = filter;
\r
89 // Returns true on successful wrap state update (valid enum parameter)
\r
90 bool Texture::setWrapS(GLenum wrap)
\r
95 case GL_MIRRORED_REPEAT:
\r
96 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
101 case GL_CLAMP_TO_EDGE:
\r
109 // Returns true on successful wrap state update (valid enum parameter)
\r
110 bool Texture::setWrapT(GLenum wrap)
\r
115 case GL_MIRRORED_REPEAT:
\r
116 if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
\r
121 case GL_CLAMP_TO_EDGE:
\r
129 // Returns true on successful max anisotropy update (valid anisotropy value)
\r
130 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy)
\r
132 textureMaxAnisotropy = std::min(textureMaxAnisotropy, MAX_TEXTURE_MAX_ANISOTROPY);
\r
134 if(textureMaxAnisotropy < 1.0f)
\r
139 if(mMaxAnisotropy != textureMaxAnisotropy)
\r
141 mMaxAnisotropy = textureMaxAnisotropy;
\r
147 GLenum Texture::getMinFilter() const
\r
152 GLenum Texture::getMagFilter() const
\r
157 GLenum Texture::getWrapS() const
\r
162 GLenum Texture::getWrapT() const
\r
167 GLfloat Texture::getMaxAnisotropy() const
\r
169 return mMaxAnisotropy;
\r
172 egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
\r
174 egl::Image *image = getRenderTarget(target, level); // Increments reference count
\r
178 image->markShared();
\r
184 void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels,egl:: Image *image)
\r
186 if(pixels && image)
\r
188 image->loadImageData(0, 0, image->getWidth(), image->getHeight(), format, type, unpackAlignment, pixels);
\r
192 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
\r
194 if(pixels && image)
\r
196 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), imageSize, pixels);
\r
200 void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
\r
204 return error(GL_INVALID_OPERATION);
\r
207 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
\r
209 return error(GL_INVALID_VALUE);
\r
212 if(IsCompressed(image->getFormat()))
\r
214 return error(GL_INVALID_OPERATION);
\r
217 if(format != image->getFormat())
\r
219 return error(GL_INVALID_OPERATION);
\r
224 image->loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels);
\r
228 void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
\r
232 return error(GL_INVALID_OPERATION);
\r
235 if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
\r
237 return error(GL_INVALID_VALUE);
\r
240 if(format != image->getFormat())
\r
242 return error(GL_INVALID_OPERATION);
\r
247 image->loadCompressedData(xoffset, yoffset, width, height, imageSize, pixels);
\r
251 bool Texture::copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest)
\r
253 Device *device = getDevice();
\r
255 sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};
\r
256 bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);
\r
260 return error(GL_OUT_OF_MEMORY, false);
\r
266 bool Texture::isMipmapFiltered() const
\r
273 case GL_NEAREST_MIPMAP_NEAREST:
\r
274 case GL_LINEAR_MIPMAP_NEAREST:
\r
275 case GL_NEAREST_MIPMAP_LINEAR:
\r
276 case GL_LINEAR_MIPMAP_LINEAR:
\r
278 default: UNREACHABLE();
\r
284 Texture2D::Texture2D(GLuint id) : Texture(id)
\r
286 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
293 mColorbufferProxy = NULL;
\r
297 Texture2D::~Texture2D()
\r
299 resource->lock(sw::DESTRUCT);
\r
301 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
305 image[i]->unbind();
\r
310 resource->unlock();
\r
314 mSurface->setBoundTexture(NULL);
\r
318 mColorbufferProxy = NULL;
\r
321 // We need to maintain a count of references to renderbuffers acting as
\r
322 // proxies for this texture, so that we do not attempt to use a pointer
\r
323 // to a renderbuffer proxy which has been deleted.
\r
324 void Texture2D::addProxyRef(const Renderbuffer *proxy)
\r
329 void Texture2D::releaseProxy(const Renderbuffer *proxy)
\r
336 if(mProxyRefs == 0)
\r
338 mColorbufferProxy = NULL;
\r
342 GLenum Texture2D::getTarget() const
\r
344 return GL_TEXTURE_2D;
\r
347 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
\r
349 ASSERT(target == GL_TEXTURE_2D);
\r
350 return image[level] ? image[level]->getWidth() : 0;
\r
353 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
\r
355 ASSERT(target == GL_TEXTURE_2D);
\r
356 return image[level] ? image[level]->getHeight() : 0;
\r
359 GLenum Texture2D::getFormat(GLenum target, GLint level) const
\r
361 ASSERT(target == GL_TEXTURE_2D);
\r
362 return image[level] ? image[level]->getFormat() : 0;
\r
365 GLenum Texture2D::getType(GLenum target, GLint level) const
\r
367 ASSERT(target == GL_TEXTURE_2D);
\r
368 return image[level] ? image[level]->getType() : 0;
\r
371 sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
\r
373 ASSERT(target == GL_TEXTURE_2D);
\r
374 return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
\r
377 int Texture2D::getLevelCount() const
\r
379 ASSERT(isSamplerComplete());
\r
382 while(levels < MIPMAP_LEVELS && image[levels])
\r
390 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
\r
394 image[level]->unbind();
\r
397 image[level] = new Image(this, width, height, format, type);
\r
401 return error(GL_OUT_OF_MEMORY);
\r
404 Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
\r
407 void Texture2D::bindTexImage(egl::Surface *surface)
\r
411 switch(surface->getInternalFormat())
\r
413 case sw::FORMAT_A8R8G8B8:
\r
416 case sw::FORMAT_X8R8G8B8:
\r
424 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
428 image[level]->unbind();
\r
433 image[0] = surface->getRenderTarget();
\r
435 mSurface = surface;
\r
436 mSurface->setBoundTexture(this);
\r
439 void Texture2D::releaseTexImage()
\r
441 for(int level = 0; level < MIPMAP_LEVELS; level++)
\r
445 image[level]->unbind();
\r
451 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
\r
455 image[level]->unbind();
\r
458 image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
462 return error(GL_OUT_OF_MEMORY);
\r
465 Texture::setCompressedImage(imageSize, pixels, image[level]);
\r
468 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
\r
470 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
\r
473 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
\r
475 Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
\r
478 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
480 egl::Image *renderTarget = source->getRenderTarget();
\r
484 ERR("Failed to retrieve the render target.");
\r
485 return error(GL_OUT_OF_MEMORY);
\r
490 image[level]->unbind();
\r
493 image[level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
497 return error(GL_OUT_OF_MEMORY);
\r
500 if(width != 0 && height != 0)
\r
502 sw::Rect sourceRect = {x, y, x + width, y + height};
\r
503 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
\r
505 copy(renderTarget, sourceRect, format, 0, 0, image[level]);
\r
508 renderTarget->release();
\r
511 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
515 return error(GL_INVALID_OPERATION);
\r
518 if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
\r
520 return error(GL_INVALID_VALUE);
\r
523 egl::Image *renderTarget = source->getRenderTarget();
\r
527 ERR("Failed to retrieve the render target.");
\r
528 return error(GL_OUT_OF_MEMORY);
\r
531 sw::Rect sourceRect = {x, y, x + width, y + height};
\r
532 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
\r
534 copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
\r
536 renderTarget->release();
\r
539 void Texture2D::setImage(egl::Image *sharedImage)
\r
541 sharedImage->addRef();
\r
545 image[0]->unbind();
\r
548 image[0] = sharedImage;
\r
551 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
\r
552 bool Texture2D::isSamplerComplete() const
\r
559 GLsizei width = image[0]->getWidth();
\r
560 GLsizei height = image[0]->getHeight();
\r
562 if(width <= 0 || height <= 0)
\r
567 if(isMipmapFiltered())
\r
569 if(!isMipmapComplete())
\r
578 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
\r
579 bool Texture2D::isMipmapComplete() const
\r
581 GLsizei width = image[0]->getWidth();
\r
582 GLsizei height = image[0]->getHeight();
\r
584 int q = log2(std::max(width, height));
\r
586 for(int level = 1; level <= q; level++)
\r
593 if(image[level]->getFormat() != image[0]->getFormat())
\r
598 if(image[level]->getType() != image[0]->getType())
\r
603 if(image[level]->getWidth() != std::max(1, width >> level))
\r
608 if(image[level]->getHeight() != std::max(1, height >> level))
\r
617 bool Texture2D::isCompressed(GLenum target, GLint level) const
\r
619 return IsCompressed(getFormat(target, level));
\r
622 bool Texture2D::isDepth(GLenum target, GLint level) const
\r
624 return IsDepthTexture(getFormat(target, level));
\r
627 void Texture2D::generateMipmaps()
\r
631 return; // FIXME: error?
\r
634 unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
\r
636 for(unsigned int i = 1; i <= q; i++)
\r
640 image[i]->unbind();
\r
643 image[i] = new Image(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
\r
647 return error(GL_OUT_OF_MEMORY);
\r
650 getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
\r
654 egl::Image *Texture2D::getImage(unsigned int level)
\r
656 return image[level];
\r
659 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
\r
661 if(target != GL_TEXTURE_2D)
\r
663 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
\r
666 if(mColorbufferProxy == NULL)
\r
668 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this));
\r
671 return mColorbufferProxy;
\r
674 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
\r
676 ASSERT(target == GL_TEXTURE_2D);
\r
677 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
681 image[level]->addRef();
\r
684 return image[level];
\r
687 bool Texture2D::isShared(GLenum target, unsigned int level) const
\r
689 ASSERT(target == GL_TEXTURE_2D);
\r
690 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
692 if(mSurface) // Bound to an EGLSurface
\r
702 return image[level]->isShared();
\r
705 TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
\r
707 for(int f = 0; f < 6; f++)
\r
709 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
715 for(int f = 0; f < 6; f++)
\r
717 mFaceProxies[f] = NULL;
\r
718 mFaceProxyRefs[f] = 0;
\r
722 TextureCubeMap::~TextureCubeMap()
\r
724 resource->lock(sw::DESTRUCT);
\r
726 for(int f = 0; f < 6; f++)
\r
728 for(int i = 0; i < MIPMAP_LEVELS; i++)
\r
732 image[f][i]->unbind();
\r
738 resource->unlock();
\r
740 for(int i = 0; i < 6; i++)
\r
742 mFaceProxies[i] = NULL;
\r
746 // We need to maintain a count of references to renderbuffers acting as
\r
747 // proxies for this texture, so that the texture is not deleted while
\r
748 // proxy references still exist. If the reference count drops to zero,
\r
749 // we set our proxy pointer NULL, so that a new attempt at referencing
\r
750 // will cause recreation.
\r
751 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
\r
753 for(int f = 0; f < 6; f++)
\r
755 if(mFaceProxies[f] == proxy)
\r
757 mFaceProxyRefs[f]++;
\r
762 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
\r
764 for(int f = 0; f < 6; f++)
\r
766 if(mFaceProxies[f] == proxy)
\r
768 if(mFaceProxyRefs[f] > 0)
\r
770 mFaceProxyRefs[f]--;
\r
773 if(mFaceProxyRefs[f] == 0)
\r
775 mFaceProxies[f] = NULL;
\r
781 GLenum TextureCubeMap::getTarget() const
\r
783 return GL_TEXTURE_CUBE_MAP;
\r
786 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
\r
788 int face = CubeFaceIndex(target);
\r
789 return image[face][level] ? image[face][level]->getWidth() : 0;
\r
792 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
\r
794 int face = CubeFaceIndex(target);
\r
795 return image[face][level] ? image[face][level]->getHeight() : 0;
\r
798 GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
\r
800 int face = CubeFaceIndex(target);
\r
801 return image[face][level] ? image[face][level]->getFormat() : 0;
\r
804 GLenum TextureCubeMap::getType(GLenum target, GLint level) const
\r
806 int face = CubeFaceIndex(target);
\r
807 return image[face][level] ? image[face][level]->getType() : 0;
\r
810 sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
\r
812 int face = CubeFaceIndex(target);
\r
813 return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
\r
816 int TextureCubeMap::getLevelCount() const
\r
818 ASSERT(isSamplerComplete());
\r
821 while(levels < MIPMAP_LEVELS && image[0][levels])
\r
829 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
\r
831 int face = CubeFaceIndex(target);
\r
833 if(image[face][level])
\r
835 image[face][level]->unbind();
\r
838 image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
840 if(!image[face][level])
\r
842 return error(GL_OUT_OF_MEMORY);
\r
845 Texture::setCompressedImage(imageSize, pixels, image[face][level]);
\r
848 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
\r
850 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[CubeFaceIndex(target)][level]);
\r
853 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
\r
855 Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
\r
858 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
\r
859 bool TextureCubeMap::isSamplerComplete() const
\r
861 for(int face = 0; face < 6; face++)
\r
863 if(!image[face][0])
\r
869 int size = image[0][0]->getWidth();
\r
876 if(!isMipmapFiltered())
\r
878 if(!isCubeComplete())
\r
885 if(!isMipmapCubeComplete()) // Also tests for isCubeComplete()
\r
894 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
\r
895 bool TextureCubeMap::isCubeComplete() const
\r
897 if(image[0][0]->getWidth() <= 0 || image[0][0]->getHeight() != image[0][0]->getWidth())
\r
902 for(unsigned int face = 1; face < 6; face++)
\r
904 if(image[face][0]->getWidth() != image[0][0]->getWidth() ||
\r
905 image[face][0]->getWidth() != image[0][0]->getHeight() ||
\r
906 image[face][0]->getFormat() != image[0][0]->getFormat() ||
\r
907 image[face][0]->getType() != image[0][0]->getType())
\r
916 bool TextureCubeMap::isMipmapCubeComplete() const
\r
918 if(!isCubeComplete())
\r
923 GLsizei size = image[0][0]->getWidth();
\r
924 int q = log2(size);
\r
926 for(int face = 0; face < 6; face++)
\r
928 for(int level = 1; level <= q; level++)
\r
930 if(!image[face][level])
\r
935 if(image[face][level]->getFormat() != image[0][0]->getFormat())
\r
940 if(image[face][level]->getType() != image[0][0]->getType())
\r
945 if(image[face][level]->getWidth() != std::max(1, size >> level))
\r
955 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
\r
957 return IsCompressed(getFormat(target, level));
\r
960 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
\r
962 return IsDepthTexture(getFormat(target, level));
\r
965 void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
\r
967 int face = CubeFaceIndex(target);
\r
969 if(image[face][level])
\r
971 image[face][level]->unbind();
\r
974 image[face][level] = new Image(this, width, height, format, type);
\r
976 if(!image[face][level])
\r
978 return error(GL_OUT_OF_MEMORY);
\r
981 Texture::setImage(format, type, unpackAlignment, pixels, image[face][level]);
\r
984 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
986 egl::Image *renderTarget = source->getRenderTarget();
\r
990 ERR("Failed to retrieve the render target.");
\r
991 return error(GL_OUT_OF_MEMORY);
\r
994 int face = CubeFaceIndex(target);
\r
996 if(image[face][level])
\r
998 image[face][level]->unbind();
\r
1001 image[face][level] = new Image(this, width, height, format, GL_UNSIGNED_BYTE);
\r
1003 if(!image[face][level])
\r
1005 return error(GL_OUT_OF_MEMORY);
\r
1008 if(width != 0 && height != 0)
\r
1010 sw::Rect sourceRect = {x, y, x + width, y + height};
\r
1011 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
\r
1013 copy(renderTarget, sourceRect, format, 0, 0, image[face][level]);
\r
1016 renderTarget->release();
\r
1019 Image *TextureCubeMap::getImage(int face, unsigned int level)
\r
1021 return image[face][level];
\r
1024 Image *TextureCubeMap::getImage(GLenum face, unsigned int level)
\r
1026 return image[CubeFaceIndex(face)][level];
\r
1029 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
\r
1031 int face = CubeFaceIndex(target);
\r
1033 if(!image[face][level])
\r
1035 return error(GL_INVALID_OPERATION);
\r
1038 GLsizei size = image[face][level]->getWidth();
\r
1040 if(xoffset + width > size || yoffset + height > size)
\r
1042 return error(GL_INVALID_VALUE);
\r
1045 egl::Image *renderTarget = source->getRenderTarget();
\r
1049 ERR("Failed to retrieve the render target.");
\r
1050 return error(GL_OUT_OF_MEMORY);
\r
1053 sw::Rect sourceRect = {x, y, x + width, y + height};
\r
1054 sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
\r
1056 copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, image[face][level]);
\r
1058 renderTarget->release();
\r
1061 void TextureCubeMap::generateMipmaps()
\r
1063 if(!isCubeComplete())
\r
1065 return error(GL_INVALID_OPERATION);
\r
1068 unsigned int q = log2(image[0][0]->getWidth());
\r
1070 for(unsigned int f = 0; f < 6; f++)
\r
1072 for(unsigned int i = 1; i <= q; i++)
\r
1076 image[f][i]->unbind();
\r
1079 image[f][i] = new 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
1083 return error(GL_OUT_OF_MEMORY);
\r
1086 getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
\r
1091 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
\r
1093 if(!IsCubemapTextureTarget(target))
\r
1095 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
\r
1098 int face = CubeFaceIndex(target);
\r
1100 if(mFaceProxies[face] == NULL)
\r
1102 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
\r
1105 return mFaceProxies[face];
\r
1108 Image *TextureCubeMap::getRenderTarget(GLenum target, unsigned int level)
\r
1110 ASSERT(IsCubemapTextureTarget(target));
\r
1111 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1113 int face = CubeFaceIndex(target);
\r
1115 if(image[face][level])
\r
1117 image[face][level]->addRef();
\r
1120 return image[face][level];
\r
1123 bool TextureCubeMap::isShared(GLenum target, unsigned int level) const
\r
1125 ASSERT(IsCubemapTextureTarget(target));
\r
1126 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
\r
1128 int face = CubeFaceIndex(target);
\r
1130 if(!image[face][level])
\r
1135 return image[face][level]->isShared();
\r
1138 TextureExternal::TextureExternal(GLuint id) : Texture2D(id)
\r
1140 mMinFilter = GL_LINEAR;
\r
1141 mMagFilter = GL_LINEAR;
\r
1142 mWrapS = GL_CLAMP_TO_EDGE;
\r
1143 mWrapT = GL_CLAMP_TO_EDGE;
\r
1146 TextureExternal::~TextureExternal()
\r
1150 GLenum TextureExternal::getTarget() const
\r
1152 return GL_TEXTURE_EXTERNAL_OES;
\r
1157 // Exported functions for use by EGL
\r
1160 egl::Image *createBackBuffer(int width, int height, const egl::Config *config)
\r
1164 return new es2::Image(0, width, height, config->mAlphaSize ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);
\r
1170 egl::Image *createDepthStencil(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
\r
1172 if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
\r
1174 ERR("Invalid parameters");
\r
1178 bool lockable = true;
\r
1182 // case sw::FORMAT_D15S1:
\r
1183 case sw::FORMAT_D24S8:
\r
1184 case sw::FORMAT_D24X8:
\r
1185 // case sw::FORMAT_D24X4S4:
\r
1186 case sw::FORMAT_D24FS8:
\r
1187 case sw::FORMAT_D32:
\r
1188 case sw::FORMAT_D16:
\r
1191 // case sw::FORMAT_S8_LOCKABLE:
\r
1192 // case sw::FORMAT_D16_LOCKABLE:
\r
1193 case sw::FORMAT_D32F_LOCKABLE:
\r
1194 // case sw::FORMAT_D32_LOCKABLE:
\r
1195 case sw::FORMAT_DF24S8:
\r
1196 case sw::FORMAT_DF16S8:
\r
1203 es2::Image *surface = new es2::Image(0, width, height, format, multiSampleDepth, lockable, true);
\r
1207 ERR("Out of memory");
\r