mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
VideoBackends: Add AbstractShader and AbstractPipeline classes
This commit is contained in:
@ -19,6 +19,8 @@ set(SRCS
|
||||
Util.cpp
|
||||
VertexFormat.cpp
|
||||
VertexManager.cpp
|
||||
VKPipeline.cpp
|
||||
VKShader.cpp
|
||||
VKTexture.cpp
|
||||
VulkanContext.cpp
|
||||
VulkanLoader.cpp
|
||||
|
@ -26,7 +26,8 @@ enum STAGING_BUFFER_TYPE
|
||||
// Descriptor set layouts
|
||||
enum DESCRIPTOR_SET_LAYOUT
|
||||
{
|
||||
DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER,
|
||||
DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS,
|
||||
DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS,
|
||||
DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS,
|
||||
@ -69,6 +70,7 @@ enum PIPELINE_LAYOUT
|
||||
PIPELINE_LAYOUT_BBOX,
|
||||
PIPELINE_LAYOUT_PUSH_CONSTANT,
|
||||
PIPELINE_LAYOUT_TEXTURE_CONVERSION,
|
||||
PIPELINE_LAYOUT_UTILITY,
|
||||
PIPELINE_LAYOUT_COMPUTE,
|
||||
NUM_PIPELINE_LAYOUTS
|
||||
};
|
||||
@ -128,7 +130,7 @@ constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||
union MultisamplingState
|
||||
{
|
||||
BitField<0, 5, u32> samples; // 1-16
|
||||
BitField<0, 1, u32> per_sample_shading; // SSAA
|
||||
BitField<5, 1, u32> per_sample_shading; // SSAA
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
|
@ -106,7 +106,10 @@ void ObjectCache::DestroySamplers()
|
||||
|
||||
bool ObjectCache::CreateDescriptorSetLayouts()
|
||||
{
|
||||
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
||||
static const VkDescriptorSetLayoutBinding single_ubo_set_bindings[] = {
|
||||
0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT};
|
||||
static const VkDescriptorSetLayoutBinding per_stage_ubo_set_bindings[] = {
|
||||
{UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||
{UBO_DESCRIPTOR_SET_BINDING_VS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||
@ -138,7 +141,9 @@ bool ObjectCache::CreateDescriptorSetLayouts()
|
||||
|
||||
static const VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = {
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(ubo_set_bindings)), ubo_set_bindings},
|
||||
static_cast<u32>(ArraySize(single_ubo_set_bindings)), single_ubo_set_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(per_stage_ubo_set_bindings)), per_stage_ubo_set_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(sampler_set_bindings)), sampler_set_bindings},
|
||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
@ -177,16 +182,19 @@ bool ObjectCache::CreatePipelineLayouts()
|
||||
|
||||
// Descriptor sets for each pipeline layout
|
||||
VkDescriptorSetLayout standard_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
||||
VkDescriptorSetLayout bbox_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS]};
|
||||
VkDescriptorSetLayout texture_conversion_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS]};
|
||||
VkDescriptorSetLayout utility_sets[] = {
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER],
|
||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
||||
VkDescriptorSetLayout compute_sets[] = {m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_COMPUTE]};
|
||||
VkPushConstantRange push_constant_range = {
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, PUSH_CONSTANT_BUFFER_SIZE};
|
||||
@ -212,6 +220,10 @@ bool ObjectCache::CreatePipelineLayouts()
|
||||
static_cast<u32>(ArraySize(texture_conversion_sets)), texture_conversion_sets, 1,
|
||||
&push_constant_range},
|
||||
|
||||
// Texture Conversion
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(utility_sets)), utility_sets, 0, nullptr},
|
||||
|
||||
// Compute
|
||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||
static_cast<u32>(ArraySize(compute_sets)), compute_sets, 1, &compute_push_constant_range}};
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
@ -23,9 +24,12 @@
|
||||
#include "VideoBackends/Vulkan/RasterFont.h"
|
||||
#include "VideoBackends/Vulkan/Renderer.h"
|
||||
#include "VideoBackends/Vulkan/StateTracker.h"
|
||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||
#include "VideoBackends/Vulkan/SwapChain.h"
|
||||
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VKPipeline.h"
|
||||
#include "VideoBackends/Vulkan/VKShader.h"
|
||||
#include "VideoBackends/Vulkan/VKTexture.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
@ -171,6 +175,202 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
||||
return VKStagingTexture::Create(type, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||
const char* source, size_t length)
|
||||
{
|
||||
return VKShader::CreateFromSource(stage, source, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||
const void* data, size_t length)
|
||||
{
|
||||
return VKShader::CreateFromBinary(stage, data, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
{
|
||||
return VKPipeline::Create(config);
|
||||
}
|
||||
|
||||
std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* uniforms,
|
||||
u32 uniforms_size)
|
||||
{
|
||||
StreamBuffer* ubo_buf = g_object_cache->GetUtilityShaderUniformBuffer();
|
||||
if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment()))
|
||||
{
|
||||
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
||||
if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment()))
|
||||
{
|
||||
PanicAlert("Failed to reserve uniform buffer space for utility draw.");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
VkBuffer ubo = ubo_buf->GetBuffer();
|
||||
u32 ubo_offset = static_cast<u32>(ubo_buf->GetCurrentOffset());
|
||||
std::memcpy(ubo_buf->GetCurrentHostPointer(), uniforms, uniforms_size);
|
||||
ubo_buf->CommitMemory(uniforms_size);
|
||||
|
||||
return std::tie(ubo, ubo_offset);
|
||||
}
|
||||
|
||||
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
||||
{
|
||||
m_graphics_pipeline = 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,
|
||||
m_graphics_pipeline->GetPipeline());
|
||||
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();
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Vulkan/Constants.h"
|
||||
@ -22,6 +23,7 @@ class SwapChain;
|
||||
class StagingTexture2D;
|
||||
class Texture2D;
|
||||
class RasterFont;
|
||||
class VKPipeline;
|
||||
class VKTexture;
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
@ -36,6 +38,12 @@ public:
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
|
||||
SwapChain* GetSwapChain() const { return m_swap_chain.get(); }
|
||||
BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); }
|
||||
bool Initialize();
|
||||
@ -59,6 +67,7 @@ public:
|
||||
void ResetAPIState() override;
|
||||
void RestoreAPIState() override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
@ -70,6 +79,11 @@ public:
|
||||
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;
|
||||
|
||||
private:
|
||||
bool CreateSemaphores();
|
||||
void DestroySemaphores();
|
||||
@ -97,6 +111,8 @@ private:
|
||||
void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect,
|
||||
const TargetRectangle& src_rect, const Texture2D* src_tex);
|
||||
|
||||
std::tuple<VkBuffer, u32> UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size);
|
||||
|
||||
VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE;
|
||||
|
||||
@ -109,5 +125,6 @@ private:
|
||||
|
||||
// Shaders used for clear/blit.
|
||||
VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE;
|
||||
const VKPipeline* m_graphics_pipeline = nullptr;
|
||||
};
|
||||
}
|
||||
|
@ -1043,7 +1043,7 @@ bool StateTracker::UpdateDescriptorSet()
|
||||
m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS] == VK_NULL_HANDLE)
|
||||
{
|
||||
VkDescriptorSetLayout layout =
|
||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS);
|
||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS);
|
||||
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(layout);
|
||||
if (set == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
@ -41,6 +41,10 @@ public:
|
||||
}
|
||||
const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; }
|
||||
const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; }
|
||||
const std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS>& GetPSSamplerBindings() const
|
||||
{
|
||||
return m_bindings.ps_samplers;
|
||||
}
|
||||
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
||||
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
||||
|
||||
|
@ -566,7 +566,7 @@ void UtilityShaderDraw::BindDescriptors()
|
||||
if (m_vs_uniform_buffer.buffer != VK_NULL_HANDLE || m_ps_uniform_buffer.buffer != VK_NULL_HANDLE)
|
||||
{
|
||||
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS));
|
||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS));
|
||||
if (set == VK_NULL_HANDLE)
|
||||
PanicAlert("Failed to allocate descriptor set for utility draw");
|
||||
|
||||
@ -595,7 +595,7 @@ void UtilityShaderDraw::BindDescriptors()
|
||||
&dummy_uniform_buffer,
|
||||
nullptr};
|
||||
|
||||
bind_descriptor_sets[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS] = set;
|
||||
bind_descriptor_sets[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS] = set;
|
||||
}
|
||||
|
||||
// PS samplers
|
||||
|
73
Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
Normal file
73
Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/ObjectCache.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VKPipeline.h"
|
||||
#include "VideoBackends/Vulkan/VKShader.h"
|
||||
#include "VideoBackends/Vulkan/VertexFormat.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
VKPipeline::VKPipeline(VkPipeline pipeline) : m_pipeline(pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
VKPipeline::~VKPipeline()
|
||||
{
|
||||
vkDestroyPipeline(g_vulkan_context->GetDevice(), m_pipeline, nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& config)
|
||||
{
|
||||
_dbg_assert_(VIDEO, config.vertex_shader && config.pixel_shader);
|
||||
|
||||
// Get render pass for config.
|
||||
VkRenderPass render_pass = g_object_cache->GetRenderPass(
|
||||
Util::GetVkFormatForHostTextureFormat(config.framebuffer_state.color_texture_format),
|
||||
VK_FORMAT_UNDEFINED, config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
|
||||
// Get pipeline layout.
|
||||
VkPipelineLayout pipeline_layout;
|
||||
switch (config.usage)
|
||||
{
|
||||
case AbstractPipelineUsage::GX:
|
||||
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||
break;
|
||||
case AbstractPipelineUsage::Utility:
|
||||
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
|
||||
break;
|
||||
default:
|
||||
PanicAlert("Unknown pipeline layout.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: Move ShaderCache stuff to here.
|
||||
PipelineInfo pinfo;
|
||||
pinfo.vertex_format = static_cast<const VertexFormat*>(config.vertex_format);
|
||||
pinfo.pipeline_layout = pipeline_layout;
|
||||
pinfo.vs = static_cast<const VKShader*>(config.vertex_shader)->GetShaderModule();
|
||||
pinfo.ps = static_cast<const VKShader*>(config.pixel_shader)->GetShaderModule();
|
||||
pinfo.gs = config.geometry_shader ?
|
||||
static_cast<const VKShader*>(config.geometry_shader)->GetShaderModule() :
|
||||
VK_NULL_HANDLE;
|
||||
pinfo.render_pass = render_pass;
|
||||
pinfo.rasterization_state.hex = config.rasterization_state.hex;
|
||||
pinfo.depth_state.hex = config.depth_state.hex;
|
||||
pinfo.blend_state.hex = config.blending_state.hex;
|
||||
pinfo.multisampling_state.hex = 0;
|
||||
pinfo.multisampling_state.samples = config.framebuffer_state.samples;
|
||||
pinfo.multisampling_state.per_sample_shading = config.framebuffer_state.per_sample_shading;
|
||||
|
||||
VkPipeline pipeline = g_shader_cache->CreatePipeline(pinfo);
|
||||
if (pipeline == VK_NULL_HANDLE)
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<VKPipeline>(pipeline);
|
||||
}
|
||||
} // namespace Vulkan
|
27
Source/Core/VideoBackends/Vulkan/VKPipeline.h
Normal file
27
Source/Core/VideoBackends/Vulkan/VKPipeline.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
class VKPipeline final : public AbstractPipeline
|
||||
{
|
||||
public:
|
||||
explicit VKPipeline(VkPipeline pipeline);
|
||||
~VKPipeline() override;
|
||||
|
||||
VkPipeline GetPipeline() const { return m_pipeline; }
|
||||
static std::unique_ptr<VKPipeline> Create(const AbstractPipelineConfig& config);
|
||||
|
||||
private:
|
||||
VkPipeline m_pipeline;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
124
Source/Core/VideoBackends/Vulkan/VKShader.cpp
Normal file
124
Source/Core/VideoBackends/Vulkan/VKShader.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "VideoBackends/Vulkan/ShaderCompiler.h"
|
||||
#include "VideoBackends/Vulkan/Util.h"
|
||||
#include "VideoBackends/Vulkan/VKShader.h"
|
||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
VKShader::VKShader(ShaderStage stage, std::vector<u32> spv, VkShaderModule mod)
|
||||
: AbstractShader(stage), m_spv(std::move(spv)), m_module(mod),
|
||||
m_compute_pipeline(VK_NULL_HANDLE)
|
||||
{
|
||||
}
|
||||
|
||||
VKShader::VKShader(std::vector<u32> spv, VkPipeline compute_pipeline)
|
||||
: AbstractShader(ShaderStage::Compute), m_spv(std::move(spv)), m_module(VK_NULL_HANDLE),
|
||||
m_compute_pipeline(compute_pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
VKShader::~VKShader()
|
||||
{
|
||||
if (m_stage != ShaderStage::Compute)
|
||||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_module, nullptr);
|
||||
else
|
||||
vkDestroyPipeline(g_vulkan_context->GetDevice(), m_compute_pipeline, nullptr);
|
||||
}
|
||||
|
||||
bool VKShader::HasBinary() const
|
||||
{
|
||||
_assert_(!m_spv.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractShader::BinaryData VKShader::GetBinary() const
|
||||
{
|
||||
BinaryData ret(sizeof(u32) * m_spv.size());
|
||||
std::memcpy(ret.data(), m_spv.data(), sizeof(u32) * m_spv.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::unique_ptr<VKShader> CreateShaderObject(ShaderStage stage,
|
||||
ShaderCompiler::SPIRVCodeVector spv)
|
||||
{
|
||||
VkShaderModule mod = Util::CreateShaderModule(spv.data(), spv.size());
|
||||
if (mod == VK_NULL_HANDLE)
|
||||
return nullptr;
|
||||
|
||||
// If it's a graphics shader, we defer pipeline creation.
|
||||
if (stage != ShaderStage::Compute)
|
||||
return std::make_unique<VKShader>(stage, std::move(spv), mod);
|
||||
|
||||
// If it's a compute shader, we create the pipeline straight away.
|
||||
ComputePipelineInfo pinfo;
|
||||
pinfo.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_COMPUTE);
|
||||
pinfo.cs = mod;
|
||||
VkPipeline pipeline = g_shader_cache->CreateComputePipeline(pinfo);
|
||||
if (pipeline == VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), mod, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shader module is no longer needed, now it is compiled to a pipeline.
|
||||
return std::make_unique<VKShader>(std::move(spv), pipeline);
|
||||
}
|
||||
|
||||
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector spv;
|
||||
bool result;
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
result = ShaderCompiler::CompileVertexShader(&spv, source, length);
|
||||
break;
|
||||
case ShaderStage::Geometry:
|
||||
result = ShaderCompiler::CompileGeometryShader(&spv, source, length);
|
||||
break;
|
||||
case ShaderStage::Pixel:
|
||||
result = ShaderCompiler::CompileFragmentShader(&spv, source, length);
|
||||
break;
|
||||
case ShaderStage::Compute:
|
||||
result = ShaderCompiler::CompileComputeShader(&spv, source, length);
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
return CreateShaderObject(stage, std::move(spv));
|
||||
}
|
||||
|
||||
std::unique_ptr<VKShader> VKShader::CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length)
|
||||
{
|
||||
ShaderCompiler::SPIRVCodeVector spv;
|
||||
const size_t size_in_words = sizeof(length) / sizeof(ShaderCompiler::SPIRVCodeType);
|
||||
if (size_in_words > 0)
|
||||
{
|
||||
spv.resize(length / size_in_words);
|
||||
std::memcpy(spv.data(), data, size_in_words);
|
||||
}
|
||||
|
||||
// Non-aligned code sizes, unlikely (unless using VK_NV_glsl).
|
||||
if ((length % sizeof(ShaderCompiler::SPIRVCodeType)) != 0)
|
||||
{
|
||||
spv.resize(size_in_words + 1);
|
||||
std::memcpy(&spv[size_in_words], data, (length % sizeof(ShaderCompiler::SPIRVCodeType)));
|
||||
}
|
||||
|
||||
return CreateShaderObject(stage, std::move(spv));
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
40
Source/Core/VideoBackends/Vulkan/VKShader.h
Normal file
40
Source/Core/VideoBackends/Vulkan/VKShader.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
class VKShader final : public AbstractShader
|
||||
{
|
||||
public:
|
||||
VKShader(ShaderStage stage, std::vector<u32> spv, VkShaderModule mod);
|
||||
VKShader(std::vector<u32> spv, VkPipeline compute_pipeline);
|
||||
~VKShader() override;
|
||||
|
||||
VkShaderModule GetShaderModule() const { return m_module; }
|
||||
VkPipeline GetComputePipeline() const { return m_compute_pipeline; }
|
||||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length);
|
||||
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length);
|
||||
|
||||
private:
|
||||
std::vector<u32> m_spv;
|
||||
VkShaderModule m_module;
|
||||
VkPipeline m_compute_pipeline;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
@ -57,6 +57,8 @@
|
||||
<ClCompile Include="Texture2D.cpp" />
|
||||
<ClCompile Include="TextureCache.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
<ClCompile Include="VKPipeline.cpp" />
|
||||
<ClCompile Include="VKShader.cpp" />
|
||||
<ClCompile Include="VKTexture.cpp" />
|
||||
<ClCompile Include="VulkanContext.cpp" />
|
||||
<ClCompile Include="VulkanLoader.cpp" />
|
||||
@ -84,6 +86,8 @@
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="VKPipeline.h" />
|
||||
<ClInclude Include="VKShader.h" />
|
||||
<ClInclude Include="VKTexture.h" />
|
||||
<ClInclude Include="VulkanContext.h" />
|
||||
<ClInclude Include="VulkanLoader.h" />
|
||||
|
Reference in New Issue
Block a user