Fix determining texture mipmap completeness
The code didn't previously take base level properly into account
when determining how many levels to check when checking for texture
completeness.
The code is refactored so that the "q" value in spec, that is the
maximum mipmap level for determining completeness, can be queried from
TextureState. This value is used now for checking completeness.
This requires moving ImageDescs under TextureState. Functions that
operate on the ImageDesc array are also moved from Texture to
TextureState. TextureState members are also renamed to start with the
"m" prefix and made private.
Also handle levels outside the base/max level range consistently in
eglCreateImageKHR validation. We interpret the spec so that if the
level used for the EGL image is not a part of the texture levels that
affect texture completeness, an error is generated.
BUG=angleproject:596
TEST=angle_end2end_tests
Change-Id: I038ef24aa83e0a6905ca3c0bbada5989eecb00d9
Reviewed-on: https://chromium-review.googlesource.com/344880
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 071b718..0c661ad 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -437,7 +437,8 @@
// TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
const Texture *texture = colorAttachment.getTexture();
ASSERT(texture);
- if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete())
+ if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
+ !texture->getTextureState().isCubeComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index 79cb693..ea4ef8d 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -55,354 +55,124 @@
}
}
-TextureState::TextureState(GLenum target)
- : target(target),
- swizzleRed(GL_RED),
- swizzleGreen(GL_GREEN),
- swizzleBlue(GL_BLUE),
- swizzleAlpha(GL_ALPHA),
- samplerState(SamplerState::CreateDefaultForTarget(target)),
- baseLevel(0),
- maxLevel(1000),
- immutableFormat(false),
- immutableLevels(0),
- usage(GL_NONE)
+SwizzleState::SwizzleState()
+ : swizzleRed(GL_INVALID_INDEX),
+ swizzleGreen(GL_INVALID_INDEX),
+ swizzleBlue(GL_INVALID_INDEX),
+ swizzleAlpha(GL_INVALID_INDEX)
{
}
-bool TextureState::swizzleRequired() const
+SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
+ : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
+{
+}
+
+bool SwizzleState::swizzleRequired() const
{
return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
swizzleAlpha != GL_ALPHA;
}
+bool SwizzleState::operator==(const SwizzleState &other) const
+{
+ return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
+ swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
+}
+
+bool SwizzleState::operator!=(const SwizzleState &other) const
+{
+ return !(*this == other);
+}
+
+TextureState::TextureState(GLenum target)
+ : mTarget(target),
+ mSwizzleState(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA),
+ mSamplerState(SamplerState::CreateDefaultForTarget(target)),
+ mBaseLevel(0),
+ mMaxLevel(1000),
+ mImmutableFormat(false),
+ mImmutableLevels(0),
+ mUsage(GL_NONE),
+ mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
+ (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
+ mCompletenessCache()
+{
+}
+
+bool TextureState::swizzleRequired() const
+{
+ return mSwizzleState.swizzleRequired();
+}
+
GLuint TextureState::getEffectiveBaseLevel() const
{
- if (immutableFormat)
+ if (mImmutableFormat)
{
// GLES 3.0.4 section 3.8.10
- return std::min(baseLevel, immutableLevels - 1);
+ return std::min(mBaseLevel, mImmutableLevels - 1);
}
// Some classes use the effective base level to index arrays with level data. By clamping the
// effective base level to max levels these arrays need just one extra item to store properties
// that should be returned for all out-of-range base level values, instead of needing special
// handling for out-of-range base levels.
- return std::min(baseLevel, static_cast<GLuint>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
+ return std::min(mBaseLevel, static_cast<GLuint>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
}
GLuint TextureState::getEffectiveMaxLevel() const
{
- if (immutableFormat)
+ if (mImmutableFormat)
{
// GLES 3.0.4 section 3.8.10
- GLuint clampedMaxLevel = std::max(maxLevel, getEffectiveBaseLevel());
- clampedMaxLevel = std::min(clampedMaxLevel, immutableLevels - 1);
+ GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
+ clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
return clampedMaxLevel;
}
- return maxLevel;
+ return mMaxLevel;
}
-Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target)
- : egl::ImageSibling(id),
- mState(target),
- mTexture(factory->createTexture(mState)),
- mLabel(),
- mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
- (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
- mCompletenessCache(),
- mBoundSurface(nullptr),
- mBoundStream(nullptr)
+size_t TextureState::getMipmapMaxLevel() const
{
-}
-
-Texture::~Texture()
-{
- if (mBoundSurface)
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
+ size_t expectedMipLevels = 0;
+ if (mTarget == GL_TEXTURE_3D)
{
- mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
- mBoundSurface = nullptr;
+ const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
+ baseImageDesc.size.depth);
+ expectedMipLevels = log2(maxDim);
}
- if (mBoundStream)
+ else
{
- mBoundStream->releaseTextures();
- mBoundStream = nullptr;
+ expectedMipLevels = log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height));
}
- SafeDelete(mTexture);
+
+ return std::min<size_t>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
}
-void Texture::setLabel(const std::string &label)
+bool TextureState::setBaseLevel(GLuint baseLevel)
{
- mLabel = label;
-}
-
-const std::string &Texture::getLabel() const
-{
- return mLabel;
-}
-
-GLenum Texture::getTarget() const
-{
- return mState.target;
-}
-
-void Texture::setSwizzleRed(GLenum swizzleRed)
-{
- mState.swizzleRed = swizzleRed;
-}
-
-GLenum Texture::getSwizzleRed() const
-{
- return mState.swizzleRed;
-}
-
-void Texture::setSwizzleGreen(GLenum swizzleGreen)
-{
- mState.swizzleGreen = swizzleGreen;
-}
-
-GLenum Texture::getSwizzleGreen() const
-{
- return mState.swizzleGreen;
-}
-
-void Texture::setSwizzleBlue(GLenum swizzleBlue)
-{
- mState.swizzleBlue = swizzleBlue;
-}
-
-GLenum Texture::getSwizzleBlue() const
-{
- return mState.swizzleBlue;
-}
-
-void Texture::setSwizzleAlpha(GLenum swizzleAlpha)
-{
- mState.swizzleAlpha = swizzleAlpha;
-}
-
-GLenum Texture::getSwizzleAlpha() const
-{
- return mState.swizzleAlpha;
-}
-
-void Texture::setMinFilter(GLenum minFilter)
-{
- mState.samplerState.minFilter = minFilter;
-}
-
-GLenum Texture::getMinFilter() const
-{
- return mState.samplerState.minFilter;
-}
-
-void Texture::setMagFilter(GLenum magFilter)
-{
- mState.samplerState.magFilter = magFilter;
-}
-
-GLenum Texture::getMagFilter() const
-{
- return mState.samplerState.magFilter;
-}
-
-void Texture::setWrapS(GLenum wrapS)
-{
- mState.samplerState.wrapS = wrapS;
-}
-
-GLenum Texture::getWrapS() const
-{
- return mState.samplerState.wrapS;
-}
-
-void Texture::setWrapT(GLenum wrapT)
-{
- mState.samplerState.wrapT = wrapT;
-}
-
-GLenum Texture::getWrapT() const
-{
- return mState.samplerState.wrapT;
-}
-
-void Texture::setWrapR(GLenum wrapR)
-{
- mState.samplerState.wrapR = wrapR;
-}
-
-GLenum Texture::getWrapR() const
-{
- return mState.samplerState.wrapR;
-}
-
-void Texture::setMaxAnisotropy(float maxAnisotropy)
-{
- mState.samplerState.maxAnisotropy = maxAnisotropy;
-}
-
-float Texture::getMaxAnisotropy() const
-{
- return mState.samplerState.maxAnisotropy;
-}
-
-void Texture::setMinLod(GLfloat minLod)
-{
- mState.samplerState.minLod = minLod;
-}
-
-GLfloat Texture::getMinLod() const
-{
- return mState.samplerState.minLod;
-}
-
-void Texture::setMaxLod(GLfloat maxLod)
-{
- mState.samplerState.maxLod = maxLod;
-}
-
-GLfloat Texture::getMaxLod() const
-{
- return mState.samplerState.maxLod;
-}
-
-void Texture::setCompareMode(GLenum compareMode)
-{
- mState.samplerState.compareMode = compareMode;
-}
-
-GLenum Texture::getCompareMode() const
-{
- return mState.samplerState.compareMode;
-}
-
-void Texture::setCompareFunc(GLenum compareFunc)
-{
- mState.samplerState.compareFunc = compareFunc;
-}
-
-GLenum Texture::getCompareFunc() const
-{
- return mState.samplerState.compareFunc;
-}
-
-const SamplerState &Texture::getSamplerState() const
-{
- return mState.samplerState;
-}
-
-void Texture::setBaseLevel(GLuint baseLevel)
-{
- if (mState.baseLevel != baseLevel)
+ if (mBaseLevel != baseLevel)
{
- mState.baseLevel = baseLevel;
+ mBaseLevel = baseLevel;
mCompletenessCache.cacheValid = false;
- mTexture->setBaseLevel(mState.getEffectiveBaseLevel());
+ return true;
}
+ return false;
}
-GLuint Texture::getBaseLevel() const
+void TextureState::setMaxLevel(GLuint maxLevel)
{
- return mState.baseLevel;
-}
-
-void Texture::setMaxLevel(GLuint maxLevel)
-{
- if (mState.maxLevel != maxLevel)
+ if (mMaxLevel != maxLevel)
{
- mState.maxLevel = maxLevel;
+ mMaxLevel = maxLevel;
mCompletenessCache.cacheValid = false;
}
}
-GLuint Texture::getMaxLevel() const
-{
- return mState.maxLevel;
-}
-
-bool Texture::getImmutableFormat() const
-{
- return mState.immutableFormat;
-}
-
-GLuint Texture::getImmutableLevels() const
-{
- return mState.immutableLevels;
-}
-
-void Texture::setUsage(GLenum usage)
-{
- mState.usage = usage;
- getImplementation()->setUsage(usage);
-}
-
-GLenum Texture::getUsage() const
-{
- return mState.usage;
-}
-
-const TextureState &Texture::getTextureState() const
-{
- return mState;
-}
-
-size_t Texture::getWidth(GLenum target, size_t level) const
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return getImageDesc(target, level).size.width;
-}
-
-size_t Texture::getHeight(GLenum target, size_t level) const
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return getImageDesc(target, level).size.height;
-}
-
-size_t Texture::getDepth(GLenum target, size_t level) const
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return getImageDesc(target, level).size.depth;
-}
-
-GLenum Texture::getInternalFormat(GLenum target, size_t level) const
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return getImageDesc(target, level).internalFormat;
-}
-
-bool Texture::isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const
-{
- const ImageDesc &baseImageDesc =
- getImageDesc(getBaseImageTarget(), mState.getEffectiveBaseLevel());
- const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
- if (!mCompletenessCache.cacheValid ||
- mCompletenessCache.samplerState != samplerState ||
- mCompletenessCache.filterable != textureCaps.filterable ||
- mCompletenessCache.clientVersion != data.clientVersion ||
- mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
- {
- mCompletenessCache.cacheValid = true;
- mCompletenessCache.samplerState = samplerState;
- mCompletenessCache.filterable = textureCaps.filterable;
- mCompletenessCache.clientVersion = data.clientVersion;
- mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
- mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
- }
- return mCompletenessCache.samplerComplete;
-}
-
-bool Texture::isMipmapComplete() const
-{
- return computeMipmapCompleteness();
-}
-
// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
-bool Texture::isCubeComplete() const
+bool TextureState::isCubeComplete() const
{
- ASSERT(mState.target == GL_TEXTURE_CUBE_MAP);
+ ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
@@ -424,386 +194,44 @@
return true;
}
-size_t Texture::getMipCompleteLevels() const
+bool TextureState::isSamplerComplete(const SamplerState &samplerState,
+ const ContextState &data) const
{
- const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
- if (mState.target == GL_TEXTURE_3D)
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
+ const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
+ if (!mCompletenessCache.cacheValid || mCompletenessCache.samplerState != samplerState ||
+ mCompletenessCache.filterable != textureCaps.filterable ||
+ mCompletenessCache.clientVersion != data.clientVersion ||
+ mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
{
- const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
- baseImageDesc.size.depth);
- return log2(maxDim) + 1;
+ mCompletenessCache.cacheValid = true;
+ mCompletenessCache.samplerState = samplerState;
+ mCompletenessCache.filterable = textureCaps.filterable;
+ mCompletenessCache.clientVersion = data.clientVersion;
+ mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
+ mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
}
- else
- {
- return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
- }
+ return mCompletenessCache.samplerComplete;
}
-egl::Surface *Texture::getBoundSurface() const
+bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
+ const ContextState &data) const
{
- return mBoundSurface;
-}
-
-egl::Stream *Texture::getBoundStream() const
-{
- return mBoundStream;
-}
-
-Error Texture::setImage(const PixelUnpackState &unpackState,
- GLenum target,
- size_t level,
- GLenum internalFormat,
- const Extents &size,
- GLenum format,
- GLenum type,
- const uint8_t *pixels)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
- orphanImages();
-
- Error error =
- mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels);
- if (error.isError())
- {
- return error;
- }
-
- setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
-
- return Error(GL_NO_ERROR);
-}
-
-Error Texture::setSubImage(const PixelUnpackState &unpackState,
- GLenum target,
- size_t level,
- const Box &area,
- GLenum format,
- GLenum type,
- const uint8_t *pixels)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return mTexture->setSubImage(target, level, area, format, type, unpackState, pixels);
-}
-
-Error Texture::setCompressedImage(const PixelUnpackState &unpackState,
- GLenum target,
- size_t level,
- GLenum internalFormat,
- const Extents &size,
- size_t imageSize,
- const uint8_t *pixels)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
- orphanImages();
-
- Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpackState,
- imageSize, pixels);
- if (error.isError())
- {
- return error;
- }
-
- setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
-
- return Error(GL_NO_ERROR);
-}
-
-Error Texture::setCompressedSubImage(const PixelUnpackState &unpackState,
- GLenum target,
- size_t level,
- const Box &area,
- GLenum format,
- size_t imageSize,
- const uint8_t *pixels)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-
- return mTexture->setCompressedSubImage(target, level, area, format, unpackState, imageSize,
- pixels);
-}
-
-Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
- const Framebuffer *source)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
- orphanImages();
-
- Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
- if (error.isError())
- {
- return error;
- }
-
- setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
- GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
-
- return Error(GL_NO_ERROR);
-}
-
-Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
- const Framebuffer *source)
-{
- ASSERT(target == mState.target ||
- (mState.target == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-
- return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
-}
-
-Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
-{
- ASSERT(target == mState.target);
-
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
- orphanImages();
-
- Error error = mTexture->setStorage(target, levels, internalFormat, size);
- if (error.isError())
- {
- return error;
- }
-
- mState.immutableFormat = true;
- mState.immutableLevels = static_cast<GLuint>(levels);
- clearImageDescs();
- setImageDescChain(levels, size, internalFormat);
-
- return Error(GL_NO_ERROR);
-}
-
-Error Texture::generateMipmaps()
-{
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
-
- // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
- // is not mip complete.
- if (!isMipmapComplete())
- {
- orphanImages();
- }
-
- Error error = mTexture->generateMipmaps();
- if (error.isError())
- {
- return error;
- }
-
- const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
- size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
- setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
-
- return Error(GL_NO_ERROR);
-}
-
-void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
-{
- for (int level = 0; level < static_cast<int>(levels); level++)
- {
- Extents levelSize(
- std::max<int>(baseSize.width >> level, 1), std::max<int>(baseSize.height >> level, 1),
- (mState.target == GL_TEXTURE_2D_ARRAY) ? baseSize.depth
- : std::max<int>(baseSize.depth >> level, 1));
- ImageDesc levelInfo(levelSize, sizedInternalFormat);
-
- if (mState.target == GL_TEXTURE_CUBE_MAP)
- {
- for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
- {
- setImageDesc(face, level, levelInfo);
- }
- }
- else
- {
- setImageDesc(mState.target, level, levelInfo);
- }
- }
-}
-
-Texture::ImageDesc::ImageDesc()
- : ImageDesc(Extents(0, 0, 0), GL_NONE)
-{
-}
-
-Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
- : size(size),
- internalFormat(internalFormat)
-{
-}
-
-const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
-{
- size_t descIndex = GetImageDescIndex(target, level);
- ASSERT(descIndex < mImageDescs.size());
- return mImageDescs[descIndex];
-}
-
-void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
-{
- size_t descIndex = GetImageDescIndex(target, level);
- ASSERT(descIndex < mImageDescs.size());
- mImageDescs[descIndex] = desc;
- mCompletenessCache.cacheValid = false;
-}
-
-void Texture::clearImageDesc(GLenum target, size_t level)
-{
- setImageDesc(target, level, ImageDesc());
-}
-
-void Texture::clearImageDescs()
-{
- for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
- {
- mImageDescs[descIndex] = ImageDesc();
- }
- mCompletenessCache.cacheValid = false;
-}
-
-void Texture::bindTexImageFromSurface(egl::Surface *surface)
-{
- ASSERT(surface);
-
- if (mBoundSurface)
- {
- releaseTexImageFromSurface();
- }
-
- mTexture->bindTexImage(surface);
- mBoundSurface = surface;
-
- // Set the image info to the size and format of the surface
- ASSERT(mState.target == GL_TEXTURE_2D);
- Extents size(surface->getWidth(), surface->getHeight(), 1);
- ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
- setImageDesc(mState.target, 0, desc);
-}
-
-void Texture::releaseTexImageFromSurface()
-{
- ASSERT(mBoundSurface);
- mBoundSurface = nullptr;
- mTexture->releaseTexImage();
-
- // Erase the image info for level 0
- ASSERT(mState.target == GL_TEXTURE_2D);
- clearImageDesc(mState.target, 0);
-}
-
-void Texture::bindStream(egl::Stream *stream)
-{
- ASSERT(stream);
-
- // It should not be possible to bind a texture already bound to another stream
- ASSERT(mBoundStream == nullptr);
-
- mBoundStream = stream;
-
- ASSERT(mState.target == GL_TEXTURE_EXTERNAL_OES);
-}
-
-void Texture::releaseStream()
-{
- ASSERT(mBoundStream);
- mBoundStream = nullptr;
-}
-
-void Texture::acquireImageFromStream(const egl::Stream::GLTextureDescription &desc)
-{
- ASSERT(mBoundStream != nullptr);
- mTexture->setImageExternal(mState.target, mBoundStream, desc);
-
- Extents size(desc.width, desc.height, 1);
- setImageDesc(mState.target, 0, ImageDesc(size, desc.internalFormat));
-}
-
-void Texture::releaseImageFromStream()
-{
- ASSERT(mBoundStream != nullptr);
- mTexture->setImageExternal(mState.target, nullptr, egl::Stream::GLTextureDescription());
-
- // Set to incomplete
- clearImageDesc(mState.target, 0);
-}
-
-void Texture::releaseTexImageInternal()
-{
- if (mBoundSurface)
- {
- // Notify the surface
- mBoundSurface->releaseTexImageFromTexture();
-
- // Then, call the same method as from the surface
- releaseTexImageFromSurface();
- }
-}
-
-Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
-{
- ASSERT(target == mState.target);
- ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES);
-
- // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
- releaseTexImageInternal();
- orphanImages();
-
- Error error = mTexture->setEGLImageTarget(target, imageTarget);
- if (error.isError())
- {
- return error;
- }
-
- setTargetImage(imageTarget);
-
- Extents size(static_cast<int>(imageTarget->getWidth()),
- static_cast<int>(imageTarget->getHeight()), 1);
- GLenum internalFormat = imageTarget->getInternalFormat();
- GLenum type = GetInternalFormatInfo(internalFormat).type;
-
- clearImageDescs();
- setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
-
- return Error(GL_NO_ERROR);
-}
-
-GLenum Texture::getBaseImageTarget() const
-{
- return mState.target == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mState.target;
-}
-
-bool Texture::computeSamplerCompleteness(const SamplerState &samplerState,
- const ContextState &data) const
-{
- if (mState.baseLevel > mState.maxLevel)
+ if (mBaseLevel > mMaxLevel)
{
return false;
}
- const ImageDesc &baseImageDesc =
- getImageDesc(getBaseImageTarget(), mState.getEffectiveBaseLevel());
- if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
+ if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
+ baseImageDesc.size.depth == 0)
{
return false;
}
// The cases where the texture is incomplete because base level is out of range should be
// handled by the above condition.
- ASSERT(mState.baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS || mState.immutableFormat);
+ ASSERT(mBaseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
- if (mState.target == GL_TEXTURE_CUBE_MAP &&
- baseImageDesc.size.width != baseImageDesc.size.height)
+ if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
{
return false;
}
@@ -841,7 +269,7 @@
}
else
{
- if (mState.target == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
+ if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
{
return false;
}
@@ -855,7 +283,7 @@
// texture, the texture will be considered incomplete.
// Sampler object state which does not affect sampling for the type of texture bound to a
// texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness.
- if (mState.target == GL_TEXTURE_EXTERNAL_OES)
+ if (mTarget == GL_TEXTURE_EXTERNAL_OES)
{
if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE)
{
@@ -878,7 +306,8 @@
{
if (samplerState.compareMode == GL_NONE)
{
- if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
+ if ((samplerState.minFilter != GL_NEAREST &&
+ samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
samplerState.magFilter != GL_NEAREST)
{
return false;
@@ -889,15 +318,13 @@
return true;
}
-bool Texture::computeMipmapCompleteness() const
+bool TextureState::computeMipmapCompleteness() const
{
- size_t expectedMipLevels = getMipCompleteLevels();
+ const size_t maxLevel = getMipmapMaxLevel();
- size_t maxLevel = std::min<size_t>(expectedMipLevels, mState.maxLevel + 1);
-
- for (size_t level = mState.getEffectiveBaseLevel(); level < maxLevel; level++)
+ for (size_t level = getEffectiveBaseLevel(); level <= maxLevel; level++)
{
- if (mState.target == GL_TEXTURE_CUBE_MAP)
+ if (mTarget == GL_TEXTURE_CUBE_MAP)
{
for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
{
@@ -909,7 +336,7 @@
}
else
{
- if (!computeLevelCompleteness(mState.target, level))
+ if (!computeLevelCompleteness(mTarget, level))
{
return false;
}
@@ -919,18 +346,18 @@
return true;
}
-bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
+bool TextureState::computeLevelCompleteness(GLenum target, size_t level) const
{
ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
- if (mState.immutableFormat)
+ if (mImmutableFormat)
{
return true;
}
- const ImageDesc &baseImageDesc =
- getImageDesc(getBaseImageTarget(), mState.getEffectiveBaseLevel());
- if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
+ if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
+ baseImageDesc.size.depth == 0)
{
return false;
}
@@ -947,8 +374,8 @@
return false;
}
- ASSERT(level >= mState.getEffectiveBaseLevel());
- const size_t relativeLevel = level - mState.getEffectiveBaseLevel();
+ ASSERT(level >= getEffectiveBaseLevel());
+ const size_t relativeLevel = level - getEffectiveBaseLevel();
if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
{
return false;
@@ -959,14 +386,14 @@
return false;
}
- if (mState.target == GL_TEXTURE_3D)
+ if (mTarget == GL_TEXTURE_3D)
{
if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
{
return false;
}
}
- else if (mState.target == GL_TEXTURE_2D_ARRAY)
+ else if (mTarget == GL_TEXTURE_2D_ARRAY)
{
if (levelImageDesc.size.depth != baseImageDesc.size.depth)
{
@@ -977,7 +404,74 @@
return true;
}
-Texture::SamplerCompletenessCache::SamplerCompletenessCache()
+GLenum TextureState::getBaseImageTarget() const
+{
+ return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
+}
+
+ImageDesc::ImageDesc() : ImageDesc(Extents(0, 0, 0), GL_NONE)
+{
+}
+
+ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
+ : size(size), internalFormat(internalFormat)
+{
+}
+
+const ImageDesc &TextureState::getImageDesc(GLenum target, size_t level) const
+{
+ size_t descIndex = GetImageDescIndex(target, level);
+ ASSERT(descIndex < mImageDescs.size());
+ return mImageDescs[descIndex];
+}
+
+void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
+{
+ size_t descIndex = GetImageDescIndex(target, level);
+ ASSERT(descIndex < mImageDescs.size());
+ mImageDescs[descIndex] = desc;
+ mCompletenessCache.cacheValid = false;
+}
+
+void TextureState::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
+{
+ for (int level = 0; level < static_cast<int>(levels); level++)
+ {
+ Extents levelSize(
+ std::max<int>(baseSize.width >> level, 1), std::max<int>(baseSize.height >> level, 1),
+ (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth
+ : std::max<int>(baseSize.depth >> level, 1));
+ ImageDesc levelInfo(levelSize, sizedInternalFormat);
+
+ if (mTarget == GL_TEXTURE_CUBE_MAP)
+ {
+ for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
+ {
+ setImageDesc(face, level, levelInfo);
+ }
+ }
+ else
+ {
+ setImageDesc(mTarget, level, levelInfo);
+ }
+ }
+}
+
+void TextureState::clearImageDesc(GLenum target, size_t level)
+{
+ setImageDesc(target, level, ImageDesc());
+}
+
+void TextureState::clearImageDescs()
+{
+ for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
+ {
+ mImageDescs[descIndex] = ImageDesc();
+ }
+ mCompletenessCache.cacheValid = false;
+}
+
+TextureState::SamplerCompletenessCache::SamplerCompletenessCache()
: cacheValid(false),
samplerState(),
filterable(false),
@@ -987,9 +481,555 @@
{
}
+Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target)
+ : egl::ImageSibling(id),
+ mState(target),
+ mTexture(factory->createTexture(mState)),
+ mLabel(),
+ mBoundSurface(nullptr),
+ mBoundStream(nullptr)
+{
+}
+
+Texture::~Texture()
+{
+ if (mBoundSurface)
+ {
+ mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
+ mBoundSurface = nullptr;
+ }
+ if (mBoundStream)
+ {
+ mBoundStream->releaseTextures();
+ mBoundStream = nullptr;
+ }
+ SafeDelete(mTexture);
+}
+
+void Texture::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Texture::getLabel() const
+{
+ return mLabel;
+}
+
+GLenum Texture::getTarget() const
+{
+ return mState.mTarget;
+}
+
+void Texture::setSwizzleRed(GLenum swizzleRed)
+{
+ mState.mSwizzleState.swizzleRed = swizzleRed;
+}
+
+GLenum Texture::getSwizzleRed() const
+{
+ return mState.mSwizzleState.swizzleRed;
+}
+
+void Texture::setSwizzleGreen(GLenum swizzleGreen)
+{
+ mState.mSwizzleState.swizzleGreen = swizzleGreen;
+}
+
+GLenum Texture::getSwizzleGreen() const
+{
+ return mState.mSwizzleState.swizzleGreen;
+}
+
+void Texture::setSwizzleBlue(GLenum swizzleBlue)
+{
+ mState.mSwizzleState.swizzleBlue = swizzleBlue;
+}
+
+GLenum Texture::getSwizzleBlue() const
+{
+ return mState.mSwizzleState.swizzleBlue;
+}
+
+void Texture::setSwizzleAlpha(GLenum swizzleAlpha)
+{
+ mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
+}
+
+GLenum Texture::getSwizzleAlpha() const
+{
+ return mState.mSwizzleState.swizzleAlpha;
+}
+
+void Texture::setMinFilter(GLenum minFilter)
+{
+ mState.mSamplerState.minFilter = minFilter;
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mState.mSamplerState.minFilter;
+}
+
+void Texture::setMagFilter(GLenum magFilter)
+{
+ mState.mSamplerState.magFilter = magFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mState.mSamplerState.magFilter;
+}
+
+void Texture::setWrapS(GLenum wrapS)
+{
+ mState.mSamplerState.wrapS = wrapS;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mState.mSamplerState.wrapS;
+}
+
+void Texture::setWrapT(GLenum wrapT)
+{
+ mState.mSamplerState.wrapT = wrapT;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mState.mSamplerState.wrapT;
+}
+
+void Texture::setWrapR(GLenum wrapR)
+{
+ mState.mSamplerState.wrapR = wrapR;
+}
+
+GLenum Texture::getWrapR() const
+{
+ return mState.mSamplerState.wrapR;
+}
+
+void Texture::setMaxAnisotropy(float maxAnisotropy)
+{
+ mState.mSamplerState.maxAnisotropy = maxAnisotropy;
+}
+
+float Texture::getMaxAnisotropy() const
+{
+ return mState.mSamplerState.maxAnisotropy;
+}
+
+void Texture::setMinLod(GLfloat minLod)
+{
+ mState.mSamplerState.minLod = minLod;
+}
+
+GLfloat Texture::getMinLod() const
+{
+ return mState.mSamplerState.minLod;
+}
+
+void Texture::setMaxLod(GLfloat maxLod)
+{
+ mState.mSamplerState.maxLod = maxLod;
+}
+
+GLfloat Texture::getMaxLod() const
+{
+ return mState.mSamplerState.maxLod;
+}
+
+void Texture::setCompareMode(GLenum compareMode)
+{
+ mState.mSamplerState.compareMode = compareMode;
+}
+
+GLenum Texture::getCompareMode() const
+{
+ return mState.mSamplerState.compareMode;
+}
+
+void Texture::setCompareFunc(GLenum compareFunc)
+{
+ mState.mSamplerState.compareFunc = compareFunc;
+}
+
+GLenum Texture::getCompareFunc() const
+{
+ return mState.mSamplerState.compareFunc;
+}
+
+const SamplerState &Texture::getSamplerState() const
+{
+ return mState.mSamplerState;
+}
+
+void Texture::setBaseLevel(GLuint baseLevel)
+{
+ if (mState.setBaseLevel(baseLevel))
+ {
+ mTexture->setBaseLevel(mState.getEffectiveBaseLevel());
+ }
+}
+
+GLuint Texture::getBaseLevel() const
+{
+ return mState.mBaseLevel;
+}
+
+void Texture::setMaxLevel(GLuint maxLevel)
+{
+ mState.setMaxLevel(maxLevel);
+}
+
+GLuint Texture::getMaxLevel() const
+{
+ return mState.mMaxLevel;
+}
+
+bool Texture::getImmutableFormat() const
+{
+ return mState.mImmutableFormat;
+}
+
+GLuint Texture::getImmutableLevels() const
+{
+ return mState.mImmutableLevels;
+}
+
+void Texture::setUsage(GLenum usage)
+{
+ mState.mUsage = usage;
+}
+
+GLenum Texture::getUsage() const
+{
+ return mState.mUsage;
+}
+
+const TextureState &Texture::getTextureState() const
+{
+ return mState;
+}
+
+size_t Texture::getWidth(GLenum target, size_t level) const
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ return mState.getImageDesc(target, level).size.width;
+}
+
+size_t Texture::getHeight(GLenum target, size_t level) const
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ return mState.getImageDesc(target, level).size.height;
+}
+
+size_t Texture::getDepth(GLenum target, size_t level) const
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ return mState.getImageDesc(target, level).size.depth;
+}
+
+GLenum Texture::getInternalFormat(GLenum target, size_t level) const
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ return mState.getImageDesc(target, level).internalFormat;
+}
+
+bool Texture::isMipmapComplete() const
+{
+ return mState.computeMipmapCompleteness();
+}
+
+egl::Surface *Texture::getBoundSurface() const
+{
+ return mBoundSurface;
+}
+
+egl::Stream *Texture::getBoundStream() const
+{
+ return mBoundStream;
+}
+
+Error Texture::setImage(const PixelUnpackState &unpackState,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error =
+ mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mState.setImageDesc(target, level,
+ ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Texture::setSubImage(const PixelUnpackState &unpackState,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ return mTexture->setSubImage(target, level, area, format, type, unpackState, pixels);
+}
+
+Error Texture::setCompressedImage(const PixelUnpackState &unpackState,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ size_t imageSize,
+ const uint8_t *pixels)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpackState,
+ imageSize, pixels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mState.setImageDesc(target, level,
+ ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Texture::setCompressedSubImage(const PixelUnpackState &unpackState,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ size_t imageSize,
+ const uint8_t *pixels)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+
+ return mTexture->setCompressedSubImage(target, level, area, format, unpackState, imageSize,
+ pixels);
+}
+
+Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
+ const Framebuffer *source)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mState.setImageDesc(target, level,
+ ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
+ GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
+ const Framebuffer *source)
+{
+ ASSERT(target == mState.mTarget ||
+ (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+
+ return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
+}
+
+Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
+{
+ ASSERT(target == mState.mTarget);
+
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error = mTexture->setStorage(target, levels, internalFormat, size);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mState.mImmutableFormat = true;
+ mState.mImmutableLevels = static_cast<GLuint>(levels);
+ mState.clearImageDescs();
+ mState.setImageDescChain(levels, size, internalFormat);
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Texture::generateMipmaps()
+{
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+
+ // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
+ // is not mip complete.
+ if (!isMipmapComplete())
+ {
+ orphanImages();
+ }
+
+ Error error = mTexture->generateMipmaps();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), 0);
+ size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
+ mState.setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
+
+ return Error(GL_NO_ERROR);
+}
+
+void Texture::bindTexImageFromSurface(egl::Surface *surface)
+{
+ ASSERT(surface);
+
+ if (mBoundSurface)
+ {
+ releaseTexImageFromSurface();
+ }
+
+ mTexture->bindTexImage(surface);
+ mBoundSurface = surface;
+
+ // Set the image info to the size and format of the surface
+ ASSERT(mState.mTarget == GL_TEXTURE_2D);
+ Extents size(surface->getWidth(), surface->getHeight(), 1);
+ ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
+ mState.setImageDesc(mState.mTarget, 0, desc);
+}
+
+void Texture::releaseTexImageFromSurface()
+{
+ ASSERT(mBoundSurface);
+ mBoundSurface = nullptr;
+ mTexture->releaseTexImage();
+
+ // Erase the image info for level 0
+ ASSERT(mState.mTarget == GL_TEXTURE_2D);
+ mState.clearImageDesc(mState.mTarget, 0);
+}
+
+void Texture::bindStream(egl::Stream *stream)
+{
+ ASSERT(stream);
+
+ // It should not be possible to bind a texture already bound to another stream
+ ASSERT(mBoundStream == nullptr);
+
+ mBoundStream = stream;
+
+ ASSERT(mState.mTarget == GL_TEXTURE_EXTERNAL_OES);
+}
+
+void Texture::releaseStream()
+{
+ ASSERT(mBoundStream);
+ mBoundStream = nullptr;
+}
+
+void Texture::acquireImageFromStream(const egl::Stream::GLTextureDescription &desc)
+{
+ ASSERT(mBoundStream != nullptr);
+ mTexture->setImageExternal(mState.mTarget, mBoundStream, desc);
+
+ Extents size(desc.width, desc.height, 1);
+ mState.setImageDesc(mState.mTarget, 0, ImageDesc(size, desc.internalFormat));
+}
+
+void Texture::releaseImageFromStream()
+{
+ ASSERT(mBoundStream != nullptr);
+ mTexture->setImageExternal(mState.mTarget, nullptr, egl::Stream::GLTextureDescription());
+
+ // Set to incomplete
+ mState.clearImageDesc(mState.mTarget, 0);
+}
+
+void Texture::releaseTexImageInternal()
+{
+ if (mBoundSurface)
+ {
+ // Notify the surface
+ mBoundSurface->releaseTexImageFromTexture();
+
+ // Then, call the same method as from the surface
+ releaseTexImageFromSurface();
+ }
+}
+
+Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
+{
+ ASSERT(target == mState.mTarget);
+ ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES);
+
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error = mTexture->setEGLImageTarget(target, imageTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ setTargetImage(imageTarget);
+
+ Extents size(static_cast<int>(imageTarget->getWidth()),
+ static_cast<int>(imageTarget->getHeight()), 1);
+ GLenum internalFormat = imageTarget->getInternalFormat();
+ GLenum type = GetInternalFormatInfo(internalFormat).type;
+
+ mState.clearImageDescs();
+ mState.setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
+
+ return Error(GL_NO_ERROR);
+}
+
Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const
{
- return getImageDesc(target.textureIndex().type, target.textureIndex().mipIndex).size;
+ return mState.getImageDesc(target.textureIndex().type, target.textureIndex().mipIndex).size;
}
GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h
index 3708327..eac72e0 100644
--- a/src/libANGLE/Texture.h
+++ b/src/libANGLE/Texture.h
@@ -33,15 +33,48 @@
{
class GLImplFactory;
class TextureImpl;
+class TextureGL;
+class Renderer11;
}
namespace gl
{
struct ContextState;
class Framebuffer;
+class Texture;
bool IsMipmapFiltered(const SamplerState &samplerState);
+struct ImageDesc final
+{
+ ImageDesc();
+ ImageDesc(const Extents &size, GLenum internalFormat);
+
+ ImageDesc(const ImageDesc &other) = default;
+ ImageDesc &operator=(const ImageDesc &other) = default;
+
+ Extents size;
+ GLenum internalFormat;
+};
+
+struct SwizzleState final
+{
+ SwizzleState();
+ SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha);
+ SwizzleState(const SwizzleState &other) = default;
+ SwizzleState &operator=(const SwizzleState &other) = default;
+
+ bool swizzleRequired() const;
+
+ bool operator==(const SwizzleState &other) const;
+ bool operator!=(const SwizzleState &other) const;
+
+ GLenum swizzleRed;
+ GLenum swizzleGreen;
+ GLenum swizzleBlue;
+ GLenum swizzleAlpha;
+};
+
// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec.
struct TextureState final : public angle::NonCopyable
{
@@ -51,25 +84,79 @@
GLuint getEffectiveBaseLevel() const;
GLuint getEffectiveMaxLevel() const;
- // TODO(jmadill): Make the data members here private.
+ // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10.
+ size_t getMipmapMaxLevel() const;
- const GLenum target;
+ // Returns true if base level changed.
+ bool setBaseLevel(GLuint baseLevel);
+ void setMaxLevel(GLuint maxLevel);
- GLenum swizzleRed;
- GLenum swizzleGreen;
- GLenum swizzleBlue;
- GLenum swizzleAlpha;
+ bool isCubeComplete() const;
+ bool isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const;
- SamplerState samplerState;
+ const ImageDesc &getImageDesc(GLenum target, size_t level) const;
- GLuint baseLevel;
- GLuint maxLevel;
+ GLenum getTarget() const { return mTarget; }
+ const SwizzleState &getSwizzleState() const { return mSwizzleState; }
+ const SamplerState &getSamplerState() const { return mSamplerState; }
+ GLenum getUsage() const { return mUsage; }
- bool immutableFormat;
- GLuint immutableLevels;
+ private:
+ // Texture needs access to the ImageDesc functions.
+ friend class Texture;
+ // TODO(jmadill): Remove TextureGL from friends.
+ friend class rx::TextureGL;
+ friend bool operator==(const TextureState &a, const TextureState &b);
+
+ // TODO(oetuaho): Remove Renderer11 from friends when GenerateMipmap is fixed.
+ friend class rx::Renderer11;
+
+ bool computeSamplerCompleteness(const SamplerState &samplerState,
+ const ContextState &data) const;
+ bool computeMipmapCompleteness() const;
+ bool computeLevelCompleteness(GLenum target, size_t level) const;
+
+ GLenum getBaseImageTarget() const;
+
+ void setImageDesc(GLenum target, size_t level, const ImageDesc &desc);
+ void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
+ void clearImageDesc(GLenum target, size_t level);
+ void clearImageDescs();
+
+ const GLenum mTarget;
+
+ SwizzleState mSwizzleState;
+
+ SamplerState mSamplerState;
+
+ GLuint mBaseLevel;
+ GLuint mMaxLevel;
+
+ bool mImmutableFormat;
+ GLuint mImmutableLevels;
// From GL_ANGLE_texture_usage
- GLenum usage;
+ GLenum mUsage;
+
+ std::vector<ImageDesc> mImageDescs;
+
+ struct SamplerCompletenessCache
+ {
+ SamplerCompletenessCache();
+
+ bool cacheValid;
+
+ // All values that affect sampler completeness that are not stored within
+ // the texture itself
+ SamplerState samplerState;
+ bool filterable;
+ GLint clientVersion;
+ bool supportsNPOT;
+
+ // Result of the sampler completeness with the above parameters
+ bool samplerComplete;
+ };
+ mutable SamplerCompletenessCache mCompletenessCache;
};
bool operator==(const TextureState &a, const TextureState &b);
@@ -152,10 +239,7 @@
size_t getDepth(GLenum target, size_t level) const;
GLenum getInternalFormat(GLenum target, size_t level) const;
- bool isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const;
bool isMipmapComplete() const;
- bool isCubeComplete() const;
- size_t getMipCompleteLevels() const;
Error setImage(const PixelUnpackState &unpackState,
GLenum target,
@@ -240,60 +324,18 @@
std::string mLabel;
- struct ImageDesc
- {
- Extents size;
- GLenum internalFormat;
-
- ImageDesc();
- ImageDesc(const Extents &size, GLenum internalFormat);
- };
-
- GLenum getBaseImageTarget() const;
-
- bool computeSamplerCompleteness(const SamplerState &samplerState,
- const ContextState &data) const;
- bool computeMipmapCompleteness() const;
- bool computeLevelCompleteness(GLenum target, size_t level) const;
-
- const ImageDesc &getImageDesc(GLenum target, size_t level) const;
- void setImageDesc(GLenum target, size_t level, const ImageDesc &desc);
- void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
- void clearImageDesc(GLenum target, size_t level);
- void clearImageDescs();
void releaseTexImageInternal();
- std::vector<ImageDesc> mImageDescs;
-
- struct SamplerCompletenessCache
- {
- SamplerCompletenessCache();
-
- bool cacheValid;
-
- // All values that affect sampler completeness that are not stored within
- // the texture itself
- SamplerState samplerState;
- bool filterable;
- GLint clientVersion;
- bool supportsNPOT;
-
- // Result of the sampler completeness with the above parameters
- bool samplerComplete;
- };
- mutable SamplerCompletenessCache mCompletenessCache;
-
egl::Surface *mBoundSurface;
egl::Stream *mBoundStream;
};
inline bool operator==(const TextureState &a, const TextureState &b)
{
- return a.swizzleRed == b.swizzleRed && a.swizzleGreen == b.swizzleGreen &&
- a.swizzleBlue == b.swizzleBlue && a.swizzleAlpha == b.swizzleAlpha &&
- a.samplerState == b.samplerState && a.baseLevel == b.baseLevel &&
- a.maxLevel == b.maxLevel && a.immutableFormat == b.immutableFormat &&
- a.immutableLevels == b.immutableLevels && a.usage == b.usage;
+ return a.mSwizzleState == b.mSwizzleState && a.mSamplerState == b.mSamplerState &&
+ a.mBaseLevel == b.mBaseLevel && a.mMaxLevel == b.mMaxLevel &&
+ a.mImmutableFormat == b.mImmutableFormat && a.mImmutableLevels == b.mImmutableLevels &&
+ a.mUsage == b.mUsage;
}
inline bool operator!=(const TextureState &a, const TextureState &b)
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index 52c4b62..642d5a4 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -110,6 +110,9 @@
Extents() : width(0), height(0), depth(0) { }
Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { }
+ Extents(const Extents &other) = default;
+ Extents &operator=(const Extents &other) = default;
+
bool empty() const { return (width * height * depth) == 0; }
};
diff --git a/src/libANGLE/renderer/TextureImpl.h b/src/libANGLE/renderer/TextureImpl.h
index 5f1ba31..737b653 100644
--- a/src/libANGLE/renderer/TextureImpl.h
+++ b/src/libANGLE/renderer/TextureImpl.h
@@ -44,8 +44,6 @@
TextureImpl(const gl::TextureState &state) : mState(state) {}
virtual ~TextureImpl() {}
- virtual void setUsage(GLenum usage) = 0;
-
virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0;
virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
diff --git a/src/libANGLE/renderer/TextureImpl_mock.h b/src/libANGLE/renderer/TextureImpl_mock.h
index a114d5d..c521aaa 100644
--- a/src/libANGLE/renderer/TextureImpl_mock.h
+++ b/src/libANGLE/renderer/TextureImpl_mock.h
@@ -21,7 +21,6 @@
public:
MockTextureImpl() : TextureImpl(gl::TextureState(GL_TEXTURE_2D)) {}
virtual ~MockTextureImpl() { destructor(); }
- MOCK_METHOD1(setUsage, void(GLenum));
MOCK_METHOD8(setImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
MOCK_METHOD7(setSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
MOCK_METHOD7(setCompressedImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, const gl::PixelUnpackState &, size_t, const uint8_t *));
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index b98fb47..db1f769 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -180,7 +180,7 @@
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
// TODO: std::binary_search may become unavailable using older versions of GCC
- if (texture->isSamplerComplete(samplerState, data) &&
+ if (texture->getTextureState().isSamplerComplete(samplerState, data) &&
!std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture))
{
diff --git a/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/libANGLE/renderer/d3d/TextureD3D.cpp
index fb63c2e..3b94058 100644
--- a/src/libANGLE/renderer/d3d/TextureD3D.cpp
+++ b/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -78,7 +78,6 @@
TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer)
: TextureImpl(state),
mRenderer(renderer),
- mUsage(GL_NONE),
mDirtyImages(true),
mImmutable(false),
mTexStorage(nullptr),
@@ -985,7 +984,7 @@
}
// TODO(geofflang): Verify storage creation had no errors
- bool renderTarget = IsRenderTargetUsage(mUsage);
+ bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = mRenderer->createTextureStorage2D(
internalFormat, renderTarget, size.width, size.height, static_cast<int>(levels), false);
@@ -1166,7 +1165,7 @@
return gl::Error(GL_NO_ERROR);
}
- bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
+ bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage);
@@ -1598,7 +1597,7 @@
}
// TODO(geofflang): Verify storage creation had no errors
- bool renderTarget = IsRenderTargetUsage(mUsage);
+ bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = mRenderer->createTextureStorageCube(
internalFormat, renderTarget, size.width, static_cast<int>(levels), false);
@@ -1709,7 +1708,7 @@
return gl::Error(GL_NO_ERROR);
}
- bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
+ bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage);
@@ -2224,7 +2223,7 @@
}
// TODO(geofflang): Verify storage creation had no errors
- bool renderTarget = IsRenderTargetUsage(mUsage);
+ bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage =
mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height,
size.depth, static_cast<int>(levels));
@@ -2315,7 +2314,7 @@
return gl::Error(GL_NO_ERROR);
}
- bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
+ bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage);
@@ -2814,7 +2813,7 @@
}
// TODO(geofflang): Verify storage creation had no errors
- bool renderTarget = IsRenderTargetUsage(mUsage);
+ bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage =
mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width,
size.height, size.depth, static_cast<int>(levels));
@@ -2899,7 +2898,7 @@
return gl::Error(GL_NO_ERROR);
}
- bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
+ bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage);
diff --git a/src/libANGLE/renderer/d3d/TextureD3D.h b/src/libANGLE/renderer/d3d/TextureD3D.h
index eedb9f6..2424604 100644
--- a/src/libANGLE/renderer/d3d/TextureD3D.h
+++ b/src/libANGLE/renderer/d3d/TextureD3D.h
@@ -35,7 +35,6 @@
gl::Error getNativeTexture(TextureStorage **outStorage);
- virtual void setUsage(GLenum usage) { mUsage = usage; }
bool hasDirtyImages() const { return mDirtyImages; }
void resetDirty() { mDirtyImages = false; }
@@ -113,8 +112,6 @@
RendererD3D *mRenderer;
- GLenum mUsage;
-
bool mDirtyImages;
bool mImmutable;
@@ -213,7 +210,6 @@
virtual bool hasDirtyImages() const { return mDirtyImages; }
virtual void resetDirty() { mDirtyImages = false; }
- virtual void setUsage(GLenum usage) { mUsage = usage; }
GLenum getInternalFormat(GLint level, GLint layer) const;
bool isDepth(GLint level, GLint layer) const;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
index b908b98..8509687 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
@@ -608,10 +608,7 @@
gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source,
ID3D11RenderTargetView *dest,
const gl::Extents &size,
- GLenum swizzleRed,
- GLenum swizzleGreen,
- GLenum swizzleBlue,
- GLenum swizzleAlpha)
+ const gl::SwizzleState &swizzleTarget)
{
gl::Error error = initResources();
if (error.isError())
@@ -698,10 +695,10 @@
}
unsigned int *swizzleIndices = reinterpret_cast<unsigned int*>(mappedResource.pData);
- swizzleIndices[0] = GetSwizzleIndex(swizzleRed);
- swizzleIndices[1] = GetSwizzleIndex(swizzleGreen);
- swizzleIndices[2] = GetSwizzleIndex(swizzleBlue);
- swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha);
+ swizzleIndices[0] = GetSwizzleIndex(swizzleTarget.swizzleRed);
+ swizzleIndices[1] = GetSwizzleIndex(swizzleTarget.swizzleGreen);
+ swizzleIndices[2] = GetSwizzleIndex(swizzleTarget.swizzleBlue);
+ swizzleIndices[3] = GetSwizzleIndex(swizzleTarget.swizzleAlpha);
deviceContext->Unmap(mSwizzleCB, 0);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/libANGLE/renderer/d3d/d3d11/Blit11.h
index 9066161..f63998f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Blit11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Blit11.h
@@ -26,8 +26,10 @@
explicit Blit11(Renderer11 *renderer);
~Blit11();
- gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size,
- GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
+ gl::Error swizzleTexture(ID3D11ShaderResourceView *source,
+ ID3D11RenderTargetView *dest,
+ const gl::Extents &size,
+ const gl::SwizzleState &swizzleTarget);
gl::Error copyTexture(ID3D11ShaderResourceView *source,
const gl::Box &sourceArea,
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
index 800eedf..cfafe04 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -69,7 +69,7 @@
TextureImpl *Context11::createTexture(const gl::TextureState &state)
{
- switch (state.target)
+ switch (state.getTarget())
{
case GL_TEXTURE_2D:
return new TextureD3D_2D(state, mRenderer);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 5b7988b..19264e4 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1167,9 +1167,7 @@
{
TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage);
const gl::TextureState &textureState = texture->getTextureState();
- error =
- storage11->generateSwizzles(textureState.swizzleRed, textureState.swizzleGreen,
- textureState.swizzleBlue, textureState.swizzleAlpha);
+ error = storage11->generateSwizzles(textureState.getSwizzleState());
if (error.isError())
{
return error;
@@ -3609,7 +3607,8 @@
ASSERT(storage11->supportsNativeMipmapFunction());
ID3D11ShaderResourceView *srv;
- gl::Error error = storage11->getSRVLevels(textureState.baseLevel, textureState.maxLevel, &srv);
+ gl::Error error =
+ storage11->getSRVLevels(textureState.mBaseLevel, textureState.mMaxLevel, &srv);
if (error.isError())
{
return error;
diff --git a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
index a0877f1..2958168 100644
--- a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -31,33 +31,6 @@
namespace rx
{
-TextureStorage11::SwizzleCacheValue::SwizzleCacheValue()
- : swizzleRed(GL_INVALID_INDEX),
- swizzleGreen(GL_INVALID_INDEX),
- swizzleBlue(GL_INVALID_INDEX),
- swizzleAlpha(GL_INVALID_INDEX)
-{
-}
-
-TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red,
- GLenum green,
- GLenum blue,
- GLenum alpha)
- : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
-{
-}
-
-bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const
-{
- return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
- swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
-}
-
-bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const
-{
- return !(*this == other);
-}
-
TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle)
: baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle)
{
@@ -215,8 +188,9 @@
// Make sure to add the level offset for our tiny compressed texture workaround
const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel();
bool swizzleRequired = textureState.swizzleRequired();
- bool mipmapping = gl::IsMipmapFiltered(textureState.samplerState);
- unsigned int mipLevels = mipmapping ? (textureState.maxLevel - effectiveBaseLevel + 1) : 1;
+ bool mipmapping = gl::IsMipmapFiltered(textureState.getSamplerState());
+ unsigned int mipLevels =
+ mipmapping ? (textureState.getEffectiveMaxLevel() - effectiveBaseLevel + 1) : 1;
// Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level,
// which corresponds to GL level 0)
@@ -240,8 +214,7 @@
if (swizzleRequired)
{
- verifySwizzleExists(textureState.swizzleRed, textureState.swizzleGreen,
- textureState.swizzleBlue, textureState.swizzleAlpha);
+ verifySwizzleExists(textureState.getSwizzleState());
}
SRVKey key(effectiveBaseLevel, mipLevels, swizzleRequired);
@@ -359,12 +332,8 @@
return mTextureFormatSet->format;
}
-gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed,
- GLenum swizzleGreen,
- GLenum swizzleBlue,
- GLenum swizzleAlpha)
+gl::Error TextureStorage11::generateSwizzles(const gl::SwizzleState &swizzleTarget)
{
- SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha);
for (int level = 0; level < getLevelCount(); level++)
{
// Check if the swizzle for this level is out of date
@@ -390,8 +359,7 @@
Blit11 *blitter = mRenderer->getBlitter();
- error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen,
- swizzleBlue, swizzleAlpha);
+ error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleTarget);
if (error.isError())
{
return error;
@@ -408,9 +376,9 @@
{
if (mipLevel >= 0 && static_cast<unsigned int>(mipLevel) < ArraySize(mSwizzleCache))
{
- // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a
- // valid swizzle combination
- mSwizzleCache[mipLevel] = SwizzleCacheValue();
+ // The default constructor of SwizzleState has GL_INVALID_INDEX for all channels which is
+ // not a valid swizzle combination
+ mSwizzleCache[mipLevel] = gl::SwizzleState();
}
}
@@ -587,15 +555,11 @@
gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR, false);
}
-void TextureStorage11::verifySwizzleExists(GLenum swizzleRed,
- GLenum swizzleGreen,
- GLenum swizzleBlue,
- GLenum swizzleAlpha)
+void TextureStorage11::verifySwizzleExists(const gl::SwizzleState &swizzleState)
{
- SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha);
for (unsigned int level = 0; level < mMipLevels; level++)
{
- ASSERT(mSwizzleCache[level] == swizzleTarget);
+ ASSERT(mSwizzleCache[level] == swizzleState);
}
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
index b02ab75..5cd2142 100644
--- a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
@@ -58,7 +58,7 @@
virtual int getLevelCount() const;
virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
- gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
+ gl::Error generateSwizzles(const gl::SwizzleState &swizzleTarget);
void invalidateSwizzleCacheLevel(int mipLevel);
void invalidateSwizzleCache();
@@ -98,7 +98,7 @@
virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture,
ID3D11ShaderResourceView **outSRV) const = 0;
- void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
+ void verifySwizzleExists(const gl::SwizzleState &swizzleState);
// Clear all cached non-swizzle SRVs and invalidate the swizzle cache.
void clearSRVCache();
@@ -114,20 +114,7 @@
unsigned int mTextureHeight;
unsigned int mTextureDepth;
- struct SwizzleCacheValue
- {
- GLenum swizzleRed;
- GLenum swizzleGreen;
- GLenum swizzleBlue;
- GLenum swizzleAlpha;
-
- SwizzleCacheValue();
- SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha);
-
- bool operator ==(const SwizzleCacheValue &other) const;
- bool operator !=(const SwizzleCacheValue &other) const;
- };
- SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+ gl::SwizzleState mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
private:
const UINT mBindFlags;
diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
index 6949d01..55dc177 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
@@ -63,7 +63,7 @@
TextureImpl *Context9::createTexture(const gl::TextureState &state)
{
- switch (state.target)
+ switch (state.getTarget())
{
case GL_TEXTURE_2D:
return new TextureD3D_2D(state, mRenderer);
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index 7d74254..6c0c12c 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -117,7 +117,7 @@
mStateManager(stateManager),
mBlitter(blitter),
mLevelInfo(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1),
- mAppliedTextureState(state.target),
+ mAppliedTextureState(state.mTarget),
mTextureID(0)
{
ASSERT(mFunctions);
@@ -125,7 +125,7 @@
ASSERT(mBlitter);
mFunctions->genTextures(1, &mTextureID);
- mStateManager->bindTexture(mState.target, mTextureID);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
}
TextureGL::~TextureGL()
@@ -134,30 +134,24 @@
mTextureID = 0;
}
-void TextureGL::setUsage(GLenum usage)
-{
- // GL_ANGLE_texture_usage not implemented for desktop GL
- UNREACHABLE();
-}
-
gl::Error TextureGL::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{
UNUSED_ASSERTION_VARIABLE(&CompatibleTextureTarget); // Reference this function to avoid warnings.
- ASSERT(CompatibleTextureTarget(mState.target, target));
+ ASSERT(CompatibleTextureTarget(mState.mTarget, target));
nativegl::TexImageFormat texImageFormat =
nativegl::GetTexImageFormat(mFunctions, mWorkarounds, internalFormat, format, type);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(size.depth == 1);
mFunctions->texImage2D(target, static_cast<GLint>(level), texImageFormat.internalFormat,
size.width, size.height, 0, texImageFormat.format,
texImageFormat.type, pixels);
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
mFunctions->texImage3D(target, static_cast<GLint>(level), texImageFormat.internalFormat,
size.width, size.height, size.depth, 0, texImageFormat.format,
@@ -176,20 +170,20 @@
gl::Error TextureGL::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{
- ASSERT(CompatibleTextureTarget(mState.target, target));
+ ASSERT(CompatibleTextureTarget(mState.mTarget, target));
nativegl::TexSubImageFormat texSubImageFormat =
nativegl::GetTexSubImageFormat(mFunctions, mWorkarounds, format, type);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(area.z == 0 && area.depth == 1);
mFunctions->texSubImage2D(target, static_cast<GLint>(level), area.x, area.y, area.width,
area.height, texSubImageFormat.format, texSubImageFormat.type,
pixels);
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
mFunctions->texSubImage3D(target, static_cast<GLint>(level), area.x, area.y, area.z,
area.width, area.height, area.depth, texSubImageFormat.format,
@@ -209,20 +203,20 @@
gl::Error TextureGL::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
- ASSERT(CompatibleTextureTarget(mState.target, target));
+ ASSERT(CompatibleTextureTarget(mState.mTarget, target));
nativegl::CompressedTexImageFormat compressedTexImageFormat =
nativegl::GetCompressedTexImageFormat(mFunctions, mWorkarounds, internalFormat);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(size.depth == 1);
mFunctions->compressedTexImage2D(target, static_cast<GLint>(level),
compressedTexImageFormat.internalFormat, size.width,
size.height, 0, static_cast<GLsizei>(imageSize), pixels);
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
mFunctions->compressedTexImage3D(
target, static_cast<GLint>(level), compressedTexImageFormat.internalFormat, size.width,
@@ -242,20 +236,20 @@
gl::Error TextureGL::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
- ASSERT(CompatibleTextureTarget(mState.target, target));
+ ASSERT(CompatibleTextureTarget(mState.mTarget, target));
nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat =
nativegl::GetCompressedSubTexImageFormat(mFunctions, mWorkarounds, format);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(area.z == 0 && area.depth == 1);
mFunctions->compressedTexSubImage2D(
target, static_cast<GLint>(level), area.x, area.y, area.width, area.height,
compressedTexSubImageFormat.format, static_cast<GLsizei>(imageSize), pixels);
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
mFunctions->compressedTexSubImage3D(target, static_cast<GLint>(level), area.x, area.y,
area.z, area.width, area.height, area.depth,
@@ -283,7 +277,7 @@
if (levelInfo.lumaWorkaround.enabled)
{
gl::Error error = mBlitter->copyImageToLUMAWorkaroundTexture(
- mTextureID, mState.target, target, levelInfo.sourceFormat, level, sourceArea,
+ mTextureID, mState.mTarget, target, levelInfo.sourceFormat, level, sourceArea,
copyTexImageFormat.internalFormat, source);
if (error.isError())
{
@@ -294,11 +288,11 @@
{
const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
- mStateManager->bindTexture(mState.target, mTextureID);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER,
sourceFramebufferGL->getFramebufferID());
- if (UseTexImage2D(mState.target))
+ if (UseTexImage2D(mState.mTarget))
{
mFunctions->copyTexImage2D(target, static_cast<GLint>(level),
copyTexImageFormat.internalFormat, sourceArea.x,
@@ -320,14 +314,14 @@
{
const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
- mStateManager->bindTexture(mState.target, mTextureID);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
const LevelInfoGL &levelInfo = mLevelInfo[level];
if (levelInfo.lumaWorkaround.enabled)
{
gl::Error error = mBlitter->copySubImageToLUMAWorkaroundTexture(
- mTextureID, mState.target, target, levelInfo.sourceFormat, level, destOffset,
+ mTextureID, mState.mTarget, target, levelInfo.sourceFormat, level, destOffset,
sourceArea, source);
if (error.isError())
{
@@ -336,14 +330,14 @@
}
else
{
- if (UseTexImage2D(mState.target))
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(destOffset.z == 0);
mFunctions->copyTexSubImage2D(target, static_cast<GLint>(level), destOffset.x,
destOffset.y, sourceArea.x, sourceArea.y,
sourceArea.width, sourceArea.height);
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
mFunctions->copyTexSubImage3D(target, static_cast<GLint>(level), destOffset.x,
destOffset.y, destOffset.z, sourceArea.x, sourceArea.y,
@@ -366,8 +360,8 @@
nativegl::TexStorageFormat texStorageFormat =
nativegl::GetTexStorageFormat(mFunctions, mWorkarounds, internalFormat);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
ASSERT(size.depth == 1);
if (mFunctions->texStorage2D)
@@ -391,7 +385,7 @@
std::max(size.height >> level, 1),
1);
- if (mState.target == GL_TEXTURE_2D)
+ if (mState.mTarget == GL_TEXTURE_2D)
{
if (internalFormatInfo.compressed)
{
@@ -409,7 +403,7 @@
internalFormatInfo.type, nullptr);
}
}
- else if (mState.target == GL_TEXTURE_CUBE_MAP)
+ else if (mState.mTarget == GL_TEXTURE_CUBE_MAP)
{
for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++)
{
@@ -437,7 +431,7 @@
}
}
}
- else if (UseTexImage3D(mState.target))
+ else if (UseTexImage3D(mState.mTarget))
{
if (mFunctions->texStorage3D)
{
@@ -459,7 +453,7 @@
{
gl::Extents levelSize(
std::max(size.width >> i, 1), std::max(size.height >> i, 1),
- mState.target == GL_TEXTURE_3D ? std::max(size.depth >> i, 1) : size.depth);
+ mState.mTarget == GL_TEXTURE_3D ? std::max(size.depth >> i, 1) : size.depth);
if (internalFormatInfo.compressed)
{
@@ -504,12 +498,12 @@
gl::Error TextureGL::generateMipmaps()
{
- mStateManager->bindTexture(mState.target, mTextureID);
- mFunctions->generateMipmap(mState.target);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ mFunctions->generateMipmap(mState.mTarget);
- for (size_t level = mState.baseLevel; level < mLevelInfo.size(); level++)
+ for (size_t level = mState.mBaseLevel; level < mLevelInfo.size(); level++)
{
- mLevelInfo[level] = mLevelInfo[mState.baseLevel];
+ mLevelInfo[level] = mLevelInfo[mState.mBaseLevel];
}
return gl::Error(GL_NO_ERROR);
@@ -517,10 +511,10 @@
void TextureGL::bindTexImage(egl::Surface *surface)
{
- ASSERT(mState.target == GL_TEXTURE_2D);
+ ASSERT(mState.mTarget == GL_TEXTURE_2D);
// Make sure this texture is bound
- mStateManager->bindTexture(mState.target, mTextureID);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
mLevelInfo[0] = LevelInfoGL();
}
@@ -528,12 +522,12 @@
void TextureGL::releaseTexImage()
{
// Not all Surface implementations reset the size of mip 0 when releasing, do it manually
- ASSERT(mState.target == GL_TEXTURE_2D);
+ ASSERT(mState.mTarget == GL_TEXTURE_2D);
- mStateManager->bindTexture(mState.target, mTextureID);
- if (UseTexImage2D(mState.target))
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
+ if (UseTexImage2D(mState.mTarget))
{
- mFunctions->texImage2D(mState.target, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ mFunctions->texImage2D(mState.mTarget, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
}
else
@@ -586,15 +580,15 @@
static inline void SyncTextureStateSwizzle(const FunctionsGL *functions,
ApplyTextureFuncType applyTextureFunc,
const LevelInfoGL &levelInfo,
- const gl::TextureState &newState,
- gl::TextureState &curState,
+ const gl::SwizzleState &newState,
+ gl::SwizzleState &curState,
GLenum textureType,
GLenum name,
- T(gl::TextureState::*stateMember))
+ T(gl::SwizzleState::*stateMember))
{
+ GLenum resultSwizzle = newState.*stateMember;
if (levelInfo.lumaWorkaround.enabled || levelInfo.depthStencilWorkaround)
{
- GLenum resultSwizzle = GL_NONE;
if (levelInfo.lumaWorkaround.enabled)
{
UNUSED_ASSERTION_VARIABLE(levelInfo.lumaWorkaround.workaroundFormat);
@@ -697,18 +691,13 @@
UNREACHABLE();
}
- // Apply the new swizzle state if needed
- if (curState.*stateMember != resultSwizzle)
- {
- applyTextureFunc();
- curState.*stateMember = resultSwizzle;
- functions->texParameterf(textureType, name, static_cast<GLfloat>(resultSwizzle));
- }
}
- else
+
+ if (curState.*stateMember != resultSwizzle)
{
- SyncTextureStateMember(functions, applyTextureFunc, newState, curState, textureType, name,
- stateMember);
+ applyTextureFunc();
+ curState.*stateMember = resultSwizzle;
+ functions->texParameterf(textureType, name, static_cast<GLfloat>(resultSwizzle));
}
}
@@ -721,7 +710,7 @@
if (!textureApplied)
{
mStateManager->activeTexture(textureUnit);
- mStateManager->bindTexture(mState.target, mTextureID);
+ mStateManager->bindTexture(mState.mTarget, mTextureID);
textureApplied = true;
}
};
@@ -732,36 +721,36 @@
if (mAppliedTextureState.getEffectiveBaseLevel() != mState.getEffectiveBaseLevel())
{
applyTextureFunc();
- mFunctions->texParameteri(mState.target, GL_TEXTURE_BASE_LEVEL,
+ mFunctions->texParameteri(mState.mTarget, GL_TEXTURE_BASE_LEVEL,
mState.getEffectiveBaseLevel());
}
- mAppliedTextureState.baseLevel = mState.baseLevel;
+ mAppliedTextureState.mBaseLevel = mState.mBaseLevel;
if (mAppliedTextureState.getEffectiveMaxLevel() != mState.getEffectiveMaxLevel())
{
applyTextureFunc();
- mFunctions->texParameteri(mState.target, GL_TEXTURE_MAX_LEVEL,
+ mFunctions->texParameteri(mState.mTarget, GL_TEXTURE_MAX_LEVEL,
mState.getEffectiveMaxLevel());
}
- mAppliedTextureState.maxLevel = mState.maxLevel;
+ mAppliedTextureState.mMaxLevel = mState.mMaxLevel;
// clang-format off
const LevelInfoGL &levelInfo = mLevelInfo[mState.getEffectiveBaseLevel()];
- SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState, mAppliedTextureState, mState.target, GL_TEXTURE_SWIZZLE_R, &gl::TextureState::swizzleRed);
- SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState, mAppliedTextureState, mState.target, GL_TEXTURE_SWIZZLE_G, &gl::TextureState::swizzleGreen);
- SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState, mAppliedTextureState, mState.target, GL_TEXTURE_SWIZZLE_B, &gl::TextureState::swizzleBlue);
- SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState, mAppliedTextureState, mState.target, GL_TEXTURE_SWIZZLE_A, &gl::TextureState::swizzleAlpha);
+ SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState.mSwizzleState, mAppliedTextureState.mSwizzleState, mState.mTarget, GL_TEXTURE_SWIZZLE_R, &gl::SwizzleState::swizzleRed);
+ SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState.mSwizzleState, mAppliedTextureState.mSwizzleState, mState.mTarget, GL_TEXTURE_SWIZZLE_G, &gl::SwizzleState::swizzleGreen);
+ SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState.mSwizzleState, mAppliedTextureState.mSwizzleState, mState.mTarget, GL_TEXTURE_SWIZZLE_B, &gl::SwizzleState::swizzleBlue);
+ SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, mState.mSwizzleState, mAppliedTextureState.mSwizzleState, mState.mTarget, GL_TEXTURE_SWIZZLE_A, &gl::SwizzleState::swizzleAlpha);
// Sync sampler state
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_MIN_FILTER, &gl::SamplerState::minFilter);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_MAG_FILTER, &gl::SamplerState::magFilter);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_WRAP_S, &gl::SamplerState::wrapS);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_WRAP_T, &gl::SamplerState::wrapT);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_WRAP_R, &gl::SamplerState::wrapR);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_MAX_ANISOTROPY_EXT, &gl::SamplerState::maxAnisotropy);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_MIN_LOD, &gl::SamplerState::minLod);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_MAX_LOD, &gl::SamplerState::maxLod);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_COMPARE_MODE, &gl::SamplerState::compareMode);
- SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.samplerState, mAppliedTextureState.samplerState, mState.target, GL_TEXTURE_COMPARE_FUNC, &gl::SamplerState::compareFunc);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_MIN_FILTER, &gl::SamplerState::minFilter);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_MAG_FILTER, &gl::SamplerState::magFilter);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_WRAP_S, &gl::SamplerState::wrapS);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_WRAP_T, &gl::SamplerState::wrapT);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_WRAP_R, &gl::SamplerState::wrapR);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, &gl::SamplerState::maxAnisotropy);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_MIN_LOD, &gl::SamplerState::minLod);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_MAX_LOD, &gl::SamplerState::maxLod);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_COMPARE_MODE, &gl::SamplerState::compareMode);
+ SyncSamplerStateMember(mFunctions, applyTextureFunc, mState.mSamplerState, mAppliedTextureState.mSamplerState, mState.mTarget, GL_TEXTURE_COMPARE_FUNC, &gl::SamplerState::compareFunc);
// clang-format on
}
diff --git a/src/libANGLE/renderer/gl/TextureGL.h b/src/libANGLE/renderer/gl/TextureGL.h
index 1daa97b..d17e2d2 100644
--- a/src/libANGLE/renderer/gl/TextureGL.h
+++ b/src/libANGLE/renderer/gl/TextureGL.h
@@ -59,8 +59,6 @@
BlitGL *blitter);
~TextureGL() override;
- void setUsage(GLenum usage) override;
-
gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 846a32d..ffb496a 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -123,6 +123,34 @@
}
return egl::Error(EGL_SUCCESS);
}
+
+egl::Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context,
+ const gl::Texture *texture,
+ EGLAttrib level)
+{
+ // Note that the spec EGL_KHR_create_image spec does not explicitly specify an error
+ // when the level is outside the base/max level range, but it does mention that the
+ // level "must be a part of the complete texture object <buffer>". It can be argued
+ // that out-of-range levels are not a part of the complete texture.
+ const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
+ if (level > 0 &&
+ (!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel ||
+ static_cast<size_t>(level) > texture->getTextureState().getMipmapMaxLevel()))
+ {
+ return egl::Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
+ }
+
+ if (level == 0 && !texture->isMipmapComplete() &&
+ TextureHasNonZeroMipLevelsSpecified(context, texture))
+ {
+ return egl::Error(EGL_BAD_PARAMETER,
+ "if level is zero and the texture is incomplete, it must have no mip "
+ "levels specified except zero.");
+ }
+
+ return egl::Error(EGL_SUCCESS);
+}
+
} // namespace
namespace egl
@@ -862,18 +890,10 @@
"target 2D texture does not have a valid size at specified level.");
}
- if (level > 0 && (!texture->isMipmapComplete() ||
- static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
+ if (error.isError())
{
- return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
- }
-
- if (level == 0 && !texture->isMipmapComplete() &&
- TextureHasNonZeroMipLevelsSpecified(context, texture))
- {
- return Error(EGL_BAD_PARAMETER,
- "if level is zero and the texture is incomplete, it must have no mip "
- "levels specified except zero.");
+ return error;
}
}
break;
@@ -918,18 +938,10 @@
"and face.");
}
- if (level > 0 && (!texture->isMipmapComplete() ||
- static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
+ if (error.isError())
{
- return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
- }
-
- if (level == 0 && !texture->isMipmapComplete() &&
- TextureHasNonZeroMipLevelsSpecified(context, texture))
- {
- return Error(EGL_BAD_PARAMETER,
- "if level is zero and the texture is incomplete, it must have no mip "
- "levels specified except zero.");
+ return error;
}
if (level == 0 && !texture->isMipmapComplete() &&
@@ -985,18 +997,10 @@
"offset at the specified level.");
}
- if (level > 0 && (!texture->isMipmapComplete() ||
- static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
+ if (error.isError())
{
- return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
- }
-
- if (level == 0 && !texture->isMipmapComplete() &&
- TextureHasNonZeroMipLevelsSpecified(context, texture))
- {
- return Error(EGL_BAD_PARAMETER,
- "if level is zero and the texture is incomplete, it must have no mip "
- "levels specified except zero.");
+ return error;
}
}
break;
diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp
index f23f498..8a54aa9 100644
--- a/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -1298,7 +1298,7 @@
}
// Cube completeness check
- if (target == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete())
+ if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
{
context->handleError(Error(GL_INVALID_OPERATION));
return;
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 742ffbd..b086461 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -1701,6 +1701,45 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that drawing works correctly when level 0 is undefined and base level is 1.
+TEST_P(Texture2DTestES3, DrawWithLevelZeroUndefined)
+{
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Observed crashing on AMD. Oddly the crash only happens with 2D textures, not 3D or array.
+ std::cout << "Test skipped on AMD OpenGL." << std::endl;
+ return;
+ }
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
+
+ EXPECT_GL_NO_ERROR();
+
+ // Texture is incomplete.
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ // Texture is now complete.
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range have
// dimensions that don't fit the images inside the range.
// GLES 3.0.4 section 3.8.13 Texture completeness