From abe6d392956dbe085e8eb5ae11ef2ddede425359 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Wed, 27 Sep 2023 15:15:18 +0300 Subject: [PATCH] more on buffer rendering, added vulkan command pool --- src/Core/PS4/HLE/Graphics/graphics_ctx.h | 10 + src/Core/PS4/HLE/Graphics/graphics_render.cpp | 189 ++++++++++++++++++ src/Core/PS4/HLE/Graphics/graphics_render.h | 40 +++- src/emulator.cpp | 97 ++++++++- 4 files changed, 334 insertions(+), 2 deletions(-) diff --git a/src/Core/PS4/HLE/Graphics/graphics_ctx.h b/src/Core/PS4/HLE/Graphics/graphics_ctx.h index 48972da7..01103466 100644 --- a/src/Core/PS4/HLE/Graphics/graphics_ctx.h +++ b/src/Core/PS4/HLE/Graphics/graphics_ctx.h @@ -6,6 +6,16 @@ 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 { Lib::Mutex* mutex = nullptr; u32 family = static_cast(-1); diff --git a/src/Core/PS4/HLE/Graphics/graphics_render.cpp b/src/Core/PS4/HLE/Graphics/graphics_render.cpp index 43d9e8ab..b5db11cf 100644 --- a/src/Core/PS4/HLE/Graphics/graphics_render.cpp +++ b/src/Core/PS4/HLE/Graphics/graphics_render.cpp @@ -1,9 +1,198 @@ #include "graphics_render.h" + #include "Util/Singleton.h" #include "emulator.h" +static thread_local GPU::CommandPool g_command_pool; + void GPU::renderCreateCtx() { auto* render_ctx = Singleton::Instance(); 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(-1); +} + +void GPU::CommandBuffer::waitForFence() { + auto* render_ctx = Singleton::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::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::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::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; + } + } +} + diff --git a/src/Core/PS4/HLE/Graphics/graphics_render.h b/src/Core/PS4/HLE/Graphics/graphics_render.h index 9b019711..aa3bbd6a 100644 --- a/src/Core/PS4/HLE/Graphics/graphics_render.h +++ b/src/Core/PS4/HLE/Graphics/graphics_render.h @@ -3,6 +3,43 @@ 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(-1); + HLE::Libs::Graphics::VulkanCommandPool* m_pool = nullptr; + bool m_execute = false; +}; + class Framebuffer { public: Framebuffer() {} @@ -14,11 +51,12 @@ class RenderCtx { virtual ~RenderCtx() {} void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) { m_graphic_ctx = ctx; } + HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() { return m_graphic_ctx; } + private: Framebuffer* m_framebuffer = nullptr; HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr; }; - void renderCreateCtx(); }; // namespace GPU \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index e9b1539d..29b31e9f 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -1,5 +1,6 @@ #include "emulator.h" +#include #include #include @@ -100,6 +101,100 @@ HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() { return &window_ctx->m_graphic_ctx; } -void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) {} +void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) { + auto* window_ctx = Singleton::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(-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(-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 \ No newline at end of file