зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
369d03c191
Коммит
a314b61c16
|
@ -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 ®ion);
|
||||
|
||||
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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче