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/Buffer.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2017-07-10 17:46:05 +00:00
|
|
|
#include "common/Assert.h"
|
2018-07-24 11:53:51 +00:00
|
|
|
#include "dawn_native/Device.h"
|
2019-02-15 21:18:40 +00:00
|
|
|
#include "dawn_native/DynamicUploader.h"
|
2018-08-22 13:37:29 +00:00
|
|
|
#include "dawn_native/ValidationUtils_autogen.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
|
|
|
#include <cstdio>
|
2017-11-24 18:59:42 +00:00
|
|
|
#include <utility>
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2018-07-24 14:45:45 +00:00
|
|
|
namespace dawn_native {
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2019-02-13 13:09:18 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class ErrorBuffer : public BufferBase {
|
|
|
|
public:
|
|
|
|
ErrorBuffer(DeviceBase* device) : BufferBase(device, ObjectBase::kError) {
|
|
|
|
}
|
|
|
|
|
2019-05-15 18:55:22 +00:00
|
|
|
static ErrorBuffer* MakeMapped(DeviceBase* device,
|
|
|
|
uint64_t size,
|
|
|
|
uint8_t** mappedPointer) {
|
|
|
|
ASSERT(mappedPointer != nullptr);
|
|
|
|
|
|
|
|
ErrorBuffer* buffer = new ErrorBuffer(device);
|
|
|
|
buffer->mFakeMappedData = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
|
|
|
|
*mappedPointer = buffer->mFakeMappedData.get();
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
void ClearMappedData() {
|
|
|
|
mFakeMappedData.reset();
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:09:18 +00:00
|
|
|
private:
|
2019-06-05 18:35:31 +00:00
|
|
|
bool IsMapWritable() const override {
|
|
|
|
UNREACHABLE();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-05-15 18:55:22 +00:00
|
|
|
MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override {
|
|
|
|
UNREACHABLE();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-06-06 16:19:15 +00:00
|
|
|
MaybeError SetSubDataImpl(uint32_t start, uint32_t count, const void* data) override {
|
2019-02-13 13:09:18 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return {};
|
|
|
|
}
|
2019-02-14 19:31:17 +00:00
|
|
|
void MapReadAsyncImpl(uint32_t serial) override {
|
2019-02-13 13:09:18 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2019-02-14 19:31:17 +00:00
|
|
|
void MapWriteAsyncImpl(uint32_t serial) override {
|
2019-02-13 13:09:18 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
void UnmapImpl() override {
|
2019-06-05 18:35:31 +00:00
|
|
|
UNREACHABLE();
|
2019-02-13 13:09:18 +00:00
|
|
|
}
|
2019-03-11 17:05:22 +00:00
|
|
|
void DestroyImpl() override {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2019-05-15 18:55:22 +00:00
|
|
|
|
|
|
|
std::unique_ptr<uint8_t[]> mFakeMappedData;
|
2019-02-13 13:09:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2018-08-22 13:37:29 +00:00
|
|
|
MaybeError ValidateBufferDescriptor(DeviceBase*, const BufferDescriptor* descriptor) {
|
2018-09-10 14:17:24 +00:00
|
|
|
if (descriptor->nextInChain != nullptr) {
|
|
|
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
|
|
|
}
|
|
|
|
|
2018-08-22 13:37:29 +00:00
|
|
|
DAWN_TRY(ValidateBufferUsageBit(descriptor->usage));
|
|
|
|
|
|
|
|
dawn::BufferUsageBit usage = descriptor->usage;
|
|
|
|
|
|
|
|
const dawn::BufferUsageBit kMapWriteAllowedUsages =
|
|
|
|
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
|
|
|
|
if (usage & dawn::BufferUsageBit::MapWrite && (usage & kMapWriteAllowedUsages) != usage) {
|
2018-09-10 14:17:24 +00:00
|
|
|
return DAWN_VALIDATION_ERROR("Only TransferSrc is allowed with MapWrite");
|
2018-08-22 13:37:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const dawn::BufferUsageBit kMapReadAllowedUsages =
|
|
|
|
dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::TransferDst;
|
|
|
|
if (usage & dawn::BufferUsageBit::MapRead && (usage & kMapReadAllowedUsages) != usage) {
|
2018-09-10 14:17:24 +00:00
|
|
|
return DAWN_VALIDATION_ERROR("Only TransferDst is allowed with MapRead");
|
2018-08-22 13:37:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
// Buffer
|
|
|
|
|
2018-08-22 13:37:29 +00:00
|
|
|
BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor)
|
2019-02-13 21:26:48 +00:00
|
|
|
: ObjectBase(device),
|
|
|
|
mSize(descriptor->size),
|
|
|
|
mUsage(descriptor->usage),
|
|
|
|
mState(BufferState::Unmapped) {
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2019-02-13 21:26:48 +00:00
|
|
|
BufferBase::BufferBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
|
|
|
: ObjectBase(device, tag), mState(BufferState::Unmapped) {
|
2019-02-13 13:09:18 +00:00
|
|
|
}
|
|
|
|
|
2017-06-09 14:51:29 +00:00
|
|
|
BufferBase::~BufferBase() {
|
2019-02-13 21:26:48 +00:00
|
|
|
if (mState == BufferState::Mapped) {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2019-02-14 19:31:17 +00:00
|
|
|
CallMapReadCallback(mMapSerial, DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0u);
|
|
|
|
CallMapWriteCallback(mMapSerial, DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0u);
|
2017-06-09 14:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:09:18 +00:00
|
|
|
// static
|
|
|
|
BufferBase* BufferBase::MakeError(DeviceBase* device) {
|
|
|
|
return new ErrorBuffer(device);
|
|
|
|
}
|
|
|
|
|
2019-05-15 18:55:22 +00:00
|
|
|
// static
|
|
|
|
BufferBase* BufferBase::MakeErrorMapped(DeviceBase* device,
|
|
|
|
uint64_t size,
|
|
|
|
uint8_t** mappedPointer) {
|
|
|
|
return ErrorBuffer::MakeMapped(device, size, mappedPointer);
|
|
|
|
}
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
uint64_t BufferBase::GetSize() const {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2017-11-23 18:32:51 +00:00
|
|
|
return mSize;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 13:08:02 +00:00
|
|
|
dawn::BufferUsageBit BufferBase::GetUsage() const {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2018-08-22 13:08:02 +00:00
|
|
|
return mUsage;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 18:55:22 +00:00
|
|
|
MaybeError BufferBase::MapAtCreation(uint8_t** mappedPointer) {
|
|
|
|
ASSERT(!IsError());
|
|
|
|
ASSERT(mappedPointer != nullptr);
|
|
|
|
|
|
|
|
mState = BufferState::Mapped;
|
2019-06-05 18:35:31 +00:00
|
|
|
|
|
|
|
if (IsMapWritable()) {
|
|
|
|
DAWN_TRY(MapAtCreationImpl(mappedPointer));
|
|
|
|
ASSERT(*mappedPointer != nullptr);
|
|
|
|
return {};
|
2019-05-15 18:55:22 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
// If any of these fail, the buffer will be deleted and replaced with an
|
|
|
|
// error buffer.
|
|
|
|
// TODO(enga): Suballocate and reuse memory from a larger staging buffer so we don't create
|
|
|
|
// many small buffers.
|
|
|
|
DynamicUploader* uploader = nullptr;
|
|
|
|
DAWN_TRY_ASSIGN(uploader, GetDevice()->GetDynamicUploader());
|
|
|
|
DAWN_TRY_ASSIGN(mStagingBuffer, uploader->CreateStagingBuffer(GetSize()));
|
|
|
|
|
|
|
|
ASSERT(mStagingBuffer->GetMappedPointer() != nullptr);
|
|
|
|
*mappedPointer = reinterpret_cast<uint8_t*>(mStagingBuffer->GetMappedPointer());
|
2019-05-15 18:55:22 +00:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2018-11-07 10:02:43 +00:00
|
|
|
MaybeError BufferBase::ValidateCanUseInSubmitNow() const {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
|
|
|
|
2019-02-13 21:26:48 +00:00
|
|
|
switch (mState) {
|
|
|
|
case BufferState::Destroyed:
|
|
|
|
return DAWN_VALIDATION_ERROR("Destroyed buffer used in a submit");
|
|
|
|
case BufferState::Mapped:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer used in a submit while mapped");
|
|
|
|
case BufferState::Unmapped:
|
|
|
|
return {};
|
2018-11-07 10:02:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-24 18:59:42 +00:00
|
|
|
void BufferBase::CallMapReadCallback(uint32_t serial,
|
2019-03-11 16:52:42 +00:00
|
|
|
DawnBufferMapAsyncStatus status,
|
2019-02-14 19:31:17 +00:00
|
|
|
const void* pointer,
|
|
|
|
uint32_t dataLength) {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2018-03-21 00:56:39 +00:00
|
|
|
if (mMapReadCallback != nullptr && serial == mMapSerial) {
|
|
|
|
ASSERT(mMapWriteCallback == nullptr);
|
2018-03-20 23:11:41 +00:00
|
|
|
// Tag the callback as fired before firing it, otherwise it could fire a second time if
|
|
|
|
// for example buffer.Unmap() is called inside the application-provided callback.
|
2019-03-11 16:52:42 +00:00
|
|
|
DawnBufferMapReadCallback callback = mMapReadCallback;
|
2017-11-23 18:32:51 +00:00
|
|
|
mMapReadCallback = nullptr;
|
2019-02-14 19:31:17 +00:00
|
|
|
callback(status, pointer, dataLength, mMapUserdata);
|
2018-03-21 00:56:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BufferBase::CallMapWriteCallback(uint32_t serial,
|
2019-03-11 16:52:42 +00:00
|
|
|
DawnBufferMapAsyncStatus status,
|
2019-02-14 19:31:17 +00:00
|
|
|
void* pointer,
|
|
|
|
uint32_t dataLength) {
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2018-03-21 00:56:39 +00:00
|
|
|
if (mMapWriteCallback != nullptr && serial == mMapSerial) {
|
|
|
|
ASSERT(mMapReadCallback == nullptr);
|
|
|
|
// Tag the callback as fired before firing it, otherwise it could fire a second time if
|
|
|
|
// for example buffer.Unmap() is called inside the application-provided callback.
|
2019-03-11 16:52:42 +00:00
|
|
|
DawnBufferMapWriteCallback callback = mMapWriteCallback;
|
2018-03-21 00:56:39 +00:00
|
|
|
mMapWriteCallback = nullptr;
|
2019-02-14 19:31:17 +00:00
|
|
|
callback(status, pointer, dataLength, mMapUserdata);
|
2017-06-09 14:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 16:19:15 +00:00
|
|
|
void BufferBase::SetSubData(uint32_t start, uint32_t count, const void* data) {
|
2018-10-15 12:54:30 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateSetSubData(start, count))) {
|
2017-04-20 18:38:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2019-01-29 00:10:07 +00:00
|
|
|
if (GetDevice()->ConsumedError(SetSubDataImpl(start, count, data))) {
|
|
|
|
return;
|
|
|
|
}
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-29 13:03:50 +00:00
|
|
|
void BufferBase::MapReadAsync(DawnBufferMapReadCallback callback, void* userdata) {
|
2019-02-14 19:31:17 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsageBit::MapRead))) {
|
|
|
|
callback(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, userdata);
|
2017-06-09 14:51:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2017-06-09 14:51:29 +00:00
|
|
|
|
2018-03-21 00:56:39 +00:00
|
|
|
ASSERT(mMapWriteCallback == nullptr);
|
2017-06-09 14:51:29 +00:00
|
|
|
|
2018-03-21 00:56:39 +00:00
|
|
|
// TODO(cwallez@chromium.org): what to do on wraparound? Could cause crashes.
|
|
|
|
mMapSerial++;
|
|
|
|
mMapReadCallback = callback;
|
|
|
|
mMapUserdata = userdata;
|
2019-02-13 21:26:48 +00:00
|
|
|
mState = BufferState::Mapped;
|
2018-03-21 00:56:39 +00:00
|
|
|
|
2019-02-14 19:31:17 +00:00
|
|
|
MapReadAsyncImpl(mMapSerial);
|
2018-03-21 00:56:39 +00:00
|
|
|
}
|
|
|
|
|
2019-06-06 16:19:15 +00:00
|
|
|
MaybeError BufferBase::SetSubDataImpl(uint32_t start, uint32_t count, const void* data) {
|
2019-02-15 21:18:40 +00:00
|
|
|
DynamicUploader* uploader = nullptr;
|
|
|
|
DAWN_TRY_ASSIGN(uploader, GetDevice()->GetDynamicUploader());
|
|
|
|
|
|
|
|
// TODO(bryan.bernhart@intel.com): Remove once alignment constraint is added to validation
|
|
|
|
// (dawn:73). D3D12 does not specify so we assume 4-byte alignment to be safe.
|
|
|
|
static constexpr size_t kDefaultAlignment = 4;
|
|
|
|
|
|
|
|
UploadHandle uploadHandle;
|
|
|
|
DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(count, kDefaultAlignment));
|
|
|
|
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
|
|
|
|
|
|
|
memcpy(uploadHandle.mappedBuffer, data, count);
|
|
|
|
|
|
|
|
DAWN_TRY(GetDevice()->CopyFromStagingToBuffer(
|
|
|
|
uploadHandle.stagingBuffer, uploadHandle.startOffset, this, start, count));
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-05-29 13:03:50 +00:00
|
|
|
void BufferBase::MapWriteAsync(DawnBufferMapWriteCallback callback, void* userdata) {
|
2019-02-14 19:31:17 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsageBit::MapWrite))) {
|
|
|
|
callback(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, userdata);
|
2017-06-09 14:51:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2017-06-09 14:51:29 +00:00
|
|
|
|
2018-03-21 00:56:39 +00:00
|
|
|
ASSERT(mMapReadCallback == nullptr);
|
|
|
|
|
2017-06-09 14:51:29 +00:00
|
|
|
// TODO(cwallez@chromium.org): what to do on wraparound? Could cause crashes.
|
2018-03-21 00:56:39 +00:00
|
|
|
mMapSerial++;
|
|
|
|
mMapWriteCallback = callback;
|
|
|
|
mMapUserdata = userdata;
|
2019-02-13 21:26:48 +00:00
|
|
|
mState = BufferState::Mapped;
|
2018-03-21 00:56:39 +00:00
|
|
|
|
2019-02-14 19:31:17 +00:00
|
|
|
MapWriteAsyncImpl(mMapSerial);
|
2017-06-09 14:51:29 +00:00
|
|
|
}
|
|
|
|
|
2019-02-13 21:26:48 +00:00
|
|
|
void BufferBase::Destroy() {
|
2019-06-05 18:35:31 +00:00
|
|
|
if (IsError()) {
|
|
|
|
// It is an error to call Destroy() on an ErrorBuffer, but we still need to reclaim the
|
|
|
|
// fake mapped staging data.
|
|
|
|
reinterpret_cast<ErrorBuffer*>(this)->ClearMappedData();
|
|
|
|
}
|
2019-02-13 21:26:48 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateDestroy())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(!IsError());
|
|
|
|
|
|
|
|
if (mState == BufferState::Mapped) {
|
2019-06-05 18:35:31 +00:00
|
|
|
if (mStagingBuffer == nullptr) {
|
|
|
|
Unmap();
|
|
|
|
}
|
|
|
|
mStagingBuffer.reset();
|
2019-02-13 21:26:48 +00:00
|
|
|
}
|
2019-04-01 19:49:04 +00:00
|
|
|
DestroyInternal();
|
2019-02-13 21:26:48 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
MaybeError BufferBase::CopyFromStagingBuffer() {
|
|
|
|
ASSERT(mStagingBuffer);
|
|
|
|
DAWN_TRY(GetDevice()->CopyFromStagingToBuffer(mStagingBuffer.get(), 0, this, 0, GetSize()));
|
|
|
|
|
|
|
|
DynamicUploader* uploader = nullptr;
|
|
|
|
DAWN_TRY_ASSIGN(uploader, GetDevice()->GetDynamicUploader());
|
|
|
|
uploader->ReleaseStagingBuffer(std::move(mStagingBuffer));
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2017-06-09 14:51:29 +00:00
|
|
|
void BufferBase::Unmap() {
|
2019-05-15 18:55:22 +00:00
|
|
|
if (IsError()) {
|
|
|
|
// It is an error to call Unmap() on an ErrorBuffer, but we still need to reclaim the
|
|
|
|
// fake mapped staging data.
|
2019-06-05 18:35:31 +00:00
|
|
|
reinterpret_cast<ErrorBuffer*>(this)->ClearMappedData();
|
2019-05-15 18:55:22 +00:00
|
|
|
}
|
2018-10-15 12:54:30 +00:00
|
|
|
if (GetDevice()->ConsumedError(ValidateUnmap())) {
|
2017-06-09 14:51:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-13 13:09:18 +00:00
|
|
|
ASSERT(!IsError());
|
2017-06-09 14:51:29 +00:00
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
if (mStagingBuffer != nullptr) {
|
|
|
|
GetDevice()->ConsumedError(CopyFromStagingBuffer());
|
|
|
|
} else {
|
|
|
|
// A map request can only be called once, so this will fire only if the request wasn't
|
|
|
|
// completed before the Unmap.
|
|
|
|
// Callbacks are not fired if there is no callback registered, so this is correct for
|
|
|
|
// CreateBufferMapped.
|
|
|
|
CallMapReadCallback(mMapSerial, DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0u);
|
|
|
|
CallMapWriteCallback(mMapSerial, DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0u);
|
|
|
|
UnmapImpl();
|
|
|
|
}
|
2019-02-13 21:26:48 +00:00
|
|
|
mState = BufferState::Unmapped;
|
2018-03-21 00:56:39 +00:00
|
|
|
mMapReadCallback = nullptr;
|
|
|
|
mMapWriteCallback = nullptr;
|
|
|
|
mMapUserdata = 0;
|
2017-06-09 14:51:29 +00:00
|
|
|
}
|
|
|
|
|
2018-07-18 19:20:07 +00:00
|
|
|
MaybeError BufferBase::ValidateSetSubData(uint32_t start, uint32_t count) const {
|
2019-02-13 13:09:18 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
switch (mState) {
|
|
|
|
case BufferState::Mapped:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer is mapped");
|
|
|
|
case BufferState::Destroyed:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer is destroyed");
|
|
|
|
case BufferState::Unmapped:
|
|
|
|
break;
|
2019-02-13 21:26:48 +00:00
|
|
|
}
|
|
|
|
|
2018-12-17 17:08:41 +00:00
|
|
|
if (count > GetSize()) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer subdata with too much data");
|
|
|
|
}
|
|
|
|
|
2019-02-27 02:46:27 +00:00
|
|
|
// Metal requests buffer to buffer copy size must be a multiple of 4 bytes on macOS
|
|
|
|
if (count % 4 != 0) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer subdata size must be a multiple of 4 bytes");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Metal requests offset of buffer to buffer copy must be a multiple of 4 bytes on macOS
|
|
|
|
if (start % 4 != 0) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Start position must be a multiple of 4 bytes");
|
|
|
|
}
|
|
|
|
|
2018-12-17 17:08:41 +00:00
|
|
|
// Note that no overflow can happen because we already checked for GetSize() >= count
|
|
|
|
if (start > GetSize() - count) {
|
2018-09-10 14:17:24 +00:00
|
|
|
return DAWN_VALIDATION_ERROR("Buffer subdata out of range");
|
2018-07-18 19:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 13:08:02 +00:00
|
|
|
if (!(mUsage & dawn::BufferUsageBit::TransferDst)) {
|
2018-09-10 14:17:24 +00:00
|
|
|
return DAWN_VALIDATION_ERROR("Buffer needs the transfer dst usage bit");
|
2018-07-18 19:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-02-14 19:31:17 +00:00
|
|
|
MaybeError BufferBase::ValidateMap(dawn::BufferUsageBit requiredUsage) const {
|
2019-02-13 13:09:18 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
|
2019-06-05 18:35:31 +00:00
|
|
|
switch (mState) {
|
|
|
|
case BufferState::Mapped:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer already mapped");
|
|
|
|
case BufferState::Destroyed:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer is destroyed");
|
|
|
|
case BufferState::Unmapped:
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 13:08:02 +00:00
|
|
|
if (!(mUsage & requiredUsage)) {
|
2018-09-10 14:17:24 +00:00
|
|
|
return DAWN_VALIDATION_ERROR("Buffer needs the correct map usage bit");
|
2018-07-18 19:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeError BufferBase::ValidateUnmap() const {
|
2019-02-13 13:09:18 +00:00
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
|
2019-02-13 21:26:48 +00:00
|
|
|
switch (mState) {
|
|
|
|
case BufferState::Mapped:
|
2019-06-05 18:35:31 +00:00
|
|
|
// A buffer may be in the Mapped state if it was created with CreateBufferMapped
|
|
|
|
// even if it did not have a mappable usage.
|
|
|
|
return {};
|
|
|
|
case BufferState::Unmapped:
|
|
|
|
if ((mUsage & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) ==
|
|
|
|
0) {
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer does not have map usage");
|
|
|
|
}
|
2019-02-13 21:26:48 +00:00
|
|
|
return {};
|
|
|
|
case BufferState::Destroyed:
|
|
|
|
return DAWN_VALIDATION_ERROR("Buffer is destroyed");
|
|
|
|
}
|
|
|
|
}
|
2018-07-09 13:15:07 +00:00
|
|
|
|
2019-02-13 21:26:48 +00:00
|
|
|
MaybeError BufferBase::ValidateDestroy() const {
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
2018-07-18 19:20:07 +00:00
|
|
|
return {};
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2019-04-01 19:49:04 +00:00
|
|
|
void BufferBase::DestroyInternal() {
|
|
|
|
if (mState != BufferState::Destroyed) {
|
|
|
|
DestroyImpl();
|
|
|
|
}
|
|
|
|
mState = BufferState::Destroyed;
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:45:45 +00:00
|
|
|
} // namespace dawn_native
|