diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/Texture.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libGLESv2/Texture.cpp | 1491 |
1 files changed, 375 insertions, 1116 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp index 3257d05dd4..b0c0ee51bd 100644 --- a/src/3rdparty/angle/src/libGLESv2/Texture.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Texture.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -12,168 +12,49 @@ #include "libGLESv2/Texture.h" #include "libGLESv2/main.h" -#include "libGLESv2/mathutil.h" -#include "libGLESv2/utilities.h" -#if defined(ANGLE_ENABLE_D3D9) -# include "libGLESv2/renderer/d3d9/Blit.h" -#else -# define D3DFMT_UNKNOWN DXGI_FORMAT_UNKNOWN -#endif +#include "common/mathutil.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/renderer/Image.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/TextureStorage.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" #include "libEGL/Surface.h" +#include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/renderer/TextureImpl.h" namespace gl { -Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id) +Texture::Texture(GLuint id, GLenum target) + : RefCountObject(id), + mUsage(GL_NONE), + mImmutable(false), + mTarget(target) { - mRenderer = renderer; - - mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR; - mSamplerState.magFilter = GL_LINEAR; - mSamplerState.wrapS = GL_REPEAT; - mSamplerState.wrapT = GL_REPEAT; - mSamplerState.maxAnisotropy = 1.0f; - mSamplerState.lodOffset = 0; - mUsage = GL_NONE; - - mDirtyImages = true; - - mImmutable = false; } Texture::~Texture() { } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMinFilter(GLenum filter) -{ - switch (filter) - { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - mSamplerState.minFilter = filter; - return true; - default: - return false; - } -} - -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMagFilter(GLenum filter) +GLenum Texture::getTarget() const { - switch (filter) - { - case GL_NEAREST: - case GL_LINEAR: - mSamplerState.magFilter = filter; - return true; - default: - return false; - } + return mTarget; } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapS(GLenum wrap) +void Texture::setUsage(GLenum usage) { - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - mSamplerState.wrapS = wrap; - return true; - default: - return false; - } + mUsage = usage; } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapT(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - mSamplerState.wrapT = wrap; - return true; - default: - return false; - } -} - -// Returns true on successful max anisotropy update (valid anisotropy value) -bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) -{ - textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); - if (textureMaxAnisotropy < 1.0f) - { - return false; - } - - mSamplerState.maxAnisotropy = textureMaxAnisotropy; - - return true; -} - -// Returns true on successful usage state update (valid enum parameter) -bool Texture::setUsage(GLenum usage) -{ - switch (usage) - { - case GL_NONE: - case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: - mUsage = usage; - return true; - default: - return false; - } -} - -GLenum Texture::getMinFilter() const -{ - return mSamplerState.minFilter; -} - -GLenum Texture::getMagFilter() const -{ - return mSamplerState.magFilter; -} - -GLenum Texture::getWrapS() const -{ - return mSamplerState.wrapS; -} - -GLenum Texture::getWrapT() const -{ - return mSamplerState.wrapT; -} - -float Texture::getMaxAnisotropy() const -{ - return mSamplerState.maxAnisotropy; -} - -int Texture::getLodOffset() -{ - rx::TextureStorageInterface *texture = getStorage(false); - return texture ? texture->getLodOffset() : 0; -} - -void Texture::getSamplerState(SamplerState *sampler) +void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler) { *sampler = mSamplerState; - sampler->lodOffset = getLodOffset(); + + // Offset the effective base level by the texture storage's top level + rx::TextureStorageInterface *texture = getNativeTexture(); + int topLevel = texture ? texture->getTopLevel() : 0; + sampler->baseLevel = topLevel + mSamplerState.baseLevel; } GLenum Texture::getUsage() const @@ -181,179 +62,97 @@ GLenum Texture::getUsage() const return mUsage; } -bool Texture::isMipmapFiltered() const +GLint Texture::getBaseLevelWidth() const { - switch (mSamplerState.minFilter) - { - case GL_NEAREST: - case GL_LINEAR: - return false; - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: UNREACHABLE(); - return false; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getWidth() : 0); } -void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image) +GLint Texture::getBaseLevelHeight() const { - if (pixels != NULL) - { - image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels); - mDirtyImages = true; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getHeight() : 0); } -void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image) +GLint Texture::getBaseLevelDepth() const { - if (pixels != NULL) - { - image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels); - mDirtyImages = true; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getDepth() : 0); } -bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image) +// Note: "base level image" is loosely defined to be any image from the base level, +// where in the base of 2D array textures and cube maps there are several. Don't use +// the base level image for anything except querying texture format and size. +GLenum Texture::getBaseLevelInternalFormat() const { - if (pixels != NULL) - { - image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels); - mDirtyImages = true; - } - - return true; -} - -bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image) -{ - if (pixels != NULL) - { - image->loadCompressedData(xoffset, yoffset, width, height, pixels); - mDirtyImages = true; - } - - return true; -} - -rx::TextureStorageInterface *Texture::getNativeTexture() -{ - // ensure the underlying texture is created - - rx::TextureStorageInterface *storage = getStorage(false); - if (storage) - { - updateTexture(); - } - - return storage; -} - -bool Texture::hasDirtyImages() const -{ - return mDirtyImages; -} - -void Texture::resetDirty() -{ - mDirtyImages = false; + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } unsigned int Texture::getTextureSerial() { - rx::TextureStorageInterface *texture = getStorage(false); + rx::TextureStorageInterface *texture = getNativeTexture(); return texture ? texture->getTextureSerial() : 0; } -unsigned int Texture::getRenderTargetSerial(GLenum target) -{ - rx::TextureStorageInterface *texture = getStorage(true); - return texture ? texture->getRenderTargetSerial(target) : 0; -} - bool Texture::isImmutable() const { return mImmutable; } -GLint Texture::creationLevels(GLsizei width, GLsizei height) const +int Texture::immutableLevelCount() { - if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport()) - { - return 0; // Maximum number of levels - } - else - { - // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. - return 1; - } + return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0); } -GLint Texture::creationLevels(GLsizei size) const +int Texture::mipLevels() const { - return creationLevels(size, size); + return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; } -Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) +Texture2D::Texture2D(rx::Texture2DImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_2D), + mTexture(impl) { - mTexStorage = NULL; mSurface = NULL; - mColorbufferProxy = NULL; - mProxyRefs = 0; - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - mImageArray[i] = renderer->createImage(); - } } Texture2D::~Texture2D() { - mColorbufferProxy = NULL; + SafeDelete(mTexture); - delete mTexStorage; - mTexStorage = NULL; - if (mSurface) { mSurface->setBoundTexture(NULL); mSurface = NULL; } - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - delete mImageArray[i]; - } } -// We need to maintain a count of references to renderbuffers acting as -// proxies for this texture, so that we do not attempt to use a pointer -// to a renderbuffer proxy which has been deleted. -void Texture2D::addProxyRef(const Renderbuffer *proxy) +rx::TextureStorageInterface *Texture2D::getNativeTexture() { - mProxyRefs++; + return mTexture->getNativeTexture(); } -void Texture2D::releaseProxy(const Renderbuffer *proxy) +void Texture2D::setUsage(GLenum usage) { - if (mProxyRefs > 0) - mProxyRefs--; + mUsage = usage; + mTexture->setUsage(usage); +} - if (mProxyRefs == 0) - mColorbufferProxy = NULL; +bool Texture2D::hasDirtyImages() const +{ + return mTexture->hasDirtyImages(); } -GLenum Texture2D::getTarget() const +void Texture2D::resetDirty() { - return GL_TEXTURE_2D; + mTexture->resetDirty(); } GLsizei Texture2D::getWidth(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getWidth(); + return mTexture->getImage(level)->getWidth(); else return 0; } @@ -361,7 +160,7 @@ GLsizei Texture2D::getWidth(GLint level) const GLsizei Texture2D::getHeight(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getHeight(); + return mTexture->getImage(level)->getHeight(); else return 0; } @@ -369,7 +168,7 @@ GLsizei Texture2D::getHeight(GLint level) const GLenum Texture2D::getInternalFormat(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getInternalFormat(); + return mTexture->getImage(level)->getInternalFormat(); else return GL_NONE; } @@ -377,63 +176,33 @@ GLenum Texture2D::getInternalFormat(GLint level) const GLenum Texture2D::getActualFormat(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getActualFormat(); + return mTexture->getImage(level)->getActualFormat(); else - return D3DFMT_UNKNOWN; + return GL_NONE; } -void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height) +void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) { releaseTexImage(); - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level); - const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level); - const int storageFormat = mImageArray[0]->getInternalFormat(); - - mImageArray[level]->redefine(mRenderer, internalformat, width, height, false); - - if (mTexStorage) - { - const int storageLevels = mTexStorage->levelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - delete mTexStorage; - mTexStorage = NULL; - mDirtyImages = true; - } - } + mTexture->redefineImage(level, internalformat, width, height); } -void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - GLint internalformat = ConvertSizedInternalFormat(format, type); - redefineImage(level, internalformat, width, height); + GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat + : GetSizedInternalFormat(format, type); + redefineImage(level, sizedInternalFormat, width, height); - Texture::setImage(unpackAlignment, pixels, mImageArray[level]); + mTexture->setImage(level, width, height, internalFormat, format, type, unpack, pixels); } void Texture2D::bindTexImage(egl::Surface *surface) { releaseTexImage(); - GLint internalformat = surface->getFormat(); + mTexture->bindTexImage(surface); - mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true); - - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain()); - - mDirtyImages = true; mSurface = surface; mSurface->setBoundTexture(this); } @@ -445,16 +214,7 @@ void Texture2D::releaseTexImage() mSurface->setBoundTexture(NULL); mSurface = NULL; - if (mTexStorage) - { - delete mTexStorage; - mTexStorage = NULL; - } - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true); - } + mTexture->releaseTexImage(); } } @@ -463,495 +223,126 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly redefineImage(level, format, width, height); - Texture::setCompressedImage(imageSize, pixels, mImageArray[level]); + mTexture->setCompressedImage(level, format, width, height, imageSize, pixels); } -void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - if (level < levelCount()) - { - rx::Image *image = mImageArray[level]; - if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height)) - { - image->markClean(); - } - } -} - -void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) -{ - if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level])) - { - commitRect(level, xoffset, yoffset, width, height); - } + mTexture->subImage(level, xoffset, yoffset, width, height, format, type, unpack, pixels); } void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) { - if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level])) - { - commitRect(level, xoffset, yoffset, width, height); - } + mTexture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, pixels); } void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); - redefineImage(level, internalformat, width, height); + GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format + : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(level, sizedInternalFormat, width, height); - if (!mImageArray[level]->isRenderableFormat()) - { - mImageArray[level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - mImageArray[level]->markClean(); - - if (width != 0 && height != 0 && level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level); - } - } + mTexture->copyImage(level, format, x, y, width, height, source); } -void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight()) - { - return gl::error(GL_INVALID_VALUE); - } - - if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) - { - mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - updateTexture(); - - if (level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, - gl::ExtractFormat(mImageArray[0]->getInternalFormat()), - xoffset, yoffset, mTexStorage, level); - } - } + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); } void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); mImmutable = true; - for (int level = 0; level < levels; level++) - { - mImageArray[level]->redefine(mRenderer, internalformat, width, height, true); - width = std::max(1, width >> 1); - height = std::max(1, height >> 1); - } - - for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true); - } - - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int level = 0; level < levels; level++) - { - mImageArray[level]->setManagedSurface(mTexStorage, level); - } - } + mTexture->storage(levels, internalformat, width, height); } // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. -bool Texture2D::isSamplerComplete() const +bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const { - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - bool mipmapping = isMipmapFiltered(); - bool filtering, renderable; - - if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || - (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) - { - if (mSamplerState.magFilter != GL_NEAREST || - (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) - { - return false; - } - } - - bool npotSupport = mRenderer->getNonPower2TextureSupport(); - - if (!npotSupport) - { - if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) || - (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height))) - { - return false; - } - } - - if (mipmapping) - { - if (!npotSupport) - { - if (!isPow2(width) || !isPow2(height)) - { - return false; - } - } - - if (!isMipmapComplete()) - { - return false; - } - } - - return true; -} - -// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isMipmapComplete() const -{ - if (isImmutable()) - { - return true; - } - - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - int q = log2(std::max(width, height)); - - for (int level = 1; level <= q; level++) - { - if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat()) - { - return false; - } - - if (mImageArray[level]->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (mImageArray[level]->getHeight() != std::max(1, height >> level)) - { - return false; - } - } - - return true; + return mTexture->isSamplerComplete(samplerState); } bool Texture2D::isCompressed(GLint level) const { - return IsCompressed(getInternalFormat(level)); + return IsFormatCompressed(getInternalFormat(level)); } bool Texture2D::isDepth(GLint level) const { - return IsDepthTexture(getInternalFormat(level)); -} - -// Constructs a native texture resource from the texture images -void Texture2D::createTexture() -{ - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (!(width > 0 && height > 0)) - return; // do not attempt to create native textures for nonexistant data - - GLint levels = creationLevels(width, height); - GLenum internalformat = mImageArray[0]->getInternalFormat(); - - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); - - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int level = 0; level < levels; level++) - { - mImageArray[level]->setManagedSurface(mTexStorage, level); - } - } - - mDirtyImages = true; -} - -void Texture2D::updateTexture() -{ - bool mipmapping = (isMipmapFiltered() && isMipmapComplete()); - - int levels = (mipmapping ? levelCount() : 1); - - for (int level = 0; level < levels; level++) - { - rx::Image *image = mImageArray[level]; - - if (image->isDirty()) - { - commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight()); - } - } -} - -void Texture2D::convertToRenderTarget() -{ - rx::TextureStorageInterface2D *newTexStorage = NULL; - - if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0) - { - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height); - GLenum internalformat = mImageArray[0]->getInternalFormat(); - - newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height); - - if (mTexStorage != NULL) - { - if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) - { - delete newTexStorage; - return gl::error(GL_OUT_OF_MEMORY); - } - } - } - - delete mTexStorage; - mTexStorage = newTexStorage; - - mDirtyImages = true; + return GetDepthBits(getInternalFormat(level)) > 0; } void Texture2D::generateMipmaps() { - if (!mRenderer->getNonPower2TextureSupport()) - { - if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight())) - { - return gl::error(GL_INVALID_OPERATION); - } - } - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight())); - for (unsigned int i = 1; i <= q; i++) + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) { - redefineImage(i, mImageArray[0]->getInternalFormat(), - std::max(mImageArray[0]->getWidth() >> i, 1), - std::max(mImageArray[0]->getHeight() >> i, 1)); + redefineImage(level, getBaseLevelInternalFormat(), + std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1)); } - if (mTexStorage && mTexStorage->isRenderTarget()) - { - for (unsigned int i = 1; i <= q; i++) - { - mTexStorage->generateMipmap(i); - - mImageArray[i]->markClean(); - } - } - else - { - for (unsigned int i = 1; i <= q; i++) - { - mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]); - } - } + mTexture->generateMipmaps(); } -Renderbuffer *Texture2D::getRenderbuffer(GLenum target) +const rx::Image *Texture2D::getBaseLevelImage() const { - if (target != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); - } - - if (mColorbufferProxy == NULL) - { - mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target)); - } - - return mColorbufferProxy; + return mTexture->getImage(0); } -rx::RenderTarget *Texture2D::getRenderTarget(GLenum target) +unsigned int Texture2D::getRenderTargetSerial(GLint level) { - ASSERT(target == GL_TEXTURE_2D); - - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } - - updateTexture(); - - // ensure this is NOT a depth texture - if (isDepth(0)) - { - return NULL; - } - - return mTexStorage->getRenderTarget(); + return mTexture->getRenderTargetSerial(level); } -rx::RenderTarget *Texture2D::getDepthStencil(GLenum target) +rx::RenderTarget *Texture2D::getRenderTarget(GLint level) { - ASSERT(target == GL_TEXTURE_2D); - - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } - - updateTexture(); - - // ensure this is actually a depth texture - if (!isDepth(0)) - { - return NULL; - } - return mTexStorage->getRenderTarget(); + return mTexture->getRenderTarget(level); } -int Texture2D::levelCount() +rx::RenderTarget *Texture2D::getDepthSencil(GLint level) { - return mTexStorage ? mTexStorage->levelCount() : 0; + return mTexture->getDepthSencil(level); } -rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget) +TextureCubeMap::TextureCubeMap(rx::TextureCubeImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_CUBE_MAP), + mTexture(impl) { - if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) - { - if (renderTarget) - { - convertToRenderTarget(); - } - else - { - createTexture(); - } - } - - return mTexStorage; } -TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) +TextureCubeMap::~TextureCubeMap() { - mTexStorage = NULL; - for (int i = 0; i < 6; i++) - { - mFaceProxies[i] = NULL; - mFaceProxyRefs[i] = 0; - - for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - mImageArray[i][j] = renderer->createImage(); - } - } + SafeDelete(mTexture); } -TextureCubeMap::~TextureCubeMap() +rx::TextureStorageInterface *TextureCubeMap::getNativeTexture() { - for (int i = 0; i < 6; i++) - { - mFaceProxies[i] = NULL; - - for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - delete mImageArray[i][j]; - } - } - - delete mTexStorage; - mTexStorage = NULL; + return mTexture->getNativeTexture(); } -// We need to maintain a count of references to renderbuffers acting as -// proxies for this texture, so that the texture is not deleted while -// proxy references still exist. If the reference count drops to zero, -// we set our proxy pointer NULL, so that a new attempt at referencing -// will cause recreation. -void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) +void TextureCubeMap::setUsage(GLenum usage) { - for (int i = 0; i < 6; i++) - { - if (mFaceProxies[i] == proxy) - mFaceProxyRefs[i]++; - } + mUsage = usage; + mTexture->setUsage(usage); } -void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) +bool TextureCubeMap::hasDirtyImages() const { - for (int i = 0; i < 6; i++) - { - if (mFaceProxies[i] == proxy) - { - if (mFaceProxyRefs[i] > 0) - mFaceProxyRefs[i]--; - - if (mFaceProxyRefs[i] == 0) - mFaceProxies[i] = NULL; - } - } + return mTexture->hasDirtyImages(); } -GLenum TextureCubeMap::getTarget() const +void TextureCubeMap::resetDirty() { - return GL_TEXTURE_CUBE_MAP; + mTexture->resetDirty(); } GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getWidth(); + return mTexture->getImage(target, level)->getWidth(); else return 0; } @@ -959,7 +350,7 @@ GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getHeight(); + return mTexture->getImage(target, level)->getHeight(); else return 0; } @@ -967,7 +358,7 @@ GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getInternalFormat(); + return mTexture->getImage(target, level)->getInternalFormat(); else return GL_NONE; } @@ -975,525 +366,393 @@ GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getActualFormat(); + return mTexture->getImage(target, level)->getActualFormat(); else - return D3DFMT_UNKNOWN; + return GL_NONE; } -void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(0, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(0, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(1, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(1, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(2, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(2, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(3, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(3, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(4, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(4, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(5, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(5, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(faceIndex(face), level, format, width, height); + mTexture->setCompressedImage(target, level, format, width, height, imageSize, pixels); +} - Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]); +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) +{ + mTexture->subImage(target, level, xoffset, yoffset, width, height, format, type, unpack, pixels); } -void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) { - if (level < levelCount()) - { - rx::Image *image = mImageArray[face][level]; - if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height)) - image->markClean(); - } + mTexture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, pixels); } -void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const { - if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level])) - { - commitRect(faceIndex(target), level, xoffset, yoffset, width, height); - } + return mTexture->isSamplerComplete(samplerState); } -void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const { - if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level])) - { - commitRect(faceIndex(target), level, xoffset, yoffset, width, height); - } + return mTexture->isCubeComplete(); } -// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. -bool TextureCubeMap::isSamplerComplete() const +bool TextureCubeMap::isCompressed(GLenum target, GLint level) const { - int size = mImageArray[0][0]->getWidth(); + return IsFormatCompressed(getInternalFormat(target, level)); +} - bool mipmapping = isMipmapFiltered(); - bool filtering, renderable; +bool TextureCubeMap::isDepth(GLenum target, GLint level) const +{ + return GetDepthBits(getInternalFormat(target, level)) > 0; +} - if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || - (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) - { - if (mSamplerState.magFilter != GL_NEAREST || - (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) - { - return false; - } - } +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copyImage(target, level, format, x, y, width, height, source); +} - if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport()) - { - if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) - { - return false; - } - } +void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - if (!mipmapping) - { - if (!isCubeComplete()) - { - return false; - } - } - else - { - if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() - { - return false; - } - } +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +{ + mImmutable = true; - return true; + mTexture->storage(levels, internalformat, size); } -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isCubeComplete() const +void TextureCubeMap::generateMipmaps() { - if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth()) - { - return false; - } + mTexture->generateMipmaps(); +} - for (unsigned int face = 1; face < 6; face++) - { - if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() || - mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() || - mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) - { - return false; - } - } +const rx::Image *TextureCubeMap::getBaseLevelImage() const +{ + // Note: if we are not cube-complete, there is no single base level image that can describe all + // cube faces, so this method is only well-defined for a cube-complete base level. + return mTexture->getImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} - return true; +unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level) +{ + return mTexture->getRenderTargetSerial(target, level); } -bool TextureCubeMap::isMipmapCubeComplete() const +rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level) { - if (isImmutable()) - { - return true; - } + return mTexture->getRenderTarget(target, level); +} - if (!isCubeComplete()) - { - return false; - } +rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level) +{ + return mTexture->getDepthStencil(target, level); +} - GLsizei size = mImageArray[0][0]->getWidth(); +Texture3D::Texture3D(rx::Texture3DImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_3D), + mTexture(impl) +{ +} - int q = log2(size); +Texture3D::~Texture3D() +{ + SafeDelete(mTexture); +} - for (int face = 0; face < 6; face++) - { - for (int level = 1; level <= q; level++) - { - if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) - { - return false; - } - - if (mImageArray[face][level]->getWidth() != std::max(1, size >> level)) - { - return false; - } - } - } +rx::TextureStorageInterface *Texture3D::getNativeTexture() +{ + return mTexture->getNativeTexture(); +} - return true; +void Texture3D::setUsage(GLenum usage) +{ + mUsage = usage; + mTexture->setUsage(usage); } -bool TextureCubeMap::isCompressed(GLenum target, GLint level) const +bool Texture3D::hasDirtyImages() const { - return IsCompressed(getInternalFormat(target, level)); + return mTexture->hasDirtyImages(); } -// Constructs a native texture resource from the texture images, or returns an existing one -void TextureCubeMap::createTexture() +void Texture3D::resetDirty() { - GLsizei size = mImageArray[0][0]->getWidth(); + mTexture->resetDirty(); +} - if (!(size > 0)) - return; // do not attempt to create native textures for nonexistant data +GLsizei Texture3D::getWidth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getWidth() : 0; +} - GLint levels = creationLevels(size); - GLenum internalformat = mImageArray[0][0]->getInternalFormat(); +GLsizei Texture3D::getHeight(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getHeight() : 0; +} - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); +GLsizei Texture3D::getDepth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getDepth() : 0; +} - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int face = 0; face < 6; face++) - { - for (int level = 0; level < levels; level++) - { - mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); - } - } - } +GLenum Texture3D::getInternalFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getInternalFormat() : GL_NONE; +} - mDirtyImages = true; +GLenum Texture3D::getActualFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getActualFormat() : GL_NONE; } -void TextureCubeMap::updateTexture() +bool Texture3D::isCompressed(GLint level) const { - bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete(); + return IsFormatCompressed(getInternalFormat(level)); +} - for (int face = 0; face < 6; face++) - { - int levels = (mipmapping ? levelCount() : 1); +bool Texture3D::isDepth(GLint level) const +{ + return GetDepthBits(getInternalFormat(level)) > 0; +} - for (int level = 0; level < levels; level++) - { - rx::Image *image = mImageArray[face][level]; +void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->setImage(level, width, height, depth, internalFormat, format, type, unpack, pixels); +} - if (image->isDirty()) - { - commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); - } - } - } +void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + mTexture->setCompressedImage(level, format, width, height, depth, imageSize, pixels); } -void TextureCubeMap::convertToRenderTarget() +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) { - rx::TextureStorageInterfaceCube *newTexStorage = NULL; + mTexture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); +} - if (mImageArray[0][0]->getWidth() != 0) - { - GLsizei size = mImageArray[0][0]->getWidth(); - GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size); - GLenum internalformat = mImageArray[0][0]->getInternalFormat(); - - newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size); - - if (mTexStorage != NULL) - { - if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) - { - delete newTexStorage; - return gl::error(GL_OUT_OF_MEMORY); - } - } - } +void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +{ + mTexture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); +} - delete mTexStorage; - mTexStorage = newTexStorage; +void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + mImmutable = true; - mDirtyImages = true; + mTexture->storage(levels, internalformat, width, height, depth); } -void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void Texture3D::generateMipmaps() { - GLint internalformat = ConvertSizedInternalFormat(format, type); - redefineImage(faceIndex, level, internalformat, width, height); + mTexture->generateMipmaps(); +} - Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]); +const rx::Image *Texture3D::getBaseLevelImage() const +{ + return mTexture->getImage(0); } -unsigned int TextureCubeMap::faceIndex(GLenum face) +void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); - META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); - META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; +bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const +{ + return mTexture->isSamplerComplete(samplerState); } -void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height) +bool Texture3D::isMipmapComplete() const { - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level); - const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level); - const int storageFormat = mImageArray[0][0]->getInternalFormat(); + return mTexture->isMipmapComplete(); +} - mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false); +unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer) +{ + return mTexture->getRenderTargetSerial(level, layer); +} - if (mTexStorage) - { - const int storageLevels = mTexStorage->levelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - for (int f = 0; f < 6; f++) - { - mImageArray[f][i]->markDirty(); - } - } - - delete mTexStorage; - mTexStorage = NULL; - - mDirtyImages = true; - } - } +rx::RenderTarget *Texture3D::getRenderTarget(GLint level) +{ + return mTexture->getRenderTarget(level); } -void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer) { - unsigned int faceindex = faceIndex(target); - GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); - redefineImage(faceindex, level, internalformat, width, height); + return mTexture->getRenderTarget(level, layer); +} - if (!mImageArray[faceindex][level]->isRenderableFormat()) - { - mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - mImageArray[faceindex][level]->markClean(); - - ASSERT(width == height); - - if (width > 0 && level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level); - } - } +rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer) +{ + return mTexture->getDepthStencil(level, layer); } -void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +Texture2DArray::Texture2DArray(rx::Texture2DArrayImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_2D_ARRAY), + mTexture(impl) { - GLsizei size = mImageArray[faceIndex(target)][level]->getWidth(); +} - if (xoffset + width > size || yoffset + height > size) - { - return gl::error(GL_INVALID_VALUE); - } +Texture2DArray::~Texture2DArray() +{ + SafeDelete(mTexture); +} - unsigned int faceindex = faceIndex(target); +rx::TextureStorageInterface *Texture2DArray::getNativeTexture() +{ + return mTexture->getNativeTexture(); +} - if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) - { - mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - updateTexture(); - - if (level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()), - xoffset, yoffset, mTexStorage, target, level); - } - } +void Texture2DArray::setUsage(GLenum usage) +{ + mUsage = usage; + mTexture->setUsage(usage); } -void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +bool Texture2DArray::hasDirtyImages() const { - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); - mImmutable = true; + return mTexture->hasDirtyImages(); +} - for (int level = 0; level < levels; level++) - { - GLsizei mipSize = std::max(1, size >> level); - for (int face = 0; face < 6; face++) - { - mImageArray[face][level]->redefine(mRenderer, internalformat, mipSize, mipSize, true); - } - } +void Texture2DArray::resetDirty() +{ + mTexture->resetDirty(); +} - for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (int face = 0; face < 6; face++) - { - mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true); - } - } +GLsizei Texture2DArray::getWidth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getWidth() : 0; +} - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int face = 0; face < 6; face++) - { - for (int level = 0; level < levels; level++) - { - mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); - } - } - } +GLsizei Texture2DArray::getHeight(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getHeight() : 0; } -void TextureCubeMap::generateMipmaps() +GLsizei Texture2DArray::getLayers(GLint level) const { - if (!isCubeComplete()) - { - return gl::error(GL_INVALID_OPERATION); - } + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getLayerCount(level) : 0; +} - if (!mRenderer->getNonPower2TextureSupport()) - { - if (!isPow2(mImageArray[0][0]->getWidth())) - { - return gl::error(GL_INVALID_OPERATION); - } - } +GLenum Texture2DArray::getInternalFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; +} - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(mImageArray[0][0]->getWidth()); - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - redefineImage(f, i, mImageArray[f][0]->getInternalFormat(), - std::max(mImageArray[f][0]->getWidth() >> i, 1), - std::max(mImageArray[f][0]->getWidth() >> i, 1)); - } - } +GLenum Texture2DArray::getActualFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; +} - if (mTexStorage && mTexStorage->isRenderTarget()) - { - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - mTexStorage->generateMipmap(f, i); - - mImageArray[f][i]->markClean(); - } - } - } - else - { - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]); - } - } - } +bool Texture2DArray::isCompressed(GLint level) const +{ + return IsFormatCompressed(getInternalFormat(level)); } -Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) +bool Texture2DArray::isDepth(GLint level) const { - if (!IsCubemapTextureTarget(target)) - { - return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); - } + return GetDepthBits(getInternalFormat(level)) > 0; +} - unsigned int face = faceIndex(target); +void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->setImage(level, width, height, depth, internalFormat, format, type, unpack, pixels); +} - if (mFaceProxies[face] == NULL) - { - mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target)); - } +void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + mTexture->setCompressedImage(level, format, width, height, depth, imageSize, pixels); +} - return mFaceProxies[face]; +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) +{ + mTexture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); } -rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target) +void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) { - ASSERT(IsCubemapTextureTarget(target)); + mTexture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); +} - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } +void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + mImmutable = true; - updateTexture(); - - return mTexStorage->getRenderTarget(target); + mTexture->storage(levels, internalformat, width, height, depth); } -int TextureCubeMap::levelCount() +void Texture2DArray::generateMipmaps() { - return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0; + mTexture->generateMipmaps(); } -rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget) +const rx::Image *Texture2DArray::getBaseLevelImage() const { - if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) - { - if (renderTarget) - { - convertToRenderTarget(); - } - else - { - createTexture(); - } - } + return (mTexture->getLayerCount(0) > 0 ? mTexture->getImage(0, 0) : NULL); +} + +void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - return mTexStorage; +bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const +{ + return mTexture->isSamplerComplete(samplerState); +} + +bool Texture2DArray::isMipmapComplete() const +{ + return mTexture->isMipmapComplete(); +} + +unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer) +{ + return mTexture->getRenderTargetSerial(level, layer); +} + +rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer) +{ + return mTexture->getRenderTarget(level, layer); +} + +rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer) +{ + return mTexture->getDepthStencil(level, layer); } } |