2018-07-18 09:40:26 +00:00
|
|
|
// Copyright 2017 The Dawn Authors
|
2017-04-20 18:38:20 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2018-07-24 11:53:51 +00:00
|
|
|
#include "dawn_native/Queue.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2018-11-07 10:02:43 +00:00
|
|
|
#include "dawn_native/Buffer.h"
|
2018-07-24 11:53:51 +00:00
|
|
|
#include "dawn_native/CommandBuffer.h"
|
2020-07-08 18:42:30 +00:00
|
|
|
#include "dawn_native/CommandValidation.h"
|
2018-07-24 11:53:51 +00:00
|
|
|
#include "dawn_native/Device.h"
|
2020-06-02 09:24:39 +00:00
|
|
|
#include "dawn_native/DynamicUploader.h"
|
2019-09-17 18:24:07 +00:00
|
|
|
#include "dawn_native/ErrorScope.h"
|
|
|
|
#include "dawn_native/ErrorScopeTracker.h"
|
2018-12-03 16:57:34 +00:00
|
|
|
#include "dawn_native/Fence.h"
|
|
|
|
#include "dawn_native/FenceSignalTracker.h"
|
2020-07-01 10:48:16 +00:00
|
|
|
#include "dawn_native/QuerySet.h"
|
2018-11-07 10:02:43 +00:00
|
|
|
#include "dawn_native/Texture.h"
|
2019-10-28 23:15:40 +00:00
|
|
|
#include "dawn_platform/DawnPlatform.h"
|
2019-08-13 19:00:34 +00:00
|
|
|
#include "dawn_platform/tracing/TraceEvent.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2020-06-03 13:36:15 +00:00
|
|
|
#include <cstring>
|
|
|
|
|
2018-07-24 14:45:45 +00:00
|
|
|
namespace dawn_native {
|
2017-04-20 18:38:20 +00:00
|
|
|
|
|
|
|
// QueueBase
|
|
|
|
|
2018-10-15 12:54:30 +00:00
|
|
|
QueueBase::QueueBase(DeviceBase* device) : ObjectBase(device) {
|
2017-05-10 13:30:05 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 21:32:08 +00:00
|
|
|
QueueBase::QueueBase(DeviceBase* device, ObjectBase::ErrorTag tag) : ObjectBase(device, tag) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
QueueBase* QueueBase::MakeError(DeviceBase* device) {
|
|
|
|
return new QueueBase(device, ObjectBase::kError);
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError QueueBase::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) {
|
|
|
|
UNREACHABLE();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-02-21 00:45:19 +00:00
|
|
|
void QueueBase::Submit(uint32_t commandCount, CommandBufferBase* const* commands) {
|
2019-09-17 18:24:07 +00:00
|
|
|
DeviceBase* device = GetDevice();
|
2020-01-15 19:02:13 +00:00
|
|
|
if (device->ConsumedError(device->ValidateIsAlive())) {
|
|
|
|
// If device is lost, don't let any commands be submitted
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-28 23:15:40 +00:00
|
|
|
TRACE_EVENT0(device->GetPlatform(), General, "Queue::Submit");
|
2019-11-21 22:09:41 +00:00
|
|
|
if (device->IsValidationEnabled() &&
|
|
|
|
device->ConsumedError(ValidateSubmit(commandCount, commands))) {
|
2018-08-01 13:12:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2018-08-01 13:12:10 +00:00
|
|
|
|
2019-09-23 21:21:10 +00:00
|
|
|
if (device->ConsumedError(SubmitImpl(commandCount, commands))) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-17 18:24:07 +00:00
|
|
|
device->GetErrorScopeTracker()->TrackUntilLastSubmitComplete(
|
|
|
|
device->GetCurrentErrorScope());
|
2018-08-01 13:12:10 +00:00
|
|
|
}
|
|
|
|
|
2019-11-13 17:00:37 +00:00
|
|
|
void QueueBase::Signal(Fence* fence, uint64_t signalValue) {
|
2019-09-17 18:24:07 +00:00
|
|
|
DeviceBase* device = GetDevice();
|
|
|
|
if (device->ConsumedError(ValidateSignal(fence, signalValue))) {
|
2018-12-03 16:57:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2018-12-03 16:57:34 +00:00
|
|
|
|
|
|
|
fence->SetSignaledValue(signalValue);
|
2019-09-17 18:24:07 +00:00
|
|
|
device->GetFenceSignalTracker()->UpdateFenceOnComplete(fence, signalValue);
|
|
|
|
device->GetErrorScopeTracker()->TrackUntilLastSubmitComplete(
|
|
|
|
device->GetCurrentErrorScope());
|
2018-12-03 16:57:34 +00:00
|
|
|
}
|
|
|
|
|
2019-11-13 17:00:37 +00:00
|
|
|
Fence* QueueBase::CreateFence(const FenceDescriptor* descriptor) {
|
2019-03-06 22:42:22 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateCreateFence(descriptor))) {
|
2019-11-13 17:00:37 +00:00
|
|
|
return Fence::MakeError(GetDevice());
|
2019-03-06 22:42:22 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 20:29:22 +00:00
|
|
|
if (descriptor == nullptr) {
|
|
|
|
FenceDescriptor defaultDescriptor = {};
|
|
|
|
return new Fence(this, &defaultDescriptor);
|
|
|
|
}
|
2019-11-13 17:00:37 +00:00
|
|
|
return new Fence(this, descriptor);
|
2019-03-06 22:42:22 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 09:24:39 +00:00
|
|
|
void QueueBase::WriteBuffer(BufferBase* buffer,
|
|
|
|
uint64_t bufferOffset,
|
|
|
|
const void* data,
|
|
|
|
size_t size) {
|
|
|
|
GetDevice()->ConsumedError(WriteBufferInternal(buffer, bufferOffset, data, size));
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError QueueBase::WriteBufferInternal(BufferBase* buffer,
|
|
|
|
uint64_t bufferOffset,
|
|
|
|
const void* data,
|
|
|
|
size_t size) {
|
|
|
|
DAWN_TRY(ValidateWriteBuffer(buffer, bufferOffset, size));
|
|
|
|
return WriteBufferImpl(buffer, bufferOffset, data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError QueueBase::WriteBufferImpl(BufferBase* buffer,
|
|
|
|
uint64_t bufferOffset,
|
|
|
|
const void* data,
|
|
|
|
size_t size) {
|
2020-06-05 15:44:03 +00:00
|
|
|
if (size == 0) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-06-02 09:24:39 +00:00
|
|
|
DeviceBase* device = GetDevice();
|
|
|
|
|
|
|
|
UploadHandle uploadHandle;
|
|
|
|
DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
|
|
|
|
size, device->GetPendingCommandSerial()));
|
|
|
|
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
|
|
|
|
|
|
|
memcpy(uploadHandle.mappedBuffer, data, size);
|
|
|
|
|
2020-06-05 15:44:03 +00:00
|
|
|
return device->CopyFromStagingToBuffer(uploadHandle.stagingBuffer, uploadHandle.startOffset,
|
|
|
|
buffer, bufferOffset, size);
|
2020-06-02 09:24:39 +00:00
|
|
|
}
|
|
|
|
|
2020-07-08 18:42:30 +00:00
|
|
|
void QueueBase::WriteTexture(const TextureCopyView* destination,
|
|
|
|
const void* data,
|
|
|
|
size_t dataSize,
|
|
|
|
const TextureDataLayout* dataLayout,
|
|
|
|
const Extent3D* writeSize) {
|
|
|
|
GetDevice()->ConsumedError(
|
|
|
|
WriteTextureInternal(destination, data, dataSize, dataLayout, writeSize));
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError QueueBase::WriteTextureInternal(const TextureCopyView* destination,
|
|
|
|
const void* data,
|
|
|
|
size_t dataSize,
|
|
|
|
const TextureDataLayout* dataLayout,
|
|
|
|
const Extent3D* writeSize) {
|
|
|
|
DAWN_TRY(ValidateWriteTexture(destination, dataSize, dataLayout, writeSize));
|
2020-07-15 18:06:07 +00:00
|
|
|
|
|
|
|
if (writeSize->width == 0 || writeSize->height == 0 || writeSize->depth == 0) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-07-08 18:42:30 +00:00
|
|
|
return WriteTextureImpl(destination, data, dataSize, dataLayout, writeSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError QueueBase::WriteTextureImpl(const TextureCopyView* destination,
|
|
|
|
const void* data,
|
|
|
|
size_t dataSize,
|
|
|
|
const TextureDataLayout* dataLayout,
|
|
|
|
const Extent3D* writeSize) {
|
|
|
|
// TODO(tommek@google.com): This should be implemented.
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-02-21 00:45:19 +00:00
|
|
|
MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
|
2020-06-02 09:24:39 +00:00
|
|
|
CommandBufferBase* const* commands) const {
|
2019-10-28 23:15:40 +00:00
|
|
|
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "Queue::ValidateSubmit");
|
2019-02-13 13:09:18 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
|
2019-02-21 00:45:19 +00:00
|
|
|
for (uint32_t i = 0; i < commandCount; ++i) {
|
2019-02-14 18:13:47 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(commands[i]));
|
|
|
|
|
2018-11-07 10:02:43 +00:00
|
|
|
const CommandBufferResourceUsage& usages = commands[i]->GetResourceUsages();
|
|
|
|
|
|
|
|
for (const PassResourceUsage& passUsages : usages.perPass) {
|
|
|
|
for (const BufferBase* buffer : passUsages.buffers) {
|
2020-06-02 09:24:39 +00:00
|
|
|
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
2018-11-07 10:02:43 +00:00
|
|
|
}
|
|
|
|
for (const TextureBase* texture : passUsages.textures) {
|
|
|
|
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
2020-06-02 09:24:39 +00:00
|
|
|
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
2018-11-07 10:02:43 +00:00
|
|
|
}
|
|
|
|
for (const TextureBase* texture : usages.topLevelTextures) {
|
|
|
|
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
|
|
|
}
|
2020-07-01 10:48:16 +00:00
|
|
|
for (const QuerySetBase* querySet : usages.usedQuerySets) {
|
|
|
|
DAWN_TRY(querySet->ValidateCanUseInSubmitNow());
|
|
|
|
}
|
2018-11-07 10:02:43 +00:00
|
|
|
}
|
|
|
|
|
2018-07-16 16:20:09 +00:00
|
|
|
return {};
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 09:24:39 +00:00
|
|
|
MaybeError QueueBase::ValidateSignal(const Fence* fence, uint64_t signalValue) const {
|
2020-02-06 00:56:35 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
2019-02-13 13:09:18 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(fence));
|
2018-12-10 10:03:08 +00:00
|
|
|
|
2019-03-06 22:42:22 +00:00
|
|
|
if (fence->GetQueue() != this) {
|
|
|
|
return DAWN_VALIDATION_ERROR(
|
|
|
|
"Fence must be signaled on the queue on which it was created.");
|
|
|
|
}
|
2018-12-03 16:57:34 +00:00
|
|
|
if (signalValue <= fence->GetSignaledValue()) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Signal value less than or equal to fence signaled value");
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-06-02 09:24:39 +00:00
|
|
|
MaybeError QueueBase::ValidateCreateFence(const FenceDescriptor* descriptor) const {
|
2020-02-06 00:56:35 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
2019-03-06 22:42:22 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
2020-05-11 20:29:22 +00:00
|
|
|
if (descriptor != nullptr) {
|
|
|
|
DAWN_TRY(ValidateFenceDescriptor(descriptor));
|
|
|
|
}
|
2019-03-06 22:42:22 +00:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-06-02 09:24:39 +00:00
|
|
|
MaybeError QueueBase::ValidateWriteBuffer(const BufferBase* buffer,
|
|
|
|
uint64_t bufferOffset,
|
|
|
|
size_t size) const {
|
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
|
|
|
|
|
|
|
if (bufferOffset % 4 != 0) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Queue::WriteBuffer bufferOffset must be a multiple of 4");
|
|
|
|
}
|
|
|
|
if (size % 4 != 0) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Queue::WriteBuffer size must be a multiple of 4");
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t bufferSize = buffer->GetSize();
|
|
|
|
if (bufferOffset > bufferSize || size > (bufferSize - bufferOffset)) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Queue::WriteBuffer out of range");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(buffer->GetUsage() & wgpu::BufferUsage::CopyDst)) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer needs the CopyDst usage bit");
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer->ValidateCanUseOnQueueNow();
|
|
|
|
}
|
|
|
|
|
2020-07-08 18:42:30 +00:00
|
|
|
MaybeError QueueBase::ValidateWriteTexture(const TextureCopyView* destination,
|
|
|
|
size_t dataSize,
|
|
|
|
const TextureDataLayout* dataLayout,
|
|
|
|
const Extent3D* writeSize) const {
|
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
|
|
|
|
|
|
|
DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination));
|
|
|
|
|
|
|
|
if (dataLayout->offset > dataSize) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Queue::WriteTexture out of range");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(destination->texture->GetUsage() & wgpu::TextureUsage::CopyDst)) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Texture needs the CopyDst usage bit");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (destination->texture->GetSampleCount() > 1) {
|
|
|
|
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
DAWN_TRY(ValidateLinearTextureData(*dataLayout, dataSize, destination->texture->GetFormat(),
|
|
|
|
*writeSize));
|
|
|
|
DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize));
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:45:45 +00:00
|
|
|
} // namespace dawn_native
|