dolphin/Source/Core/VideoBackends/Vulkan/VKBoundingBox.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

156 lines
6.0 KiB
C++
Raw Normal View History

2016-08-13 06:57:50 -06:00
// Copyright 2016 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2016-08-13 06:57:50 -06:00
2021-12-09 19:22:16 -07:00
#include "VideoBackends/Vulkan/VKBoundingBox.h"
2016-08-13 06:57:50 -06:00
#include <vector>
#include "Common/Logging/Log.h"
2016-08-13 06:57:50 -06:00
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/StagingBuffer.h"
#include "VideoBackends/Vulkan/StateTracker.h"
2023-01-27 19:12:28 -07:00
#include "VideoBackends/Vulkan/VKGfx.h"
2016-08-13 06:57:50 -06:00
#include "VideoBackends/Vulkan/VulkanContext.h"
namespace Vulkan
{
VKBoundingBox::~VKBoundingBox()
2016-08-13 06:57:50 -06:00
{
if (m_gpu_buffer != VK_NULL_HANDLE)
{
vmaDestroyBuffer(g_vulkan_context->GetMemoryAllocator(), m_gpu_buffer, m_gpu_allocation);
2016-08-13 06:57:50 -06:00
}
}
bool VKBoundingBox::Initialize()
2016-08-13 06:57:50 -06:00
{
if (!CreateGPUBuffer())
return false;
if (!CreateReadbackBuffer())
return false;
// Bind bounding box to state tracker
StateTracker::GetInstance()->SetSSBO(m_gpu_buffer, 0, BUFFER_SIZE);
2016-08-13 06:57:50 -06:00
return true;
}
std::vector<BBoxType> VKBoundingBox::Read(u32 index, u32 length)
2016-08-13 06:57:50 -06:00
{
// Can't be done within a render pass.
StateTracker::GetInstance()->EndRenderPass();
2016-08-13 06:57:50 -06:00
// Ensure all writes are completed to the GPU buffer prior to the transfer.
StagingBuffer::BufferMemoryBarrier(
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 0,
BUFFER_SIZE, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
m_readback_buffer->PrepareForGPUWrite(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT);
2016-08-13 06:57:50 -06:00
// Copy from GPU -> readback buffer.
VkBufferCopy region = {0, 0, BUFFER_SIZE};
vkCmdCopyBuffer(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
m_readback_buffer->GetBuffer(), 1, &region);
2016-08-13 06:57:50 -06:00
// Restore GPU buffer access.
StagingBuffer::BufferMemoryBarrier(
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer, VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, 0, BUFFER_SIZE,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
m_readback_buffer->FlushGPUCache(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
2016-08-13 06:57:50 -06:00
// Wait until these commands complete.
2023-01-27 19:12:28 -07:00
VKGfx::GetInstance()->ExecuteCommandBuffer(false, true);
2016-08-13 06:57:50 -06:00
// Cache is now valid.
m_readback_buffer->InvalidateCPUCache();
2016-08-13 06:57:50 -06:00
// Read out the values and return
std::vector<BBoxType> values(length);
m_readback_buffer->Read(index * sizeof(BBoxType), values.data(), length * sizeof(BBoxType),
false);
return values;
2016-08-13 06:57:50 -06:00
}
void VKBoundingBox::Write(u32 index, const std::vector<BBoxType>& values)
2016-08-13 06:57:50 -06:00
{
// We can't issue vkCmdUpdateBuffer within a render pass.
// However, the writes must be serialized, so we can't put it in the init buffer.
StateTracker::GetInstance()->EndRenderPass();
2016-08-13 06:57:50 -06:00
// Ensure GPU buffer is in a state where it can be transferred to.
StagingBuffer::BufferMemoryBarrier(
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 0,
BUFFER_SIZE, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
// Write the values to the GPU buffer
vkCmdUpdateBuffer(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer,
index * sizeof(BBoxType), values.size() * sizeof(BBoxType),
reinterpret_cast<const BBoxType*>(values.data()));
2016-08-13 06:57:50 -06:00
// Restore fragment shader access to the buffer.
StagingBuffer::BufferMemoryBarrier(
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_gpu_buffer, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, 0, BUFFER_SIZE,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
2016-08-13 06:57:50 -06:00
}
bool VKBoundingBox::CreateGPUBuffer()
2016-08-13 06:57:50 -06:00
{
VkBufferUsageFlags buffer_usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VkBufferCreateInfo info = {
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
nullptr, // const void* pNext
0, // VkBufferCreateFlags flags
BUFFER_SIZE, // VkDeviceSize size
buffer_usage, // VkBufferUsageFlags usage
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
0, // uint32_t queueFamilyIndexCount
nullptr // const uint32_t* pQueueFamilyIndices
};
VmaAllocationCreateInfo alloc_create_info = {};
alloc_create_info.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
alloc_create_info.pool = VK_NULL_HANDLE;
alloc_create_info.pUserData = nullptr;
alloc_create_info.priority = 0.0;
alloc_create_info.requiredFlags = 0;
alloc_create_info.preferredFlags = 0;
2016-08-13 06:57:50 -06:00
VkBuffer buffer;
VmaAllocation alloc;
VkResult res = vmaCreateBuffer(g_vulkan_context->GetMemoryAllocator(), &info, &alloc_create_info,
&buffer, &alloc, nullptr);
2016-08-13 06:57:50 -06:00
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vmaCreateBuffer failed: ");
2016-08-13 06:57:50 -06:00
return false;
}
m_gpu_buffer = buffer;
m_gpu_allocation = alloc;
2016-08-13 06:57:50 -06:00
return true;
}
bool VKBoundingBox::CreateReadbackBuffer()
2016-08-13 06:57:50 -06:00
{
m_readback_buffer = StagingBuffer::Create(STAGING_BUFFER_TYPE_READBACK, BUFFER_SIZE,
VK_BUFFER_USAGE_TRANSFER_DST_BIT);
if (!m_readback_buffer || !m_readback_buffer->Map())
return false;
return true;
}
} // namespace Vulkan