Commit f10bf6bf by Jamie Madill Committed by Commit Bot

Vulkan: Implement multi-threaded GL.

The main component of this change is to make vk::BufferHelper, vk::ImageHelper and vk::SyncHelper use a common path. We introduce a new "vk::SharedGarbage" helper class that stores small lists of garbage from individual objects like an ImageHelper or BufferHelper. The SharedGarbage is stored in the RendererVk with the ResourceUse of the helper object. The ResourceUse tells RendererVk when it is safe to destroy the GarbageObjects. New "onGraphAccess" commands are added in a few places to enable the common garbage collection path. A couple Context-only resources like default attributes now are referenced where they were not before. Also reorganizes some functions so we can add a few helpful ASSERTs to our graph dependencies. Added "updateCurrentAccessNodes" for this. Also adds a "RendererScoped" helper to replace many uses of "ContextScoped". The multithreading EGL tests mostly pass but have some remaining flakiness so cannot yet be enabled. Bug: angleproject:2464 Change-Id: Ia3e3ae8848d731abf3f21ebe04c33e381e130be0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1808444 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 988f7170
...@@ -78,11 +78,12 @@ void BufferVk::destroy(const gl::Context *context) ...@@ -78,11 +78,12 @@ void BufferVk::destroy(const gl::Context *context)
void BufferVk::release(ContextVk *contextVk) void BufferVk::release(ContextVk *contextVk)
{ {
mBuffer.release(contextVk); RendererVk *renderer = contextVk->getRenderer();
mBuffer.release(renderer);
for (ConversionBuffer &buffer : mVertexConversionBuffers) for (ConversionBuffer &buffer : mVertexConversionBuffers)
{ {
buffer.data.release(contextVk); buffer.data.release(renderer);
} }
} }
......
...@@ -255,29 +255,32 @@ bool CommandGraphResource::isResourceInUse(ContextVk *contextVk) const ...@@ -255,29 +255,32 @@ bool CommandGraphResource::isResourceInUse(ContextVk *contextVk) const
return mUse.isCurrentlyInGraph() || contextVk->isSerialInUse(mUse.getSerial()); return mUse.isCurrentlyInGraph() || contextVk->isSerialInUse(mUse.getSerial());
} }
angle::Result CommandGraphResource::recordCommands(ContextVk *context, angle::Result CommandGraphResource::recordCommands(ContextVk *contextVk,
CommandBuffer **commandBufferOut) CommandBuffer **commandBufferOut)
{ {
onGraphAccess(context->getCommandGraph()); updateCurrentAccessNodes();
if (!hasChildlessWritingNode() || hasStartedRenderPass()) if (!hasChildlessWritingNode() || hasStartedRenderPass())
{ {
startNewCommands(context); startNewCommands(contextVk);
return mCurrentWritingNode->beginOutsideRenderPassRecording( return mCurrentWritingNode->beginOutsideRenderPassRecording(
context, context->getCommandPool(), commandBufferOut); contextVk, contextVk->getCommandPool(), commandBufferOut);
} }
CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands(); CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
if (!outsideRenderPassCommands->valid()) if (!outsideRenderPassCommands->valid())
{ {
ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording( ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
context, context->getCommandPool(), commandBufferOut)); contextVk, contextVk->getCommandPool(), commandBufferOut));
} }
else else
{ {
*commandBufferOut = outsideRenderPassCommands; *commandBufferOut = outsideRenderPassCommands;
} }
// Store reference to usage in graph.
contextVk->getCommandGraph()->onResourceUse(mUse);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -822,6 +825,42 @@ void CommandGraphNode::getMemoryUsageStatsForDiagnostics(size_t *usedMemoryOut, ...@@ -822,6 +825,42 @@ void CommandGraphNode::getMemoryUsageStatsForDiagnostics(size_t *usedMemoryOut,
*allocatedMemoryOut += commandBufferAllocated; *allocatedMemoryOut += commandBufferAllocated;
} }
// SharedGarbage implementation.
SharedGarbage::SharedGarbage() = default;
SharedGarbage::SharedGarbage(SharedGarbage &&other)
{
*this = std::move(other);
}
SharedGarbage::SharedGarbage(SharedResourceUse &&use, std::vector<GarbageObject> &&garbage)
: mLifetime(std::move(use)), mGarbage(std::move(garbage))
{}
SharedGarbage::~SharedGarbage() = default;
SharedGarbage &SharedGarbage::operator=(SharedGarbage &&rhs)
{
std::swap(mLifetime, rhs.mLifetime);
std::swap(mGarbage, rhs.mGarbage);
return *this;
}
bool SharedGarbage::destroyIfComplete(VkDevice device, Serial completedSerial)
{
if (mLifetime.isCurrentlyInGraph() || mLifetime.getSerial() > completedSerial)
return false;
mLifetime.release();
for (GarbageObject &object : mGarbage)
{
object.destroy(device);
}
return true;
}
// CommandGraph implementation. // CommandGraph implementation.
CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator) CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
: mEnableGraphDiagnostics(enableGraphDiagnostics), : mEnableGraphDiagnostics(enableGraphDiagnostics),
...@@ -835,6 +874,7 @@ CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *po ...@@ -835,6 +874,7 @@ CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *po
CommandGraph::~CommandGraph() CommandGraph::~CommandGraph()
{ {
ASSERT(empty()); ASSERT(empty());
ASSERT(mResourceUses.empty());
} }
CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function) CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
......
...@@ -351,6 +351,24 @@ class SharedResourceUse final : angle::NonCopyable ...@@ -351,6 +351,24 @@ class SharedResourceUse final : angle::NonCopyable
ResourceUse *mUse; ResourceUse *mUse;
}; };
class SharedGarbage
{
public:
SharedGarbage();
SharedGarbage(SharedGarbage &&other);
SharedGarbage(SharedResourceUse &&use, std::vector<GarbageObject> &&garbage);
~SharedGarbage();
SharedGarbage &operator=(SharedGarbage &&rhs);
bool destroyIfComplete(VkDevice device, Serial completedSerial);
private:
SharedResourceUse mLifetime;
std::vector<GarbageObject> mGarbage;
};
using SharedGarbageList = std::vector<SharedGarbage>;
// This is a helper class for back-end objects used in Vk command buffers. It records a serial // This is a helper class for back-end objects used in Vk command buffers. It records a serial
// at command recording times indicating an order in the queue. We use Fences to detect when // at command recording times indicating an order in the queue. We use Fences to detect when
// commands finish, and then release any unreferenced and deleted resources based on the stored // commands finish, and then release any unreferenced and deleted resources based on the stored
...@@ -377,6 +395,7 @@ class CommandGraphResource : angle::NonCopyable ...@@ -377,6 +395,7 @@ class CommandGraphResource : angle::NonCopyable
// Updates the in-use serial tracked for this resource. Will clear dependencies if the resource // Updates the in-use serial tracked for this resource. Will clear dependencies if the resource
// was not used in this set of command nodes. // was not used in this set of command nodes.
void onGraphAccess(CommandGraph *commandGraph); void onGraphAccess(CommandGraph *commandGraph);
void updateCurrentAccessNodes();
// Allocates a write node via getNewWriteNode and returns a started command buffer. // Allocates a write node via getNewWriteNode and returns a started command buffer.
// The started command buffer will render outside of a RenderPass. // The started command buffer will render outside of a RenderPass.
...@@ -427,6 +446,9 @@ class CommandGraphResource : angle::NonCopyable ...@@ -427,6 +446,9 @@ class CommandGraphResource : angle::NonCopyable
protected: protected:
explicit CommandGraphResource(CommandGraphResourceType resourceType); explicit CommandGraphResource(CommandGraphResourceType resourceType);
// Current resource lifetime.
SharedResourceUse mUse;
private: private:
// Returns true if this node has a current writing node with no children. // Returns true if this node has a current writing node with no children.
ANGLE_INLINE bool hasChildlessWritingNode() const; ANGLE_INLINE bool hasChildlessWritingNode() const;
...@@ -435,9 +457,6 @@ class CommandGraphResource : angle::NonCopyable ...@@ -435,9 +457,6 @@ class CommandGraphResource : angle::NonCopyable
void onWriteImpl(ContextVk *contextVk, CommandGraphNode *writingNode); void onWriteImpl(ContextVk *contextVk, CommandGraphNode *writingNode);
// Current resource lifetime.
SharedResourceUse mUse;
std::vector<CommandGraphNode *> mCurrentReadingNodes; std::vector<CommandGraphNode *> mCurrentReadingNodes;
// Current command graph writing node. // Current command graph writing node.
...@@ -583,7 +602,7 @@ ANGLE_INLINE bool CommandGraphResource::hasStartedRenderPass() const ...@@ -583,7 +602,7 @@ ANGLE_INLINE bool CommandGraphResource::hasStartedRenderPass() const
return hasChildlessWritingNode() && mCurrentWritingNode->getInsideRenderPassCommands()->valid(); return hasChildlessWritingNode() && mCurrentWritingNode->getInsideRenderPassCommands()->valid();
} }
ANGLE_INLINE void CommandGraphResource::onGraphAccess(CommandGraph *commandGraph) ANGLE_INLINE void CommandGraphResource::updateCurrentAccessNodes()
{ {
// Clear dependencies if this is a new access. // Clear dependencies if this is a new access.
if (!mUse.isCurrentlyInGraph()) if (!mUse.isCurrentlyInGraph())
...@@ -591,6 +610,11 @@ ANGLE_INLINE void CommandGraphResource::onGraphAccess(CommandGraph *commandGraph ...@@ -591,6 +610,11 @@ ANGLE_INLINE void CommandGraphResource::onGraphAccess(CommandGraph *commandGraph
mCurrentWritingNode = nullptr; mCurrentWritingNode = nullptr;
mCurrentReadingNodes.clear(); mCurrentReadingNodes.clear();
} }
}
ANGLE_INLINE void CommandGraphResource::onGraphAccess(CommandGraph *commandGraph)
{
updateCurrentAccessNodes();
// Store reference to usage in graph. // Store reference to usage in graph.
commandGraph->onResourceUse(mUse); commandGraph->onResourceUse(mUse);
...@@ -600,9 +624,13 @@ ANGLE_INLINE bool CommandGraphResource::appendToStartedRenderPass(CommandGraph * ...@@ -600,9 +624,13 @@ ANGLE_INLINE bool CommandGraphResource::appendToStartedRenderPass(CommandGraph *
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
CommandBuffer **commandBufferOut) CommandBuffer **commandBufferOut)
{ {
onGraphAccess(graph); updateCurrentAccessNodes();
if (hasStartedRenderPass()) if (hasStartedRenderPass())
{ {
// Store reference to usage in graph.
graph->onResourceUse(mUse);
if (mCurrentWritingNode->getRenderPassRenderArea().encloses(renderArea)) if (mCurrentWritingNode->getRenderPassRenderArea().encloses(renderArea))
{ {
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands(); *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
...@@ -689,6 +717,7 @@ ANGLE_INLINE bool CommandGraphResource::hasChildlessWritingNode() const ...@@ -689,6 +717,7 @@ ANGLE_INLINE bool CommandGraphResource::hasChildlessWritingNode() const
// CommandGraph inlines. // CommandGraph inlines.
ANGLE_INLINE void CommandGraph::onResourceUse(const SharedResourceUse &resourceUse) ANGLE_INLINE void CommandGraph::onResourceUse(const SharedResourceUse &resourceUse)
{ {
ASSERT(!empty());
SharedResourceUse newUse; SharedResourceUse newUse;
newUse.set(resourceUse); newUse.set(resourceUse);
mResourceUses.emplace_back(std::move(newUse)); mResourceUses.emplace_back(std::move(newUse));
......
...@@ -1052,7 +1052,9 @@ angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(const gl::Context *con ...@@ -1052,7 +1052,9 @@ angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(const gl::Context *con
mVertexArray->getCurrentArrayBuffers(); mVertexArray->getCurrentArrayBuffers();
vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer(); vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask()) // Mark all active vertex buffers as accessed by the graph.
gl::AttributesMask attribsMask = mProgram->getState().getActiveAttribLocationsMask();
for (size_t attribIndex : attribsMask)
{ {
vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex]; vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
if (arrayBuffer) if (arrayBuffer)
...@@ -3141,6 +3143,7 @@ angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex) ...@@ -3141,6 +3143,7 @@ angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
ANGLE_TRY(defaultBuffer.flush(this)); ANGLE_TRY(defaultBuffer.flush(this));
mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle, mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle,
defaultBuffer.getCurrentBuffer(),
static_cast<uint32_t>(offset)); static_cast<uint32_t>(offset));
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -340,7 +340,10 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -340,7 +340,10 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
template <typename T> template <typename T>
void addGarbage(T *object) void addGarbage(T *object)
{ {
mCurrentGarbage.emplace_back(vk::GetGarbage(object)); if (object->valid())
{
mCurrentGarbage.emplace_back(vk::GetGarbage(object));
}
} }
// It would be nice if we didn't have to expose this for QueryVk::getResult. // It would be nice if we didn't have to expose this for QueryVk::getResult.
......
...@@ -181,7 +181,7 @@ void FramebufferVk::destroy(const gl::Context *context) ...@@ -181,7 +181,7 @@ void FramebufferVk::destroy(const gl::Context *context)
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
mFramebuffer.release(contextVk); mFramebuffer.release(contextVk);
mReadPixelBuffer.release(contextVk); mReadPixelBuffer.release(contextVk->getRenderer());
} }
angle::Result FramebufferVk::discard(const gl::Context *context, angle::Result FramebufferVk::discard(const gl::Context *context,
...@@ -263,7 +263,7 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -263,7 +263,7 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
mFramebuffer.onGraphAccess(contextVk->getCommandGraph()); mFramebuffer.updateCurrentAccessNodes();
// This function assumes that only enabled attachments are asked to be cleared. // This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers); ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
...@@ -1604,7 +1604,7 @@ void FramebufferVk::onScissorChange(ContextVk *contextVk) ...@@ -1604,7 +1604,7 @@ void FramebufferVk::onScissorChange(ContextVk *contextVk)
// is too small, we need to start a new one. The latter can happen if a scissored clear starts // is too small, we need to start a new one. The latter can happen if a scissored clear starts
// a render pass, the scissor is disabled and a draw call is issued to affect the whole // a render pass, the scissor is disabled and a draw call is issued to affect the whole
// framebuffer. // framebuffer.
mFramebuffer.onGraphAccess(contextVk->getCommandGraph()); mFramebuffer.updateCurrentAccessNodes();
if (mFramebuffer.hasStartedRenderPass() && if (mFramebuffer.hasStartedRenderPass() &&
!mFramebuffer.getRenderPassRenderArea().encloses(scissoredRenderArea)) !mFramebuffer.getRenderPassRenderArea().encloses(scissoredRenderArea))
{ {
......
...@@ -32,33 +32,19 @@ void ImageVk::onDestroy(const egl::Display *display) ...@@ -32,33 +32,19 @@ void ImageVk::onDestroy(const egl::Display *display)
DisplayVk *displayVk = vk::GetImpl(display); DisplayVk *displayVk = vk::GetImpl(display);
RendererVk *renderer = displayVk->getRenderer(); RendererVk *renderer = displayVk->getRenderer();
std::vector<vk::GarbageObject> garbage;
if (mImage != nullptr && mOwnsImage) if (mImage != nullptr && mOwnsImage)
{ {
mImage->releaseImage(displayVk, &garbage); mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(displayVk, &garbage); mImage->releaseStagingBuffer(renderer);
delete mImage; SafeDelete(mImage);
} }
else if (egl::IsExternalImageTarget(mState.target)) else if (egl::IsExternalImageTarget(mState.target))
{ {
ASSERT(mState.source != nullptr); ASSERT(mState.source != nullptr);
ExternalImageSiblingVk *externalImageSibling = ExternalImageSiblingVk *externalImageSibling =
GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source)); GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
externalImageSibling->release(displayVk, &garbage); externalImageSibling->release(renderer);
} mImage = nullptr;
mImage = nullptr;
if (!garbage.empty())
{
renderer->addGarbage(std::move(mImageLastUseFences), std::move(garbage));
}
else
{
for (vk::Shared<vk::Fence> &fence : mImageLastUseFences)
{
fence.reset(displayVk->getDevice());
}
} }
} }
...@@ -160,12 +146,6 @@ angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sib ...@@ -160,12 +146,6 @@ angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sib
// Flush the context to make sure the fence has been submitted. // Flush the context to make sure the fence has been submitted.
ANGLE_TRY(contextVk->flushImpl(nullptr)); ANGLE_TRY(contextVk->flushImpl(nullptr));
vk::Shared<vk::Fence> fence = contextVk->getLastSubmittedFence();
if (fence.isReferenced())
{
mImageLastUseFences.push_back(std::move(fence));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -24,7 +24,7 @@ class ExternalImageSiblingVk : public ExternalImageSiblingImpl ...@@ -24,7 +24,7 @@ class ExternalImageSiblingVk : public ExternalImageSiblingImpl
virtual vk::ImageHelper *getImage() const = 0; virtual vk::ImageHelper *getImage() const = 0;
virtual void release(DisplayVk *display, std::vector<vk::GarbageObject> *garbageQueue) = 0; virtual void release(RendererVk *renderer) = 0;
}; };
class ImageVk : public ImageImpl class ImageVk : public ImageImpl
......
...@@ -81,7 +81,7 @@ void OverlayVk::onDestroy(const gl::Context *context) ...@@ -81,7 +81,7 @@ void OverlayVk::onDestroy(const gl::Context *context)
angle::Result OverlayVk::createFont(ContextVk *contextVk) angle::Result OverlayVk::createFont(ContextVk *contextVk)
{ {
RendererVk *rendererVk = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
// Create a buffer to stage font data upload. // Create a buffer to stage font data upload.
VkBufferCreateInfo bufferCreateInfo = {}; VkBufferCreateInfo bufferCreateInfo = {};
...@@ -91,7 +91,7 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk) ...@@ -91,7 +91,7 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vk::ContextScoped<vk::BufferHelper> fontDataBuffer(contextVk); vk::RendererScoped<vk::BufferHelper> fontDataBuffer(renderer);
ANGLE_TRY(fontDataBuffer.get().init(contextVk, bufferCreateInfo, ANGLE_TRY(fontDataBuffer.get().init(contextVk, bufferCreateInfo,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
...@@ -110,10 +110,10 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk) ...@@ -110,10 +110,10 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
ANGLE_TRY( ANGLE_TRY(
mFontImage.init(contextVk, gl::TextureType::_2D, mFontImage.init(contextVk, gl::TextureType::_2D,
VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1}, VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1},
rendererVk->getFormat(angle::FormatID::R8_UNORM), 1, renderer->getFormat(angle::FormatID::R8_UNORM), 1,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1,
gl::overlay::kFontCount)); gl::overlay::kFontCount));
ANGLE_TRY(mFontImage.initMemory(contextVk, rendererVk->getMemoryProperties(), ANGLE_TRY(mFontImage.initMemory(contextVk, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray, ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
...@@ -149,10 +149,10 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk) ...@@ -149,10 +149,10 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
angle::Result OverlayVk::cullWidgets(ContextVk *contextVk) angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
{ {
RendererVk *rendererVk = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
// Release old culledWidgets image // Release old culledWidgets image
mCulledWidgets.releaseImage(contextVk); mCulledWidgets.releaseImage(renderer);
contextVk->addGarbage(&mCulledWidgetsView); contextVk->addGarbage(&mCulledWidgetsView);
// Create a buffer to contain coordinates of enabled text and graph widgets. This buffer will // Create a buffer to contain coordinates of enabled text and graph widgets. This buffer will
...@@ -163,7 +163,7 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk) ...@@ -163,7 +163,7 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vk::ContextScoped<vk::BufferHelper> enabledWidgetsBuffer(contextVk); vk::RendererScoped<vk::BufferHelper> enabledWidgetsBuffer(renderer);
ANGLE_TRY(enabledWidgetsBuffer.get().init(contextVk, bufferCreateInfo, ANGLE_TRY(enabledWidgetsBuffer.get().init(contextVk, bufferCreateInfo,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
...@@ -186,10 +186,10 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk) ...@@ -186,10 +186,10 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1}; UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1};
ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent, ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent,
rendererVk->getFormat(angle::FormatID::R32G32_UINT), 1, renderer->getFormat(angle::FormatID::R32G32_UINT), 1,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1,
1)); 1));
ANGLE_TRY(mCulledWidgets.initMemory(contextVk, rendererVk->getMemoryProperties(), ANGLE_TRY(mCulledWidgets.initMemory(contextVk, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D, ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
...@@ -214,10 +214,10 @@ angle::Result OverlayVk::onPresent(ContextVk *contextVk, ...@@ -214,10 +214,10 @@ angle::Result OverlayVk::onPresent(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
RendererVk *rendererVk = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
// If the swapchain image doesn't support storage image, we can't output to it. // If the swapchain image doesn't support storage image, we can't output to it.
VkFormatFeatureFlags featureBits = rendererVk->getImageFormatFeatureBits( VkFormatFeatureFlags featureBits = renderer->getImageFormatFeatureBits(
imageToPresent->getFormat().vkImageFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT); imageToPresent->getFormat().vkImageFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
{ {
...@@ -240,8 +240,8 @@ angle::Result OverlayVk::onPresent(ContextVk *contextVk, ...@@ -240,8 +240,8 @@ angle::Result OverlayVk::onPresent(ContextVk *contextVk,
mRefreshCulledWidgets = false; mRefreshCulledWidgets = false;
} }
vk::ContextScoped<vk::BufferHelper> textDataBuffer(contextVk); vk::RendererScoped<vk::BufferHelper> textDataBuffer(renderer);
vk::ContextScoped<vk::BufferHelper> graphDataBuffer(contextVk); vk::RendererScoped<vk::BufferHelper> graphDataBuffer(renderer);
VkBufferCreateInfo textBufferCreateInfo = {}; VkBufferCreateInfo textBufferCreateInfo = {};
textBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; textBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
......
...@@ -446,15 +446,17 @@ void ProgramVk::reset(ContextVk *contextVk) ...@@ -446,15 +446,17 @@ void ProgramVk::reset(ContextVk *contextVk)
} }
mPipelineLayout.reset(); mPipelineLayout.reset();
RendererVk *renderer = contextVk->getRenderer();
for (auto &uniformBlock : mDefaultUniformBlocks) for (auto &uniformBlock : mDefaultUniformBlocks)
{ {
uniformBlock.storage.release(contextVk); uniformBlock.storage.release(renderer);
} }
mDefaultShaderInfo.release(contextVk); mDefaultShaderInfo.release(contextVk);
mLineRasterShaderInfo.release(contextVk); mLineRasterShaderInfo.release(contextVk);
mEmptyBuffer.release(contextVk); mEmptyBuffer.release(renderer);
mDescriptorSets.clear(); mDescriptorSets.clear();
mEmptyDescriptorSets.fill(VK_NULL_HANDLE); mEmptyDescriptorSets.fill(VK_NULL_HANDLE);
...@@ -470,6 +472,7 @@ void ProgramVk::reset(ContextVk *contextVk) ...@@ -470,6 +472,7 @@ void ProgramVk::reset(ContextVk *contextVk)
} }
mTextureDescriptorsCache.clear(); mTextureDescriptorsCache.clear();
mDescriptorBuffersCache.clear();
} }
std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context, std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
...@@ -1219,6 +1222,8 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk) ...@@ -1219,6 +1222,8 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
uint32_t bindingIndex = 0; uint32_t bindingIndex = 0;
mDescriptorBuffersCache.clear();
// Write default uniforms for each shader type. // Write default uniforms for each shader type.
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
...@@ -1228,13 +1233,15 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk) ...@@ -1228,13 +1233,15 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
if (!uniformBlock.uniformData.empty()) if (!uniformBlock.uniformData.empty())
{ {
const vk::BufferHelper *bufferHelper = uniformBlock.storage.getCurrentBuffer(); vk::BufferHelper *bufferHelper = uniformBlock.storage.getCurrentBuffer();
bufferInfo.buffer = bufferHelper->getBuffer().getHandle(); bufferInfo.buffer = bufferHelper->getBuffer().getHandle();
mDescriptorBuffersCache.emplace_back(bufferHelper);
} }
else else
{ {
mEmptyBuffer.onGraphAccess(contextVk->getCommandGraph()); mEmptyBuffer.onGraphAccess(contextVk->getCommandGraph());
bufferInfo.buffer = mEmptyBuffer.getBuffer().getHandle(); bufferInfo.buffer = mEmptyBuffer.getBuffer().getHandle();
mDescriptorBuffersCache.emplace_back(&mEmptyBuffer);
} }
bufferInfo.offset = 0; bufferInfo.offset = 0;
...@@ -1751,6 +1758,11 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk, ...@@ -1751,6 +1758,11 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
mDynamicBufferOffsets.data()); mDynamicBufferOffsets.data());
} }
for (vk::BufferHelper *buffer : mDescriptorBuffersCache)
{
buffer->onGraphAccess(contextVk->getCommandGraph());
}
return angle::Result::Continue; return angle::Result::Continue;
} }
} // namespace rx } // namespace rx
...@@ -141,7 +141,7 @@ class ProgramVk : public ProgramImpl ...@@ -141,7 +141,7 @@ class ProgramVk : public ProgramImpl
vk::ShaderProgramHelper *shaderProgram; vk::ShaderProgramHelper *shaderProgram;
ANGLE_TRY(initGraphicsShaders(contextVk, mode, &shaderProgram)); ANGLE_TRY(initGraphicsShaders(contextVk, mode, &shaderProgram));
ASSERT(shaderProgram->isGraphicsProgram()); ASSERT(shaderProgram->isGraphicsProgram());
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
vk::PipelineCache *pipelineCache = nullptr; vk::PipelineCache *pipelineCache = nullptr;
ANGLE_TRY(renderer->getPipelineCache(&pipelineCache)); ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
return shaderProgram->getGraphicsPipeline( return shaderProgram->getGraphicsPipeline(
...@@ -282,6 +282,7 @@ class ProgramVk : public ProgramImpl ...@@ -282,6 +282,7 @@ class ProgramVk : public ProgramImpl
// Descriptor sets for uniform blocks and textures for this program. // Descriptor sets for uniform blocks and textures for this program.
std::vector<VkDescriptorSet> mDescriptorSets; std::vector<VkDescriptorSet> mDescriptorSets;
vk::DescriptorSetLayoutArray<VkDescriptorSet> mEmptyDescriptorSets; vk::DescriptorSetLayoutArray<VkDescriptorSet> mEmptyDescriptorSets;
std::vector<vk::BufferHelper *> mDescriptorBuffersCache;
std::unordered_map<vk::TextureDescriptorDesc, VkDescriptorSet> mTextureDescriptorsCache; std::unordered_map<vk::TextureDescriptorDesc, VkDescriptorSet> mTextureDescriptorsCache;
......
...@@ -225,8 +225,10 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk) ...@@ -225,8 +225,10 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk)
{ {
if (mImage && mOwnsImage) if (mImage && mOwnsImage)
{ {
mImage->releaseImage(contextVk); RendererVk *renderer = contextVk->getRenderer();
mImage->releaseStagingBuffer(contextVk);
mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(renderer);
} }
else else
{ {
......
...@@ -505,31 +505,6 @@ void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices, ...@@ -505,31 +505,6 @@ void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices,
*physicalDeviceOut = physicalDevices[0]; *physicalDeviceOut = physicalDevices[0];
vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut); vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
} }
angle::Result WaitFences(vk::Context *context,
std::vector<vk::Shared<vk::Fence>> *fences,
bool block)
{
uint64_t timeout = block ? context->getRenderer()->getMaxFenceWaitTimeNs() : 0;
// Iterate backwards over the fences, removing them from the list in constant time when they
// are complete.
while (!fences->empty())
{
VkResult result = fences->back().get().wait(context->getDevice(), timeout);
if (result == VK_TIMEOUT)
{
return angle::Result::Continue;
}
ANGLE_VK_TRY(context, result);
context->getRenderer()->resetSharedFence(&fences->back());
fences->pop_back();
}
return angle::Result::Continue;
}
} // namespace } // namespace
// RendererVk implementation. // RendererVk implementation.
...@@ -561,12 +536,13 @@ RendererVk::RendererVk() ...@@ -561,12 +536,13 @@ RendererVk::RendererVk()
RendererVk::~RendererVk() RendererVk::~RendererVk()
{ {
ASSERT(mFencedGarbage.empty()); ASSERT(mSharedGarbage.empty());
} }
void RendererVk::onDestroy(vk::Context *context) void RendererVk::onDestroy(vk::Context *context)
{ {
(void)cleanupGarbage(context, true); (void)cleanupGarbage(context, true);
ASSERT(mSharedGarbage.empty());
mFenceRecycler.destroy(mDevice); mFenceRecycler.destroy(mDevice);
...@@ -1621,20 +1597,6 @@ angle::Result RendererVk::newSharedFence(vk::Context *context, ...@@ -1621,20 +1597,6 @@ angle::Result RendererVk::newSharedFence(vk::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
void RendererVk::addGarbage(vk::Shared<vk::Fence> &&fence, std::vector<vk::GarbageObject> &&garbage)
{
std::vector<vk::Shared<vk::Fence>> fences;
fences.push_back(std::move(fence));
addGarbage(std::move(fences), std::move(garbage));
}
void RendererVk::addGarbage(std::vector<vk::Shared<vk::Fence>> &&fences,
std::vector<vk::GarbageObject> &&garbage)
{
std::lock_guard<decltype(mGarbageMutex)> lock(mGarbageMutex);
mFencedGarbage.emplace_back(std::move(fences), std::move(garbage));
}
template <VkFormatFeatureFlags VkFormatProperties::*features> template <VkFormatFeatureFlags VkFormatProperties::*features>
VkFormatFeatureFlags RendererVk::getFormatFeatureBits(VkFormat format, VkFormatFeatureFlags RendererVk::getFormatFeatureBits(VkFormat format,
const VkFormatFeatureFlags featureBits) const VkFormatFeatureFlags featureBits)
...@@ -1675,17 +1637,13 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block) ...@@ -1675,17 +1637,13 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block)
{ {
std::lock_guard<decltype(mGarbageMutex)> lock(mGarbageMutex); std::lock_guard<decltype(mGarbageMutex)> lock(mGarbageMutex);
auto garbageIter = mFencedGarbage.begin(); for (auto garbageIter = mSharedGarbage.begin(); garbageIter != mSharedGarbage.end();)
while (garbageIter != mFencedGarbage.end())
{ {
ANGLE_TRY(WaitFences(context, &garbageIter->first, block)); // Possibly 'counter' should be always zero when we add the object to garbage.
if (garbageIter->first.empty()) vk::SharedGarbage &garbage = *garbageIter;
if (garbage.destroyIfComplete(mDevice, mLastCompletedQueueSerial))
{ {
for (vk::GarbageObject &garbageObject : garbageIter->second) garbageIter = mSharedGarbage.erase(garbageIter);
{
garbageObject.destroy(mDevice);
}
garbageIter = mFencedGarbage.erase(garbageIter);
} }
else else
{ {
......
...@@ -45,6 +45,18 @@ struct Format; ...@@ -45,6 +45,18 @@ struct Format;
// glSignalSemaphoreEXT. // glSignalSemaphoreEXT.
using SignalSemaphoreVector = angle::FixedVector<VkSemaphore, 2>; using SignalSemaphoreVector = angle::FixedVector<VkSemaphore, 2>;
inline void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut) {}
template <typename ArgT, typename... ArgsT>
void CollectGarbage(std::vector<vk::GarbageObject> *garbageOut, ArgT object, ArgsT... objectsIn)
{
if (object->valid())
{
garbageOut->emplace_back(vk::GarbageObject::Get(object));
}
CollectGarbage(garbageOut, objectsIn...);
}
class RendererVk : angle::NonCopyable class RendererVk : angle::NonCopyable
{ {
public: public:
...@@ -151,9 +163,23 @@ class RendererVk : angle::NonCopyable ...@@ -151,9 +163,23 @@ class RendererVk : angle::NonCopyable
sharedFenceIn->resetAndRecycle(&mFenceRecycler); sharedFenceIn->resetAndRecycle(&mFenceRecycler);
} }
void addGarbage(vk::Shared<vk::Fence> &&fence, std::vector<vk::GarbageObject> &&garbage); template <typename... ArgsT>
void addGarbage(std::vector<vk::Shared<vk::Fence>> &&fences, void collectGarbageAndReinit(vk::SharedResourceUse *use, ArgsT... garbageIn)
std::vector<vk::GarbageObject> &&garbage); {
std::vector<vk::GarbageObject> sharedGarbage;
CollectGarbage(&sharedGarbage, garbageIn...);
if (!sharedGarbage.empty())
{
mSharedGarbage.emplace_back(std::move(*use), std::move(sharedGarbage));
}
else
{
// Force releasing "use" even if no garbage was created.
use->release();
}
// Keep "use" valid.
use->init();
}
static constexpr size_t kMaxExtensionNames = 200; static constexpr size_t kMaxExtensionNames = 200;
using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>; using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>;
...@@ -230,9 +256,7 @@ class RendererVk : angle::NonCopyable ...@@ -230,9 +256,7 @@ class RendererVk : angle::NonCopyable
vk::Recycler<vk::Fence> mFenceRecycler; vk::Recycler<vk::Fence> mFenceRecycler;
std::mutex mGarbageMutex; std::mutex mGarbageMutex;
using FencedGarbage = vk::SharedGarbageList mSharedGarbage;
std::pair<std::vector<vk::Shared<vk::Fence>>, std::vector<vk::GarbageObject>>;
std::vector<FencedGarbage> mFencedGarbage;
vk::MemoryProperties mMemoryProperties; vk::MemoryProperties mMemoryProperties;
vk::FormatTable mFormatTable; vk::FormatTable mFormatTable;
......
...@@ -887,10 +887,12 @@ angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk, ...@@ -887,10 +887,12 @@ angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk,
void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk) void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
{ {
RendererVk *renderer = contextVk->getRenderer();
if (mDepthStencilImage.valid()) if (mDepthStencilImage.valid())
{ {
mDepthStencilImage.releaseImage(contextVk); mDepthStencilImage.releaseImage(renderer);
mDepthStencilImage.releaseStagingBuffer(contextVk); mDepthStencilImage.releaseStagingBuffer(renderer);
if (mDepthStencilImageView.valid()) if (mDepthStencilImageView.valid())
{ {
...@@ -900,8 +902,8 @@ void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk) ...@@ -900,8 +902,8 @@ void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
if (mColorImageMS.valid()) if (mColorImageMS.valid())
{ {
mColorImageMS.releaseImage(contextVk); mColorImageMS.releaseImage(renderer);
mColorImageMS.releaseStagingBuffer(contextVk); mColorImageMS.releaseStagingBuffer(renderer);
contextVk->addGarbage(&mColorImageViewMS); contextVk->addGarbage(&mColorImageViewMS);
contextVk->addGarbage(&mFramebufferMS); contextVk->addGarbage(&mFramebufferMS);
......
...@@ -17,32 +17,25 @@ ...@@ -17,32 +17,25 @@
namespace rx namespace rx
{ {
FenceSyncVk::FenceSyncVk() {} namespace vk
FenceSyncVk::~FenceSyncVk() {}
void FenceSyncVk::onDestroy(ContextVk *contextVk)
{ {
if (mEvent.valid()) SyncHelper::SyncHelper()
{ {
contextVk->addGarbage(&mEvent); mUse.init();
}
for (vk::Shared<vk::Fence> &fence : mFences)
{
fence.reset(contextVk->getDevice());
}
} }
void FenceSyncVk::onDestroy(DisplayVk *display) SyncHelper::~SyncHelper()
{ {
std::vector<vk::GarbageObject> garbage; mUse.release();
garbage.emplace_back(vk::GetGarbage(&mEvent)); }
display->getRenderer()->addGarbage(std::move(mFences), std::move(garbage)); void SyncHelper::releaseToRenderer(RendererVk *renderer)
{
renderer->collectGarbageAndReinit(&mUse, &mEvent);
mFence.reset(renderer->getDevice());
} }
angle::Result FenceSyncVk::initialize(ContextVk *contextVk) angle::Result SyncHelper::initialize(ContextVk *contextVk)
{ {
ASSERT(!mEvent.valid()); ASSERT(!mEvent.valid());
...@@ -53,24 +46,24 @@ angle::Result FenceSyncVk::initialize(ContextVk *contextVk) ...@@ -53,24 +46,24 @@ angle::Result FenceSyncVk::initialize(ContextVk *contextVk)
eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
eventCreateInfo.flags = 0; eventCreateInfo.flags = 0;
vk::DeviceScoped<vk::Event> event(device); DeviceScoped<Event> event(device);
ANGLE_VK_TRY(contextVk, event.get().init(device, eventCreateInfo)); ANGLE_VK_TRY(contextVk, event.get().init(device, eventCreateInfo));
ANGLE_TRY(contextVk->getNextSubmitFence(&mFence));
vk::Shared<vk::Fence> fence;
ANGLE_TRY(contextVk->getNextSubmitFence(&fence));
mEvent = event.release(); mEvent = event.release();
mFences.emplace_back(std::move(fence));
contextVk->getCommandGraph()->setFenceSync(mEvent); CommandGraph *commandGraph = contextVk->getCommandGraph();
commandGraph->setFenceSync(mEvent);
commandGraph->onResourceUse(mUse);
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result FenceSyncVk::clientWait(vk::Context *context, angle::Result SyncHelper::clientWait(Context *context,
ContextVk *contextVk, ContextVk *contextVk,
bool flushCommands, bool flushCommands,
uint64_t timeout, uint64_t timeout,
VkResult *outResult) VkResult *outResult)
{ {
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = context->getRenderer();
...@@ -97,8 +90,8 @@ angle::Result FenceSyncVk::clientWait(vk::Context *context, ...@@ -97,8 +90,8 @@ angle::Result FenceSyncVk::clientWait(vk::Context *context,
// Wait on the fence that's expected to be signaled on the first vkQueueSubmit after // Wait on the fence that's expected to be signaled on the first vkQueueSubmit after
// `initialize` was called. The first fence is the fence created to signal this sync. // `initialize` was called. The first fence is the fence created to signal this sync.
ASSERT(!mFences.empty()); ASSERT(mFence.get().valid());
VkResult status = mFences[0].get().wait(renderer->getDevice(), timeout); VkResult status = mFence.get().wait(renderer->getDevice(), timeout);
// Check for errors, but don't consider timeout as such. // Check for errors, but don't consider timeout as such.
if (status != VK_TIMEOUT) if (status != VK_TIMEOUT)
...@@ -110,21 +103,14 @@ angle::Result FenceSyncVk::clientWait(vk::Context *context, ...@@ -110,21 +103,14 @@ angle::Result FenceSyncVk::clientWait(vk::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result FenceSyncVk::serverWait(vk::Context *context, ContextVk *contextVk) void SyncHelper::serverWait(ContextVk *contextVk)
{ {
if (contextVk) CommandGraph *commandGraph = contextVk->getCommandGraph();
{ commandGraph->waitFenceSync(mEvent);
contextVk->getCommandGraph()->waitFenceSync(mEvent); commandGraph->onResourceUse(mUse);
// Track fences from Contexts that use this sync for garbage collection.
vk::Shared<vk::Fence> nextSubmitFence;
ANGLE_TRY(contextVk->getNextSubmitFence(&nextSubmitFence));
mFences.emplace_back(std::move(nextSubmitFence));
}
return angle::Result::Continue;
} }
angle::Result FenceSyncVk::getStatus(vk::Context *context, bool *signaled) angle::Result SyncHelper::getStatus(Context *context, bool *signaled)
{ {
VkResult result = mEvent.getStatus(context->getDevice()); VkResult result = mEvent.getStatus(context->getDevice());
if (result != VK_EVENT_SET && result != VK_EVENT_RESET) if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
...@@ -134,6 +120,7 @@ angle::Result FenceSyncVk::getStatus(vk::Context *context, bool *signaled) ...@@ -134,6 +120,7 @@ angle::Result FenceSyncVk::getStatus(vk::Context *context, bool *signaled)
*signaled = result == VK_EVENT_SET; *signaled = result == VK_EVENT_SET;
return angle::Result::Continue; return angle::Result::Continue;
} }
} // namespace vk
SyncVk::SyncVk() : SyncImpl() {} SyncVk::SyncVk() : SyncImpl() {}
...@@ -141,7 +128,7 @@ SyncVk::~SyncVk() {} ...@@ -141,7 +128,7 @@ SyncVk::~SyncVk() {}
void SyncVk::onDestroy(const gl::Context *context) void SyncVk::onDestroy(const gl::Context *context)
{ {
mFenceSync.onDestroy(vk::GetImpl(context)); mFenceSync.releaseToRenderer(vk::GetImpl(context)->getRenderer());
} }
angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags) angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags)
...@@ -194,7 +181,8 @@ angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, G ...@@ -194,7 +181,8 @@ angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, G
ASSERT(timeout == GL_TIMEOUT_IGNORED); ASSERT(timeout == GL_TIMEOUT_IGNORED);
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
return mFenceSync.serverWait(contextVk, contextVk); mFenceSync.serverWait(contextVk);
return angle::Result::Continue;
} }
angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult) angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
...@@ -215,7 +203,7 @@ EGLSyncVk::~EGLSyncVk() {} ...@@ -215,7 +203,7 @@ EGLSyncVk::~EGLSyncVk() {}
void EGLSyncVk::onDestroy(const egl::Display *display) void EGLSyncVk::onDestroy(const egl::Display *display)
{ {
mFenceSync.onDestroy(vk::GetImpl(display)); mFenceSync.releaseToRenderer(vk::GetImpl(display)->getRenderer());
} }
egl::Error EGLSyncVk::initialize(const egl::Display *display, egl::Error EGLSyncVk::initialize(const egl::Display *display,
...@@ -275,12 +263,14 @@ egl::Error EGLSyncVk::serverWait(const egl::Display *display, ...@@ -275,12 +263,14 @@ egl::Error EGLSyncVk::serverWait(const egl::Display *display,
const gl::Context *context, const gl::Context *context,
EGLint flags) EGLint flags)
{ {
// Server wait requires a valid bound context.
ASSERT(context);
// No flags are currently implemented.
ASSERT(flags == 0); ASSERT(flags == 0);
ContextVk *contextVk = context ? vk::GetImpl(context) : nullptr;
if (mFenceSync.serverWait(vk::GetImpl(display), contextVk) == angle::Result::Stop) ContextVk *contextVk = vk::GetImpl(context);
{ mFenceSync.serverWait(contextVk);
return egl::Error(EGL_BAD_ALLOC);
}
return egl::NoError(); return egl::NoError();
} }
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
#include "libANGLE/renderer/EGLSyncImpl.h" #include "libANGLE/renderer/EGLSyncImpl.h"
#include "libANGLE/renderer/SyncImpl.h" #include "libANGLE/renderer/SyncImpl.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace egl namespace egl
{ {
...@@ -22,34 +21,38 @@ class AttributeMap; ...@@ -22,34 +21,38 @@ class AttributeMap;
namespace rx namespace rx
{ {
namespace vk
{
// The behaviors of SyncImpl and EGLSyncImpl as fence syncs (only supported type) are currently // The behaviors of SyncImpl and EGLSyncImpl as fence syncs (only supported type) are currently
// identical for the Vulkan backend, and this class implements both interfaces. // identical for the Vulkan backend, and this class implements both interfaces.
class FenceSyncVk class SyncHelper
{ {
public: public:
FenceSyncVk(); SyncHelper();
~FenceSyncVk(); ~SyncHelper();
void onDestroy(ContextVk *contextVk); void releaseToRenderer(RendererVk *renderer);
void onDestroy(DisplayVk *display);
angle::Result initialize(ContextVk *contextVk); angle::Result initialize(ContextVk *contextVk);
angle::Result clientWait(vk::Context *context, angle::Result clientWait(Context *context,
ContextVk *contextVk, ContextVk *contextVk,
bool flushCommands, bool flushCommands,
uint64_t timeout, uint64_t timeout,
VkResult *outResult); VkResult *outResult);
angle::Result serverWait(vk::Context *context, ContextVk *contextVk); void serverWait(ContextVk *contextVk);
angle::Result getStatus(vk::Context *context, bool *signaled); angle::Result getStatus(Context *context, bool *signaled);
private: private:
// The vkEvent that's signaled on `init` and can be waited on in `serverWait`, or queried with // The vkEvent that's signaled on `init` and can be waited on in `serverWait`, or queried with
// `getStatus`. // `getStatus`.
vk::Event mEvent; Event mEvent;
// The first fence in the list is signaled once the CB including the `init` signal is executed. // The fence is signaled once the CB including the `init` signal is executed.
// `clientWait` waits on this fence. The other fences are referenced to prevent deletion. // `clientWait` waits on this fence.
std::vector<vk::Shared<vk::Fence>> mFences; Shared<Fence> mFence;
SharedResourceUse mUse;
}; };
} // namespace vk
class SyncVk final : public SyncImpl class SyncVk final : public SyncImpl
{ {
...@@ -70,7 +73,7 @@ class SyncVk final : public SyncImpl ...@@ -70,7 +73,7 @@ class SyncVk final : public SyncImpl
angle::Result getStatus(const gl::Context *context, GLint *outResult) override; angle::Result getStatus(const gl::Context *context, GLint *outResult) override;
private: private:
FenceSyncVk mFenceSync; vk::SyncHelper mFenceSync;
}; };
class EGLSyncVk final : public EGLSyncImpl class EGLSyncVk final : public EGLSyncImpl
...@@ -97,7 +100,7 @@ class EGLSyncVk final : public EGLSyncImpl ...@@ -97,7 +100,7 @@ class EGLSyncVk final : public EGLSyncImpl
egl::Error dupNativeFenceFD(const egl::Display *display, EGLint *result) const override; egl::Error dupNativeFenceFD(const egl::Display *display, EGLint *result) const override;
private: private:
FenceSyncVk mFenceSync; vk::SyncHelper mFenceSync;
}; };
} // namespace rx } // namespace rx
......
...@@ -1023,10 +1023,10 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk, ...@@ -1023,10 +1023,10 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1); gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
VkBuffer copyBufferHandle = VK_NULL_HANDLE; vk::BufferHelper *copyBuffer = nullptr;
VkDeviceSize sourceCopyOffset = 0; VkDeviceSize sourceCopyOffset = 0;
ANGLE_TRY(copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, area, &copyBufferHandle, ANGLE_TRY(copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, area, &copyBuffer,
&sourceCopyOffset, outDataPtr)); &sourceCopyOffset, outDataPtr));
// Explicitly finish. If new use cases arise where we don't want to block we can change this. // Explicitly finish. If new use cases arise where we don't want to block we can change this.
...@@ -1040,7 +1040,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -1040,7 +1040,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
uint32_t layerCount, uint32_t layerCount,
uint32_t baseLayer, uint32_t baseLayer,
const gl::Box &sourceArea, const gl::Box &sourceArea,
VkBuffer *bufferHandleOut, vk::BufferHelper **bufferOut,
VkDeviceSize *bufferOffsetOut, VkDeviceSize *bufferOffsetOut,
uint8_t **outDataPtr) uint8_t **outDataPtr)
{ {
...@@ -1058,7 +1058,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -1058,7 +1058,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
// Allocate staging buffer data // Allocate staging buffer data
ANGLE_TRY(mImage->allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr, ANGLE_TRY(mImage->allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr,
bufferHandleOut, bufferOffsetOut, nullptr)); bufferOut, bufferOffsetOut, nullptr));
VkBufferImageCopy region = {}; VkBufferImageCopy region = {};
region.bufferOffset = *bufferOffsetOut; region.bufferOffset = *bufferOffsetOut;
...@@ -1076,7 +1076,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -1076,7 +1076,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel); region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
commandBuffer->copyImageToBuffer(mImage->getImage(), mImage->getCurrentLayout(), commandBuffer->copyImageToBuffer(mImage->getImage(), mImage->getCurrentLayout(),
*bufferHandleOut, 1, &region); (*bufferOut)->getBuffer().getHandle(), 1, &region);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1244,17 +1244,17 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL ...@@ -1244,17 +1244,17 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL
} }
// Now copy from the image to the staging buffer // Now copy from the image to the staging buffer
VkBuffer stagingBufferHandle = VK_NULL_HANDLE; vk::BufferHelper *stagingBuffer = nullptr;
VkDeviceSize stagingBufferOffset = 0; VkDeviceSize stagingBufferOffset = 0;
ANGLE_TRY(copyImageDataToBuffer(contextVk, srcLevelVK, 1, layer, area, ANGLE_TRY(copyImageDataToBuffer(contextVk, srcLevelVK, 1, layer, area, &stagingBuffer,
&stagingBufferHandle, &stagingBufferOffset, nullptr)); &stagingBufferOffset, nullptr));
// Stage an update to the new image that we will populate with existing mip levels // Stage an update to the new image that we will populate with existing mip levels
// We're providing the buffer handle and offset to use, since we *just* populated it // We're providing the buffer handle and offset to use, since we *just* populated it
size_t bufferSize = extents.width * extents.height * extents.depth * info.pixelBytes; size_t bufferSize = extents.width * extents.height * extents.depth * info.pixelBytes;
ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer( ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(contextVk, bufferSize, level, layer,
contextVk, bufferSize, level, layer, 1, extents, gl::Offset(), stagingBufferHandle, 1, extents, gl::Offset(),
stagingBufferOffset)); stagingBuffer, stagingBufferOffset));
} }
} }
...@@ -1810,7 +1810,7 @@ void TextureVk::releaseImage(ContextVk *contextVk) ...@@ -1810,7 +1810,7 @@ void TextureVk::releaseImage(ContextVk *contextVk)
{ {
if (mOwnsImage) if (mOwnsImage)
{ {
mImage->releaseImage(contextVk); mImage->releaseImage(contextVk->getRenderer());
} }
else else
{ {
...@@ -1862,7 +1862,7 @@ void TextureVk::releaseStagingBuffer(ContextVk *contextVk) ...@@ -1862,7 +1862,7 @@ void TextureVk::releaseStagingBuffer(ContextVk *contextVk)
{ {
if (mImage) if (mImage)
{ {
mImage->releaseStagingBuffer(contextVk); mImage->releaseStagingBuffer(contextVk->getRenderer());
} }
} }
......
...@@ -241,10 +241,10 @@ class TextureVk : public TextureImpl ...@@ -241,10 +241,10 @@ class TextureVk : public TextureImpl
angle::Result copyImageDataToBuffer(ContextVk *contextVk, angle::Result copyImageDataToBuffer(ContextVk *contextVk,
size_t sourceLevel, size_t sourceLevel,
uint32_t layerCount, uint32_t layerCount,
uint32_t layer, uint32_t baseLayer,
const gl::Box &sourceArea, const gl::Box &sourceArea,
VkBuffer *stagingBufferHandleOut, vk::BufferHelper **bufferOut,
VkDeviceSize *stagingOffsetOut, VkDeviceSize *bufferOffsetOut,
uint8_t **outDataPtr); uint8_t **outDataPtr);
angle::Result generateMipmapsWithCPU(const gl::Context *context); angle::Result generateMipmapsWithCPU(const gl::Context *context);
......
...@@ -237,7 +237,7 @@ void TransformFeedbackVk::onBeginOrEnd(const gl::Context *context) ...@@ -237,7 +237,7 @@ void TransformFeedbackVk::onBeginOrEnd(const gl::Context *context)
FramebufferVk *framebufferVk = vk::GetImpl(context->getState().getDrawFramebuffer()); FramebufferVk *framebufferVk = vk::GetImpl(context->getState().getDrawFramebuffer());
vk::FramebufferHelper *framebuffer = framebufferVk->getFramebuffer(); vk::FramebufferHelper *framebuffer = framebufferVk->getFramebuffer();
framebuffer->onGraphAccess(contextVk->getCommandGraph()); framebuffer->updateCurrentAccessNodes();
if (framebuffer->hasStartedRenderPass()) if (framebuffer->hasStartedRenderPass())
{ {
framebuffer->finishCurrentCommands(contextVk); framebuffer->finishCurrentCommands(contextVk);
......
...@@ -1371,7 +1371,7 @@ angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk, ...@@ -1371,7 +1371,7 @@ angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk,
&descriptorPoolBinding, &descriptorSet)); &descriptorPoolBinding, &descriptorSet));
// Create a temporary buffer to blit/resolve stencil into. // Create a temporary buffer to blit/resolve stencil into.
vk::ContextScoped<vk::BufferHelper> blitBuffer(contextVk); vk::RendererScoped<vk::BufferHelper> blitBuffer(contextVk->getRenderer());
uint32_t bufferRowLengthInUints = UnsignedCeilDivide(params.blitArea.width, sizeof(uint32_t)); uint32_t bufferRowLengthInUints = UnsignedCeilDivide(params.blitArea.width, sizeof(uint32_t));
VkDeviceSize bufferSize = bufferRowLengthInUints * sizeof(uint32_t) * params.blitArea.height; VkDeviceSize bufferSize = bufferRowLengthInUints * sizeof(uint32_t) * params.blitArea.height;
......
...@@ -148,11 +148,13 @@ void VertexArrayVk::destroy(const gl::Context *context) ...@@ -148,11 +148,13 @@ void VertexArrayVk::destroy(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
mTheNullBuffer.release(contextVk); RendererVk *renderer = contextVk->getRenderer();
mTheNullBuffer.release(renderer);
mDynamicVertexData.release(contextVk); mDynamicVertexData.release(renderer);
mDynamicIndexData.release(contextVk); mDynamicIndexData.release(renderer);
mTranslatedByteIndexData.release(contextVk); mTranslatedByteIndexData.release(renderer);
mLineLoopHelper.release(contextVk); mLineLoopHelper.release(contextVk);
} }
...@@ -597,7 +599,7 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context, ...@@ -597,7 +599,7 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
gl::DrawElementsType indexTypeOrInvalid, gl::DrawElementsType indexTypeOrInvalid,
const void *indices) const void *indices)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
const gl::AttributesMask activeAttribs = const gl::AttributesMask activeAttribs =
context->getStateCache().getActiveClientAttribsMask() | context->getStateCache().getActiveClientAttribsMask() |
context->getStateCache().getActiveBufferedAttribsMask(); context->getStateCache().getActiveBufferedAttribsMask();
...@@ -631,7 +633,7 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context, ...@@ -631,7 +633,7 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
ASSERT(GetVertexInputAlignment(vertexFormat) <= vk::kVertexBufferAlignment); ASSERT(GetVertexInputAlignment(vertexFormat) <= vk::kVertexBufferAlignment);
const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer); const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer);
const uint32_t divisor = binding.getDivisor(); const uint32_t divisor = binding.getDivisor();
if (divisor > 0) if (divisor > 0)
{ {
...@@ -760,13 +762,14 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk, ...@@ -760,13 +762,14 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk, void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk,
size_t attribIndex, size_t attribIndex,
VkBuffer bufferHandle, VkBuffer bufferHandle,
vk::BufferHelper *buffer,
uint32_t offset) uint32_t offset)
{ {
if (!mState.getEnabledAttributesMask().test(attribIndex)) if (!mState.getEnabledAttributesMask().test(attribIndex))
{ {
mCurrentArrayBufferHandles[attribIndex] = bufferHandle; mCurrentArrayBufferHandles[attribIndex] = bufferHandle;
mCurrentArrayBufferOffsets[attribIndex] = offset; mCurrentArrayBufferOffsets[attribIndex] = offset;
mCurrentArrayBuffers[attribIndex] = nullptr; mCurrentArrayBuffers[attribIndex] = buffer;
setDefaultPackedInput(contextVk, attribIndex); setDefaultPackedInput(contextVk, attribIndex);
} }
......
...@@ -35,6 +35,7 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -35,6 +35,7 @@ class VertexArrayVk : public VertexArrayImpl
void updateDefaultAttrib(ContextVk *contextVk, void updateDefaultAttrib(ContextVk *contextVk,
size_t attribIndex, size_t attribIndex,
VkBuffer bufferHandle, VkBuffer bufferHandle,
vk::BufferHelper *buffer,
uint32_t offset); uint32_t offset);
angle::Result updateStreamedAttribs(const gl::Context *context, angle::Result updateStreamedAttribs(const gl::Context *context,
......
...@@ -201,13 +201,12 @@ vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const ...@@ -201,13 +201,12 @@ vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const
return mImage; return mImage;
} }
void HardwareBufferImageSiblingVkAndroid::release(DisplayVk *display, void HardwareBufferImageSiblingVkAndroid::release(RendererVk *renderer)
std::vector<vk::GarbageObject> *garbageQueue)
{ {
if (mImage != nullptr) if (mImage != nullptr)
{ {
mImage->releaseImage(display, garbageQueue); mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(display, garbageQueue); mImage->releaseStagingBuffer(renderer);
SafeDelete(mImage); SafeDelete(mImage);
} }
} }
......
...@@ -36,7 +36,7 @@ class HardwareBufferImageSiblingVkAndroid : public ExternalImageSiblingVk ...@@ -36,7 +36,7 @@ class HardwareBufferImageSiblingVkAndroid : public ExternalImageSiblingVk
// ExternalImageSiblingVk interface // ExternalImageSiblingVk interface
vk::ImageHelper *getImage() const override; vk::ImageHelper *getImage() const override;
void release(DisplayVk *display, std::vector<vk::GarbageObject> *garbageQueue) override; void release(RendererVk *renderer) override;
private: private:
angle::Result initImpl(DisplayVk *displayVk); angle::Result initImpl(DisplayVk *displayVk);
......
...@@ -82,8 +82,7 @@ class DynamicBuffer : angle::NonCopyable ...@@ -82,8 +82,7 @@ class DynamicBuffer : angle::NonCopyable
angle::Result invalidate(ContextVk *contextVk); angle::Result invalidate(ContextVk *contextVk);
// This releases resources when they might currently be in use. // This releases resources when they might currently be in use.
void release(ContextVk *contextVk); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObject> *garbageQueue);
// This releases all the buffers that have been allocated since this was last called. // This releases all the buffers that have been allocated since this was last called.
void releaseInFlightBuffers(ContextVk *contextVk); void releaseInFlightBuffers(ContextVk *contextVk);
...@@ -101,10 +100,7 @@ class DynamicBuffer : angle::NonCopyable ...@@ -101,10 +100,7 @@ class DynamicBuffer : angle::NonCopyable
private: private:
void reset(); void reset();
angle::Result allocateNewBuffer(ContextVk *contextVk); angle::Result allocateNewBuffer(ContextVk *contextVk);
void releaseBufferListToContext(ContextVk *contextVk, std::vector<BufferHelper *> *buffers); void releaseBufferListToRenderer(RendererVk *renderer, std::vector<BufferHelper *> *buffers);
void releaseBufferListToDisplay(DisplayVk *display,
std::vector<GarbageObject> *garbageQueue,
std::vector<BufferHelper *> *buffers);
void destroyBufferList(VkDevice device, std::vector<BufferHelper *> *buffers); void destroyBufferList(VkDevice device, std::vector<BufferHelper *> *buffers);
VkBufferUsageFlags mUsage; VkBufferUsageFlags mUsage;
...@@ -448,8 +444,7 @@ class BufferHelper final : public CommandGraphResource ...@@ -448,8 +444,7 @@ class BufferHelper final : public CommandGraphResource
VkMemoryPropertyFlags memoryPropertyFlags); VkMemoryPropertyFlags memoryPropertyFlags);
void destroy(VkDevice device); void destroy(VkDevice device);
void release(ContextVk *contextVk); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObject> *garbageQueue);
bool valid() const { return mBuffer.valid(); } bool valid() const { return mBuffer.valid(); }
const Buffer &getBuffer() const { return mBuffer; } const Buffer &getBuffer() const { return mBuffer; }
...@@ -707,11 +702,8 @@ class ImageHelper final : public CommandGraphResource ...@@ -707,11 +702,8 @@ class ImageHelper final : public CommandGraphResource
VkImageUsageFlags usage, VkImageUsageFlags usage,
uint32_t layerCount); uint32_t layerCount);
void releaseImage(ContextVk *contextVk); void releaseImage(RendererVk *rendererVk);
void releaseImage(DisplayVk *display, std::vector<GarbageObject> *garbageQueue); void releaseStagingBuffer(RendererVk *renderer);
void releaseStagingBuffer(ContextVk *contextVk);
void releaseStagingBuffer(DisplayVk *display, std::vector<GarbageObject> *garbageQueue);
bool valid() const { return mImage.valid(); } bool valid() const { return mImage.valid(); }
...@@ -790,7 +782,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -790,7 +782,7 @@ class ImageHelper final : public CommandGraphResource
uint32_t layerCount, uint32_t layerCount,
const gl::Extents &glExtents, const gl::Extents &glExtents,
const gl::Offset &offset, const gl::Offset &offset,
VkBuffer stagingBufferHandle, BufferHelper *stagingBuffer,
VkDeviceSize stagingOffset); VkDeviceSize stagingOffset);
angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context,
...@@ -823,7 +815,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -823,7 +815,7 @@ class ImageHelper final : public CommandGraphResource
angle::Result allocateStagingMemory(ContextVk *contextVk, angle::Result allocateStagingMemory(ContextVk *contextVk,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
VkBuffer *handleOut, BufferHelper **bufferOut,
VkDeviceSize *offsetOut, VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut); bool *newBufferAllocatedOut);
...@@ -894,16 +886,39 @@ class ImageHelper final : public CommandGraphResource ...@@ -894,16 +886,39 @@ class ImageHelper final : public CommandGraphResource
uint32_t layerCount, uint32_t layerCount,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
enum class UpdateSource
{
Clear,
Buffer,
Image,
};
struct ClearUpdate
{
VkClearValue value;
uint32_t levelIndex;
uint32_t layerIndex;
uint32_t layerCount;
};
struct BufferUpdate
{
BufferHelper *bufferHelper;
VkBufferImageCopy copyRegion;
};
struct ImageUpdate
{
ImageHelper *image;
VkImageCopy copyRegion;
};
struct SubresourceUpdate struct SubresourceUpdate
{ {
SubresourceUpdate(); SubresourceUpdate();
SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy &copyRegion); SubresourceUpdate(BufferHelper *bufferHelperIn, const VkBufferImageCopy &copyRegion);
SubresourceUpdate(ImageHelper *image, const VkImageCopy &copyRegion); SubresourceUpdate(ImageHelper *image, const VkImageCopy &copyRegion);
SubresourceUpdate(const VkClearValue &clearValue, const gl::ImageIndex &imageIndex); SubresourceUpdate(const VkClearValue &clearValue, const gl::ImageIndex &imageIndex);
SubresourceUpdate(const SubresourceUpdate &other); SubresourceUpdate(const SubresourceUpdate &other);
void release(ContextVk *contextVk); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObject> *garbageQueue);
const VkImageSubresourceLayers &dstSubresource() const const VkImageSubresourceLayers &dstSubresource() const
{ {
...@@ -913,30 +928,6 @@ class ImageHelper final : public CommandGraphResource ...@@ -913,30 +928,6 @@ class ImageHelper final : public CommandGraphResource
} }
bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const; bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const;
enum class UpdateSource
{
Clear,
Buffer,
Image,
};
struct ClearUpdate
{
VkClearValue value;
uint32_t levelIndex;
uint32_t layerIndex;
uint32_t layerCount;
};
struct BufferUpdate
{
VkBuffer bufferHandle;
VkBufferImageCopy copyRegion;
};
struct ImageUpdate
{
ImageHelper *image;
VkImageCopy copyRegion;
};
UpdateSource updateSource; UpdateSource updateSource;
union union
{ {
......
...@@ -233,6 +233,7 @@ class GarbageObject ...@@ -233,6 +233,7 @@ class GarbageObject
GarbageObject(GarbageObject &&other); GarbageObject(GarbageObject &&other);
GarbageObject &operator=(GarbageObject &&rhs); GarbageObject &operator=(GarbageObject &&rhs);
bool valid() const { return mHandle != VK_NULL_HANDLE; }
void destroy(VkDevice device); void destroy(VkDevice device);
template <typename DerivedT, typename HandleT> template <typename DerivedT, typename HandleT>
...@@ -377,6 +378,23 @@ class ContextScoped final : angle::NonCopyable ...@@ -377,6 +378,23 @@ class ContextScoped final : angle::NonCopyable
T mVar; T mVar;
}; };
template <typename T>
class RendererScoped final : angle::NonCopyable
{
public:
RendererScoped(RendererVk *renderer) : mRenderer(renderer) {}
~RendererScoped() { mVar.release(mRenderer); }
const T &get() const { return mVar; }
T &get() { return mVar; }
T &&release() { return std::move(mVar); }
private:
RendererVk *mRenderer;
T mVar;
};
// This is a very simple RefCount class that has no autoreleasing. Used in the descriptor set and // This is a very simple RefCount class that has no autoreleasing. Used in the descriptor set and
// pipeline layout caches. // pipeline layout caches.
template <typename T> template <typename T>
......
...@@ -156,6 +156,44 @@ TEST_P(LinkAndRelinkTest, RenderingProgramFailsWithProgramInstalled) ...@@ -156,6 +156,44 @@ TEST_P(LinkAndRelinkTest, RenderingProgramFailsWithProgramInstalled)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Tests uniform default values.
TEST_P(LinkAndRelinkTest, UniformDefaultValues)
{
constexpr char kFS[] = R"(precision mediump float;
uniform vec4 u_uniform;
bool isZero(vec4 value) {
return value == vec4(0,0,0,0);
}
void main()
{
gl_FragColor = isZero(u_uniform) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
glUseProgram(program);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
GLint loc = glGetUniformLocation(program, "u_uniform");
ASSERT_NE(-1, loc);
glUniform4f(loc, 0.1f, 0.2f, 0.3f, 0.4f);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glLinkProgram(program);
ASSERT_GL_NO_ERROR();
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// When program link fails and no valid compute program is installed in the GL // When program link fails and no valid compute program is installed in the GL
// state before the link, it should report an error for UseProgram and // state before the link, it should report an error for UseProgram and
// DispatchCompute. // DispatchCompute.
......
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