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
{
kTexture0SubjectIndex = 0,
kTextureMaxSubjectIndex = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
kUniformBuffer0SubjectIndex = kTextureMaxSubjectIndex,
kImage0SubjectIndex = kTextureMaxSubjectIndex,
kImageMaxSubjectIndex = kImage0SubjectIndex + IMPLEMENTATION_MAX_IMAGE_UNITS,
kUniformBuffer0SubjectIndex = kImageMaxSubjectIndex,
kUniformBufferMaxSubjectIndex =
kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex,
......@@ -367,6 +369,12 @@ Context::Context(egl::Display *display,
{
mSamplerObserverBindings.emplace_back(this, samplerIndex);
}
for (angle::SubjectIndex imageIndex = kImage0SubjectIndex; imageIndex < kImageMaxSubjectIndex;
++imageIndex)
{
mImageObserverBindings.emplace_back(this, imageIndex);
}
}
void Context::initialize()
......@@ -535,6 +543,7 @@ void Context::initialize()
mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_IMAGES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
......@@ -1166,6 +1175,7 @@ void Context::bindImageTexture(GLuint unit,
{
Texture *tex = mState.mTextureManager->getTexture(texture);
mState.setImageUnit(this, unit, tex, level, layered, layer, access, format);
mImageObserverBindings[unit].bind(tex);
}
void Context::useProgram(ShaderProgramID program)
......@@ -2796,6 +2806,16 @@ bool Context::isTransformFeedbackGenerated(TransformFeedbackID transformFeedback
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
// 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
......@@ -8839,6 +8859,14 @@ void Context::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess
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)
{
mState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
......
......@@ -715,6 +715,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::ObserverBinding mReadFramebufferObserverBinding;
std::vector<angle::ObserverBinding> mUniformBufferObserverBindings;
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.
mutable angle::ScratchBuffer mScratchBuffer;
......
......@@ -2697,6 +2697,24 @@ angle::Result State::syncTextures(const Context *context)
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)
{
if (mDirtySamplers.none())
......@@ -2900,6 +2918,12 @@ void State::onImageStateChange(const Context *context, size_t unit)
{
const ImageUnit &image = mImageUnits[unit];
ASSERT(image.texture.get());
if (image.texture->hasAnyDirtyBit())
{
mDirtyImages.set(unit);
mDirtyObjects.set(DIRTY_OBJECT_IMAGES);
}
if (mRobustResourceInit && image.texture->initState() == InitState::MayNeedInit)
{
mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT);
......
......@@ -586,6 +586,7 @@ class State : angle::NonCopyable
DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY,
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_PROGRAM,
DIRTY_OBJECT_UNKNOWN,
......@@ -702,6 +703,7 @@ class State : angle::NonCopyable
angle::Result syncDrawFramebuffer(const Context *context);
angle::Result syncVertexArray(const Context *context);
angle::Result syncTextures(const Context *context);
angle::Result syncImages(const Context *context);
angle::Result syncSamplers(const Context *context);
angle::Result syncProgram(const Context *context);
......@@ -709,8 +711,8 @@ class State : angle::NonCopyable
static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = {
&State::syncTexturesInit, &State::syncImagesInit, &State::syncReadAttachments,
&State::syncDrawAttachments, &State::syncReadFramebuffer, &State::syncDrawFramebuffer,
&State::syncVertexArray, &State::syncTextures, &State::syncSamplers,
&State::syncProgram,
&State::syncVertexArray, &State::syncTextures, &State::syncImages,
&State::syncSamplers, &State::syncProgram,
};
// Robust init must happen before Framebuffer init for the Vulkan back-end.
......@@ -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_VERTEX_ARRAY == 6, "check DIRTY_OBJECT_VERTEX_ARRAY 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_PROGRAM == 9, "check DIRTY_OBJECT_PROGRAM index");
static_assert(DIRTY_OBJECT_IMAGES == 8, "check DIRTY_OBJECT_IMAGES 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.
static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters;
......
......@@ -3086,10 +3086,6 @@ TEST_P(SimpleStateChangeTestES31, RebindImageTextureDispatchAgain)
// and then dispatch again correctly.
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> subColors = {
{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