mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-10-30 07:11:05 +00:00
Implement ImGui.
This commit is contained in:
parent
dabda369ca
commit
05e09ba7e2
16 changed files with 361 additions and 23 deletions
|
|
@ -43,6 +43,7 @@ set(SWA_CPU_CXX_SOURCES
|
||||||
|
|
||||||
set(SWA_GPU_CXX_SOURCES
|
set(SWA_GPU_CXX_SOURCES
|
||||||
"gpu/video.cpp"
|
"gpu/video.cpp"
|
||||||
|
"gpu/imgui_snapshot.cpp"
|
||||||
"gpu/rhi/rt64_d3d12.cpp"
|
"gpu/rhi/rt64_d3d12.cpp"
|
||||||
"gpu/rhi/rt64_vulkan.cpp"
|
"gpu/rhi/rt64_vulkan.cpp"
|
||||||
)
|
)
|
||||||
|
|
@ -111,6 +112,7 @@ find_package(directx-dxc REQUIRED)
|
||||||
find_package(zstd CONFIG REQUIRED)
|
find_package(zstd CONFIG REQUIRED)
|
||||||
find_package(Stb REQUIRED)
|
find_package(Stb REQUIRED)
|
||||||
find_package(unofficial-concurrentqueue REQUIRED)
|
find_package(unofficial-concurrentqueue REQUIRED)
|
||||||
|
find_package(imgui CONFIG REQUIRED)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
||||||
add_custom_command(TARGET UnleashedRecomp POST_BUILD
|
add_custom_command(TARGET UnleashedRecomp POST_BUILD
|
||||||
|
|
@ -142,6 +144,7 @@ target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
zstd::libzstd_static
|
zstd::libzstd_static
|
||||||
unofficial::concurrentqueue::concurrentqueue
|
unofficial::concurrentqueue::concurrentqueue
|
||||||
Synchronization
|
Synchronization
|
||||||
|
imgui::imgui
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(UnleashedRecomp PRIVATE
|
target_include_directories(UnleashedRecomp PRIVATE
|
||||||
|
|
@ -178,6 +181,8 @@ function(compile_pixel_shader FILE_PATH)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
compile_vertex_shader(copy_vs)
|
compile_vertex_shader(copy_vs)
|
||||||
|
compile_pixel_shader(imgui_ps)
|
||||||
|
compile_vertex_shader(imgui_vs)
|
||||||
compile_pixel_shader(movie_ps)
|
compile_pixel_shader(movie_ps)
|
||||||
compile_vertex_shader(movie_vs)
|
compile_vertex_shader(movie_vs)
|
||||||
compile_pixel_shader(resolve_msaa_depth_2x)
|
compile_pixel_shader(resolve_msaa_depth_2x)
|
||||||
|
|
|
||||||
54
UnleashedRecomp/gpu/imgui_snapshot.cpp
Normal file
54
UnleashedRecomp/gpu/imgui_snapshot.cpp
Normal file
|
|
@ -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<ImDrawList*> 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
32
UnleashedRecomp/gpu/imgui_snapshot.h
Normal file
32
UnleashedRecomp/gpu/imgui_snapshot.h
Normal file
|
|
@ -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<ImDrawDataSnapshotEntry> 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)); }
|
||||||
|
};
|
||||||
|
|
@ -1265,7 +1265,7 @@ namespace RT64 {
|
||||||
float mipLODBias = 0.0f;
|
float mipLODBias = 0.0f;
|
||||||
uint32_t maxAnisotropy = 16;
|
uint32_t maxAnisotropy = 16;
|
||||||
bool anisotropyEnabled = false;
|
bool anisotropyEnabled = false;
|
||||||
RenderComparisonFunction comparisonFunc = RenderComparisonFunction::LESS_EQUAL;
|
RenderComparisonFunction comparisonFunc = RenderComparisonFunction::NEVER;
|
||||||
bool comparisonEnabled = false;
|
bool comparisonEnabled = false;
|
||||||
RenderBorderColor borderColor = RenderBorderColor::OPAQUE_BLACK;
|
RenderBorderColor borderColor = RenderBorderColor::OPAQUE_BLACK;
|
||||||
float minLOD = 0.0f;
|
float minLOD = 0.0f;
|
||||||
|
|
|
||||||
18
UnleashedRecomp/gpu/shader/imgui_common.hlsli
Normal file
18
UnleashedRecomp/gpu/shader/imgui_common.hlsli
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct PushConstants
|
||||||
|
{
|
||||||
|
uint Texture2DDescriptorIndex;
|
||||||
|
float2 InverseDisplaySize;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
|
||||||
|
SamplerState g_SamplerDescriptorHeap[] : register(s0, space1);
|
||||||
|
[[vk::push_constant]] ConstantBuffer<PushConstants> g_PushConstants : register(b0, space2);
|
||||||
|
|
||||||
|
struct Interpolators
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float2 UV : TEXCOORD;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
};
|
||||||
11
UnleashedRecomp/gpu/shader/imgui_ps.hlsl
Normal file
11
UnleashedRecomp/gpu/shader/imgui_ps.hlsl
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
8
UnleashedRecomp/gpu/shader/imgui_vs.hlsl
Normal file
8
UnleashedRecomp/gpu/shader/imgui_vs.hlsl
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli"
|
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli"
|
||||||
|
|
||||||
#ifdef __spirv__
|
#ifdef __spirv__
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "movie_common.hlsl"
|
#include "movie_common.hlsli"
|
||||||
|
|
||||||
PixelShaderOutput main(in Interpolators In)
|
PixelShaderOutput main(in Interpolators In)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "movie_common.hlsl"
|
#include "movie_common.hlsli"
|
||||||
|
|
||||||
Interpolators main(in VertexShaderInput In)
|
Interpolators main(in VertexShaderInput In)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
struct PushConstants
|
struct PushConstants
|
||||||
{
|
{
|
||||||
uint ResourceDescriptorIndex;
|
uint ResourceDescriptorIndex;
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,17 @@
|
||||||
#include <xxHashMap.h>
|
#include <xxHashMap.h>
|
||||||
#include <shader/shader_cache.h>
|
#include <shader/shader_cache.h>
|
||||||
|
|
||||||
|
#include "imgui_snapshot.h"
|
||||||
#include "gpu/video.h"
|
#include "gpu/video.h"
|
||||||
#include "ui/window.h"
|
#include "ui/window.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "shader/copy_vs.hlsl.dxil.h"
|
#include "shader/copy_vs.hlsl.dxil.h"
|
||||||
#include "shader/copy_vs.hlsl.spirv.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.dxil.h"
|
||||||
#include "shader/movie_vs.hlsl.spirv.h"
|
#include "shader/movie_vs.hlsl.spirv.h"
|
||||||
#include "shader/movie_ps.hlsl.dxil.h"
|
#include "shader/movie_ps.hlsl.dxil.h"
|
||||||
|
|
@ -516,6 +521,7 @@ enum class RenderCommandType
|
||||||
UnlockTextureRect,
|
UnlockTextureRect,
|
||||||
UnlockBuffer16,
|
UnlockBuffer16,
|
||||||
UnlockBuffer32,
|
UnlockBuffer32,
|
||||||
|
DrawImGui,
|
||||||
Present,
|
Present,
|
||||||
StretchRect,
|
StretchRect,
|
||||||
SetRenderTarget,
|
SetRenderTarget,
|
||||||
|
|
@ -952,11 +958,146 @@ static bool DetectWine()
|
||||||
return dllHandle != nullptr && GetProcAddress(dllHandle, "wine_get_version") != nullptr;
|
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<RenderTexture> g_imFontTexture;
|
||||||
|
static std::unique_ptr<RenderTextureView> g_imFontTextureView;
|
||||||
|
static uint32_t g_imFontTextureDescriptorIndex;
|
||||||
|
static bool g_imPendingBarrier = true;
|
||||||
|
static std::unique_ptr<RenderPipelineLayout> g_imPipelineLayout;
|
||||||
|
static std::unique_ptr<RenderPipeline> g_imPipeline;
|
||||||
|
static ImDrawDataSnapshot g_imSnapshot;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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<uint8_t*>(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()
|
static void CreateHostDevice()
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < 16; i++)
|
for (uint32_t i = 0; i < 16; i++)
|
||||||
g_inputSlots[i].index = i;
|
g_inputSlots[i].index = i;
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
Window::Init();
|
Window::Init();
|
||||||
|
|
||||||
g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan;
|
g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan;
|
||||||
|
|
@ -995,9 +1136,6 @@ static void CreateHostDevice()
|
||||||
RenderPipelineLayoutBuilder pipelineLayoutBuilder;
|
RenderPipelineLayoutBuilder pipelineLayoutBuilder;
|
||||||
pipelineLayoutBuilder.begin(false, true);
|
pipelineLayoutBuilder.begin(false, true);
|
||||||
|
|
||||||
constexpr size_t TEXTURE_DESCRIPTOR_SIZE = 65536;
|
|
||||||
constexpr size_t SAMPLER_DESCRIPTOR_SIZE = 1024;
|
|
||||||
|
|
||||||
RenderDescriptorSetBuilder descriptorSetBuilder;
|
RenderDescriptorSetBuilder descriptorSetBuilder;
|
||||||
descriptorSetBuilder.begin();
|
descriptorSetBuilder.begin();
|
||||||
descriptorSetBuilder.addTexture(0, TEXTURE_DESCRIPTOR_SIZE);
|
descriptorSetBuilder.addTexture(0, TEXTURE_DESCRIPTOR_SIZE);
|
||||||
|
|
@ -1113,6 +1251,8 @@ static void CreateHostDevice()
|
||||||
desc.depthTargetFormat = RenderFormat::D32_FLOAT;
|
desc.depthTargetFormat = RenderFormat::D32_FLOAT;
|
||||||
g_resolveMsaaDepthPipelines[i] = g_device->createGraphicsPipeline(desc);
|
g_resolveMsaaDepthPipelines[i] = g_device->createGraphicsPipeline(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateImGuiBackend();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WaitForGPU()
|
static void WaitForGPU()
|
||||||
|
|
@ -1252,9 +1392,6 @@ static void ProcDestructResource(const RenderCommand& cmd)
|
||||||
g_tempResources[g_frame].push_back(args.resource);
|
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)
|
static uint32_t ComputeTexturePitch(GuestTexture* texture)
|
||||||
{
|
{
|
||||||
return (texture->width * RenderFormatSize(texture->format) + PITCH_ALIGNMENT - 1) & ~(PITCH_ALIGNMENT - 1);
|
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);
|
return LockBuffer(buffer, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
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<typename T>
|
template<typename T>
|
||||||
static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue)
|
static void UnlockBuffer(GuestBuffer* buffer, bool useCopyQueue)
|
||||||
{
|
{
|
||||||
|
|
@ -1434,9 +1559,79 @@ static uint32_t HashVertexDeclaration(uint32_t vertexDeclaration)
|
||||||
return 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<false>(drawList->VtxBuffer.Data, drawList->VtxBuffer.Size * sizeof(ImDrawVert), alignof(ImDrawVert));
|
||||||
|
auto indexBufferAllocation = g_uploadAllocators[g_frame].allocate<false>(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()
|
static void Present()
|
||||||
{
|
{
|
||||||
|
DrawImGui();
|
||||||
WaitForRenderThread();
|
WaitForRenderThread();
|
||||||
|
|
||||||
g_pendingRenderThread = true;
|
g_pendingRenderThread = true;
|
||||||
|
|
||||||
RenderCommand cmd;
|
RenderCommand cmd;
|
||||||
|
|
@ -2954,6 +3149,7 @@ static std::thread g_renderThread([]
|
||||||
case RenderCommandType::UnlockTextureRect: ProcUnlockTextureRect(cmd); break;
|
case RenderCommandType::UnlockTextureRect: ProcUnlockTextureRect(cmd); break;
|
||||||
case RenderCommandType::UnlockBuffer16: ProcUnlockBuffer16(cmd); break;
|
case RenderCommandType::UnlockBuffer16: ProcUnlockBuffer16(cmd); break;
|
||||||
case RenderCommandType::UnlockBuffer32: ProcUnlockBuffer32(cmd); break;
|
case RenderCommandType::UnlockBuffer32: ProcUnlockBuffer32(cmd); break;
|
||||||
|
case RenderCommandType::DrawImGui: ProcDrawImGui(cmd); break;
|
||||||
case RenderCommandType::Present: ProcPresent(cmd); break;
|
case RenderCommandType::Present: ProcPresent(cmd); break;
|
||||||
case RenderCommandType::StretchRect: ProcStretchRect(cmd); break;
|
case RenderCommandType::StretchRect: ProcStretchRect(cmd); break;
|
||||||
case RenderCommandType::SetRenderTarget: ProcSetRenderTarget(cmd); break;
|
case RenderCommandType::SetRenderTarget: ProcSetRenderTarget(cmd); break;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <concurrentqueue/blockingconcurrentqueue.h>
|
#include <concurrentqueue/blockingconcurrentqueue.h>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
#include <imgui_impl_sdl2.h>
|
||||||
|
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ bool m_isFullscreenKeyReleased = true;
|
||||||
|
|
||||||
int Window_OnSDLEvent(void*, SDL_Event* event)
|
int Window_OnSDLEvent(void*, SDL_Event* event)
|
||||||
{
|
{
|
||||||
|
if (ImGui::GetIO().BackendPlatformUserData != nullptr)
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(event);
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include "res/icon.h"
|
#include "res/icon.h"
|
||||||
#include "ui/window_events.h"
|
#include "ui/window_events.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@
|
||||||
"tomlplusplus",
|
"tomlplusplus",
|
||||||
"zstd",
|
"zstd",
|
||||||
"stb",
|
"stb",
|
||||||
"concurrentqueue"
|
"concurrentqueue",
|
||||||
|
{
|
||||||
|
"name": "imgui",
|
||||||
|
"features": [ "sdl2-binding" ]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue