renderer_vulkan: Texture management fixes

This commit is contained in:
emufan
2022-06-15 22:34:02 +03:00
parent ed9000d0ec
commit d4b88ac158
13 changed files with 154 additions and 73 deletions

View File

@@ -48,14 +48,15 @@ void EmuThread::run() {
MicroProfileOnThreadCreate("EmuThread"); MicroProfileOnThreadCreate("EmuThread");
Frontend::ScopeAcquireContext scope(core_context); Frontend::ScopeAcquireContext scope(core_context);
/*emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources( Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total); emit LoadProgress(stage, value, total);
}); });
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);*/ emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
emit HideLoadingScreen();
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) { if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
// Usually the loading screen is hidden after the first frame is drawn. In this case // Usually the loading screen is hidden after the first frame is drawn. In this case

View File

@@ -185,10 +185,12 @@ void RendererVulkan::PrepareRendertarget() {
if (color_fill.is_enabled) { if (color_fill.is_enabled) {
LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i]); LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i]);
} else { } else {
auto extent = screen_infos[i].texture.GetArea().extent; auto [width, height] = screen_infos[i].texture.GetArea().extent;
auto format = screen_infos[i].format; u32 fwidth = framebuffer.width;
if (extent.width != framebuffer.width || extent.height != framebuffer.height || u32 fheight = framebuffer.height;
format != framebuffer.color_format) {
if (width != fwidth || height != fheight ||
screen_infos[i].format != framebuffer.color_format) {
// Reallocate texture if the framebuffer size has changed. // Reallocate texture if the framebuffer size has changed.
// This is expected to not happen very often and hence should not be a // This is expected to not happen very often and hence should not be a
// performance problem. // performance problem.
@@ -271,6 +273,7 @@ void RendererVulkan::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
*/ */
void RendererVulkan::CreateVulkanObjects() { void RendererVulkan::CreateVulkanObjects() {
clear_color = vk::ClearColorValue{std::array<float, 4>{Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f}}; clear_color = vk::ClearColorValue{std::array<float, 4>{Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f}};
clear_color = vk::ClearColorValue(std::array<float, 4>{1.0f, 0.0f, 0.0, 1.0f});
//filter_sampler.Create(); //filter_sampler.Create();
//ReloadSampler(); //ReloadSampler();
@@ -286,7 +289,7 @@ void RendererVulkan::CreateVulkanObjects() {
} }
void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer) { void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer) {
GPU::Regs::PixelFormat format = framebuffer.color_format; screen.format = framebuffer.color_format;
VKTexture::Info texture_info{ VKTexture::Info texture_info{
.width = framebuffer.width, .width = framebuffer.width,
@@ -298,7 +301,7 @@ void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::
vk::ImageUsageFlagBits::eSampled vk::ImageUsageFlagBits::eSampled
}; };
switch (format) { switch (screen.format) {
case GPU::Regs::PixelFormat::RGBA8: case GPU::Regs::PixelFormat::RGBA8:
texture_info.format = vk::Format::eR8G8B8A8Srgb; texture_info.format = vk::Format::eR8G8B8A8Srgb;
break; break;
@@ -371,7 +374,9 @@ void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
state.ApplyPresentState(); state.ApplyPresentState();
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0}); vk::DeviceSize offset = 0;
cmdbuffer.bindVertexBuffers(0, 1, &vertex_buffer.GetBuffer(), &offset);
cmdbuffer.draw(4, 1, 0, 0); cmdbuffer.draw(4, 1, 0, 0);
} }
@@ -716,9 +721,9 @@ VideoCore::ResultStatus RendererVulkan::Init() {
g_vk_instace->Create(instance, physical_devices[1], surface, true); g_vk_instace->Create(instance, physical_devices[1], surface, true);
g_vk_task_scheduler->Create(); g_vk_task_scheduler->Create();
auto& layout = render_window.GetFramebufferLayout(); //auto& layout = render_window.GetFramebufferLayout();
swapchain = std::make_shared<VKSwapChain>(surface); swapchain = std::make_shared<VKSwapChain>(surface);
swapchain->Create(layout.width, layout.height, false); //swapchain->Create(layout.width, layout.height, false);
// Create Vulkan state // Create Vulkan state
VulkanState::Create(swapchain); VulkanState::Create(swapchain);

View File

@@ -158,6 +158,9 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
buffer_pos += size; buffer_pos += size;
} }
else {
printf("f");
}
} }
} }

View File

@@ -44,7 +44,7 @@ public:
/// Return a pointer to the mapped memory if the buffer is host mapped /// Return a pointer to the mapped memory if the buffer is host mapped
u8* GetHostPointer() const { return reinterpret_cast<u8*>(host_ptr); } u8* GetHostPointer() const { return reinterpret_cast<u8*>(host_ptr); }
const vk::BufferView& GetView(u32 i = 0) const { return views[i]; } const vk::BufferView& GetView(u32 i = 0) const { return views[i]; }
vk::Buffer GetBuffer() const { return buffer; } const vk::Buffer& GetBuffer() const { return buffer; }
u32 GetSize() const { return buffer_info.size; } u32 GetSize() const { return buffer_info.size; }
void Upload(std::span<const std::byte> data, u32 offset, void Upload(std::span<const std::byte> data, u32 offset,

View File

@@ -245,7 +245,7 @@ void PipelineBuilder::SetRenderingFormats(vk::Format color, vk::Format depth_ste
}; };
const u32 color_attachment_count = color == vk::Format::eUndefined ? 0 : 1; const u32 color_attachment_count = color == vk::Format::eUndefined ? 0 : 1;
rendering_info = vk::PipelineRenderingCreateInfoKHR{0, color_attachment_count, &color_format, depth_stencil_format, rendering_info = vk::PipelineRenderingCreateInfo{0, color_attachment_count, &color_format, depth_stencil_format,
IsStencil(depth_stencil) ? depth_stencil : vk::Format::eUndefined}; IsStencil(depth_stencil) ? depth_stencil : vk::Format::eUndefined};
pipeline_info.pNext = &rendering_info; pipeline_info.pNext = &rendering_info;
} }

View File

@@ -69,7 +69,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
VKBuffer::Info texel_buffer_info = { VKBuffer::Info texel_buffer_info = {
.size = TEXTURE_BUFFER_SIZE, .size = TEXTURE_BUFFER_SIZE,
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
.usage = vk::BufferUsageFlagBits::eStorageTexelBuffer | .usage = vk::BufferUsageFlagBits::eUniformTexelBuffer |
vk::BufferUsageFlagBits::eTransferDst, vk::BufferUsageFlagBits::eTransferDst,
}; };
@@ -116,13 +116,18 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
index_buffer.Create(index_info); index_buffer.Create(index_info);
// Set clear texture color // Set clear texture color
state.SetPlaceholderColor(0, 0, 0, 255); state.SetPlaceholderColor(255, 0, 0, 255);
SyncEntireState(); SyncEntireState();
} }
RasterizerVulkan::~RasterizerVulkan() = default; RasterizerVulkan::~RasterizerVulkan() = default;
void RasterizerVulkan::LoadDiskResources(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
}
void RasterizerVulkan::SyncEntireState() { void RasterizerVulkan::SyncEntireState() {
// Sync fixed function Vulkan state // Sync fixed function Vulkan state
SyncClipEnabled(); SyncClipEnabled();
@@ -394,8 +399,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
} }
state.EndRendering(); state.EndRendering();
color_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
depth_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
g_vk_task_scheduler->Submit(); g_vk_task_scheduler->Submit();
auto gpu_tick = g_vk_task_scheduler->GetGPUTick();
auto cpu_tick = g_vk_task_scheduler->GetCPUTick();
return true; return true;
} }

View File

@@ -117,7 +117,7 @@ public:
~RasterizerVulkan() override; ~RasterizerVulkan() override;
void LoadDiskResources(const std::atomic_bool& stop_loading, void LoadDiskResources(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) override {} const VideoCore::DiskResourceLoadCallback& callback) override;
void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v2) override; const Pica::Shader::OutputVertex& v2) override;

View File

@@ -7,6 +7,7 @@
#include <bitset> #include <bitset>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <iostream>
#include <iterator> #include <iterator>
#include <optional> #include <optional>
#include <unordered_set> #include <unordered_set>
@@ -428,6 +429,7 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac
MICROPROFILE_DEFINE(Vulkan_SurfaceLoad, "Vulkan", "Surface Load", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(Vulkan_SurfaceLoad, "Vulkan", "Surface Load", MP_RGB(128, 192, 64));
void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) { void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) {
ASSERT(type != SurfaceType::Fill); ASSERT(type != SurfaceType::Fill);
const bool need_swap = (pixel_format == PixelFormat::RGBA8 || pixel_format == PixelFormat::RGB8);
const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr); const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr);
if (texture_src_data == nullptr) if (texture_src_data == nullptr)
@@ -451,8 +453,27 @@ void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) {
if (!is_tiled) { if (!is_tiled) {
ASSERT(type == SurfaceType::Color); ASSERT(type == SurfaceType::Color);
std::memcpy(&vk_buffer[start_offset], texture_src_data + start_offset, if (need_swap) {
// TODO(liushuyu): check if the byteswap here is 100% correct
// cannot fully test this
if (pixel_format == PixelFormat::RGBA8) {
for (std::size_t i = start_offset; i < load_end - addr; i += 4) {
vk_buffer[i] = texture_src_data[i + 3];
vk_buffer[i + 1] = texture_src_data[i + 2];
vk_buffer[i + 2] = texture_src_data[i + 1];
vk_buffer[i + 3] = texture_src_data[i];
}
} else if (pixel_format == PixelFormat::RGB8) {
for (std::size_t i = start_offset; i < load_end - addr; i += 3) {
vk_buffer[i] = texture_src_data[i + 2];
vk_buffer[i + 1] = texture_src_data[i + 1];
vk_buffer[i + 2] = texture_src_data[i];
}
}
} else {
std::memcpy(&vk_buffer[start_offset], texture_src_data + start_offset,
load_end - load_start); load_end - load_start);
}
} else { } else {
if (type == SurfaceType::Texture) { if (type == SurfaceType::Texture) {
Pica::Texture::TextureInfo tex_info{}; Pica::Texture::TextureInfo tex_info{};

View File

@@ -1677,7 +1677,7 @@ vk::ShaderModule CompileShader(const std::string& source, vk::ShaderStageFlagBit
shaderc::Compiler compiler; shaderc::Compiler compiler;
shaderc::CompileOptions options; shaderc::CompileOptions options;
options.SetOptimizationLevel(shaderc_optimization_level_performance); options.SetOptimizationLevel(shaderc_optimization_level_performance);
options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1);
options.SetWarningsAsErrors(); options.SetWarningsAsErrors();
options.SetSourceLanguage(shaderc_source_language_glsl); options.SetSourceLanguage(shaderc_source_language_glsl);

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include <span> #include <span>
#include "video_core/renderer_vulkan/vk_state.h" #include "video_core/renderer_vulkan/vk_state.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -13,6 +14,17 @@ namespace Vulkan {
std::unique_ptr<VulkanState> s_vulkan_state{}; std::unique_ptr<VulkanState> s_vulkan_state{};
auto IsStencil = [](vk::Format format) -> bool {
switch (format) {
case vk::Format::eD16UnormS8Uint:
case vk::Format::eD24UnormS8Uint:
case vk::Format::eD32SfloatS8Uint:
return true;
default:
return false;
};
};
void DescriptorUpdater::Update() { void DescriptorUpdater::Update() {
assert(update_count > 0); assert(update_count > 0);
@@ -151,7 +163,7 @@ void VulkanState::SetTexture(u32 binding, const VKTexture& image) {
void VulkanState::SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer, u32 view_index) { void VulkanState::SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer, u32 view_index) {
auto& set = descriptor_sets[2]; auto& set = descriptor_sets[2];
updater.PushBufferUpdate(set, binding, updater.PushBufferUpdate(set, binding,
vk::DescriptorType::eStorageTexelBuffer, vk::DescriptorType::eUniformTexelBuffer,
offset, size, buffer.GetBuffer(), offset, size, buffer.GetBuffer(),
buffer.GetView(view_index)); buffer.GetView(view_index));
descriptors_dirty = true; descriptors_dirty = true;
@@ -177,18 +189,24 @@ void VulkanState::UnbindTexture(const VKTexture& image) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (render_views[i] == image.GetView()) { if (render_views[i] == image.GetView()) {
render_views[i] = placeholder.GetView(); render_views[i] = placeholder.GetView();
updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], i,
render_sampler, render_views[i]);
descriptors_dirty = true; descriptors_dirty = true;
} }
} }
if (present_view == image.GetView()) { if (present_view == image.GetView()) {
present_view = placeholder.GetView(); present_view = placeholder.GetView();
updater.PushCombinedImageSamplerUpdate(descriptor_sets[3], 0,
render_sampler, present_view);
descriptors_dirty = true; descriptors_dirty = true;
} }
} }
void VulkanState::UnbindTexture(u32 unit) { void VulkanState::UnbindTexture(u32 unit) {
render_views[unit] = placeholder.GetView(); render_views[unit] = placeholder.GetView();
updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], unit,
render_sampler, render_views[unit]);
descriptors_dirty = true; descriptors_dirty = true;
} }
@@ -227,13 +245,17 @@ void VulkanState::BeginRendering(OptRef<VKTexture> color, OptRef<VKTexture> dept
depth_load_op, depth_store_op, depth_clear depth_load_op, depth_store_op, depth_clear
}; };
infos[2] = vk::RenderingAttachmentInfo{
image.GetView(), image.GetLayout(), {}, {}, {},
stencil_load_op, stencil_store_op, depth_clear
};
render_info.pDepthAttachment = &infos[1]; render_info.pDepthAttachment = &infos[1];
render_info.pStencilAttachment = &infos[2];
if (IsStencil(image.GetFormat())) {
infos[2] = vk::RenderingAttachmentInfo{
image.GetView(), image.GetLayout(), {}, {}, {},
stencil_load_op, stencil_store_op, depth_clear
};
render_info.pStencilAttachment = &infos[2];
}
} }
if (update_pipeline_formats) { if (update_pipeline_formats) {
@@ -363,25 +385,26 @@ void VulkanState::InitDescriptorSets() {
auto sets = device.allocateDescriptorSets(allocate_info); auto sets = device.allocateDescriptorSets(allocate_info);
// Update them if the previous sets are valid // Update them if the previous sets are valid
auto result = std::ranges::find_if(descriptor_sets, [](vk::DescriptorSet set) { return bool(set); }); u32 copy_count = 0;
if (result != descriptor_sets.end()) { std::array<vk::CopyDescriptorSet, 10> copies;
std::array<vk::CopyDescriptorSet, 10> copies{{
{descriptor_sets[0], 0, 0, sets[0], 0, 0}, // shader_data
{descriptor_sets[0], 1, 0, sets[0], 1, 0}, // pica_uniforms
{descriptor_sets[1], 0, 0, sets[1], 0, 0}, // tex0
{descriptor_sets[1], 1, 0, sets[1], 1, 0}, // tex1
{descriptor_sets[1], 2, 0, sets[1], 2, 0}, // tex2
{descriptor_sets[1], 3, 0, sets[1], 3, 0}, // tex_cube
{descriptor_sets[2], 0, 0, sets[2], 0, 0}, // texture_buffer_lut_lf
{descriptor_sets[2], 1, 0, sets[2], 1, 0}, // texture_buffer_lut_rg
{descriptor_sets[2], 2, 0, sets[2], 2, 0}, // texture_buffer_lut_rgba
{descriptor_sets[3], 0, 0, sets[3], 0, 0}
}};
device.updateDescriptorSets({}, copies); // Copy only valid descriptors
std::array<u32, 4> binding_count{2, 4, 3, 1};
for (int i = 0; i < descriptor_sets.size(); i++) {
if (descriptor_sets[i]) {
for (u32 binding = 0; binding < binding_count[i]; binding++) {
copies[copy_count++] = {descriptor_sets[i], binding, 0, sets[i], binding, 0, 1};
}
}
} }
std::copy_n(sets.begin(), 4, descriptor_sets.begin()); if (copy_count < 10) {
// Some descriptors weren't copied and thus need manual updating
descriptors_dirty = true;
}
device.updateDescriptorSets(0, nullptr, copy_count, copies.data());
std::copy_n(sets.begin(), descriptor_sets.size(), descriptor_sets.begin());
} }
void VulkanState::ApplyRenderState(const Pica::Regs& regs) { void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
@@ -533,9 +556,9 @@ void VulkanState::BuildDescriptorLayouts() {
{3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, // tex_cube {3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, // tex_cube
}}; }};
std::array<vk::DescriptorSetLayoutBinding, 3> lut_set{{ std::array<vk::DescriptorSetLayoutBinding, 3> lut_set{{
{0, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf {0, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf
{1, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg {1, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg
{2, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba {2, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba
}}; }};
std::array<vk::DescriptorSetLayoutBinding, 1> present_set{{ std::array<vk::DescriptorSetLayoutBinding, 1> present_set{{
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment} {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}
@@ -579,7 +602,7 @@ void VulkanState::ConfigureRenderPipeline() {
// Enable every required dynamic state // Enable every required dynamic state
std::array dynamic_states{ std::array dynamic_states{
vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth, vk::DynamicState::eDepthCompareOp,
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable, vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable,
vk::DynamicState::eStencilOp, vk::DynamicState::eStencilOp,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
@@ -614,7 +637,7 @@ void VulkanState::ConfigurePresentPipeline() {
present_pipeline_builder.SetPrimitiveTopology(vk::PrimitiveTopology::eTriangleStrip); present_pipeline_builder.SetPrimitiveTopology(vk::PrimitiveTopology::eTriangleStrip);
present_pipeline_builder.SetLineWidth(1.0f); present_pipeline_builder.SetLineWidth(1.0f);
present_pipeline_builder.SetNoCullRasterizationState(); present_pipeline_builder.SetNoCullRasterizationState();
present_pipeline_builder.SetRenderingFormats(swapchain->GetCurrentImage().GetFormat()); present_pipeline_builder.SetRenderingFormats(vk::Format::eB8G8R8A8Unorm);
// Set depth, stencil tests and blending // Set depth, stencil tests and blending
present_pipeline_builder.SetNoDepthTestState(); present_pipeline_builder.SetNoDepthTestState();
@@ -623,7 +646,6 @@ void VulkanState::ConfigurePresentPipeline() {
// Enable every required dynamic state // Enable every required dynamic state
std::array dynamic_states{ std::array dynamic_states{
vk::DynamicState::eLineWidth,
vk::DynamicState::eViewport, vk::DynamicState::eViewport,
vk::DynamicState::eScissor, vk::DynamicState::eScissor,
}; };

View File

@@ -125,8 +125,7 @@ private:
private: private:
// Render targets // Render targets
std::shared_ptr<VKSwapChain> swapchain; std::shared_ptr<VKSwapChain> swapchain;
bool rendering{}; bool rendering{false};
VKTexture* color_render_target{}, *depth_render_target{};
vk::ImageView present_view; vk::ImageView present_view;
std::array<vk::ImageView, 4> render_views; std::array<vk::ImageView, 4> render_views;
DrawInfo present_data; DrawInfo present_data;

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <fstream>
#include <iostream>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_texture.h" #include "video_core/renderer_vulkan/vk_texture.h"
@@ -26,6 +28,7 @@ static int BytesPerPixel(vk::Format format) {
case vk::Format::eR5G6B5UnormPack16: case vk::Format::eR5G6B5UnormPack16:
case vk::Format::eR5G5B5A1UnormPack16: case vk::Format::eR5G5B5A1UnormPack16:
case vk::Format::eR4G4B4A4UnormPack16: case vk::Format::eR4G4B4A4UnormPack16:
case vk::Format::eD16Unorm:
return 2; return 2;
default: default:
UNREACHABLE(); UNREACHABLE();
@@ -247,7 +250,9 @@ void VKTexture::OverrideImageLayout(vk::ImageLayout new_layout) {
} }
void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span<u8> pixels) { void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span<u8> pixels) {
auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(pixels.size_bytes()); u32 request_size = is_rgb ? (pixels.size() / 3) * 4 :
(is_d24s8 ? (pixels.size() / 4) * 5 : pixels.size());
auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(request_size);
if (!buffer) { if (!buffer) {
LOG_ERROR(Render_Vulkan, "Cannot upload pixels without staging buffer!"); LOG_ERROR(Render_Vulkan, "Cannot upload pixels without staging buffer!");
} }
@@ -271,8 +276,6 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region,
std::memcpy(buffer, pixels.data(), pixels.size()); std::memcpy(buffer, pixels.data(), pixels.size());
} }
std::memcpy(buffer, pixels.data(), pixels.size());
vk::BufferImageCopy copy_region{ vk::BufferImageCopy copy_region{
offset, row_length, region.extent.height, offset, row_length, region.extent.height,
{aspect, level, layer, 1}, {aspect, level, layer, 1},
@@ -342,33 +345,44 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region
Transition(cmdbuffer, old_layout); Transition(cmdbuffer, old_layout);
} }
template <typename Out, typename In>
std::span<Out> SpanCast(std::span<In> span) {
return std::span(reinterpret_cast<Out*>(span.data()), span.size_bytes() / sizeof(Out));
}
std::vector<u8> VKTexture::RGBToRGBA(std::span<u8> data) { std::vector<u8> VKTexture::RGBToRGBA(std::span<u8> data) {
ASSERT(data.size() % 3 == 0); ASSERT(data.size() % 3 == 0);
u32 new_size = (data.size() / 3) * 4; u32 new_size = (data.size() / 3) * 4;
std::vector<u8> rgba(new_size, 255); std::vector<u8> rgba(new_size);
u32 dst_pos = 0; u32 dst_pos = 0;
for (u32 i = 0; i < data.size(); i += 3) { for (u32 i = 0; i < data.size(); i += 3) {
std::memcpy(rgba.data() + dst_pos, data.data() + i, 3); std::memcpy(rgba.data() + dst_pos, data.data() + i, 3);
rgba[dst_pos + 3] = 255u;
dst_pos += 4; dst_pos += 4;
} }
return rgba; return rgba;
} }
std::vector<u8> VKTexture::D24S8ToD32S8(std::span<u8> data) { std::vector<u64> VKTexture::D24S8ToD32S8(std::span<u8> data) {
ASSERT(data.size() % 4 == 0); ASSERT(data.size() % 4 == 0);
u32 new_size = (data.size() / 4) * 8; std::vector<u64> d32s8;
std::vector<u8> d32s8(new_size, 0); std::span<u32> d24s8 = SpanCast<u32>(data);
u32 dst_pos = 0; d32s8.reserve(data.size() * 2);
for (u32 i = 0; i < data.size(); i += 4) { std::ranges::transform(d24s8, std::back_inserter(d32s8), [](u32 comp) -> u64 {
std::memcpy(d32s8.data() + dst_pos, data.data() + i, 3); // Convert normalized 24bit depth component to floating point
d32s8[dst_pos + 4] = data[i + 3]; float fdepth = static_cast<float>(comp & 0xFFFFFF) / 0xFFFFFF;
dst_pos += 8; u64 result = static_cast<u64>(comp) << 8;
}
// Use std::memcpy to avoid the unsafe casting required to preserve the floating
// point bits
std::memcpy(&result, &fdepth, 4);
return result;
});
return d32s8; return d32s8;
} }
@@ -388,18 +402,23 @@ std::vector<u8> VKTexture::RGBAToRGB(std::span<u8> data) {
return rgb; return rgb;
} }
std::vector<u8> VKTexture::D32S8ToD24S8(std::span<u8> data) { std::vector<u32> VKTexture::D32S8ToD24S8(std::span<u8> data) {
ASSERT(data.size() % 8 == 0); ASSERT(data.size() % 8 == 0);
u32 new_size = (data.size() / 8) * 4; std::vector<u32> d24s8;
std::vector<u8> d24s8(new_size); std::span<u64> d32s8 = SpanCast<u64>(data);
u32 dst_pos = 0; d24s8.reserve(data.size() / 2);
for (u32 i = 0; i < data.size(); i += 5) { std::ranges::transform(d32s8, std::back_inserter(d24s8), [](u64 comp) -> u32 {
std::memcpy(d24s8.data() + dst_pos, data.data() + i, 3); // Convert floating point to 24bit normalized depth
d24s8[dst_pos + 3] = data[i + 4]; float fdepth = 0.f;
dst_pos += 4; u32 depth = comp & 0xFFFFFFFF;
} std::memcpy(&fdepth, &depth, 4);
u32 stencil = (comp >> 32) & 0xFF;
u64 result = static_cast<u32>(fdepth * 0xFFFFFF) | (stencil << 24);
return result;
});
return d24s8; return d24s8;
} }

View File

@@ -62,10 +62,10 @@ public:
private: private:
std::vector<u8> RGBToRGBA(std::span<u8> data); std::vector<u8> RGBToRGBA(std::span<u8> data);
std::vector<u8> D24S8ToD32S8(std::span<u8> data); std::vector<u64> D24S8ToD32S8(std::span<u8> data);
std::vector<u8> RGBAToRGB(std::span<u8> data); std::vector<u8> RGBAToRGB(std::span<u8> data);
std::vector<u8> D32S8ToD24S8(std::span<u8> data); std::vector<u32> D32S8ToD24S8(std::span<u8> data);
private: private:
VKTexture::Info info{}; VKTexture::Info info{};