Commit a314b61c by Olli Etuaho Committed by Commit Bot

Determine D3D texture storage size with correct base level

The size of the texture storage is now determined by extrapolating the level zero texture dimensions from the base level dimensions. This fixes crashing when images for levels below the base level are not defined, and also fixes texture storage dimensions being calculated wrong in case the levels outside the used level range have dimensions that are inconsistent with the dimensions inside the used level range. Checking texture level completeness in TextureD3D is now done based on the dimensions of the base level, and levels that are outside the base level to max level range are not taken into account. Textures are marked incomplete in case their base level is greater than their max level. Changing the base level can also affect the size of the storage required for the texture. Old storage is now discarded when the base level is changed and the new base level calls for different storage dimensions. Code in TextureD3D is refactored so that "base level" actually means the base level of the texture specified through the GLES API, and "level zero" is used where TextureD3D would sometimes previously use "base level". Changing either the base level or max level can also affect texture completeness, so invalidate the cached completeness in Texture if they are changed. Some of the added tests are still failing on Intel and NVIDIA OpenGL drivers because of driver bugs. Tests also fail on OSX. BUG=angleproject:596 TEST=angle_end2end_tests, dEQP-GLES3.functional.texture.* (no regressions), dEQP-GLES3.functional.shaders.texture_functions.* (no regressions), dEQP-GLES3.functional.state_query.texture.* (no regressions) Change-Id: Icd73d6e29f84a341ed5ff36d5ec5cb2f469cb4e8 Reviewed-on: https://chromium-review.googlesource.com/333352Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 369d03c1
...@@ -54,8 +54,10 @@ Texture::Texture(rx::ImplFactory *factory, GLuint id, GLenum target) ...@@ -54,8 +54,10 @@ Texture::Texture(rx::ImplFactory *factory, GLuint id, GLenum target)
mTexture(factory->createTexture(target)), mTexture(factory->createTexture(target)),
mLabel(), mLabel(),
mTextureState(), mTextureState(),
mEffectiveBaseLevel(0),
mTarget(target), mTarget(target),
mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
(target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
mCompletenessCache(), mCompletenessCache(),
mBoundSurface(nullptr), mBoundSurface(nullptr),
mBoundStream(nullptr) mBoundStream(nullptr)
...@@ -239,7 +241,30 @@ const SamplerState &Texture::getSamplerState() const ...@@ -239,7 +241,30 @@ const SamplerState &Texture::getSamplerState() const
void Texture::setBaseLevel(GLuint baseLevel) void Texture::setBaseLevel(GLuint baseLevel)
{ {
if (mTextureState.baseLevel != baseLevel)
{
mTextureState.baseLevel = baseLevel; mTextureState.baseLevel = baseLevel;
mCompletenessCache.cacheValid = false;
updateEffectiveBaseLevel();
mTexture->setBaseLevel(mEffectiveBaseLevel);
}
}
void Texture::updateEffectiveBaseLevel()
{
mEffectiveBaseLevel = mTextureState.baseLevel;
if (mTextureState.immutableFormat && mEffectiveBaseLevel > mTextureState.immutableLevels - 1)
{
mEffectiveBaseLevel = mTextureState.immutableLevels - 1;
}
// Ensure that this class doesn't access out-of-range memory when querying effective base level
// properties.
if (mEffectiveBaseLevel > gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
// gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS is still an out-of-range level, but the arrays
// for level data have an extra dummy level for querying out-of-range base level properties.
mEffectiveBaseLevel = gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS;
}
} }
GLuint Texture::getBaseLevel() const GLuint Texture::getBaseLevel() const
...@@ -247,9 +272,18 @@ GLuint Texture::getBaseLevel() const ...@@ -247,9 +272,18 @@ GLuint Texture::getBaseLevel() const
return mTextureState.baseLevel; return mTextureState.baseLevel;
} }
GLuint Texture::getEffectiveBaseLevel() const
{
return mEffectiveBaseLevel;
}
void Texture::setMaxLevel(GLuint maxLevel) void Texture::setMaxLevel(GLuint maxLevel)
{ {
if (mTextureState.maxLevel != maxLevel)
{
mTextureState.maxLevel = maxLevel; mTextureState.maxLevel = maxLevel;
mCompletenessCache.cacheValid = false;
}
} }
GLuint Texture::getMaxLevel() const GLuint Texture::getMaxLevel() const
...@@ -309,7 +343,7 @@ GLenum Texture::getInternalFormat(GLenum target, size_t level) const ...@@ -309,7 +343,7 @@ GLenum Texture::getInternalFormat(GLenum target, size_t level) const
bool Texture::isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const bool Texture::isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const
{ {
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mEffectiveBaseLevel);
const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
if (!mCompletenessCache.cacheValid || if (!mCompletenessCache.cacheValid ||
mCompletenessCache.samplerState != samplerState || mCompletenessCache.samplerState != samplerState ||
...@@ -506,6 +540,7 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c ...@@ -506,6 +540,7 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c
mTextureState.immutableFormat = true; mTextureState.immutableFormat = true;
mTextureState.immutableLevels = static_cast<GLuint>(levels); mTextureState.immutableLevels = static_cast<GLuint>(levels);
updateEffectiveBaseLevel();
clearImageDescs(); clearImageDescs();
setImageDescChain(levels, size, internalFormat); setImageDescChain(levels, size, internalFormat);
...@@ -715,11 +750,19 @@ GLenum Texture::getBaseImageTarget() const ...@@ -715,11 +750,19 @@ GLenum Texture::getBaseImageTarget() const
bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, bool Texture::computeSamplerCompleteness(const SamplerState &samplerState,
const ContextState &data) const const ContextState &data) const
{ {
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); if (mTextureState.baseLevel > mTextureState.maxLevel)
{
return false;
}
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mEffectiveBaseLevel);
if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
{ {
return false; return false;
} }
// The cases where the texture is incomplete because base level is out of range should be
// handled by the above condition.
ASSERT(mTextureState.baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS ||
mTextureState.immutableFormat);
if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
{ {
...@@ -792,7 +835,7 @@ bool Texture::computeMipmapCompleteness() const ...@@ -792,7 +835,7 @@ bool Texture::computeMipmapCompleteness() const
size_t maxLevel = std::min<size_t>(expectedMipLevels, mTextureState.maxLevel + 1); size_t maxLevel = std::min<size_t>(expectedMipLevels, mTextureState.maxLevel + 1);
for (size_t level = mTextureState.baseLevel; level < maxLevel; level++) for (size_t level = mEffectiveBaseLevel; level < maxLevel; level++)
{ {
if (mTarget == GL_TEXTURE_CUBE_MAP) if (mTarget == GL_TEXTURE_CUBE_MAP)
{ {
...@@ -825,7 +868,7 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const ...@@ -825,7 +868,7 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
return true; return true;
} }
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mEffectiveBaseLevel);
if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
{ {
return false; return false;
...@@ -843,8 +886,8 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const ...@@ -843,8 +886,8 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
return false; return false;
} }
ASSERT(level >= mTextureState.baseLevel); ASSERT(level >= mEffectiveBaseLevel);
const size_t relativeLevel = level - mTextureState.baseLevel; const size_t relativeLevel = level - mEffectiveBaseLevel;
if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
{ {
return false; return false;
......
...@@ -101,6 +101,8 @@ class Texture final : public egl::ImageSibling, ...@@ -101,6 +101,8 @@ class Texture final : public egl::ImageSibling,
void setBaseLevel(GLuint baseLevel); void setBaseLevel(GLuint baseLevel);
GLuint getBaseLevel() const; GLuint getBaseLevel() const;
// Returns base level after clamping required for immutable textures.
GLuint getEffectiveBaseLevel() const;
void setMaxLevel(GLuint maxLevel); void setMaxLevel(GLuint maxLevel);
GLuint getMaxLevel() const; GLuint getMaxLevel() const;
...@@ -207,6 +209,7 @@ class Texture final : public egl::ImageSibling, ...@@ -207,6 +209,7 @@ class Texture final : public egl::ImageSibling,
std::string mLabel; std::string mLabel;
TextureState mTextureState; TextureState mTextureState;
GLuint mEffectiveBaseLevel;
GLenum mTarget; GLenum mTarget;
...@@ -233,6 +236,8 @@ class Texture final : public egl::ImageSibling, ...@@ -233,6 +236,8 @@ class Texture final : public egl::ImageSibling,
void clearImageDescs(); void clearImageDescs();
void releaseTexImageInternal(); void releaseTexImageInternal();
void updateEffectiveBaseLevel();
std::vector<ImageDesc> mImageDescs; std::vector<ImageDesc> mImageDescs;
struct SamplerCompletenessCache struct SamplerCompletenessCache
......
...@@ -71,6 +71,8 @@ class TextureImpl : public FramebufferAttachmentObjectImpl ...@@ -71,6 +71,8 @@ class TextureImpl : public FramebufferAttachmentObjectImpl
virtual gl::Error generateMipmaps(const gl::TextureState &textureState) = 0; virtual gl::Error generateMipmaps(const gl::TextureState &textureState) = 0;
virtual void setBaseLevel(GLuint baseLevel) = 0;
virtual void bindTexImage(egl::Surface *surface) = 0; virtual void bindTexImage(egl::Surface *surface) = 0;
virtual void releaseTexImage() = 0; virtual void releaseTexImage() = 0;
}; };
......
...@@ -37,6 +37,8 @@ class MockTextureImpl : public TextureImpl ...@@ -37,6 +37,8 @@ class MockTextureImpl : public TextureImpl
MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **)); MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **));
MOCK_METHOD1(setBaseLevel, void(GLuint));
MOCK_METHOD0(destructor, void()); MOCK_METHOD0(destructor, void());
}; };
......
...@@ -80,7 +80,8 @@ TextureD3D::TextureD3D(RendererD3D *renderer) ...@@ -80,7 +80,8 @@ TextureD3D::TextureD3D(RendererD3D *renderer)
mUsage(GL_NONE), mUsage(GL_NONE),
mDirtyImages(true), mDirtyImages(true),
mImmutable(false), mImmutable(false),
mTexStorage(NULL) mTexStorage(nullptr),
mBaseLevel(0)
{ {
} }
...@@ -112,6 +113,21 @@ gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) ...@@ -112,6 +113,21 @@ gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
GLint TextureD3D::getLevelZeroWidth() const
{
return getBaseLevelWidth() << mBaseLevel;
}
GLint TextureD3D::getLevelZeroHeight() const
{
return getBaseLevelHeight() << mBaseLevel;
}
GLint TextureD3D::getLevelZeroDepth() const
{
return getBaseLevelDepth();
}
GLint TextureD3D::getBaseLevelWidth() const GLint TextureD3D::getBaseLevelWidth() const
{ {
const ImageD3D *baseImage = getBaseLevelImage(); const ImageD3D *baseImage = getBaseLevelImage();
...@@ -359,7 +375,9 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c ...@@ -359,7 +375,9 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c
int TextureD3D::mipLevels() const int TextureD3D::mipLevels() const
{ {
return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; return gl::log2(
std::max(std::max(getLevelZeroWidth(), getLevelZeroHeight()), getLevelZeroDepth())) +
1;
} }
TextureStorage *TextureD3D::getStorage() TextureStorage *TextureD3D::getStorage()
...@@ -370,7 +388,11 @@ TextureStorage *TextureD3D::getStorage() ...@@ -370,7 +388,11 @@ TextureStorage *TextureD3D::getStorage()
ImageD3D *TextureD3D::getBaseLevelImage() const ImageD3D *TextureD3D::getBaseLevelImage() const
{ {
return getImage(getImageIndex(0, 0)); if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return nullptr;
}
return getImage(getImageIndex(mBaseLevel, 0));
} }
gl::Error TextureD3D::setImageExternal(GLenum target, gl::Error TextureD3D::setImageExternal(GLenum target,
...@@ -444,7 +466,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages() ...@@ -444,7 +466,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages()
GLint mipCount = mipLevels(); GLint mipCount = mipLevels();
// We know that all layers have the same dimension, for the texture to be complete // We know that all layers have the same dimension, for the texture to be complete
GLint layerCount = static_cast<GLint>(getLayerCount(0)); GLint layerCount = static_cast<GLint>(getLayerCount(getBaseLevel()));
// When making mipmaps with the setData workaround enabled, the texture storage has // When making mipmaps with the setData workaround enabled, the texture storage has
// the image data already. For non-render-target storage, we have to pull it out into // the image data already. For non-render-target storage, we have to pull it out into
...@@ -540,7 +562,7 @@ bool TextureD3D::isBaseImageZeroSize() const ...@@ -540,7 +562,7 @@ bool TextureD3D::isBaseImageZeroSize() const
return true; return true;
} }
if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(getBaseLevel()) <= 0)
{ {
return true; return true;
} }
...@@ -621,6 +643,26 @@ gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment: ...@@ -621,6 +643,26 @@ gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment:
return error; return error;
} }
void TextureD3D::setBaseLevel(GLuint baseLevel)
{
const int oldStorageWidth = std::max(1, getLevelZeroWidth());
const int oldStorageHeight = std::max(1, getLevelZeroHeight());
const int oldStorageDepth = std::max(1, getLevelZeroDepth());
mBaseLevel = baseLevel;
// When the base level changes, the texture storage might not be valid anymore, since it could
// have been created based on the dimensions of the previous specified level range.
const int newStorageWidth = std::max(1, getLevelZeroWidth());
const int newStorageHeight = std::max(1, getLevelZeroHeight());
const int newStorageDepth = std::max(1, getLevelZeroDepth());
if (mTexStorage && (newStorageWidth != oldStorageWidth ||
newStorageHeight != oldStorageHeight || newStorageDepth != oldStorageDepth))
{
markAllImagesDirty();
SafeDelete(mTexStorage);
}
}
TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
: TextureD3D(renderer) : TextureD3D(renderer)
{ {
...@@ -1025,9 +1067,8 @@ void TextureD3D_2D::initMipmapsImages() ...@@ -1025,9 +1067,8 @@ void TextureD3D_2D::initMipmapsImages()
int levelCount = mipLevels(); int levelCount = mipLevels();
for (int level = 1; level < levelCount; level++) for (int level = 1; level < levelCount; level++)
{ {
gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
std::max(getBaseLevelHeight() >> level, 1), std::max(getLevelZeroHeight() >> level, 1), 1);
1);
redefineImage(level, getBaseLevelInternalFormat(), levelSize, false); redefineImage(level, getBaseLevelInternalFormat(), levelSize, false);
} }
...@@ -1065,10 +1106,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const ...@@ -1065,10 +1106,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const
return true; return true;
} }
const ImageD3D *baseImage = getBaseLevelImage(); GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
GLsizei width = baseImage->getWidth();
GLsizei height = baseImage->getHeight();
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
{ {
...@@ -1076,15 +1115,15 @@ bool TextureD3D_2D::isLevelComplete(int level) const ...@@ -1076,15 +1115,15 @@ bool TextureD3D_2D::isLevelComplete(int level) const
} }
// The base image level is complete if the width and height are positive // The base image level is complete if the width and height are positive
if (level == 0) if (level == static_cast<int>(getBaseLevel()))
{ {
return true; return true;
} }
ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); ASSERT(level >= 0 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != nullptr);
ImageD3D *image = mImageArray[level]; ImageD3D *image = mImageArray[level];
if (image->getInternalFormat() != baseImage->getInternalFormat()) if (image->getInternalFormat() != getBaseLevelInternalFormat())
{ {
return false; return false;
} }
...@@ -1117,7 +1156,7 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) ...@@ -1117,7 +1156,7 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
} }
// do not attempt to create storage for nonexistant data // do not attempt to create storage for nonexistant data
if (!isLevelComplete(0)) if (!isLevelComplete(getBaseLevel()))
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -1152,8 +1191,8 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) ...@@ -1152,8 +1191,8 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
{ {
GLsizei width = getBaseLevelWidth(); GLsizei width = getLevelZeroWidth();
GLsizei height = getBaseLevelHeight(); GLsizei height = getLevelZeroHeight();
GLenum internalFormat = getBaseLevelInternalFormat(); GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0); ASSERT(width > 0 && height > 0);
...@@ -1247,8 +1286,8 @@ void TextureD3D_2D::redefineImage(size_t level, ...@@ -1247,8 +1286,8 @@ void TextureD3D_2D::redefineImage(size_t level,
ASSERT(size.depth == 1); ASSERT(size.depth == 1);
// If there currently is a corresponding storage texture image, it has these parameters // If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level); const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat(); const GLenum storageFormat = getBaseLevelInternalFormat();
mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease); mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease);
...@@ -1270,13 +1309,8 @@ void TextureD3D_2D::redefineImage(size_t level, ...@@ -1270,13 +1309,8 @@ void TextureD3D_2D::redefineImage(size_t level,
size.height != storageHeight || size.height != storageHeight ||
internalformat != storageFormat) // Discard mismatched storage internalformat != storageFormat) // Discard mismatched storage
{ {
for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) markAllImagesDirty();
{
mImageArray[i]->markDirty();
}
SafeDelete(mTexStorage); SafeDelete(mTexStorage);
mDirtyImages = true;
} }
} }
...@@ -1301,6 +1335,15 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const ...@@ -1301,6 +1335,15 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
} }
void TextureD3D_2D::markAllImagesDirty()
{
for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
mImageArray[i]->markDirty();
}
mDirtyImages = true;
}
TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
: TextureD3D(renderer) : TextureD3D(renderer)
{ {
...@@ -1588,7 +1631,7 @@ bool TextureD3D_Cube::isCubeComplete() const ...@@ -1588,7 +1631,7 @@ bool TextureD3D_Cube::isCubeComplete() const
for (int faceIndex = 1; faceIndex < 6; faceIndex++) for (int faceIndex = 1; faceIndex < 6; faceIndex++)
{ {
const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
if (faceBaseImage.getWidth() != baseWidth || if (faceBaseImage.getWidth() != baseWidth ||
faceBaseImage.getHeight() != baseHeight || faceBaseImage.getHeight() != baseHeight ||
...@@ -1656,7 +1699,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) ...@@ -1656,7 +1699,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
} }
// do not attempt to create storage for nonexistant data // do not attempt to create storage for nonexistant data
if (!isFaceLevelComplete(0, 0)) if (!isFaceLevelComplete(0, getBaseLevel()))
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -1691,7 +1734,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) ...@@ -1691,7 +1734,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
{ {
GLsizei size = getBaseLevelWidth(); GLsizei size = getLevelZeroWidth();
ASSERT(size > 0); ASSERT(size > 0);
...@@ -1772,16 +1815,21 @@ bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const ...@@ -1772,16 +1815,21 @@ bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
{ {
ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return false;
}
ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) &&
mImageArray[faceIndex][level] != nullptr);
if (isImmutable()) if (isImmutable())
{ {
return true; return true;
} }
int baseSize = getBaseLevelWidth(); int levelZeroSize = getLevelZeroWidth();
if (baseSize <= 0) if (levelZeroSize <= 0)
{ {
return false; return false;
} }
...@@ -1802,7 +1850,7 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const ...@@ -1802,7 +1850,7 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
return false; return false;
} }
if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
{ {
return false; return false;
} }
...@@ -1838,8 +1886,8 @@ gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) ...@@ -1838,8 +1886,8 @@ gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
{ {
// If there currently is a corresponding storage texture image, it has these parameters // If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level); const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat(); const GLenum storageFormat = getBaseLevelInternalFormat();
mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
...@@ -1853,17 +1901,8 @@ void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalf ...@@ -1853,17 +1901,8 @@ void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalf
size.height != storageHeight || size.height != storageHeight ||
internalformat != storageFormat) // Discard mismatched storage internalformat != storageFormat) // Discard mismatched storage
{ {
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) markAllImagesDirty();
{
for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++)
{
mImageArray[dirtyFace][dirtyLevel]->markDirty();
}
}
SafeDelete(mTexStorage); SafeDelete(mTexStorage);
mDirtyImages = true;
} }
} }
} }
...@@ -1885,6 +1924,18 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const ...@@ -1885,6 +1924,18 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
} }
void TextureD3D_Cube::markAllImagesDirty()
{
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
{
for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++)
{
mImageArray[dirtyFace][dirtyLevel]->markDirty();
}
}
mDirtyImages = true;
}
TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
: TextureD3D(renderer) : TextureD3D(renderer)
{ {
...@@ -1991,7 +2042,7 @@ gl::Error TextureD3D_3D::setImage(GLenum target, ...@@ -1991,7 +2042,7 @@ gl::Error TextureD3D_3D::setImage(GLenum target,
gl::ImageIndex index = gl::ImageIndex::Make3D(level); gl::ImageIndex index = gl::ImageIndex::Make3D(level);
// Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty()) if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty() && isLevelComplete(level))
{ {
// Will try to create RT storage if it does not exist // Will try to create RT storage if it does not exist
RenderTargetD3D *destRenderTarget = NULL; RenderTargetD3D *destRenderTarget = NULL;
...@@ -2041,7 +2092,7 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target, ...@@ -2041,7 +2092,7 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target,
gl::ImageIndex index = gl::ImageIndex::Make3D(level); gl::ImageIndex index = gl::ImageIndex::Make3D(level);
// Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
if (isFastUnpackable(unpack, getInternalFormat(level))) if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
{ {
RenderTargetD3D *destRenderTarget = NULL; RenderTargetD3D *destRenderTarget = NULL;
gl::Error error = getRenderTarget(index, &destRenderTarget); gl::Error error = getRenderTarget(index, &destRenderTarget);
...@@ -2209,9 +2260,9 @@ void TextureD3D_3D::initMipmapsImages() ...@@ -2209,9 +2260,9 @@ void TextureD3D_3D::initMipmapsImages()
int levelCount = mipLevels(); int levelCount = mipLevels();
for (int level = 1; level < levelCount; level++) for (int level = 1; level < levelCount; level++)
{ {
gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
std::max(getBaseLevelHeight() >> level, 1), std::max(getLevelZeroHeight() >> level, 1),
std::max(getBaseLevelDepth() >> level, 1)); std::max(getLevelZeroDepth() >> level, 1));
redefineImage(level, getBaseLevelInternalFormat(), levelSize); redefineImage(level, getBaseLevelInternalFormat(), levelSize);
} }
} }
...@@ -2254,7 +2305,7 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) ...@@ -2254,7 +2305,7 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
} }
// do not attempt to create storage for nonexistant data // do not attempt to create storage for nonexistant data
if (!isLevelComplete(0)) if (!isLevelComplete(getBaseLevel()))
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -2289,9 +2340,9 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) ...@@ -2289,9 +2340,9 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
{ {
GLsizei width = getBaseLevelWidth(); GLsizei width = getLevelZeroWidth();
GLsizei height = getBaseLevelHeight(); GLsizei height = getLevelZeroHeight();
GLsizei depth = getBaseLevelDepth(); GLsizei depth = getLevelZeroDepth();
GLenum internalFormat = getBaseLevelInternalFormat(); GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0 && depth > 0); ASSERT(width > 0 && height > 0 && depth > 0);
...@@ -2350,16 +2401,16 @@ bool TextureD3D_3D::isLevelComplete(int level) const ...@@ -2350,16 +2401,16 @@ bool TextureD3D_3D::isLevelComplete(int level) const
return true; return true;
} }
GLsizei width = getBaseLevelWidth(); GLsizei width = getLevelZeroWidth();
GLsizei height = getBaseLevelHeight(); GLsizei height = getLevelZeroHeight();
GLsizei depth = getBaseLevelDepth(); GLsizei depth = getLevelZeroDepth();
if (width <= 0 || height <= 0 || depth <= 0) if (width <= 0 || height <= 0 || depth <= 0)
{ {
return false; return false;
} }
if (level == 0) if (level == static_cast<int>(getBaseLevel()))
{ {
return true; return true;
} }
...@@ -2416,15 +2467,15 @@ gl::Error TextureD3D_3D::updateStorageLevel(int level) ...@@ -2416,15 +2467,15 @@ gl::Error TextureD3D_3D::updateStorageLevel(int level)
void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
{ {
// If there currently is a corresponding storage texture image, it has these parameters // If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level); const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const int storageDepth = std::max(1, getBaseLevelDepth() >> level); const int storageDepth = std::max(1, getLevelZeroDepth() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat();
mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
if (mTexStorage) if (mTexStorage)
{ {
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageLevels = mTexStorage->getLevelCount(); const int storageLevels = mTexStorage->getLevelCount();
if ((level >= storageLevels && storageLevels != 0) || if ((level >= storageLevels && storageLevels != 0) ||
...@@ -2433,13 +2484,8 @@ void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl:: ...@@ -2433,13 +2484,8 @@ void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::
size.depth != storageDepth || size.depth != storageDepth ||
internalformat != storageFormat) // Discard mismatched storage internalformat != storageFormat) // Discard mismatched storage
{ {
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) markAllImagesDirty();
{
mImageArray[i]->markDirty();
}
SafeDelete(mTexStorage); SafeDelete(mTexStorage);
mDirtyImages = true;
} }
} }
} }
...@@ -2462,6 +2508,20 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const ...@@ -2462,6 +2508,20 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
} }
void TextureD3D_3D::markAllImagesDirty()
{
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
mImageArray[i]->markDirty();
}
mDirtyImages = true;
}
GLint TextureD3D_3D::getLevelZeroDepth() const
{
return getBaseLevelDepth() << getBaseLevel();
}
TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
: TextureD3D(renderer) : TextureD3D(renderer)
{ {
...@@ -2708,8 +2768,10 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target, ...@@ -2708,8 +2768,10 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target,
return error; return error;
} }
error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format, error = mRenderer->copyImage2DArray(
destOffset, mTexStorage, level); source, sourceArea,
gl::GetInternalFormatInfo(getInternalFormat(getBaseLevel())).format, destOffset,
mTexStorage, level);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -2784,9 +2846,9 @@ void TextureD3D_2DArray::releaseTexImage() ...@@ -2784,9 +2846,9 @@ void TextureD3D_2DArray::releaseTexImage()
void TextureD3D_2DArray::initMipmapsImages() void TextureD3D_2DArray::initMipmapsImages()
{ {
int baseWidth = getBaseLevelWidth(); int baseWidth = getLevelZeroWidth();
int baseHeight = getBaseLevelHeight(); int baseHeight = getLevelZeroHeight();
int baseDepth = getLayerCount(0); int baseDepth = getLayerCount(getBaseLevel());
GLenum baseFormat = getBaseLevelInternalFormat(); GLenum baseFormat = getBaseLevelInternalFormat();
// Purge array levels 1 through q and reset them to represent the generated mipmap levels. // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
...@@ -2827,7 +2889,7 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) ...@@ -2827,7 +2889,7 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
} }
// do not attempt to create storage for nonexistant data // do not attempt to create storage for nonexistant data
if (!isLevelComplete(0)) if (!isLevelComplete(getBaseLevel()))
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -2862,9 +2924,9 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) ...@@ -2862,9 +2924,9 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
{ {
GLsizei width = getBaseLevelWidth(); GLsizei width = getLevelZeroWidth();
GLsizei height = getBaseLevelHeight(); GLsizei height = getLevelZeroHeight();
GLsizei depth = getLayerCount(0); GLsizei depth = getLayerCount(getBaseLevel());
GLenum internalFormat = getBaseLevelInternalFormat(); GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0 && depth > 0); ASSERT(width > 0 && height > 0 && depth > 0);
...@@ -2923,21 +2985,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const ...@@ -2923,21 +2985,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const
return true; return true;
} }
GLsizei width = getBaseLevelWidth(); GLsizei width = getLevelZeroWidth();
GLsizei height = getBaseLevelHeight(); GLsizei height = getLevelZeroHeight();
GLsizei layers = getLayerCount(0);
if (width <= 0 || height <= 0 || layers <= 0) if (width <= 0 || height <= 0)
{ {
return false; return false;
} }
if (level == 0) // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
// queried.
GLsizei layers = getLayerCount(getBaseLevel());
if (layers <= 0)
{
return false;
}
if (level == static_cast<int>(getBaseLevel()))
{ {
return true; return true;
} }
if (getInternalFormat(level) != getInternalFormat(0)) if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
{ {
return false; return false;
} }
...@@ -3005,10 +3075,14 @@ void TextureD3D_2DArray::deleteImages() ...@@ -3005,10 +3075,14 @@ void TextureD3D_2DArray::deleteImages()
void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
{ {
// If there currently is a corresponding storage texture image, it has these parameters // If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level); const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const int storageDepth = getLayerCount(0); const GLuint baseLevel = getBaseLevel();
const GLenum storageFormat = getBaseLevelInternalFormat(); int storageDepth = 0;
if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
storageDepth = getLayerCount(baseLevel);
}
// Only reallocate the layers if the size doesn't match // Only reallocate the layers if the size doesn't match
if (size.depth != mLayerCounts[level]) if (size.depth != mLayerCounts[level])
...@@ -3041,6 +3115,7 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const ...@@ -3041,6 +3115,7 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const
if (mTexStorage) if (mTexStorage)
{ {
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageLevels = mTexStorage->getLevelCount(); const int storageLevels = mTexStorage->getLevelCount();
if ((level >= storageLevels && storageLevels != 0) || if ((level >= storageLevels && storageLevels != 0) ||
...@@ -3049,17 +3124,8 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const ...@@ -3049,17 +3124,8 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const
size.depth != storageDepth || size.depth != storageDepth ||
internalformat != storageFormat) // Discard mismatched storage internalformat != storageFormat) // Discard mismatched storage
{ {
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) markAllImagesDirty();
{ SafeDelete(mTexStorage);
for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
{
mImageArray[dirtyLevel][dirtyLayer]->markDirty();
}
}
delete mTexStorage;
mTexStorage = NULL;
mDirtyImages = true;
} }
} }
} }
...@@ -3092,6 +3158,18 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const ...@@ -3092,6 +3158,18 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
} }
void TextureD3D_2DArray::markAllImagesDirty()
{
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
{
for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
{
mImageArray[dirtyLevel][dirtyLayer]->markDirty();
}
}
mDirtyImages = true;
}
TextureD3D_External::TextureD3D_External(RendererD3D *renderer) : TextureD3D(renderer) TextureD3D_External::TextureD3D_External(RendererD3D *renderer) : TextureD3D(renderer)
{ {
mImage = renderer->createImage(); mImage = renderer->createImage();
...@@ -3338,4 +3416,9 @@ bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const ...@@ -3338,4 +3416,9 @@ bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
{ {
return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0); return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0);
} }
void TextureD3D_External::markAllImagesDirty()
{
UNREACHABLE();
}
} }
...@@ -44,7 +44,6 @@ class TextureD3D : public TextureImpl ...@@ -44,7 +44,6 @@ class TextureD3D : public TextureImpl
GLint getBaseLevelWidth() const; GLint getBaseLevelWidth() const;
GLint getBaseLevelHeight() const; GLint getBaseLevelHeight() const;
GLint getBaseLevelDepth() const;
GLenum getBaseLevelInternalFormat() const; GLenum getBaseLevelInternalFormat() const;
bool isImmutable() const { return mImmutable; } bool isImmutable() const { return mImmutable; }
...@@ -69,6 +68,8 @@ class TextureD3D : public TextureImpl ...@@ -69,6 +68,8 @@ class TextureD3D : public TextureImpl
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
FramebufferAttachmentRenderTarget **rtOut) override; FramebufferAttachmentRenderTarget **rtOut) override;
void setBaseLevel(GLuint baseLevel) override;
protected: protected:
gl::Error setImageImpl(const gl::ImageIndex &index, gl::Error setImageImpl(const gl::ImageIndex &index,
GLenum type, GLenum type,
...@@ -87,6 +88,10 @@ class TextureD3D : public TextureImpl ...@@ -87,6 +88,10 @@ class TextureD3D : public TextureImpl
gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget); GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget);
GLint getLevelZeroWidth() const;
GLint getLevelZeroHeight() const;
virtual GLint getLevelZeroDepth() const;
GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const;
int mipLevels() const; int mipLevels() const;
virtual void initMipmapsImages() = 0; virtual void initMipmapsImages() = 0;
...@@ -100,6 +105,12 @@ class TextureD3D : public TextureImpl ...@@ -100,6 +105,12 @@ class TextureD3D : public TextureImpl
virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0;
gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region); gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
GLuint getBaseLevel() const { return mBaseLevel; };
virtual void markAllImagesDirty() = 0;
GLint getBaseLevelDepth() const;
RendererD3D *mRenderer; RendererD3D *mRenderer;
GLenum mUsage; GLenum mUsage;
...@@ -117,6 +128,8 @@ class TextureD3D : public TextureImpl ...@@ -117,6 +128,8 @@ class TextureD3D : public TextureImpl
bool shouldUseSetData(const ImageD3D *image) const; bool shouldUseSetData(const ImageD3D *image) const;
gl::Error generateMipmapsUsingImages(); gl::Error generateMipmapsUsingImages();
GLuint mBaseLevel;
}; };
class TextureD3D_2D : public TextureD3D class TextureD3D_2D : public TextureD3D
...@@ -162,6 +175,9 @@ class TextureD3D_2D : public TextureD3D ...@@ -162,6 +175,9 @@ class TextureD3D_2D : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const; virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private: private:
virtual gl::Error initializeStorage(bool renderTarget); virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
...@@ -230,6 +246,9 @@ class TextureD3D_Cube : public TextureD3D ...@@ -230,6 +246,9 @@ class TextureD3D_Cube : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const; virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private: private:
virtual gl::Error initializeStorage(bool renderTarget); virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
...@@ -293,6 +312,10 @@ class TextureD3D_3D : public TextureD3D ...@@ -293,6 +312,10 @@ class TextureD3D_3D : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const; virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
GLint getLevelZeroDepth() const override;
private: private:
virtual gl::Error initializeStorage(bool renderTarget); virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
...@@ -354,6 +377,9 @@ class TextureD3D_2DArray : public TextureD3D ...@@ -354,6 +377,9 @@ class TextureD3D_2DArray : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const; virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private: private:
virtual gl::Error initializeStorage(bool renderTarget); virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
...@@ -454,6 +480,9 @@ class TextureD3D_External : public TextureD3D ...@@ -454,6 +480,9 @@ class TextureD3D_External : public TextureD3D
gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override;
bool isValidIndex(const gl::ImageIndex &index) const override; bool isValidIndex(const gl::ImageIndex &index) const override;
protected:
void markAllImagesDirty() override;
private: private:
gl::Error initializeStorage(bool renderTarget) override; gl::Error initializeStorage(bool renderTarget) override;
gl::Error createCompleteStorage(bool renderTarget, gl::Error createCompleteStorage(bool renderTarget,
......
...@@ -1298,7 +1298,7 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t ...@@ -1298,7 +1298,7 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t
// Make sure to add the level offset for our tiny compressed texture workaround // Make sure to add the level offset for our tiny compressed texture workaround
gl::TextureState textureState = texture->getTextureState(); gl::TextureState textureState = texture->getTextureState();
textureState.baseLevel += storage11->getTopLevel(); textureState.baseLevel = texture->getEffectiveBaseLevel() + storage11->getTopLevel();
error = storage11->getSRV(textureState, &textureSRV); error = storage11->getSRV(textureState, &textureSRV);
if (error.isError()) if (error.isError())
...@@ -2413,8 +2413,8 @@ void Renderer11::SamplerMetadataD3D11::initData(unsigned int samplerCount) ...@@ -2413,8 +2413,8 @@ void Renderer11::SamplerMetadataD3D11::initData(unsigned int samplerCount)
void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, const gl::Texture &texture) void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, const gl::Texture &texture)
{ {
unsigned int baseLevel = texture.getBaseLevel(); unsigned int baseLevel = texture.getEffectiveBaseLevel();
GLenum internalFormat = texture.getInternalFormat(texture.getTarget(), texture.getBaseLevel()); GLenum internalFormat = texture.getInternalFormat(texture.getTarget(), baseLevel);
if (mSamplerMetadata[samplerIndex].baseLevel != static_cast<int>(baseLevel)) if (mSamplerMetadata[samplerIndex].baseLevel != static_cast<int>(baseLevel))
{ {
mSamplerMetadata[samplerIndex].baseLevel = static_cast<int>(baseLevel); mSamplerMetadata[samplerIndex].baseLevel = static_cast<int>(baseLevel);
......
...@@ -729,7 +729,8 @@ gl::Error StateManagerGL::setGenericDrawState(const gl::ContextState &data) ...@@ -729,7 +729,8 @@ gl::Error StateManagerGL::setGenericDrawState(const gl::ContextState &data)
bindTexture(textureType, textureGL->getTextureID()); bindTexture(textureType, textureGL->getTextureID());
} }
textureGL->syncState(textureUnitIndex, texture->getTextureState()); textureGL->syncState(textureUnitIndex, texture->getTextureState(),
texture->getEffectiveBaseLevel());
} }
else else
{ {
......
...@@ -117,7 +117,7 @@ TextureGL::TextureGL(GLenum type, ...@@ -117,7 +117,7 @@ TextureGL::TextureGL(GLenum type,
mWorkarounds(workarounds), mWorkarounds(workarounds),
mStateManager(stateManager), mStateManager(stateManager),
mBlitter(blitter), mBlitter(blitter),
mLevelInfo(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS), mLevelInfo(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1),
mAppliedTextureState(), mAppliedTextureState(),
mTextureID(0) mTextureID(0)
{ {
...@@ -712,7 +712,9 @@ static inline void SyncTextureStateSwizzle(const FunctionsGL *functions, ...@@ -712,7 +712,9 @@ static inline void SyncTextureStateSwizzle(const FunctionsGL *functions,
} }
} }
void TextureGL::syncState(size_t textureUnit, const gl::TextureState &textureState) const void TextureGL::syncState(size_t textureUnit,
const gl::TextureState &textureState,
const GLuint effectiveBaseLevel) const
{ {
// Callback lamdba to bind this texture only if needed. // Callback lamdba to bind this texture only if needed.
bool textureApplied = false; bool textureApplied = false;
...@@ -732,7 +734,7 @@ void TextureGL::syncState(size_t textureUnit, const gl::TextureState &textureSta ...@@ -732,7 +734,7 @@ void TextureGL::syncState(size_t textureUnit, const gl::TextureState &textureSta
SyncTextureStateMember(mFunctions, applyTextureFunc, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_BASE_LEVEL, &gl::TextureState::baseLevel); SyncTextureStateMember(mFunctions, applyTextureFunc, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_BASE_LEVEL, &gl::TextureState::baseLevel);
SyncTextureStateMember(mFunctions, applyTextureFunc, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_MAX_LEVEL, &gl::TextureState::maxLevel); SyncTextureStateMember(mFunctions, applyTextureFunc, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_MAX_LEVEL, &gl::TextureState::maxLevel);
const LevelInfoGL &levelInfo = mLevelInfo[textureState.baseLevel]; const LevelInfoGL &levelInfo = mLevelInfo[effectiveBaseLevel];
SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_R, &gl::TextureState::swizzleRed); SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_R, &gl::TextureState::swizzleRed);
SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_G, &gl::TextureState::swizzleGreen); SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_G, &gl::TextureState::swizzleGreen);
SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_B, &gl::TextureState::swizzleBlue); SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_B, &gl::TextureState::swizzleBlue);
......
...@@ -88,7 +88,9 @@ class TextureGL : public TextureImpl ...@@ -88,7 +88,9 @@ class TextureGL : public TextureImpl
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
void syncState(size_t textureUnit, const gl::TextureState &textureState) const; void syncState(size_t textureUnit,
const gl::TextureState &textureState,
const GLuint effectiveBaseLevel) const;
GLuint getTextureID() const; GLuint getTextureID() const;
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
...@@ -97,6 +99,8 @@ class TextureGL : public TextureImpl ...@@ -97,6 +99,8 @@ class TextureGL : public TextureImpl
return gl::Error(GL_OUT_OF_MEMORY, "Not supported on OpenGL"); return gl::Error(GL_OUT_OF_MEMORY, "Not supported on OpenGL");
} }
void setBaseLevel(GLuint) override {}
private: private:
GLenum mTextureType; GLenum mTextureType;
......
...@@ -1008,13 +1008,21 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pnam ...@@ -1008,13 +1008,21 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pnam
case GL_TEXTURE_BASE_LEVEL: case GL_TEXTURE_BASE_LEVEL:
case GL_TEXTURE_MAX_LEVEL: case GL_TEXTURE_MAX_LEVEL:
if (target == GL_TEXTURE_EXTERNAL_OES)
{
// This is not specified, but in line with the spirit of OES_EGL_image_external spec,
// which generally forbids setting mipmap related parameters on external textures.
context->handleError(
Error(GL_INVALID_OPERATION,
"Setting the base level or max level of external textures not supported"));
return false;
}
if (param < 0) if (param < 0)
{ {
context->handleError(Error(GL_INVALID_VALUE)); context->handleError(Error(GL_INVALID_VALUE));
return false; return false;
} }
return true; return true;
default: default:
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
return false; return false;
......
...@@ -268,7 +268,7 @@ class Texture2DTest : public TexCoordDrawTest ...@@ -268,7 +268,7 @@ class Texture2DTest : public TexCoordDrawTest
int testImageChannels = std::min(sourceImageChannels, destImageChannels); int testImageChannels = std::min(sourceImageChannels, destImageChannels);
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
if (testImageChannels > 1) if (testImageChannels > 1)
{ {
EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255); EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255);
...@@ -780,6 +780,60 @@ class TextureSizeTextureArrayTest : public TexCoordDrawTest ...@@ -780,6 +780,60 @@ class TextureSizeTextureArrayTest : public TexCoordDrawTest
GLint mTexture1Location; GLint mTexture1Location;
}; };
class Texture3DTestES3 : public TexCoordDrawTest
{
protected:
Texture3DTestES3() : TexCoordDrawTest(), mTexture3D(0), mTexture3DUniformLocation(-1) {}
std::string getVertexShaderSource() override
{
return std::string(
"#version 300 es\n"
"out vec2 texcoord;\n"
"in vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position.xy, 0.0, 1.0);\n"
" texcoord = (position.xy * 0.5) + 0.5;\n"
"}\n");
}
std::string getFragmentShaderSource() override
{
return std::string(
"#version 300 es\n"
"precision highp float;\n"
"uniform highp sampler3D tex3D;\n"
"in vec2 texcoord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
" fragColor = texture(tex3D, vec3(texcoord, 0.0));\n"
"}\n");
}
void SetUp() override
{
TexCoordDrawTest::SetUp();
glGenTextures(1, &mTexture3D);
setUpProgram();
mTexture3DUniformLocation = glGetUniformLocation(mProgram, "tex3D");
ASSERT_NE(-1, mTexture3DUniformLocation);
}
void TearDown() override
{
glDeleteTextures(1, &mTexture3D);
TexCoordDrawTest::TearDown();
}
GLuint mTexture3D;
GLint mTexture3DUniformLocation;
};
class ShadowSamplerPlusSampler3DTestES3 : public TexCoordDrawTest class ShadowSamplerPlusSampler3DTestES3 : public TexCoordDrawTest
{ {
protected: protected:
...@@ -990,11 +1044,10 @@ class SamplerInStructTest : public Texture2DTest ...@@ -990,11 +1044,10 @@ class SamplerInStructTest : public Texture2DTest
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D); glBindTexture(GL_TEXTURE_2D, mTexture2D);
GLubyte texDataGreen[1u * 1u * 4u]; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
FillWithRGBA<GLubyte>(1u * 1u, 0u, 255u, 0u, 255u, texDataGreen); &GLColor::green);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
}; };
...@@ -1232,11 +1285,9 @@ TEST_P(Texture2DTestWithDrawScale, MipmapsTwice) ...@@ -1232,11 +1285,9 @@ TEST_P(Texture2DTestWithDrawScale, MipmapsTwice)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D); glBindTexture(GL_TEXTURE_2D, mTexture2D);
// Fill with red std::vector<GLColor> pixelsRed(16u * 16u, GLColor::red);
std::vector<GLubyte> pixels(4 * 16 * 16);
FillWithRGBA<GLubyte>(16u * 16u, 255u, 0u, 0u, 255u, pixels.data());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
...@@ -1246,24 +1297,24 @@ TEST_P(Texture2DTestWithDrawScale, MipmapsTwice) ...@@ -1246,24 +1297,24 @@ TEST_P(Texture2DTestWithDrawScale, MipmapsTwice)
glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f); glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f);
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255); EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Fill with blue std::vector<GLColor> pixelsBlue(16u * 16u, GLColor::blue);
FillWithRGBA<GLubyte>(16u * 16u, 0u, 0u, 255u, 255u, pixels.data());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsBlue.data());
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
// Fill with green std::vector<GLColor> pixelsGreen(16u * 16u, GLColor::green);
FillWithRGBA<GLubyte>(16u * 16u, 0u, 255u, 0u, 255u, pixels.data());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsGreen.data());
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255); EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
} }
// Test creating a FBO with a cube map render target, to test an ANGLE bug // Test creating a FBO with a cube map render target, to test an ANGLE bug
...@@ -1598,22 +1649,543 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1) ...@@ -1598,22 +1649,543 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1)
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D); glBindTexture(GL_TEXTURE_2D, mTexture2D);
GLubyte texDataRed[4u * 4u * 4u];
FillWithRGBA<GLubyte>(4u * 4u, 255u, 0u, 0u, 255u, texDataRed); std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
GLubyte texDataGreen[2u * 2u * 4u]; std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
FillWithRGBA<GLubyte>(2u * 2u, 0u, 255u, 0u, 255u, texDataGreen); glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen); texDataGreen.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen); glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 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);
EXPECT_GL_NO_ERROR();
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 do not
// have images defined.
TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined)
{
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, 1);
EXPECT_GL_NO_ERROR();
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
TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
{
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> texDataRed(8u * 8u, GLColor::red);
std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
std::vector<GLColor> texDataCyan(2u * 2u, GLColor::cyan);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Two levels that are initially unused.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataCyan.data());
// One level that is used - only this level should affect completeness.
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
// level was changed.
std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
return;
}
// Switch the level that is being used to the cyan level 2.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
// have images defined.
TEST_P(Texture3DTestES3, DrawWithLevelsOutsideRangeUndefined)
{
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
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
TEST_P(Texture3DTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
{
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
std::vector<GLColor> texDataRed(8u * 8u * 8u, GLColor::red);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
std::vector<GLColor> texDataCyan(2u * 2u * 2u, GLColor::cyan);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Two levels that are initially unused.
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataCyan.data());
// One level that is used - only this level should affect completeness.
glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
// level was changed.
std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
return;
}
// Switch the level that is being used to the cyan level 2.
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 2);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
// have images defined.
TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeUndefined)
{
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
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
TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
{
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, m2DArrayTexture);
std::vector<GLColor> texDataRed(8u * 8u * 8u, GLColor::red);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
std::vector<GLColor> texDataCyan(2u * 2u * 2u, GLColor::cyan);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Two levels that are initially unused.
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glTexImage3D(GL_TEXTURE_2D_ARRAY, 2, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataCyan.data());
// One level that is used - only this level should affect completeness.
glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
// level was changed.
std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
return;
}
if (IsNVIDIA() && (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE ||
getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE))
{
// NVIDIA was observed drawing color 0,0,0,0 instead of the texture color after the base
// level was changed.
std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
return;
}
// Switch the level that is being used to the cyan level 2.
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 2);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
// Test that texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
{
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed having wrong behavior after the texture is made incomplete by changing
// the base level.
std::cout << "Test skipped on Intel 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(8u * 8u, GLColor::green);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// A level that is initially unused.
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
// One level that is initially used - only this level should affect completeness.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Switch the max level to level 1. The levels within the used range now have inconsistent
// dimensions and the texture should be incomplete.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// Test that 3D texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel)
{
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed having wrong behavior after the texture is made incomplete by changing
// the base level.
std::cout << "Test skipped on Intel 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_3D, mTexture3D);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// A level that is initially unused.
glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
// One level that is initially used - only this level should affect completeness.
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Switch the max level to level 1. The levels within the used range now have inconsistent
// dimensions and the texture should be incomplete.
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// Test that texture completeness is updated if texture base level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture2DTestES3, TextureCompletenessChangesWithBaseLevel)
{
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel was observed having wrong behavior after the texture is made incomplete by changing
// the base level.
std::cout << "Test skipped on Intel OpenGL." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
std::vector<GLColor> texDataGreen(8u * 8u, GLColor::green);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Two levels that are initially unused.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
// One level that is initially used - only this level should affect completeness.
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Switch the base level to level 1. The levels within the used range now have inconsistent
// dimensions and the texture should be incomplete.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// Test that texture is not complete if base level is greater than max level.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture2DTestES3, TextureBaseLevelGreaterThanMaxLevel)
{
if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Intel Windows OpenGL driver crashes if the base level of a non-immutable texture is out
// of range.
std::cout << "Test skipped on Intel OpenGL." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
// Texture should be incomplete.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// Test that immutable texture base level and max level are clamped.
// GLES 3.0.4 section 3.8.10 subsection Mipmapping
TEST_P(Texture2DTestES3, ImmutableTextureBaseLevelOutOfRange)
{
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Observed incorrect rendering on AMD OpenGL.
std::cout << "Test skipped on AMD OpenGL." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
// For immutable-format textures, base level should be clamped to [0, levels - 1], and max level
// should be clamped to [base_level, levels - 1].
// GLES 3.0.4 section 3.8.10 subsection Mipmapping
// In the case of this test, those rules make the effective base level and max level 0.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10000);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
// Texture should be complete.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that setting a texture image works when base level is out of range.
TEST_P(Texture2DTestES3, SetImageWhenBaseLevelOutOfRange)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10000);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
EXPECT_GL_NO_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
drawQuad(mProgram, "position", 0.5f);
// Texture should be complete.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// In the D3D11 renderer, we need to initialize some texture formats, to fill empty channels. EG RBA->RGBA8, with 1.0 // In the D3D11 renderer, we need to initialize some texture formats, to fill empty channels. EG RBA->RGBA8, with 1.0
...@@ -1641,12 +2213,12 @@ TEST_P(Texture2DArrayTestES3, RedefineInittableArray) ...@@ -1641,12 +2213,12 @@ TEST_P(Texture2DArrayTestES3, RedefineInittableArray)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
drawQuad(mProgram, "position", 1.0f); drawQuad(mProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// The dimension of the respecification must match the original exactly to trigger the bug. // The dimension of the respecification must match the original exactly to trigger the bug.
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]); glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
drawQuad(mProgram, "position", 1.0f); drawQuad(mProgram, "position", 1.0f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -2538,6 +3110,7 @@ ANGLE_INSTANTIATE_TEST(SamplerArrayAsFunctionParameterTest, ...@@ -2538,6 +3110,7 @@ ANGLE_INSTANTIATE_TEST(SamplerArrayAsFunctionParameterTest,
ES2_OPENGL(), ES2_OPENGL(),
ES2_OPENGLES()); ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(Texture2DTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture3DTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DIntegerAlpha1TestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(Texture2DIntegerAlpha1TestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DUnsignedIntegerAlpha1TestES3, ANGLE_INSTANTIATE_TEST(Texture2DUnsignedIntegerAlpha1TestES3,
ES3_D3D11(), ES3_D3D11(),
......
...@@ -15,6 +15,12 @@ ...@@ -15,6 +15,12 @@
namespace angle namespace angle
{ {
const GLColor GLColor::red = GLColor(255u, 0u, 0u, 255u);
const GLColor GLColor::green = GLColor(0u, 255u, 0u, 255u);
const GLColor GLColor::blue = GLColor(0u, 0u, 255u, 255u);
const GLColor GLColor::cyan = GLColor(0u, 255u, 255u, 255u);
const GLColor GLColor::black = GLColor(0u, 0u, 0u, 255u);
namespace namespace
{ {
float ColorNorm(GLubyte channelValue) float ColorNorm(GLubyte channelValue)
......
...@@ -52,6 +52,12 @@ struct GLColor ...@@ -52,6 +52,12 @@ struct GLColor
Vector4 toNormalizedVector() const; Vector4 toNormalizedVector() const;
GLubyte R, G, B, A; GLubyte R, G, B, A;
static const GLColor red;
static const GLColor green;
static const GLColor blue;
static const GLColor cyan;
static const GLColor black;
}; };
// Useful to cast any type to GLubyte. // Useful to cast any type to GLubyte.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment