From 05e09ba7e242072602620fd378a025910e6be717 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Sat, 9 Nov 2024 21:47:50 +0300 Subject: [PATCH] Implement ImGui. --- UnleashedRecomp/CMakeLists.txt | 5 + UnleashedRecomp/gpu/imgui_snapshot.cpp | 54 ++++ UnleashedRecomp/gpu/imgui_snapshot.h | 32 +++ .../gpu/rhi/rt64_render_interface_types.h | 2 +- UnleashedRecomp/gpu/shader/imgui_common.hlsli | 18 ++ UnleashedRecomp/gpu/shader/imgui_ps.hlsl | 11 + UnleashedRecomp/gpu/shader/imgui_vs.hlsl | 8 + .../{movie_common.hlsl => movie_common.hlsli} | 2 + UnleashedRecomp/gpu/shader/movie_ps.hlsl | 2 +- UnleashedRecomp/gpu/shader/movie_vs.hlsl | 2 +- .../gpu/shader/resolve_msaa_depth.hlsli | 2 + UnleashedRecomp/gpu/video.cpp | 232 ++++++++++++++++-- UnleashedRecomp/stdafx.h | 4 + UnleashedRecomp/ui/window.cpp | 3 + UnleashedRecomp/ui/window.h | 1 - vcpkg.json | 6 +- 16 files changed, 361 insertions(+), 23 deletions(-) create mode 100644 UnleashedRecomp/gpu/imgui_snapshot.cpp create mode 100644 UnleashedRecomp/gpu/imgui_snapshot.h create mode 100644 UnleashedRecomp/gpu/shader/imgui_common.hlsli create mode 100644 UnleashedRecomp/gpu/shader/imgui_ps.hlsl create mode 100644 UnleashedRecomp/gpu/shader/imgui_vs.hlsl rename UnleashedRecomp/gpu/shader/{movie_common.hlsl => movie_common.hlsli} (99%) diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 1beca68..552f9fb 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -43,6 +43,7 @@ set(SWA_CPU_CXX_SOURCES set(SWA_GPU_CXX_SOURCES "gpu/video.cpp" + "gpu/imgui_snapshot.cpp" "gpu/rhi/rt64_d3d12.cpp" "gpu/rhi/rt64_vulkan.cpp" ) @@ -111,6 +112,7 @@ find_package(directx-dxc REQUIRED) find_package(zstd CONFIG REQUIRED) find_package(Stb REQUIRED) find_package(unofficial-concurrentqueue REQUIRED) +find_package(imgui CONFIG REQUIRED) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) add_custom_command(TARGET UnleashedRecomp POST_BUILD @@ -142,6 +144,7 @@ target_link_libraries(UnleashedRecomp PRIVATE zstd::libzstd_static unofficial::concurrentqueue::concurrentqueue Synchronization + imgui::imgui ) target_include_directories(UnleashedRecomp PRIVATE @@ -178,6 +181,8 @@ function(compile_pixel_shader FILE_PATH) endfunction() compile_vertex_shader(copy_vs) +compile_pixel_shader(imgui_ps) +compile_vertex_shader(imgui_vs) compile_pixel_shader(movie_ps) compile_vertex_shader(movie_vs) compile_pixel_shader(resolve_msaa_depth_2x) diff --git a/UnleashedRecomp/gpu/imgui_snapshot.cpp b/UnleashedRecomp/gpu/imgui_snapshot.cpp new file mode 100644 index 0000000..492b61f --- /dev/null +++ b/UnleashedRecomp/gpu/imgui_snapshot.cpp @@ -0,0 +1,54 @@ +#include "imgui_snapshot.h" + +void ImDrawDataSnapshot::Clear() +{ + for (int n = 0; n < Cache.GetMapSize(); n++) + if (ImDrawDataSnapshotEntry* entry = Cache.TryGetMapData(n)) + IM_DELETE(entry->OurCopy); + Cache.Clear(); + DrawData.Clear(); +} + +void ImDrawDataSnapshot::SnapUsingSwap(ImDrawData* src, double current_time) +{ + ImDrawData* dst = &DrawData; + IM_ASSERT(src != dst && src->Valid); + + // Copy all fields except CmdLists[] + ImVector backup_draw_list; + backup_draw_list.swap(src->CmdLists); + IM_ASSERT(src->CmdLists.Data == NULL); + *dst = *src; + backup_draw_list.swap(src->CmdLists); + + // Swap and mark as used + for (ImDrawList* src_list : src->CmdLists) + { + ImDrawDataSnapshotEntry* entry = GetOrAddEntry(src_list); + if (entry->OurCopy == NULL) + { + entry->SrcCopy = src_list; + entry->OurCopy = IM_NEW(ImDrawList)(src_list->_Data); + } + IM_ASSERT(entry->SrcCopy == src_list); + entry->SrcCopy->CmdBuffer.swap(entry->OurCopy->CmdBuffer); // Cheap swap + entry->SrcCopy->IdxBuffer.swap(entry->OurCopy->IdxBuffer); + entry->SrcCopy->VtxBuffer.swap(entry->OurCopy->VtxBuffer); + entry->SrcCopy->CmdBuffer.reserve(entry->OurCopy->CmdBuffer.Capacity); // Preserve bigger size to avoid reallocs for two consecutive frames + entry->SrcCopy->IdxBuffer.reserve(entry->OurCopy->IdxBuffer.Capacity); + entry->SrcCopy->VtxBuffer.reserve(entry->OurCopy->VtxBuffer.Capacity); + entry->LastUsedTime = current_time; + dst->CmdLists.push_back(entry->OurCopy); + } + + // Cleanup unused data + const double gc_threshold = current_time - MemoryCompactTimer; + for (int n = 0; n < Cache.GetMapSize(); n++) + if (ImDrawDataSnapshotEntry* entry = Cache.TryGetMapData(n)) + { + if (entry->LastUsedTime > gc_threshold) + continue; + IM_DELETE(entry->OurCopy); + Cache.Remove(GetDrawListID(entry->SrcCopy), entry); + } +}; diff --git a/UnleashedRecomp/gpu/imgui_snapshot.h b/UnleashedRecomp/gpu/imgui_snapshot.h new file mode 100644 index 0000000..f08393b --- /dev/null +++ b/UnleashedRecomp/gpu/imgui_snapshot.h @@ -0,0 +1,32 @@ +#pragma once + +// https://github.com/ocornut/imgui/issues/1860#issuecomment-1927630727 + +// Usage: +// static ImDrawDataSnapshot snapshot; // Important: make persistent accross frames to reuse buffers. +// snapshot.SnapUsingSwap(ImGui::GetDrawData(), ImGui::GetTime()); +// [...] +// ImGui_ImplDX11_RenderDrawData(&snapshot.DrawData); + +struct ImDrawDataSnapshotEntry +{ + ImDrawList* SrcCopy = NULL; + ImDrawList* OurCopy = NULL; + double LastUsedTime = 0.0; +}; + +struct ImDrawDataSnapshot +{ + // Members + ImDrawData DrawData; + ImPool Cache; + float MemoryCompactTimer = 20.0f; // Discard unused data after 20 seconds + + ~ImDrawDataSnapshot() { Clear(); } + void Clear(); + void SnapUsingSwap(ImDrawData* src, double current_time); // Efficient snapshot by swapping data, meaning "src_list" is unusable. + + // Internals + ImGuiID GetDrawListID(ImDrawList* src_list) { return ImHashData(&src_list, sizeof(src_list)); } // Hash pointer + ImDrawDataSnapshotEntry* GetOrAddEntry(ImDrawList* src_list) { return Cache.GetOrAddByKey(GetDrawListID(src_list)); } +}; diff --git a/UnleashedRecomp/gpu/rhi/rt64_render_interface_types.h b/UnleashedRecomp/gpu/rhi/rt64_render_interface_types.h index e7c716f..1f2e3ee 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_render_interface_types.h +++ b/UnleashedRecomp/gpu/rhi/rt64_render_interface_types.h @@ -1265,7 +1265,7 @@ namespace RT64 { float mipLODBias = 0.0f; uint32_t maxAnisotropy = 16; bool anisotropyEnabled = false; - RenderComparisonFunction comparisonFunc = RenderComparisonFunction::LESS_EQUAL; + RenderComparisonFunction comparisonFunc = RenderComparisonFunction::NEVER; bool comparisonEnabled = false; RenderBorderColor borderColor = RenderBorderColor::OPAQUE_BLACK; float minLOD = 0.0f; diff --git a/UnleashedRecomp/gpu/shader/imgui_common.hlsli b/UnleashedRecomp/gpu/shader/imgui_common.hlsli new file mode 100644 index 0000000..d54f529 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/imgui_common.hlsli @@ -0,0 +1,18 @@ +#pragma once + +struct PushConstants +{ + uint Texture2DDescriptorIndex; + float2 InverseDisplaySize; +}; + +Texture2D g_Texture2DDescriptorHeap[] : register(t0, space0); +SamplerState g_SamplerDescriptorHeap[] : register(s0, space1); +[[vk::push_constant]] ConstantBuffer g_PushConstants : register(b0, space2); + +struct Interpolators +{ + float4 Position : SV_Position; + float2 UV : TEXCOORD; + float4 Color : COLOR; +}; diff --git a/UnleashedRecomp/gpu/shader/imgui_ps.hlsl b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl new file mode 100644 index 0000000..bc0cd76 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl @@ -0,0 +1,11 @@ +#include "imgui_common.hlsli" + +float4 main(in Interpolators interpolators) : SV_Target +{ + float4 color = interpolators.Color; + + if (g_PushConstants.Texture2DDescriptorIndex != 0) + color *= g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex].Sample(g_SamplerDescriptorHeap[0], interpolators.UV); + + return color; +} diff --git a/UnleashedRecomp/gpu/shader/imgui_vs.hlsl b/UnleashedRecomp/gpu/shader/imgui_vs.hlsl new file mode 100644 index 0000000..90481cd --- /dev/null +++ b/UnleashedRecomp/gpu/shader/imgui_vs.hlsl @@ -0,0 +1,8 @@ +#include "imgui_common.hlsli" + +void main(in float2 position : POSITION, in float2 uv : TEXCOORD, in float4 color : COLOR, out Interpolators interpolators) +{ + interpolators.Position = float4(position * g_PushConstants.InverseDisplaySize * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); + interpolators.UV = uv; + interpolators.Color = color; +} diff --git a/UnleashedRecomp/gpu/shader/movie_common.hlsl b/UnleashedRecomp/gpu/shader/movie_common.hlsli similarity index 99% rename from UnleashedRecomp/gpu/shader/movie_common.hlsl rename to UnleashedRecomp/gpu/shader/movie_common.hlsli index 69ce580..d890e48 100644 --- a/UnleashedRecomp/gpu/shader/movie_common.hlsl +++ b/UnleashedRecomp/gpu/shader/movie_common.hlsli @@ -1,3 +1,5 @@ +#pragma once + #include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli" #ifdef __spirv__ diff --git a/UnleashedRecomp/gpu/shader/movie_ps.hlsl b/UnleashedRecomp/gpu/shader/movie_ps.hlsl index 7d788cd..f60e5fe 100644 --- a/UnleashedRecomp/gpu/shader/movie_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/movie_ps.hlsl @@ -1,4 +1,4 @@ -#include "movie_common.hlsl" +#include "movie_common.hlsli" PixelShaderOutput main(in Interpolators In) { diff --git a/UnleashedRecomp/gpu/shader/movie_vs.hlsl b/UnleashedRecomp/gpu/shader/movie_vs.hlsl index 0d92472..c4e47c1 100644 --- a/UnleashedRecomp/gpu/shader/movie_vs.hlsl +++ b/UnleashedRecomp/gpu/shader/movie_vs.hlsl @@ -1,4 +1,4 @@ -#include "movie_common.hlsl" +#include "movie_common.hlsli" Interpolators main(in VertexShaderInput In) { diff --git a/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli b/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli index d06c83d..bc04695 100644 --- a/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli +++ b/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli @@ -1,3 +1,5 @@ +#pragma once + struct PushConstants { uint ResourceDescriptorIndex; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 17cdfd5..2df3def 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -8,12 +8,17 @@ #include #include +#include "imgui_snapshot.h" #include "gpu/video.h" #include "ui/window.h" #include "config.h" #include "shader/copy_vs.hlsl.dxil.h" #include "shader/copy_vs.hlsl.spirv.h" +#include "shader/imgui_ps.hlsl.dxil.h" +#include "shader/imgui_ps.hlsl.spirv.h" +#include "shader/imgui_vs.hlsl.dxil.h" +#include "shader/imgui_vs.hlsl.spirv.h" #include "shader/movie_vs.hlsl.dxil.h" #include "shader/movie_vs.hlsl.spirv.h" #include "shader/movie_ps.hlsl.dxil.h" @@ -516,6 +521,7 @@ enum class RenderCommandType UnlockTextureRect, UnlockBuffer16, UnlockBuffer32, + DrawImGui, Present, StretchRect, SetRenderTarget, @@ -952,11 +958,146 @@ static bool DetectWine() return dllHandle != nullptr && GetProcAddress(dllHandle, "wine_get_version") != nullptr; } +static constexpr size_t TEXTURE_DESCRIPTOR_SIZE = 65536; +static constexpr size_t SAMPLER_DESCRIPTOR_SIZE = 1024; + +static std::unique_ptr g_imFontTexture; +static std::unique_ptr g_imFontTextureView; +static uint32_t g_imFontTextureDescriptorIndex; +static bool g_imPendingBarrier = true; +static std::unique_ptr g_imPipelineLayout; +static std::unique_ptr g_imPipeline; +static ImDrawDataSnapshot g_imSnapshot; + +template +static void ExecuteCopyCommandList(const T& function) +{ + std::lock_guard lock(g_copyMutex); + + g_copyCommandList->begin(); + function(); + g_copyCommandList->end(); + g_copyQueue->executeCommandLists(g_copyCommandList.get(), g_copyCommandFence.get()); + g_copyQueue->waitForCommandFence(g_copyCommandFence.get()); +} + +static constexpr uint32_t PITCH_ALIGNMENT = 0x100; +static constexpr uint32_t PLACEMENT_ALIGNMENT = 0x200; + +static void CreateImGuiBackend() +{ + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; + + ImGui_ImplSDL2_InitForOther(Window::s_pWindow); + + uint8_t* pixels; + int width, height; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); + + RenderTextureDesc textureDesc; + textureDesc.dimension = RenderTextureDimension::TEXTURE_2D; + textureDesc.width = width; + textureDesc.height = height; + textureDesc.depth = 1; + textureDesc.mipLevels = 1; + textureDesc.arraySize = 1; + textureDesc.format = RenderFormat::R8_UNORM; + g_imFontTexture = g_device->createTexture(textureDesc); + + uint32_t rowPitch = (width + PITCH_ALIGNMENT - 1) & ~(PITCH_ALIGNMENT - 1); + uint32_t slicePitch = (rowPitch * height + PLACEMENT_ALIGNMENT - 1) & ~(PLACEMENT_ALIGNMENT - 1); + auto uploadBuffer = g_device->createBuffer(RenderBufferDesc::UploadBuffer(slicePitch)); + uint8_t* mappedMemory = reinterpret_cast(uploadBuffer->map()); + + if (rowPitch == width) + { + memcpy(mappedMemory, pixels, slicePitch); + } + else + { + for (size_t i = 0; i < height; i++) + { + memcpy(mappedMemory, pixels, width); + pixels += width; + mappedMemory += rowPitch; + } + } + + uploadBuffer->unmap(); + + ExecuteCopyCommandList([&] + { + g_copyCommandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(g_imFontTexture.get(), RenderTextureLayout::COPY_DEST)); + + g_copyCommandList->copyTextureRegion( + RenderTextureCopyLocation::Subresource(g_imFontTexture.get(), 0), + RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), RenderFormat::R8_UNORM, width, height, 1, rowPitch, 0)); + }); + + RenderTextureViewDesc textureViewDesc; + textureViewDesc.format = textureDesc.format; + textureViewDesc.dimension = RenderTextureViewDimension::TEXTURE_2D; + textureViewDesc.mipLevels = 1; + textureViewDesc.componentMapping = RenderComponentMapping(RenderSwizzle::ONE, RenderSwizzle::ONE, RenderSwizzle::ONE, RenderSwizzle::R); + g_imFontTextureView = g_imFontTexture->createTextureView(textureViewDesc); + + g_imFontTextureDescriptorIndex = g_textureDescriptorAllocator.allocate(); + g_textureDescriptorSet->setTexture(g_imFontTextureDescriptorIndex, g_imFontTexture.get(), RenderTextureLayout::SHADER_READ, g_imFontTextureView.get()); + + io.Fonts->SetTexID(ImTextureID(g_imFontTextureDescriptorIndex)); + + RenderPipelineLayoutBuilder pipelineLayoutBuilder; + pipelineLayoutBuilder.begin(false, true); + + RenderDescriptorSetBuilder descriptorSetBuilder; + descriptorSetBuilder.begin(); + descriptorSetBuilder.addTexture(0, TEXTURE_DESCRIPTOR_SIZE); + descriptorSetBuilder.end(true, TEXTURE_DESCRIPTOR_SIZE); + pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); + + descriptorSetBuilder.begin(); + descriptorSetBuilder.addSampler(0, SAMPLER_DESCRIPTOR_SIZE); + descriptorSetBuilder.end(true, SAMPLER_DESCRIPTOR_SIZE); + pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); + + pipelineLayoutBuilder.addPushConstant(0, 2, 12, RenderShaderStageFlag::VERTEX | RenderShaderStageFlag::PIXEL); + + pipelineLayoutBuilder.end(); + g_imPipelineLayout = pipelineLayoutBuilder.create(g_device.get()); + + auto vertexShader = CREATE_SHADER(imgui_vs); + auto pixelShader = CREATE_SHADER(imgui_ps); + + RenderInputElement inputElements[3]; + inputElements[0] = RenderInputElement("POSITION", 0, 0, RenderFormat::R32G32_FLOAT, 0, offsetof(ImDrawVert, pos)); + inputElements[1] = RenderInputElement("TEXCOORD", 0, 1, RenderFormat::R32G32_FLOAT, 0, offsetof(ImDrawVert, uv)); + inputElements[2] = RenderInputElement("COLOR", 0, 2, RenderFormat::R8G8B8A8_UNORM, 0, offsetof(ImDrawVert, col)); + + RenderInputSlot inputSlot(0, sizeof(ImDrawVert)); + + RenderGraphicsPipelineDesc pipelineDesc; + pipelineDesc.pipelineLayout = g_imPipelineLayout.get(); + pipelineDesc.vertexShader = vertexShader.get(); + pipelineDesc.pixelShader = pixelShader.get(); + pipelineDesc.renderTargetFormat[0] = RenderFormat::B8G8R8A8_UNORM; + pipelineDesc.renderTargetBlend[0] = RenderBlendDesc::AlphaBlend(); + pipelineDesc.renderTargetCount = 1; + pipelineDesc.inputElements = inputElements; + pipelineDesc.inputElementsCount = std::size(inputElements); + pipelineDesc.inputSlots = &inputSlot; + pipelineDesc.inputSlotsCount = 1; + g_imPipeline = g_device->createGraphicsPipeline(pipelineDesc); +} + static void CreateHostDevice() { for (uint32_t i = 0; i < 16; i++) g_inputSlots[i].index = i; + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + Window::Init(); g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan; @@ -994,9 +1135,6 @@ static void CreateHostDevice() RenderPipelineLayoutBuilder pipelineLayoutBuilder; pipelineLayoutBuilder.begin(false, true); - - constexpr size_t TEXTURE_DESCRIPTOR_SIZE = 65536; - constexpr size_t SAMPLER_DESCRIPTOR_SIZE = 1024; RenderDescriptorSetBuilder descriptorSetBuilder; descriptorSetBuilder.begin(); @@ -1113,6 +1251,8 @@ static void CreateHostDevice() desc.depthTargetFormat = RenderFormat::D32_FLOAT; g_resolveMsaaDepthPipelines[i] = g_device->createGraphicsPipeline(desc); } + + CreateImGuiBackend(); } static void WaitForGPU() @@ -1252,9 +1392,6 @@ static void ProcDestructResource(const RenderCommand& cmd) g_tempResources[g_frame].push_back(args.resource); } -static constexpr uint32_t PITCH_ALIGNMENT = 0x100; -static constexpr uint32_t PLACEMENT_ALIGNMENT = 0x200; - static uint32_t ComputeTexturePitch(GuestTexture* texture) { return (texture->width * RenderFormatSize(texture->format) + PITCH_ALIGNMENT - 1) & ~(PITCH_ALIGNMENT - 1); @@ -1313,18 +1450,6 @@ static void* LockVertexBuffer(GuestBuffer* buffer, uint32_t, uint32_t, uint32_t return LockBuffer(buffer, flags); } -template -static void ExecuteCopyCommandList(const T& function) -{ - std::lock_guard lock(g_copyMutex); - - g_copyCommandList->begin(); - function(); - g_copyCommandList->end(); - g_copyQueue->executeCommandLists(g_copyCommandList.get(), g_copyCommandFence.get()); - g_copyQueue->waitForCommandFence(g_copyCommandFence.get()); -} - template static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue) { @@ -1434,9 +1559,79 @@ static uint32_t HashVertexDeclaration(uint32_t vertexDeclaration) return vertexDeclaration; } +static void DrawImGui() +{ + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + // ImGui logic here + ImGui::Render(); + + auto drawData = ImGui::GetDrawData(); + if (drawData->CmdListsCount != 0) + { + g_imSnapshot.SnapUsingSwap(drawData, ImGui::GetTime()); + + RenderCommand cmd; + cmd.type = RenderCommandType::DrawImGui; + g_renderQueue.enqueue(cmd); + } +} + +static void ProcDrawImGui(const RenderCommand& cmd) +{ + auto& commandList = g_commandLists[g_frame]; + + if (g_imPendingBarrier) + { + commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(g_imFontTexture.get(), RenderTextureLayout::SHADER_READ)); + g_imPendingBarrier = false; + } + + commandList->setGraphicsPipelineLayout(g_imPipelineLayout.get()); + commandList->setPipeline(g_imPipeline.get()); + commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 0); + commandList->setGraphicsDescriptorSet(g_samplerDescriptorSet.get(), 1); + + auto& drawData = g_imSnapshot.DrawData; + commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y)); + + float inverseDisplaySize[] = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y }; + commandList->setGraphicsPushConstants(0, inverseDisplaySize, 4, 8); + + for (int i = 0; i < drawData.CmdListsCount; i++) + { + auto& drawList = drawData.CmdLists[i]; + + auto vertexBufferAllocation = g_uploadAllocators[g_frame].allocate(drawList->VtxBuffer.Data, drawList->VtxBuffer.Size * sizeof(ImDrawVert), alignof(ImDrawVert)); + auto indexBufferAllocation = g_uploadAllocators[g_frame].allocate(drawList->IdxBuffer.Data, drawList->IdxBuffer.Size * sizeof(uint16_t), alignof(uint16_t)); + + const RenderVertexBufferView vertexBufferView(vertexBufferAllocation.buffer->at(vertexBufferAllocation.offset), drawList->VtxBuffer.Size * sizeof(ImDrawVert)); + const RenderInputSlot inputSlot(0, sizeof(ImDrawVert)); + commandList->setVertexBuffers(0, &vertexBufferView, 1, &inputSlot); + + const RenderIndexBufferView indexBufferView(indexBufferAllocation.buffer->at(indexBufferAllocation.offset), drawList->IdxBuffer.Size * sizeof(uint16_t), RenderFormat::R16_UINT); + commandList->setIndexBuffer(&indexBufferView); + + for (int j = 0; j < drawList->CmdBuffer.Size; j++) + { + auto& drawCmd = drawList->CmdBuffer[j]; + + if (drawCmd.ClipRect.z <= drawCmd.ClipRect.x || drawCmd.ClipRect.w <= drawCmd.ClipRect.y) + continue; + + uint32_t descriptorIndex = uint32_t(drawCmd.GetTexID()); + commandList->setGraphicsPushConstants(0, &descriptorIndex, 0, 4); + commandList->setScissors(RenderRect(int32_t(drawCmd.ClipRect.x), int32_t(drawCmd.ClipRect.y), int32_t(drawCmd.ClipRect.z), int32_t(drawCmd.ClipRect.w))); + commandList->drawIndexedInstanced(drawCmd.ElemCount, 1, drawCmd.IdxOffset, drawCmd.VtxOffset, 0); + } + } +} + static void Present() { + DrawImGui(); WaitForRenderThread(); + g_pendingRenderThread = true; RenderCommand cmd; @@ -2954,6 +3149,7 @@ static std::thread g_renderThread([] case RenderCommandType::UnlockTextureRect: ProcUnlockTextureRect(cmd); break; case RenderCommandType::UnlockBuffer16: ProcUnlockBuffer16(cmd); break; case RenderCommandType::UnlockBuffer32: ProcUnlockBuffer32(cmd); break; + case RenderCommandType::DrawImGui: ProcDrawImGui(cmd); break; case RenderCommandType::Present: ProcPresent(cmd); break; case RenderCommandType::StretchRect: ProcStretchRect(cmd); break; case RenderCommandType::SetRenderTarget: ProcSetRenderTarget(cmd); break; diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index 5e0607d..b0075c4 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include "framework.h" #include "mutex.h" diff --git a/UnleashedRecomp/ui/window.cpp b/UnleashedRecomp/ui/window.cpp index 85f87c2..fb5b746 100644 --- a/UnleashedRecomp/ui/window.cpp +++ b/UnleashedRecomp/ui/window.cpp @@ -7,6 +7,9 @@ bool m_isFullscreenKeyReleased = true; int Window_OnSDLEvent(void*, SDL_Event* event) { + if (ImGui::GetIO().BackendPlatformUserData != nullptr) + ImGui_ImplSDL2_ProcessEvent(event); + switch (event->type) { case SDL_QUIT: diff --git a/UnleashedRecomp/ui/window.h b/UnleashedRecomp/ui/window.h index f463168..85a8399 100644 --- a/UnleashedRecomp/ui/window.h +++ b/UnleashedRecomp/ui/window.h @@ -1,6 +1,5 @@ #pragma once -#include #include "res/icon.h" #include "ui/window_events.h" #include "config.h" diff --git a/vcpkg.json b/vcpkg.json index f394886..46ee79a 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -15,6 +15,10 @@ "tomlplusplus", "zstd", "stb", - "concurrentqueue" + "concurrentqueue", + { + "name": "imgui", + "features": [ "sdl2-binding" ] + } ] }