renderer_vulkan: Texture management fixes
This commit is contained in:
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -158,6 +158,9 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
|||||||
|
|
||||||
buffer_pos += size;
|
buffer_pos += size;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
printf("f");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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{};
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
};
|
};
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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{};
|
||||||
|
Reference in New Issue
Block a user