Vulkan: Handle CopyBufferToBuffer commands

This as this is the first command handled by the Vulkan backend, this
commit also introduces the b:✌️:CommandBUffer class and implements
b:✌️:Queue::Submit.

Also enables the BufferSetSubData tests that are now passing on Vulkan
even though the buffer transitions are unimplemented.
This commit is contained in:
Corentin Wallez 2017-12-04 16:29:41 -05:00 committed by Corentin Wallez
parent a9b98af710
commit 77a1d908b6
11 changed files with 134 additions and 6 deletions

View File

@ -293,6 +293,8 @@ if (NXT_ENABLE_VULKAN)
${VULKAN_DIR}/BufferUploader.h
${VULKAN_DIR}/BufferVk.cpp
${VULKAN_DIR}/BufferVk.h
${VULKAN_DIR}/CommandBufferVk.cpp
${VULKAN_DIR}/CommandBufferVk.h
${VULKAN_DIR}/FencedDeleter.cpp
${VULKAN_DIR}/FencedDeleter.h
${VULKAN_DIR}/MemoryAllocator.cpp

View File

@ -168,6 +168,7 @@ namespace backend {
// This needs to be called before the CommandIterator is freed so that the Ref<> present in
// the commands have a chance to run their destructor and remove internal references.
class CommandIterator;
void FreeCommands(CommandIterator* commands);
void SkipCommand(CommandIterator* commands, Command type);

View File

@ -35,6 +35,7 @@ namespace backend { namespace d3d12 {
Device* mDevice;
CommandIterator mCommands;
};
}} // namespace backend::d3d12
#endif // BACKEND_D3D12_COMMANDBUFFERD3D12_H_

View File

@ -102,6 +102,10 @@ namespace backend { namespace vulkan {
CallMapReadCallback(mapSerial, NXT_BUFFER_MAP_READ_STATUS_SUCCESS, data);
}
VkBuffer Buffer::GetHandle() const {
return mHandle;
}
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
BufferUploader* uploader = ToBackend(GetDevice())->GetBufferUploader();
uploader->BufferSubData(mHandle, start * sizeof(uint32_t), count * sizeof(uint32_t), data);

View File

@ -32,6 +32,8 @@ namespace backend { namespace vulkan {
void OnMapReadCommandSerialFinished(uint32_t mapSerial, const void* data);
VkBuffer GetHandle() const;
private:
void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;

View File

@ -0,0 +1,63 @@
// Copyright 2017 The NXT Authors
//
// 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.
#include "backend/vulkan/CommandBufferVk.h"
#include "backend/Commands.h"
#include "backend/vulkan/BufferVk.h"
#include "backend/vulkan/VulkanBackend.h"
#include <iostream>
namespace backend { namespace vulkan {
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
: CommandBufferBase(builder), mCommands(builder->AcquireCommands()) {
}
CommandBuffer::~CommandBuffer() {
FreeCommands(&mCommands);
}
void CommandBuffer::RecordCommands(VkCommandBuffer commands) {
Device* device = ToBackend(GetDevice());
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::CopyBufferToBuffer: {
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
auto& src = copy->source;
auto& dst = copy->destination;
VkBufferCopy region;
region.srcOffset = src.offset;
region.dstOffset = dst.offset;
region.size = copy->size;
VkBuffer srcHandle = ToBackend(src.buffer)->GetHandle();
VkBuffer dstHandle = ToBackend(dst.buffer)->GetHandle();
device->fn.CmdCopyBuffer(commands, srcHandle, dstHandle, 1, &region);
} break;
case Command::TransitionBufferUsage: {
SkipCommand(&mCommands, type);
} break;
default: { UNREACHABLE(); } break;
}
}
}
}} // namespace backend::vulkan

View File

@ -0,0 +1,37 @@
// Copyright 2017 The NXT Authors
//
// 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.
#ifndef BACKEND_VULKAN_COMMANDBUFFERVK_H_
#define BACKEND_VULKAN_COMMANDBUFFERVK_H_
#include "backend/CommandBuffer.h"
#include "backend/vulkan/vulkan_platform.h"
namespace backend { namespace vulkan {
class CommandBuffer : public CommandBufferBase {
public:
CommandBuffer(CommandBufferBuilder* builder);
~CommandBuffer();
void RecordCommands(VkCommandBuffer commands);
private:
CommandIterator mCommands;
};
}} // namespace backend::vulkan
#endif // BACKEND_VULKAN_COMMANDBUFFERVK_H_

View File

@ -13,4 +13,5 @@
// limitations under the License.
#include "backend/vulkan/BufferVk.h"
#include "backend/vulkan/CommandBufferVk.h"
#include "backend/vulkan/VulkanBackend.h"

View File

@ -17,6 +17,7 @@
#include "backend/Commands.h"
#include "backend/vulkan/BufferUploader.h"
#include "backend/vulkan/BufferVk.h"
#include "backend/vulkan/CommandBufferVk.h"
#include "backend/vulkan/FencedDeleter.h"
#include "common/Platform.h"
@ -246,6 +247,11 @@ namespace backend { namespace vulkan {
if (mPendingCommands.pool != VK_NULL_HANDLE) {
SubmitPendingCommands();
} else if (mCompletedSerial == mNextSerial - 1) {
// If there's no GPU work in flight we still need to artificially increment the serial
// so that CPU operations waiting on GPU completion can know they don't have to wait.
mCompletedSerial++;
mNextSerial++;
}
}
@ -584,7 +590,15 @@ namespace backend { namespace vulkan {
Queue::~Queue() {
}
void Queue::Submit(uint32_t, CommandBuffer* const*) {
void Queue::Submit(uint32_t numCommands, CommandBuffer* const* commands) {
Device* device = ToBackend(GetDevice());
VkCommandBuffer commandBuffer = device->GetPendingCommandBuffer();
for (uint32_t i = 0; i < numCommands; ++i) {
commands[i]->RecordCommands(commandBuffer);
}
device->SubmitPendingCommands();
}
// Texture

View File

@ -20,7 +20,6 @@
#include "backend/BindGroup.h"
#include "backend/BindGroupLayout.h"
#include "backend/BlendState.h"
#include "backend/CommandBuffer.h"
#include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
@ -50,7 +49,7 @@ namespace backend { namespace vulkan {
using BlendState = BlendStateBase;
class Buffer;
using BufferView = BufferViewBase;
using CommandBuffer = CommandBufferBase;
class CommandBuffer;
using ComputePipeline = ComputePipelineBase;
using DepthStencilState = DepthStencilStateBase;
class Device;

View File

@ -136,10 +136,10 @@ TEST_P(BufferSetSubDataTests, SmallDataAtOffset) {
// Stress test for many calls to SetSubData
TEST_P(BufferSetSubDataTests, ManySetSubData) {
if (IsD3D12() || IsMetal()) {
if (IsD3D12() || IsMetal() || IsVulkan()) {
// TODO(cwallez@chromium.org): Use ringbuffers for SetSubData on explicit APIs.
// otherwise this creates too many resources and can take freeze the driver(?)
std::cout << "Test skipped on D3D12 and Metal" << std::endl;
std::cout << "Test skipped on D3D12, Metal and Vulkan" << std::endl;
return;
}
@ -180,4 +180,8 @@ TEST_P(BufferSetSubDataTests, LargeSetSubData) {
EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), buffer, 0, kElements);
}
NXT_INSTANTIATE_TEST(BufferSetSubDataTests, D3D12Backend, MetalBackend, OpenGLBackend)
NXT_INSTANTIATE_TEST(BufferSetSubDataTests,
D3D12Backend,
MetalBackend,
OpenGLBackend,
VulkanBackend)