mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-06 02:33:15 +00:00
Rewrite Save Data & Impl Save Data Dialog (#824)
* core: Rewrite PSF parser & add encoder add .sfo hex pattern to /scripts * core/fs: allow to mount path as read-only * common: Add CString wrapper to handle native null-terminated strings * SaveData: rewrite to implement full functionality * mock value for SYSTEM_VER * SavaData: backup features * SavaData: SaveDataMemory features * imgui Ref-counted textures - has a background thread to decode textures * imgui: rework gamepad navigation * PSF: fixed psf not using enum class for PSFEntryFmt (was a standard old ugly enum) - Add null check to CString when itself is used in a nullable field * SaveDataDialog implementation - Fix Mounting/Unmounting check of SaveInstance
This commit is contained in:
parent
077f8981a7
commit
0f4bcd8c83
51 changed files with 4919 additions and 1134 deletions
|
@ -4,6 +4,8 @@
|
|||
// Based on imgui_impl_vulkan.cpp from Dear ImGui repository
|
||||
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "imgui_impl_vulkan.h"
|
||||
|
@ -47,13 +49,15 @@ struct VkData {
|
|||
vk::ShaderModule shader_module_vert{};
|
||||
vk::ShaderModule shader_module_frag{};
|
||||
|
||||
std::mutex command_pool_mutex;
|
||||
vk::CommandPool command_pool{};
|
||||
vk::Sampler simple_sampler{};
|
||||
|
||||
// Font data
|
||||
vk::Sampler font_sampler{};
|
||||
vk::DeviceMemory font_memory{};
|
||||
vk::Image font_image{};
|
||||
vk::ImageView font_view{};
|
||||
vk::DescriptorSet font_descriptor_set{};
|
||||
vk::CommandPool font_command_pool{};
|
||||
vk::CommandBuffer font_command_buffer{};
|
||||
|
||||
// Render buffers
|
||||
|
@ -222,12 +226,53 @@ static inline vk::DeviceSize AlignBufferSize(vk::DeviceSize size, vk::DeviceSize
|
|||
return (size + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
// Register a texture
|
||||
vk::DescriptorSet AddTexture(vk::Sampler sampler, vk::ImageView image_view,
|
||||
vk::ImageLayout image_layout) {
|
||||
void UploadTextureData::Upload() {
|
||||
VkData* bd = GetBackendData();
|
||||
const InitInfo& v = bd->init_info;
|
||||
|
||||
vk::SubmitInfo submit_info{
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer,
|
||||
};
|
||||
CheckVkErr(v.queue.submit({submit_info}));
|
||||
CheckVkErr(v.queue.waitIdle());
|
||||
|
||||
v.device.destroyBuffer(upload_buffer, v.allocator);
|
||||
v.device.freeMemory(upload_buffer_memory, v.allocator);
|
||||
{
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
v.device.freeCommandBuffers(bd->command_pool, {command_buffer});
|
||||
}
|
||||
upload_buffer = VK_NULL_HANDLE;
|
||||
upload_buffer_memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void UploadTextureData::Destroy() {
|
||||
VkData* bd = GetBackendData();
|
||||
const InitInfo& v = bd->init_info;
|
||||
|
||||
CheckVkErr(v.device.waitIdle());
|
||||
RemoveTexture(descriptor_set);
|
||||
descriptor_set = VK_NULL_HANDLE;
|
||||
|
||||
v.device.destroyImageView(image_view, v.allocator);
|
||||
image_view = VK_NULL_HANDLE;
|
||||
v.device.destroyImage(image, v.allocator);
|
||||
image = VK_NULL_HANDLE;
|
||||
v.device.freeMemory(image_memory, v.allocator);
|
||||
image_memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// Register a texture
|
||||
vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
|
||||
vk::Sampler sampler) {
|
||||
VkData* bd = GetBackendData();
|
||||
const InitInfo& v = bd->init_info;
|
||||
|
||||
if (sampler == VK_NULL_HANDLE) {
|
||||
sampler = bd->simple_sampler;
|
||||
}
|
||||
|
||||
// Create Descriptor Set:
|
||||
vk::DescriptorSet descriptor_set;
|
||||
{
|
||||
|
@ -262,6 +307,166 @@ vk::DescriptorSet AddTexture(vk::Sampler sampler, vk::ImageView image_view,
|
|||
}
|
||||
return descriptor_set;
|
||||
}
|
||||
UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height,
|
||||
size_t size) {
|
||||
ImGuiIO& io = GetIO();
|
||||
VkData* bd = GetBackendData();
|
||||
const InitInfo& v = bd->init_info;
|
||||
|
||||
UploadTextureData info{};
|
||||
{
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
info.command_buffer =
|
||||
CheckVkResult(v.device.allocateCommandBuffers(vk::CommandBufferAllocateInfo{
|
||||
.commandPool = bd->command_pool,
|
||||
.commandBufferCount = 1,
|
||||
}))
|
||||
.front();
|
||||
CheckVkErr(info.command_buffer.begin(vk::CommandBufferBeginInfo{
|
||||
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit,
|
||||
}));
|
||||
}
|
||||
|
||||
// Create Image
|
||||
{
|
||||
vk::ImageCreateInfo image_info{
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
info.image = CheckVkResult(v.device.createImage(image_info, v.allocator));
|
||||
auto req = v.device.getImageMemoryRequirements(info.image);
|
||||
vk::MemoryAllocateInfo alloc_info{
|
||||
.allocationSize = IM_MAX(v.min_allocation_size, req.size),
|
||||
.memoryTypeIndex =
|
||||
FindMemoryType(vk::MemoryPropertyFlagBits::eDeviceLocal, req.memoryTypeBits),
|
||||
};
|
||||
info.image_memory = CheckVkResult(v.device.allocateMemory(alloc_info, v.allocator));
|
||||
CheckVkErr(v.device.bindImageMemory(info.image, info.image_memory, 0));
|
||||
}
|
||||
|
||||
// Create Image View
|
||||
{
|
||||
vk::ImageViewCreateInfo view_info{
|
||||
.image = info.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = format,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
info.image_view = CheckVkResult(v.device.createImageView(view_info, v.allocator));
|
||||
}
|
||||
|
||||
// Create descriptor set (ImTextureID)
|
||||
info.descriptor_set = AddTexture(info.image_view, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
// Create Upload Buffer
|
||||
{
|
||||
vk::BufferCreateInfo buffer_info{
|
||||
.size = size,
|
||||
.usage = vk::BufferUsageFlagBits::eTransferSrc,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
};
|
||||
info.upload_buffer = CheckVkResult(v.device.createBuffer(buffer_info, v.allocator));
|
||||
auto req = v.device.getBufferMemoryRequirements(info.upload_buffer);
|
||||
auto alignemtn = IM_MAX(bd->buffer_memory_alignment, req.alignment);
|
||||
vk::MemoryAllocateInfo alloc_info{
|
||||
.allocationSize = IM_MAX(v.min_allocation_size, req.size),
|
||||
.memoryTypeIndex =
|
||||
FindMemoryType(vk::MemoryPropertyFlagBits::eHostVisible, req.memoryTypeBits),
|
||||
};
|
||||
info.upload_buffer_memory = CheckVkResult(v.device.allocateMemory(alloc_info, v.allocator));
|
||||
CheckVkErr(v.device.bindBufferMemory(info.upload_buffer, info.upload_buffer_memory, 0));
|
||||
}
|
||||
|
||||
// Upload to Buffer
|
||||
{
|
||||
char* map = (char*)CheckVkResult(v.device.mapMemory(info.upload_buffer_memory, 0, size));
|
||||
memcpy(map, data, size);
|
||||
vk::MappedMemoryRange range[1]{
|
||||
{
|
||||
.memory = info.upload_buffer_memory,
|
||||
.size = size,
|
||||
},
|
||||
};
|
||||
CheckVkErr(v.device.flushMappedMemoryRanges(range));
|
||||
v.device.unmapMemory(info.upload_buffer_memory);
|
||||
}
|
||||
|
||||
// Copy to Image
|
||||
{
|
||||
vk::ImageMemoryBarrier copy_barrier[1]{
|
||||
{
|
||||
.sType = vk::StructureType::eImageMemoryBarrier,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = info.image,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
info.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost,
|
||||
vk::PipelineStageFlagBits::eTransfer, {}, {}, {},
|
||||
{copy_barrier});
|
||||
|
||||
vk::BufferImageCopy region{
|
||||
.imageSubresource{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageExtent{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depth = 1,
|
||||
},
|
||||
};
|
||||
info.command_buffer.copyBufferToImage(info.upload_buffer, info.image,
|
||||
vk::ImageLayout::eTransferDstOptimal, {region});
|
||||
|
||||
vk::ImageMemoryBarrier use_barrier[1]{{
|
||||
.sType = vk::StructureType::eImageMemoryBarrier,
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = info.image,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
}};
|
||||
info.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {},
|
||||
{use_barrier});
|
||||
}
|
||||
|
||||
CheckVkErr(info.command_buffer.end());
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void RemoveTexture(vk::DescriptorSet descriptor_set) {
|
||||
VkData* bd = GetBackendData();
|
||||
|
@ -517,27 +722,20 @@ static bool CreateFontsTexture() {
|
|||
DestroyFontsTexture();
|
||||
}
|
||||
|
||||
// Create command pool/buffer
|
||||
if (bd->font_command_pool == VK_NULL_HANDLE) {
|
||||
vk::CommandPoolCreateInfo info{
|
||||
.sType = vk::StructureType::eCommandPoolCreateInfo,
|
||||
.flags = vk::CommandPoolCreateFlags{},
|
||||
.queueFamilyIndex = v.queue_family,
|
||||
};
|
||||
bd->font_command_pool = CheckVkResult(v.device.createCommandPool(info, v.allocator));
|
||||
}
|
||||
// Create command buffer
|
||||
if (bd->font_command_buffer == VK_NULL_HANDLE) {
|
||||
vk::CommandBufferAllocateInfo info{
|
||||
.sType = vk::StructureType::eCommandBufferAllocateInfo,
|
||||
.commandPool = bd->font_command_pool,
|
||||
.commandPool = bd->command_pool,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
bd->font_command_buffer = CheckVkResult(v.device.allocateCommandBuffers(info)).front();
|
||||
}
|
||||
|
||||
// Start command buffer
|
||||
{
|
||||
CheckVkErr(v.device.resetCommandPool(bd->font_command_pool, vk::CommandPoolResetFlags{}));
|
||||
CheckVkErr(bd->font_command_buffer.reset());
|
||||
vk::CommandBufferBeginInfo begin_info{};
|
||||
begin_info.sType = vk::StructureType::eCommandBufferBeginInfo;
|
||||
begin_info.flags |= vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
|
||||
|
@ -597,8 +795,7 @@ static bool CreateFontsTexture() {
|
|||
}
|
||||
|
||||
// Create the Descriptor Set:
|
||||
bd->font_descriptor_set =
|
||||
AddTexture(bd->font_sampler, bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
bd->font_descriptor_set = AddTexture(bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
// Create the Upload Buffer:
|
||||
vk::DeviceMemory upload_buffer_memory{};
|
||||
|
@ -956,25 +1153,6 @@ bool CreateDeviceObjects() {
|
|||
bd->descriptor_pool = CheckVkResult(v.device.createDescriptorPool(pool_info));
|
||||
}
|
||||
|
||||
if (!bd->font_sampler) {
|
||||
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |=
|
||||
// ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow
|
||||
// point/nearest sampling.
|
||||
vk::SamplerCreateInfo info{
|
||||
.sType = vk::StructureType::eSamplerCreateInfo,
|
||||
.magFilter = vk::Filter::eLinear,
|
||||
.minFilter = vk::Filter::eLinear,
|
||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||
.maxAnisotropy = 1.0f,
|
||||
.minLod = -1000,
|
||||
.maxLod = 1000,
|
||||
};
|
||||
bd->font_sampler = CheckVkResult(v.device.createSampler(info, v.allocator));
|
||||
}
|
||||
|
||||
if (!bd->descriptor_set_layout) {
|
||||
vk::DescriptorSetLayoutBinding binding[1]{
|
||||
{
|
||||
|
@ -1016,6 +1194,35 @@ bool CreateDeviceObjects() {
|
|||
|
||||
CreatePipeline(v.device, v.allocator, v.pipeline_cache, nullptr, &bd->pipeline, v.subpass);
|
||||
|
||||
if (bd->command_pool == VK_NULL_HANDLE) {
|
||||
vk::CommandPoolCreateInfo info{
|
||||
.sType = vk::StructureType::eCommandPoolCreateInfo,
|
||||
.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
|
||||
.queueFamilyIndex = v.queue_family,
|
||||
};
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
bd->command_pool = CheckVkResult(v.device.createCommandPool(info, v.allocator));
|
||||
}
|
||||
|
||||
if (!bd->simple_sampler) {
|
||||
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |=
|
||||
// ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow
|
||||
// point/nearest sampling.
|
||||
vk::SamplerCreateInfo info{
|
||||
.sType = vk::StructureType::eSamplerCreateInfo,
|
||||
.magFilter = vk::Filter::eLinear,
|
||||
.minFilter = vk::Filter::eLinear,
|
||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||
.maxAnisotropy = 1.0f,
|
||||
.minLod = -1000,
|
||||
.maxLod = 1000,
|
||||
};
|
||||
bd->simple_sampler = CheckVkResult(v.device.createSampler(info, v.allocator));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1026,12 +1233,14 @@ void ImGuiImplVulkanDestroyDeviceObjects() {
|
|||
DestroyFontsTexture();
|
||||
|
||||
if (bd->font_command_buffer) {
|
||||
v.device.freeCommandBuffers(bd->font_command_pool, {bd->font_command_buffer});
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
v.device.freeCommandBuffers(bd->command_pool, {bd->font_command_buffer});
|
||||
bd->font_command_buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
if (bd->font_command_pool) {
|
||||
v.device.destroyCommandPool(bd->font_command_pool, v.allocator);
|
||||
bd->font_command_pool = VK_NULL_HANDLE;
|
||||
if (bd->command_pool) {
|
||||
std::unique_lock lk(bd->command_pool_mutex);
|
||||
v.device.destroyCommandPool(bd->command_pool, v.allocator);
|
||||
bd->command_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
if (bd->shader_module_vert) {
|
||||
v.device.destroyShaderModule(bd->shader_module_vert, v.allocator);
|
||||
|
@ -1041,9 +1250,9 @@ void ImGuiImplVulkanDestroyDeviceObjects() {
|
|||
v.device.destroyShaderModule(bd->shader_module_frag, v.allocator);
|
||||
bd->shader_module_frag = VK_NULL_HANDLE;
|
||||
}
|
||||
if (bd->font_sampler) {
|
||||
v.device.destroySampler(bd->font_sampler, v.allocator);
|
||||
bd->font_sampler = VK_NULL_HANDLE;
|
||||
if (bd->simple_sampler) {
|
||||
v.device.destroySampler(bd->simple_sampler, v.allocator);
|
||||
bd->simple_sampler = VK_NULL_HANDLE;
|
||||
}
|
||||
if (bd->descriptor_set_layout) {
|
||||
v.device.destroyDescriptorSetLayout(bd->descriptor_set_layout, v.allocator);
|
||||
|
@ -1095,13 +1304,4 @@ void Shutdown() {
|
|||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void NewFrame() {
|
||||
VkData* bd = GetBackendData();
|
||||
IM_ASSERT(bd != nullptr &&
|
||||
"Context or backend not initialized! Did you call ImGuiImplVulkanInit()?");
|
||||
|
||||
if (!bd->font_descriptor_set)
|
||||
CreateFontsTexture();
|
||||
}
|
||||
|
||||
} // namespace ImGui::Vulkan
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue