more on buffer rendering, added vulkan command pool

This commit is contained in:
georgemoralis 2023-09-27 15:15:18 +03:00
parent 3b853413c7
commit abe6d39295
4 changed files with 334 additions and 2 deletions

View File

@ -6,6 +6,16 @@
namespace HLE::Libs::Graphics { namespace HLE::Libs::Graphics {
struct VulkanCommandPool {
Lib::Mutex mutex;
VkCommandPool pool = nullptr;
VkCommandBuffer* buffers = nullptr;
VkFence* fences = nullptr;
VkSemaphore* semaphores = nullptr;
bool* busy = nullptr;
u32 buffers_count = 0;
};
struct VulkanQueueInfo { struct VulkanQueueInfo {
Lib::Mutex* mutex = nullptr; Lib::Mutex* mutex = nullptr;
u32 family = static_cast<u32>(-1); u32 family = static_cast<u32>(-1);

View File

@ -1,9 +1,198 @@
#include "graphics_render.h" #include "graphics_render.h"
#include "Util/Singleton.h" #include "Util/Singleton.h"
#include "emulator.h" #include "emulator.h"
static thread_local GPU::CommandPool g_command_pool;
void GPU::renderCreateCtx() { void GPU::renderCreateCtx() {
auto* render_ctx = Singleton<RenderCtx>::Instance(); auto* render_ctx = Singleton<RenderCtx>::Instance();
render_ctx->setGraphicCtx(Emulator::getGraphicCtx()); render_ctx->setGraphicCtx(Emulator::getGraphicCtx());
} }
void GPU::CommandBuffer::allocateBuffer() {
m_pool = g_command_pool.getPool(m_queue);
Lib::LockMutexGuard lock(m_pool->mutex);
for (uint32_t i = 0; i < m_pool->buffers_count; i++) {
if (!m_pool->busy[i]) {
m_pool->busy[i] = true;
vkResetCommandBuffer(m_pool->buffers[i], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
m_index = i;
break;
}
}
}
void GPU::CommandBuffer::freeBuffer() {
Lib::LockMutexGuard lock(m_pool->mutex);
waitForFence();
m_pool->busy[m_index] = false;
vkResetCommandBuffer(m_pool->buffers[m_index], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
m_index = static_cast<uint32_t>(-1);
}
void GPU::CommandBuffer::waitForFence() {
auto* render_ctx = Singleton<RenderCtx>::Instance();
if (m_execute) {
auto* device = render_ctx->getGraphicCtx()->m_device;
vkWaitForFences(device, 1, &m_pool->fences[m_index], VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &m_pool->fences[m_index]);
m_execute = false;
}
}
void GPU::CommandBuffer::begin() const {
auto* buffer = m_pool->buffers[m_index];
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.pNext = nullptr;
begin_info.flags = 0;
begin_info.pInheritanceInfo = nullptr;
auto result = vkBeginCommandBuffer(buffer, &begin_info);
if (result != VK_SUCCESS) {
printf("vkBeginCommandBuffer failed\n");
std::exit(0);
}
}
void GPU::CommandBuffer::end() const {
auto* buffer = m_pool->buffers[m_index];
auto result = vkEndCommandBuffer(buffer);
if (result != VK_SUCCESS) {
printf("vkEndCommandBuffer failed\n");
std::exit(0);
}
}
void GPU::CommandBuffer::executeWithSemaphore() {
auto* buffer = m_pool->buffers[m_index];
auto* fence = m_pool->fences[m_index];
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &m_pool->semaphores[m_index];
auto* render_ctx = Singleton<RenderCtx>::Instance();
const auto& queue = render_ctx->getGraphicCtx()->queues[m_queue];
if (queue.mutex != nullptr) {
queue.mutex->LockMutex();
}
auto result = vkQueueSubmit(queue.vk_queue, 1, &submit_info, fence);
if (queue.mutex != nullptr) {
queue.mutex->LockMutex();
}
m_execute = true;
if (result != VK_SUCCESS) {
printf("vkQueueSubmit failed\n");
std::exit(0);
}
}
void GPU::CommandPool::createPool(int id) {
auto* render_ctx = Singleton<RenderCtx>::Instance();
auto* ctx = render_ctx->getGraphicCtx();
m_pool[id] = new HLE::Libs::Graphics::VulkanCommandPool;
VkCommandPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.pNext = nullptr;
pool_info.queueFamilyIndex = ctx->queues[id].family;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vkCreateCommandPool(ctx->m_device, &pool_info, nullptr, &m_pool[id]->pool);
if (m_pool[id]->pool == nullptr) {
printf("pool is nullptr");
std::exit(0);
}
m_pool[id]->buffers_count = 4;
m_pool[id]->buffers = new VkCommandBuffer[m_pool[id]->buffers_count];
m_pool[id]->fences = new VkFence[m_pool[id]->buffers_count];
m_pool[id]->semaphores = new VkSemaphore[m_pool[id]->buffers_count];
m_pool[id]->busy = new bool[m_pool[id]->buffers_count];
VkCommandBufferAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.commandPool = m_pool[id]->pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandBufferCount = m_pool[id]->buffers_count;
if (vkAllocateCommandBuffers(ctx->m_device, &alloc_info, m_pool[id]->buffers) != VK_SUCCESS) {
printf("Can't allocate command buffers\n");
std::exit(0);
}
for (uint32_t i = 0; i < m_pool[id]->buffers_count; i++) {
m_pool[id]->busy[i] = false;
VkFenceCreateInfo fence_info{};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_info.pNext = nullptr;
fence_info.flags = 0;
if (vkCreateFence(ctx->m_device, &fence_info, nullptr, &m_pool[id]->fences[i]) != VK_SUCCESS) {
printf("Can't create fence\n");
std::exit(0);
}
VkSemaphoreCreateInfo semaphore_info{};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphore_info.pNext = nullptr;
semaphore_info.flags = 0;
if (vkCreateSemaphore(ctx->m_device, &semaphore_info, nullptr, &m_pool[id]->semaphores[i]) != VK_SUCCESS) {
printf("Can't create semas\n");
std::exit(0);
}
}
}
void GPU::CommandPool::deleteAllPool() {
auto* render_ctx = Singleton<RenderCtx>::Instance();
auto* ctx = render_ctx->getGraphicCtx();
for (auto& pool : m_pool) {
if (pool != nullptr) {
for (uint32_t i = 0; i < pool->buffers_count; i++) {
vkDestroySemaphore(ctx->m_device, pool->semaphores[i], nullptr);
vkDestroyFence(ctx->m_device, pool->fences[i], nullptr);
}
vkFreeCommandBuffers(ctx->m_device, pool->pool, pool->buffers_count, pool->buffers);
vkDestroyCommandPool(ctx->m_device, pool->pool, nullptr);
delete[] pool->semaphores;
delete[] pool->fences;
delete[] pool->buffers;
delete[] pool->busy;
delete pool;
pool = nullptr;
}
}
}

View File

@ -3,6 +3,43 @@
namespace GPU { namespace GPU {
class CommandPool {
public:
CommandPool() = default;
~CommandPool() {}
HLE::Libs::Graphics::VulkanCommandPool* getPool(int id) {
if (m_pool[id] == nullptr) {
createPool(id);
}
return m_pool[id];
}
private:
void createPool(int id);
void deleteAllPool();
HLE::Libs::Graphics::VulkanCommandPool* m_pool[11] = {};
};
class CommandBuffer {
public:
explicit CommandBuffer(int queue) : m_queue(queue) { allocateBuffer(); }
virtual ~CommandBuffer() { freeBuffer(); }
void allocateBuffer();
void freeBuffer();
void waitForFence();
void begin() const;
void end() const;
void executeWithSemaphore();
u32 getIndex() const { return m_index; }
HLE::Libs::Graphics::VulkanCommandPool* getPool() { return m_pool; }
private:
int m_queue = -1;
u32 m_index = static_cast<u32>(-1);
HLE::Libs::Graphics::VulkanCommandPool* m_pool = nullptr;
bool m_execute = false;
};
class Framebuffer { class Framebuffer {
public: public:
Framebuffer() {} Framebuffer() {}
@ -14,11 +51,12 @@ class RenderCtx {
virtual ~RenderCtx() {} virtual ~RenderCtx() {}
void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) { m_graphic_ctx = ctx; } void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) { m_graphic_ctx = ctx; }
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() { return m_graphic_ctx; }
private: private:
Framebuffer* m_framebuffer = nullptr; Framebuffer* m_framebuffer = nullptr;
HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr; HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr;
}; };
void renderCreateCtx(); void renderCreateCtx();
}; // namespace GPU }; // namespace GPU

View File

@ -1,5 +1,6 @@
#include "emulator.h" #include "emulator.h"
#include <Core/PS4/HLE/Graphics/graphics_render.h>
#include <Util/Singleton.h> #include <Util/Singleton.h>
#include <vulkan_util.h> #include <vulkan_util.h>
@ -100,6 +101,100 @@ HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() {
return &window_ctx->m_graphic_ctx; return &window_ctx->m_graphic_ctx;
} }
void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) {} void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) {
auto* window_ctx = Singleton<Emulator::WindowCtx>::Instance();
if (window_ctx->is_window_hidden) {
SDL_ShowWindow(window_ctx->m_window);
window_ctx->is_window_hidden = false;
}
window_ctx->swapchain->current_index = static_cast<u32>(-1);
auto result = vkAcquireNextImageKHR(window_ctx->m_graphic_ctx.m_device, window_ctx->swapchain->swapchain, UINT64_MAX, nullptr,
window_ctx->swapchain->present_complete_fence, &window_ctx->swapchain->current_index);
if (result != VK_SUCCESS) {
printf("Can't aquireNextImage\n");
std::exit(0);
}
if (window_ctx->swapchain->current_index == static_cast<u32>(-1)) {
printf("Unsupported:swapchain current index is -1\n");
std::exit(0);
}
do {
result = vkWaitForFences(window_ctx->m_graphic_ctx.m_device, 1, &window_ctx->swapchain->present_complete_fence, VK_TRUE, 100000000);
} while (result == VK_TIMEOUT);
if (result != VK_SUCCESS) {
printf("vkWaitForFences is not success\n");
std::exit(0);
}
vkResetFences(window_ctx->m_graphic_ctx.m_device, 1, &window_ctx->swapchain->present_complete_fence);
auto* blt_src_image = image;
auto* blt_dst_image = window_ctx->swapchain;
if (blt_src_image == nullptr) {
printf("blt_src_image is null\n");
std::exit(0);
}
if (blt_dst_image == nullptr) {
printf("blt_dst_image is null\n");
std::exit(0);
}
GPU::CommandBuffer buffer(10);
auto* vk_buffer = buffer.getPool()->buffers[buffer.getIndex()];
buffer.begin();
//UtilBlitImage(&buffer, blt_src_image, blt_dst_image);
VkImageMemoryBarrier pre_present_barrier{};
pre_present_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
pre_present_barrier.pNext = nullptr;
pre_present_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
pre_present_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
pre_present_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
pre_present_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
pre_present_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
pre_present_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
pre_present_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
pre_present_barrier.subresourceRange.baseMipLevel = 0;
pre_present_barrier.subresourceRange.levelCount = 1;
pre_present_barrier.subresourceRange.baseArrayLayer = 0;
pre_present_barrier.subresourceRange.layerCount = 1;
pre_present_barrier.image = window_ctx->swapchain->swapchain_images[window_ctx->swapchain->current_index];
vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
&pre_present_barrier);
buffer.end();
buffer.executeWithSemaphore();
VkPresentInfoKHR present{};
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.pNext = nullptr;
present.swapchainCount = 1;
present.pSwapchains = &window_ctx->swapchain->swapchain;
present.pImageIndices = &window_ctx->swapchain->current_index;
present.pWaitSemaphores = &buffer.getPool()->semaphores[buffer.getIndex()];
present.waitSemaphoreCount = 1;
present.pResults = nullptr;
const auto& queue = window_ctx->m_graphic_ctx.queues[10];
if (queue.mutex != nullptr) {
printf("queue.mutexe is null\n");
std::exit(0);
}
result = vkQueuePresentKHR(queue.vk_queue, &present);
if (result != VK_SUCCESS) {
printf("vkQueuePresentKHR failed\n");
std::exit(0);
}
}
} // namespace Emulator } // namespace Emulator