Vulkan: Add a new garbage type gated by fences.

This allows Vulkan EGL objects such as EGL Syncs and EGL Images to give their
garbage to the renderer before destroying.

BUG=angleproject:2464

Change-Id: I59b8e1080e4292bd0856e59a928750c7e77a372e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1562522
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Geoff Lang 2019-04-10 09:58:21 -04:00 коммит произвёл Commit Bot
Родитель d7d42395ac
Коммит e755a5374f
13 изменённых файлов: 274 добавлений и 39 удалений

Просмотреть файл

@ -32,13 +32,34 @@ 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::GarbageObjectBase> garbage;
if (mImage != nullptr && mOwnsImage) if (mImage != nullptr && mOwnsImage)
{ {
mImage->releaseImage(renderer); mImage->releaseImage(displayVk, &garbage);
mImage->releaseStagingBuffer(renderer); mImage->releaseStagingBuffer(displayVk, &garbage);
delete mImage; delete mImage;
} }
else if (egl::IsExternalImageTarget(mState.target))
{
ASSERT(mState.source != nullptr);
ExternalImageSiblingVk *externalImageSibling =
GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
externalImageSibling->release(displayVk, &garbage);
}
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());
}
}
} }
egl::Error ImageVk::initialize(const egl::Display *display) egl::Error ImageVk::initialize(const egl::Display *display)
@ -129,6 +150,19 @@ angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sib
} }
} }
// Grab a fence from the releasing context to know when the image is no longer used
ASSERT(mContext != nullptr);
ContextVk *contextVk = vk::GetImpl(mContext);
// Flush the context to make sure the fence has been submitted.
ANGLE_TRY(contextVk->flushImpl());
vk::Shared<vk::Fence> fence = contextVk->getRenderer()->getLastSubmittedFence();
if (fence.isReferenced())
{
mImageLastUseFences.push_back(std::move(fence));
}
return angle::Result::Continue; return angle::Result::Continue;
} }

Просмотреть файл

@ -23,6 +23,8 @@ class ExternalImageSiblingVk : public ExternalImageSiblingImpl
~ExternalImageSiblingVk() override {} ~ExternalImageSiblingVk() override {}
virtual vk::ImageHelper *getImage() const = 0; virtual vk::ImageHelper *getImage() const = 0;
virtual void release(DisplayVk *display, std::vector<vk::GarbageObjectBase> *garbageQueue) = 0;
}; };
class ImageVk : public ImageImpl class ImageVk : public ImageImpl
@ -49,6 +51,8 @@ class ImageVk : public ImageImpl
bool mOwnsImage; bool mOwnsImage;
vk::ImageHelper *mImage; vk::ImageHelper *mImage;
std::vector<vk::Shared<vk::Fence>> mImageLastUseFences;
const gl::Context *mContext; const gl::Context *mContext;
}; };

Просмотреть файл

@ -486,6 +486,30 @@ void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
} }
} }
angle::Result WaitFences(vk::Context *context,
std::vector<vk::Shared<vk::Fence>> *fences,
bool block)
{
uint64_t timeout = block ? kMaxFenceWaitTimeNs : 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);
fences->back().reset(context->getDevice());
fences->pop_back();
}
return angle::Result::Continue;
}
// Initially dumping the command graphs is disabled. // Initially dumping the command graphs is disabled.
constexpr bool kEnableCommandGraphDiagnostics = false; constexpr bool kEnableCommandGraphDiagnostics = false;
@ -544,11 +568,15 @@ RendererVk::RendererVk()
mFormatProperties.fill(invalid); mFormatProperties.fill(invalid);
} }
RendererVk::~RendererVk() {} RendererVk::~RendererVk()
{
ASSERT(mGarbage.empty());
ASSERT(mFencedGarbage.empty());
}
void RendererVk::onDestroy(vk::Context *context) void RendererVk::onDestroy(vk::Context *context)
{ {
if (!mInFlightCommands.empty() || !mGarbage.empty()) if (!mInFlightCommands.empty() || !mGarbage.empty() || !mFencedGarbage.empty())
{ {
// TODO(jmadill): Not nice to pass nullptr here, but shouldn't be a problem. // TODO(jmadill): Not nice to pass nullptr here, but shouldn't be a problem.
(void)finish(context, nullptr, nullptr); (void)finish(context, nullptr, nullptr);
@ -1392,6 +1420,9 @@ angle::Result RendererVk::finish(vk::Context *context,
ANGLE_VK_TRY(context, vkQueueWaitIdle(mQueue)); ANGLE_VK_TRY(context, vkQueueWaitIdle(mQueue));
freeAllInFlightResources(); freeAllInFlightResources();
ANGLE_TRY(cleanupFencedGarbage(context, true));
ASSERT(mFencedGarbage.empty());
if (mGpuEventsEnabled) if (mGpuEventsEnabled)
{ {
// This loop should in practice execute once since the queue is already idle. // This loop should in practice execute once since the queue is already idle.
@ -1473,6 +1504,8 @@ angle::Result RendererVk::checkCompletedCommands(vk::Context *context)
mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex); mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
} }
ANGLE_TRY(cleanupFencedGarbage(context, false));
return angle::Result::Continue; return angle::Result::Continue;
} }
@ -2204,6 +2237,20 @@ void RendererVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpu
mGpuEvents.clear(); mGpuEvents.clear();
} }
void RendererVk::addGarbage(vk::Shared<vk::Fence> &&fence,
std::vector<vk::GarbageObjectBase> &&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::GarbageObjectBase> &&garbage)
{
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)
@ -2234,6 +2281,29 @@ bool RendererVk::hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlag
return IsMaskFlagSet(getFormatFeatureBits<features>(format, featureBits), featureBits); return IsMaskFlagSet(getFormatFeatureBits<features>(format, featureBits), featureBits);
} }
angle::Result RendererVk::cleanupFencedGarbage(vk::Context *context, bool block)
{
auto garbageIter = mFencedGarbage.begin();
while (garbageIter != mFencedGarbage.end())
{
ANGLE_TRY(WaitFences(context, &garbageIter->first, block));
if (garbageIter->first.empty())
{
for (vk::GarbageObjectBase &garbageObject : garbageIter->second)
{
garbageObject.destroy(mDevice);
}
garbageIter = mFencedGarbage.erase(garbageIter);
}
else
{
garbageIter++;
}
}
return angle::Result::Continue;
}
uint32_t GetUniformBufferDescriptorCount() uint32_t GetUniformBufferDescriptorCount()
{ {
return kUniformBufferDescriptorsPerDescriptorSet; return kUniformBufferDescriptorsPerDescriptorSet;

Просмотреть файл

@ -213,6 +213,10 @@ class RendererVk : angle::NonCopyable
void pushDebugMarker(GLenum source, GLuint id, std::string &&marker); void pushDebugMarker(GLenum source, GLuint id, std::string &&marker);
void popDebugMarker(); void popDebugMarker();
void addGarbage(vk::Shared<vk::Fence> &&fence, std::vector<vk::GarbageObjectBase> &&garbage);
void addGarbage(std::vector<vk::Shared<vk::Fence>> &&fences,
std::vector<vk::GarbageObjectBase> &&garbage);
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>;
@ -254,6 +258,8 @@ class RendererVk : angle::NonCopyable
void nextSerial(); void nextSerial();
angle::Result cleanupFencedGarbage(vk::Context *context, bool block);
egl::Display *mDisplay; egl::Display *mDisplay;
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
@ -302,6 +308,11 @@ class RendererVk : angle::NonCopyable
std::vector<CommandBatch> mInFlightCommands; std::vector<CommandBatch> mInFlightCommands;
std::vector<vk::GarbageObject> mGarbage; std::vector<vk::GarbageObject> mGarbage;
using FencedGarbage =
std::pair<std::vector<vk::Shared<vk::Fence>>, std::vector<vk::GarbageObjectBase>>;
std::vector<FencedGarbage> mFencedGarbage;
vk::MemoryProperties mMemoryProperties; vk::MemoryProperties mMemoryProperties;
vk::FormatTable mFormatTable; vk::FormatTable mFormatTable;

Просмотреть файл

@ -31,6 +31,14 @@ void FenceSyncVk::onDestroy(RendererVk *renderer)
mFence.reset(renderer->getDevice()); mFence.reset(renderer->getDevice());
} }
void FenceSyncVk::onDestroy(DisplayVk *display)
{
std::vector<vk::GarbageObjectBase> garbage;
mEvent.dumpResources(&garbage);
display->getRenderer()->addGarbage(std::move(mFence), std::move(garbage));
}
angle::Result FenceSyncVk::initialize(ContextVk *contextVk) angle::Result FenceSyncVk::initialize(ContextVk *contextVk)
{ {
ASSERT(!mEvent.valid()); ASSERT(!mEvent.valid());

Просмотреть файл

@ -31,6 +31,7 @@ class FenceSyncVk
~FenceSyncVk(); ~FenceSyncVk();
void onDestroy(RendererVk *renderer); void onDestroy(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(vk::Context *context,

Просмотреть файл

@ -164,15 +164,7 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display) void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display)
{ {
DisplayVk *displayVk = vk::GetImpl(display); ASSERT(mImage == nullptr);
RendererVk *renderer = displayVk->getRenderer();
if (mImage != nullptr)
{
mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(renderer);
SafeDelete(mImage);
}
} }
gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const
@ -205,4 +197,16 @@ vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const
{ {
return mImage; return mImage;
} }
void HardwareBufferImageSiblingVkAndroid::release(DisplayVk *display,
std::vector<vk::GarbageObjectBase> *garbageQueue)
{
if (mImage != nullptr)
{
mImage->releaseImage(display, garbageQueue);
mImage->releaseStagingBuffer(display, garbageQueue);
SafeDelete(mImage);
}
}
} // namespace rx } // namespace rx

Просмотреть файл

@ -36,6 +36,8 @@ 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::GarbageObjectBase> *garbageQueue) override;
private: private:
angle::Result initImpl(DisplayVk *displayVk); angle::Result initImpl(DisplayVk *displayVk);

Просмотреть файл

@ -12,6 +12,7 @@
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/BufferVk.h" #include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h" #include "libANGLE/renderer/vulkan/vk_utils.h"
@ -375,6 +376,21 @@ void DynamicBuffer::release(RendererVk *renderer)
} }
} }
void DynamicBuffer::release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
{
reset();
releaseRetainedBuffers(display, garbageQueue);
if (mBuffer)
{
mBuffer->unmap(display->getDevice());
mBuffer->release(display, garbageQueue);
delete mBuffer;
mBuffer = nullptr;
}
}
void DynamicBuffer::releaseRetainedBuffers(RendererVk *renderer) void DynamicBuffer::releaseRetainedBuffers(RendererVk *renderer)
{ {
for (BufferHelper *toFree : mRetainedBuffers) for (BufferHelper *toFree : mRetainedBuffers)
@ -388,6 +404,18 @@ void DynamicBuffer::releaseRetainedBuffers(RendererVk *renderer)
mRetainedBuffers.clear(); mRetainedBuffers.clear();
} }
void DynamicBuffer::releaseRetainedBuffers(DisplayVk *display,
std::vector<GarbageObjectBase> *garbageQueue)
{
for (BufferHelper *toFree : mRetainedBuffers)
{
toFree->release(display, garbageQueue);
delete toFree;
}
mRetainedBuffers.clear();
}
void DynamicBuffer::destroy(VkDevice device) void DynamicBuffer::destroy(VkDevice device)
{ {
reset(); reset();
@ -1120,6 +1148,17 @@ void BufferHelper::release(RendererVk *renderer)
renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory); renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory);
} }
void BufferHelper::release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
{
unmap(display->getDevice());
mSize = 0;
mViewFormat = nullptr;
mBuffer.dumpResources(garbageQueue);
mBufferView.dumpResources(garbageQueue);
mDeviceMemory.dumpResources(garbageQueue);
}
void BufferHelper::onWrite(VkAccessFlagBits writeAccessType) void BufferHelper::onWrite(VkAccessFlagBits writeAccessType)
{ {
if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0) if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
@ -1351,6 +1390,12 @@ void ImageHelper::releaseImage(RendererVk *renderer)
renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory); renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory);
} }
void ImageHelper::releaseImage(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
{
mImage.dumpResources(garbageQueue);
mDeviceMemory.dumpResources(garbageQueue);
}
void ImageHelper::releaseStagingBuffer(RendererVk *renderer) void ImageHelper::releaseStagingBuffer(RendererVk *renderer)
{ {
// Remove updates that never made it to the texture. // Remove updates that never made it to the texture.
@ -1362,6 +1407,18 @@ void ImageHelper::releaseStagingBuffer(RendererVk *renderer)
mSubresourceUpdates.clear(); mSubresourceUpdates.clear();
} }
void ImageHelper::releaseStagingBuffer(DisplayVk *display,
std::vector<GarbageObjectBase> *garbageQueue)
{
// Remove updates that never made it to the texture.
for (SubresourceUpdate &update : mSubresourceUpdates)
{
update.release(display, garbageQueue);
}
mStagingBuffer.release(display, garbageQueue);
mSubresourceUpdates.clear();
}
void ImageHelper::resetImageWeakReference() void ImageHelper::resetImageWeakReference()
{ {
mImage.reset(); mImage.reset();
@ -2269,6 +2326,17 @@ void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
} }
} }
void ImageHelper::SubresourceUpdate::release(DisplayVk *display,
std::vector<GarbageObjectBase> *garbageQueue)
{
if (updateSource == UpdateSource::Image)
{
image.image->releaseImage(display, garbageQueue);
image.image->releaseStagingBuffer(display, garbageQueue);
SafeDelete(image.image);
}
}
bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex, bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex,
uint32_t levelIndex) const uint32_t levelIndex) const
{ {

Просмотреть файл

@ -58,9 +58,11 @@ class DynamicBuffer : angle::NonCopyable
// This releases resources when they might currently be in use. // This releases resources when they might currently be in use.
void release(RendererVk *renderer); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObjectBase> *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 releaseRetainedBuffers(RendererVk *renderer); void releaseRetainedBuffers(RendererVk *renderer);
void releaseRetainedBuffers(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
// This frees resources immediately. // This frees resources immediately.
void destroy(VkDevice device); void destroy(VkDevice device);
@ -397,7 +399,9 @@ class BufferHelper final : public CommandGraphResource
const VkBufferCreateInfo &createInfo, const VkBufferCreateInfo &createInfo,
VkMemoryPropertyFlags memoryPropertyFlags); VkMemoryPropertyFlags memoryPropertyFlags);
void destroy(VkDevice device); void destroy(VkDevice device);
void release(RendererVk *renderer); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObjectBase> *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; }
@ -585,7 +589,10 @@ class ImageHelper final : public CommandGraphResource
uint32_t layerCount); uint32_t layerCount);
void releaseImage(RendererVk *renderer); void releaseImage(RendererVk *renderer);
void releaseImage(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
void releaseStagingBuffer(RendererVk *renderer); void releaseStagingBuffer(RendererVk *renderer);
void releaseStagingBuffer(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
bool valid() const { return mImage.valid(); } bool valid() const { return mImage.valid(); }
@ -756,6 +763,7 @@ class ImageHelper final : public CommandGraphResource
SubresourceUpdate(const SubresourceUpdate &other); SubresourceUpdate(const SubresourceUpdate &other);
void release(RendererVk *renderer); void release(RendererVk *renderer);
void release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue);
const VkImageSubresourceLayers &dstSubresource() const const VkImageSubresourceLayers &dstSubresource() const
{ {

Просмотреть файл

@ -415,27 +415,11 @@ angle::Result InitShaderAndSerial(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
// GarbageObject implementation. GarbageObjectBase::GarbageObjectBase() : mHandleType(HandleType::Invalid), mHandle(VK_NULL_HANDLE)
GarbageObject::GarbageObject()
: mSerial(), mHandleType(HandleType::Invalid), mHandle(VK_NULL_HANDLE)
{} {}
GarbageObject::GarbageObject(const GarbageObject &other) = default; // GarbageObjectBase implementation
void GarbageObjectBase::destroy(VkDevice device)
GarbageObject &GarbageObject::operator=(const GarbageObject &other) = default;
bool GarbageObject::destroyIfComplete(VkDevice device, Serial completedSerial)
{
if (completedSerial >= mSerial)
{
destroy(device);
return true;
}
return false;
}
void GarbageObject::destroy(VkDevice device)
{ {
switch (mHandleType) switch (mHandleType)
{ {
@ -503,6 +487,25 @@ void GarbageObject::destroy(VkDevice device)
break; break;
} }
} }
// GarbageObject implementation.
GarbageObject::GarbageObject() : mSerial() {}
GarbageObject::GarbageObject(const GarbageObject &other) = default;
GarbageObject &GarbageObject::operator=(const GarbageObject &other) = default;
bool GarbageObject::destroyIfComplete(VkDevice device, Serial completedSerial)
{
if (completedSerial >= mSerial)
{
destroy(device);
return true;
}
return false;
}
} // namespace vk } // namespace vk
// VK_EXT_debug_utils // VK_EXT_debug_utils

Просмотреть файл

@ -163,30 +163,41 @@ GetImplType<T> *GetImpl(const T *glObject)
return GetImplAs<GetImplType<T>>(glObject); return GetImplAs<GetImplType<T>>(glObject);
} }
class GarbageObject final class GarbageObjectBase
{ {
public: public:
template <typename ObjectT> template <typename ObjectT>
GarbageObject(Serial serial, const ObjectT &object) GarbageObjectBase(const ObjectT &object)
: mSerial(serial), : mHandleType(HandleTypeHelper<ObjectT>::kHandleType),
mHandleType(HandleTypeHelper<ObjectT>::kHandleType),
mHandle(reinterpret_cast<VkDevice>(object.getHandle())) mHandle(reinterpret_cast<VkDevice>(object.getHandle()))
{} {}
GarbageObjectBase();
void destroy(VkDevice device);
private:
HandleType mHandleType;
VkDevice mHandle;
};
class GarbageObject final : public GarbageObjectBase
{
public:
template <typename ObjectT>
GarbageObject(Serial serial, const ObjectT &object) : GarbageObjectBase(object), mSerial(serial)
{}
GarbageObject(); GarbageObject();
GarbageObject(const GarbageObject &other); GarbageObject(const GarbageObject &other);
GarbageObject &operator=(const GarbageObject &other); GarbageObject &operator=(const GarbageObject &other);
bool destroyIfComplete(VkDevice device, Serial completedSerial); bool destroyIfComplete(VkDevice device, Serial completedSerial);
void destroy(VkDevice device);
private: private:
// TODO(jmadill): Since many objects will have the same serial, it might be more efficient to // TODO(jmadill): Since many objects will have the same serial, it might be more efficient to
// store the serial outside of the garbage object itself. We could index ranges of garbage // store the serial outside of the garbage object itself. We could index ranges of garbage
// objects in the Renderer, using a circular buffer. // objects in the Renderer, using a circular buffer.
Serial mSerial; Serial mSerial;
HandleType mHandleType;
VkDevice mHandle;
}; };
class MemoryProperties final : angle::NonCopyable class MemoryProperties final : angle::NonCopyable
@ -465,6 +476,7 @@ class Shared final : angle::NonCopyable
private: private:
RefCounted<T> *mRefCounted; RefCounted<T> *mRefCounted;
}; };
} // namespace vk } // namespace vk
// List of function pointers for used extensions. // List of function pointers for used extensions.

Просмотреть файл

@ -39,6 +39,16 @@ class WrappedObject : angle::NonCopyable
} }
} }
template <typename ResourceOutType>
void dumpResources(std::vector<ResourceOutType> *outQueue)
{
if (valid())
{
outQueue->emplace_back(*static_cast<DerivedT *>(this));
mHandle = VK_NULL_HANDLE;
}
}
protected: protected:
WrappedObject() : mHandle(VK_NULL_HANDLE) {} WrappedObject() : mHandle(VK_NULL_HANDLE) {}
~WrappedObject() { ASSERT(!valid()); } ~WrappedObject() { ASSERT(!valid()); }