renderer_vulkan: Fix many validation errors

This commit is contained in:
emufan
2022-06-14 14:29:52 +03:00
parent a657ef33e6
commit ed9000d0ec
14 changed files with 196 additions and 58 deletions

View File

@ -48,14 +48,14 @@ 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);*/
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
@ -488,9 +488,6 @@ bool GRenderWindow::InitRenderTarget() {
break; 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); child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
layout()->addWidget(child_widget); layout()->addWidget(child_widget);
// Reset minimum required size to avoid resizing issues on the main window after restarting. // 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); 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); OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
OnFramebufferSizeChanged(); OnFramebufferSizeChanged();
BackupGeometry(); BackupGeometry();
@ -611,4 +611,4 @@ std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext()
} }
return std::make_unique<DummyContext>(); return std::make_unique<DummyContext>();
} }

View File

@ -713,7 +713,7 @@ VideoCore::ResultStatus RendererVulkan::Init() {
auto surface = CreateSurface(instance, render_window); auto surface = CreateSurface(instance, render_window);
g_vk_instace = std::make_unique<VKInstance>(); g_vk_instace = std::make_unique<VKInstance>();
g_vk_task_scheduler = std::make_unique<VKTaskScheduler>(); 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(); g_vk_task_scheduler->Create();
auto& layout = render_window.GetFramebufferLayout(); auto& layout = render_window.GetFramebufferLayout();

View File

@ -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, void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
vk::PipelineStageFlags stage_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 cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer();
auto& staging = g_vk_task_scheduler->GetStaging(); auto& staging = g_vk_task_scheduler->GetStaging();
cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk); cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk);
vk::BufferMemoryBarrier barrier{ vk::BufferMemoryBarrier barrier{
vk::AccessFlagBits::eTransferWrite, access_to_block, vk::AccessFlagBits::eTransferWrite, access_to_block,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
buffer, mapped_chunk.srcOffset, mapped_chunk.size buffer, mapped_chunk.srcOffset, mapped_chunk.size
}; };
// Add a pipeline barrier for the region modified // Add a pipeline barrier for the region modified
cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block, cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block,
vk::DependencyFlagBits::eByRegion, vk::DependencyFlagBits::eByRegion,
0, nullptr, 1, &barrier, 0, nullptr); 0, nullptr, 1, &barrier, 0, nullptr);
buffer_pos += size; buffer_pos += size;
}
} }
} }

View File

@ -7,6 +7,10 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_instance.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 { namespace Vulkan {
std::unique_ptr<VKInstance> g_vk_instace; std::unique_ptr<VKInstance> g_vk_instace;
@ -96,6 +100,10 @@ bool VKInstance::CreateDevice(vk::SurfaceKHR surface, bool validation_enabled) {
// Create logical device // Create logical device
device = physical_device.createDeviceUnique(device_info); 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. // Grab the graphics and present queues.
graphics_queue = device->getQueue(graphics_queue_family_index, 0); graphics_queue = device->getQueue(graphics_queue_family_index, 0);
present_queue = device->getQueue(present_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_state_features.extendedDynamicState = true;
dynamic_state2_features.extendedDynamicState2 = true; dynamic_state2_features.extendedDynamicState2 = true;
dynamic_state2_features.extendedDynamicState2LogicOp = true; dynamic_state2_features.extendedDynamicState2LogicOp = true;
color_write_features.colorWriteEnable = true;
// Include features in device creation // Include features in device creation
vk12_features.pNext = &vk13_features; vk12_features.pNext = &vk13_features;
vk13_features.pNext = &dynamic_state_features; vk13_features.pNext = &dynamic_state_features;
dynamic_state_features.pNext = &dynamic_state2_features; dynamic_state_features.pNext = &dynamic_state2_features;
dynamic_state2_features.pNext = &color_write_features;
features = vk::PhysicalDeviceFeatures2{vk_features, &vk12_features}; features = vk::PhysicalDeviceFeatures2{vk_features, &vk12_features};
return true; return true;
} }
bool VKInstance::FindExtensions() bool VKInstance::FindExtensions() {
{
auto available = physical_device.enumerateDeviceExtensionProperties(); auto available = physical_device.enumerateDeviceExtensionProperties();
if (available.empty()) { if (available.empty()) {
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device."); LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
@ -177,7 +186,8 @@ bool VKInstance::FindExtensions()
if (!AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true) || if (!AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true) ||
!AddExtension(VK_KHR_DYNAMIC_RENDERING_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_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; return false;
} }
@ -185,3 +195,7 @@ bool VKInstance::FindExtensions()
} }
} // namespace Vulkan } // namespace Vulkan
void vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables) {
ptr_vkCmdSetColorWriteEnableEXT(commandBuffer, attachmentCount, pColorWriteEnables);
}

View File

@ -61,8 +61,13 @@ public:
vk::PhysicalDeviceVulkan12Features vk12_features{}; vk::PhysicalDeviceVulkan12Features vk12_features{};
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state_features{}; vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state_features{};
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2_features{}; vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2_features{};
vk::PhysicalDeviceColorWriteEnableFeaturesEXT color_write_features{};
}; };
extern std::unique_ptr<VKInstance> g_vk_instace; extern std::unique_ptr<VKInstance> g_vk_instace;
} // namespace Vulkan } // namespace Vulkan
#if defined(VK_EXT_color_write_enable)
extern PFN_vkCmdSetColorWriteEnableEXT ptr_vkCmdSetColorWriteEnableEXT;
#endif /* defined(VK_EXT_color_write_enable) */

View File

@ -224,7 +224,6 @@ void PipelineBuilder::SetDynamicStates(const std::span<vk::DynamicState> states)
// Copy the state data // Copy the state data
std::copy(states.begin(), states.end(), dynamic_states.begin()); std::copy(states.begin(), states.end(), dynamic_states.begin());
dynamic_info.dynamicStateCount = states.size(); dynamic_info.dynamicStateCount = states.size();
dynamic_info.pDynamicStates = dynamic_states.data(); dynamic_info.pDynamicStates = dynamic_states.data();
pipeline_info.pDynamicState = &dynamic_info; pipeline_info.pDynamicState = &dynamic_info;
return; return;

View File

@ -73,7 +73,7 @@ public:
void SetRenderingFormats(vk::Format color, vk::Format depth_stencil = vk::Format::eUndefined); void SetRenderingFormats(vk::Format color, vk::Format depth_stencil = vk::Format::eUndefined);
private: 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_SHADER_STAGES = 3;
static constexpr u32 MAX_VERTEX_BUFFERS = 8; static constexpr u32 MAX_VERTEX_BUFFERS = 8;
static constexpr u32 MAX_VERTEX_ATTRIBUTES = 16; static constexpr u32 MAX_VERTEX_ATTRIBUTES = 16;

View File

@ -69,7 +69,8 @@ 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::eStorageTexelBuffer |
vk::BufferUsageFlagBits::eTransferDst,
}; };
texel_buffer_info.view_formats[0] = vk::Format::eR32G32Sfloat; texel_buffer_info.view_formats[0] = vk::Format::eR32G32Sfloat;
@ -82,7 +83,8 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
VKBuffer::Info uniform_info = { VKBuffer::Info uniform_info = {
.size = UNIFORM_BUFFER_SIZE, .size = UNIFORM_BUFFER_SIZE,
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
.usage = vk::BufferUsageFlagBits::eUniformBuffer .usage = vk::BufferUsageFlagBits::eUniformBuffer |
vk::BufferUsageFlagBits::eTransferDst
}; };
uniform_buffer.Create(uniform_info); uniform_buffer.Create(uniform_info);
@ -99,13 +101,15 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) {
VKBuffer::Info vertex_info = { VKBuffer::Info vertex_info = {
.size = VERTEX_BUFFER_SIZE, .size = VERTEX_BUFFER_SIZE,
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
.usage = vk::BufferUsageFlagBits::eVertexBuffer .usage = vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eTransferDst
}; };
VKBuffer::Info index_info = { VKBuffer::Info index_info = {
.size = INDEX_BUFFER_SIZE, .size = INDEX_BUFFER_SIZE,
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
.usage = vk::BufferUsageFlagBits::eIndexBuffer .usage = vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eTransferDst
}; };
vertex_buffer.Create(vertex_info); vertex_buffer.Create(vertex_info);
@ -389,6 +393,9 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
depth_surface); depth_surface);
} }
state.EndRendering();
g_vk_task_scheduler->Submit();
return true; return true;
} }
@ -1240,11 +1247,18 @@ void RasterizerVulkan::SyncColorWriteMask() {
return regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0; 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(); auto& state = VulkanState::Get();
state.SetColorMask(WriteEnabled(regs.framebuffer.output_merger.red_enable), state.SetColorMask(mask);
WriteEnabled(regs.framebuffer.output_merger.green_enable),
WriteEnabled(regs.framebuffer.output_merger.blue_enable),
WriteEnabled(regs.framebuffer.output_merger.alpha_enable));
} }
void RasterizerVulkan::SyncStencilWriteMask() { void RasterizerVulkan::SyncStencilWriteMask() {

View File

@ -294,7 +294,8 @@ static vk::Rect2D FromRect(Common::Rectangle<u32> rect) {
} }
// Allocate an uninitialized texture of appropriate size and format for the surface // 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 // First check if the texture can be recycled
auto recycled_tex = host_texture_recycler.find({format, width, height}); auto recycled_tex = host_texture_recycler.find({format, width, height});
if (recycled_tex != host_texture_recycler.end()) { if (recycled_tex != host_texture_recycler.end()) {
@ -303,6 +304,28 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w
return texture; 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 // Otherwise create a brand new texture
u32 levels = std::log2(std::max(width, height)) + 1; u32 levels = std::log2(std::max(width, height)) + 1;
VKTexture::Info texture_info = { VKTexture::Info texture_info = {
@ -311,8 +334,7 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w
.format = format, .format = format,
.type = vk::ImageType::e2D, .type = vk::ImageType::e2D,
.view_type = vk::ImageViewType::e2D, .view_type = vk::ImageViewType::e2D,
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | .usage = GetUsage(type),
vk::ImageUsageFlagBits::eTransferSrc,
.levels = levels .levels = levels
}; };
@ -1330,7 +1352,7 @@ Surface RasterizerCacheVulkan::CreateSurface(const SurfaceParams& params) {
static_cast<SurfaceParams&>(*surface) = params; static_cast<SurfaceParams&>(*surface) = params;
surface->invalid_regions.insert(surface->GetInterval()); 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()); surface->GetScaledWidth(), surface->GetScaledHeight());
return surface; return surface;
} }

View File

@ -342,7 +342,8 @@ private:
std::recursive_mutex mutex; std::recursive_mutex mutex;
public: 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; std::unique_ptr<FormatReinterpreterVulkan> format_reinterpreter;
}; };

View File

@ -284,8 +284,7 @@ void VulkanState::SetFrontFace(vk::FrontFace face) {
} }
} }
void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) { void VulkanState::SetColorMask(vk::ColorComponentFlags mask) {
auto mask = static_cast<vk::ColorComponentFlags>(red | (green << 1) | (blue << 2) | (alpha << 3));
render_pipeline_key.blend_config.colorWriteMask = 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 code = GenerateFragmentShader(render_pipeline_key.fragment_config);
auto module = CompileShader(code, vk::ShaderStageFlagBits::eFragment); auto module = CompileShader(code, vk::ShaderStageFlagBits::eFragment);
render_fragment_shaders.emplace(render_pipeline_key.fragment_config, vk::UniqueShaderModule{module}); 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 // Update pipeline builder
@ -432,6 +431,9 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
// Force set all dynamic state for new pipeline
dirty_flags.set();
ApplyCommonState(true); ApplyCommonState(true);
// Bind render descriptor sets // Bind render descriptor sets
@ -578,12 +580,13 @@ 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::eLineWidth,
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eColorWriteEnableEXT, vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable,
vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilOp, vk::DynamicState::eStencilOp,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
vk::DynamicState::eStencilReference, vk::DynamicState::eDepthWriteEnable,
vk::DynamicState::eCullMode, vk::DynamicState::eBlendConstants, vk::DynamicState::eCullMode, vk::DynamicState::eBlendConstants,
vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eViewport, vk::DynamicState::eScissor,
vk::DynamicState::eLogicOpEXT, vk::DynamicState::eFrontFace vk::DynamicState::eFrontFace
}; };
render_pipeline_builder.SetDynamicStates(dynamic_states); render_pipeline_builder.SetDynamicStates(dynamic_states);

View File

@ -83,7 +83,7 @@ public:
vk::CompareOp compare, u32 ref); vk::CompareOp compare, u32 ref);
void SetDepthWrite(bool enable); void SetDepthWrite(bool enable);
void SetDepthTest(bool enable, vk::CompareOp compare); 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 SetBlendEnable(bool enable);
void SetBlendCostants(float red, float green, float blue, float alpha); 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, void SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::BlendFactor src_color, vk::BlendFactor dst_color,
@ -162,7 +162,7 @@ private:
ColorWrite, ColorWrite,
CullMode, CullMode,
BlendConstants, BlendConstants,
FrontFace FrontFace,
}; };
std::bitset<16> dirty_flags; std::bitset<16> dirty_flags;

View File

@ -12,6 +12,9 @@ namespace Vulkan {
static int BytesPerPixel(vk::Format format) { static int BytesPerPixel(vk::Format format) {
switch (format) { switch (format) {
case vk::Format::eD32SfloatS8Uint:
return 5;
case vk::Format::eD32Sfloat:
case vk::Format::eB8G8R8A8Unorm: case vk::Format::eB8G8R8A8Unorm:
case vk::Format::eR8G8B8A8Uint: case vk::Format::eR8G8B8A8Uint:
case vk::Format::eR8G8B8A8Srgb: case vk::Format::eR8G8B8A8Srgb:
@ -63,6 +66,12 @@ void VKTexture::Create(const Info& create_info) {
info.format = vk::Format::eR8G8B8A8Srgb; 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 // Create the texture
image_size = info.width * info.height * BytesPerPixel(info.format); image_size = info.width * info.height * BytesPerPixel(info.format);
aspect = GetImageAspect(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 // 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()); std::memcpy(buffer, pixels.data(), pixels.size());
vk::BufferImageCopy copy_region{ 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) { 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); auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(request_size);
if (!buffer) { if (!buffer) {
LOG_ERROR(Render_Vulkan, "Cannot download texture without staging 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(); auto& state = VulkanState::Get();
state.EndRendering(); state.EndRendering();
@ -290,7 +314,11 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region
// Automatically convert RGB to RGBA // Automatically convert RGB to RGBA
if (is_rgb) { 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()); std::memcpy(buffer, data.data(), data.size());
} }
else { else {
@ -318,16 +346,62 @@ 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); std::vector<u8> rgba(new_size, 255);
u32 dst_pos{0}; u32 dst_pos = 0;
for (int 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) {
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 } // namespace Vulkan

View File

@ -62,6 +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<u8> RGBAToRGB(std::span<u8> data);
std::vector<u8> D32S8ToD24S8(std::span<u8> data);
private: private:
VKTexture::Info info{}; VKTexture::Info info{};
@ -72,7 +76,7 @@ private:
vk::DeviceMemory memory; vk::DeviceMemory memory;
u32 image_size{}; u32 image_size{};
bool adopted{false}; bool adopted{false};
bool is_rgb{false}; bool is_rgb{false}, is_d24s8{false};
}; };
} // namespace Vulkan } // namespace Vulkan