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/333352
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
This commit is contained in:
Olli Etuaho 2016-03-10 16:43:00 +02:00 коммит произвёл Commit Bot
Родитель 369d03c191
Коммит a314b61c16
14 изменённых файлов: 915 добавлений и 151 удалений

Просмотреть файл

@ -54,8 +54,10 @@ Texture::Texture(rx::ImplFactory *factory, GLuint id, GLenum target)
mTexture(factory->createTexture(target)),
mLabel(),
mTextureState(),
mEffectiveBaseLevel(0),
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(),
mBoundSurface(nullptr),
mBoundStream(nullptr)
@ -239,7 +241,30 @@ const SamplerState &Texture::getSamplerState() const
void Texture::setBaseLevel(GLuint baseLevel)
{
mTextureState.baseLevel = baseLevel;
if (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
@ -247,9 +272,18 @@ GLuint Texture::getBaseLevel() const
return mTextureState.baseLevel;
}
GLuint Texture::getEffectiveBaseLevel() const
{
return mEffectiveBaseLevel;
}
void Texture::setMaxLevel(GLuint maxLevel)
{
mTextureState.maxLevel = maxLevel;
if (mTextureState.maxLevel != maxLevel)
{
mTextureState.maxLevel = maxLevel;
mCompletenessCache.cacheValid = false;
}
}
GLuint Texture::getMaxLevel() const
@ -309,7 +343,7 @@ GLenum Texture::getInternalFormat(GLenum target, size_t level) 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);
if (!mCompletenessCache.cacheValid ||
mCompletenessCache.samplerState != samplerState ||
@ -506,6 +540,7 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c
mTextureState.immutableFormat = true;
mTextureState.immutableLevels = static_cast<GLuint>(levels);
updateEffectiveBaseLevel();
clearImageDescs();
setImageDescChain(levels, size, internalFormat);
@ -715,11 +750,19 @@ GLenum Texture::getBaseImageTarget() const
bool Texture::computeSamplerCompleteness(const SamplerState &samplerState,
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)
{
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)
{
@ -792,7 +835,7 @@ bool Texture::computeMipmapCompleteness() const
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)
{
@ -825,7 +868,7 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
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)
{
return false;
@ -843,8 +886,8 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
return false;
}
ASSERT(level >= mTextureState.baseLevel);
const size_t relativeLevel = level - mTextureState.baseLevel;
ASSERT(level >= mEffectiveBaseLevel);
const size_t relativeLevel = level - mEffectiveBaseLevel;
if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
{
return false;

Просмотреть файл

@ -101,6 +101,8 @@ class Texture final : public egl::ImageSibling,
void setBaseLevel(GLuint baseLevel);
GLuint getBaseLevel() const;
// Returns base level after clamping required for immutable textures.
GLuint getEffectiveBaseLevel() const;
void setMaxLevel(GLuint maxLevel);
GLuint getMaxLevel() const;
@ -207,6 +209,7 @@ class Texture final : public egl::ImageSibling,
std::string mLabel;
TextureState mTextureState;
GLuint mEffectiveBaseLevel;
GLenum mTarget;
@ -233,6 +236,8 @@ class Texture final : public egl::ImageSibling,
void clearImageDescs();
void releaseTexImageInternal();
void updateEffectiveBaseLevel();
std::vector<ImageDesc> mImageDescs;
struct SamplerCompletenessCache

Просмотреть файл

@ -71,6 +71,8 @@ class TextureImpl : public FramebufferAttachmentObjectImpl
virtual gl::Error generateMipmaps(const gl::TextureState &textureState) = 0;
virtual void setBaseLevel(GLuint baseLevel) = 0;
virtual void bindTexImage(egl::Surface *surface) = 0;
virtual void releaseTexImage() = 0;
};

Просмотреть файл

@ -37,6 +37,8 @@ class MockTextureImpl : public TextureImpl
MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **));
MOCK_METHOD1(setBaseLevel, void(GLuint));
MOCK_METHOD0(destructor, void());
};

Просмотреть файл

@ -80,7 +80,8 @@ TextureD3D::TextureD3D(RendererD3D *renderer)
mUsage(GL_NONE),
mDirtyImages(true),
mImmutable(false),
mTexStorage(NULL)
mTexStorage(nullptr),
mBaseLevel(0)
{
}
@ -112,6 +113,21 @@ gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage)
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
{
const ImageD3D *baseImage = getBaseLevelImage();
@ -359,7 +375,9 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c
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()
@ -370,7 +388,11 @@ TextureStorage *TextureD3D::getStorage()
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,
@ -444,7 +466,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages()
GLint mipCount = mipLevels();
// 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
// the image data already. For non-render-target storage, we have to pull it out into
@ -540,7 +562,7 @@ bool TextureD3D::isBaseImageZeroSize() const
return true;
}
if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(getBaseLevel()) <= 0)
{
return true;
}
@ -621,6 +643,26 @@ gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment:
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(renderer)
{
@ -1025,9 +1067,8 @@ void TextureD3D_2D::initMipmapsImages()
int levelCount = mipLevels();
for (int level = 1; level < levelCount; level++)
{
gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
std::max(getBaseLevelHeight() >> level, 1),
1);
gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
std::max(getLevelZeroHeight() >> level, 1), 1);
redefineImage(level, getBaseLevelInternalFormat(), levelSize, false);
}
@ -1065,10 +1106,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const
return true;
}
const ImageD3D *baseImage = getBaseLevelImage();
GLsizei width = baseImage->getWidth();
GLsizei height = baseImage->getHeight();
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
if (width <= 0 || height <= 0)
{
@ -1076,15 +1115,15 @@ bool TextureD3D_2D::isLevelComplete(int level) const
}
// The base image level is complete if the width and height are positive
if (level == 0)
if (level == static_cast<int>(getBaseLevel()))
{
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];
if (image->getInternalFormat() != baseImage->getInternalFormat())
if (image->getInternalFormat() != getBaseLevelInternalFormat())
{
return false;
}
@ -1117,7 +1156,7 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
}
// do not attempt to create storage for nonexistant data
if (!isLevelComplete(0))
if (!isLevelComplete(getBaseLevel()))
{
return gl::Error(GL_NO_ERROR);
}
@ -1152,8 +1191,8 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
{
GLsizei width = getBaseLevelWidth();
GLsizei height = getBaseLevelHeight();
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0);
@ -1247,8 +1286,8 @@ void TextureD3D_2D::redefineImage(size_t level,
ASSERT(size.depth == 1);
// If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat();
mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease);
@ -1270,13 +1309,8 @@ void TextureD3D_2D::redefineImage(size_t level,
size.height != storageHeight ||
internalformat != storageFormat) // Discard mismatched storage
{
for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
mImageArray[i]->markDirty();
}
markAllImagesDirty();
SafeDelete(mTexStorage);
mDirtyImages = true;
}
}
@ -1301,6 +1335,15 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
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(renderer)
{
@ -1588,7 +1631,7 @@ bool TextureD3D_Cube::isCubeComplete() const
for (int faceIndex = 1; faceIndex < 6; faceIndex++)
{
const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
if (faceBaseImage.getWidth() != baseWidth ||
faceBaseImage.getHeight() != baseHeight ||
@ -1656,7 +1699,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
}
// do not attempt to create storage for nonexistant data
if (!isFaceLevelComplete(0, 0))
if (!isFaceLevelComplete(0, getBaseLevel()))
{
return gl::Error(GL_NO_ERROR);
}
@ -1691,7 +1734,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
{
GLsizei size = getBaseLevelWidth();
GLsizei size = getLevelZeroWidth();
ASSERT(size > 0);
@ -1772,16 +1815,21 @@ bool TextureD3D_Cube::isValidFaceLevel(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())
{
return true;
}
int baseSize = getBaseLevelWidth();
int levelZeroSize = getLevelZeroWidth();
if (baseSize <= 0)
if (levelZeroSize <= 0)
{
return false;
}
@ -1802,7 +1850,7 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
return false;
}
if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
{
return false;
}
@ -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)
{
// If there currently is a corresponding storage texture image, it has these parameters
const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat();
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
size.height != storageHeight ||
internalformat != storageFormat) // Discard mismatched storage
{
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
{
for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++)
{
mImageArray[dirtyFace][dirtyLevel]->markDirty();
}
}
markAllImagesDirty();
SafeDelete(mTexStorage);
mDirtyImages = true;
}
}
}
@ -1885,6 +1924,18 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
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(renderer)
{
@ -1991,7 +2042,7 @@ gl::Error TextureD3D_3D::setImage(GLenum target,
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
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
RenderTargetD3D *destRenderTarget = NULL;
@ -2041,7 +2092,7 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target,
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
if (isFastUnpackable(unpack, getInternalFormat(level)))
if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
{
RenderTargetD3D *destRenderTarget = NULL;
gl::Error error = getRenderTarget(index, &destRenderTarget);
@ -2209,9 +2260,9 @@ void TextureD3D_3D::initMipmapsImages()
int levelCount = mipLevels();
for (int level = 1; level < levelCount; level++)
{
gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
std::max(getBaseLevelHeight() >> level, 1),
std::max(getBaseLevelDepth() >> level, 1));
gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
std::max(getLevelZeroHeight() >> level, 1),
std::max(getLevelZeroDepth() >> level, 1));
redefineImage(level, getBaseLevelInternalFormat(), levelSize);
}
}
@ -2254,7 +2305,7 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
}
// do not attempt to create storage for nonexistant data
if (!isLevelComplete(0))
if (!isLevelComplete(getBaseLevel()))
{
return gl::Error(GL_NO_ERROR);
}
@ -2289,9 +2340,9 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
{
GLsizei width = getBaseLevelWidth();
GLsizei height = getBaseLevelHeight();
GLsizei depth = getBaseLevelDepth();
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
GLsizei depth = getLevelZeroDepth();
GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0 && depth > 0);
@ -2350,16 +2401,16 @@ bool TextureD3D_3D::isLevelComplete(int level) const
return true;
}
GLsizei width = getBaseLevelWidth();
GLsizei height = getBaseLevelHeight();
GLsizei depth = getBaseLevelDepth();
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
GLsizei depth = getLevelZeroDepth();
if (width <= 0 || height <= 0 || depth <= 0)
{
return false;
}
if (level == 0)
if (level == static_cast<int>(getBaseLevel()))
{
return true;
}
@ -2416,15 +2467,15 @@ gl::Error TextureD3D_3D::updateStorageLevel(int level)
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
const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const int storageDepth = std::max(1, getLevelZeroDepth() >> level);
mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
if (mTexStorage)
{
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageLevels = mTexStorage->getLevelCount();
if ((level >= storageLevels && storageLevels != 0) ||
@ -2433,13 +2484,8 @@ void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::
size.depth != storageDepth ||
internalformat != storageFormat) // Discard mismatched storage
{
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
mImageArray[i]->markDirty();
}
markAllImagesDirty();
SafeDelete(mTexStorage);
mDirtyImages = true;
}
}
}
@ -2462,6 +2508,20 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
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(renderer)
{
@ -2708,8 +2768,10 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target,
return error;
}
error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
destOffset, mTexStorage, level);
error = mRenderer->copyImage2DArray(
source, sourceArea,
gl::GetInternalFormatInfo(getInternalFormat(getBaseLevel())).format, destOffset,
mTexStorage, level);
if (error.isError())
{
return error;
@ -2784,9 +2846,9 @@ void TextureD3D_2DArray::releaseTexImage()
void TextureD3D_2DArray::initMipmapsImages()
{
int baseWidth = getBaseLevelWidth();
int baseHeight = getBaseLevelHeight();
int baseDepth = getLayerCount(0);
int baseWidth = getLevelZeroWidth();
int baseHeight = getLevelZeroHeight();
int baseDepth = getLayerCount(getBaseLevel());
GLenum baseFormat = getBaseLevelInternalFormat();
// 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)
}
// do not attempt to create storage for nonexistant data
if (!isLevelComplete(0))
if (!isLevelComplete(getBaseLevel()))
{
return gl::Error(GL_NO_ERROR);
}
@ -2862,9 +2924,9 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
{
GLsizei width = getBaseLevelWidth();
GLsizei height = getBaseLevelHeight();
GLsizei depth = getLayerCount(0);
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
GLsizei depth = getLayerCount(getBaseLevel());
GLenum internalFormat = getBaseLevelInternalFormat();
ASSERT(width > 0 && height > 0 && depth > 0);
@ -2923,21 +2985,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const
return true;
}
GLsizei width = getBaseLevelWidth();
GLsizei height = getBaseLevelHeight();
GLsizei layers = getLayerCount(0);
GLsizei width = getLevelZeroWidth();
GLsizei height = getLevelZeroHeight();
if (width <= 0 || height <= 0 || layers <= 0)
if (width <= 0 || height <= 0)
{
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;
}
if (getInternalFormat(level) != getInternalFormat(0))
if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
{
return false;
}
@ -3005,10 +3075,14 @@ void TextureD3D_2DArray::deleteImages()
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
const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
const int storageDepth = getLayerCount(0);
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
const GLuint baseLevel = getBaseLevel();
int storageDepth = 0;
if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
storageDepth = getLayerCount(baseLevel);
}
// Only reallocate the layers if the size doesn't match
if (size.depth != mLayerCounts[level])
@ -3041,6 +3115,7 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const
if (mTexStorage)
{
const GLenum storageFormat = getBaseLevelInternalFormat();
const int storageLevels = mTexStorage->getLevelCount();
if ((level >= storageLevels && storageLevels != 0) ||
@ -3049,17 +3124,8 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const
size.depth != storageDepth ||
internalformat != storageFormat) // Discard mismatched storage
{
for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
{
for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
{
mImageArray[dirtyLevel][dirtyLayer]->markDirty();
}
}
delete mTexStorage;
mTexStorage = NULL;
mDirtyImages = true;
markAllImagesDirty();
SafeDelete(mTexStorage);
}
}
}
@ -3092,6 +3158,18 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
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)
{
mImage = renderer->createImage();
@ -3338,4 +3416,9 @@ bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
{
return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0);
}
void TextureD3D_External::markAllImagesDirty()
{
UNREACHABLE();
}
}

Просмотреть файл

@ -44,7 +44,6 @@ class TextureD3D : public TextureImpl
GLint getBaseLevelWidth() const;
GLint getBaseLevelHeight() const;
GLint getBaseLevelDepth() const;
GLenum getBaseLevelInternalFormat() const;
bool isImmutable() const { return mImmutable; }
@ -69,6 +68,8 @@ class TextureD3D : public TextureImpl
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
FramebufferAttachmentRenderTarget **rtOut) override;
void setBaseLevel(GLuint baseLevel) override;
protected:
gl::Error setImageImpl(const gl::ImageIndex &index,
GLenum type,
@ -87,6 +88,10 @@ class TextureD3D : public TextureImpl
gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
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;
int mipLevels() const;
virtual void initMipmapsImages() = 0;
@ -100,6 +105,12 @@ class TextureD3D : public TextureImpl
virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0;
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;
GLenum mUsage;
@ -117,6 +128,8 @@ class TextureD3D : public TextureImpl
bool shouldUseSetData(const ImageD3D *image) const;
gl::Error generateMipmapsUsingImages();
GLuint mBaseLevel;
};
class TextureD3D_2D : public TextureD3D
@ -162,6 +175,9 @@ class TextureD3D_2D : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private:
virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
@ -230,6 +246,9 @@ class TextureD3D_Cube : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private:
virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const;
@ -293,6 +312,10 @@ class TextureD3D_3D : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
GLint getLevelZeroDepth() const override;
private:
virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
@ -354,6 +377,9 @@ class TextureD3D_2DArray : public TextureD3D
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
virtual bool isValidIndex(const gl::ImageIndex &index) const;
protected:
void markAllImagesDirty() override;
private:
virtual gl::Error initializeStorage(bool renderTarget);
virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const;
@ -454,6 +480,9 @@ class TextureD3D_External : public TextureD3D
gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override;
bool isValidIndex(const gl::ImageIndex &index) const override;
protected:
void markAllImagesDirty() override;
private:
gl::Error initializeStorage(bool renderTarget) override;
gl::Error createCompleteStorage(bool renderTarget,

Просмотреть файл

@ -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
gl::TextureState textureState = texture->getTextureState();
textureState.baseLevel += storage11->getTopLevel();
textureState.baseLevel = texture->getEffectiveBaseLevel() + storage11->getTopLevel();
error = storage11->getSRV(textureState, &textureSRV);
if (error.isError())
@ -2413,8 +2413,8 @@ void Renderer11::SamplerMetadataD3D11::initData(unsigned int samplerCount)
void Renderer11::SamplerMetadataD3D11::update(unsigned int samplerIndex, const gl::Texture &texture)
{
unsigned int baseLevel = texture.getBaseLevel();
GLenum internalFormat = texture.getInternalFormat(texture.getTarget(), texture.getBaseLevel());
unsigned int baseLevel = texture.getEffectiveBaseLevel();
GLenum internalFormat = texture.getInternalFormat(texture.getTarget(), baseLevel);
if (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)
bindTexture(textureType, textureGL->getTextureID());
}
textureGL->syncState(textureUnitIndex, texture->getTextureState());
textureGL->syncState(textureUnitIndex, texture->getTextureState(),
texture->getEffectiveBaseLevel());
}
else
{

Просмотреть файл

@ -117,7 +117,7 @@ TextureGL::TextureGL(GLenum type,
mWorkarounds(workarounds),
mStateManager(stateManager),
mBlitter(blitter),
mLevelInfo(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS),
mLevelInfo(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1),
mAppliedTextureState(),
mTextureID(0)
{
@ -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.
bool textureApplied = false;
@ -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_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_G, &gl::TextureState::swizzleGreen);
SyncTextureStateSwizzle(mFunctions, applyTextureFunc, levelInfo, textureState, mAppliedTextureState, mTextureType, GL_TEXTURE_SWIZZLE_B, &gl::TextureState::swizzleBlue);

Просмотреть файл

@ -88,7 +88,9 @@ class TextureGL : public TextureImpl
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;
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
@ -97,6 +99,8 @@ class TextureGL : public TextureImpl
return gl::Error(GL_OUT_OF_MEMORY, "Not supported on OpenGL");
}
void setBaseLevel(GLuint) override {}
private:
GLenum mTextureType;

Просмотреть файл

@ -1008,16 +1008,24 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pnam
case GL_TEXTURE_BASE_LEVEL:
case GL_TEXTURE_MAX_LEVEL:
if (param < 0)
{
context->handleError(Error(GL_INVALID_VALUE));
return false;
}
return true;
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)
{
context->handleError(Error(GL_INVALID_VALUE));
return false;
}
return true;
default:
context->handleError(Error(GL_INVALID_ENUM));
return false;
return false;
}
}

Просмотреть файл

@ -268,7 +268,7 @@ class Texture2DTest : public TexCoordDrawTest
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)
{
EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255);
@ -780,6 +780,60 @@ class TextureSizeTextureArrayTest : public TexCoordDrawTest
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
{
protected:
@ -990,11 +1044,10 @@ class SamplerInStructTest : public Texture2DTest
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
GLubyte texDataGreen[1u * 1u * 4u];
FillWithRGBA<GLubyte>(1u * 1u, 0u, 255u, 0u, 255u, texDataGreen);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&GLColor::green);
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)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
// Fill with red
std::vector<GLubyte> pixels(4 * 16 * 16);
FillWithRGBA<GLubyte>(16u * 16u, 255u, 0u, 0u, 255u, pixels.data());
std::vector<GLColor> pixelsRed(16u * 16u, GLColor::red);
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_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
@ -1246,24 +1297,24 @@ TEST_P(Texture2DTestWithDrawScale, MipmapsTwice)
glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Fill with blue
FillWithRGBA<GLubyte>(16u * 16u, 0u, 0u, 255u, 255u, pixels.data());
std::vector<GLColor> pixelsBlue(16u * 16u, GLColor::blue);
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);
// Fill with green
FillWithRGBA<GLubyte>(16u * 16u, 0u, 255u, 0u, 255u, pixels.data());
std::vector<GLColor> pixelsGreen(16u * 16u, GLColor::green);
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);
drawQuad(mProgram, "position", 0.5f);
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
@ -1598,13 +1649,14 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
GLubyte texDataRed[4u * 4u * 4u];
FillWithRGBA<GLubyte>(4u * 4u, 255u, 0u, 0u, 255u, texDataRed);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed);
GLubyte texDataGreen[2u * 2u * 4u];
FillWithRGBA<GLubyte>(2u * 2u, 0u, 255u, 0u, 255u, texDataGreen);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
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);
@ -1613,7 +1665,527 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1)
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
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_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_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();
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(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
@ -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_T, GL_REPEAT);
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.
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
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();
}
@ -2538,6 +3110,7 @@ ANGLE_INSTANTIATE_TEST(SamplerArrayAsFunctionParameterTest,
ES2_OPENGL(),
ES2_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(Texture2DUnsignedIntegerAlpha1TestES3,
ES3_D3D11(),

Просмотреть файл

@ -15,6 +15,12 @@
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
{
float ColorNorm(GLubyte channelValue)

Просмотреть файл

@ -52,6 +52,12 @@ struct GLColor
Vector4 toNormalizedVector() const;
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.