renderer_vulkan: Fix many validation errors
This commit is contained in:
@ -48,14 +48,14 @@ 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);*/
|
||||
|
||||
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
||||
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
||||
@ -488,9 +488,6 @@ bool GRenderWindow::InitRenderTarget() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the Window System information with the new render target
|
||||
window_info = GetWindowSystemInfo(child_widget->windowHandle());
|
||||
|
||||
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
layout()->addWidget(child_widget);
|
||||
// Reset minimum required size to avoid resizing issues on the main window after restarting.
|
||||
@ -498,6 +495,9 @@ bool GRenderWindow::InitRenderTarget() {
|
||||
|
||||
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
|
||||
// Update the Window System information with the new render target
|
||||
window_info = GetWindowSystemInfo(child_widget->windowHandle());
|
||||
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
OnFramebufferSizeChanged();
|
||||
BackupGeometry();
|
||||
@ -611,4 +611,4 @@ std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext()
|
||||
}
|
||||
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ VideoCore::ResultStatus RendererVulkan::Init() {
|
||||
auto surface = CreateSurface(instance, render_window);
|
||||
g_vk_instace = std::make_unique<VKInstance>();
|
||||
g_vk_task_scheduler = std::make_unique<VKTaskScheduler>();
|
||||
g_vk_instace->Create(instance, physical_devices[0], surface, true);
|
||||
g_vk_instace->Create(instance, physical_devices[1], surface, true);
|
||||
g_vk_task_scheduler->Create();
|
||||
|
||||
auto& layout = render_window.GetFramebufferLayout();
|
||||
|
@ -138,24 +138,26 @@ std::tuple<u8*, u32, bool> StreamBuffer::Map(u32 size, u32 alignment) {
|
||||
|
||||
void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
||||
vk::PipelineStageFlags stage_to_block) {
|
||||
mapped_chunk.size = size;
|
||||
if (size > 0) {
|
||||
mapped_chunk.size = size;
|
||||
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer();
|
||||
auto& staging = g_vk_task_scheduler->GetStaging();
|
||||
cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk);
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer();
|
||||
auto& staging = g_vk_task_scheduler->GetStaging();
|
||||
cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk);
|
||||
|
||||
vk::BufferMemoryBarrier barrier{
|
||||
vk::AccessFlagBits::eTransferWrite, access_to_block,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
buffer, mapped_chunk.srcOffset, mapped_chunk.size
|
||||
};
|
||||
vk::BufferMemoryBarrier barrier{
|
||||
vk::AccessFlagBits::eTransferWrite, access_to_block,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
buffer, mapped_chunk.srcOffset, mapped_chunk.size
|
||||
};
|
||||
|
||||
// Add a pipeline barrier for the region modified
|
||||
cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block,
|
||||
vk::DependencyFlagBits::eByRegion,
|
||||
0, nullptr, 1, &barrier, 0, nullptr);
|
||||
// Add a pipeline barrier for the region modified
|
||||
cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block,
|
||||
vk::DependencyFlagBits::eByRegion,
|
||||
0, nullptr, 1, &barrier, 0, nullptr);
|
||||
|
||||
buffer_pos += size;
|
||||
buffer_pos += size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,10 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
||||
#if defined(VK_EXT_color_write_enable)
|
||||
PFN_vkCmdSetColorWriteEnableEXT ptr_vkCmdSetColorWriteEnableEXT;
|
||||
#endif /* defined(VK_EXT_color_write_enable) */
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
std::unique_ptr<VKInstance> g_vk_instace;
|
||||
@ -96,6 +100,10 @@ bool VKInstance::CreateDevice(vk::SurfaceKHR surface, bool validation_enabled) {
|
||||
// Create logical device
|
||||
device = physical_device.createDeviceUnique(device_info);
|
||||
|
||||
#if defined(VK_EXT_color_write_enable)
|
||||
ptr_vkCmdSetColorWriteEnableEXT = reinterpret_cast<PFN_vkCmdSetColorWriteEnableEXT>(device->getProcAddr("vkCmdSetColorWriteEnableEXT"));
|
||||
#endif /* defined(VK_EXT_color_write_enable) */
|
||||
|
||||
// Grab the graphics and present queues.
|
||||
graphics_queue = device->getQueue(graphics_queue_family_index, 0);
|
||||
present_queue = device->getQueue(present_queue_family_index, 0);
|
||||
@ -131,18 +139,19 @@ bool VKInstance::FindFeatures() {
|
||||
dynamic_state_features.extendedDynamicState = true;
|
||||
dynamic_state2_features.extendedDynamicState2 = true;
|
||||
dynamic_state2_features.extendedDynamicState2LogicOp = true;
|
||||
color_write_features.colorWriteEnable = true;
|
||||
|
||||
// Include features in device creation
|
||||
vk12_features.pNext = &vk13_features;
|
||||
vk13_features.pNext = &dynamic_state_features;
|
||||
dynamic_state_features.pNext = &dynamic_state2_features;
|
||||
dynamic_state2_features.pNext = &color_write_features;
|
||||
features = vk::PhysicalDeviceFeatures2{vk_features, &vk12_features};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VKInstance::FindExtensions()
|
||||
{
|
||||
bool VKInstance::FindExtensions() {
|
||||
auto available = physical_device.enumerateDeviceExtensionProperties();
|
||||
if (available.empty()) {
|
||||
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
|
||||
@ -177,7 +186,8 @@ bool VKInstance::FindExtensions()
|
||||
if (!AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true) ||
|
||||
!AddExtension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, true) ||
|
||||
!AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, true) ||
|
||||
!AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, true)) {
|
||||
!AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, true) ||
|
||||
!AddExtension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -185,3 +195,7 @@ bool VKInstance::FindExtensions()
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
void vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables) {
|
||||
ptr_vkCmdSetColorWriteEnableEXT(commandBuffer, attachmentCount, pColorWriteEnables);
|
||||
}
|
||||
|
@ -61,8 +61,13 @@ public:
|
||||
vk::PhysicalDeviceVulkan12Features vk12_features{};
|
||||
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state_features{};
|
||||
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2_features{};
|
||||
vk::PhysicalDeviceColorWriteEnableFeaturesEXT color_write_features{};
|
||||
};
|
||||
|
||||
extern std::unique_ptr<VKInstance> g_vk_instace;
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
#if defined(VK_EXT_color_write_enable)
|
||||
extern PFN_vkCmdSetColorWriteEnableEXT ptr_vkCmdSetColorWriteEnableEXT;
|
||||
#endif /* defined(VK_EXT_color_write_enable) */
|
||||
|
@ -224,7 +224,6 @@ void PipelineBuilder::SetDynamicStates(const std::span<vk::DynamicState> states)
|
||||
// Copy the state data
|
||||
std::copy(states.begin(), states.end(), dynamic_states.begin());
|
||||
dynamic_info.dynamicStateCount = states.size();
|
||||
|
||||
dynamic_info.pDynamicStates = dynamic_states.data();
|
||||
pipeline_info.pDynamicState = &dynamic_info;
|
||||
return;
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
void SetRenderingFormats(vk::Format color, vk::Format depth_stencil = vk::Format::eUndefined);
|
||||
|
||||
private:
|
||||
static constexpr u32 MAX_DYNAMIC_STATES = 14;
|
||||
static constexpr u32 MAX_DYNAMIC_STATES = 20;
|
||||
static constexpr u32 MAX_SHADER_STAGES = 3;
|
||||
static constexpr u32 MAX_VERTEX_BUFFERS = 8;
|
||||
static constexpr u32 MAX_VERTEX_ATTRIBUTES = 16;
|
||||
|
@ -69,7 +69,8 @@ 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::eStorageTexelBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst,
|
||||
};
|
||||
|
||||
texel_buffer_info.view_formats[0] = vk::Format::eR32G32Sfloat;
|
||||
@ -82,7 +83,8 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
|
||||
VKBuffer::Info uniform_info = {
|
||||
.size = UNIFORM_BUFFER_SIZE,
|
||||
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
.usage = vk::BufferUsageFlagBits::eUniformBuffer
|
||||
.usage = vk::BufferUsageFlagBits::eUniformBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst
|
||||
};
|
||||
|
||||
uniform_buffer.Create(uniform_info);
|
||||
@ -99,13 +101,15 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
|
||||
VKBuffer::Info vertex_info = {
|
||||
.size = VERTEX_BUFFER_SIZE,
|
||||
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
.usage = vk::BufferUsageFlagBits::eVertexBuffer
|
||||
.usage = vk::BufferUsageFlagBits::eVertexBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst
|
||||
};
|
||||
|
||||
VKBuffer::Info index_info = {
|
||||
.size = INDEX_BUFFER_SIZE,
|
||||
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
.usage = vk::BufferUsageFlagBits::eIndexBuffer
|
||||
.usage = vk::BufferUsageFlagBits::eIndexBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst
|
||||
};
|
||||
|
||||
vertex_buffer.Create(vertex_info);
|
||||
@ -389,6 +393,9 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
depth_surface);
|
||||
}
|
||||
|
||||
state.EndRendering();
|
||||
g_vk_task_scheduler->Submit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1240,11 +1247,18 @@ void RasterizerVulkan::SyncColorWriteMask() {
|
||||
return regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0;
|
||||
};
|
||||
|
||||
vk::ColorComponentFlags mask;
|
||||
if (WriteEnabled(regs.framebuffer.output_merger.red_enable))
|
||||
mask |= vk::ColorComponentFlagBits::eR;
|
||||
if (WriteEnabled(regs.framebuffer.output_merger.green_enable))
|
||||
mask |= vk::ColorComponentFlagBits::eG;
|
||||
if (WriteEnabled(regs.framebuffer.output_merger.blue_enable))
|
||||
mask |= vk::ColorComponentFlagBits::eB;
|
||||
if (WriteEnabled(regs.framebuffer.output_merger.alpha_enable))
|
||||
mask |= vk::ColorComponentFlagBits::eA;
|
||||
|
||||
auto& state = VulkanState::Get();
|
||||
state.SetColorMask(WriteEnabled(regs.framebuffer.output_merger.red_enable),
|
||||
WriteEnabled(regs.framebuffer.output_merger.green_enable),
|
||||
WriteEnabled(regs.framebuffer.output_merger.blue_enable),
|
||||
WriteEnabled(regs.framebuffer.output_merger.alpha_enable));
|
||||
state.SetColorMask(mask);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncStencilWriteMask() {
|
||||
|
@ -294,7 +294,8 @@ static vk::Rect2D FromRect(Common::Rectangle<u32> rect) {
|
||||
}
|
||||
|
||||
// Allocate an uninitialized texture of appropriate size and format for the surface
|
||||
VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 width, u32 height) {
|
||||
VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(SurfaceType type, vk::Format format,
|
||||
u32 width, u32 height) {
|
||||
// First check if the texture can be recycled
|
||||
auto recycled_tex = host_texture_recycler.find({format, width, height});
|
||||
if (recycled_tex != host_texture_recycler.end()) {
|
||||
@ -303,6 +304,28 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w
|
||||
return texture;
|
||||
}
|
||||
|
||||
auto GetUsage = [](SurfaceType type) {
|
||||
auto usage = vk::ImageUsageFlagBits::eSampled |
|
||||
vk::ImageUsageFlagBits::eTransferDst |
|
||||
vk::ImageUsageFlagBits::eTransferSrc;
|
||||
|
||||
switch (type) {
|
||||
case SurfaceType::Color:
|
||||
case SurfaceType::Fill:
|
||||
case SurfaceType::Texture:
|
||||
usage |= vk::ImageUsageFlagBits::eColorAttachment;
|
||||
break;
|
||||
case SurfaceType::Depth:
|
||||
case SurfaceType::DepthStencil:
|
||||
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return usage;
|
||||
};
|
||||
|
||||
// Otherwise create a brand new texture
|
||||
u32 levels = std::log2(std::max(width, height)) + 1;
|
||||
VKTexture::Info texture_info = {
|
||||
@ -311,8 +334,7 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w
|
||||
.format = format,
|
||||
.type = vk::ImageType::e2D,
|
||||
.view_type = vk::ImageViewType::e2D,
|
||||
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst |
|
||||
vk::ImageUsageFlagBits::eTransferSrc,
|
||||
.usage = GetUsage(type),
|
||||
.levels = levels
|
||||
};
|
||||
|
||||
@ -1330,7 +1352,7 @@ Surface RasterizerCacheVulkan::CreateSurface(const SurfaceParams& params) {
|
||||
static_cast<SurfaceParams&>(*surface) = params;
|
||||
|
||||
surface->invalid_regions.insert(surface->GetInterval());
|
||||
surface->texture = AllocateSurfaceTexture(GetFormatTuple(surface->pixel_format),
|
||||
surface->texture = AllocateSurfaceTexture(params.type, GetFormatTuple(surface->pixel_format),
|
||||
surface->GetScaledWidth(), surface->GetScaledHeight());
|
||||
return surface;
|
||||
}
|
||||
|
@ -342,7 +342,8 @@ private:
|
||||
std::recursive_mutex mutex;
|
||||
|
||||
public:
|
||||
VKTexture AllocateSurfaceTexture(vk::Format format, u32 width, u32 height);
|
||||
VKTexture AllocateSurfaceTexture(SurfaceParams::SurfaceType type, vk::Format format,
|
||||
u32 width, u32 height);
|
||||
std::unique_ptr<FormatReinterpreterVulkan> format_reinterpreter;
|
||||
};
|
||||
|
||||
|
@ -284,8 +284,7 @@ void VulkanState::SetFrontFace(vk::FrontFace face) {
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) {
|
||||
auto mask = static_cast<vk::ColorComponentFlags>(red | (green << 1) | (blue << 2) | (alpha << 3));
|
||||
void VulkanState::SetColorMask(vk::ColorComponentFlags mask) {
|
||||
render_pipeline_key.blend_config.colorWriteMask = mask;
|
||||
}
|
||||
|
||||
@ -412,7 +411,7 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
|
||||
auto code = GenerateFragmentShader(render_pipeline_key.fragment_config);
|
||||
auto module = CompileShader(code, vk::ShaderStageFlagBits::eFragment);
|
||||
render_fragment_shaders.emplace(render_pipeline_key.fragment_config, vk::UniqueShaderModule{module});
|
||||
render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, shader->second.get());
|
||||
render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, module);
|
||||
}
|
||||
|
||||
// Update pipeline builder
|
||||
@ -432,6 +431,9 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
||||
|
||||
// Force set all dynamic state for new pipeline
|
||||
dirty_flags.set();
|
||||
|
||||
ApplyCommonState(true);
|
||||
|
||||
// Bind render descriptor sets
|
||||
@ -578,12 +580,13 @@ void VulkanState::ConfigureRenderPipeline() {
|
||||
// Enable every required dynamic state
|
||||
std::array dynamic_states{
|
||||
vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth,
|
||||
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eColorWriteEnableEXT,
|
||||
vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilOp,
|
||||
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable,
|
||||
vk::DynamicState::eStencilOp,
|
||||
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
|
||||
vk::DynamicState::eStencilReference, vk::DynamicState::eDepthWriteEnable,
|
||||
vk::DynamicState::eCullMode, vk::DynamicState::eBlendConstants,
|
||||
vk::DynamicState::eViewport, vk::DynamicState::eScissor,
|
||||
vk::DynamicState::eLogicOpEXT, vk::DynamicState::eFrontFace
|
||||
vk::DynamicState::eFrontFace
|
||||
};
|
||||
|
||||
render_pipeline_builder.SetDynamicStates(dynamic_states);
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
vk::CompareOp compare, u32 ref);
|
||||
void SetDepthWrite(bool enable);
|
||||
void SetDepthTest(bool enable, vk::CompareOp compare);
|
||||
void SetColorMask(bool red, bool green, bool blue, bool alpha);
|
||||
void SetColorMask(vk::ColorComponentFlags mask);
|
||||
void SetBlendEnable(bool enable);
|
||||
void SetBlendCostants(float red, float green, float blue, float alpha);
|
||||
void SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::BlendFactor src_color, vk::BlendFactor dst_color,
|
||||
@ -162,7 +162,7 @@ private:
|
||||
ColorWrite,
|
||||
CullMode,
|
||||
BlendConstants,
|
||||
FrontFace
|
||||
FrontFace,
|
||||
};
|
||||
|
||||
std::bitset<16> dirty_flags;
|
||||
|
@ -12,6 +12,9 @@ namespace Vulkan {
|
||||
|
||||
static int BytesPerPixel(vk::Format format) {
|
||||
switch (format) {
|
||||
case vk::Format::eD32SfloatS8Uint:
|
||||
return 5;
|
||||
case vk::Format::eD32Sfloat:
|
||||
case vk::Format::eB8G8R8A8Unorm:
|
||||
case vk::Format::eR8G8B8A8Uint:
|
||||
case vk::Format::eR8G8B8A8Srgb:
|
||||
@ -63,6 +66,12 @@ void VKTexture::Create(const Info& create_info) {
|
||||
info.format = vk::Format::eR8G8B8A8Srgb;
|
||||
}
|
||||
|
||||
is_d24s8 = false;
|
||||
if (info.format == vk::Format::eD24UnormS8Uint) {
|
||||
is_d24s8 = true;
|
||||
info.format = vk::Format::eD32SfloatS8Uint;
|
||||
}
|
||||
|
||||
// Create the texture
|
||||
image_size = info.width * info.height * BytesPerPixel(info.format);
|
||||
aspect = GetImageAspect(info.format);
|
||||
@ -244,7 +253,24 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region,
|
||||
}
|
||||
|
||||
// Copy pixels to staging buffer
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer();
|
||||
auto& state = VulkanState::Get();
|
||||
state.EndRendering();
|
||||
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
|
||||
// Automatically convert RGB to RGBA
|
||||
if (is_rgb) {
|
||||
auto data = RGBToRGBA(pixels);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
}
|
||||
else if (is_d24s8) {
|
||||
auto data = D24S8ToD32S8(pixels);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
}
|
||||
else {
|
||||
std::memcpy(buffer, pixels.data(), pixels.size());
|
||||
}
|
||||
|
||||
std::memcpy(buffer, pixels.data(), pixels.size());
|
||||
|
||||
vk::BufferImageCopy copy_region{
|
||||
@ -266,15 +292,13 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region,
|
||||
}
|
||||
|
||||
void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span<u8> memory) {
|
||||
u32 request_size = is_rgb ? (memory.size() / 3) * 4 : memory.size();
|
||||
u32 request_size = is_rgb ? (memory.size() / 3) * 4 :
|
||||
(is_d24s8 ? (memory.size() / 4) * 5 : memory.size());
|
||||
auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(request_size);
|
||||
if (!buffer) {
|
||||
LOG_ERROR(Render_Vulkan, "Cannot download texture without staging buffer!");
|
||||
}
|
||||
|
||||
// Downloads can happen after the image has been rendered to or changed by blitting
|
||||
// so we must perform it in the render command buffer. However there is no guarantee
|
||||
// of the rendering context so terminate the current renderpass to be sure
|
||||
auto& state = VulkanState::Get();
|
||||
state.EndRendering();
|
||||
|
||||
@ -290,7 +314,11 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region
|
||||
|
||||
// Automatically convert RGB to RGBA
|
||||
if (is_rgb) {
|
||||
auto data = RGBToRGBA(memory);
|
||||
auto data = RGBAToRGB(memory);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
}
|
||||
else if (is_d24s8) {
|
||||
auto data = D32S8ToD24S8(memory);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
}
|
||||
else {
|
||||
@ -318,16 +346,62 @@ 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);
|
||||
std::vector<u8> rgba(new_size, 255);
|
||||
|
||||
u32 dst_pos{0};
|
||||
for (int i = 0; i < data.size(); i += 3) {
|
||||
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) {
|
||||
ASSERT(data.size() % 4 == 0);
|
||||
|
||||
u32 new_size = (data.size() / 4) * 8;
|
||||
std::vector<u8> d32s8(new_size, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return d32s8;
|
||||
}
|
||||
|
||||
std::vector<u8> VKTexture::RGBAToRGB(std::span<u8> data) {
|
||||
ASSERT(data.size() % 4 == 0);
|
||||
|
||||
u32 new_size = (data.size() / 4) * 3;
|
||||
std::vector<u8> rgb(new_size);
|
||||
|
||||
u32 dst_pos = 0;
|
||||
for (u32 i = 0; i < data.size(); i += 4) {
|
||||
std::memcpy(rgb.data() + dst_pos, data.data() + i, 3);
|
||||
dst_pos += 3;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
std::vector<u8> VKTexture::D32S8ToD24S8(std::span<u8> data) {
|
||||
ASSERT(data.size() % 8 == 0);
|
||||
|
||||
u32 new_size = (data.size() / 8) * 4;
|
||||
std::vector<u8> d24s8(new_size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return d24s8;
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -62,6 +62,10 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<u8> RGBToRGBA(std::span<u8> data);
|
||||
std::vector<u8> D24S8ToD32S8(std::span<u8> data);
|
||||
|
||||
std::vector<u8> RGBAToRGB(std::span<u8> data);
|
||||
std::vector<u8> D32S8ToD24S8(std::span<u8> data);
|
||||
|
||||
private:
|
||||
VKTexture::Info info{};
|
||||
@ -72,7 +76,7 @@ private:
|
||||
vk::DeviceMemory memory;
|
||||
u32 image_size{};
|
||||
bool adopted{false};
|
||||
bool is_rgb{false};
|
||||
bool is_rgb{false}, is_d24s8{false};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
Reference in New Issue
Block a user