Add the last usage serial in Buffer
Add the last usage serial in Buffer, it is used for optimizing MapAsync(), so the callback of MapAsync() is called when the last usage serial is done instead of using the current pending serial when the MapAsync() is called. Bug: b/265151060 Change-Id: Ibc95d4e41d41896f0a49b0fd1068912b46ea14e1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116693 Commit-Queue: Peng Huang <penghuang@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
b36e09c71a
commit
e3eb03f8a3
|
@ -455,8 +455,12 @@ void BufferBase::APIMapAsync(wgpu::MapMode mode,
|
||||||
std::unique_ptr<MapRequestTask> request =
|
std::unique_ptr<MapRequestTask> request =
|
||||||
std::make_unique<MapRequestTask>(GetDevice()->GetPlatform(), this, mLastMapID);
|
std::make_unique<MapRequestTask>(GetDevice()->GetPlatform(), this, mLastMapID);
|
||||||
TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Buffer::APIMapAsync", "serial",
|
TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Buffer::APIMapAsync", "serial",
|
||||||
uint64_t(GetDevice()->GetPendingCommandSerial()));
|
uint64_t(mLastUsageSerial));
|
||||||
GetDevice()->GetQueue()->TrackTask(std::move(request));
|
if (mLastUsageSerial != kMaxExecutionSerial) {
|
||||||
|
GetDevice()->GetQueue()->TrackTask(std::move(request), mLastUsageSerial);
|
||||||
|
} else {
|
||||||
|
GetDevice()->GetQueue()->TrackTaskAfterEventualFlush(std::move(request));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* BufferBase::APIGetMappedRange(size_t offset, size_t size) {
|
void* BufferBase::APIGetMappedRange(size_t offset, size_t size) {
|
||||||
|
@ -661,6 +665,11 @@ void BufferBase::SetIsDataInitialized() {
|
||||||
mIsDataInitialized = true;
|
mIsDataInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BufferBase::SetLastUsageSerial(ExecutionSerial serial) {
|
||||||
|
ASSERT(serial >= mLastUsageSerial);
|
||||||
|
mLastUsageSerial = serial;
|
||||||
|
}
|
||||||
|
|
||||||
bool BufferBase::IsFullBufferRange(uint64_t offset, uint64_t size) const {
|
bool BufferBase::IsFullBufferRange(uint64_t offset, uint64_t size) const {
|
||||||
return offset == 0 && size == GetSize();
|
return offset == 0 && size == GetSize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ class BufferBase : public ApiObjectBase {
|
||||||
bool NeedsInitialization() const;
|
bool NeedsInitialization() const;
|
||||||
bool IsDataInitialized() const;
|
bool IsDataInitialized() const;
|
||||||
void SetIsDataInitialized();
|
void SetIsDataInitialized();
|
||||||
|
void SetLastUsageSerial(ExecutionSerial serial);
|
||||||
|
|
||||||
virtual void* GetMappedPointer() = 0;
|
virtual void* GetMappedPointer() = 0;
|
||||||
void* GetMappedRange(size_t offset, size_t size, bool writable = true);
|
void* GetMappedRange(size_t offset, size_t size, bool writable = true);
|
||||||
|
@ -106,6 +107,8 @@ class BufferBase : public ApiObjectBase {
|
||||||
|
|
||||||
uint64_t mAllocatedSize = 0;
|
uint64_t mAllocatedSize = 0;
|
||||||
|
|
||||||
|
ExecutionSerial mLastUsageSerial = ExecutionSerial(0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A helper structure to enforce that the mapAsync callback is called only at the very end of
|
// A helper structure to enforce that the mapAsync callback is called only at the very end of
|
||||||
// methods that might trigger callbacks. Non-copyable but movable for the assertion in the
|
// methods that might trigger callbacks. Non-copyable but movable for the assertion in the
|
||||||
|
|
|
@ -1159,11 +1159,11 @@ void CommandEncoder::APICopyBufferToBuffer(BufferBase* source,
|
||||||
"validating source %s usage.", source);
|
"validating source %s usage.", source);
|
||||||
DAWN_TRY_CONTEXT(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst),
|
DAWN_TRY_CONTEXT(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst),
|
||||||
"validating destination %s usage.", destination);
|
"validating destination %s usage.", destination);
|
||||||
|
|
||||||
mTopLevelBuffers.insert(source);
|
|
||||||
mTopLevelBuffers.insert(destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(source);
|
||||||
|
mTopLevelBuffers.insert(destination);
|
||||||
|
|
||||||
CopyBufferToBufferCmd* copy =
|
CopyBufferToBufferCmd* copy =
|
||||||
allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
||||||
copy->source = source;
|
copy->source = source;
|
||||||
|
@ -1210,11 +1210,11 @@ void CommandEncoder::APICopyBufferToTexture(const ImageCopyBuffer* source,
|
||||||
destination->texture->GetFormat().HasDepthOrStencil()));
|
destination->texture->GetFormat().HasDepthOrStencil()));
|
||||||
DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
|
DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
|
||||||
blockInfo, *copySize));
|
blockInfo, *copySize));
|
||||||
|
|
||||||
mTopLevelBuffers.insert(source->buffer);
|
|
||||||
mTopLevelTextures.insert(destination->texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(source->buffer);
|
||||||
|
mTopLevelTextures.insert(destination->texture);
|
||||||
|
|
||||||
TextureDataLayout srcLayout = source->layout;
|
TextureDataLayout srcLayout = source->layout;
|
||||||
ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
|
ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
|
||||||
|
|
||||||
|
@ -1269,11 +1269,11 @@ void CommandEncoder::APICopyTextureToBuffer(const ImageCopyTexture* source,
|
||||||
source->texture->GetFormat().HasDepthOrStencil()));
|
source->texture->GetFormat().HasDepthOrStencil()));
|
||||||
DAWN_TRY(ValidateLinearTextureData(
|
DAWN_TRY(ValidateLinearTextureData(
|
||||||
destination->layout, destination->buffer->GetSize(), blockInfo, *copySize));
|
destination->layout, destination->buffer->GetSize(), blockInfo, *copySize));
|
||||||
|
|
||||||
mTopLevelTextures.insert(source->texture);
|
|
||||||
mTopLevelBuffers.insert(destination->buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelTextures.insert(source->texture);
|
||||||
|
mTopLevelBuffers.insert(destination->buffer);
|
||||||
|
|
||||||
TextureDataLayout dstLayout = destination->layout;
|
TextureDataLayout dstLayout = destination->layout;
|
||||||
ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
|
ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
|
||||||
|
|
||||||
|
@ -1377,11 +1377,11 @@ void CommandEncoder::APICopyTextureToTextureHelper(const ImageCopyTexture* sourc
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
|
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst,
|
||||||
mUsageValidationMode));
|
mUsageValidationMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
mTopLevelTextures.insert(source->texture);
|
|
||||||
mTopLevelTextures.insert(destination->texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelTextures.insert(source->texture);
|
||||||
|
mTopLevelTextures.insert(destination->texture);
|
||||||
|
|
||||||
CopyTextureToTextureCmd* copy =
|
CopyTextureToTextureCmd* copy =
|
||||||
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||||
copy->source.texture = source->texture;
|
copy->source.texture = source->texture;
|
||||||
|
@ -1434,7 +1434,6 @@ void CommandEncoder::APIClearBuffer(BufferBase* buffer, uint64_t offset, uint64_
|
||||||
DAWN_INVALID_IF(offset % 4 != 0, "Offset (%u) is not a multiple of 4 bytes,",
|
DAWN_INVALID_IF(offset % 4 != 0, "Offset (%u) is not a multiple of 4 bytes,",
|
||||||
offset);
|
offset);
|
||||||
|
|
||||||
mTopLevelBuffers.insert(buffer);
|
|
||||||
} else {
|
} else {
|
||||||
if (size == wgpu::kWholeSize) {
|
if (size == wgpu::kWholeSize) {
|
||||||
DAWN_ASSERT(buffer->GetSize() >= offset);
|
DAWN_ASSERT(buffer->GetSize() >= offset);
|
||||||
|
@ -1442,6 +1441,8 @@ void CommandEncoder::APIClearBuffer(BufferBase* buffer, uint64_t offset, uint64_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(buffer);
|
||||||
|
|
||||||
ClearBufferCmd* cmd = allocator->Allocate<ClearBufferCmd>(Command::ClearBuffer);
|
ClearBufferCmd* cmd = allocator->Allocate<ClearBufferCmd>(Command::ClearBuffer);
|
||||||
cmd->buffer = buffer;
|
cmd->buffer = buffer;
|
||||||
cmd->offset = offset;
|
cmd->offset = offset;
|
||||||
|
@ -1528,9 +1529,10 @@ void CommandEncoder::APIResolveQuerySet(QuerySetBase* querySet,
|
||||||
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
|
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
|
||||||
|
|
||||||
TrackUsedQuerySet(querySet);
|
TrackUsedQuerySet(querySet);
|
||||||
mTopLevelBuffers.insert(destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(destination);
|
||||||
|
|
||||||
ResolveQuerySetCmd* cmd =
|
ResolveQuerySetCmd* cmd =
|
||||||
allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
|
allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
|
||||||
cmd->querySet = querySet;
|
cmd->querySet = querySet;
|
||||||
|
|
|
@ -218,24 +218,35 @@ void QueueBase::APIOnSubmittedWorkDone(uint64_t signalValue,
|
||||||
// also used to make sure ALL queue work is finished in tests, so we also wait for pending
|
// also used to make sure ALL queue work is finished in tests, so we also wait for pending
|
||||||
// commands (this is non-observable outside of tests so it's ok to do deviate a bit from the
|
// commands (this is non-observable outside of tests so it's ok to do deviate a bit from the
|
||||||
// spec).
|
// spec).
|
||||||
TrackTask(std::move(task));
|
TrackTaskAfterEventualFlush(std::move(task));
|
||||||
|
|
||||||
TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Queue::APIOnSubmittedWorkDone", "serial",
|
TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Queue::APIOnSubmittedWorkDone", "serial",
|
||||||
uint64_t(GetDevice()->GetPendingCommandSerial()));
|
uint64_t(GetDevice()->GetPendingCommandSerial()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueBase::TrackTask(std::unique_ptr<TrackTaskCallback> task) {
|
void QueueBase::TrackTask(std::unique_ptr<TrackTaskCallback> task, ExecutionSerial serial) {
|
||||||
GetDevice()->ForceEventualFlushOfCommands();
|
// If the task depends on a serial which is not submitted yet, force a flush.
|
||||||
// we can move the task to the callback task manager, as it's ready to be called if there are no
|
if (serial > GetDevice()->GetLastSubmittedCommandSerial()) {
|
||||||
// scheduled commands.
|
GetDevice()->ForceEventualFlushOfCommands();
|
||||||
if (!GetDevice()->HasScheduledCommands()) {
|
}
|
||||||
|
|
||||||
|
ASSERT(serial <= GetDevice()->GetScheduledWorkDoneSerial());
|
||||||
|
|
||||||
|
// If the serial indicated command has been completed, the task will be moved to callback task
|
||||||
|
// manager.
|
||||||
|
if (serial <= GetDevice()->GetCompletedCommandSerial()) {
|
||||||
task->SetFinishedSerial(GetDevice()->GetCompletedCommandSerial());
|
task->SetFinishedSerial(GetDevice()->GetCompletedCommandSerial());
|
||||||
GetDevice()->GetCallbackTaskManager()->AddCallbackTask(std::move(task));
|
GetDevice()->GetCallbackTaskManager()->AddCallbackTask(std::move(task));
|
||||||
} else {
|
} else {
|
||||||
mTasksInFlight.Enqueue(std::move(task), GetDevice()->GetScheduledWorkDoneSerial());
|
mTasksInFlight.Enqueue(std::move(task), serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QueueBase::TrackTaskAfterEventualFlush(std::unique_ptr<TrackTaskCallback> task) {
|
||||||
|
GetDevice()->ForceEventualFlushOfCommands();
|
||||||
|
TrackTask(std::move(task), GetDevice()->GetScheduledWorkDoneSerial());
|
||||||
|
}
|
||||||
|
|
||||||
void QueueBase::Tick(ExecutionSerial finishedSerial) {
|
void QueueBase::Tick(ExecutionSerial finishedSerial) {
|
||||||
// If a user calls Queue::Submit inside a task, for example in a Buffer::MapAsync callback,
|
// If a user calls Queue::Submit inside a task, for example in a Buffer::MapAsync callback,
|
||||||
// then the device will be ticked, which in turns ticks the queue, causing reentrance here.
|
// then the device will be ticked, which in turns ticks the queue, causing reentrance here.
|
||||||
|
@ -427,9 +438,13 @@ MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
|
||||||
for (uint32_t i = 0; i < commandCount; ++i) {
|
for (uint32_t i = 0; i < commandCount; ++i) {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(commands[i]));
|
DAWN_TRY(GetDevice()->ValidateObject(commands[i]));
|
||||||
DAWN_TRY(commands[i]->ValidateCanUseInSubmitNow());
|
DAWN_TRY(commands[i]->ValidateCanUseInSubmitNow());
|
||||||
|
|
||||||
const CommandBufferResourceUsage& usages = commands[i]->GetResourceUsages();
|
const CommandBufferResourceUsage& usages = commands[i]->GetResourceUsages();
|
||||||
|
|
||||||
|
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
||||||
|
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe track last usage for other resources, and use it to release resources earlier?
|
||||||
for (const SyncScopeResourceUsage& scope : usages.renderPasses) {
|
for (const SyncScopeResourceUsage& scope : usages.renderPasses) {
|
||||||
for (const BufferBase* buffer : scope.buffers) {
|
for (const BufferBase* buffer : scope.buffers) {
|
||||||
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
||||||
|
@ -456,9 +471,6 @@ MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
|
||||||
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
|
||||||
}
|
|
||||||
for (const TextureBase* texture : usages.topLevelTextures) {
|
for (const TextureBase* texture : usages.topLevelTextures) {
|
||||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||||
}
|
}
|
||||||
|
@ -529,9 +541,10 @@ void QueueBase::SubmitInternal(uint32_t commandCount, CommandBufferBase* const*
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_EVENT0(device->GetPlatform(), General, "Queue::Submit");
|
TRACE_EVENT0(device->GetPlatform(), General, "Queue::Submit");
|
||||||
if (device->IsValidationEnabled() &&
|
if (device->IsValidationEnabled()) {
|
||||||
device->ConsumedError(ValidateSubmit(commandCount, commands))) {
|
if (device->ConsumedError(ValidateSubmit(commandCount, commands))) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ASSERT(!IsError());
|
ASSERT(!IsError());
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "dawn/common/SerialQueue.h"
|
#include "dawn/common/SerialMap.h"
|
||||||
#include "dawn/native/CallbackTaskManager.h"
|
#include "dawn/native/CallbackTaskManager.h"
|
||||||
#include "dawn/native/Error.h"
|
#include "dawn/native/Error.h"
|
||||||
#include "dawn/native/Forward.h"
|
#include "dawn/native/Forward.h"
|
||||||
|
@ -77,7 +77,8 @@ class QueueBase : public ApiObjectBase {
|
||||||
uint64_t bufferOffset,
|
uint64_t bufferOffset,
|
||||||
const void* data,
|
const void* data,
|
||||||
size_t size);
|
size_t size);
|
||||||
void TrackTask(std::unique_ptr<TrackTaskCallback> task);
|
void TrackTask(std::unique_ptr<TrackTaskCallback> task, ExecutionSerial serial);
|
||||||
|
void TrackTaskAfterEventualFlush(std::unique_ptr<TrackTaskCallback> task);
|
||||||
void Tick(ExecutionSerial finishedSerial);
|
void Tick(ExecutionSerial finishedSerial);
|
||||||
void HandleDeviceLoss();
|
void HandleDeviceLoss();
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ class QueueBase : public ApiObjectBase {
|
||||||
|
|
||||||
void SubmitInternal(uint32_t commandCount, CommandBufferBase* const* commands);
|
void SubmitInternal(uint32_t commandCount, CommandBufferBase* const* commands);
|
||||||
|
|
||||||
SerialQueue<ExecutionSerial, std::unique_ptr<TrackTaskCallback>> mTasksInFlight;
|
SerialMap<ExecutionSerial, std::unique_ptr<TrackTaskCallback>> mTasksInFlight;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
|
|
@ -203,25 +203,8 @@ bool Buffer::TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandCon
|
||||||
Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
|
Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
|
||||||
commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial());
|
commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial());
|
||||||
|
|
||||||
// Return the resource barrier.
|
SetLastUsageSerial(GetDevice()->GetPendingCommandSerial());
|
||||||
return TransitionUsageAndGetResourceBarrier(commandContext, barrier, newUsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buffer::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
|
|
||||||
wgpu::BufferUsage newUsage) {
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
|
||||||
|
|
||||||
if (TrackUsageAndGetResourceBarrier(commandContext, &barrier, newUsage)) {
|
|
||||||
commandContext->GetCommandList()->ResourceBarrier(1, &barrier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a
|
|
||||||
// ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can
|
|
||||||
// cause subsequent errors.
|
|
||||||
bool Buffer::TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
|
|
||||||
D3D12_RESOURCE_BARRIER* barrier,
|
|
||||||
wgpu::BufferUsage newUsage) {
|
|
||||||
// Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state
|
// Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state
|
||||||
if (mFixedResourceState) {
|
if (mFixedResourceState) {
|
||||||
ASSERT(mLastUsage == newUsage);
|
ASSERT(mLastUsage == newUsage);
|
||||||
|
@ -298,6 +281,15 @@ bool Buffer::TransitionUsageAndGetResourceBarrier(CommandRecordingContext* comma
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
|
||||||
|
wgpu::BufferUsage newUsage) {
|
||||||
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
|
|
||||||
|
if (TrackUsageAndGetResourceBarrier(commandContext, &barrier, newUsage)) {
|
||||||
|
commandContext->GetCommandList()->ResourceBarrier(1, &barrier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
|
D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
|
||||||
return mResourceAllocation.GetGPUPointer();
|
return mResourceAllocation.GetGPUPointer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,6 @@ class Buffer final : public BufferBase {
|
||||||
|
|
||||||
MaybeError MapInternal(bool isWrite, size_t start, size_t end, const char* contextInfo);
|
MaybeError MapInternal(bool isWrite, size_t start, size_t end, const char* contextInfo);
|
||||||
|
|
||||||
bool TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
|
|
||||||
D3D12_RESOURCE_BARRIER* barrier,
|
|
||||||
wgpu::BufferUsage newUsage);
|
|
||||||
|
|
||||||
MaybeError InitializeToZero(CommandRecordingContext* commandContext);
|
MaybeError InitializeToZero(CommandRecordingContext* commandContext);
|
||||||
MaybeError ClearBuffer(CommandRecordingContext* commandContext,
|
MaybeError ClearBuffer(CommandRecordingContext* commandContext,
|
||||||
uint8_t clearValue,
|
uint8_t clearValue,
|
||||||
|
|
|
@ -34,6 +34,7 @@ class Buffer final : public BufferBase {
|
||||||
|
|
||||||
id<MTLBuffer> GetMTLBuffer() const;
|
id<MTLBuffer> GetMTLBuffer() const;
|
||||||
|
|
||||||
|
void TrackUsage();
|
||||||
bool EnsureDataInitialized(CommandRecordingContext* commandContext);
|
bool EnsureDataInitialized(CommandRecordingContext* commandContext);
|
||||||
bool EnsureDataInitializedAsDestination(CommandRecordingContext* commandContext,
|
bool EnsureDataInitializedAsDestination(CommandRecordingContext* commandContext,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
|
|
|
@ -178,6 +178,10 @@ void Buffer::DestroyImpl() {
|
||||||
mMtlBuffer = nullptr;
|
mMtlBuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::TrackUsage() {
|
||||||
|
SetLastUsageSerial(GetDevice()->GetPendingCommandSerial());
|
||||||
|
}
|
||||||
|
|
||||||
bool Buffer::EnsureDataInitialized(CommandRecordingContext* commandContext) {
|
bool Buffer::EnsureDataInitialized(CommandRecordingContext* commandContext) {
|
||||||
if (!NeedsInitialization()) {
|
if (!NeedsInitialization()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -234,6 +238,7 @@ void Buffer::ClearBuffer(CommandRecordingContext* commandContext,
|
||||||
ASSERT(commandContext != nullptr);
|
ASSERT(commandContext != nullptr);
|
||||||
size = size > 0 ? size : GetAllocatedSize();
|
size = size > 0 ? size : GetAllocatedSize();
|
||||||
ASSERT(size > 0);
|
ASSERT(size > 0);
|
||||||
|
TrackUsage();
|
||||||
[commandContext->EnsureBlit() fillBuffer:mMtlBuffer.Get()
|
[commandContext->EnsureBlit() fillBuffer:mMtlBuffer.Get()
|
||||||
range:NSMakeRange(offset, size)
|
range:NSMakeRange(offset, size)
|
||||||
value:clearValue];
|
value:clearValue];
|
||||||
|
|
|
@ -496,6 +496,7 @@ class BindGroupTracker : public BindGroupTrackerBase<true, uint64_t> {
|
||||||
switch (bindingInfo.bindingType) {
|
switch (bindingInfo.bindingType) {
|
||||||
case BindingInfoType::Buffer: {
|
case BindingInfoType::Buffer: {
|
||||||
const BufferBinding& binding = group->GetBindingAsBufferBinding(bindingIndex);
|
const BufferBinding& binding = group->GetBindingAsBufferBinding(bindingIndex);
|
||||||
|
ToBackend(binding.buffer)->TrackUsage();
|
||||||
const id<MTLBuffer> buffer = ToBackend(binding.buffer)->GetMTLBuffer();
|
const id<MTLBuffer> buffer = ToBackend(binding.buffer)->GetMTLBuffer();
|
||||||
NSUInteger offset = binding.offset;
|
NSUInteger offset = binding.offset;
|
||||||
|
|
||||||
|
@ -591,6 +592,7 @@ class VertexBufferTracker {
|
||||||
: mLengthTracker(lengthTracker) {}
|
: mLengthTracker(lengthTracker) {}
|
||||||
|
|
||||||
void OnSetVertexBuffer(VertexBufferSlot slot, Buffer* buffer, uint64_t offset) {
|
void OnSetVertexBuffer(VertexBufferSlot slot, Buffer* buffer, uint64_t offset) {
|
||||||
|
buffer->TrackUsage();
|
||||||
mVertexBuffers[slot] = buffer->GetMTLBuffer();
|
mVertexBuffers[slot] = buffer->GetMTLBuffer();
|
||||||
mVertexBufferOffsets[slot] = offset;
|
mVertexBufferOffsets[slot] = offset;
|
||||||
|
|
||||||
|
@ -819,10 +821,13 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ToBackend(copy->source)->EnsureDataInitialized(commandContext);
|
auto srcBuffer = ToBackend(copy->source);
|
||||||
ToBackend(copy->destination)
|
srcBuffer->EnsureDataInitialized(commandContext);
|
||||||
->EnsureDataInitializedAsDestination(commandContext, copy->destinationOffset,
|
srcBuffer->TrackUsage();
|
||||||
copy->size);
|
auto dstBuffer = ToBackend(copy->destination);
|
||||||
|
dstBuffer->EnsureDataInitializedAsDestination(commandContext,
|
||||||
|
copy->destinationOffset, copy->size);
|
||||||
|
dstBuffer->TrackUsage();
|
||||||
|
|
||||||
[commandContext->EnsureBlit()
|
[commandContext->EnsureBlit()
|
||||||
copyFromBuffer:ToBackend(copy->source)->GetMTLBuffer()
|
copyFromBuffer:ToBackend(copy->source)->GetMTLBuffer()
|
||||||
|
@ -849,6 +854,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
buffer->EnsureDataInitialized(commandContext);
|
buffer->EnsureDataInitialized(commandContext);
|
||||||
EnsureDestinationTextureInitialized(commandContext, texture, dst, copySize);
|
EnsureDestinationTextureInitialized(commandContext, texture, dst, copySize);
|
||||||
|
|
||||||
|
buffer->TrackUsage();
|
||||||
texture->SynchronizeTextureBeforeUse(commandContext);
|
texture->SynchronizeTextureBeforeUse(commandContext);
|
||||||
RecordCopyBufferToTexture(commandContext, buffer->GetMTLBuffer(), buffer->GetSize(),
|
RecordCopyBufferToTexture(commandContext, buffer->GetMTLBuffer(), buffer->GetSize(),
|
||||||
src.offset, src.bytesPerRow, src.rowsPerImage, texture,
|
src.offset, src.bytesPerRow, src.rowsPerImage, texture,
|
||||||
|
@ -874,6 +880,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
texture->SynchronizeTextureBeforeUse(commandContext);
|
texture->SynchronizeTextureBeforeUse(commandContext);
|
||||||
texture->EnsureSubresourceContentInitialized(
|
texture->EnsureSubresourceContentInitialized(
|
||||||
commandContext, GetSubresourcesAffectedByCopy(src, copySize));
|
commandContext, GetSubresourcesAffectedByCopy(src, copySize));
|
||||||
|
buffer->TrackUsage();
|
||||||
|
|
||||||
TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit(
|
TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit(
|
||||||
texture, src.mipLevel, src.origin, copySize, buffer->GetSize(), dst.offset,
|
texture, src.mipLevel, src.origin, copySize, buffer->GetSize(), dst.offset,
|
||||||
|
@ -1028,6 +1035,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
commandContext, cmd->offset, cmd->size);
|
commandContext, cmd->offset, cmd->size);
|
||||||
|
|
||||||
if (!clearedToZero) {
|
if (!clearedToZero) {
|
||||||
|
dstBuffer->TrackUsage();
|
||||||
[commandContext->EnsureBlit() fillBuffer:dstBuffer->GetMTLBuffer()
|
[commandContext->EnsureBlit() fillBuffer:dstBuffer->GetMTLBuffer()
|
||||||
range:NSMakeRange(cmd->offset, cmd->size)
|
range:NSMakeRange(cmd->offset, cmd->size)
|
||||||
value:0u];
|
value:0u];
|
||||||
|
@ -1045,6 +1053,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
commandContext, cmd->destinationOffset, cmd->queryCount * sizeof(uint64_t));
|
commandContext, cmd->destinationOffset, cmd->queryCount * sizeof(uint64_t));
|
||||||
|
|
||||||
if (querySet->GetQueryType() == wgpu::QueryType::Occlusion) {
|
if (querySet->GetQueryType() == wgpu::QueryType::Occlusion) {
|
||||||
|
destination->TrackUsage();
|
||||||
[commandContext->EnsureBlit()
|
[commandContext->EnsureBlit()
|
||||||
copyFromBuffer:querySet->GetVisibilityBuffer()
|
copyFromBuffer:querySet->GetVisibilityBuffer()
|
||||||
sourceOffset:NSUInteger(cmd->firstQuery * sizeof(uint64_t))
|
sourceOffset:NSUInteger(cmd->firstQuery * sizeof(uint64_t))
|
||||||
|
@ -1053,6 +1062,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
size:NSUInteger(cmd->queryCount * sizeof(uint64_t))];
|
size:NSUInteger(cmd->queryCount * sizeof(uint64_t))];
|
||||||
} else {
|
} else {
|
||||||
if (@available(macos 10.15, iOS 14.0, *)) {
|
if (@available(macos 10.15, iOS 14.0, *)) {
|
||||||
|
destination->TrackUsage();
|
||||||
[commandContext->EnsureBlit()
|
[commandContext->EnsureBlit()
|
||||||
resolveCounters:querySet->GetCounterSampleBuffer()
|
resolveCounters:querySet->GetCounterSampleBuffer()
|
||||||
inRange:NSMakeRange(cmd->firstQuery, cmd->queryCount)
|
inRange:NSMakeRange(cmd->firstQuery, cmd->queryCount)
|
||||||
|
@ -1142,6 +1152,7 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
||||||
|
|
||||||
dstBuffer->EnsureDataInitializedAsDestination(commandContext, offset, size);
|
dstBuffer->EnsureDataInitializedAsDestination(commandContext, offset, size);
|
||||||
|
|
||||||
|
dstBuffer->TrackUsage();
|
||||||
[commandContext->EnsureBlit()
|
[commandContext->EnsureBlit()
|
||||||
copyFromBuffer:ToBackend(uploadHandle.stagingBuffer)->GetMTLBuffer()
|
copyFromBuffer:ToBackend(uploadHandle.stagingBuffer)->GetMTLBuffer()
|
||||||
sourceOffset:uploadHandle.startOffset
|
sourceOffset:uploadHandle.startOffset
|
||||||
|
@ -1245,6 +1256,7 @@ MaybeError CommandBuffer::EncodeComputePass(CommandRecordingContext* commandCont
|
||||||
storageBufferLengths.Apply(encoder, lastPipeline);
|
storageBufferLengths.Apply(encoder, lastPipeline);
|
||||||
|
|
||||||
Buffer* buffer = ToBackend(dispatch->indirectBuffer.Get());
|
Buffer* buffer = ToBackend(dispatch->indirectBuffer.Get());
|
||||||
|
buffer->TrackUsage();
|
||||||
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
||||||
[encoder
|
[encoder
|
||||||
dispatchThreadgroupsWithIndirectBuffer:indirectBuffer
|
dispatchThreadgroupsWithIndirectBuffer:indirectBuffer
|
||||||
|
@ -1422,6 +1434,7 @@ MaybeError CommandBuffer::EncodeRenderPass(id<MTLRenderCommandEncoder> encoder,
|
||||||
storageBufferLengths.Apply(encoder, lastPipeline, enableVertexPulling);
|
storageBufferLengths.Apply(encoder, lastPipeline, enableVertexPulling);
|
||||||
|
|
||||||
Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
|
Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
|
||||||
|
buffer->TrackUsage();
|
||||||
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
||||||
[encoder drawPrimitives:lastPipeline->GetMTLPrimitiveTopology()
|
[encoder drawPrimitives:lastPipeline->GetMTLPrimitiveTopology()
|
||||||
indirectBuffer:indirectBuffer
|
indirectBuffer:indirectBuffer
|
||||||
|
@ -1439,6 +1452,7 @@ MaybeError CommandBuffer::EncodeRenderPass(id<MTLRenderCommandEncoder> encoder,
|
||||||
Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
|
Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
|
||||||
ASSERT(buffer != nullptr);
|
ASSERT(buffer != nullptr);
|
||||||
|
|
||||||
|
buffer->TrackUsage();
|
||||||
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer();
|
||||||
[encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology()
|
[encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology()
|
||||||
indexType:indexBufferType
|
indexType:indexBufferType
|
||||||
|
@ -1518,6 +1532,7 @@ MaybeError CommandBuffer::EncodeRenderPass(id<MTLRenderCommandEncoder> encoder,
|
||||||
case Command::SetIndexBuffer: {
|
case Command::SetIndexBuffer: {
|
||||||
SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
|
SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
|
||||||
auto b = ToBackend(cmd->buffer.Get());
|
auto b = ToBackend(cmd->buffer.Get());
|
||||||
|
b->TrackUsage();
|
||||||
indexBuffer = b->GetMTLBuffer();
|
indexBuffer = b->GetMTLBuffer();
|
||||||
indexBufferBaseOffset = cmd->offset;
|
indexBufferBaseOffset = cmd->offset;
|
||||||
indexBufferType = MTLIndexFormat(cmd->format);
|
indexBufferType = MTLIndexFormat(cmd->format);
|
||||||
|
|
|
@ -478,11 +478,12 @@ MaybeError Device::CopyFromStagingToBufferImpl(BufferBase* source,
|
||||||
GetPendingCommandContext(DeviceBase::SubmitMode::Passive), destinationOffset, size);
|
GetPendingCommandContext(DeviceBase::SubmitMode::Passive), destinationOffset, size);
|
||||||
|
|
||||||
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetMTLBuffer();
|
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetMTLBuffer();
|
||||||
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
|
Buffer* buffer = ToBackend(destination);
|
||||||
|
buffer->TrackUsage();
|
||||||
[GetPendingCommandContext(DeviceBase::SubmitMode::Passive)->EnsureBlit()
|
[GetPendingCommandContext(DeviceBase::SubmitMode::Passive)->EnsureBlit()
|
||||||
copyFromBuffer:uploadBuffer
|
copyFromBuffer:uploadBuffer
|
||||||
sourceOffset:sourceOffset
|
sourceOffset:sourceOffset
|
||||||
toBuffer:buffer
|
toBuffer:buffer->GetMTLBuffer()
|
||||||
destinationOffset:destinationOffset
|
destinationOffset:destinationOffset
|
||||||
size:size];
|
size:size];
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -39,6 +39,8 @@ ResultOrError<Ref<Buffer>> Buffer::CreateInternalBuffer(Device* device,
|
||||||
|
|
||||||
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
|
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
|
||||||
: BufferBase(device, descriptor) {
|
: BufferBase(device, descriptor) {
|
||||||
|
// TODO(penghuang): track usage for GL.
|
||||||
|
mLastUsageSerial = kMaxExecutionSerial;
|
||||||
const OpenGLFunctions& gl = device->GetGL();
|
const OpenGLFunctions& gl = device->GetGL();
|
||||||
// Allocate at least 4 bytes so clamped accesses are always in bounds.
|
// Allocate at least 4 bytes so clamped accesses are always in bounds.
|
||||||
mAllocatedSize = std::max(GetSize(), uint64_t(4u));
|
mAllocatedSize = std::max(GetSize(), uint64_t(4u));
|
||||||
|
|
|
@ -249,7 +249,7 @@ void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext,
|
||||||
VkPipelineStageFlags srcStages = 0;
|
VkPipelineStageFlags srcStages = 0;
|
||||||
VkPipelineStageFlags dstStages = 0;
|
VkPipelineStageFlags dstStages = 0;
|
||||||
|
|
||||||
if (TransitionUsageAndGetResourceBarrier(usage, &barrier, &srcStages, &dstStages)) {
|
if (TrackUsageAndGetResourceBarrier(usage, &barrier, &srcStages, &dstStages)) {
|
||||||
ASSERT(srcStages != 0 && dstStages != 0);
|
ASSERT(srcStages != 0 && dstStages != 0);
|
||||||
ToBackend(GetDevice())
|
ToBackend(GetDevice())
|
||||||
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
||||||
|
@ -257,10 +257,12 @@ void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::TransitionUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
bool Buffer::TrackUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
||||||
VkBufferMemoryBarrier* barrier,
|
VkBufferMemoryBarrier* barrier,
|
||||||
VkPipelineStageFlags* srcStages,
|
VkPipelineStageFlags* srcStages,
|
||||||
VkPipelineStageFlags* dstStages) {
|
VkPipelineStageFlags* dstStages) {
|
||||||
|
SetLastUsageSerial(GetDevice()->GetPendingCommandSerial());
|
||||||
|
|
||||||
bool lastIncludesTarget = IsSubset(usage, mLastUsage);
|
bool lastIncludesTarget = IsSubset(usage, mLastUsage);
|
||||||
constexpr wgpu::BufferUsage kReuseNoBarrierBufferUsages =
|
constexpr wgpu::BufferUsage kReuseNoBarrierBufferUsages =
|
||||||
kReadOnlyBufferUsages | wgpu::BufferUsage::MapWrite;
|
kReadOnlyBufferUsages | wgpu::BufferUsage::MapWrite;
|
||||||
|
|
|
@ -36,10 +36,10 @@ class Buffer final : public BufferBase {
|
||||||
// `commands`.
|
// `commands`.
|
||||||
// TODO(crbug.com/dawn/851): coalesce barriers and do them early when possible.
|
// TODO(crbug.com/dawn/851): coalesce barriers and do them early when possible.
|
||||||
void TransitionUsageNow(CommandRecordingContext* recordingContext, wgpu::BufferUsage usage);
|
void TransitionUsageNow(CommandRecordingContext* recordingContext, wgpu::BufferUsage usage);
|
||||||
bool TransitionUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
bool TrackUsageAndGetResourceBarrier(wgpu::BufferUsage usage,
|
||||||
VkBufferMemoryBarrier* barrier,
|
VkBufferMemoryBarrier* barrier,
|
||||||
VkPipelineStageFlags* srcStages,
|
VkPipelineStageFlags* srcStages,
|
||||||
VkPipelineStageFlags* dstStages);
|
VkPipelineStageFlags* dstStages);
|
||||||
|
|
||||||
// All the Ensure methods return true if the buffer was initialized to zero.
|
// All the Ensure methods return true if the buffer was initialized to zero.
|
||||||
bool EnsureDataInitialized(CommandRecordingContext* recordingContext);
|
bool EnsureDataInitialized(CommandRecordingContext* recordingContext);
|
||||||
|
|
|
@ -167,8 +167,8 @@ void TransitionAndClearForSyncScope(Device* device,
|
||||||
buffer->EnsureDataInitialized(recordingContext);
|
buffer->EnsureDataInitialized(recordingContext);
|
||||||
|
|
||||||
VkBufferMemoryBarrier bufferBarrier;
|
VkBufferMemoryBarrier bufferBarrier;
|
||||||
if (buffer->TransitionUsageAndGetResourceBarrier(scope.bufferUsages[i], &bufferBarrier,
|
if (buffer->TrackUsageAndGetResourceBarrier(scope.bufferUsages[i], &bufferBarrier,
|
||||||
&srcStages, &dstStages)) {
|
&srcStages, &dstStages)) {
|
||||||
bufferBarriers.push_back(bufferBarrier);
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -541,6 +541,164 @@ DAWN_INSTANTIATE_TEST(BufferMappingTests,
|
||||||
OpenGLESBackend(),
|
OpenGLESBackend(),
|
||||||
VulkanBackend());
|
VulkanBackend());
|
||||||
|
|
||||||
|
class BufferMappingCallbackTests : public BufferMappingTests {
|
||||||
|
protected:
|
||||||
|
void SubmitCommandBuffer(wgpu::Buffer buffer) {
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Record enough commands to make sure the submission cannot be completed by GPU too
|
||||||
|
// quick.
|
||||||
|
constexpr int kRepeatCount = 50;
|
||||||
|
constexpr int kBufferSize = 1024 * 1024 * 10;
|
||||||
|
wgpu::Buffer tempWriteBuffer = CreateMapWriteBuffer(kBufferSize);
|
||||||
|
wgpu::Buffer tempReadBuffer = CreateMapReadBuffer(kBufferSize);
|
||||||
|
for (int i = 0; i < kRepeatCount; ++i) {
|
||||||
|
encoder.CopyBufferToBuffer(tempWriteBuffer, 0, tempReadBuffer, 0, kBufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
if (buffer.GetUsage() & wgpu::BufferUsage::CopyDst) {
|
||||||
|
encoder.ClearBuffer(buffer);
|
||||||
|
} else {
|
||||||
|
wgpu::Buffer tempBuffer = CreateMapReadBuffer(buffer.GetSize());
|
||||||
|
encoder.CopyBufferToBuffer(buffer, 0, tempBuffer, 0, buffer.GetSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
|
queue.Submit(1, &commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait(std::vector<bool>& done) {
|
||||||
|
do {
|
||||||
|
WaitABit();
|
||||||
|
} while (std::any_of(done.begin(), done.end(), [](bool done) { return !done; }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(BufferMappingCallbackTests, EmptySubmissionAndThenMap) {
|
||||||
|
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||||
|
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize);
|
||||||
|
buffer.Unmap();
|
||||||
|
|
||||||
|
std::vector<bool> done = {false, false};
|
||||||
|
|
||||||
|
// 1. submission without using buffer.
|
||||||
|
SubmitCommandBuffer({});
|
||||||
|
queue.OnSubmittedWorkDone(
|
||||||
|
0,
|
||||||
|
[](WGPUQueueWorkDoneStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUQueueWorkDoneStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[0] = true;
|
||||||
|
// Step 2 callback should be called first, this is the second.
|
||||||
|
const std::vector<bool> kExpected = {true, true};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
// 2.
|
||||||
|
buffer.MapAsync(
|
||||||
|
wgpu::MapMode::Write, 0, 4,
|
||||||
|
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[1] = true;
|
||||||
|
// The buffer is not used by step 1, so this callback is called first.
|
||||||
|
const std::vector<bool> kExpected = {false, true};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
Wait(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BufferMappingCallbackTests, UseTheBufferAndThenMap) {
|
||||||
|
wgpu::Buffer buffer = CreateMapWriteBuffer(4);
|
||||||
|
MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize);
|
||||||
|
buffer.Unmap();
|
||||||
|
|
||||||
|
std::vector<bool> done = {false, false};
|
||||||
|
|
||||||
|
// 1. Submit a command buffer which uses the buffer
|
||||||
|
SubmitCommandBuffer(buffer);
|
||||||
|
queue.OnSubmittedWorkDone(
|
||||||
|
0,
|
||||||
|
[](WGPUQueueWorkDoneStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUQueueWorkDoneStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[0] = true;
|
||||||
|
// This callback should be called first
|
||||||
|
const std::vector<bool> kExpected = {true, false};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
// 2.
|
||||||
|
buffer.MapAsync(
|
||||||
|
wgpu::MapMode::Write, 0, 4,
|
||||||
|
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[1] = true;
|
||||||
|
// The buffer is used by step 1, so this callback is called second.
|
||||||
|
const std::vector<bool> kExpected = {true, true};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
Wait(done);
|
||||||
|
|
||||||
|
buffer.Unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(BufferMappingCallbackTests, EmptySubmissionWriteAndThenMap) {
|
||||||
|
wgpu::Buffer buffer = CreateMapReadBuffer(4);
|
||||||
|
MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, wgpu::kWholeMapSize);
|
||||||
|
buffer.Unmap();
|
||||||
|
|
||||||
|
std::vector<bool> done = {false, false};
|
||||||
|
|
||||||
|
// 1. submission without using buffer.
|
||||||
|
SubmitCommandBuffer({});
|
||||||
|
queue.OnSubmittedWorkDone(
|
||||||
|
0,
|
||||||
|
[](WGPUQueueWorkDoneStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUQueueWorkDoneStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[0] = true;
|
||||||
|
// Step 2 callback should be called first, this is the second.
|
||||||
|
const std::vector<bool> kExpected = {true, false};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
int32_t data = 0x12345678;
|
||||||
|
queue.WriteBuffer(buffer, 0, &data, sizeof(data));
|
||||||
|
|
||||||
|
// 2.
|
||||||
|
buffer.MapAsync(
|
||||||
|
wgpu::MapMode::Read, 0, 4,
|
||||||
|
[](WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||||
|
EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Success);
|
||||||
|
auto& done = *static_cast<std::vector<bool>*>(userdata);
|
||||||
|
done[1] = true;
|
||||||
|
// The buffer is not used by step 1, so this callback is called first.
|
||||||
|
const std::vector<bool> kExpected = {true, true};
|
||||||
|
EXPECT_EQ(done, kExpected);
|
||||||
|
},
|
||||||
|
&done);
|
||||||
|
|
||||||
|
Wait(done);
|
||||||
|
|
||||||
|
buffer.Unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapAsync() will record pipeline barrier in pending command buffer with Vulkan.
|
||||||
|
// TODO(penghuang): enable this test for Vulkan.
|
||||||
|
DAWN_INSTANTIATE_TEST(BufferMappingCallbackTests, D3D12Backend(), MetalBackend());
|
||||||
|
|
||||||
class BufferMappedAtCreationTests : public DawnTest {
|
class BufferMappedAtCreationTests : public DawnTest {
|
||||||
protected:
|
protected:
|
||||||
static void MapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
|
static void MapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
|
||||||
|
|
Loading…
Reference in New Issue