summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2018-12-04 08:47:46 +0100
committerGitHub <noreply@github.com>2018-12-04 08:47:46 +0100
commit59de8ea50338b39f604fde738229aaeb791cc459 (patch)
tree17f445fc7a686cd28859e6c46fb1a32d64a56123 /Source/Core/VideoBackends/Vulkan
parentc675ef148e6872115bd46cca5b5c51826c75b373 (diff)
parent7afd5cc2fb7e45f2c497e5aed007a017b8461335 (diff)
Merge pull request #7592 from stenzek/imgui-prereq
VideoBackends: Share GX vertex/index/uniform buffers with utility draws
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp236
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.h14
-rw-r--r--Source/Core/VideoBackends/Vulkan/StateTracker.cpp95
-rw-r--r--Source/Core/VideoBackends/Vulkan/StateTracker.h13
-rw-r--r--Source/Core/VideoBackends/Vulkan/SwapChain.cpp48
-rw-r--r--Source/Core/VideoBackends/Vulkan/SwapChain.h8
-rw-r--r--Source/Core/VideoBackends/Vulkan/Util.cpp3
-rw-r--r--Source/Core/VideoBackends/Vulkan/VertexManager.cpp87
-rw-r--r--Source/Core/VideoBackends/Vulkan/VertexManager.h15
9 files changed, 247 insertions, 272 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
index ce52b0718d..6bec599882 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
@@ -49,7 +49,8 @@ namespace Vulkan
{
Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain)
: ::Renderer(swap_chain ? static_cast<int>(swap_chain->GetWidth()) : 1,
- swap_chain ? static_cast<int>(swap_chain->GetHeight()) : 0),
+ swap_chain ? static_cast<int>(swap_chain->GetHeight()) : 0,
+ swap_chain ? swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined),
m_swap_chain(std::move(swap_chain))
{
UpdateActiveConfig();
@@ -57,13 +58,7 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain)
m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex;
}
-Renderer::~Renderer()
-{
- UpdateActiveConfig();
-
- DestroyShaders();
- DestroySemaphores();
-}
+Renderer::~Renderer() = default;
Renderer* Renderer::GetInstance()
{
@@ -77,6 +72,9 @@ bool Renderer::IsHeadless() const
bool Renderer::Initialize()
{
+ if (!::Renderer::Initialize())
+ return false;
+
BindEFBToStateTracker();
if (!CreateSemaphores())
@@ -98,6 +96,23 @@ bool Renderer::Initialize()
return false;
}
+ // Swap chain render pass.
+ if (m_swap_chain)
+ {
+ m_swap_chain_render_pass =
+ g_object_cache->GetRenderPass(m_swap_chain->GetSurfaceFormat().format, VK_FORMAT_UNDEFINED,
+ 1, VK_ATTACHMENT_LOAD_OP_LOAD);
+ m_swap_chain_clear_render_pass =
+ g_object_cache->GetRenderPass(m_swap_chain->GetSurfaceFormat().format, VK_FORMAT_UNDEFINED,
+ 1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+ if (m_swap_chain_render_pass == VK_NULL_HANDLE ||
+ m_swap_chain_clear_render_pass == VK_NULL_HANDLE)
+ {
+ PanicAlert("Failed to create swap chain render passes.");
+ return false;
+ }
+ }
+
m_bounding_box = std::make_unique<BoundingBox>();
if (!m_bounding_box->Initialize())
{
@@ -131,6 +146,18 @@ bool Renderer::Initialize()
return true;
}
+void Renderer::Shutdown()
+{
+ ::Renderer::Shutdown();
+
+ // Submit the current command buffer, in case there's a partial frame.
+ StateTracker::GetInstance()->EndRenderPass();
+ g_command_buffer_mgr->ExecuteCommandBuffer(false, true);
+
+ DestroyShaders();
+ DestroySemaphores();
+}
+
bool Renderer::CreateSemaphores()
{
// Create two semaphores, one that is triggered when the swapchain buffer is ready, another after
@@ -232,164 +259,12 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(pipeline));
}
-void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
- u32 vertex_stride, u32 num_vertices)
-{
- // Binding the utility pipeline layout breaks the standard layout.
- StateTracker::GetInstance()->SetPendingRebind();
-
- // Upload uniforms.
- VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
- u32 uniform_buffer_offset = 0;
- if (uniforms_size > 0)
- std::tie(uniform_buffer, uniform_buffer_offset) =
- UpdateUtilityUniformBuffer(uniforms, uniforms_size);
-
- // Upload vertices.
- VkBuffer vertex_buffer = VK_NULL_HANDLE;
- VkDeviceSize vertex_buffer_offset = 0;
- if (vertices)
- {
- u32 vertices_size = vertex_stride * num_vertices;
- StreamBuffer* vbo_buf = g_object_cache->GetUtilityShaderVertexBuffer();
- if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride))
- {
- Util::ExecuteCurrentCommandsAndRestoreState(true);
- if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride))
- {
- PanicAlert("Failed to reserve vertex buffer space for utility draw.");
- return;
- }
- }
-
- vertex_buffer = vbo_buf->GetBuffer();
- vertex_buffer_offset = vbo_buf->GetCurrentOffset();
- std::memcpy(vbo_buf->GetCurrentHostPointer(), vertices, vertices_size);
- vbo_buf->CommitMemory(vertices_size);
- }
-
- // Allocate descriptor sets.
- std::array<VkDescriptorSet, 2> dsets;
- dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER));
- dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS));
-
- // Flush first if failed.
- if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE)
- {
- Util::ExecuteCurrentCommandsAndRestoreState(true);
- dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER));
- dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS));
-
- if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE)
- {
- PanicAlert("Failed to allocate descriptor sets in utility draw.");
- return;
- }
- }
-
- // Build UBO descriptor set.
- std::array<VkWriteDescriptorSet, 2> dswrites;
- VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)};
- dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dsets[0], 0, 0, 1,
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr};
- dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- nullptr,
- dsets[1],
- 0,
- 0,
- NUM_PIXEL_SHADER_SAMPLERS,
- VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- StateTracker::GetInstance()->GetPSSamplerBindings().data(),
- nullptr,
- nullptr};
-
- // Build commands.
- VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- StateTracker::GetInstance()->GetPipeline()->GetVkPipeline());
- if (vertex_buffer != VK_NULL_HANDLE)
- vkCmdBindVertexBuffers(command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset);
-
- // Update and bind descriptors.
- VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
- vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<u32>(dswrites.size()),
- dswrites.data(), 0, nullptr);
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0,
- static_cast<u32>(dsets.size()), dsets.data(), 1, &uniform_buffer_offset);
-
- // Ensure we're in a render pass before drawing, just in case we had to flush.
- StateTracker::GetInstance()->BeginRenderPass();
- vkCmdDraw(command_buffer, num_vertices, 1, 0, 0);
-}
-
-void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms,
- u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z)
-{
- // Binding the utility pipeline layout breaks the standard layout.
- StateTracker::GetInstance()->SetPendingRebind();
- StateTracker::GetInstance()->EndRenderPass();
-
- // Upload uniforms.
- VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
- u32 uniform_buffer_offset = 0;
- if (uniforms_size > 0)
- std::tie(uniform_buffer, uniform_buffer_offset) =
- UpdateUtilityUniformBuffer(uniforms, uniforms_size);
-
- // Flush first if failed.
- VkDescriptorSet dset = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE));
- if (dset == VK_NULL_HANDLE)
- {
- Util::ExecuteCurrentCommandsAndRestoreState(true);
- dset = g_command_buffer_mgr->AllocateDescriptorSet(
- g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE));
- if (dset == VK_NULL_HANDLE)
- {
- PanicAlert("Failed to allocate descriptor sets in utility dispatch.");
- return;
- }
- }
-
- std::array<VkWriteDescriptorSet, 2> dswrites;
- VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)};
- dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dset, 0, 0, 1,
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr};
- dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- nullptr,
- dset,
- 1,
- 0,
- NUM_PIXEL_SHADER_SAMPLERS,
- VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- StateTracker::GetInstance()->GetPSSamplerBindings().data(),
- nullptr,
- nullptr};
-
- // TODO: Texel buffers, storage images.
-
- // Build commands.
- VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
- VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
- static_cast<const VKShader*>(shader)->GetComputePipeline());
- vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<u32>(dswrites.size()),
- dswrites.data(), 0, nullptr);
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1,
- &dset, 1, &uniform_buffer_offset);
- vkCmdDispatch(command_buffer, groups_x, groups_y, groups_z);
-}
-
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
{
u32 backbuffer_width = m_swap_chain->GetWidth();
u32 backbuffer_height = m_swap_chain->GetHeight();
- m_raster_font->PrintMultiLineText(m_swap_chain->GetRenderPass(), text,
+ m_raster_font->PrintMultiLineText(m_swap_chain_render_pass, text,
left * 2.0f / static_cast<float>(backbuffer_width) - 1,
1 - top * 2.0f / static_cast<float>(backbuffer_height),
backbuffer_width, backbuffer_height, color);
@@ -807,20 +682,18 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region
m_current_framebuffer_width = backbuffer->GetWidth();
m_current_framebuffer_height = backbuffer->GetHeight();
+ // Draw to the backbuffer.
+ VkRect2D region = {{0, 0}, {backbuffer->GetWidth(), backbuffer->GetHeight()}};
+ StateTracker::GetInstance()->SetRenderPass(m_swap_chain_render_pass,
+ m_swap_chain_clear_render_pass);
+ StateTracker::GetInstance()->SetFramebuffer(m_swap_chain->GetCurrentFramebuffer(), region);
+
// Begin render pass for rendering to the swap chain.
VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
- VkRenderPassBeginInfo info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
- nullptr,
- m_swap_chain->GetRenderPass(),
- m_swap_chain->GetCurrentFramebuffer(),
- {{0, 0}, {backbuffer->GetWidth(), backbuffer->GetHeight()}},
- 1,
- &clear_value};
- vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info,
- VK_SUBPASS_CONTENTS_INLINE);
+ StateTracker::GetInstance()->BeginClearRenderPass(region, &clear_value, 1);
// Draw
- BlitScreen(m_swap_chain->GetRenderPass(), GetTargetRectangle(), xfb_region,
+ BlitScreen(m_swap_chain_render_pass, GetTargetRectangle(), xfb_region,
xfb_texture->GetRawTexIdentifier());
// Draw OSD
@@ -831,7 +704,7 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region
OSD::DrawMessages();
// End drawing to backbuffer
- vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer());
+ StateTracker::GetInstance()->EndRenderPass();
// Transition the backbuffer to PRESENT_SRC to ensure all commands drawing
// to it have finished before present.
@@ -1021,6 +894,8 @@ void Renderer::RestoreAPIState()
static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample();
BindEFBToStateTracker();
+ BPFunctions::SetViewport();
+ BPFunctions::SetScissor();
// Instruct the state tracker to re-bind everything before the next draw
StateTracker::GetInstance()->SetPendingRebind();
@@ -1158,6 +1033,23 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
StateTracker::GetInstance()->SetViewport(viewport);
}
+void Renderer::Draw(u32 base_vertex, u32 num_vertices)
+{
+ if (StateTracker::GetInstance()->Bind())
+ return;
+
+ vkCmdDraw(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_vertices, 1, base_vertex, 0);
+}
+
+void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
+{
+ if (!StateTracker::GetInstance()->Bind())
+ return;
+
+ vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_indices, 1, base_index,
+ base_vertex, 0);
+}
+
void Renderer::RecompileShaders()
{
DestroyShaders();
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h
index ba8fd889bd..bd7efc88ca 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.h
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.h
@@ -37,6 +37,9 @@ public:
bool IsHeadless() const override;
+ bool Initialize() override;
+ void Shutdown() override;
+
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
@@ -52,8 +55,6 @@ public:
SwapChain* GetSwapChain() const { return m_swap_chain.get(); }
BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); }
- bool Initialize();
-
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override;
@@ -86,11 +87,8 @@ public:
void SetInterlacingMode() override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
-
- void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
- u32 vertex_stride, u32 num_vertices) override;
- void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, u32 uniforms_size,
- u32 groups_x, u32 groups_y, u32 groups_z) override;
+ void Draw(u32 base_vertex, u32 num_vertices) override;
+ void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
private:
bool CreateSemaphores();
@@ -124,6 +122,8 @@ private:
VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE;
VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE;
+ VkRenderPass m_swap_chain_render_pass = VK_NULL_HANDLE;
+ VkRenderPass m_swap_chain_clear_render_pass = VK_NULL_HANDLE;
std::unique_ptr<SwapChain> m_swap_chain;
std::unique_ptr<BoundingBox> m_bounding_box;
diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
index f3b2752ddd..471a8b12f5 100644
--- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
+++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
@@ -218,6 +218,37 @@ void StateTracker::UpdatePixelShaderConstants()
PixelShaderManager::dirty = false;
}
+void StateTracker::UpdateConstants(const void* data, u32 data_size)
+{
+ if (!m_uniform_stream_buffer->ReserveMemory(
+ data_size, g_vulkan_context->GetUniformBufferAlignment(), true, true, false))
+ {
+ WARN_LOG(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer");
+ Util::ExecuteCurrentCommandsAndRestoreState(false);
+ }
+
+ for (u32 binding = 0; binding < NUM_UBO_DESCRIPTOR_SET_BINDINGS; binding++)
+ {
+ if (m_bindings.uniform_buffer_bindings[binding].buffer != m_uniform_stream_buffer->GetBuffer())
+ {
+ m_bindings.uniform_buffer_bindings[binding].buffer = m_uniform_stream_buffer->GetBuffer();
+ m_dirty_flags |= DIRTY_FLAG_VS_UBO << binding;
+ }
+ m_bindings.uniform_buffer_offsets[binding] =
+ static_cast<uint32_t>(m_uniform_stream_buffer->GetCurrentOffset());
+ }
+ m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS;
+
+ std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), data, data_size);
+ ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
+ m_uniform_stream_buffer->CommitMemory(data_size);
+
+ // Cached data is now out-of-sync.
+ VertexShaderManager::dirty = true;
+ GeometryShaderManager::dirty = true;
+ PixelShaderManager::dirty = true;
+}
+
bool StateTracker::ReserveConstantStorage()
{
// Since we invalidate all constants on command buffer execution, it doesn't matter if this
@@ -473,16 +504,16 @@ bool StateTracker::Bind(bool rebind_all /*= false*/)
{
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline->GetVkPipelineLayout(), 0, m_num_active_descriptor_sets,
- m_descriptor_sets.data(), NUM_UBO_DESCRIPTOR_SET_BINDINGS,
+ m_descriptor_sets.data(), m_num_dynamic_offsets,
m_bindings.uniform_buffer_offsets.data());
}
else if (m_dirty_flags & DIRTY_FLAG_DYNAMIC_OFFSETS)
{
- vkCmdBindDescriptorSets(
- command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(),
- DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS, 1,
- &m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS],
- NUM_UBO_DESCRIPTOR_SET_BINDINGS, m_bindings.uniform_buffer_offsets.data());
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ m_pipeline->GetVkPipelineLayout(),
+ DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS, 1,
+ &m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS],
+ m_num_dynamic_offsets, m_bindings.uniform_buffer_offsets.data());
}
if (m_dirty_flags & DIRTY_FLAG_VIEWPORT || rebind_all)
@@ -640,6 +671,14 @@ void StateTracker::EndClearRenderPass()
bool StateTracker::UpdateDescriptorSet()
{
+ if (m_pipeline->GetUsage() == AbstractPipelineUsage::GX)
+ return UpdateGXDescriptorSet();
+ else
+ return UpdateUtilityDescriptorSet();
+}
+
+bool StateTracker::UpdateGXDescriptorSet()
+{
const size_t MAX_DESCRIPTOR_WRITES = NUM_UBO_DESCRIPTOR_SET_BINDINGS + // UBO
1 + // Samplers
1; // SSBO
@@ -729,6 +768,50 @@ bool StateTracker::UpdateDescriptorSet()
vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), num_writes, writes.data(), 0, nullptr);
m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS;
+ m_num_dynamic_offsets = NUM_UBO_DESCRIPTOR_SET_BINDINGS;
+ return true;
+}
+
+bool StateTracker::UpdateUtilityDescriptorSet()
+{
+ // Allocate descriptor sets.
+ m_descriptor_sets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
+ g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER));
+ m_descriptor_sets[1] = g_command_buffer_mgr->AllocateDescriptorSet(
+ g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS));
+ if (m_descriptor_sets[0] == VK_NULL_HANDLE || m_descriptor_sets[1] == VK_NULL_HANDLE)
+ {
+ return false;
+ }
+
+ // Build UBO descriptor set.
+ std::array<VkWriteDescriptorSet, 2> dswrites;
+ dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ nullptr,
+ m_descriptor_sets[0],
+ 0,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ nullptr,
+ &m_bindings.uniform_buffer_bindings[UBO_DESCRIPTOR_SET_BINDING_VS],
+ nullptr};
+ dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ nullptr,
+ m_descriptor_sets[1],
+ 0,
+ 0,
+ NUM_PIXEL_SHADER_SAMPLERS,
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ m_bindings.ps_samplers.data(),
+ nullptr,
+ nullptr};
+
+ vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<uint32_t>(dswrites.size()),
+ dswrites.data(), 0, nullptr);
+ m_num_active_descriptor_sets = NUM_UTILITY_DRAW_DESCRIPTOR_SETS;
+ m_num_dynamic_offsets = 1;
+ m_dirty_flags |= DIRTY_FLAG_DESCRIPTOR_SET_BINDING;
return true;
}
diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h
index 895e139756..a3d7a365ae 100644
--- a/Source/Core/VideoBackends/Vulkan/StateTracker.h
+++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h
@@ -30,10 +30,6 @@ public:
static bool CreateInstance();
static void DestroyInstance();
- const std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS>& GetPSSamplerBindings() const
- {
- return m_bindings.ps_samplers;
- }
VkFramebuffer GetFramebuffer() const { return m_framebuffer; }
const VKPipeline* GetPipeline() const { return m_pipeline; }
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
@@ -47,6 +43,9 @@ public:
void UpdateGeometryShaderConstants();
void UpdatePixelShaderConstants();
+ // Updates constants from external data, e.g. utility draws.
+ void UpdateConstants(const void* data, u32 data_size);
+
void SetTexture(size_t index, VkImageView view);
void SetSampler(size_t index, VkSampler sampler);
@@ -104,7 +103,8 @@ private:
// Number of descriptor sets for game draws.
enum
{
- NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1
+ NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1,
+ NUM_UTILITY_DRAW_DESCRIPTOR_SETS = 2
};
enum DITRY_FLAG : u32
@@ -133,6 +133,8 @@ private:
bool IsViewportWithinRenderArea() const;
bool UpdateDescriptorSet();
+ bool UpdateGXDescriptorSet();
+ bool UpdateUtilityDescriptorSet();
// Allocates storage in the uniform buffer of the specified size. If this storage cannot be
// allocated immediately, the current command buffer will be submitted and all stage's
@@ -167,6 +169,7 @@ private:
} m_bindings;
size_t m_uniform_buffer_reserve_size = 0;
u32 m_num_active_descriptor_sets = 0;
+ u32 m_num_dynamic_offsets = 0;
// rasterization
VkViewport m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp
index ffddfe4d07..3ba46b9baa 100644
--- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp
+++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp
@@ -142,11 +142,8 @@ std::unique_ptr<SwapChain> SwapChain::Create(void* display_handle, void* native_
std::unique_ptr<SwapChain> swap_chain =
std::make_unique<SwapChain>(display_handle, native_handle, surface, vsync);
- if (!swap_chain->CreateSwapChain() || !swap_chain->CreateRenderPass() ||
- !swap_chain->SetupSwapChainImages())
- {
+ if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages())
return nullptr;
- }
return swap_chain;
}
@@ -175,13 +172,27 @@ bool SwapChain::SelectSurfaceFormat()
return true;
}
- // Use the first surface format, just use what it prefers.
- // Some drivers seem to return a SRGB format here (Intel Mesa).
- // This results in gamma correction when presenting to the screen, which we don't want.
- // Use a linear format instead, if this is the case.
- m_surface_format.format = Util::GetLinearFormat(surface_formats[0].format);
- m_surface_format.colorSpace = surface_formats[0].colorSpace;
- return true;
+ // Try to find a suitable format.
+ for (const VkSurfaceFormatKHR& surface_format : surface_formats)
+ {
+ // Some drivers seem to return a SRGB format here (Intel Mesa).
+ // This results in gamma correction when presenting to the screen, which we don't want.
+ // Use a linear format instead, if this is the case.
+ VkFormat format = Util::GetLinearFormat(surface_format.format);
+ if (format == VK_FORMAT_R8G8B8A8_UNORM)
+ m_texture_format = AbstractTextureFormat::RGBA8;
+ else if (format == VK_FORMAT_B8G8R8A8_UNORM)
+ m_texture_format = AbstractTextureFormat::BGRA8;
+ else
+ continue;
+
+ m_surface_format.format = format;
+ m_surface_format.colorSpace = surface_format.colorSpace;
+ return true;
+ }
+
+ PanicAlert("Failed to find a suitable format for swap chain buffers.");
+ return false;
}
bool SwapChain::SelectPresentMode()
@@ -236,14 +247,6 @@ bool SwapChain::SelectPresentMode()
return true;
}
-bool SwapChain::CreateRenderPass()
-{
- // render pass for rendering to the swap chain
- m_render_pass = g_object_cache->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, 1,
- VK_ATTACHMENT_LOAD_OP_CLEAR);
- return m_render_pass != VK_NULL_HANDLE;
-}
-
bool SwapChain::CreateSwapChain()
{
// Look up surface properties to determine image count and dimensions
@@ -367,6 +370,9 @@ bool SwapChain::SetupSwapChainImages()
images.data());
ASSERT(res == VK_SUCCESS);
+ VkRenderPass render_pass = g_object_cache->GetRenderPass(
+ m_surface_format.format, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+
m_swap_chain_images.reserve(image_count);
for (uint32_t i = 0; i < image_count; i++)
{
@@ -382,7 +388,7 @@ bool SwapChain::SetupSwapChainImages()
VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
- m_render_pass,
+ render_pass,
1,
&view,
m_width,
@@ -499,7 +505,7 @@ bool SwapChain::RecreateSurface(void* native_handle)
}
// Finally re-create the swap chain
- if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateRenderPass())
+ if (!CreateSwapChain() || !SetupSwapChainImages())
return false;
return true;
diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.h b/Source/Core/VideoBackends/Vulkan/SwapChain.h
index 8cf2776a36..4494d7bc57 100644
--- a/Source/Core/VideoBackends/Vulkan/SwapChain.h
+++ b/Source/Core/VideoBackends/Vulkan/SwapChain.h
@@ -10,6 +10,7 @@
#include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/Constants.h"
#include "VideoBackends/Vulkan/Texture2D.h"
+#include "VideoCommon/TextureConfig.h"
namespace Vulkan
{
@@ -33,10 +34,10 @@ public:
void* GetNativeHandle() const { return m_native_handle; }
VkSurfaceKHR GetSurface() const { return m_surface; }
VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
+ AbstractTextureFormat GetTextureFormat() const { return m_texture_format; }
bool IsVSyncEnabled() const { return m_vsync_enabled; }
bool IsStereoEnabled() const { return m_layers == 2; }
VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
- VkRenderPass GetRenderPass() const { return m_render_pass; }
u32 GetWidth() const { return m_width; }
u32 GetHeight() const { return m_height; }
u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; }
@@ -69,8 +70,6 @@ private:
bool CreateSwapChain();
void DestroySwapChain();
- bool CreateRenderPass();
-
bool SetupSwapChainImages();
void DestroySwapChainImages();
@@ -88,14 +87,13 @@ private:
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
VkSurfaceFormatKHR m_surface_format = {};
VkPresentModeKHR m_present_mode = VK_PRESENT_MODE_RANGE_SIZE_KHR;
+ AbstractTextureFormat m_texture_format = AbstractTextureFormat::Undefined;
bool m_vsync_enabled;
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
std::vector<SwapChainImage> m_swap_chain_images;
u32 m_current_swap_chain_image_index = 0;
- VkRenderPass m_render_pass = VK_NULL_HANDLE;
-
u32 m_width = 0;
u32 m_height = 0;
u32 m_layers = 0;
diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp
index 4ffa5c0146..35c9bcfbaf 100644
--- a/Source/Core/VideoBackends/Vulkan/Util.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Util.cpp
@@ -130,6 +130,9 @@ VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format)
case AbstractTextureFormat::D32F_S8:
return VK_FORMAT_D32_SFLOAT_S8_UINT;
+ case AbstractTextureFormat::Undefined:
+ return VK_FORMAT_UNDEFINED;
+
default:
PanicAlert("Unhandled texture format.");
return VK_FORMAT_R8G8B8A8_UNORM;
diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp
index 4fa3a92b09..bd0ab0b54d 100644
--- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp
+++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp
@@ -69,25 +69,14 @@ VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_dec
return std::make_unique<VertexFormat>(vtx_decl);
}
-void VertexManager::PrepareDrawBuffers(u32 stride)
+void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
{
- size_t vertex_data_size = IndexGenerator::GetNumVerts() * stride;
- size_t index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16);
-
- m_vertex_stream_buffer->CommitMemory(vertex_data_size);
- m_index_stream_buffer->CommitMemory(index_data_size);
-
- ADDSTAT(stats.thisFrame.bytesVertexStreamed, static_cast<int>(vertex_data_size));
- ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast<int>(index_data_size));
-
- StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0);
- StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0,
- VK_INDEX_TYPE_UINT16);
+ StateTracker::GetInstance()->UpdateConstants(uniforms, uniforms_size);
}
-void VertexManager::ResetBuffer(u32 stride)
+void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
{
- if (m_cull_all)
+ if (cull_all)
{
// Not drawing on the gpu, so store in a heap buffer instead
m_cur_buffer_pointer = m_base_buffer_pointer = m_cpu_vertex_buffer.data();
@@ -97,7 +86,8 @@ void VertexManager::ResetBuffer(u32 stride)
}
// Attempt to allocate from buffers
- bool has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, stride);
+ bool has_vbuffer_allocation =
+ m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride);
bool has_ibuffer_allocation =
m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
if (!has_vbuffer_allocation || !has_ibuffer_allocation)
@@ -108,7 +98,7 @@ void VertexManager::ResetBuffer(u32 stride)
// Attempt to allocate again, this may cause a fence wait
if (!has_vbuffer_allocation)
- has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, stride);
+ has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride);
if (!has_ibuffer_allocation)
has_ibuffer_allocation =
m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
@@ -123,34 +113,40 @@ void VertexManager::ResetBuffer(u32 stride)
m_end_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer() + MAXVBUFFERSIZE;
m_cur_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer();
IndexGenerator::Start(reinterpret_cast<u16*>(m_index_stream_buffer->GetCurrentHostPointer()));
-
- // Update base indices
- m_current_draw_base_vertex =
- static_cast<u32>(m_vertex_stream_buffer->GetCurrentOffset() / stride);
- m_current_draw_base_index =
- static_cast<u32>(m_index_stream_buffer->GetCurrentOffset() / sizeof(u16));
}
-void VertexManager::vFlush()
+void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
+ u32* out_base_vertex, u32* out_base_index)
{
- const VertexFormat* vertex_format =
- static_cast<VertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat());
- u32 vertex_stride = vertex_format->GetVertexStride();
+ const u32 vertex_data_size = num_vertices * vertex_stride;
+ const u32 index_data_size = num_indices * sizeof(u16);
+
+ *out_base_vertex =
+ vertex_stride > 0 ?
+ static_cast<u32>(m_vertex_stream_buffer->GetCurrentOffset() / vertex_stride) :
+ 0;
+ *out_base_index = static_cast<u32>(m_index_stream_buffer->GetCurrentOffset() / sizeof(u16));
- // Figure out the number of indices to draw
- u32 index_count = IndexGenerator::GetIndexLen();
+ m_vertex_stream_buffer->CommitMemory(vertex_data_size);
+ m_index_stream_buffer->CommitMemory(index_data_size);
- // Update tracked state
+ ADDSTAT(stats.thisFrame.bytesVertexStreamed, static_cast<int>(vertex_data_size));
+ ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast<int>(index_data_size));
+
+ StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0);
+ StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0,
+ VK_INDEX_TYPE_UINT16);
+}
+
+void VertexManager::UploadConstants()
+{
StateTracker::GetInstance()->UpdateVertexShaderConstants();
StateTracker::GetInstance()->UpdateGeometryShaderConstants();
StateTracker::GetInstance()->UpdatePixelShaderConstants();
+}
- // Commit memory to device.
- // NOTE: This must be done after constant upload, as a constant buffer overrun can cause
- // the current command buffer to be executed, and we want the buffer space to be associated
- // with the command buffer that has the corresponding draw.
- PrepareDrawBuffers(vertex_stride);
-
+void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
+{
// Flush all EFB pokes and invalidate the peek cache.
FramebufferManager::GetInstance()->InvalidatePeekCache();
FramebufferManager::GetInstance()->FlushEFBPokes();
@@ -168,19 +164,14 @@ void VertexManager::vFlush()
}
// Bind all pending state to the command buffer
- if (m_current_pipeline_object)
+ if (StateTracker::GetInstance()->Bind())
{
- g_renderer->SetPipeline(m_current_pipeline_object);
- if (!StateTracker::GetInstance()->Bind())
- {
- WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count);
- return;
- }
-
- // Execute the draw
- vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), index_count, 1,
- m_current_draw_base_index, m_current_draw_base_vertex, 0);
- INCSTAT(stats.thisFrame.numDrawCalls);
+ vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_indices, 1, base_index,
+ base_vertex, 0);
+ }
+ else
+ {
+ WARN_LOG(VIDEO, "Skipped draw of %u indices", num_indices);
}
StateTracker::GetInstance()->OnDraw();
diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.h b/Source/Core/VideoBackends/Vulkan/VertexManager.h
index 1f892e4151..65c31e11f4 100644
--- a/Source/Core/VideoBackends/Vulkan/VertexManager.h
+++ b/Source/Core/VideoBackends/Vulkan/VertexManager.h
@@ -27,20 +27,19 @@ public:
std::unique_ptr<NativeVertexFormat>
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
-protected:
- void PrepareDrawBuffers(u32 stride);
- void ResetBuffer(u32 stride) override;
+ void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
-private:
- void vFlush() override;
+protected:
+ void ResetBuffer(u32 vertex_stride, bool cull_all) override;
+ void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
+ u32* out_base_index) override;
+ void UploadConstants() override;
+ void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
std::vector<u8> m_cpu_vertex_buffer;
std::vector<u16> m_cpu_index_buffer;
std::unique_ptr<StreamBuffer> m_vertex_stream_buffer;
std::unique_ptr<StreamBuffer> m_index_stream_buffer;
-
- u32 m_current_draw_base_vertex = 0;
- u32 m_current_draw_base_index = 0;
};
}