VideoBackends: Add AbstractShader and AbstractPipeline classes

This commit is contained in:
Stenzek
2017-09-08 19:42:56 +10:00
parent 31111ef143
commit fec6bb4d56
47 changed files with 1825 additions and 33 deletions

View File

@ -19,6 +19,8 @@ set(SRCS
Util.cpp
VertexFormat.cpp
VertexManager.cpp
VKPipeline.cpp
VKShader.cpp
VKTexture.cpp
VulkanContext.cpp
VulkanLoader.cpp

View File

@ -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;
};

View File

@ -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}};

View File

@ -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();

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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);

View File

@ -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

View 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

View 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

View 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

View 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

View File

@ -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" />