Commit a314b61c by Olli Etuaho Committed by Commit Bot

Determine D3D texture storage size with correct base level

The size of the texture storage is now determined by extrapolating the level zero texture dimensions from the base level dimensions. This fixes crashing when images for levels below the base level are not defined, and also fixes texture storage dimensions being calculated wrong in case the levels outside the used level range have dimensions that are inconsistent with the dimensions inside the used level range. Checking texture level completeness in TextureD3D is now done based on the dimensions of the base level, and levels that are outside the base level to max level range are not taken into account. Textures are marked incomplete in case their base level is greater than their max level. Changing the base level can also affect the size of the storage required for the texture. Old storage is now discarded when the base level is changed and the new base level calls for different storage dimensions. Code in TextureD3D is refactored so that "base level" actually means the base level of the texture specified through the GLES API, and "level zero" is used where TextureD3D would sometimes previously use "base level". Changing either the base level or max level can also affect texture completeness, so invalidate the cached completeness in Texture if they are changed. Some of the added tests are still failing on Intel and NVIDIA OpenGL drivers because of driver bugs. Tests also fail on OSX. BUG=angleproject:596 TEST=angle_end2end_tests, dEQP-GLES3.functional.texture.* (no regressions), dEQP-GLES3.functional.shaders.texture_functions.* (no regressions), dEQP-GLES3.functional.state_query.texture.* (no regressions) Change-Id: Icd73d6e29f84a341ed5ff36d5ec5cb2f469cb4e8 Reviewed-on: https://chromium-review.googlesource.com/333352Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 369d03c1
......@@ -54,8 +54,10 @@ Texture::Texture(rx::ImplFactory *factory, GLuint id, GLenum target)
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());
};
......
......@@ -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;
}
}
......
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment