Commit b56ddbb7 by Yuly Novikov Committed by Commit Bot

Vulkan: Handle VK_ERROR_DEVICE_LOST

By notifying egl::Display that the device is lost, which marks all gl::Context as lost, turning all future GL commands to no-ops. Also clear CommandGraph and destroy in flight resources, making sure no more commands are executed on the lost device. Bug: angleproject:2657 Change-Id: I3a1e3646c8ebb37faff507a3c5cec7582a7e05fc Reviewed-on: https://chromium-review.googlesource.com/c/1323849Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
parent 526392dd
...@@ -650,8 +650,6 @@ angle::Result CommandGraph::submitCommands(Context *context, ...@@ -650,8 +650,6 @@ angle::Result CommandGraph::submitCommands(Context *context,
previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount); previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
} }
mLastBarrierIndex = kInvalidNodeIndex;
VkCommandBufferAllocateInfo primaryInfo = {}; VkCommandBufferAllocateInfo primaryInfo = {};
primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
primaryInfo.commandPool = commandPool->getHandle(); primaryInfo.commandPool = commandPool->getHandle();
...@@ -715,12 +713,7 @@ angle::Result CommandGraph::submitCommands(Context *context, ...@@ -715,12 +713,7 @@ angle::Result CommandGraph::submitCommands(Context *context,
ANGLE_VK_TRY(context, primaryCommandBufferOut->end()); ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
// TODO(jmadill): Use pool allocation so we don't need to deallocate command graph. clear();
for (CommandGraphNode *node : mNodes)
{
delete node;
}
mNodes.clear();
return angle::Result::Continue(); return angle::Result::Continue();
} }
...@@ -730,6 +723,18 @@ bool CommandGraph::empty() const ...@@ -730,6 +723,18 @@ bool CommandGraph::empty() const
return mNodes.empty(); return mNodes.empty();
} }
void CommandGraph::clear()
{
mLastBarrierIndex = kInvalidNodeIndex;
// TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
for (CommandGraphNode *node : mNodes)
{
delete node;
}
mNodes.clear();
}
// Dumps the command graph into a dot file that works with graphviz. // Dumps the command graph into a dot file that works with graphviz.
void CommandGraph::dumpGraphDotFile(std::ostream &out) const void CommandGraph::dumpGraphDotFile(std::ostream &out) const
{ {
......
...@@ -318,6 +318,7 @@ class CommandGraph final : angle::NonCopyable ...@@ -318,6 +318,7 @@ class CommandGraph final : angle::NonCopyable
CommandPool *commandPool, CommandPool *commandPool,
CommandBuffer *primaryCommandBufferOut); CommandBuffer *primaryCommandBufferOut);
bool empty() const; bool empty() const;
void clear();
CommandGraphNode *getLastBarrierNode(size_t *indexOut); CommandGraphNode *getLastBarrierNode(size_t *indexOut);
......
...@@ -1235,7 +1235,7 @@ void ContextVk::handleError(VkResult errorCode, const char *file, unsigned int l ...@@ -1235,7 +1235,7 @@ void ContextVk::handleError(VkResult errorCode, const char *file, unsigned int l
if (errorCode == VK_ERROR_DEVICE_LOST) if (errorCode == VK_ERROR_DEVICE_LOST)
{ {
mRenderer->markDeviceLost(); mRenderer->notifyDeviceLost();
} }
mErrors->handleError(gl::Error(glErrorCode, glErrorCode, errorStream.str())); mErrors->handleError(gl::Error(glErrorCode, glErrorCode, errorStream.str()));
......
...@@ -32,7 +32,7 @@ DisplayVk::~DisplayVk() ...@@ -32,7 +32,7 @@ DisplayVk::~DisplayVk()
egl::Error DisplayVk::initialize(egl::Display *display) egl::Error DisplayVk::initialize(egl::Display *display)
{ {
ASSERT(mRenderer != nullptr && display != nullptr); ASSERT(mRenderer != nullptr && display != nullptr);
angle::Result result = mRenderer->initialize(this, display->getAttributeMap(), getWSIName()); angle::Result result = mRenderer->initialize(this, display, getWSIName());
ANGLE_TRY(angle::ToEGL(result, this, EGL_NOT_INITIALIZED)); ANGLE_TRY(angle::ToEGL(result, this, EGL_NOT_INITIALIZED));
return egl::NoError(); return egl::NoError();
} }
...@@ -196,7 +196,7 @@ void DisplayVk::handleError(VkResult result, const char *file, unsigned int line ...@@ -196,7 +196,7 @@ void DisplayVk::handleError(VkResult result, const char *file, unsigned int line
if (result == VK_ERROR_DEVICE_LOST) if (result == VK_ERROR_DEVICE_LOST)
{ {
mRenderer->markDeviceLost(); mRenderer->notifyDeviceLost();
} }
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/system_utils.h" #include "common/system_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/driver_utils.h" #include "libANGLE/renderer/driver_utils.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h" #include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/CompilerVk.h" #include "libANGLE/renderer/vulkan/CompilerVk.h"
...@@ -49,6 +50,8 @@ namespace ...@@ -49,6 +50,8 @@ namespace
constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2; constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2;
// Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes) // Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes)
static constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60; static constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
// Wait a maximum of 10s. If that times out, we declare it a failure.
static constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
bool ShouldEnableMockICD(const egl::AttributeMap &attribs) bool ShouldEnableMockICD(const egl::AttributeMap &attribs)
{ {
...@@ -294,7 +297,8 @@ void RendererVk::CommandBatch::destroy(VkDevice device) ...@@ -294,7 +297,8 @@ void RendererVk::CommandBatch::destroy(VkDevice device)
// RendererVk implementation. // RendererVk implementation.
RendererVk::RendererVk() RendererVk::RendererVk()
: mCapsInitialized(false), : mDisplay(nullptr),
mCapsInitialized(false),
mInstance(VK_NULL_HANDLE), mInstance(VK_NULL_HANDLE),
mEnableValidationLayers(false), mEnableValidationLayers(false),
mEnableMockICD(false), mEnableMockICD(false),
...@@ -368,9 +372,16 @@ void RendererVk::onDestroy(vk::Context *context) ...@@ -368,9 +372,16 @@ void RendererVk::onDestroy(vk::Context *context)
mPhysicalDevice = VK_NULL_HANDLE; mPhysicalDevice = VK_NULL_HANDLE;
} }
void RendererVk::markDeviceLost() void RendererVk::notifyDeviceLost()
{ {
mDeviceLost = true; mDeviceLost = true;
mCommandGraph.clear();
mLastSubmittedQueueSerial = mCurrentQueueSerial;
mCurrentQueueSerial = mQueueSerialFactory.generate();
freeAllInFlightResources();
mDisplay->notifyDeviceLost();
} }
bool RendererVk::isDeviceLost() const bool RendererVk::isDeviceLost() const
...@@ -379,9 +390,11 @@ bool RendererVk::isDeviceLost() const ...@@ -379,9 +390,11 @@ bool RendererVk::isDeviceLost() const
} }
angle::Result RendererVk::initialize(DisplayVk *displayVk, angle::Result RendererVk::initialize(DisplayVk *displayVk,
const egl::AttributeMap &attribs, egl::Display *display,
const char *wsiName) const char *wsiName)
{ {
mDisplay = display;
const egl::AttributeMap &attribs = mDisplay->getAttributeMap();
ScopedVkLoaderEnvironment scopedEnvironment(ShouldUseDebugLayers(attribs), ScopedVkLoaderEnvironment scopedEnvironment(ShouldUseDebugLayers(attribs),
ShouldEnableMockICD(attribs)); ShouldEnableMockICD(attribs));
mEnableValidationLayers = scopedEnvironment.canEnableValidationLayers(); mEnableValidationLayers = scopedEnvironment.canEnableValidationLayers();
...@@ -933,6 +946,13 @@ void RendererVk::freeAllInFlightResources() ...@@ -933,6 +946,13 @@ void RendererVk::freeAllInFlightResources()
{ {
for (CommandBatch &batch : mInFlightCommands) for (CommandBatch &batch : mInFlightCommands)
{ {
// On device loss we need to wait for fence to be signaled before destroying it
if (mDeviceLost)
{
VkResult status = batch.fence.wait(mDevice, kMaxFenceWaitTimeNs);
// If wait times out, it is probably not possible to recover from lost device
ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST);
}
batch.fence.destroy(mDevice); batch.fence.destroy(mDevice);
batch.commandPool.destroy(mDevice); batch.commandPool.destroy(mDevice);
} }
...@@ -1063,8 +1083,6 @@ angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial) ...@@ -1063,8 +1083,6 @@ angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial)
const CommandBatch &batch = mInFlightCommands[batchIndex]; const CommandBatch &batch = mInFlightCommands[batchIndex];
// Wait for it finish // Wait for it finish
constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
// Wait a maximum of 10s. If that times out, we declare it a failure.
ANGLE_VK_TRY(context, batch.fence.wait(mDevice, kMaxFenceWaitTimeNs)); ANGLE_VK_TRY(context, batch.fence.wait(mDevice, kMaxFenceWaitTimeNs));
// Clean up finished batches. // Clean up finished batches.
...@@ -1335,8 +1353,6 @@ angle::Result RendererVk::getTimestamp(vk::Context *context, uint64_t *timestamp ...@@ -1335,8 +1353,6 @@ angle::Result RendererVk::getTimestamp(vk::Context *context, uint64_t *timestamp
// Wait for the submission to finish. Given no semaphores, there is hope that it would execute // Wait for the submission to finish. Given no semaphores, there is hope that it would execute
// in parallel with what's already running on the GPU. // in parallel with what's already running on the GPU.
// Declare it a failure if it times out.
constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
ANGLE_VK_TRY(context, fence.get().wait(mDevice, kMaxFenceWaitTimeNs)); ANGLE_VK_TRY(context, fence.get().wait(mDevice, kMaxFenceWaitTimeNs));
// Get the query results // Get the query results
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
namespace egl namespace egl
{ {
class AttributeMap; class Display;
class BlobCache; class BlobCache;
} }
...@@ -44,12 +44,10 @@ class RendererVk : angle::NonCopyable ...@@ -44,12 +44,10 @@ class RendererVk : angle::NonCopyable
RendererVk(); RendererVk();
~RendererVk(); ~RendererVk();
angle::Result initialize(DisplayVk *displayVk, angle::Result initialize(DisplayVk *displayVk, egl::Display *display, const char *wsiName);
const egl::AttributeMap &attribs,
const char *wsiName);
void onDestroy(vk::Context *context); void onDestroy(vk::Context *context);
void markDeviceLost(); void notifyDeviceLost();
bool isDeviceLost() const; bool isDeviceLost() const;
std::string getVendorString() const; std::string getVendorString() const;
...@@ -222,6 +220,8 @@ class RendererVk : angle::NonCopyable ...@@ -222,6 +220,8 @@ class RendererVk : angle::NonCopyable
angle::Result checkCompletedGpuEvents(vk::Context *context); angle::Result checkCompletedGpuEvents(vk::Context *context);
void flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS); void flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS);
egl::Display *mDisplay;
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
mutable gl::Caps mNativeCaps; mutable gl::Caps mNativeCaps;
mutable gl::TextureCapsMap mNativeTextureCaps; mutable gl::TextureCapsMap mNativeTextureCaps;
......
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