Commit e8528d89 by Olli Etuaho Committed by Commit Bot

Fix determining texture mipmap completeness

The code didn't previously take base level properly into account when determining how many levels to check when checking for texture completeness. The code is refactored so that the "q" value in spec, that is the maximum mipmap level for determining completeness, can be queried from TextureState. This value is used now for checking completeness. This requires moving ImageDescs under TextureState. Functions that operate on the ImageDesc array are also moved from Texture to TextureState. TextureState members are also renamed to start with the "m" prefix and made private. Also handle levels outside the base/max level range consistently in eglCreateImageKHR validation. We interpret the spec so that if the level used for the EGL image is not a part of the texture levels that affect texture completeness, an error is generated. BUG=angleproject:596 TEST=angle_end2end_tests Change-Id: I038ef24aa83e0a6905ca3c0bbada5989eecb00d9 Reviewed-on: https://chromium-review.googlesource.com/344880Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent b66a9097
...@@ -437,7 +437,8 @@ GLenum Framebuffer::checkStatus(const ContextState &data) const ...@@ -437,7 +437,8 @@ GLenum Framebuffer::checkStatus(const ContextState &data) const
// TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness. // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
const Texture *texture = colorAttachment.getTexture(); const Texture *texture = colorAttachment.getTexture();
ASSERT(texture); ASSERT(texture);
if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete()) if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
!texture->getTextureState().isCubeComplete())
{ {
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
} }
......
...@@ -33,15 +33,48 @@ namespace rx ...@@ -33,15 +33,48 @@ namespace rx
{ {
class GLImplFactory; class GLImplFactory;
class TextureImpl; class TextureImpl;
class TextureGL;
class Renderer11;
} }
namespace gl namespace gl
{ {
struct ContextState; struct ContextState;
class Framebuffer; class Framebuffer;
class Texture;
bool IsMipmapFiltered(const SamplerState &samplerState); bool IsMipmapFiltered(const SamplerState &samplerState);
struct ImageDesc final
{
ImageDesc();
ImageDesc(const Extents &size, GLenum internalFormat);
ImageDesc(const ImageDesc &other) = default;
ImageDesc &operator=(const ImageDesc &other) = default;
Extents size;
GLenum internalFormat;
};
struct SwizzleState final
{
SwizzleState();
SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha);
SwizzleState(const SwizzleState &other) = default;
SwizzleState &operator=(const SwizzleState &other) = default;
bool swizzleRequired() const;
bool operator==(const SwizzleState &other) const;
bool operator!=(const SwizzleState &other) const;
GLenum swizzleRed;
GLenum swizzleGreen;
GLenum swizzleBlue;
GLenum swizzleAlpha;
};
// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec. // State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec.
struct TextureState final : public angle::NonCopyable struct TextureState final : public angle::NonCopyable
{ {
...@@ -51,25 +84,79 @@ struct TextureState final : public angle::NonCopyable ...@@ -51,25 +84,79 @@ struct TextureState final : public angle::NonCopyable
GLuint getEffectiveBaseLevel() const; GLuint getEffectiveBaseLevel() const;
GLuint getEffectiveMaxLevel() const; GLuint getEffectiveMaxLevel() const;
// TODO(jmadill): Make the data members here private. // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10.
size_t getMipmapMaxLevel() const;
const GLenum target; // Returns true if base level changed.
bool setBaseLevel(GLuint baseLevel);
void setMaxLevel(GLuint maxLevel);
GLenum swizzleRed; bool isCubeComplete() const;
GLenum swizzleGreen; bool isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const;
GLenum swizzleBlue;
GLenum swizzleAlpha;
SamplerState samplerState; const ImageDesc &getImageDesc(GLenum target, size_t level) const;
GLenum getTarget() const { return mTarget; }
const SwizzleState &getSwizzleState() const { return mSwizzleState; }
const SamplerState &getSamplerState() const { return mSamplerState; }
GLenum getUsage() const { return mUsage; }
GLuint baseLevel; private:
GLuint maxLevel; // Texture needs access to the ImageDesc functions.
friend class Texture;
// TODO(jmadill): Remove TextureGL from friends.
friend class rx::TextureGL;
friend bool operator==(const TextureState &a, const TextureState &b);
bool immutableFormat; // TODO(oetuaho): Remove Renderer11 from friends when GenerateMipmap is fixed.
GLuint immutableLevels; friend class rx::Renderer11;
bool computeSamplerCompleteness(const SamplerState &samplerState,
const ContextState &data) const;
bool computeMipmapCompleteness() const;
bool computeLevelCompleteness(GLenum target, size_t level) const;
GLenum getBaseImageTarget() const;
void setImageDesc(GLenum target, size_t level, const ImageDesc &desc);
void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
void clearImageDesc(GLenum target, size_t level);
void clearImageDescs();
const GLenum mTarget;
SwizzleState mSwizzleState;
SamplerState mSamplerState;
GLuint mBaseLevel;
GLuint mMaxLevel;
bool mImmutableFormat;
GLuint mImmutableLevels;
// From GL_ANGLE_texture_usage // From GL_ANGLE_texture_usage
GLenum usage; GLenum mUsage;
std::vector<ImageDesc> mImageDescs;
struct SamplerCompletenessCache
{
SamplerCompletenessCache();
bool cacheValid;
// All values that affect sampler completeness that are not stored within
// the texture itself
SamplerState samplerState;
bool filterable;
GLint clientVersion;
bool supportsNPOT;
// Result of the sampler completeness with the above parameters
bool samplerComplete;
};
mutable SamplerCompletenessCache mCompletenessCache;
}; };
bool operator==(const TextureState &a, const TextureState &b); bool operator==(const TextureState &a, const TextureState &b);
...@@ -152,10 +239,7 @@ class Texture final : public egl::ImageSibling, ...@@ -152,10 +239,7 @@ class Texture final : public egl::ImageSibling,
size_t getDepth(GLenum target, size_t level) const; size_t getDepth(GLenum target, size_t level) const;
GLenum getInternalFormat(GLenum target, size_t level) const; GLenum getInternalFormat(GLenum target, size_t level) const;
bool isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const;
bool isMipmapComplete() const; bool isMipmapComplete() const;
bool isCubeComplete() const;
size_t getMipCompleteLevels() const;
Error setImage(const PixelUnpackState &unpackState, Error setImage(const PixelUnpackState &unpackState,
GLenum target, GLenum target,
...@@ -240,60 +324,18 @@ class Texture final : public egl::ImageSibling, ...@@ -240,60 +324,18 @@ class Texture final : public egl::ImageSibling,
std::string mLabel; std::string mLabel;
struct ImageDesc
{
Extents size;
GLenum internalFormat;
ImageDesc();
ImageDesc(const Extents &size, GLenum internalFormat);
};
GLenum getBaseImageTarget() const;
bool computeSamplerCompleteness(const SamplerState &samplerState,
const ContextState &data) const;
bool computeMipmapCompleteness() const;
bool computeLevelCompleteness(GLenum target, size_t level) const;
const ImageDesc &getImageDesc(GLenum target, size_t level) const;
void setImageDesc(GLenum target, size_t level, const ImageDesc &desc);
void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
void clearImageDesc(GLenum target, size_t level);
void clearImageDescs();
void releaseTexImageInternal(); void releaseTexImageInternal();
std::vector<ImageDesc> mImageDescs;
struct SamplerCompletenessCache
{
SamplerCompletenessCache();
bool cacheValid;
// All values that affect sampler completeness that are not stored within
// the texture itself
SamplerState samplerState;
bool filterable;
GLint clientVersion;
bool supportsNPOT;
// Result of the sampler completeness with the above parameters
bool samplerComplete;
};
mutable SamplerCompletenessCache mCompletenessCache;
egl::Surface *mBoundSurface; egl::Surface *mBoundSurface;
egl::Stream *mBoundStream; egl::Stream *mBoundStream;
}; };
inline bool operator==(const TextureState &a, const TextureState &b) inline bool operator==(const TextureState &a, const TextureState &b)
{ {
return a.swizzleRed == b.swizzleRed && a.swizzleGreen == b.swizzleGreen && return a.mSwizzleState == b.mSwizzleState && a.mSamplerState == b.mSamplerState &&
a.swizzleBlue == b.swizzleBlue && a.swizzleAlpha == b.swizzleAlpha && a.mBaseLevel == b.mBaseLevel && a.mMaxLevel == b.mMaxLevel &&
a.samplerState == b.samplerState && a.baseLevel == b.baseLevel && a.mImmutableFormat == b.mImmutableFormat && a.mImmutableLevels == b.mImmutableLevels &&
a.maxLevel == b.maxLevel && a.immutableFormat == b.immutableFormat && a.mUsage == b.mUsage;
a.immutableLevels == b.immutableLevels && a.usage == b.usage;
} }
inline bool operator!=(const TextureState &a, const TextureState &b) inline bool operator!=(const TextureState &a, const TextureState &b)
......
...@@ -110,6 +110,9 @@ struct Extents ...@@ -110,6 +110,9 @@ struct Extents
Extents() : width(0), height(0), depth(0) { } Extents() : width(0), height(0), depth(0) { }
Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { }
Extents(const Extents &other) = default;
Extents &operator=(const Extents &other) = default;
bool empty() const { return (width * height * depth) == 0; } bool empty() const { return (width * height * depth) == 0; }
}; };
......
...@@ -44,8 +44,6 @@ class TextureImpl : public FramebufferAttachmentObjectImpl ...@@ -44,8 +44,6 @@ class TextureImpl : public FramebufferAttachmentObjectImpl
TextureImpl(const gl::TextureState &state) : mState(state) {} TextureImpl(const gl::TextureState &state) : mState(state) {}
virtual ~TextureImpl() {} virtual ~TextureImpl() {}
virtual void setUsage(GLenum usage) = 0;
virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0;
virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
......
...@@ -21,7 +21,6 @@ class MockTextureImpl : public TextureImpl ...@@ -21,7 +21,6 @@ class MockTextureImpl : public TextureImpl
public: public:
MockTextureImpl() : TextureImpl(gl::TextureState(GL_TEXTURE_2D)) {} MockTextureImpl() : TextureImpl(gl::TextureState(GL_TEXTURE_2D)) {}
virtual ~MockTextureImpl() { destructor(); } virtual ~MockTextureImpl() { destructor(); }
MOCK_METHOD1(setUsage, void(GLenum));
MOCK_METHOD8(setImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *)); MOCK_METHOD8(setImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
MOCK_METHOD7(setSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *)); MOCK_METHOD7(setSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
MOCK_METHOD7(setCompressedImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, const gl::PixelUnpackState &, size_t, const uint8_t *)); MOCK_METHOD7(setCompressedImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, const gl::PixelUnpackState &, size_t, const uint8_t *));
......
...@@ -180,7 +180,7 @@ gl::Error RendererD3D::applyTextures(GLImplFactory *implFactory, ...@@ -180,7 +180,7 @@ gl::Error RendererD3D::applyTextures(GLImplFactory *implFactory,
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
// TODO: std::binary_search may become unavailable using older versions of GCC // TODO: std::binary_search may become unavailable using older versions of GCC
if (texture->isSamplerComplete(samplerState, data) && if (texture->getTextureState().isSamplerComplete(samplerState, data) &&
!std::binary_search(framebufferTextures.begin(), !std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture)) framebufferTextures.begin() + framebufferTextureCount, texture))
{ {
......
...@@ -78,7 +78,6 @@ bool IsRenderTargetUsage(GLenum usage) ...@@ -78,7 +78,6 @@ bool IsRenderTargetUsage(GLenum usage)
TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer) TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer)
: TextureImpl(state), : TextureImpl(state),
mRenderer(renderer), mRenderer(renderer),
mUsage(GL_NONE),
mDirtyImages(true), mDirtyImages(true),
mImmutable(false), mImmutable(false),
mTexStorage(nullptr), mTexStorage(nullptr),
...@@ -985,7 +984,7 @@ gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum interna ...@@ -985,7 +984,7 @@ gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum interna
} }
// TODO(geofflang): Verify storage creation had no errors // TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage); bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = mRenderer->createTextureStorage2D( TextureStorage *storage = mRenderer->createTextureStorage2D(
internalFormat, renderTarget, size.width, size.height, static_cast<int>(levels), false); internalFormat, renderTarget, size.width, size.height, static_cast<int>(levels), false);
...@@ -1166,7 +1165,7 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) ...@@ -1166,7 +1165,7 @@ gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL; TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage); gl::Error error = createCompleteStorage(createRenderTarget, &storage);
...@@ -1598,7 +1597,7 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter ...@@ -1598,7 +1597,7 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter
} }
// TODO(geofflang): Verify storage creation had no errors // TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage); bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = mRenderer->createTextureStorageCube( TextureStorage *storage = mRenderer->createTextureStorageCube(
internalFormat, renderTarget, size.width, static_cast<int>(levels), false); internalFormat, renderTarget, size.width, static_cast<int>(levels), false);
...@@ -1709,7 +1708,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) ...@@ -1709,7 +1708,7 @@ gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL; TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage); gl::Error error = createCompleteStorage(createRenderTarget, &storage);
...@@ -2224,7 +2223,7 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna ...@@ -2224,7 +2223,7 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna
} }
// TODO(geofflang): Verify storage creation had no errors // TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage); bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = TextureStorage *storage =
mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height,
size.depth, static_cast<int>(levels)); size.depth, static_cast<int>(levels));
...@@ -2315,7 +2314,7 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) ...@@ -2315,7 +2314,7 @@ gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL; TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage); gl::Error error = createCompleteStorage(createRenderTarget, &storage);
...@@ -2814,7 +2813,7 @@ gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum in ...@@ -2814,7 +2813,7 @@ gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum in
} }
// TODO(geofflang): Verify storage creation had no errors // TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage); bool renderTarget = IsRenderTargetUsage(mState.getUsage());
TextureStorage *storage = TextureStorage *storage =
mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width,
size.height, size.depth, static_cast<int>(levels)); size.height, size.depth, static_cast<int>(levels));
...@@ -2899,7 +2898,7 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) ...@@ -2899,7 +2898,7 @@ gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
TextureStorage *storage = NULL; TextureStorage *storage = NULL;
gl::Error error = createCompleteStorage(createRenderTarget, &storage); gl::Error error = createCompleteStorage(createRenderTarget, &storage);
......
...@@ -35,7 +35,6 @@ class TextureD3D : public TextureImpl ...@@ -35,7 +35,6 @@ class TextureD3D : public TextureImpl
gl::Error getNativeTexture(TextureStorage **outStorage); gl::Error getNativeTexture(TextureStorage **outStorage);
virtual void setUsage(GLenum usage) { mUsage = usage; }
bool hasDirtyImages() const { return mDirtyImages; } bool hasDirtyImages() const { return mDirtyImages; }
void resetDirty() { mDirtyImages = false; } void resetDirty() { mDirtyImages = false; }
...@@ -113,8 +112,6 @@ class TextureD3D : public TextureImpl ...@@ -113,8 +112,6 @@ class TextureD3D : public TextureImpl
RendererD3D *mRenderer; RendererD3D *mRenderer;
GLenum mUsage;
bool mDirtyImages; bool mDirtyImages;
bool mImmutable; bool mImmutable;
...@@ -213,7 +210,6 @@ class TextureD3D_Cube : public TextureD3D ...@@ -213,7 +210,6 @@ class TextureD3D_Cube : public TextureD3D
virtual bool hasDirtyImages() const { return mDirtyImages; } virtual bool hasDirtyImages() const { return mDirtyImages; }
virtual void resetDirty() { mDirtyImages = false; } virtual void resetDirty() { mDirtyImages = false; }
virtual void setUsage(GLenum usage) { mUsage = usage; }
GLenum getInternalFormat(GLint level, GLint layer) const; GLenum getInternalFormat(GLint level, GLint layer) const;
bool isDepth(GLint level, GLint layer) const; bool isDepth(GLint level, GLint layer) const;
......
...@@ -608,10 +608,7 @@ Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader) ...@@ -608,10 +608,7 @@ Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader)
gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source,
ID3D11RenderTargetView *dest, ID3D11RenderTargetView *dest,
const gl::Extents &size, const gl::Extents &size,
GLenum swizzleRed, const gl::SwizzleState &swizzleTarget)
GLenum swizzleGreen,
GLenum swizzleBlue,
GLenum swizzleAlpha)
{ {
gl::Error error = initResources(); gl::Error error = initResources();
if (error.isError()) if (error.isError())
...@@ -698,10 +695,10 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ...@@ -698,10 +695,10 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source,
} }
unsigned int *swizzleIndices = reinterpret_cast<unsigned int*>(mappedResource.pData); unsigned int *swizzleIndices = reinterpret_cast<unsigned int*>(mappedResource.pData);
swizzleIndices[0] = GetSwizzleIndex(swizzleRed); swizzleIndices[0] = GetSwizzleIndex(swizzleTarget.swizzleRed);
swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); swizzleIndices[1] = GetSwizzleIndex(swizzleTarget.swizzleGreen);
swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); swizzleIndices[2] = GetSwizzleIndex(swizzleTarget.swizzleBlue);
swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); swizzleIndices[3] = GetSwizzleIndex(swizzleTarget.swizzleAlpha);
deviceContext->Unmap(mSwizzleCB, 0); deviceContext->Unmap(mSwizzleCB, 0);
......
...@@ -26,8 +26,10 @@ class Blit11 : angle::NonCopyable ...@@ -26,8 +26,10 @@ class Blit11 : angle::NonCopyable
explicit Blit11(Renderer11 *renderer); explicit Blit11(Renderer11 *renderer);
~Blit11(); ~Blit11();
gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, gl::Error swizzleTexture(ID3D11ShaderResourceView *source,
GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); ID3D11RenderTargetView *dest,
const gl::Extents &size,
const gl::SwizzleState &swizzleTarget);
gl::Error copyTexture(ID3D11ShaderResourceView *source, gl::Error copyTexture(ID3D11ShaderResourceView *source,
const gl::Box &sourceArea, const gl::Box &sourceArea,
......
...@@ -69,7 +69,7 @@ FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data) ...@@ -69,7 +69,7 @@ FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data)
TextureImpl *Context11::createTexture(const gl::TextureState &state) TextureImpl *Context11::createTexture(const gl::TextureState &state)
{ {
switch (state.target) switch (state.getTarget())
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
return new TextureD3D_2D(state, mRenderer); return new TextureD3D_2D(state, mRenderer);
......
...@@ -1167,9 +1167,7 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture) ...@@ -1167,9 +1167,7 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture)
{ {
TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage); TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage);
const gl::TextureState &textureState = texture->getTextureState(); const gl::TextureState &textureState = texture->getTextureState();
error = error = storage11->generateSwizzles(textureState.getSwizzleState());
storage11->generateSwizzles(textureState.swizzleRed, textureState.swizzleGreen,
textureState.swizzleBlue, textureState.swizzleAlpha);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -3609,7 +3607,8 @@ gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage, ...@@ -3609,7 +3607,8 @@ gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage,
ASSERT(storage11->supportsNativeMipmapFunction()); ASSERT(storage11->supportsNativeMipmapFunction());
ID3D11ShaderResourceView *srv; ID3D11ShaderResourceView *srv;
gl::Error error = storage11->getSRVLevels(textureState.baseLevel, textureState.maxLevel, &srv); gl::Error error =
storage11->getSRVLevels(textureState.mBaseLevel, textureState.mMaxLevel, &srv);
if (error.isError()) if (error.isError())
{ {
return error; return error;
......
...@@ -31,33 +31,6 @@ ...@@ -31,33 +31,6 @@
namespace rx namespace rx
{ {
TextureStorage11::SwizzleCacheValue::SwizzleCacheValue()
: swizzleRed(GL_INVALID_INDEX),
swizzleGreen(GL_INVALID_INDEX),
swizzleBlue(GL_INVALID_INDEX),
swizzleAlpha(GL_INVALID_INDEX)
{
}
TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red,
GLenum green,
GLenum blue,
GLenum alpha)
: swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
{
}
bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const
{
return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
}
bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const
{
return !(*this == other);
}
TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle)
: baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle)
{ {
...@@ -215,8 +188,9 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState, ...@@ -215,8 +188,9 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState,
// Make sure to add the level offset for our tiny compressed texture workaround // Make sure to add the level offset for our tiny compressed texture workaround
const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel(); const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel();
bool swizzleRequired = textureState.swizzleRequired(); bool swizzleRequired = textureState.swizzleRequired();
bool mipmapping = gl::IsMipmapFiltered(textureState.samplerState); bool mipmapping = gl::IsMipmapFiltered(textureState.getSamplerState());
unsigned int mipLevels = mipmapping ? (textureState.maxLevel - effectiveBaseLevel + 1) : 1; unsigned int mipLevels =
mipmapping ? (textureState.getEffectiveMaxLevel() - effectiveBaseLevel + 1) : 1;
// Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level,
// which corresponds to GL level 0) // which corresponds to GL level 0)
...@@ -240,8 +214,7 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState, ...@@ -240,8 +214,7 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState,
if (swizzleRequired) if (swizzleRequired)
{ {
verifySwizzleExists(textureState.swizzleRed, textureState.swizzleGreen, verifySwizzleExists(textureState.getSwizzleState());
textureState.swizzleBlue, textureState.swizzleAlpha);
} }
SRVKey key(effectiveBaseLevel, mipLevels, swizzleRequired); SRVKey key(effectiveBaseLevel, mipLevels, swizzleRequired);
...@@ -359,12 +332,8 @@ d3d11::ANGLEFormat TextureStorage11::getANGLEFormat() const ...@@ -359,12 +332,8 @@ d3d11::ANGLEFormat TextureStorage11::getANGLEFormat() const
return mTextureFormatSet->format; return mTextureFormatSet->format;
} }
gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, gl::Error TextureStorage11::generateSwizzles(const gl::SwizzleState &swizzleTarget)
GLenum swizzleGreen,
GLenum swizzleBlue,
GLenum swizzleAlpha)
{ {
SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha);
for (int level = 0; level < getLevelCount(); level++) for (int level = 0; level < getLevelCount(); level++)
{ {
// Check if the swizzle for this level is out of date // Check if the swizzle for this level is out of date
...@@ -390,8 +359,7 @@ gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, ...@@ -390,8 +359,7 @@ gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed,
Blit11 *blitter = mRenderer->getBlitter(); Blit11 *blitter = mRenderer->getBlitter();
error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleTarget);
swizzleBlue, swizzleAlpha);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -408,9 +376,9 @@ void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) ...@@ -408,9 +376,9 @@ void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel)
{ {
if (mipLevel >= 0 && static_cast<unsigned int>(mipLevel) < ArraySize(mSwizzleCache)) if (mipLevel >= 0 && static_cast<unsigned int>(mipLevel) < ArraySize(mSwizzleCache))
{ {
// The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a // The default constructor of SwizzleState has GL_INVALID_INDEX for all channels which is
// valid swizzle combination // not a valid swizzle combination
mSwizzleCache[mipLevel] = SwizzleCacheValue(); mSwizzleCache[mipLevel] = gl::SwizzleState();
} }
} }
...@@ -587,15 +555,11 @@ gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, ...@@ -587,15 +555,11 @@ gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex,
gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR, false); gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR, false);
} }
void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, void TextureStorage11::verifySwizzleExists(const gl::SwizzleState &swizzleState)
GLenum swizzleGreen,
GLenum swizzleBlue,
GLenum swizzleAlpha)
{ {
SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha);
for (unsigned int level = 0; level < mMipLevels; level++) for (unsigned int level = 0; level < mMipLevels; level++)
{ {
ASSERT(mSwizzleCache[level] == swizzleTarget); ASSERT(mSwizzleCache[level] == swizzleState);
} }
} }
......
...@@ -58,7 +58,7 @@ class TextureStorage11 : public TextureStorage ...@@ -58,7 +58,7 @@ class TextureStorage11 : public TextureStorage
virtual int getLevelCount() const; virtual int getLevelCount() const;
virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); gl::Error generateSwizzles(const gl::SwizzleState &swizzleTarget);
void invalidateSwizzleCacheLevel(int mipLevel); void invalidateSwizzleCacheLevel(int mipLevel);
void invalidateSwizzleCache(); void invalidateSwizzleCache();
...@@ -98,7 +98,7 @@ class TextureStorage11 : public TextureStorage ...@@ -98,7 +98,7 @@ class TextureStorage11 : public TextureStorage
virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture,
ID3D11ShaderResourceView **outSRV) const = 0; ID3D11ShaderResourceView **outSRV) const = 0;
void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); void verifySwizzleExists(const gl::SwizzleState &swizzleState);
// Clear all cached non-swizzle SRVs and invalidate the swizzle cache. // Clear all cached non-swizzle SRVs and invalidate the swizzle cache.
void clearSRVCache(); void clearSRVCache();
...@@ -114,20 +114,7 @@ class TextureStorage11 : public TextureStorage ...@@ -114,20 +114,7 @@ class TextureStorage11 : public TextureStorage
unsigned int mTextureHeight; unsigned int mTextureHeight;
unsigned int mTextureDepth; unsigned int mTextureDepth;
struct SwizzleCacheValue gl::SwizzleState mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
{
GLenum swizzleRed;
GLenum swizzleGreen;
GLenum swizzleBlue;
GLenum swizzleAlpha;
SwizzleCacheValue();
SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha);
bool operator ==(const SwizzleCacheValue &other) const;
bool operator !=(const SwizzleCacheValue &other) const;
};
SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
private: private:
const UINT mBindFlags; const UINT mBindFlags;
......
...@@ -63,7 +63,7 @@ FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data) ...@@ -63,7 +63,7 @@ FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data)
TextureImpl *Context9::createTexture(const gl::TextureState &state) TextureImpl *Context9::createTexture(const gl::TextureState &state)
{ {
switch (state.target) switch (state.getTarget())
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
return new TextureD3D_2D(state, mRenderer); return new TextureD3D_2D(state, mRenderer);
......
...@@ -59,8 +59,6 @@ class TextureGL : public TextureImpl ...@@ -59,8 +59,6 @@ class TextureGL : public TextureImpl
BlitGL *blitter); BlitGL *blitter);
~TextureGL() override; ~TextureGL() override;
void setUsage(GLenum usage) override;
gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
......
...@@ -123,6 +123,34 @@ egl::Error ValidateStreamAttribute(const EGLAttrib attribute, ...@@ -123,6 +123,34 @@ egl::Error ValidateStreamAttribute(const EGLAttrib attribute,
} }
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context,
const gl::Texture *texture,
EGLAttrib level)
{
// Note that the spec EGL_KHR_create_image spec does not explicitly specify an error
// when the level is outside the base/max level range, but it does mention that the
// level "must be a part of the complete texture object <buffer>". It can be argued
// that out-of-range levels are not a part of the complete texture.
const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
if (level > 0 &&
(!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel ||
static_cast<size_t>(level) > texture->getTextureState().getMipmapMaxLevel()))
{
return egl::Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
}
if (level == 0 && !texture->isMipmapComplete() &&
TextureHasNonZeroMipLevelsSpecified(context, texture))
{
return egl::Error(EGL_BAD_PARAMETER,
"if level is zero and the texture is incomplete, it must have no mip "
"levels specified except zero.");
}
return egl::Error(EGL_SUCCESS);
}
} // namespace } // namespace
namespace egl namespace egl
...@@ -862,18 +890,10 @@ Error ValidateCreateImageKHR(const Display *display, ...@@ -862,18 +890,10 @@ Error ValidateCreateImageKHR(const Display *display,
"target 2D texture does not have a valid size at specified level."); "target 2D texture does not have a valid size at specified level.");
} }
if (level > 0 && (!texture->isMipmapComplete() || Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
static_cast<size_t>(level) >= texture->getMipCompleteLevels())) if (error.isError())
{
return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
}
if (level == 0 && !texture->isMipmapComplete() &&
TextureHasNonZeroMipLevelsSpecified(context, texture))
{ {
return Error(EGL_BAD_PARAMETER, return error;
"if level is zero and the texture is incomplete, it must have no mip "
"levels specified except zero.");
} }
} }
break; break;
...@@ -918,18 +938,10 @@ Error ValidateCreateImageKHR(const Display *display, ...@@ -918,18 +938,10 @@ Error ValidateCreateImageKHR(const Display *display,
"and face."); "and face.");
} }
if (level > 0 && (!texture->isMipmapComplete() || Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
static_cast<size_t>(level) >= texture->getMipCompleteLevels())) if (error.isError())
{ {
return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); return error;
}
if (level == 0 && !texture->isMipmapComplete() &&
TextureHasNonZeroMipLevelsSpecified(context, texture))
{
return Error(EGL_BAD_PARAMETER,
"if level is zero and the texture is incomplete, it must have no mip "
"levels specified except zero.");
} }
if (level == 0 && !texture->isMipmapComplete() && if (level == 0 && !texture->isMipmapComplete() &&
...@@ -985,18 +997,10 @@ Error ValidateCreateImageKHR(const Display *display, ...@@ -985,18 +997,10 @@ Error ValidateCreateImageKHR(const Display *display,
"offset at the specified level."); "offset at the specified level.");
} }
if (level > 0 && (!texture->isMipmapComplete() || Error error = ValidateCreateImageKHRMipLevelCommon(context, texture, level);
static_cast<size_t>(level) >= texture->getMipCompleteLevels())) if (error.isError())
{
return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
}
if (level == 0 && !texture->isMipmapComplete() &&
TextureHasNonZeroMipLevelsSpecified(context, texture))
{ {
return Error(EGL_BAD_PARAMETER, return error;
"if level is zero and the texture is incomplete, it must have no mip "
"levels specified except zero.");
} }
} }
break; break;
......
...@@ -1298,7 +1298,7 @@ void GL_APIENTRY GenerateMipmap(GLenum target) ...@@ -1298,7 +1298,7 @@ void GL_APIENTRY GenerateMipmap(GLenum target)
} }
// Cube completeness check // Cube completeness check
if (target == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete()) if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
{ {
context->handleError(Error(GL_INVALID_OPERATION)); context->handleError(Error(GL_INVALID_OPERATION));
return; return;
......
...@@ -1701,6 +1701,45 @@ TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined) ...@@ -1701,6 +1701,45 @@ TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test that drawing works correctly when level 0 is undefined and base level is 1.
TEST_P(Texture2DTestES3, DrawWithLevelZeroUndefined)
{
if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
// Observed crashing on AMD. Oddly the crash only happens with 2D textures, not 3D or array.
std::cout << "Test skipped on AMD OpenGL." << std::endl;
return;
}
if (IsOSX())
{
// Observed incorrect rendering on OSX.
std::cout << "Test skipped on OSX." << std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
EXPECT_GL_NO_ERROR();
// Texture is incomplete.
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
// Texture is now complete.
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range have // 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. // dimensions that don't fit the images inside the range.
// GLES 3.0.4 section 3.8.13 Texture completeness // GLES 3.0.4 section 3.8.13 Texture completeness
......
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