This commit is contained in:
Martin Baliet 2024-05-04 20:18:48 +02:00
parent 812b20f966
commit bbf3d661df
9 changed files with 260 additions and 20 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)
include(ExternalProject)
set(PSOFF_LIB_VERSION v.0.0)
set(PSOFF_LIB_VERSION v.0.2)
set(PSOFF_RENDER_VERSION v.0.5-nightly_29.04.24-fix)
set(ProjectName psOff_${CMAKE_BUILD_TYPE})

View File

@ -47,6 +47,7 @@ target_link_libraries(core PRIVATE
IPHLPAPI.lib
Ws2_32.lib
ntdll.dll
imgui
VulkanMemoryAllocator
${Vulkan_LIBRARIES}
)

View File

@ -1,12 +1,16 @@
add_library(videoout OBJECT
videoout.cpp
imageHandler.cpp
vulkan/vulkanSetup.cpp
vulkan/vulkanHelper.cpp
imageHandler.cpp
overlay/overlay.cpp
)
add_dependencies(videoout third_party psOff_utility gamereport initParams config_emu psoff_render)
target_include_directories(videoout PRIVATE
${Vulkan_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/third_party/src/third_party/include
)

View File

@ -32,7 +32,8 @@ class ImageHandler: public IImageHandler {
uint32_t m_countImages = 0;
std::vector<VkImage> m_scImages;
std::vector<VkImage> m_srcImages;
std::vector<VkImageView> m_srcImageViews;
// - vulkan
boost::mutex m_mutexInt;
@ -96,9 +97,9 @@ void ImageHandler::recreate() {
uint32_t numImages = 0;
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, nullptr);
m_scImages.resize(numImages);
m_srcImages.resize(numImages);
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, m_scImages.data());
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, m_srcImages.data());
}
}
@ -155,7 +156,8 @@ std::optional<ImageData> ImageHandler::getImage_blocking() {
m_nextIndex = (++m_nextIndex) % m_maxImages;
++m_countImages;
imageData.swapchainImage = m_scImages[imageData.index];
imageData.swapchainImage = m_srcImages[imageData.index];
imageData.imageView = m_srcImageViews[imageData.index];
imageData.extent = m_extentWindow;
@ -261,9 +263,32 @@ void ImageHandler::init(vulkan::VulkanObj* obj, VkSurfaceKHR surface) {
{ // swapchain images
uint32_t numImages = 0;
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, nullptr);
m_scImages.resize(numImages);
m_srcImages.resize(numImages);
m_srcImageViews.resize(numImages);
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, m_scImages.data());
vkGetSwapchainImagesKHR(m_deviceInfo->device, m_swapchain, &numImages, m_srcImages.data());
for (size_t n = 0; n < numImages; ++n) {
VkImageViewCreateInfo createInfo {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.image = m_srcImages[n],
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = m_imageFormat, // todo swizzle?
.components = {},
.subresourceRange =
{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1u,
},
};
vkCreateImageView(m_deviceInfo->device, &createInfo, nullptr, &m_srcImageViews[n]);
}
}
{ // Command buffer
@ -304,8 +329,12 @@ void ImageHandler::deinit() {
for (auto& fence: m_fenceSubmit) {
vkDestroyFence(m_deviceInfo->device, fence, nullptr);
}
for (auto& view: m_srcImageViews) {
vkDestroyImageView(m_deviceInfo->device, view, nullptr);
}
if (m_commandPool != nullptr) vkDestroyCommandPool(m_deviceInfo->device, m_commandPool, nullptr);
if (m_swapchain != nullptr) vkDestroySwapchainKHR(m_deviceInfo->device, m_swapchain, nullptr);
printf("deinit ImageHandler| done\n");

View File

@ -7,6 +7,8 @@
struct ImageData {
VkImage swapchainImage = nullptr;
VkImageView imageView = nullptr;
VkSemaphore semImageReady = nullptr; /// image is ready for operation
VkSemaphore semImageCopied = nullptr; /// Image has been copied, ready to swap
VkCommandBuffer cmdBuffer = nullptr; /// Commandbuffer to be used for transer etc. Already called begin!

View File

@ -0,0 +1,165 @@
#include "overlay.h"
#include "../imageHandler.h"
#include "logging.h"
#include <imgui/imgui.h>
#include <imgui/imgui_impl_sdl2.h>
#include <imgui/imgui_impl_vulkan.h>
#include <vulkan/vk_enum_string_helper.h>
LOG_DEFINE_MODULE(Overlay);
class OverlayHandler: public IOverlayHandler {
std::shared_ptr<vulkan::DeviceInfo> m_deviceInfo;
VkDescriptorPool m_descriptorPool;
bool m_isInit = false, m_isStop = false;
void init(SDL_Window* window, vulkan::QueueInfo* queue, VkFormat displayFormat);
void draw();
public:
OverlayHandler(std::shared_ptr<vulkan::DeviceInfo>& deviceInfo, SDL_Window* window, vulkan::QueueInfo* queue, VkFormat displayFormat)
: m_deviceInfo(deviceInfo) {
init(window, queue, displayFormat);
}
virtual ~OverlayHandler() {
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
vkDestroyDescriptorPool(m_deviceInfo->device, m_descriptorPool, nullptr);
}
// ### Interface
void stop() final { m_isStop = true; }
void submit(ImageData const& imageData) final;
void processEvent(SDL_Event const* event) final {
[[unlikely]] if (!m_isInit || !m_isStop)
return;
ImGui_ImplSDL2_ProcessEvent(event);
}
};
std::unique_ptr<IOverlayHandler> createOverlay(std::shared_ptr<vulkan::DeviceInfo>& deviceInfo, SDL_Window* window, vulkan::QueueInfo* queue,
VkFormat displayFormat) {
return std::make_unique<OverlayHandler>(deviceInfo, window, queue, displayFormat);
}
void OverlayHandler::init(SDL_Window* window, vulkan::QueueInfo* queue, VkFormat displayFormat) {
LOG_USE_MODULE(Overlay);
// Create intern vulkan data
VkDescriptorPoolSize poolSizes[] = {{VK_DESCRIPTOR_TYPE_SAMPLER, 1000},
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000},
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000},
{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000}};
VkDescriptorPoolCreateInfo poolInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
.maxSets = 1000,
.poolSizeCount = std::size(poolSizes),
.pPoolSizes = poolSizes,
};
if (auto res = vkCreateDescriptorPool(m_deviceInfo->device, &poolInfo, nullptr, &m_descriptorPool); res != VK_SUCCESS) {
LOG_ERR(L"Couldn't create descriptor pool %S", string_VkResult(res));
return;
}
// -
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui::StyleColorsDark();
// ImGui::StyleColorsLight();
ImGui_ImplSDL2_InitForVulkan(window);
ImGui_ImplVulkan_InitInfo initInfo = {
.Instance = m_deviceInfo->instance,
.PhysicalDevice = m_deviceInfo->physicalDevice,
.Device = m_deviceInfo->device,
.QueueFamily = queue->family,
.Queue = queue->queue,
.DescriptorPool = m_descriptorPool,
.RenderPass = nullptr, // Dynamic
.MinImageCount = 2,
.ImageCount = 3,
.MSAASamples = VK_SAMPLE_COUNT_1_BIT,
.PipelineCache = nullptr,
.Subpass = 0,
.UseDynamicRendering = true,
.PipelineRenderingCreateInfo =
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.colorAttachmentCount = 1,
.pColorAttachmentFormats = &displayFormat,
},
.Allocator = nullptr,
.CheckVkResultFn = nullptr,
};
ImGui_ImplVulkan_Init(&initInfo);
m_isInit = true;
}
void OverlayHandler::submit(ImageData const& imageData) {
[[unlikely]] if (!m_isInit || m_isStop)
return;
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
ImGui::Render();
ImDrawData* drawData = ImGui::GetDrawData();
VkRenderingAttachmentInfo colorInfo {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = imageData.imageView,
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.resolveMode = VK_RESOLVE_MODE_NONE,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = {},
};
VkRenderingInfo renderingInfo {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.renderArea = {{}, imageData.extent},
.layerCount = 1,
.colorAttachmentCount = 1,
.pColorAttachments = &colorInfo,
.pDepthAttachment = nullptr,
.pStencilAttachment = nullptr,
};
vkCmdBeginRendering(imageData.cmdBuffer, &renderingInfo);
ImGui_ImplVulkan_RenderDrawData(drawData, imageData.cmdBuffer);
vkCmdEndRendering(imageData.cmdBuffer);
}
void OverlayHandler::draw() {
ImGui::ShowDemoWindow();
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "../vulkan/vulkanSetup.h"
#include "core/videoout/vulkan/vulkanTypes.h"
#include "utility/utility.h"
#include <SDL2/SDL.h>
#include <memory>
struct ImageData;
class IOverlayHandler {
CLASS_NO_COPY(IOverlayHandler);
protected:
IOverlayHandler() = default;
public:
virtual ~IOverlayHandler() = default;
virtual void stop() = 0;
virtual void submit(ImageData const& imageData) = 0;
virtual void processEvent(SDL_Event const* event) = 0;
};
std::unique_ptr<IOverlayHandler> createOverlay(std::shared_ptr<vulkan::DeviceInfo>& deviceInfo, SDL_Window* window, vulkan::QueueInfo* queue,
VkFormat displayFormat);

View File

@ -13,6 +13,7 @@
#include "modules/libSceVideoOut/codes.h"
#include "modules/libSceVideoOut/types.h"
#include "modules_include/common.h"
#include "overlay/overlay.h"
#include "vulkan/vulkanHelper.h"
#include <SDL2/SDL.h>
@ -173,7 +174,9 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
vulkan::VulkanObj* m_vulkanObj = nullptr;
std::unique_ptr<IGraphics> m_graphics;
std::unique_ptr<IImageHandler> m_imageHandler;
std::unique_ptr<IOverlayHandler> m_overlayHandler;
std::thread m_threadSDL2;
std::condition_variable m_condSDL2;
@ -332,6 +335,8 @@ VideoOut::~VideoOut() {
// printf("VideoOut| waiting on gpu idle\n");
m_imageHandler->stop();
m_graphics->stop();
m_overlayHandler->stop();
vkQueueWaitIdle(m_imageHandler->getQueue()->queue);
// shutdown graphics first (uses vulkan)
@ -347,6 +352,8 @@ VideoOut::~VideoOut() {
m_imageHandler->deinit();
m_imageHandler.reset();
m_overlayHandler.reset();
printf("VideoOut| Destroy vulkan\n");
deinitVulkan(m_vulkanObj);
@ -492,6 +499,7 @@ int VideoOut::SDLInit(uint32_t flags) {
void VideoOut::transferDisplay(ImageData const& imageData, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema, size_t waitValue) {
vulkan::transfer2Display(&displayBufferMeta, imageData, m_graphics.get());
m_overlayHandler->submit(imageData);
vulkan::submitDisplayTransfer(&displayBufferMeta, imageData, m_imageHandler->getQueue(), waitSema, waitValue);
}
@ -782,9 +790,11 @@ std::thread VideoOut::createSDLThread() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
// SDL polling helper
auto func_pollSDL = [](auto& window) {
auto func_pollSDL = [&](auto& window) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
m_overlayHandler->processEvent(&event);
switch (event.type) {
case SDL_WINDOWEVENT:
switch (event.window.event) {
@ -926,6 +936,9 @@ std::thread VideoOut::createSDLThread() {
queue, &window);
m_imageHandler->init(m_vulkanObj, window.surface);
auto [format, _] = vulkan::getDisplayFormat(m_vulkanObj);
m_overlayHandler = createOverlay(m_vulkanObj->deviceInfo, window.window, queue, format);
*item.result = 0;
} else {
vulkan::createSurface(m_vulkanObj, window.window, window.surface);

View File

@ -80,6 +80,10 @@ void submitDisplayTransfer(SwapchainData::DisplayBuffers const* displayBuffer, I
size_t waitValue) {
LOG_USE_MODULE(vulkanHelper);
if (vkEndCommandBuffer(imageData.cmdBuffer) != VK_SUCCESS) {
LOG_CRIT(L"Couldn't end commandbuffer");
}
size_t waitValues[] = {0, waitValue};
uint32_t waitCount = waitSema != nullptr ? 2 : 1;
@ -89,7 +93,7 @@ void submitDisplayTransfer(SwapchainData::DisplayBuffers const* displayBuffer, I
.pWaitSemaphoreValues = waitValues,
};
VkPipelineStageFlags waitStage[] = {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT};
VkPipelineStageFlags waitStage[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT};
VkSemaphore sems[] = {imageData.semImageReady, waitSema};
VkSubmitInfo const submitInfo {
@ -155,12 +159,6 @@ void transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer, ImageD
vkCmdPipelineBarrier(imageData.cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
// - Present layout
// End CmdBuffer -> Submit
if (vkEndCommandBuffer(imageData.cmdBuffer) != VK_SUCCESS) {
LOG_CRIT(L"Couldn't end commandbuffer");
}
// -
}
void presentImage(ImageData const& imageData, VkSwapchainKHR swapchain, QueueInfo const* queue) {