1 #include "precompiled.h"
3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
8 // Texture.cpp: Implements the gl::Texture class and its derived classes
9 // Texture2D and TextureCubeMap. Implements GL texture objects and related
10 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
12 #include "libGLESv2/Texture.h"
14 #include "libGLESv2/main.h"
15 #include "common/mathutil.h"
16 #include "common/utilities.h"
17 #include "libGLESv2/formatutils.h"
18 #include "libGLESv2/Renderbuffer.h"
19 #include "libGLESv2/renderer/Image.h"
20 #include "libGLESv2/renderer/Renderer.h"
21 #include "libGLESv2/renderer/TextureStorage.h"
22 #include "libEGL/Surface.h"
23 #include "libGLESv2/Buffer.h"
24 #include "libGLESv2/renderer/BufferStorage.h"
25 #include "libGLESv2/renderer/RenderTarget.h"
30 bool IsMipmapFiltered(const SamplerState &samplerState)
32 switch (samplerState.minFilter)
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
42 default: UNREACHABLE();
47 bool IsRenderTargetUsage(GLenum usage)
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
52 Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
56 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57 mSamplerState.magFilter = GL_LINEAR;
58 mSamplerState.wrapS = GL_REPEAT;
59 mSamplerState.wrapT = GL_REPEAT;
60 mSamplerState.wrapR = GL_REPEAT;
61 mSamplerState.maxAnisotropy = 1.0f;
62 mSamplerState.baseLevel = 0;
63 mSamplerState.maxLevel = 1000;
64 mSamplerState.minLod = -1000.0f;
65 mSamplerState.maxLod = 1000.0f;
66 mSamplerState.compareMode = GL_NONE;
67 mSamplerState.compareFunc = GL_LEQUAL;
68 mSamplerState.swizzleRed = GL_RED;
69 mSamplerState.swizzleGreen = GL_GREEN;
70 mSamplerState.swizzleBlue = GL_BLUE;
71 mSamplerState.swizzleAlpha = GL_ALPHA;
85 GLenum Texture::getTarget() const
90 void Texture::addProxyRef(const FramebufferAttachment *proxy)
92 mRenderbufferProxies.addRef(proxy);
95 void Texture::releaseProxy(const FramebufferAttachment *proxy)
97 mRenderbufferProxies.release(proxy);
100 void Texture::setMinFilter(GLenum filter)
102 mSamplerState.minFilter = filter;
105 void Texture::setMagFilter(GLenum filter)
107 mSamplerState.magFilter = filter;
110 void Texture::setWrapS(GLenum wrap)
112 mSamplerState.wrapS = wrap;
115 void Texture::setWrapT(GLenum wrap)
117 mSamplerState.wrapT = wrap;
120 void Texture::setWrapR(GLenum wrap)
122 mSamplerState.wrapR = wrap;
125 void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
127 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
130 void Texture::setCompareMode(GLenum mode)
132 mSamplerState.compareMode = mode;
135 void Texture::setCompareFunc(GLenum func)
137 mSamplerState.compareFunc = func;
140 void Texture::setSwizzleRed(GLenum swizzle)
142 mSamplerState.swizzleRed = swizzle;
145 void Texture::setSwizzleGreen(GLenum swizzle)
147 mSamplerState.swizzleGreen = swizzle;
150 void Texture::setSwizzleBlue(GLenum swizzle)
152 mSamplerState.swizzleBlue = swizzle;
155 void Texture::setSwizzleAlpha(GLenum swizzle)
157 mSamplerState.swizzleAlpha = swizzle;
160 void Texture::setBaseLevel(GLint baseLevel)
162 mSamplerState.baseLevel = baseLevel;
165 void Texture::setMaxLevel(GLint maxLevel)
167 mSamplerState.maxLevel = maxLevel;
170 void Texture::setMinLod(GLfloat minLod)
172 mSamplerState.minLod = minLod;
175 void Texture::setMaxLod(GLfloat maxLod)
177 mSamplerState.maxLod = maxLod;
180 void Texture::setUsage(GLenum usage)
185 GLenum Texture::getMinFilter() const
187 return mSamplerState.minFilter;
190 GLenum Texture::getMagFilter() const
192 return mSamplerState.magFilter;
195 GLenum Texture::getWrapS() const
197 return mSamplerState.wrapS;
200 GLenum Texture::getWrapT() const
202 return mSamplerState.wrapT;
205 GLenum Texture::getWrapR() const
207 return mSamplerState.wrapR;
210 float Texture::getMaxAnisotropy() const
212 return mSamplerState.maxAnisotropy;
215 GLenum Texture::getSwizzleRed() const
217 return mSamplerState.swizzleRed;
220 GLenum Texture::getSwizzleGreen() const
222 return mSamplerState.swizzleGreen;
225 GLenum Texture::getSwizzleBlue() const
227 return mSamplerState.swizzleBlue;
230 GLenum Texture::getSwizzleAlpha() const
232 return mSamplerState.swizzleAlpha;
235 GLint Texture::getBaseLevel() const
237 return mSamplerState.baseLevel;
240 GLint Texture::getMaxLevel() const
242 return mSamplerState.maxLevel;
245 GLfloat Texture::getMinLod() const
247 return mSamplerState.minLod;
250 GLfloat Texture::getMaxLod() const
252 return mSamplerState.maxLod;
255 bool Texture::isSwizzled() const
257 return mSamplerState.swizzleRed != GL_RED ||
258 mSamplerState.swizzleGreen != GL_GREEN ||
259 mSamplerState.swizzleBlue != GL_BLUE ||
260 mSamplerState.swizzleAlpha != GL_ALPHA;
263 void Texture::getSamplerState(SamplerState *sampler)
265 *sampler = mSamplerState;
267 // Offset the effective base level by the texture storage's top level
268 rx::TextureStorageInterface *texture = getNativeTexture();
269 int topLevel = texture ? texture->getTopLevel() : 0;
270 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
273 GLenum Texture::getUsage() const
278 GLint Texture::getBaseLevelWidth() const
280 const rx::Image *baseImage = getBaseLevelImage();
281 return (baseImage ? baseImage->getWidth() : 0);
284 GLint Texture::getBaseLevelHeight() const
286 const rx::Image *baseImage = getBaseLevelImage();
287 return (baseImage ? baseImage->getHeight() : 0);
290 GLint Texture::getBaseLevelDepth() const
292 const rx::Image *baseImage = getBaseLevelImage();
293 return (baseImage ? baseImage->getDepth() : 0);
296 // Note: "base level image" is loosely defined to be any image from the base level,
297 // where in the base of 2D array textures and cube maps there are several. Don't use
298 // the base level image for anything except querying texture format and size.
299 GLenum Texture::getBaseLevelInternalFormat() const
301 const rx::Image *baseImage = getBaseLevelImage();
302 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
305 void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
308 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
313 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
314 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
315 const void *pixelData = pixels;
317 if (unpack.pixelBuffer.id() != 0)
319 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
320 Buffer *pixelBuffer = unpack.pixelBuffer.get();
321 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
322 const void *bufferData = pixelBuffer->getStorage()->getData();
323 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
326 if (pixelData != NULL)
328 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
333 bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
335 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
338 bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
339 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
341 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
346 // In order to perform the fast copy through the shader, we must have the right format, and be able
347 // to create a render target.
348 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
350 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
352 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
355 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
359 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
364 bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
365 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
367 const void *pixelData = pixels;
369 // CPU readback & copy where direct GPU copy is not supported
370 if (unpack.pixelBuffer.id() != 0)
372 Buffer *pixelBuffer = unpack.pixelBuffer.get();
373 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
374 const void *bufferData = pixelBuffer->getStorage()->getData();
375 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
378 if (pixelData != NULL)
380 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
387 bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
388 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
392 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
399 rx::TextureStorageInterface *Texture::getNativeTexture()
401 // ensure the underlying texture is created
402 initializeStorage(false);
404 rx::TextureStorageInterface *storage = getBaseLevelStorage();
413 bool Texture::hasDirtyImages() const
418 void Texture::resetDirty()
420 mDirtyImages = false;
423 unsigned int Texture::getTextureSerial()
425 rx::TextureStorageInterface *texture = getNativeTexture();
426 return texture ? texture->getTextureSerial() : 0;
429 bool Texture::isImmutable() const
434 int Texture::immutableLevelCount()
436 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
439 GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
441 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
443 // Maximum number of levels
444 return log2(std::max(std::max(width, height), depth)) + 1;
448 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
453 int Texture::mipLevels() const
455 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
458 Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
463 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
465 mImageArray[i] = renderer->createImage();
469 Texture2D::~Texture2D()
476 mSurface->setBoundTexture(NULL);
480 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
482 delete mImageArray[i];
486 GLsizei Texture2D::getWidth(GLint level) const
488 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
489 return mImageArray[level]->getWidth();
494 GLsizei Texture2D::getHeight(GLint level) const
496 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
497 return mImageArray[level]->getHeight();
502 GLenum Texture2D::getInternalFormat(GLint level) const
504 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
505 return mImageArray[level]->getInternalFormat();
510 GLenum Texture2D::getActualFormat(GLint level) const
512 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
513 return mImageArray[level]->getActualFormat();
518 void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
522 // If there currently is a corresponding storage texture image, it has these parameters
523 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
524 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
525 const GLenum storageFormat = getBaseLevelInternalFormat();
527 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
531 const int storageLevels = mTexStorage->getLevelCount();
533 if ((level >= storageLevels && storageLevels != 0) ||
534 width != storageWidth ||
535 height != storageHeight ||
536 internalformat != storageFormat) // Discard mismatched storage
538 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
540 mImageArray[i]->markDirty();
550 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
552 GLuint clientVersion = mRenderer->getCurrentClientVersion();
553 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
554 : GetSizedInternalFormat(format, type, clientVersion);
555 redefineImage(level, sizedInternalFormat, width, height);
557 bool fastUnpacked = false;
559 // Attempt a fast gpu copy of the pixel data to the surface
560 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
562 // Will try to create RT storage if it does not exist
563 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
564 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
566 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
568 // Ensure we don't overwrite our newly initialized data
569 mImageArray[level]->markClean();
577 Texture::setImage(unpack, type, pixels, mImageArray[level]);
581 void Texture2D::bindTexImage(egl::Surface *surface)
585 GLenum internalformat = surface->getFormat();
587 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
590 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
594 mSurface->setBoundTexture(this);
597 void Texture2D::releaseTexImage()
601 mSurface->setBoundTexture(NULL);
610 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
612 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
617 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
619 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
620 redefineImage(level, format, width, height);
622 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
625 void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
627 if (isValidLevel(level))
629 rx::Image *image = mImageArray[level];
630 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
637 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
639 bool fastUnpacked = false;
641 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
643 rx::RenderTarget *renderTarget = getRenderTarget(level);
644 Box destArea(xoffset, yoffset, 0, width, height, 1);
646 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
648 // Ensure we don't overwrite our newly initialized data
649 mImageArray[level]->markClean();
655 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
657 commitRect(level, xoffset, yoffset, width, height);
661 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
663 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
665 commitRect(level, xoffset, yoffset, width, height);
669 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
671 GLuint clientVersion = mRenderer->getCurrentClientVersion();
672 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
673 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
674 redefineImage(level, sizedInternalFormat, width, height);
676 if (!mImageArray[level]->isRenderableFormat())
678 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
683 ensureRenderTarget();
684 mImageArray[level]->markClean();
686 if (width != 0 && height != 0 && isValidLevel(level))
688 gl::Rectangle sourceRect;
690 sourceRect.width = width;
692 sourceRect.height = height;
694 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
699 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
701 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
702 // the current level we're copying to is defined (with appropriate format, width & height)
703 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
705 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
707 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
712 ensureRenderTarget();
714 if (isValidLevel(level))
716 updateStorageLevel(level);
718 GLuint clientVersion = mRenderer->getCurrentClientVersion();
720 gl::Rectangle sourceRect;
722 sourceRect.width = width;
724 sourceRect.height = height;
726 mRenderer->copyImage(source, sourceRect,
727 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
728 xoffset, yoffset, mTexStorage, level);
733 void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
735 for (int level = 0; level < levels; level++)
737 GLsizei levelWidth = std::max(1, width >> level);
738 GLsizei levelHeight = std::max(1, height >> level);
739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
742 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
744 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
749 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
752 void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
754 SafeDelete(mTexStorage);
755 mTexStorage = newCompleteTexStorage;
757 if (mTexStorage && mTexStorage->isManaged())
759 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
761 mImageArray[level]->setManagedSurface(mTexStorage, level);
768 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
769 bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
771 GLsizei width = getBaseLevelWidth();
772 GLsizei height = getBaseLevelHeight();
774 if (width <= 0 || height <= 0)
779 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
781 if (samplerState.magFilter != GL_NEAREST ||
782 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
788 bool npotSupport = mRenderer->getNonPower2TextureSupport();
792 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
793 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
799 if (IsMipmapFiltered(samplerState))
803 if (!isPow2(width) || !isPow2(height))
809 if (!isMipmapComplete())
815 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
816 // The internalformat specified for the texture arrays is a sized internal depth or
817 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
818 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
819 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
820 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
821 mRenderer->getCurrentClientVersion() > 2)
823 if (mSamplerState.compareMode == GL_NONE)
825 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
826 mSamplerState.magFilter != GL_NEAREST)
836 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
837 bool Texture2D::isMipmapComplete() const
839 int levelCount = mipLevels();
841 for (int level = 0; level < levelCount; level++)
843 if (!isLevelComplete(level))
852 bool Texture2D::isLevelComplete(int level) const
859 const rx::Image *baseImage = getBaseLevelImage();
861 GLsizei width = baseImage->getWidth();
862 GLsizei height = baseImage->getHeight();
864 if (width <= 0 || height <= 0)
869 // The base image level is complete if the width and height are positive
875 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
876 rx::Image *image = mImageArray[level];
878 if (image->getInternalFormat() != baseImage->getInternalFormat())
883 if (image->getWidth() != std::max(1, width >> level))
888 if (image->getHeight() != std::max(1, height >> level))
896 bool Texture2D::isCompressed(GLint level) const
898 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
901 bool Texture2D::isDepth(GLint level) const
903 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
906 // Constructs a native texture resource from the texture images
907 void Texture2D::initializeStorage(bool renderTarget)
909 // Only initialize the first time this texture is used as a render target or shader resource
915 // do not attempt to create storage for nonexistant data
916 if (!isLevelComplete(0))
921 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
923 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
926 // flush image data to the storage
930 rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
932 GLsizei width = getBaseLevelWidth();
933 GLsizei height = getBaseLevelHeight();
935 ASSERT(width > 0 && height > 0);
937 // use existing storage level count, when previously specified by TexStorage*D
938 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
940 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
943 void Texture2D::updateStorage()
945 ASSERT(mTexStorage != NULL);
946 GLint storageLevels = mTexStorage->getLevelCount();
947 for (int level = 0; level < storageLevels; level++)
949 if (mImageArray[level]->isDirty() && isLevelComplete(level))
951 updateStorageLevel(level);
956 void Texture2D::updateStorageLevel(int level)
958 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
959 ASSERT(isLevelComplete(level));
961 if (mImageArray[level]->isDirty())
963 commitRect(level, 0, 0, getWidth(level), getHeight(level));
967 bool Texture2D::ensureRenderTarget()
969 initializeStorage(true);
971 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
974 if (!mTexStorage->isRenderTarget())
976 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
978 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
980 delete newRenderTargetStorage;
981 return gl::error(GL_OUT_OF_MEMORY, false);
984 setCompleteTexStorage(newRenderTargetStorage);
988 return (mTexStorage && mTexStorage->isRenderTarget());
991 void Texture2D::generateMipmaps()
993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
994 int levelCount = mipLevels();
995 for (int level = 1; level < levelCount; level++)
997 redefineImage(level, getBaseLevelInternalFormat(),
998 std::max(getBaseLevelWidth() >> level, 1),
999 std::max(getBaseLevelHeight() >> level, 1));
1002 if (mTexStorage && mTexStorage->isRenderTarget())
1004 for (int level = 1; level < levelCount; level++)
1006 mTexStorage->generateMipmap(level);
1008 mImageArray[level]->markClean();
1013 for (int level = 1; level < levelCount; level++)
1015 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1020 const rx::Image *Texture2D::getBaseLevelImage() const
1022 return mImageArray[0];
1025 rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
1030 FramebufferAttachment *Texture2D::getAttachment(GLint level)
1032 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, 0);
1035 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DAttachment(this, level));
1036 mRenderbufferProxies.add(level, 0, attachment);
1042 unsigned int Texture2D::getRenderTargetSerial(GLint level)
1044 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
1047 rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1049 // ensure the underlying texture is created
1050 if (!ensureRenderTarget())
1055 updateStorageLevel(level);
1057 // ensure this is NOT a depth texture
1063 return mTexStorage->getRenderTarget(level);
1066 rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
1068 // ensure the underlying texture is created
1069 if (!ensureRenderTarget())
1074 updateStorageLevel(level);
1076 // ensure this is actually a depth texture
1077 if (!isDepth(level))
1082 return mTexStorage->getRenderTarget(level);
1085 bool Texture2D::isValidLevel(int level) const
1087 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1090 TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
1093 for (int i = 0; i < 6; i++)
1095 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1097 mImageArray[i][j] = renderer->createImage();
1102 TextureCubeMap::~TextureCubeMap()
1104 for (int i = 0; i < 6; i++)
1106 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1108 delete mImageArray[i][j];
1116 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1118 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1119 return mImageArray[targetToIndex(target)][level]->getWidth();
1124 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1126 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1127 return mImageArray[targetToIndex(target)][level]->getHeight();
1132 GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1134 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1135 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
1140 GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
1142 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1143 return mImageArray[targetToIndex(target)][level]->getActualFormat();
1148 void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1150 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
1153 void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1155 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
1158 void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1160 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
1163 void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1165 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
1168 void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1170 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
1173 void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1175 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
1178 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1180 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1181 int faceIndex = targetToIndex(target);
1182 redefineImage(faceIndex, level, format, width, height);
1184 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
1187 void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1189 if (isValidFaceLevel(faceIndex, level))
1191 rx::Image *image = mImageArray[faceIndex][level];
1192 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1197 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1199 int faceIndex = targetToIndex(target);
1200 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
1202 commitRect(faceIndex, level, xoffset, yoffset, width, height);
1206 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1208 int faceIndex = targetToIndex(target);
1209 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
1211 commitRect(faceIndex, level, xoffset, yoffset, width, height);
1215 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1216 bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
1218 int size = getBaseLevelWidth();
1220 bool mipmapping = IsMipmapFiltered(samplerState);
1222 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
1224 if (samplerState.magFilter != GL_NEAREST ||
1225 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1231 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
1233 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
1241 if (!isCubeComplete())
1248 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1257 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1258 bool TextureCubeMap::isCubeComplete() const
1260 int baseWidth = getBaseLevelWidth();
1261 int baseHeight = getBaseLevelHeight();
1262 GLenum baseFormat = getBaseLevelInternalFormat();
1264 if (baseWidth <= 0 || baseWidth != baseHeight)
1269 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1271 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
1273 if (faceBaseImage.getWidth() != baseWidth ||
1274 faceBaseImage.getHeight() != baseHeight ||
1275 faceBaseImage.getInternalFormat() != baseFormat )
1284 bool TextureCubeMap::isMipmapCubeComplete() const
1291 if (!isCubeComplete())
1296 int levelCount = mipLevels();
1298 for (int face = 0; face < 6; face++)
1300 for (int level = 1; level < levelCount; level++)
1302 if (!isFaceLevelComplete(face, level))
1312 bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
1314 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1321 int baseSize = getBaseLevelWidth();
1328 // "isCubeComplete" checks for base level completeness and we must call that
1329 // to determine if any face at level 0 is complete. We omit that check here
1330 // to avoid re-checking cube-completeness for every face at level 0.
1336 // Check that non-zero levels are consistent with the base level.
1337 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
1339 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1344 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1352 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1354 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
1357 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1359 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1362 void TextureCubeMap::initializeStorage(bool renderTarget)
1364 // Only initialize the first time this texture is used as a render target or shader resource
1370 // do not attempt to create storage for nonexistant data
1371 if (!isFaceLevelComplete(0, 0))
1376 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1378 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1379 ASSERT(mTexStorage);
1381 // flush image data to the storage
1385 rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1387 GLsizei size = getBaseLevelWidth();
1391 // use existing storage level count, when previously specified by TexStorage*D
1392 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1394 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1397 void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1399 SafeDelete(mTexStorage);
1400 mTexStorage = newCompleteTexStorage;
1402 if (mTexStorage && mTexStorage->isManaged())
1404 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1406 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1408 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1413 mDirtyImages = true;
1416 void TextureCubeMap::updateStorage()
1418 ASSERT(mTexStorage != NULL);
1419 GLint storageLevels = mTexStorage->getLevelCount();
1420 for (int face = 0; face < 6; face++)
1422 for (int level = 0; level < storageLevels; level++)
1424 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1426 updateStorageFaceLevel(face, level);
1432 void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
1434 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1435 rx::Image *image = mImageArray[faceIndex][level];
1437 if (image->isDirty())
1439 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1443 bool TextureCubeMap::ensureRenderTarget()
1445 initializeStorage(true);
1447 if (getBaseLevelWidth() > 0)
1449 ASSERT(mTexStorage);
1450 if (!mTexStorage->isRenderTarget())
1452 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1454 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1456 delete newRenderTargetStorage;
1457 return gl::error(GL_OUT_OF_MEMORY, false);
1460 setCompleteTexStorage(newRenderTargetStorage);
1464 return (mTexStorage && mTexStorage->isRenderTarget());
1467 void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1469 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1470 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1471 : GetSizedInternalFormat(format, type, clientVersion);
1473 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1475 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
1478 int TextureCubeMap::targetToIndex(GLenum target)
1480 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1481 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1482 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1483 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1484 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1486 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1489 void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1491 // If there currently is a corresponding storage texture image, it has these parameters
1492 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1493 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1494 const GLenum storageFormat = getBaseLevelInternalFormat();
1496 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1500 const int storageLevels = mTexStorage->getLevelCount();
1502 if ((level >= storageLevels && storageLevels != 0) ||
1503 width != storageWidth ||
1504 height != storageHeight ||
1505 internalformat != storageFormat) // Discard mismatched storage
1507 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1509 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1511 mImageArray[faceIndex][level]->markDirty();
1518 mDirtyImages = true;
1523 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1525 int faceIndex = targetToIndex(target);
1526 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1527 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1528 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1529 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1531 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1533 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1534 mDirtyImages = true;
1538 ensureRenderTarget();
1539 mImageArray[faceIndex][level]->markClean();
1541 ASSERT(width == height);
1543 if (width > 0 && isValidFaceLevel(faceIndex, level))
1545 gl::Rectangle sourceRect;
1547 sourceRect.width = width;
1549 sourceRect.height = height;
1551 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1556 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1558 int faceIndex = targetToIndex(target);
1560 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1561 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1562 // rely on the "getBaseLevel*" methods reliably otherwise.
1563 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1565 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1567 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1568 mDirtyImages = true;
1572 ensureRenderTarget();
1574 if (isValidFaceLevel(faceIndex, level))
1576 updateStorageFaceLevel(faceIndex, level);
1578 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1580 gl::Rectangle sourceRect;
1582 sourceRect.width = width;
1584 sourceRect.height = height;
1586 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1587 xoffset, yoffset, mTexStorage, target, level);
1592 void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1594 for (int level = 0; level < levels; level++)
1596 GLsizei mipSize = std::max(1, size >> level);
1597 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1599 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1603 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1605 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1607 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1613 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
1616 void TextureCubeMap::generateMipmaps()
1618 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1619 int levelCount = mipLevels();
1620 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1622 for (int level = 1; level < levelCount; level++)
1624 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1625 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1629 if (mTexStorage && mTexStorage->isRenderTarget())
1631 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1633 for (int level = 1; level < levelCount; level++)
1635 mTexStorage->generateMipmap(faceIndex, level);
1637 mImageArray[faceIndex][level]->markClean();
1643 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1645 for (int level = 1; level < levelCount; level++)
1647 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1653 const rx::Image *TextureCubeMap::getBaseLevelImage() const
1655 // Note: if we are not cube-complete, there is no single base level image that can describe all
1656 // cube faces, so this method is only well-defined for a cube-complete base level.
1657 return mImageArray[0][0];
1660 rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1665 FramebufferAttachment *TextureCubeMap::getAttachment(GLenum target, GLint level)
1667 ASSERT(!IsCubemapTextureTarget(target));
1668 int faceIndex = targetToIndex(target);
1670 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, faceIndex);
1673 attachment = new FramebufferAttachment(mRenderer, id(), new TextureCubeMapAttachment(this, target, level));
1674 mRenderbufferProxies.add(level, faceIndex, attachment);
1680 unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
1682 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1685 rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
1687 ASSERT(IsCubemapTextureTarget(target));
1689 // ensure the underlying texture is created
1690 if (!ensureRenderTarget())
1695 updateStorageFaceLevel(targetToIndex(target), level);
1697 // ensure this is NOT a depth texture
1698 if (isDepth(target, level))
1703 return mTexStorage->getRenderTarget(target, level);
1706 rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1708 ASSERT(IsCubemapTextureTarget(target));
1710 // ensure the underlying texture is created
1711 if (!ensureRenderTarget())
1716 updateStorageFaceLevel(targetToIndex(target), level);
1718 // ensure this is a depth texture
1719 if (!isDepth(target, level))
1724 return mTexStorage->getRenderTarget(target, level);
1727 bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
1729 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1732 Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
1736 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1738 mImageArray[i] = renderer->createImage();
1742 Texture3D::~Texture3D()
1747 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1749 delete mImageArray[i];
1753 GLsizei Texture3D::getWidth(GLint level) const
1755 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1758 GLsizei Texture3D::getHeight(GLint level) const
1760 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1763 GLsizei Texture3D::getDepth(GLint level) const
1765 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1768 GLenum Texture3D::getInternalFormat(GLint level) const
1770 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1773 GLenum Texture3D::getActualFormat(GLint level) const
1775 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
1778 bool Texture3D::isCompressed(GLint level) const
1780 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
1783 bool Texture3D::isDepth(GLint level) const
1785 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
1788 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1790 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1791 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1792 : GetSizedInternalFormat(format, type, clientVersion);
1793 redefineImage(level, sizedInternalFormat, width, height, depth);
1795 bool fastUnpacked = false;
1797 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1798 if (isFastUnpackable(unpack, sizedInternalFormat))
1800 // Will try to create RT storage if it does not exist
1801 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1802 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1804 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1806 // Ensure we don't overwrite our newly initialized data
1807 mImageArray[level]->markClean();
1809 fastUnpacked = true;
1815 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1819 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1822 redefineImage(level, format, width, height, depth);
1824 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1827 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1829 bool fastUnpacked = false;
1831 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1832 if (isFastUnpackable(unpack, getInternalFormat(level)))
1834 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1835 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1837 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1839 // Ensure we don't overwrite our newly initialized data
1840 mImageArray[level]->markClean();
1842 fastUnpacked = true;
1846 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1848 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1852 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1854 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1856 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1860 void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1862 for (int level = 0; level < levels; level++)
1864 GLsizei levelWidth = std::max(1, width >> level);
1865 GLsizei levelHeight = std::max(1, height >> level);
1866 GLsizei levelDepth = std::max(1, depth >> level);
1867 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1870 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1872 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1877 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1880 void Texture3D::generateMipmaps()
1882 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1883 int levelCount = mipLevels();
1884 for (int level = 1; level < levelCount; level++)
1886 redefineImage(level, getBaseLevelInternalFormat(),
1887 std::max(getBaseLevelWidth() >> level, 1),
1888 std::max(getBaseLevelHeight() >> level, 1),
1889 std::max(getBaseLevelDepth() >> level, 1));
1892 if (mTexStorage && mTexStorage->isRenderTarget())
1894 for (int level = 1; level < levelCount; level++)
1896 mTexStorage->generateMipmap(level);
1898 mImageArray[level]->markClean();
1903 for (int level = 1; level < levelCount; level++)
1905 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1910 const rx::Image *Texture3D::getBaseLevelImage() const
1912 return mImageArray[0];
1915 rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1920 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1922 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1923 // the current level we're copying to is defined (with appropriate format, width & height)
1924 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1926 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1928 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1929 mDirtyImages = true;
1933 ensureRenderTarget();
1935 if (isValidLevel(level))
1937 updateStorageLevel(level);
1939 gl::Rectangle sourceRect;
1941 sourceRect.width = width;
1943 sourceRect.height = height;
1945 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1947 mRenderer->copyImage(source, sourceRect,
1948 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1949 xoffset, yoffset, zoffset, mTexStorage, level);
1954 bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
1956 GLsizei width = getBaseLevelWidth();
1957 GLsizei height = getBaseLevelHeight();
1958 GLsizei depth = getBaseLevelDepth();
1960 if (width <= 0 || height <= 0 || depth <= 0)
1965 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
1967 if (samplerState.magFilter != GL_NEAREST ||
1968 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1974 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
1982 bool Texture3D::isMipmapComplete() const
1984 int levelCount = mipLevels();
1986 for (int level = 0; level < levelCount; level++)
1988 if (!isLevelComplete(level))
1997 bool Texture3D::isLevelComplete(int level) const
1999 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2006 GLsizei width = getBaseLevelWidth();
2007 GLsizei height = getBaseLevelHeight();
2008 GLsizei depth = getBaseLevelDepth();
2010 if (width <= 0 || height <= 0 || depth <= 0)
2020 rx::Image *levelImage = mImageArray[level];
2022 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2027 if (levelImage->getWidth() != std::max(1, width >> level))
2032 if (levelImage->getHeight() != std::max(1, height >> level))
2037 if (levelImage->getDepth() != std::max(1, depth >> level))
2045 FramebufferAttachment *Texture3D::getAttachment(GLint level, GLint layer)
2047 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2050 attachment = new FramebufferAttachment(mRenderer, id(), new Texture3DAttachment(this, level, layer));
2051 mRenderbufferProxies.add(level, 0, attachment);
2057 unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2059 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2062 bool Texture3D::isValidLevel(int level) const
2064 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2067 void Texture3D::initializeStorage(bool renderTarget)
2069 // Only initialize the first time this texture is used as a render target or shader resource
2075 // do not attempt to create storage for nonexistant data
2076 if (!isLevelComplete(0))
2081 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2083 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2084 ASSERT(mTexStorage);
2086 // flush image data to the storage
2090 rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2092 GLsizei width = getBaseLevelWidth();
2093 GLsizei height = getBaseLevelHeight();
2094 GLsizei depth = getBaseLevelDepth();
2096 ASSERT(width > 0 && height > 0 && depth > 0);
2098 // use existing storage level count, when previously specified by TexStorage*D
2099 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2101 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2104 void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2106 SafeDelete(mTexStorage);
2107 mTexStorage = newCompleteTexStorage;
2108 mDirtyImages = true;
2110 // We do not support managed 3D storage, as that is D3D9/ES2-only
2111 ASSERT(!mTexStorage->isManaged());
2114 void Texture3D::updateStorage()
2116 ASSERT(mTexStorage != NULL);
2117 GLint storageLevels = mTexStorage->getLevelCount();
2118 for (int level = 0; level < storageLevels; level++)
2120 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2122 updateStorageLevel(level);
2127 void Texture3D::updateStorageLevel(int level)
2129 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2130 ASSERT(isLevelComplete(level));
2132 if (mImageArray[level]->isDirty())
2134 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2138 bool Texture3D::ensureRenderTarget()
2140 initializeStorage(true);
2142 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
2144 ASSERT(mTexStorage);
2145 if (!mTexStorage->isRenderTarget())
2147 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2151 delete newRenderTargetStorage;
2152 return gl::error(GL_OUT_OF_MEMORY, false);
2155 setCompleteTexStorage(newRenderTargetStorage);
2159 return (mTexStorage && mTexStorage->isRenderTarget());
2162 rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2164 // ensure the underlying texture is created
2165 if (!ensureRenderTarget())
2170 updateStorageLevel(level);
2172 // ensure this is NOT a depth texture
2178 return mTexStorage->getRenderTarget(level);
2181 rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
2183 // ensure the underlying texture is created
2184 if (!ensureRenderTarget())
2191 // ensure this is NOT a depth texture
2197 return mTexStorage->getRenderTarget(level, layer);
2200 rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2202 // ensure the underlying texture is created
2203 if (!ensureRenderTarget())
2208 updateStorageLevel(level);
2210 // ensure this is a depth texture
2211 if (!isDepth(level))
2216 return mTexStorage->getRenderTarget(level, layer);
2219 void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2221 // If there currently is a corresponding storage texture image, it has these parameters
2222 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2223 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2224 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2225 const GLenum storageFormat = getBaseLevelInternalFormat();
2227 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2231 const int storageLevels = mTexStorage->getLevelCount();
2233 if ((level >= storageLevels && storageLevels != 0) ||
2234 width != storageWidth ||
2235 height != storageHeight ||
2236 depth != storageDepth ||
2237 internalformat != storageFormat) // Discard mismatched storage
2239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2241 mImageArray[i]->markDirty();
2246 mDirtyImages = true;
2251 void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2253 if (isValidLevel(level))
2255 rx::Image *image = mImageArray[level];
2256 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2263 Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
2267 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2269 mLayerCounts[level] = 0;
2270 mImageArray[level] = NULL;
2274 Texture2DArray::~Texture2DArray()
2282 void Texture2DArray::deleteImages()
2284 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2286 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2288 delete mImageArray[level][layer];
2290 delete[] mImageArray[level];
2291 mImageArray[level] = NULL;
2292 mLayerCounts[level] = 0;
2296 GLsizei Texture2DArray::getWidth(GLint level) const
2298 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2301 GLsizei Texture2DArray::getHeight(GLint level) const
2303 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2306 GLsizei Texture2DArray::getLayers(GLint level) const
2308 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
2311 GLenum Texture2DArray::getInternalFormat(GLint level) const
2313 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2316 GLenum Texture2DArray::getActualFormat(GLint level) const
2318 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
2321 bool Texture2DArray::isCompressed(GLint level) const
2323 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
2326 bool Texture2DArray::isDepth(GLint level) const
2328 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
2331 void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2333 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2334 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2335 : GetSizedInternalFormat(format, type, clientVersion);
2336 redefineImage(level, sizedInternalFormat, width, height, depth);
2338 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
2340 for (int i = 0; i < depth; i++)
2342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2343 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2347 void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2349 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2350 redefineImage(level, format, width, height, depth);
2352 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2353 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2355 for (int i = 0; i < depth; i++)
2357 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2358 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2362 void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2364 GLenum internalformat = getInternalFormat(level);
2365 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2366 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
2368 for (int i = 0; i < depth; i++)
2370 int layer = zoffset + i;
2371 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2373 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
2375 commitRect(level, xoffset, yoffset, layer, width, height);
2380 void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2382 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2383 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2385 for (int i = 0; i < depth; i++)
2387 int layer = zoffset + i;
2388 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2390 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2392 commitRect(level, xoffset, yoffset, layer, width, height);
2397 void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2401 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2403 GLsizei levelWidth = std::max(1, width >> level);
2404 GLsizei levelHeight = std::max(1, height >> level);
2406 mLayerCounts[level] = (level < levels ? depth : 0);
2408 if (mLayerCounts[level] > 0)
2410 // Create new images for this level
2411 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
2413 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2415 mImageArray[level][layer] = mRenderer->createImage();
2416 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2417 levelHeight, 1, true);
2423 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
2426 void Texture2DArray::generateMipmaps()
2428 int baseWidth = getBaseLevelWidth();
2429 int baseHeight = getBaseLevelHeight();
2430 int baseDepth = getBaseLevelDepth();
2431 GLenum baseFormat = getBaseLevelInternalFormat();
2433 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2434 int levelCount = mipLevels();
2435 for (int level = 1; level < levelCount; level++)
2437 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2440 if (mTexStorage && mTexStorage->isRenderTarget())
2442 for (int level = 1; level < levelCount; level++)
2444 mTexStorage->generateMipmap(level);
2446 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2448 mImageArray[level][layer]->markClean();
2454 for (int level = 1; level < levelCount; level++)
2456 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2458 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2464 const rx::Image *Texture2DArray::getBaseLevelImage() const
2466 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2469 rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2474 void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2476 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2477 // the current level we're copying to is defined (with appropriate format, width & height)
2478 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2480 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2482 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2483 mDirtyImages = true;
2487 ensureRenderTarget();
2489 if (isValidLevel(level))
2491 updateStorageLevel(level);
2493 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2495 gl::Rectangle sourceRect;
2497 sourceRect.width = width;
2499 sourceRect.height = height;
2501 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
2502 xoffset, yoffset, zoffset, mTexStorage, level);
2507 bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
2509 GLsizei width = getBaseLevelWidth();
2510 GLsizei height = getBaseLevelHeight();
2511 GLsizei depth = getLayers(0);
2513 if (width <= 0 || height <= 0 || depth <= 0)
2518 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
2520 if (samplerState.magFilter != GL_NEAREST ||
2521 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2527 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
2535 bool Texture2DArray::isMipmapComplete() const
2537 int levelCount = mipLevels();
2539 for (int level = 1; level < levelCount; level++)
2541 if (!isLevelComplete(level))
2550 bool Texture2DArray::isLevelComplete(int level) const
2552 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2559 GLsizei width = getBaseLevelWidth();
2560 GLsizei height = getBaseLevelHeight();
2561 GLsizei layers = getLayers(0);
2563 if (width <= 0 || height <= 0 || layers <= 0)
2573 if (getInternalFormat(level) != getInternalFormat(0))
2578 if (getWidth(level) != std::max(1, width >> level))
2583 if (getHeight(level) != std::max(1, height >> level))
2588 if (getLayers(level) != layers)
2596 FramebufferAttachment *Texture2DArray::getAttachment(GLint level, GLint layer)
2598 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2601 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DArrayAttachment(this, level, layer));
2602 mRenderbufferProxies.add(level, 0, attachment);
2608 unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
2610 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2613 bool Texture2DArray::isValidLevel(int level) const
2615 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2618 void Texture2DArray::initializeStorage(bool renderTarget)
2620 // Only initialize the first time this texture is used as a render target or shader resource
2626 // do not attempt to create storage for nonexistant data
2627 if (!isLevelComplete(0))
2632 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2634 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2635 ASSERT(mTexStorage);
2637 // flush image data to the storage
2641 rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2643 GLsizei width = getBaseLevelWidth();
2644 GLsizei height = getBaseLevelHeight();
2645 GLsizei depth = getLayers(0);
2647 ASSERT(width > 0 && height > 0 && depth > 0);
2649 // use existing storage level count, when previously specified by TexStorage*D
2650 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2652 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2655 void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2657 SafeDelete(mTexStorage);
2658 mTexStorage = newCompleteTexStorage;
2659 mDirtyImages = true;
2661 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2662 ASSERT(!mTexStorage->isManaged());
2665 void Texture2DArray::updateStorage()
2667 ASSERT(mTexStorage != NULL);
2668 GLint storageLevels = mTexStorage->getLevelCount();
2669 for (int level = 0; level < storageLevels; level++)
2671 if (isLevelComplete(level))
2673 updateStorageLevel(level);
2678 void Texture2DArray::updateStorageLevel(int level)
2680 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2681 ASSERT(isLevelComplete(level));
2683 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2685 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2686 if (mImageArray[level][layer]->isDirty())
2688 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2693 bool Texture2DArray::ensureRenderTarget()
2695 initializeStorage(true);
2697 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2699 ASSERT(mTexStorage);
2700 if (!mTexStorage->isRenderTarget())
2702 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2704 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2706 delete newRenderTargetStorage;
2707 return gl::error(GL_OUT_OF_MEMORY, false);
2710 setCompleteTexStorage(newRenderTargetStorage);
2714 return (mTexStorage && mTexStorage->isRenderTarget());
2717 rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
2719 // ensure the underlying texture is created
2720 if (!ensureRenderTarget())
2725 updateStorageLevel(level);
2727 // ensure this is NOT a depth texture
2733 return mTexStorage->getRenderTarget(level, layer);
2736 rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2738 // ensure the underlying texture is created
2739 if (!ensureRenderTarget())
2744 updateStorageLevel(level);
2746 // ensure this is a depth texture
2747 if (!isDepth(level))
2752 return mTexStorage->getRenderTarget(level, layer);
2755 void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2757 // If there currently is a corresponding storage texture image, it has these parameters
2758 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2759 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2760 const int storageDepth = getLayers(0);
2761 const GLenum storageFormat = getBaseLevelInternalFormat();
2763 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2765 delete mImageArray[level][layer];
2767 delete[] mImageArray[level];
2768 mImageArray[level] = NULL;
2769 mLayerCounts[level] = depth;
2773 mImageArray[level] = new rx::Image*[depth]();
2775 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2777 mImageArray[level][layer] = mRenderer->createImage();
2778 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2784 const int storageLevels = mTexStorage->getLevelCount();
2786 if ((level >= storageLevels && storageLevels != 0) ||
2787 width != storageWidth ||
2788 height != storageHeight ||
2789 depth != storageDepth ||
2790 internalformat != storageFormat) // Discard mismatched storage
2792 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2794 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2796 mImageArray[level][layer]->markDirty();
2802 mDirtyImages = true;
2807 void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2809 if (isValidLevel(level) && layerTarget < getLayers(level))
2811 rx::Image *image = mImageArray[level][layerTarget];
2812 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))