Commit 5549ef04 by Mohan Maiya Committed by Commit Bot

Vulkan: Fix content synchronization for textures bound to images

Added state tracking back for images bound with glBindImageTexture This fixes a bug where updating a texture with glTexSubImage2D would not trigger a content update when the same image was re-used in a dispatch Bug: angleproject:3887 Test: SimpleStateChangeTestES31.DispatchWithImageTextureTexSubImageThenDispatchAgain/ES3_1_Vulkan Change-Id: I030ec52f1c470f9e9ff7c14f1c24fe213000a3ad Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1835943 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent f750d86a
...@@ -292,7 +292,9 @@ enum SubjectIndexes : angle::SubjectIndex ...@@ -292,7 +292,9 @@ enum SubjectIndexes : angle::SubjectIndex
{ {
kTexture0SubjectIndex = 0, kTexture0SubjectIndex = 0,
kTextureMaxSubjectIndex = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES, kTextureMaxSubjectIndex = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
kUniformBuffer0SubjectIndex = kTextureMaxSubjectIndex, kImage0SubjectIndex = kTextureMaxSubjectIndex,
kImageMaxSubjectIndex = kImage0SubjectIndex + IMPLEMENTATION_MAX_IMAGE_UNITS,
kUniformBuffer0SubjectIndex = kImageMaxSubjectIndex,
kUniformBufferMaxSubjectIndex = kUniformBufferMaxSubjectIndex =
kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS, kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex, kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex,
...@@ -367,6 +369,12 @@ Context::Context(egl::Display *display, ...@@ -367,6 +369,12 @@ Context::Context(egl::Display *display,
{ {
mSamplerObserverBindings.emplace_back(this, samplerIndex); mSamplerObserverBindings.emplace_back(this, samplerIndex);
} }
for (angle::SubjectIndex imageIndex = kImage0SubjectIndex; imageIndex < kImageMaxSubjectIndex;
++imageIndex)
{
mImageObserverBindings.emplace_back(this, imageIndex);
}
} }
void Context::initialize() void Context::initialize()
...@@ -535,6 +543,7 @@ void Context::initialize() ...@@ -535,6 +543,7 @@ void Context::initialize()
mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING); mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES); mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM); mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_IMAGES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS); mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING); mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
...@@ -1166,6 +1175,7 @@ void Context::bindImageTexture(GLuint unit, ...@@ -1166,6 +1175,7 @@ void Context::bindImageTexture(GLuint unit,
{ {
Texture *tex = mState.mTextureManager->getTexture(texture); Texture *tex = mState.mTextureManager->getTexture(texture);
mState.setImageUnit(this, unit, tex, level, layered, layer, access, format); mState.setImageUnit(this, unit, tex, level, layered, layer, access, format);
mImageObserverBindings[unit].bind(tex);
} }
void Context::useProgram(ShaderProgramID program) void Context::useProgram(ShaderProgramID program)
...@@ -2796,6 +2806,16 @@ bool Context::isTransformFeedbackGenerated(TransformFeedbackID transformFeedback ...@@ -2796,6 +2806,16 @@ bool Context::isTransformFeedbackGenerated(TransformFeedbackID transformFeedback
void Context::detachTexture(TextureID texture) void Context::detachTexture(TextureID texture)
{ {
// The State cannot unbind image observers itself, they are owned by the Context
Texture *tex = mState.mTextureManager->getTexture(texture);
for (auto &imageBinding : mImageObserverBindings)
{
if (imageBinding.getSubject() == tex)
{
imageBinding.reset();
}
}
// Simple pass-through to State's detachTexture method, as textures do not require // Simple pass-through to State's detachTexture method, as textures do not require
// allocation map management either here or in the resource manager at detach time. // allocation map management either here or in the resource manager at detach time.
// Zero textures are held by the Context, and we don't attempt to request them from // Zero textures are held by the Context, and we don't attempt to request them from
...@@ -8839,6 +8859,14 @@ void Context::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess ...@@ -8839,6 +8859,14 @@ void Context::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess
mStateCache.onActiveTextureChange(this); mStateCache.onActiveTextureChange(this);
} }
} }
else if (index < kImageMaxSubjectIndex)
{
mState.onImageStateChange(this, index - kImage0SubjectIndex);
if (message == angle::SubjectMessage::ContentsChanged)
{
mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_IMAGE_BINDINGS);
}
}
else if (index < kUniformBufferMaxSubjectIndex) else if (index < kUniformBufferMaxSubjectIndex)
{ {
mState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex); mState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
......
...@@ -715,6 +715,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl ...@@ -715,6 +715,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::ObserverBinding mReadFramebufferObserverBinding; angle::ObserverBinding mReadFramebufferObserverBinding;
std::vector<angle::ObserverBinding> mUniformBufferObserverBindings; std::vector<angle::ObserverBinding> mUniformBufferObserverBindings;
std::vector<angle::ObserverBinding> mSamplerObserverBindings; std::vector<angle::ObserverBinding> mSamplerObserverBindings;
std::vector<angle::ObserverBinding> mImageObserverBindings;
// Not really a property of context state. The size and contexts change per-api-call. // Not really a property of context state. The size and contexts change per-api-call.
mutable angle::ScratchBuffer mScratchBuffer; mutable angle::ScratchBuffer mScratchBuffer;
......
...@@ -2697,6 +2697,24 @@ angle::Result State::syncTextures(const Context *context) ...@@ -2697,6 +2697,24 @@ angle::Result State::syncTextures(const Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result State::syncImages(const Context *context)
{
if (mDirtyImages.none())
return angle::Result::Continue;
for (size_t imageUnitIndex : mDirtyImages)
{
Texture *texture = mImageUnits[imageUnitIndex].texture.get();
if (texture && texture->hasAnyDirtyBit())
{
ANGLE_TRY(texture->syncState(context));
}
}
mDirtyImages.reset();
return angle::Result::Continue;
}
angle::Result State::syncSamplers(const Context *context) angle::Result State::syncSamplers(const Context *context)
{ {
if (mDirtySamplers.none()) if (mDirtySamplers.none())
...@@ -2900,6 +2918,12 @@ void State::onImageStateChange(const Context *context, size_t unit) ...@@ -2900,6 +2918,12 @@ void State::onImageStateChange(const Context *context, size_t unit)
{ {
const ImageUnit &image = mImageUnits[unit]; const ImageUnit &image = mImageUnits[unit];
ASSERT(image.texture.get()); ASSERT(image.texture.get());
if (image.texture->hasAnyDirtyBit())
{
mDirtyImages.set(unit);
mDirtyObjects.set(DIRTY_OBJECT_IMAGES);
}
if (mRobustResourceInit && image.texture->initState() == InitState::MayNeedInit) if (mRobustResourceInit && image.texture->initState() == InitState::MayNeedInit)
{ {
mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT); mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT);
......
...@@ -586,6 +586,7 @@ class State : angle::NonCopyable ...@@ -586,6 +586,7 @@ class State : angle::NonCopyable
DIRTY_OBJECT_DRAW_FRAMEBUFFER, DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY, DIRTY_OBJECT_VERTEX_ARRAY,
DIRTY_OBJECT_TEXTURES, // Top-level dirty bit. Also see mDirtyTextures. DIRTY_OBJECT_TEXTURES, // Top-level dirty bit. Also see mDirtyTextures.
DIRTY_OBJECT_IMAGES, // Top-level dirty bit. Also see mDirtyImages.
DIRTY_OBJECT_SAMPLERS, // Top-level dirty bit. Also see mDirtySamplers. DIRTY_OBJECT_SAMPLERS, // Top-level dirty bit. Also see mDirtySamplers.
DIRTY_OBJECT_PROGRAM, DIRTY_OBJECT_PROGRAM,
DIRTY_OBJECT_UNKNOWN, DIRTY_OBJECT_UNKNOWN,
...@@ -702,6 +703,7 @@ class State : angle::NonCopyable ...@@ -702,6 +703,7 @@ class State : angle::NonCopyable
angle::Result syncDrawFramebuffer(const Context *context); angle::Result syncDrawFramebuffer(const Context *context);
angle::Result syncVertexArray(const Context *context); angle::Result syncVertexArray(const Context *context);
angle::Result syncTextures(const Context *context); angle::Result syncTextures(const Context *context);
angle::Result syncImages(const Context *context);
angle::Result syncSamplers(const Context *context); angle::Result syncSamplers(const Context *context);
angle::Result syncProgram(const Context *context); angle::Result syncProgram(const Context *context);
...@@ -709,8 +711,8 @@ class State : angle::NonCopyable ...@@ -709,8 +711,8 @@ class State : angle::NonCopyable
static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = { static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = {
&State::syncTexturesInit, &State::syncImagesInit, &State::syncReadAttachments, &State::syncTexturesInit, &State::syncImagesInit, &State::syncReadAttachments,
&State::syncDrawAttachments, &State::syncReadFramebuffer, &State::syncDrawFramebuffer, &State::syncDrawAttachments, &State::syncReadFramebuffer, &State::syncDrawFramebuffer,
&State::syncVertexArray, &State::syncTextures, &State::syncSamplers, &State::syncVertexArray, &State::syncTextures, &State::syncImages,
&State::syncProgram, &State::syncSamplers, &State::syncProgram,
}; };
// Robust init must happen before Framebuffer init for the Vulkan back-end. // Robust init must happen before Framebuffer init for the Vulkan back-end.
...@@ -727,8 +729,9 @@ class State : angle::NonCopyable ...@@ -727,8 +729,9 @@ class State : angle::NonCopyable
static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 5, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index"); static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 5, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index");
static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 6, "check DIRTY_OBJECT_VERTEX_ARRAY index"); static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 6, "check DIRTY_OBJECT_VERTEX_ARRAY index");
static_assert(DIRTY_OBJECT_TEXTURES == 7, "check DIRTY_OBJECT_TEXTURES index"); static_assert(DIRTY_OBJECT_TEXTURES == 7, "check DIRTY_OBJECT_TEXTURES index");
static_assert(DIRTY_OBJECT_SAMPLERS == 8, "check DIRTY_OBJECT_SAMPLERS index"); static_assert(DIRTY_OBJECT_IMAGES == 8, "check DIRTY_OBJECT_IMAGES index");
static_assert(DIRTY_OBJECT_PROGRAM == 9, "check DIRTY_OBJECT_PROGRAM index"); static_assert(DIRTY_OBJECT_SAMPLERS == 9, "check DIRTY_OBJECT_SAMPLERS index");
static_assert(DIRTY_OBJECT_PROGRAM == 10, "check DIRTY_OBJECT_PROGRAM index");
// Dispatch table for buffer update functions. // Dispatch table for buffer update functions.
static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters; static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters;
......
...@@ -3086,10 +3086,6 @@ TEST_P(SimpleStateChangeTestES31, RebindImageTextureDispatchAgain) ...@@ -3086,10 +3086,6 @@ TEST_P(SimpleStateChangeTestES31, RebindImageTextureDispatchAgain)
// and then dispatch again correctly. // and then dispatch again correctly.
TEST_P(SimpleStateChangeTestES31, DispatchWithImageTextureTexSubImageThenDispatchAgain) TEST_P(SimpleStateChangeTestES31, DispatchWithImageTextureTexSubImageThenDispatchAgain)
{ {
// The change to the texture between the dispatch calls is not flushed in the Vulkan backend.
// http://anglebug.com/3539
ANGLE_SKIP_TEST_IF(IsVulkan());
std::array<GLColor, 4> colors = {{GLColor::red, GLColor::red, GLColor::red, GLColor::red}}; std::array<GLColor, 4> colors = {{GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
std::array<GLColor, 4> subColors = { std::array<GLColor, 4> subColors = {
{GLColor::green, GLColor::green, GLColor::green, GLColor::green}}; {GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
......
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