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:
Austin Eng 2018-12-01 03:20:19 +00:00 committed by Commit Bot service account
parent 179db44c25
commit 8b07e43dad
20 changed files with 204 additions and 88 deletions

View File

@ -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();

View File

@ -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) {

View File

@ -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];
} }

View File

@ -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,

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;
} }

View File

@ -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) {

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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;
}; };

View File

@ -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 {

View File

@ -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;
}; };

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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) {