Update resolveQuerySet for unavailable queries on D3D12

Now resolving unavailable queries is undefined behaviour on D3D12, it
might cause device hangs or removal. Update to just resolve available
part like Vulkan did, and clear the destination buffer to 0s for the
unavailable part.

Bug: dawn:973

Change-Id: I7cf6808d67179425b4883e8847c76daaf8444dc2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/59420
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
Li Hao 2021-07-26 14:34:47 +00:00 committed by Dawn LUCI CQ
parent a6057ac716
commit d812d57739
2 changed files with 88 additions and 8 deletions

View File

@ -258,6 +258,13 @@ namespace dawn_native { namespace d3d12 {
return false;
}
// TODO(crbug.com/dawn/1024): The before and after states must be different. Remove this
// workaround and use D3D12 states instead of WebGPU usages to manage the tracking of
// barrier state.
if (lastState == newState) {
return false;
}
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier->Transition.pResource = GetD3D12Resource();

View File

@ -16,6 +16,8 @@
#include "dawn_native/BindGroupTracker.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/DynamicUploader.h"
#include "dawn_native/Error.h"
#include "dawn_native/RenderBundle.h"
#include "dawn_native/d3d12/BindGroupD3D12.h"
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
@ -27,6 +29,7 @@
#include "dawn_native/d3d12/RenderPassBuilderD3D12.h"
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
#include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
#include "dawn_native/d3d12/StagingBufferD3D12.h"
#include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
#include "dawn_native/d3d12/UtilsD3D12.h"
@ -93,6 +96,63 @@ namespace dawn_native { namespace d3d12 {
cmd->queryIndex);
}
void RecordResolveQuerySetCmd(ID3D12GraphicsCommandList* commandList,
Device* device,
QuerySet* querySet,
uint32_t firstQuery,
uint32_t queryCount,
Buffer* destination,
uint64_t destinationOffset) {
const std::vector<bool>& availability = querySet->GetQueryAvailability();
auto currentIt = availability.begin() + firstQuery;
auto lastIt = availability.begin() + firstQuery + queryCount;
// Traverse available queries in the range of [firstQuery, firstQuery + queryCount - 1]
while (currentIt != lastIt) {
auto firstTrueIt = std::find(currentIt, lastIt, true);
// No available query found for resolving
if (firstTrueIt == lastIt) {
break;
}
auto nextFalseIt = std::find(firstTrueIt, lastIt, false);
// The query index of firstTrueIt where the resolving starts
uint32_t resolveQueryIndex = std::distance(availability.begin(), firstTrueIt);
// The queries count between firstTrueIt and nextFalseIt need to be resolved
uint32_t resolveQueryCount = std::distance(firstTrueIt, nextFalseIt);
// Calculate destinationOffset based on the current resolveQueryIndex and firstQuery
uint32_t resolveDestinationOffset =
destinationOffset + (resolveQueryIndex - firstQuery) * sizeof(uint64_t);
// Resolve the queries between firstTrueIt and nextFalseIt (which is at most lastIt)
commandList->ResolveQueryData(
querySet->GetQueryHeap(), D3D12QueryType(querySet->GetQueryType()),
resolveQueryIndex, resolveQueryCount, destination->GetD3D12Resource(),
resolveDestinationOffset);
// Set current iterator to next false
currentIt = nextFalseIt;
}
}
MaybeError ClearBufferToZero(Device* device,
Buffer* destination,
uint64_t destinationOffset,
uint64_t size) {
DynamicUploader* uploader = device->GetDynamicUploader();
UploadHandle uploadHandle;
DAWN_TRY_ASSIGN(uploadHandle,
uploader->Allocate(size, device->GetPendingCommandSerial(),
kCopyBufferToBufferOffsetAlignment));
memset(uploadHandle.mappedBuffer, 0u, size);
return device->CopyFromStagingToBuffer(uploadHandle.stagingBuffer,
uploadHandle.startOffset, destination,
destinationOffset, size);
}
void RecordFirstIndexOffset(ID3D12GraphicsCommandList* commandList,
RenderPipeline* pipeline,
uint32_t firstVertex,
@ -840,18 +900,31 @@ namespace dawn_native { namespace d3d12 {
case Command::ResolveQuerySet: {
ResolveQuerySetCmd* cmd = mCommands.NextCommand<ResolveQuerySetCmd>();
QuerySet* querySet = ToBackend(cmd->querySet.Get());
uint32_t firstQuery = cmd->firstQuery;
uint32_t queryCount = cmd->queryCount;
Buffer* destination = ToBackend(cmd->destination.Get());
uint64_t destinationOffset = cmd->destinationOffset;
DAWN_TRY(destination->EnsureDataInitializedAsDestination(
commandContext, cmd->destinationOffset,
cmd->queryCount * sizeof(uint64_t)));
destination->TrackUsageAndTransitionNow(commandContext,
wgpu::BufferUsage::CopyDst);
commandContext, destinationOffset, queryCount * sizeof(uint64_t)));
commandList->ResolveQueryData(
querySet->GetQueryHeap(), D3D12QueryType(querySet->GetQueryType()),
cmd->firstQuery, cmd->queryCount, destination->GetD3D12Resource(),
cmd->destinationOffset);
// Resolving unavailable queries is undefined behaviour on D3D12, we only can
// resolve the available part of sparse queries. In order to resolve the
// unavailables as 0s, we need to clear the resolving region of the destination
// buffer to 0s.
auto startIt = querySet->GetQueryAvailability().begin() + firstQuery;
auto endIt = querySet->GetQueryAvailability().begin() + firstQuery + queryCount;
bool hasUnavailableQueries = std::find(startIt, endIt, false) != endIt;
if (hasUnavailableQueries) {
DAWN_TRY(ClearBufferToZero(device, destination, destinationOffset,
queryCount * sizeof(uint64_t)));
}
destination->TrackUsageAndTransitionNow(commandContext,
wgpu::BufferUsage::QueryResolve);
RecordResolveQuerySetCmd(commandList, device, querySet, firstQuery, queryCount,
destination, destinationOffset);
break;
}