src/ngfx/porting/d3d/D3DBuffer.cpp
Source code
/*
* Copyright 2020 GoPro Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "ngfx/porting/d3d/D3DBuffer.h"
#include "ngfx/porting/d3d/D3DDebugUtil.h"
#include "ngfx/porting/d3d/D3DGraphicsContext.h"
#include "ngfx/porting/d3d/D3DReadbackBuffer.h"
#include <cassert>
#include <d3dx12.h>
using namespace ngfx;
void D3DBuffer::create(D3DGraphicsContext *ctx, const void *data, uint32_t size,
BufferUsageFlags bufferUsageFlags) {
if (bufferUsageFlags & BUFFER_USAGE_TRANSFER_SRC_BIT)
heapType = D3D12_HEAP_TYPE_UPLOAD;
else
heapType = D3D12_HEAP_TYPE_DEFAULT;
D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE;
if (bufferUsageFlags & BUFFER_USAGE_STORAGE_BUFFER_BIT)
resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
create(ctx, data, size, heapType, resourceFlags);
}
void D3DBuffer::create(D3DGraphicsContext *ctx, const void *data, uint32_t size,
D3D12_HEAP_TYPE heapType,
D3D12_RESOURCE_FLAGS resourceFlags,
D3D12_RESOURCE_STATES initialResourceState) {
HRESULT hResult;
this->ctx = ctx;
auto &device = ctx->d3dDevice.v;
this->size = size;
this->heapType = heapType;
this->initialResourceState = initialResourceState;
CD3DX12_HEAP_PROPERTIES heapProperties(heapType);
CD3DX12_RESOURCE_DESC resourceDesc =
CD3DX12_RESOURCE_DESC::Buffer(size, resourceFlags);
V(device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE,
&resourceDesc, initialResourceState,
nullptr, IID_PPV_ARGS(&v)));
currentResourceState = initialResourceState;
if (data)
upload(data, size, 0);
}
D3DBuffer::~D3DBuffer() {}
// TODO: add read/write flags for map
void *D3DBuffer::map() {
if (heapType == D3D12_HEAP_TYPE_DEFAULT) {
assert(d3dReadbackBuffer == nullptr);
auto ©CommandList = ctx->d3dCopyCommandList;
copyCommandList.begin();
d3dReadbackBuffer = new D3DReadbackBuffer();
d3dReadbackBuffer->create(ctx, size);
if (currentResourceState != D3D12_RESOURCE_STATE_COPY_SOURCE) {
CD3DX12_RESOURCE_BARRIER resourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(
v.Get(), currentResourceState, D3D12_RESOURCE_STATE_COPY_SOURCE);
D3D_TRACE(copyCommandList.v.Get()->ResourceBarrier(1, &resourceBarrier));
}
D3D_TRACE(copyCommandList.v.Get()->CopyBufferRegion(
d3dReadbackBuffer->v.Get(), 0, v.Get(), 0, size));
CD3DX12_RESOURCE_BARRIER resourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(v.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_RESOURCE_STATE_GENERIC_READ);
D3D_TRACE(copyCommandList.v.Get()->ResourceBarrier(1, &resourceBarrier));
copyCommandList.end();
ctx->d3dCommandQueue.submit(©CommandList);
ctx->d3dCommandQueue.waitIdle();
d3dReadBackBufferPtr = d3dReadbackBuffer->map();
return d3dReadBackBufferPtr;
} else {
UINT8 *ptr;
HRESULT hResult;
V(v->Map(0, nullptr, reinterpret_cast<void **>(&ptr)));
return ptr;
}
}
void D3DBuffer::unmap() {
if (heapType == D3D12_HEAP_TYPE_DEFAULT) {
assert(d3dReadbackBuffer);
upload(d3dReadBackBufferPtr, size, 0);
d3dReadbackBuffer->unmap();
delete d3dReadbackBuffer;
d3dReadbackBuffer = nullptr;
d3dReadBackBufferPtr = nullptr;
} else {
D3D_TRACE(v->Unmap(0, nullptr));
}
}
void D3DBuffer::upload(const void *data, uint32_t size, uint32_t offset) {
if (heapType == D3D12_HEAP_TYPE_DEFAULT) {
auto ©CommandList = ctx->d3dCopyCommandList;
copyCommandList.begin();
D3DBuffer stagingBuffer;
if (data) {
stagingBuffer.create(ctx, data, size, D3D12_HEAP_TYPE_UPLOAD);
if (currentResourceState != D3D12_RESOURCE_STATE_COPY_DEST) {
CD3DX12_RESOURCE_BARRIER resourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(
v.Get(), currentResourceState, D3D12_RESOURCE_STATE_COPY_DEST);
D3D_TRACE(
copyCommandList.v.Get()->ResourceBarrier(1, &resourceBarrier));
}
D3D_TRACE(copyCommandList.v.Get()->CopyBufferRegion(
v.Get(), 0, stagingBuffer.v.Get(), 0, size));
}
CD3DX12_RESOURCE_BARRIER resourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(v.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_GENERIC_READ);
D3D_TRACE(copyCommandList.v.Get()->ResourceBarrier(1, &resourceBarrier));
copyCommandList.end();
ctx->d3dCommandQueue.submit(©CommandList);
ctx->d3dCommandQueue.waitIdle();
currentResourceState = D3D12_RESOURCE_STATE_GENERIC_READ;
} else {
uint8_t *dst = (uint8_t *)map();
memcpy(dst + offset, data, size);
unmap();
}
}
Buffer *Buffer::create(GraphicsContext *ctx, const void *data, uint32_t size,
BufferUsageFlags usageFlags) {
D3DBuffer *d3dBuffer = new D3DBuffer();
d3dBuffer->create(d3d(ctx), data, size, usageFlags);
return d3dBuffer;
}
Updated on 3 April 2021 at 20:21:51 PDT