Let DeviceBase know about Completed and LastSubmitted command Serials
This is needed to implement the timeline fence signal tracker in the frontend Bug: dawn:26 Change-Id: Id6eb2afb81385de5093b57c5cb23ace93c8aab1b Reviewed-on: https://dawn-review.googlesource.com/c/2741 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
179db44c25
commit
8b07e43dad
|
@ -15,6 +15,7 @@
|
||||||
#ifndef DAWNNATIVE_DEVICEBASE_H_
|
#ifndef DAWNNATIVE_DEVICEBASE_H_
|
||||||
#define DAWNNATIVE_DEVICEBASE_H_
|
#define DAWNNATIVE_DEVICEBASE_H_
|
||||||
|
|
||||||
|
#include "common/Serial.h"
|
||||||
#include "dawn_native/Error.h"
|
#include "dawn_native/Error.h"
|
||||||
#include "dawn_native/Forward.h"
|
#include "dawn_native/Forward.h"
|
||||||
#include "dawn_native/ObjectBase.h"
|
#include "dawn_native/ObjectBase.h"
|
||||||
|
@ -58,6 +59,8 @@ namespace dawn_native {
|
||||||
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
|
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
|
||||||
virtual SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) = 0;
|
virtual SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) = 0;
|
||||||
|
|
||||||
|
virtual Serial GetCompletedCommandSerial() const = 0;
|
||||||
|
virtual Serial GetLastSubmittedCommandSerial() const = 0;
|
||||||
virtual void TickImpl() = 0;
|
virtual void TickImpl() = 0;
|
||||||
|
|
||||||
// Many Dawn objects are completely immutable once created which means that if two
|
// Many Dawn objects are completely immutable once created which means that if two
|
||||||
|
@ -99,6 +102,7 @@ namespace dawn_native {
|
||||||
const TextureViewDescriptor* descriptor);
|
const TextureViewDescriptor* descriptor);
|
||||||
|
|
||||||
void Tick();
|
void Tick();
|
||||||
|
|
||||||
void SetErrorCallback(dawn::DeviceErrorCallback callback, dawn::CallbackUserdata userdata);
|
void SetErrorCallback(dawn::DeviceErrorCallback callback, dawn::CallbackUserdata userdata);
|
||||||
void Reference();
|
void Reference();
|
||||||
void Release();
|
void Release();
|
||||||
|
|
|
@ -237,7 +237,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
request.data = data;
|
request.data = data;
|
||||||
request.isWrite = isWrite;
|
request.isWrite = isWrite;
|
||||||
|
|
||||||
mInflightRequests.Enqueue(std::move(request), mDevice->GetSerial());
|
mInflightRequests.Enqueue(std::move(request), mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapRequestTracker::Tick(Serial finishedSerial) {
|
void MapRequestTracker::Tick(Serial finishedSerial) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// Enqueue the command allocator. It will be scheduled for reset after the next
|
// Enqueue the command allocator. It will be scheduled for reset after the next
|
||||||
// ExecuteCommandLists
|
// ExecuteCommandLists
|
||||||
mInFlightCommandAllocators.Enqueue({mCommandAllocators[firstFreeIndex], firstFreeIndex},
|
mInFlightCommandAllocators.Enqueue({mCommandAllocators[firstFreeIndex], firstFreeIndex},
|
||||||
device->GetSerial());
|
device->GetPendingCommandSerial());
|
||||||
|
|
||||||
return mCommandAllocators[firstFreeIndex];
|
return mCommandAllocators[firstFreeIndex];
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
// Descriptors don't need to be recorded if they have already been recorded in
|
// Descriptors don't need to be recorded if they have already been recorded in
|
||||||
// the heap. Indices are only updated when descriptors are recorded
|
// the heap. Indices are only updated when descriptors are recorded
|
||||||
const uint64_t serial = device->GetSerial();
|
const uint64_t serial = device->GetPendingCommandSerial();
|
||||||
if (group->GetHeapSerial() != serial ||
|
if (group->GetHeapSerial() != serial ||
|
||||||
group->GetIndexInSubmit() != indexInSubmit) {
|
group->GetIndexInSubmit() != indexInSubmit) {
|
||||||
group->RecordDescriptors(cbvSrvUavCPUDescriptorHeap, &cbvSrvUavDescriptorIndex,
|
group->RecordDescriptors(cbvSrvUavCPUDescriptorHeap, &cbvSrvUavDescriptorIndex,
|
||||||
|
|
|
@ -127,6 +127,6 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorHeapAllocator::Release(DescriptorHeapHandle handle) {
|
void DescriptorHeapAllocator::Release(DescriptorHeapHandle handle) {
|
||||||
mReleasedHandles.Enqueue(handle, mDevice->GetSerial());
|
mReleasedHandles.Enqueue(handle, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
}} // namespace dawn_native::d3d12
|
}} // namespace dawn_native::d3d12
|
||||||
|
|
|
@ -144,8 +144,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
ASSERT_SUCCESS(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
|
ASSERT_SUCCESS(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
|
||||||
|
|
||||||
ASSERT_SUCCESS(
|
ASSERT_SUCCESS(mD3d12Device->CreateFence(mLastSubmittedSerial, D3D12_FENCE_FLAG_NONE,
|
||||||
mD3d12Device->CreateFence(mSerial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)));
|
IID_PPV_ARGS(&mFence)));
|
||||||
mFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
mFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
ASSERT(mFenceEvent != nullptr);
|
ASSERT(mFenceEvent != nullptr);
|
||||||
|
|
||||||
|
@ -160,9 +160,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device() {
|
Device::~Device() {
|
||||||
const uint64_t currentSerial = GetSerial();
|
|
||||||
NextSerial();
|
NextSerial();
|
||||||
WaitForSerial(currentSerial); // Wait for all in-flight commands to finish executing
|
WaitForSerial(mLastSubmittedSerial); // Wait for all in-flight commands to finish executing
|
||||||
TickImpl(); // Call tick one last time so resources are cleaned up
|
TickImpl(); // Call tick one last time so resources are cleaned up
|
||||||
|
|
||||||
ASSERT(mUsedComObjectRefs.Empty());
|
ASSERT(mUsedComObjectRefs.Empty());
|
||||||
|
@ -224,14 +223,26 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return mPendingCommands.commandList;
|
return mPendingCommands.commandList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial Device::GetCompletedCommandSerial() const {
|
||||||
|
return mCompletedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetLastSubmittedCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetPendingCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial + 1;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::TickImpl() {
|
void Device::TickImpl() {
|
||||||
// Perform cleanup operations to free unused objects
|
// Perform cleanup operations to free unused objects
|
||||||
const uint64_t lastCompletedSerial = mFence->GetCompletedValue();
|
mCompletedSerial = mFence->GetCompletedValue();
|
||||||
mResourceAllocator->Tick(lastCompletedSerial);
|
mResourceAllocator->Tick(mCompletedSerial);
|
||||||
mCommandAllocatorManager->Tick(lastCompletedSerial);
|
mCommandAllocatorManager->Tick(mCompletedSerial);
|
||||||
mDescriptorHeapAllocator->Tick(lastCompletedSerial);
|
mDescriptorHeapAllocator->Tick(mCompletedSerial);
|
||||||
mMapRequestTracker->Tick(lastCompletedSerial);
|
mMapRequestTracker->Tick(mCompletedSerial);
|
||||||
mUsedComObjectRefs.ClearUpTo(lastCompletedSerial);
|
mUsedComObjectRefs.ClearUpTo(mCompletedSerial);
|
||||||
ExecuteCommandLists({});
|
ExecuteCommandLists({});
|
||||||
NextSerial();
|
NextSerial();
|
||||||
}
|
}
|
||||||
|
@ -240,24 +251,21 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return mPCIInfo;
|
return mPCIInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Device::GetSerial() const {
|
|
||||||
return mSerial;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::NextSerial() {
|
void Device::NextSerial() {
|
||||||
ASSERT_SUCCESS(mCommandQueue->Signal(mFence.Get(), mSerial++));
|
mLastSubmittedSerial++;
|
||||||
|
ASSERT_SUCCESS(mCommandQueue->Signal(mFence.Get(), mLastSubmittedSerial));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::WaitForSerial(uint64_t serial) {
|
void Device::WaitForSerial(uint64_t serial) {
|
||||||
const uint64_t lastCompletedSerial = mFence->GetCompletedValue();
|
mCompletedSerial = mFence->GetCompletedValue();
|
||||||
if (lastCompletedSerial < serial) {
|
if (mCompletedSerial < serial) {
|
||||||
ASSERT_SUCCESS(mFence->SetEventOnCompletion(serial, mFenceEvent));
|
ASSERT_SUCCESS(mFence->SetEventOnCompletion(serial, mFenceEvent));
|
||||||
WaitForSingleObject(mFenceEvent, INFINITE);
|
WaitForSingleObject(mFenceEvent, INFINITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::ReferenceUntilUnused(ComPtr<IUnknown> object) {
|
void Device::ReferenceUntilUnused(ComPtr<IUnknown> object) {
|
||||||
mUsedComObjectRefs.Enqueue(object, mSerial);
|
mUsedComObjectRefs.Enqueue(object, GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists) {
|
void Device::ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists) {
|
||||||
|
|
|
@ -52,6 +52,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||||
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
||||||
|
|
||||||
|
Serial GetCompletedCommandSerial() const final override;
|
||||||
|
Serial GetLastSubmittedCommandSerial() const final override;
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||||
|
@ -68,10 +70,10 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
|
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||||
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
||||||
|
Serial GetPendingCommandSerial() const;
|
||||||
|
|
||||||
uint64_t GetSerial() const;
|
|
||||||
void NextSerial();
|
void NextSerial();
|
||||||
void WaitForSerial(uint64_t serial);
|
void WaitForSerial(Serial serial);
|
||||||
|
|
||||||
void ReferenceUntilUnused(ComPtr<IUnknown> object);
|
void ReferenceUntilUnused(ComPtr<IUnknown> object);
|
||||||
|
|
||||||
|
@ -99,7 +101,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// D3D12 DLLs are unloaded before we are done using it.
|
// D3D12 DLLs are unloaded before we are done using it.
|
||||||
std::unique_ptr<PlatformFunctions> mFunctions;
|
std::unique_ptr<PlatformFunctions> mFunctions;
|
||||||
|
|
||||||
uint64_t mSerial = 0;
|
Serial mCompletedSerial = 0;
|
||||||
|
Serial mLastSubmittedSerial = 0;
|
||||||
ComPtr<ID3D12Fence> mFence;
|
ComPtr<ID3D12Fence> mFence;
|
||||||
HANDLE mFenceEvent;
|
HANDLE mFenceEvent;
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// TODO(cwallez@chromium.org): Make the serial ticking implicit.
|
// TODO(cwallez@chromium.org): Make the serial ticking implicit.
|
||||||
mDevice->NextSerial();
|
mDevice->NextSerial();
|
||||||
|
|
||||||
mBufferSerials[mCurrentBuffer] = mDevice->GetSerial();
|
mBufferSerials[mCurrentBuffer] = mDevice->GetPendingCommandSerial();
|
||||||
return DAWN_SWAP_CHAIN_NO_ERROR;
|
return DAWN_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
void ResourceAllocator::Release(ComPtr<ID3D12Resource> resource) {
|
void ResourceAllocator::Release(ComPtr<ID3D12Resource> resource) {
|
||||||
// Resources may still be in use on the GPU. Enqueue them so that we hold onto them until
|
// Resources may still be in use on the GPU. Enqueue them so that we hold onto them until
|
||||||
// GPU execution has completed
|
// GPU execution has completed
|
||||||
mReleasedResources.Enqueue(resource, mDevice->GetSerial());
|
mReleasedResources.Enqueue(resource, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceAllocator::Tick(uint64_t lastCompletedSerial) {
|
void ResourceAllocator::Tick(uint64_t lastCompletedSerial) {
|
||||||
|
|
|
@ -48,6 +48,8 @@ namespace dawn_native { namespace metal {
|
||||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||||
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
||||||
|
|
||||||
|
Serial GetCompletedCommandSerial() const final override;
|
||||||
|
Serial GetLastSubmittedCommandSerial() const final override;
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||||
|
@ -55,8 +57,8 @@ namespace dawn_native { namespace metal {
|
||||||
id<MTLDevice> GetMTLDevice();
|
id<MTLDevice> GetMTLDevice();
|
||||||
|
|
||||||
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
||||||
|
Serial GetPendingCommandSerial() const;
|
||||||
void SubmitPendingCommandBuffer();
|
void SubmitPendingCommandBuffer();
|
||||||
Serial GetPendingCommandSerial();
|
|
||||||
|
|
||||||
MapRequestTracker* GetMapTracker() const;
|
MapRequestTracker* GetMapTracker() const;
|
||||||
ResourceUploader* GetResourceUploader() const;
|
ResourceUploader* GetResourceUploader() const;
|
||||||
|
@ -86,8 +88,8 @@ namespace dawn_native { namespace metal {
|
||||||
std::unique_ptr<MapRequestTracker> mMapTracker;
|
std::unique_ptr<MapRequestTracker> mMapTracker;
|
||||||
std::unique_ptr<ResourceUploader> mResourceUploader;
|
std::unique_ptr<ResourceUploader> mResourceUploader;
|
||||||
|
|
||||||
Serial mFinishedCommandSerial = 0;
|
Serial mCompletedSerial = 0;
|
||||||
Serial mPendingCommandSerial = 1;
|
Serial mLastSubmittedSerial = 0;
|
||||||
id<MTLCommandBuffer> mPendingCommands = nil;
|
id<MTLCommandBuffer> mPendingCommands = nil;
|
||||||
|
|
||||||
dawn_native::PCIInfo mPCIInfo;
|
dawn_native::PCIInfo mPCIInfo;
|
||||||
|
|
|
@ -144,7 +144,7 @@ namespace dawn_native { namespace metal {
|
||||||
// store the pendingSerial before SubmitPendingCommandBuffer then wait for it to be passed.
|
// store the pendingSerial before SubmitPendingCommandBuffer then wait for it to be passed.
|
||||||
// Instead we submit and wait for the serial before the next pendingCommandSerial.
|
// Instead we submit and wait for the serial before the next pendingCommandSerial.
|
||||||
SubmitPendingCommandBuffer();
|
SubmitPendingCommandBuffer();
|
||||||
while (mFinishedCommandSerial != mPendingCommandSerial - 1) {
|
while (mCompletedSerial != mLastSubmittedSerial) {
|
||||||
usleep(100);
|
usleep(100);
|
||||||
}
|
}
|
||||||
Tick();
|
Tick();
|
||||||
|
@ -224,13 +224,30 @@ namespace dawn_native { namespace metal {
|
||||||
return new TextureView(texture, descriptor);
|
return new TextureView(texture, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::TickImpl() {
|
Serial Device::GetCompletedCommandSerial() const {
|
||||||
mResourceUploader->Tick(mFinishedCommandSerial);
|
return mCompletedSerial;
|
||||||
mMapTracker->Tick(mFinishedCommandSerial);
|
}
|
||||||
|
|
||||||
// Code above might have added GPU work, submit it. This also makes sure
|
Serial Device::GetLastSubmittedCommandSerial() const {
|
||||||
// that even when no GPU work is happening, the serial number keeps incrementing.
|
return mLastSubmittedSerial;
|
||||||
SubmitPendingCommandBuffer();
|
}
|
||||||
|
|
||||||
|
Serial Device::GetPendingCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::TickImpl() {
|
||||||
|
mResourceUploader->Tick(mCompletedSerial);
|
||||||
|
mMapTracker->Tick(mCompletedSerial);
|
||||||
|
|
||||||
|
if (mPendingCommands != nil) {
|
||||||
|
SubmitPendingCommandBuffer();
|
||||||
|
} else if (mCompletedSerial == mLastSubmittedSerial) {
|
||||||
|
// If there's no GPU work in flight we still need to artificially increment the serial
|
||||||
|
// so that CPU operations waiting on GPU completion can know they don't have to wait.
|
||||||
|
mCompletedSerial++;
|
||||||
|
mLastSubmittedSerial++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dawn_native::PCIInfo& Device::GetPCIInfo() const {
|
const dawn_native::PCIInfo& Device::GetPCIInfo() const {
|
||||||
|
@ -258,24 +275,15 @@ namespace dawn_native { namespace metal {
|
||||||
// so this-> works as expected. However it is unclear how members are captured, (are they
|
// so this-> works as expected. However it is unclear how members are captured, (are they
|
||||||
// captured using this-> or by value?) so we make a copy of the pendingCommandSerial on the
|
// captured using this-> or by value?) so we make a copy of the pendingCommandSerial on the
|
||||||
// stack.
|
// stack.
|
||||||
Serial pendingSerial = mPendingCommandSerial;
|
mLastSubmittedSerial++;
|
||||||
|
Serial pendingSerial = mLastSubmittedSerial;
|
||||||
[mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
[mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
||||||
this->mFinishedCommandSerial = pendingSerial;
|
this->mCompletedSerial = pendingSerial;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[mPendingCommands commit];
|
[mPendingCommands commit];
|
||||||
[mPendingCommands release];
|
[mPendingCommands release];
|
||||||
mPendingCommands = nil;
|
mPendingCommands = nil;
|
||||||
mPendingCommandSerial++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t Device::GetPendingCommandSerial() {
|
|
||||||
// If this is called, then it means some piece of code somewhere will wait for this serial
|
|
||||||
// to complete. Make sure the pending command buffer is created so that it is on the worst
|
|
||||||
// case enqueued on the next Tick() and eventually increments the serial. Otherwise if no
|
|
||||||
// GPU work happens we could be waiting for this serial forever.
|
|
||||||
GetPendingCommandBuffer();
|
|
||||||
return mPendingCommandSerial;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MapRequestTracker* Device::GetMapTracker() const {
|
MapRequestTracker* Device::GetMapTracker() const {
|
||||||
|
|
|
@ -109,14 +109,29 @@ namespace dawn_native { namespace null {
|
||||||
return mPCIInfo;
|
return mPCIInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial Device::GetCompletedCommandSerial() const {
|
||||||
|
return mCompletedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetLastSubmittedCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::TickImpl() {
|
void Device::TickImpl() {
|
||||||
|
SubmitPendingOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::AddPendingOperation(std::unique_ptr<PendingOperation> operation) {
|
void Device::AddPendingOperation(std::unique_ptr<PendingOperation> operation) {
|
||||||
mPendingOperations.emplace_back(std::move(operation));
|
mPendingOperations.emplace_back(std::move(operation));
|
||||||
}
|
}
|
||||||
std::vector<std::unique_ptr<PendingOperation>> Device::AcquirePendingOperations() {
|
void Device::SubmitPendingOperations() {
|
||||||
return std::move(mPendingOperations);
|
for (auto& operation : mPendingOperations) {
|
||||||
|
operation->Execute();
|
||||||
|
}
|
||||||
|
mPendingOperations.clear();
|
||||||
|
|
||||||
|
mCompletedSerial = mLastSubmittedSerial;
|
||||||
|
mLastSubmittedSerial++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer
|
// Buffer
|
||||||
|
@ -200,13 +215,7 @@ namespace dawn_native { namespace null {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::SubmitImpl(uint32_t, CommandBufferBase* const*) {
|
void Queue::SubmitImpl(uint32_t, CommandBufferBase* const*) {
|
||||||
auto operations = ToBackend(GetDevice())->AcquirePendingOperations();
|
ToBackend(GetDevice())->SubmitPendingOperations();
|
||||||
|
|
||||||
for (auto& operation : operations) {
|
|
||||||
operation->Execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
operations.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SwapChain
|
// SwapChain
|
||||||
|
|
|
@ -106,12 +106,14 @@ namespace dawn_native { namespace null {
|
||||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||||
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
||||||
|
|
||||||
|
Serial GetCompletedCommandSerial() const final override;
|
||||||
|
Serial GetLastSubmittedCommandSerial() const final override;
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||||
|
|
||||||
void AddPendingOperation(std::unique_ptr<PendingOperation> operation);
|
void AddPendingOperation(std::unique_ptr<PendingOperation> operation);
|
||||||
std::vector<std::unique_ptr<PendingOperation>> AcquirePendingOperations();
|
void SubmitPendingOperations();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
|
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
|
||||||
|
@ -131,6 +133,8 @@ namespace dawn_native { namespace null {
|
||||||
const TextureViewDescriptor* descriptor) override;
|
const TextureViewDescriptor* descriptor) override;
|
||||||
void InitFakePCIInfo();
|
void InitFakePCIInfo();
|
||||||
|
|
||||||
|
Serial mCompletedSerial = 0;
|
||||||
|
Serial mLastSubmittedSerial = 0;
|
||||||
std::vector<std::unique_ptr<PendingOperation>> mPendingOperations;
|
std::vector<std::unique_ptr<PendingOperation>> mPendingOperations;
|
||||||
dawn_native::PCIInfo mPCIInfo;
|
dawn_native::PCIInfo mPCIInfo;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,17 @@ namespace dawn_native { namespace opengl {
|
||||||
CollectPCIInfo();
|
CollectPCIInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
CheckPassedFences();
|
||||||
|
ASSERT(mFencesInFlight.empty());
|
||||||
|
|
||||||
|
// Some operations might have been started since the last submit and waiting
|
||||||
|
// on a serial that doesn't have a corresponding fence enqueued. Force all
|
||||||
|
// operations to look as if they were completed (because they were).
|
||||||
|
mCompletedSerial = mLastSubmittedSerial + 1;
|
||||||
|
Tick();
|
||||||
|
}
|
||||||
|
|
||||||
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
||||||
return new BindGroup(builder);
|
return new BindGroup(builder);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +123,47 @@ namespace dawn_native { namespace opengl {
|
||||||
return new TextureView(texture, descriptor);
|
return new TextureView(texture, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::SubmitFenceSync() {
|
||||||
|
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
mLastSubmittedSerial++;
|
||||||
|
mFencesInFlight.emplace(sync, mLastSubmittedSerial);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetCompletedCommandSerial() const {
|
||||||
|
return mCompletedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetLastSubmittedCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::TickImpl() {
|
void Device::TickImpl() {
|
||||||
|
CheckPassedFences();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::CheckPassedFences() {
|
||||||
|
while (!mFencesInFlight.empty()) {
|
||||||
|
GLsync sync = mFencesInFlight.front().first;
|
||||||
|
Serial fenceSerial = mFencesInFlight.front().second;
|
||||||
|
|
||||||
|
GLint status = 0;
|
||||||
|
GLsizei length;
|
||||||
|
glGetSynciv(sync, GL_SYNC_CONDITION, sizeof(GLint), &length, &status);
|
||||||
|
ASSERT(length == 1);
|
||||||
|
|
||||||
|
// Fence are added in order, so we can stop searching as soon
|
||||||
|
// as we see one that's not ready.
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDeleteSync(sync);
|
||||||
|
|
||||||
|
mFencesInFlight.pop();
|
||||||
|
|
||||||
|
ASSERT(fenceSerial > mCompletedSerial);
|
||||||
|
mCompletedSerial = fenceSerial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dawn_native::PCIInfo& Device::GetPCIInfo() const {
|
const dawn_native::PCIInfo& Device::GetPCIInfo() const {
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
// Remove windows.h macros after glad's include of windows.h
|
// Remove windows.h macros after glad's include of windows.h
|
||||||
#if defined(DAWN_PLATFORM_WINDOWS)
|
#if defined(DAWN_PLATFORM_WINDOWS)
|
||||||
# include "common/windows_with_undefs.h"
|
# include "common/windows_with_undefs.h"
|
||||||
|
@ -33,6 +35,11 @@ namespace dawn_native { namespace opengl {
|
||||||
class Device : public DeviceBase {
|
class Device : public DeviceBase {
|
||||||
public:
|
public:
|
||||||
Device();
|
Device();
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
void SubmitFenceSync();
|
||||||
|
|
||||||
|
// Dawn API
|
||||||
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
|
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
|
||||||
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
|
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
|
||||||
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
|
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
|
||||||
|
@ -44,6 +51,8 @@ namespace dawn_native { namespace opengl {
|
||||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||||
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
||||||
|
|
||||||
|
Serial GetCompletedCommandSerial() const final override;
|
||||||
|
Serial GetLastSubmittedCommandSerial() const final override;
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||||
|
@ -66,6 +75,12 @@ namespace dawn_native { namespace opengl {
|
||||||
const TextureViewDescriptor* descriptor) override;
|
const TextureViewDescriptor* descriptor) override;
|
||||||
void CollectPCIInfo();
|
void CollectPCIInfo();
|
||||||
|
|
||||||
|
void CheckPassedFences();
|
||||||
|
|
||||||
|
Serial mCompletedSerial = 0;
|
||||||
|
Serial mLastSubmittedSerial = 0;
|
||||||
|
std::queue<std::pair<GLsync, Serial>> mFencesInFlight;
|
||||||
|
|
||||||
dawn_native::PCIInfo mPCIInfo;
|
dawn_native::PCIInfo mPCIInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,13 @@ namespace dawn_native { namespace opengl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::SubmitImpl(uint32_t numCommands, CommandBufferBase* const* commands) {
|
void Queue::SubmitImpl(uint32_t numCommands, CommandBufferBase* const* commands) {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < numCommands; ++i) {
|
for (uint32_t i = 0; i < numCommands; ++i) {
|
||||||
ToBackend(commands[i])->Execute();
|
ToBackend(commands[i])->Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device->SubmitFenceSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::opengl
|
}} // namespace dawn_native::opengl
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
request.data = data;
|
request.data = data;
|
||||||
request.isWrite = isWrite;
|
request.isWrite = isWrite;
|
||||||
|
|
||||||
mInflightRequests.Enqueue(std::move(request), mDevice->GetSerial());
|
mInflightRequests.Enqueue(std::move(request), mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapRequestTracker::Tick(Serial finishedSerial) {
|
void MapRequestTracker::Tick(Serial finishedSerial) {
|
||||||
|
|
|
@ -170,7 +170,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
// Some operations might have been started since the last submit and waiting
|
// Some operations might have been started since the last submit and waiting
|
||||||
// on a serial that doesn't have a corresponding fence enqueued. Force all
|
// on a serial that doesn't have a corresponding fence enqueued. Force all
|
||||||
// operations to look as if they were completed (because they were).
|
// operations to look as if they were completed (because they were).
|
||||||
mCompletedSerial = mNextSerial;
|
mCompletedSerial = mLastSubmittedSerial + 1;
|
||||||
Tick();
|
Tick();
|
||||||
|
|
||||||
ASSERT(mCommandsInFlight.Empty());
|
ASSERT(mCommandsInFlight.Empty());
|
||||||
|
@ -277,6 +277,18 @@ namespace dawn_native { namespace vulkan {
|
||||||
return new TextureView(texture, descriptor);
|
return new TextureView(texture, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial Device::GetCompletedCommandSerial() const {
|
||||||
|
return mCompletedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetLastSubmittedCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial Device::GetPendingCommandSerial() const {
|
||||||
|
return mLastSubmittedSerial + 1;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::TickImpl() {
|
void Device::TickImpl() {
|
||||||
CheckPassedFences();
|
CheckPassedFences();
|
||||||
RecycleCompletedCommands();
|
RecycleCompletedCommands();
|
||||||
|
@ -289,11 +301,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
if (mPendingCommands.pool != VK_NULL_HANDLE) {
|
if (mPendingCommands.pool != VK_NULL_HANDLE) {
|
||||||
SubmitPendingCommands();
|
SubmitPendingCommands();
|
||||||
} else if (mCompletedSerial == mNextSerial - 1) {
|
} else if (mCompletedSerial == mLastSubmittedSerial) {
|
||||||
// If there's no GPU work in flight we still need to artificially increment the serial
|
// If there's no GPU work in flight we still need to artificially increment the serial
|
||||||
// so that CPU operations waiting on GPU completion can know they don't have to wait.
|
// so that CPU operations waiting on GPU completion can know they don't have to wait.
|
||||||
mCompletedSerial++;
|
mCompletedSerial++;
|
||||||
mNextSerial++;
|
mLastSubmittedSerial++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,10 +357,6 @@ namespace dawn_native { namespace vulkan {
|
||||||
return mRenderPassCache.get();
|
return mRenderPassCache.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial Device::GetSerial() const {
|
|
||||||
return mNextSerial;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer Device::GetPendingCommandBuffer() {
|
VkCommandBuffer Device::GetPendingCommandBuffer() {
|
||||||
if (mPendingCommands.pool == VK_NULL_HANDLE) {
|
if (mPendingCommands.pool == VK_NULL_HANDLE) {
|
||||||
mPendingCommands = GetUnusedCommands();
|
mPendingCommands = GetUnusedCommands();
|
||||||
|
@ -395,16 +403,15 @@ namespace dawn_native { namespace vulkan {
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCommandsInFlight.Enqueue(mPendingCommands, mNextSerial);
|
mLastSubmittedSerial++;
|
||||||
|
mCommandsInFlight.Enqueue(mPendingCommands, mLastSubmittedSerial);
|
||||||
mPendingCommands = CommandPoolAndBuffer();
|
mPendingCommands = CommandPoolAndBuffer();
|
||||||
mFencesInFlight.emplace(fence, mNextSerial);
|
mFencesInFlight.emplace(fence, mLastSubmittedSerial);
|
||||||
|
|
||||||
for (VkSemaphore semaphore : mWaitSemaphores) {
|
for (VkSemaphore semaphore : mWaitSemaphores) {
|
||||||
mDeleter->DeleteWhenUnused(semaphore);
|
mDeleter->DeleteWhenUnused(semaphore);
|
||||||
}
|
}
|
||||||
mWaitSemaphores.clear();
|
mWaitSemaphores.clear();
|
||||||
|
|
||||||
mNextSerial++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::AddWaitSemaphore(VkSemaphore semaphore) {
|
void Device::AddWaitSemaphore(VkSemaphore semaphore) {
|
||||||
|
|
|
@ -57,9 +57,8 @@ namespace dawn_native { namespace vulkan {
|
||||||
MemoryAllocator* GetMemoryAllocator() const;
|
MemoryAllocator* GetMemoryAllocator() const;
|
||||||
RenderPassCache* GetRenderPassCache() const;
|
RenderPassCache* GetRenderPassCache() const;
|
||||||
|
|
||||||
Serial GetSerial() const;
|
|
||||||
|
|
||||||
VkCommandBuffer GetPendingCommandBuffer();
|
VkCommandBuffer GetPendingCommandBuffer();
|
||||||
|
Serial GetPendingCommandSerial() const;
|
||||||
void SubmitPendingCommands();
|
void SubmitPendingCommands();
|
||||||
void AddWaitSemaphore(VkSemaphore semaphore);
|
void AddWaitSemaphore(VkSemaphore semaphore);
|
||||||
|
|
||||||
|
@ -75,6 +74,8 @@ namespace dawn_native { namespace vulkan {
|
||||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||||
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
|
||||||
|
|
||||||
|
Serial GetCompletedCommandSerial() const final override;
|
||||||
|
Serial GetLastSubmittedCommandSerial() const final override;
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||||
|
@ -143,8 +144,8 @@ namespace dawn_native { namespace vulkan {
|
||||||
// have finished.
|
// have finished.
|
||||||
std::queue<std::pair<VkFence, Serial>> mFencesInFlight;
|
std::queue<std::pair<VkFence, Serial>> mFencesInFlight;
|
||||||
std::vector<VkFence> mUnusedFences;
|
std::vector<VkFence> mUnusedFences;
|
||||||
Serial mNextSerial = 1;
|
|
||||||
Serial mCompletedSerial = 0;
|
Serial mCompletedSerial = 0;
|
||||||
|
Serial mLastSubmittedSerial = 0;
|
||||||
|
|
||||||
struct CommandPoolAndBuffer {
|
struct CommandPoolAndBuffer {
|
||||||
VkCommandPool pool = VK_NULL_HANDLE;
|
VkCommandPool pool = VK_NULL_HANDLE;
|
||||||
|
|
|
@ -39,59 +39,59 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkBuffer buffer) {
|
void FencedDeleter::DeleteWhenUnused(VkBuffer buffer) {
|
||||||
mBuffersToDelete.Enqueue(buffer, mDevice->GetSerial());
|
mBuffersToDelete.Enqueue(buffer, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkDescriptorPool pool) {
|
void FencedDeleter::DeleteWhenUnused(VkDescriptorPool pool) {
|
||||||
mDescriptorPoolsToDelete.Enqueue(pool, mDevice->GetSerial());
|
mDescriptorPoolsToDelete.Enqueue(pool, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkDeviceMemory memory) {
|
void FencedDeleter::DeleteWhenUnused(VkDeviceMemory memory) {
|
||||||
mMemoriesToDelete.Enqueue(memory, mDevice->GetSerial());
|
mMemoriesToDelete.Enqueue(memory, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkFramebuffer framebuffer) {
|
void FencedDeleter::DeleteWhenUnused(VkFramebuffer framebuffer) {
|
||||||
mFramebuffersToDelete.Enqueue(framebuffer, mDevice->GetSerial());
|
mFramebuffersToDelete.Enqueue(framebuffer, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkImage image) {
|
void FencedDeleter::DeleteWhenUnused(VkImage image) {
|
||||||
mImagesToDelete.Enqueue(image, mDevice->GetSerial());
|
mImagesToDelete.Enqueue(image, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkImageView view) {
|
void FencedDeleter::DeleteWhenUnused(VkImageView view) {
|
||||||
mImageViewsToDelete.Enqueue(view, mDevice->GetSerial());
|
mImageViewsToDelete.Enqueue(view, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkPipeline pipeline) {
|
void FencedDeleter::DeleteWhenUnused(VkPipeline pipeline) {
|
||||||
mPipelinesToDelete.Enqueue(pipeline, mDevice->GetSerial());
|
mPipelinesToDelete.Enqueue(pipeline, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkPipelineLayout layout) {
|
void FencedDeleter::DeleteWhenUnused(VkPipelineLayout layout) {
|
||||||
mPipelineLayoutsToDelete.Enqueue(layout, mDevice->GetSerial());
|
mPipelineLayoutsToDelete.Enqueue(layout, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkRenderPass renderPass) {
|
void FencedDeleter::DeleteWhenUnused(VkRenderPass renderPass) {
|
||||||
mRenderPassesToDelete.Enqueue(renderPass, mDevice->GetSerial());
|
mRenderPassesToDelete.Enqueue(renderPass, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkSampler sampler) {
|
void FencedDeleter::DeleteWhenUnused(VkSampler sampler) {
|
||||||
mSamplersToDelete.Enqueue(sampler, mDevice->GetSerial());
|
mSamplersToDelete.Enqueue(sampler, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkSemaphore semaphore) {
|
void FencedDeleter::DeleteWhenUnused(VkSemaphore semaphore) {
|
||||||
mSemaphoresToDelete.Enqueue(semaphore, mDevice->GetSerial());
|
mSemaphoresToDelete.Enqueue(semaphore, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkShaderModule module) {
|
void FencedDeleter::DeleteWhenUnused(VkShaderModule module) {
|
||||||
mShaderModulesToDelete.Enqueue(module, mDevice->GetSerial());
|
mShaderModulesToDelete.Enqueue(module, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkSurfaceKHR surface) {
|
void FencedDeleter::DeleteWhenUnused(VkSurfaceKHR surface) {
|
||||||
mSurfacesToDelete.Enqueue(surface, mDevice->GetSerial());
|
mSurfacesToDelete.Enqueue(surface, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::DeleteWhenUnused(VkSwapchainKHR swapChain) {
|
void FencedDeleter::DeleteWhenUnused(VkSwapchainKHR swapChain) {
|
||||||
mSwapChainsToDelete.Enqueue(swapChain, mDevice->GetSerial());
|
mSwapChainsToDelete.Enqueue(swapChain, mDevice->GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FencedDeleter::Tick(Serial completedSerial) {
|
void FencedDeleter::Tick(Serial completedSerial) {
|
||||||
|
|
Loading…
Reference in New Issue