Commit 535d4783 by Tim Van Patten Committed by Commit Bot

Vulkan: Flush if sync object is pending during SyncVk::getStatus()

When a glGetSynciv() is performed for GL_SYNC_STATUS, we should flush any pending commands if a sync object is pending a flush, since the caller is interested in the status of a fence. This will guarantee that the work is submitted to the hardware and eventually completes. This is accomplished by moving mSyncObjectPendingFlush from ContextVk to ShareGroupVk, so that any sync objects used by any contexts within the share group are submitted to hardware and the required work completes. Bug: angleproject:5306 Bug: angleproject:5425 Test: FenceSyncTest.BasicOperations Change-Id: I2e2681ad01fda429ba37f061c9bac5eb91f800fd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2641095Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Tim Van Patten <timvp@google.com>
parent 26e02593
...@@ -373,7 +373,6 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -373,7 +373,6 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mOutsideRenderPassCommands(nullptr), mOutsideRenderPassCommands(nullptr),
mRenderPassCommands(nullptr), mRenderPassCommands(nullptr),
mGpuEventsEnabled(false), mGpuEventsEnabled(false),
mSyncObjectPendingFlush(false),
mEGLSyncObjectPendingFlush(false), mEGLSyncObjectPendingFlush(false),
mHasDeferredFlush(false), mHasDeferredFlush(false),
mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()}, mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
...@@ -694,7 +693,8 @@ angle::Result ContextVk::flush(const gl::Context *context) ...@@ -694,7 +693,8 @@ angle::Result ContextVk::flush(const gl::Context *context)
// lands in the correct place within the command stream. // lands in the correct place within the command stream.
// EGL sync objects can span across context share groups, so don't defer flushes if there's one // EGL sync objects can span across context share groups, so don't defer flushes if there's one
// pending a flush. // pending a flush.
if (mSyncObjectPendingFlush && context->isShared() && !mEGLSyncObjectPendingFlush) if (getShareGroupVk()->isSyncObjectPendingFlush() && context->isShared() &&
!mEGLSyncObjectPendingFlush)
{ {
// Flush the commands to create a sync point in the command stream. // Flush the commands to create a sync point in the command stream.
ANGLE_TRY(flushCommandsAndEndRenderPass()); ANGLE_TRY(flushCommandsAndEndRenderPass());
...@@ -4278,8 +4278,8 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore) ...@@ -4278,8 +4278,8 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
// We must set this to false before calling flushCommandsAndEndRenderPass to prevent it from // We must set this to false before calling flushCommandsAndEndRenderPass to prevent it from
// calling back to flushImpl. // calling back to flushImpl.
mHasDeferredFlush = false; mHasDeferredFlush = false;
mSyncObjectPendingFlush = false; getShareGroupVk()->clearSyncObjectPendingFlush();
ANGLE_TRY(flushCommandsAndEndRenderPass()); ANGLE_TRY(flushCommandsAndEndRenderPass());
......
...@@ -568,7 +568,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -568,7 +568,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
const vk::PerfCounters &getPerfCounters() const { return mPerfCounters; } const vk::PerfCounters &getPerfCounters() const { return mPerfCounters; }
vk::PerfCounters &getPerfCounters() { return mPerfCounters; } vk::PerfCounters &getPerfCounters() { return mPerfCounters; }
void onSyncHelperInitialize() { mSyncObjectPendingFlush = true; } void onSyncHelperInitialize() { getShareGroupVk()->setSyncObjectPendingFlush(); }
void onEGLSyncHelperInitialize() { mEGLSyncObjectPendingFlush = true; } void onEGLSyncHelperInitialize() { mEGLSyncObjectPendingFlush = true; }
// Implementation of MultisampleTextureInitializer // Implementation of MultisampleTextureInitializer
...@@ -991,7 +991,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -991,7 +991,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
// Track SyncHelper object been added into secondary command buffer that has not been flushed to // Track SyncHelper object been added into secondary command buffer that has not been flushed to
// vulkan. // vulkan.
bool mSyncObjectPendingFlush;
bool mEGLSyncObjectPendingFlush; bool mEGLSyncObjectPendingFlush;
bool mHasDeferredFlush; bool mHasDeferredFlush;
......
...@@ -284,6 +284,8 @@ void DisplayVk::populateFeatureList(angle::FeatureList *features) ...@@ -284,6 +284,8 @@ void DisplayVk::populateFeatureList(angle::FeatureList *features)
mRenderer->getFeatures().populateFeatureList(features); mRenderer->getFeatures().populateFeatureList(features);
} }
ShareGroupVk::ShareGroupVk() : mSyncObjectPendingFlush(false) {}
void ShareGroupVk::onDestroy(const egl::Display *display) void ShareGroupVk::onDestroy(const egl::Display *display)
{ {
DisplayVk *displayVk = vk::GetImpl(display); DisplayVk *displayVk = vk::GetImpl(display);
......
...@@ -25,7 +25,7 @@ using ShareContextSet = std::set<ContextVk *>; ...@@ -25,7 +25,7 @@ using ShareContextSet = std::set<ContextVk *>;
class ShareGroupVk : public ShareGroupImpl class ShareGroupVk : public ShareGroupImpl
{ {
public: public:
ShareGroupVk() {} ShareGroupVk();
void onDestroy(const egl::Display *display) override; void onDestroy(const egl::Display *display) override;
// PipelineLayoutCache and DescriptorSetLayoutCache can be shared between multiple threads // PipelineLayoutCache and DescriptorSetLayoutCache can be shared between multiple threads
...@@ -44,6 +44,10 @@ class ShareGroupVk : public ShareGroupImpl ...@@ -44,6 +44,10 @@ class ShareGroupVk : public ShareGroupImpl
mResourceUseLists.emplace_back(std::move(resourceUseList)); mResourceUseLists.emplace_back(std::move(resourceUseList));
} }
bool isSyncObjectPendingFlush() { return mSyncObjectPendingFlush; }
void setSyncObjectPendingFlush() { mSyncObjectPendingFlush = true; }
void clearSyncObjectPendingFlush() { mSyncObjectPendingFlush = false; }
private: private:
// ANGLE uses a PipelineLayout cache to store compatible pipeline layouts. // ANGLE uses a PipelineLayout cache to store compatible pipeline layouts.
PipelineLayoutCache mPipelineLayoutCache; PipelineLayoutCache mPipelineLayoutCache;
...@@ -57,6 +61,8 @@ class ShareGroupVk : public ShareGroupImpl ...@@ -57,6 +61,8 @@ class ShareGroupVk : public ShareGroupImpl
// List of resources currently used that need to be freed when any ContextVk in this // List of resources currently used that need to be freed when any ContextVk in this
// ShareGroupVk submits the next command. // ShareGroupVk submits the next command.
std::vector<vk::ResourceUseList> mResourceUseLists; std::vector<vk::ResourceUseList> mResourceUseLists;
bool mSyncObjectPendingFlush;
}; };
class DisplayVk : public DisplayImpl, public vk::Context class DisplayVk : public DisplayImpl, public vk::Context
......
...@@ -34,8 +34,14 @@ angle::Result FenceNVVk::set(const gl::Context *context, GLenum condition) ...@@ -34,8 +34,14 @@ angle::Result FenceNVVk::set(const gl::Context *context, GLenum condition)
angle::Result FenceNVVk::test(const gl::Context *context, GLboolean *outFinished) angle::Result FenceNVVk::test(const gl::Context *context, GLboolean *outFinished)
{ {
ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getShareGroupVk()->isSyncObjectPendingFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
bool signaled = false; bool signaled = false;
ANGLE_TRY(mFenceSync.getStatus(vk::GetImpl(context), &signaled)); ANGLE_TRY(mFenceSync.getStatus(contextVk, &signaled));
ASSERT(outFinished); ASSERT(outFinished);
*outFinished = signaled ? GL_TRUE : GL_FALSE; *outFinished = signaled ? GL_TRUE : GL_FALSE;
......
...@@ -452,8 +452,14 @@ angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, G ...@@ -452,8 +452,14 @@ angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, G
angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult) angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
{ {
ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getShareGroupVk()->isSyncObjectPendingFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
bool signaled = false; bool signaled = false;
ANGLE_TRY(mSyncHelper.getStatus(vk::GetImpl(context), &signaled)); ANGLE_TRY(mSyncHelper.getStatus(contextVk, &signaled));
*outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED; *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -230,9 +230,6 @@ TEST_P(FenceSyncTest, BasicQueries) ...@@ -230,9 +230,6 @@ TEST_P(FenceSyncTest, BasicQueries)
// Test that basic usage works and doesn't generate errors or crash // Test that basic usage works and doesn't generate errors or crash
TEST_P(FenceSyncTest, BasicOperations) TEST_P(FenceSyncTest, BasicOperations)
{ {
// TODO(http://anglebug.com/5425): glClientWaitSync() returns GL_TIMEOUT_EXPIRED
ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D11());
glClearColor(1.0f, 0.0f, 1.0f, 1.0f); glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
...@@ -241,17 +238,28 @@ TEST_P(FenceSyncTest, BasicOperations) ...@@ -241,17 +238,28 @@ TEST_P(FenceSyncTest, BasicOperations)
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
GLsizei length = 0;
GLint value = 0;
unsigned int loopCount = 0;
glFlush(); glFlush();
// Don't wait forever to make sure the test terminates // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
constexpr GLuint64 kTimeout = 1'000'000'000; // 1 second while (value != GL_SIGNALED && loopCount <= 1000000)
GLint value = 0; {
loopCount++;
glGetSynciv(sync, GL_SYNC_STATUS, 1, &length, &value);
ASSERT_GL_NO_ERROR();
}
ASSERT_GLENUM_EQ(GL_SIGNALED, value);
for (size_t i = 0; i < 20; i++) for (size_t i = 0; i < 20; i++)
{ {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
value = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, kTimeout); glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
ASSERT_TRUE(value == GL_CONDITION_SATISFIED || value == GL_ALREADY_SIGNALED);
} }
} }
......
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