renderer_vulkan: Texture management fixes
This commit is contained in:
@@ -48,14 +48,15 @@ void EmuThread::run() {
|
||||
MicroProfileOnThreadCreate("EmuThread");
|
||||
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(
|
||||
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t 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()) {
|
||||
// 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) {
|
||||
LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i]);
|
||||
} else {
|
||||
auto extent = screen_infos[i].texture.GetArea().extent;
|
||||
auto format = screen_infos[i].format;
|
||||
if (extent.width != framebuffer.width || extent.height != framebuffer.height ||
|
||||
format != framebuffer.color_format) {
|
||||
auto [width, height] = screen_infos[i].texture.GetArea().extent;
|
||||
u32 fwidth = framebuffer.width;
|
||||
u32 fheight = framebuffer.height;
|
||||
|
||||
if (width != fwidth || height != fheight ||
|
||||
screen_infos[i].format != framebuffer.color_format) {
|
||||
// Reallocate texture if the framebuffer size has changed.
|
||||
// This is expected to not happen very often and hence should not be a
|
||||
// performance problem.
|
||||
@@ -271,6 +273,7 @@ void RendererVulkan::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
|
||||
*/
|
||||
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>{1.0f, 0.0f, 0.0, 1.0f});
|
||||
|
||||
//filter_sampler.Create();
|
||||
//ReloadSampler();
|
||||
@@ -286,7 +289,7 @@ void RendererVulkan::CreateVulkanObjects() {
|
||||
}
|
||||
|
||||
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{
|
||||
.width = framebuffer.width,
|
||||
@@ -298,7 +301,7 @@ void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::
|
||||
vk::ImageUsageFlagBits::eSampled
|
||||
};
|
||||
|
||||
switch (format) {
|
||||
switch (screen.format) {
|
||||
case GPU::Regs::PixelFormat::RGBA8:
|
||||
texture_info.format = vk::Format::eR8G8B8A8Srgb;
|
||||
break;
|
||||
@@ -371,7 +374,9 @@ void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
|
||||
state.ApplyPresentState();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -716,9 +721,9 @@ VideoCore::ResultStatus RendererVulkan::Init() {
|
||||
g_vk_instace->Create(instance, physical_devices[1], surface, true);
|
||||
g_vk_task_scheduler->Create();
|
||||
|
||||
auto& layout = render_window.GetFramebufferLayout();
|
||||
//auto& layout = render_window.GetFramebufferLayout();
|
||||
swapchain = std::make_shared<VKSwapChain>(surface);
|
||||
swapchain->Create(layout.width, layout.height, false);
|
||||
//swapchain->Create(layout.width, layout.height, false);
|
||||
|
||||
// Create Vulkan state
|
||||
VulkanState::Create(swapchain);
|
||||
|
@@ -158,6 +158,9 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
||||
|
||||
buffer_pos += size;
|
||||
}
|
||||
else {
|
||||
printf("f");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ public:
|
||||
/// Return a pointer to the mapped memory if the buffer is host mapped
|
||||
u8* GetHostPointer() const { return reinterpret_cast<u8*>(host_ptr); }
|
||||
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; }
|
||||
|
||||
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;
|
||||
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};
|
||||
pipeline_info.pNext = &rendering_info;
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
|
||||
VKBuffer::Info texel_buffer_info = {
|
||||
.size = TEXTURE_BUFFER_SIZE,
|
||||
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
.usage = vk::BufferUsageFlagBits::eStorageTexelBuffer |
|
||||
.usage = vk::BufferUsageFlagBits::eUniformTexelBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst,
|
||||
};
|
||||
|
||||
@@ -116,13 +116,18 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
|
||||
index_buffer.Create(index_info);
|
||||
|
||||
// Set clear texture color
|
||||
state.SetPlaceholderColor(0, 0, 0, 255);
|
||||
state.SetPlaceholderColor(255, 0, 0, 255);
|
||||
|
||||
SyncEntireState();
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() = default;
|
||||
|
||||
void RasterizerVulkan::LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncEntireState() {
|
||||
// Sync fixed function Vulkan state
|
||||
SyncClipEnabled();
|
||||
@@ -394,8 +399,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
}
|
||||
|
||||
state.EndRendering();
|
||||
color_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
depth_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
g_vk_task_scheduler->Submit();
|
||||
|
||||
auto gpu_tick = g_vk_task_scheduler->GetGPUTick();
|
||||
auto cpu_tick = g_vk_task_scheduler->GetCPUTick();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -117,7 +117,7 @@ public:
|
||||
~RasterizerVulkan() override;
|
||||
|
||||
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,
|
||||
const Pica::Shader::OutputVertex& v2) override;
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#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));
|
||||
void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) {
|
||||
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);
|
||||
if (texture_src_data == nullptr)
|
||||
@@ -451,8 +453,27 @@ void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) {
|
||||
|
||||
if (!is_tiled) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
if (type == SurfaceType::Texture) {
|
||||
Pica::Texture::TextureInfo tex_info{};
|
||||
|
@@ -1677,7 +1677,7 @@ vk::ShaderModule CompileShader(const std::string& source, vk::ShaderStageFlagBit
|
||||
shaderc::Compiler compiler;
|
||||
shaderc::CompileOptions options;
|
||||
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.SetSourceLanguage(shaderc_source_language_glsl);
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
#include "video_core/renderer_vulkan/vk_state.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
@@ -13,6 +14,17 @@ namespace Vulkan {
|
||||
|
||||
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() {
|
||||
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) {
|
||||
auto& set = descriptor_sets[2];
|
||||
updater.PushBufferUpdate(set, binding,
|
||||
vk::DescriptorType::eStorageTexelBuffer,
|
||||
vk::DescriptorType::eUniformTexelBuffer,
|
||||
offset, size, buffer.GetBuffer(),
|
||||
buffer.GetView(view_index));
|
||||
descriptors_dirty = true;
|
||||
@@ -177,18 +189,24 @@ void VulkanState::UnbindTexture(const VKTexture& image) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (render_views[i] == image.GetView()) {
|
||||
render_views[i] = placeholder.GetView();
|
||||
updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], i,
|
||||
render_sampler, render_views[i]);
|
||||
descriptors_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (present_view == image.GetView()) {
|
||||
present_view = placeholder.GetView();
|
||||
updater.PushCombinedImageSamplerUpdate(descriptor_sets[3], 0,
|
||||
render_sampler, present_view);
|
||||
descriptors_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanState::UnbindTexture(u32 unit) {
|
||||
render_views[unit] = placeholder.GetView();
|
||||
updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], unit,
|
||||
render_sampler, render_views[unit]);
|
||||
descriptors_dirty = true;
|
||||
}
|
||||
|
||||
@@ -227,13 +245,17 @@ void VulkanState::BeginRendering(OptRef<VKTexture> color, OptRef<VKTexture> dept
|
||||
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.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) {
|
||||
@@ -363,25 +385,26 @@ void VulkanState::InitDescriptorSets() {
|
||||
auto sets = device.allocateDescriptorSets(allocate_info);
|
||||
|
||||
// Update them if the previous sets are valid
|
||||
auto result = std::ranges::find_if(descriptor_sets, [](vk::DescriptorSet set) { return bool(set); });
|
||||
if (result != descriptor_sets.end()) {
|
||||
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}
|
||||
}};
|
||||
u32 copy_count = 0;
|
||||
std::array<vk::CopyDescriptorSet, 10> copies;
|
||||
|
||||
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) {
|
||||
@@ -533,9 +556,9 @@ void VulkanState::BuildDescriptorLayouts() {
|
||||
{3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, // tex_cube
|
||||
}};
|
||||
std::array<vk::DescriptorSetLayoutBinding, 3> lut_set{{
|
||||
{0, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf
|
||||
{1, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg
|
||||
{2, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba
|
||||
{0, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf
|
||||
{1, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg
|
||||
{2, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba
|
||||
}};
|
||||
std::array<vk::DescriptorSetLayoutBinding, 1> present_set{{
|
||||
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}
|
||||
@@ -579,7 +602,7 @@ void VulkanState::ConfigureRenderPipeline() {
|
||||
|
||||
// Enable every required dynamic state
|
||||
std::array dynamic_states{
|
||||
vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth,
|
||||
vk::DynamicState::eDepthCompareOp,
|
||||
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable,
|
||||
vk::DynamicState::eStencilOp,
|
||||
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
|
||||
@@ -614,7 +637,7 @@ void VulkanState::ConfigurePresentPipeline() {
|
||||
present_pipeline_builder.SetPrimitiveTopology(vk::PrimitiveTopology::eTriangleStrip);
|
||||
present_pipeline_builder.SetLineWidth(1.0f);
|
||||
present_pipeline_builder.SetNoCullRasterizationState();
|
||||
present_pipeline_builder.SetRenderingFormats(swapchain->GetCurrentImage().GetFormat());
|
||||
present_pipeline_builder.SetRenderingFormats(vk::Format::eB8G8R8A8Unorm);
|
||||
|
||||
// Set depth, stencil tests and blending
|
||||
present_pipeline_builder.SetNoDepthTestState();
|
||||
@@ -623,7 +646,6 @@ void VulkanState::ConfigurePresentPipeline() {
|
||||
|
||||
// Enable every required dynamic state
|
||||
std::array dynamic_states{
|
||||
vk::DynamicState::eLineWidth,
|
||||
vk::DynamicState::eViewport,
|
||||
vk::DynamicState::eScissor,
|
||||
};
|
||||
|
@@ -125,8 +125,7 @@ private:
|
||||
private:
|
||||
// Render targets
|
||||
std::shared_ptr<VKSwapChain> swapchain;
|
||||
bool rendering{};
|
||||
VKTexture* color_render_target{}, *depth_render_target{};
|
||||
bool rendering{false};
|
||||
vk::ImageView present_view;
|
||||
std::array<vk::ImageView, 4> render_views;
|
||||
DrawInfo present_data;
|
||||
|
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.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::eR5G5B5A1UnormPack16:
|
||||
case vk::Format::eR4G4B4A4UnormPack16:
|
||||
case vk::Format::eD16Unorm:
|
||||
return 2;
|
||||
default:
|
||||
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) {
|
||||
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) {
|
||||
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());
|
||||
|
||||
vk::BufferImageCopy copy_region{
|
||||
offset, row_length, region.extent.height,
|
||||
{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);
|
||||
}
|
||||
|
||||
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) {
|
||||
ASSERT(data.size() % 3 == 0);
|
||||
|
||||
u32 new_size = (data.size() / 3) * 4;
|
||||
std::vector<u8> rgba(new_size, 255);
|
||||
std::vector<u8> rgba(new_size);
|
||||
|
||||
u32 dst_pos = 0;
|
||||
for (u32 i = 0; i < data.size(); i += 3) {
|
||||
std::memcpy(rgba.data() + dst_pos, data.data() + i, 3);
|
||||
rgba[dst_pos + 3] = 255u;
|
||||
dst_pos += 4;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
u32 new_size = (data.size() / 4) * 8;
|
||||
std::vector<u8> d32s8(new_size, 0);
|
||||
std::vector<u64> d32s8;
|
||||
std::span<u32> d24s8 = SpanCast<u32>(data);
|
||||
|
||||
u32 dst_pos = 0;
|
||||
for (u32 i = 0; i < data.size(); i += 4) {
|
||||
std::memcpy(d32s8.data() + dst_pos, data.data() + i, 3);
|
||||
d32s8[dst_pos + 4] = data[i + 3];
|
||||
dst_pos += 8;
|
||||
}
|
||||
d32s8.reserve(data.size() * 2);
|
||||
std::ranges::transform(d24s8, std::back_inserter(d32s8), [](u32 comp) -> u64 {
|
||||
// Convert normalized 24bit depth component to floating point
|
||||
float fdepth = static_cast<float>(comp & 0xFFFFFF) / 0xFFFFFF;
|
||||
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;
|
||||
}
|
||||
@@ -388,18 +402,23 @@ std::vector<u8> VKTexture::RGBAToRGB(std::span<u8> data) {
|
||||
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);
|
||||
|
||||
u32 new_size = (data.size() / 8) * 4;
|
||||
std::vector<u8> d24s8(new_size);
|
||||
std::vector<u32> d24s8;
|
||||
std::span<u64> d32s8 = SpanCast<u64>(data);
|
||||
|
||||
u32 dst_pos = 0;
|
||||
for (u32 i = 0; i < data.size(); i += 5) {
|
||||
std::memcpy(d24s8.data() + dst_pos, data.data() + i, 3);
|
||||
d24s8[dst_pos + 3] = data[i + 4];
|
||||
dst_pos += 4;
|
||||
}
|
||||
d24s8.reserve(data.size() / 2);
|
||||
std::ranges::transform(d32s8, std::back_inserter(d24s8), [](u64 comp) -> u32 {
|
||||
// Convert floating point to 24bit normalized depth
|
||||
float fdepth = 0.f;
|
||||
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;
|
||||
}
|
||||
|
@@ -62,10 +62,10 @@ public:
|
||||
|
||||
private:
|
||||
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> D32S8ToD24S8(std::span<u8> data);
|
||||
std::vector<u32> D32S8ToD24S8(std::span<u8> data);
|
||||
|
||||
private:
|
||||
VKTexture::Info info{};
|
||||
|
Reference in New Issue
Block a user