Byte counting WriteBuffer/Texture to submit

Only tag to submit when the total size is larger than the threshold,
so that we can make as few submits as possible meanwhile avoiding OOM.

Bug: chromium:1258986
Change-Id: I7190e1bb942bfaffc5cd424ce4743173735b25e3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106418
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
This commit is contained in:
jchen10 2022-11-03 09:58:59 +00:00 committed by Dawn LUCI CQ
parent e8dd681f19
commit 61d6d21091
22 changed files with 292 additions and 149 deletions

View File

@ -1918,4 +1918,28 @@ ExecutionSerial DeviceBase::GetScheduledWorkDoneSerial() const {
return HasPendingCommands() ? GetPendingCommandSerial() : GetLastSubmittedCommandSerial();
}
MaybeError DeviceBase::CopyFromStagingToBuffer(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) {
DAWN_TRY(
CopyFromStagingToBufferImpl(source, sourceOffset, destination, destinationOffset, size));
if (GetDynamicUploader()->ShouldFlush()) {
ForceEventualFlushOfCommands();
}
return {};
}
MaybeError DeviceBase::CopyFromStagingToTexture(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
DAWN_TRY(CopyFromStagingToTextureImpl(source, src, dst, copySizePixels));
if (GetDynamicUploader()->ShouldFlush()) {
ForceEventualFlushOfCommands();
}
return {};
}
} // namespace dawn::native

View File

@ -298,15 +298,15 @@ class DeviceBase : public RefCountedWithExternalCount {
void StoreCachedBlob(const CacheKey& key, const Blob& blob);
virtual ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) = 0;
virtual MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) = 0;
virtual MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
uint64_t size);
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) = 0;
const Extent3D& copySizePixels);
DynamicUploader* GetDynamicUploader() const;
@ -405,6 +405,15 @@ class DeviceBase : public RefCountedWithExternalCount {
// The serial by which time all currently submitted or pending operations will be completed.
ExecutionSerial GetScheduledWorkDoneSerial() const;
// For the commands being internally recorded in backend, that were not urgent to submit, this
// method makes them to be submitted as soon as possbile in next ticks.
virtual void ForceEventualFlushOfCommands() = 0;
// In the 'Normal' mode, currently recorded commands in the backend normally will be actually
// submitted in the next Tick. However in the 'Passive' mode, the submission will be postponed
// as late as possible, for example, until the client has explictly issued a submission.
enum class SubmitMode { Normal, Passive };
protected:
// Constructor used only for mocking and testing.
DeviceBase();
@ -515,6 +524,16 @@ class DeviceBase : public RefCountedWithExternalCount {
// Indicates whether the backend has pending commands to be submitted as soon as possible.
virtual bool HasPendingCommands() const = 0;
virtual MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) = 0;
virtual MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) = 0;
wgpu::ErrorCallback mUncapturedErrorCallback = nullptr;
void* mUncapturedErrorUserdata = nullptr;

View File

@ -126,4 +126,25 @@ ResultOrError<UploadHandle> DynamicUploader::Allocate(uint64_t allocationSize,
uploadHandle.startOffset += additionalOffset;
return uploadHandle;
}
bool DynamicUploader::ShouldFlush() {
uint64_t kTotalAllocatedSizeThreshold = 64 * 1024 * 1024;
// We use total allocated size instead of pending-upload size to prevent Dawn from allocating
// too much GPU memory so that the risk of OOM can be minimized.
return GetTotalAllocatedSize() > kTotalAllocatedSizeThreshold;
}
uint64_t DynamicUploader::GetTotalAllocatedSize() {
uint64_t size = 0;
for (const auto& buffer : mReleasedStagingBuffers.IterateAll()) {
size += buffer->GetSize();
}
for (const auto& buffer : mRingBuffers) {
if (buffer->mStagingBuffer != nullptr) {
size += buffer->mStagingBuffer->GetSize();
}
}
return size;
}
} // namespace dawn::native

View File

@ -49,8 +49,11 @@ class DynamicUploader {
uint64_t offsetAlignment);
void Deallocate(ExecutionSerial lastCompletedSerial);
bool ShouldFlush();
private:
static constexpr uint64_t kRingBufferSize = 4 * 1024 * 1024;
uint64_t GetTotalAllocatedSize();
struct RingBuffer {
std::unique_ptr<StagingBufferBase> mStagingBuffer;

View File

@ -225,6 +225,7 @@ void QueueBase::APIOnSubmittedWorkDone(uint64_t signalValue,
}
void QueueBase::TrackTask(std::unique_ptr<TrackTaskCallback> task) {
GetDevice()->ForceEventualFlushOfCommands();
// we can move the task to the callback task manager, as it's ready to be called if there are no
// scheduled commands.
if (!GetDevice()->HasScheduledCommands()) {

View File

@ -488,7 +488,7 @@ MaybeError Buffer::ClearBuffer(CommandRecordingContext* commandContext,
memset(uploadHandle.mappedBuffer, clearValue, size);
device->CopyFromStagingToBufferImpl(commandContext, uploadHandle.stagingBuffer,
device->CopyFromStagingToBufferHelper(commandContext, uploadHandle.stagingBuffer,
uploadHandle.startOffset, this, offset, size);
}

View File

@ -60,6 +60,7 @@ MaybeError CommandRecordingContext::Open(ID3D12Device* d3d12Device,
}
mIsOpen = true;
mNeedsSubmit = false;
return {};
}
@ -128,6 +129,7 @@ MaybeError CommandRecordingContext::ExecuteCommandList(Device* device) {
}
mIsOpen = false;
mNeedsSubmit = false;
mSharedTextures.clear();
mHeapsPendingUsage.clear();
mTempBuffers.clear();
@ -162,6 +164,7 @@ void CommandRecordingContext::Release() {
mD3d12CommandList.Reset();
mD3d12CommandList4.Reset();
mIsOpen = false;
mNeedsSubmit = false;
mSharedTextures.clear();
mHeapsPendingUsage.clear();
mTempBuffers.clear();
@ -171,6 +174,14 @@ bool CommandRecordingContext::IsOpen() const {
return mIsOpen;
}
bool CommandRecordingContext::NeedsSubmit() const {
return mNeedsSubmit;
}
void CommandRecordingContext::SetNeedsSubmit() {
mNeedsSubmit = true;
}
void CommandRecordingContext::AddToTempBuffers(Ref<Buffer> tempBuffer) {
mTempBuffers.emplace_back(tempBuffer);
}

View File

@ -37,6 +37,8 @@ class CommandRecordingContext {
ID3D12GraphicsCommandList4* GetCommandList4() const;
void Release();
bool IsOpen() const;
bool NeedsSubmit() const;
void SetNeedsSubmit();
MaybeError ExecuteCommandList(Device* device);
@ -48,6 +50,7 @@ class CommandRecordingContext {
ComPtr<ID3D12GraphicsCommandList> mD3d12CommandList;
ComPtr<ID3D12GraphicsCommandList4> mD3d12CommandList4;
bool mIsOpen = false;
bool mNeedsSubmit = false;
std::set<Texture*> mSharedTextures;
std::vector<Heap*> mHeapsPendingUsage;

View File

@ -274,12 +274,16 @@ ResidencyManager* Device::GetResidencyManager() const {
return mResidencyManager.get();
}
ResultOrError<CommandRecordingContext*> Device::GetPendingCommandContext() {
ResultOrError<CommandRecordingContext*> Device::GetPendingCommandContext(
Device::SubmitMode submitMode) {
// Callers of GetPendingCommandList do so to record commands. Only reserve a command
// allocator when it is needed so we don't submit empty command lists
if (!mPendingCommands.IsOpen()) {
DAWN_TRY(mPendingCommands.Open(mD3d12Device.Get(), mCommandAllocatorManager.get()));
}
if (submitMode == Device::SubmitMode::Normal) {
mPendingCommands.SetNeedsSubmit();
}
return &mPendingCommands;
}
@ -309,7 +313,7 @@ MaybeError Device::ClearBufferToZero(CommandRecordingContext* commandContext,
memset(uploadHandle.mappedBuffer, 0u, kZeroBufferSize);
CopyFromStagingToBufferImpl(commandContext, uploadHandle.stagingBuffer,
CopyFromStagingToBufferHelper(commandContext, uploadHandle.stagingBuffer,
uploadHandle.startOffset, mZeroBuffer.Get(), 0,
kZeroBufferSize);
@ -346,7 +350,7 @@ MaybeError Device::TickImpl() {
mDepthStencilViewAllocator->Tick(completedSerial);
mUsedComObjectRefs.ClearUpTo(completedSerial);
if (mPendingCommands.IsOpen()) {
if (mPendingCommands.IsOpen() && mPendingCommands.NeedsSubmit()) {
DAWN_TRY(ExecutePendingCommandContext());
DAWN_TRY(NextSerial());
}
@ -401,7 +405,13 @@ void Device::ReferenceUntilUnused(ComPtr<IUnknown> object) {
}
bool Device::HasPendingCommands() const {
return mPendingCommands.IsOpen();
return mPendingCommands.NeedsSubmit();
}
void Device::ForceEventualFlushOfCommands() {
if (mPendingCommands.IsOpen()) {
mPendingCommands.SetNeedsSubmit();
}
}
MaybeError Device::ExecutePendingCommandContext() {
@ -484,13 +494,13 @@ ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(si
return std::move(stagingBuffer);
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError Device::CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) {
CommandRecordingContext* commandRecordingContext;
DAWN_TRY_ASSIGN(commandRecordingContext, GetPendingCommandContext());
DAWN_TRY_ASSIGN(commandRecordingContext, GetPendingCommandContext(Device::SubmitMode::Passive));
Buffer* dstBuffer = ToBackend(destination);
@ -499,13 +509,13 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
commandRecordingContext, destinationOffset, size));
DAWN_UNUSED(cleared);
CopyFromStagingToBufferImpl(commandRecordingContext, source, sourceOffset, destination,
CopyFromStagingToBufferHelper(commandRecordingContext, source, sourceOffset, destination,
destinationOffset, size);
return {};
}
void Device::CopyFromStagingToBufferImpl(CommandRecordingContext* commandContext,
void Device::CopyFromStagingToBufferHelper(CommandRecordingContext* commandContext,
StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
@ -521,12 +531,12 @@ void Device::CopyFromStagingToBufferImpl(CommandRecordingContext* commandContext
sourceOffset, size);
}
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError Device::CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
CommandRecordingContext* commandContext;
DAWN_TRY_ASSIGN(commandContext, GetPendingCommandContext());
DAWN_TRY_ASSIGN(commandContext, GetPendingCommandContext(Device::SubmitMode::Passive));
Texture* texture = ToBackend(dst->texture.Get());
SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySizePixels);

View File

@ -77,7 +77,8 @@ class Device final : public DeviceBase {
ComPtr<IDxcCompiler> GetDxcCompiler() const;
ComPtr<IDxcValidator> GetDxcValidator() const;
ResultOrError<CommandRecordingContext*> GetPendingCommandContext();
ResultOrError<CommandRecordingContext*> GetPendingCommandContext(
Device::SubmitMode submitMode = Device::SubmitMode::Normal);
MaybeError ClearBufferToZero(CommandRecordingContext* commandContext,
BufferBase* destination,
@ -91,23 +92,25 @@ class Device final : public DeviceBase {
void ReferenceUntilUnused(ComPtr<IUnknown> object);
void ForceEventualFlushOfCommands() override;
MaybeError ExecutePendingCommandContext();
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
void CopyFromStagingToBufferImpl(CommandRecordingContext* commandContext,
void CopyFromStagingToBufferHelper(CommandRecordingContext* commandContext,
StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size);
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) override;

View File

@ -30,6 +30,8 @@ class CommandRecordingContext : NonMovable {
~CommandRecordingContext();
id<MTLCommandBuffer> GetCommands();
void SetNeedsSubmit();
bool NeedsSubmit() const;
void MarkUsed();
bool WasUsed() const;
@ -59,6 +61,7 @@ class CommandRecordingContext : NonMovable {
NSPRef<id<MTLComputeCommandEncoder>> mCompute;
NSPRef<id<MTLRenderCommandEncoder>> mRender;
bool mInEncoder = false;
bool mNeedsSubmit = false;
bool mUsed = false;
};

View File

@ -29,6 +29,13 @@ id<MTLCommandBuffer> CommandRecordingContext::GetCommands() {
return mCommands.Get();
}
void CommandRecordingContext::SetNeedsSubmit() {
mNeedsSubmit = true;
}
bool CommandRecordingContext::NeedsSubmit() const {
return mNeedsSubmit;
}
void CommandRecordingContext::MarkUsed() {
mUsed = true;
}
@ -38,6 +45,7 @@ bool CommandRecordingContext::WasUsed() const {
MaybeError CommandRecordingContext::PrepareNextCommandBuffer(id<MTLCommandQueue> queue) {
ASSERT(mCommands == nil);
ASSERT(!mNeedsSubmit);
ASSERT(!mUsed);
// The MTLCommandBuffer will be autoreleased by default.
@ -58,6 +66,7 @@ NSPRef<id<MTLCommandBuffer>> CommandRecordingContext::AcquireCommands() {
}
ASSERT(!mInEncoder);
mNeedsSubmit = false;
mUsed = false;
return std::move(mCommands);
}

View File

@ -49,7 +49,8 @@ class Device final : public DeviceBase {
id<MTLDevice> GetMTLDevice();
id<MTLCommandQueue> GetMTLQueue();
CommandRecordingContext* GetPendingCommandContext();
CommandRecordingContext* GetPendingCommandContext(
Device::SubmitMode submitMode = Device::SubmitMode::Normal);
MaybeError SubmitPendingCommandBuffer();
Ref<Texture> CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
@ -57,12 +58,12 @@ class Device final : public DeviceBase {
void WaitForCommandsToBeScheduled();
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& dataLayout,
TextureCopy* dst,
const Extent3D& copySizePixels) override;
@ -79,6 +80,8 @@ class Device final : public DeviceBase {
// single-byte buffer
id<MTLBuffer> GetDummyBlitMtlBuffer();
void ForceEventualFlushOfCommands() override;
private:
Device(AdapterBase* adapter,
NSPRef<id<MTLDevice>> mtlDevice,

View File

@ -343,7 +343,9 @@ ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
}
MaybeError Device::TickImpl() {
if (mCommandContext.NeedsSubmit()) {
DAWN_TRY(SubmitPendingCommandBuffer());
}
// Just run timestamp period calculation when timestamp feature is enabled and timestamp
// conversion is not disabled.
@ -366,17 +368,26 @@ id<MTLCommandQueue> Device::GetMTLQueue() {
return mCommandQueue.Get();
}
CommandRecordingContext* Device::GetPendingCommandContext() {
CommandRecordingContext* Device::GetPendingCommandContext(Device::SubmitMode submitMode) {
if (submitMode == DeviceBase::SubmitMode::Normal) {
mCommandContext.SetNeedsSubmit();
}
mCommandContext.MarkUsed();
return &mCommandContext;
}
bool Device::HasPendingCommands() const {
return mCommandContext.WasUsed();
return mCommandContext.NeedsSubmit();
}
void Device::ForceEventualFlushOfCommands() {
if (mCommandContext.WasUsed()) {
mCommandContext.SetNeedsSubmit();
}
}
MaybeError Device::SubmitPendingCommandBuffer() {
if (!mCommandContext.WasUsed()) {
if (!mCommandContext.NeedsSubmit()) {
return {};
}
@ -428,7 +439,7 @@ ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(si
return std::move(stagingBuffer);
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError Device::CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
@ -438,11 +449,13 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
ASSERT(size != 0);
ToBackend(destination)
->EnsureDataInitializedAsDestination(GetPendingCommandContext(), destinationOffset, size);
->EnsureDataInitializedAsDestination(
GetPendingCommandContext(DeviceBase::SubmitMode::Passive), destinationOffset, size);
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetBufferHandle();
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
[GetPendingCommandContext()->EnsureBlit() copyFromBuffer:uploadBuffer
[GetPendingCommandContext(DeviceBase::SubmitMode::Passive)->EnsureBlit()
copyFromBuffer:uploadBuffer
sourceOffset:sourceOffset
toBuffer:buffer
destinationOffset:destinationOffset
@ -453,17 +466,18 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
// In Metal we don't write from the CPU to the texture directly which can be done using the
// replaceRegion function, because the function requires a non-private storage mode and Dawn
// sets the private storage mode by default for all textures except IOSurfaces on macOS.
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError Device::CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& dataLayout,
TextureCopy* dst,
const Extent3D& copySizePixels) {
Texture* texture = ToBackend(dst->texture.Get());
EnsureDestinationTextureInitialized(GetPendingCommandContext(), texture, *dst, copySizePixels);
EnsureDestinationTextureInitialized(GetPendingCommandContext(DeviceBase::SubmitMode::Passive),
texture, *dst, copySizePixels);
RecordCopyBufferToTexture(GetPendingCommandContext(), ToBackend(source)->GetBufferHandle(),
source->GetSize(), dataLayout.offset, dataLayout.bytesPerRow,
dataLayout.rowsPerImage, texture, dst->mipLevel, dst->origin,
dst->aspect, copySizePixels);
RecordCopyBufferToTexture(GetPendingCommandContext(DeviceBase::SubmitMode::Passive),
ToBackend(source)->GetBufferHandle(), source->GetSize(),
dataLayout.offset, dataLayout.bytesPerRow, dataLayout.rowsPerImage,
texture, dst->mipLevel, dst->origin, dst->aspect, copySizePixels);
return {};
}

View File

@ -217,7 +217,7 @@ bool Device::HasPendingCommands() const {
return false;
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError Device::CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
@ -238,7 +238,7 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
return {};
}
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError Device::CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
@ -556,6 +556,8 @@ float Device::GetTimestampPeriodInNS() const {
return 1.0f;
}
void Device::ForceEventualFlushOfCommands() {}
Texture::Texture(DeviceBase* device, const TextureDescriptor* descriptor, TextureState state)
: TextureBase(device, descriptor, state) {}

View File

@ -106,12 +106,12 @@ class Device final : public DeviceBase {
MaybeError SubmitPendingOperations();
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) override;
@ -124,6 +124,8 @@ class Device final : public DeviceBase {
float GetTimestampPeriodInNS() const override;
void ForceEventualFlushOfCommands() override;
private:
using DeviceBase::DeviceBase;

View File

@ -418,7 +418,7 @@ ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(si
return DAWN_UNIMPLEMENTED_ERROR("Device unable to create staging buffer.");
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError Device::CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
@ -426,7 +426,7 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer.");
}
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError Device::CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
@ -464,6 +464,8 @@ float Device::GetTimestampPeriodInNS() const {
return 1.0f;
}
void Device::ForceEventualFlushOfCommands() {}
const OpenGLFunctions& Device::GetGL() const {
if (mContext) {
mContext->MakeCurrent();

View File

@ -68,13 +68,13 @@ class Device final : public DeviceBase {
MaybeError TickImpl() override;
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) override;
@ -83,6 +83,7 @@ class Device final : public DeviceBase {
uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
float GetTimestampPeriodInNS() const override;
void ForceEventualFlushOfCommands() override;
class Context {
public:

View File

@ -40,6 +40,7 @@ struct CommandRecordingContext {
// For Device state tracking only.
VkCommandPool commandPool = VK_NULL_HANDLE;
bool needsSubmit = false;
bool used = false;
// In some cases command buffer will need to be split to accomodate driver bug workarounds.

View File

@ -230,7 +230,7 @@ MaybeError Device::TickImpl() {
mDeleter->Tick(completedSerial);
mDescriptorAllocatorsPendingDeallocation.ClearUpTo(completedSerial);
if (mRecordingContext.used) {
if (mRecordingContext.needsSubmit) {
DAWN_TRY(SubmitPendingCommands());
}
@ -282,18 +282,23 @@ void Device::EnqueueDeferredDeallocation(DescriptorSetAllocator* allocator) {
mDescriptorAllocatorsPendingDeallocation.Enqueue(allocator, GetPendingCommandSerial());
}
CommandRecordingContext* Device::GetPendingRecordingContext() {
CommandRecordingContext* Device::GetPendingRecordingContext(Device::SubmitMode submitMode) {
ASSERT(mRecordingContext.commandBuffer != VK_NULL_HANDLE);
mRecordingContext.needsSubmit |= (submitMode == DeviceBase::SubmitMode::Normal);
mRecordingContext.used = true;
return &mRecordingContext;
}
bool Device::HasPendingCommands() const {
return mRecordingContext.used;
return mRecordingContext.needsSubmit;
}
void Device::ForceEventualFlushOfCommands() {
mRecordingContext.needsSubmit |= mRecordingContext.used;
}
MaybeError Device::SubmitPendingCommands() {
if (!mRecordingContext.used) {
if (!mRecordingContext.needsSubmit) {
return {};
}
@ -705,7 +710,7 @@ ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
}
MaybeError Device::PrepareRecordingContext() {
ASSERT(!mRecordingContext.used);
ASSERT(!mRecordingContext.needsSubmit);
ASSERT(mRecordingContext.commandBuffer == VK_NULL_HANDLE);
ASSERT(mRecordingContext.commandPool == VK_NULL_HANDLE);
@ -812,7 +817,7 @@ ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(si
return std::move(stagingBuffer);
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError Device::CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
@ -821,7 +826,8 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
// calling this function.
ASSERT(size != 0);
CommandRecordingContext* recordingContext = GetPendingRecordingContext();
CommandRecordingContext* recordingContext =
GetPendingRecordingContext(DeviceBase::SubmitMode::Passive);
ToBackend(destination)
->EnsureDataInitializedAsDestination(recordingContext, destinationOffset, size);
@ -845,7 +851,7 @@ MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
return {};
}
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError Device::CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
@ -853,7 +859,8 @@ MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
// operation for HOST_COHERENT memory. The Vulkan spec for vkQueueSubmit describes that it
// does an implicit availability, visibility and domain operation.
CommandRecordingContext* recordingContext = GetPendingRecordingContext();
CommandRecordingContext* recordingContext =
GetPendingRecordingContext(DeviceBase::SubmitMode::Passive);
VkBufferImageCopy region = ComputeBufferImageCopyRegion(src, *dst, copySizePixels);
VkImageSubresourceLayers subresource = region.imageSubresource;
@ -1118,7 +1125,7 @@ void Device::DestroyImpl() {
ToBackend(GetAdapter())->GetVulkanInstance()->StopListeningForDeviceMessages(this);
// Immediately tag the recording context as unused so we don't try to submit it in Tick.
mRecordingContext.used = false;
mRecordingContext.needsSubmit = false;
if (mRecordingContext.commandPool != VK_NULL_HANDLE) {
// The VkCommandBuffer memory should be wholly owned by the pool and freed when it is
// destroyed, but that's not the case in some drivers and the leak memory.

View File

@ -65,7 +65,8 @@ class Device final : public DeviceBase {
ResourceMemoryAllocator* GetResourceMemoryAllocator() const;
external_semaphore::Service* GetExternalSemaphoreService() const;
CommandRecordingContext* GetPendingRecordingContext();
CommandRecordingContext* GetPendingRecordingContext(
Device::SubmitMode submitMode = Device::SubmitMode::Normal);
MaybeError SplitRecordingContext(CommandRecordingContext* recordingContext);
MaybeError SubmitPendingCommands();
@ -89,12 +90,12 @@ class Device final : public DeviceBase {
MaybeError TickImpl() override;
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
MaybeError CopyFromStagingToBufferImpl(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
MaybeError CopyFromStagingToTextureImpl(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) override;
@ -115,6 +116,8 @@ class Device final : public DeviceBase {
// Used to associate this device with validation layer messages.
const char* GetDebugPrefix() { return mDebugPrefix.c_str(); }
void ForceEventualFlushOfCommands() override;
private:
Device(Adapter* adapter,
const DeviceDescriptor* descriptor,

View File

@ -39,11 +39,11 @@ class DeviceMock : public DeviceBase {
(size_t),
(override));
MOCK_METHOD(MaybeError,
CopyFromStagingToBuffer,
CopyFromStagingToBufferImpl,
(StagingBufferBase*, uint64_t, BufferBase*, uint64_t, uint64_t),
(override));
MOCK_METHOD(MaybeError,
CopyFromStagingToTexture,
CopyFromStagingToTextureImpl,
(const StagingBufferBase*, const TextureDataLayout&, TextureCopy*, const Extent3D&),
(override));
@ -51,6 +51,7 @@ class DeviceMock : public DeviceBase {
MOCK_METHOD(uint64_t, GetOptimalBufferToTextureCopyOffsetAlignment, (), (const, override));
MOCK_METHOD(float, GetTimestampPeriodInNS, (), (const, override));
MOCK_METHOD(void, ForceEventualFlushOfCommands, (), (override));
MOCK_METHOD(ResultOrError<Ref<BindGroupBase>>,
CreateBindGroupImpl,