renderer_vulkan: Add very basic pipeline and shader cache

This commit is contained in:
GPUCode
2022-05-14 18:31:03 +03:00
parent 72340c5685
commit 0d0712f7d7
12 changed files with 2003 additions and 196 deletions

View File

@ -82,6 +82,8 @@ add_library(video_core STATIC
renderer_vulkan/vk_rasterizer.cpp renderer_vulkan/vk_rasterizer.cpp
renderer_vulkan/vk_rasterizer.h renderer_vulkan/vk_rasterizer.h
renderer_vulkan/vk_shader_state.h renderer_vulkan/vk_shader_state.h
renderer_vulkan/vk_shader_gen.cpp
renderer_vulkan/vk_shader_gen.h
renderer_vulkan/vk_state.cpp renderer_vulkan/vk_state.cpp
renderer_vulkan/vk_state.h renderer_vulkan/vk_state.h
renderer_vulkan/vk_surface_params.cpp renderer_vulkan/vk_surface_params.cpp

View File

@ -29,24 +29,12 @@
#include "core/tracer/recorder.h" #include "core/tracer/recorder.h"
#include "video_core/debug_utils/debug_utils.h" #include "video_core/debug_utils/debug_utils.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_vulkan/vk_state.h"
#include "video_core/renderer_opengl/gl_vars.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_opengl/post_processing_opengl.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
namespace Vulkan { namespace Vulkan {
// If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have
// to wait on available presentation frames. There doesn't seem to be much of a downside to a larger
// number but 9 swap textures at 60FPS presentation allows for 800% speed so thats probably fine
#ifdef ANDROID
// Reduce the size of swap_chain, since the UI only allows upto 200% speed.
constexpr std::size_t SWAP_CHAIN_SIZE = 6;
#else
constexpr std::size_t SWAP_CHAIN_SIZE = 9;
#endif
class OGLTextureMailboxException : public std::runtime_error { class OGLTextureMailboxException : public std::runtime_error {
public: public:
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
@ -371,13 +359,13 @@ RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
frame_dumper.mailbox = std::make_unique<OGLVideoDumpingMailbox>(); frame_dumper.mailbox = std::make_unique<OGLVideoDumpingMailbox>();
} }
RendererOpenGL::~RendererOpenGL() = default; RendererVulkan::~RendererVulkan() = default;
MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64)); MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64));
MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128));
/// Swap buffers (render frame) /// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers() { void RendererVulkan::SwapBuffers() {
// Maintain the rasterizer's state as a priority // Maintain the rasterizer's state as a priority
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
state.Apply(); state.Apply();
@ -415,7 +403,7 @@ void RendererOpenGL::SwapBuffers() {
} }
} }
void RendererOpenGL::RenderScreenshot() { void RendererVulkan::RenderScreenshot() {
if (VideoCore::g_renderer_screenshot_requested) { if (VideoCore::g_renderer_screenshot_requested) {
// Draw this frame to the screenshot framebuffer // Draw this frame to the screenshot framebuffer
screenshot_framebuffer.Create(); screenshot_framebuffer.Create();
@ -449,7 +437,7 @@ void RendererOpenGL::RenderScreenshot() {
} }
} }
void RendererOpenGL::PrepareRendertarget() { void RendererVulkan::PrepareRendertarget() {
for (int i : {0, 1, 2}) { for (int i : {0, 1, 2}) {
int fb_id = i == 2 ? 1 : 0; int fb_id = i == 2 ? 1 : 0;
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id]; const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
@ -486,7 +474,7 @@ void RendererOpenGL::PrepareRendertarget() {
} }
} }
void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout, void RendererVulkan::RenderToMailbox(const Layout::FramebufferLayout& layout,
std::unique_ptr<Frontend::TextureMailbox>& mailbox, std::unique_ptr<Frontend::TextureMailbox>& mailbox,
bool flipped) { bool flipped) {
@ -540,7 +528,7 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
/** /**
* Loads framebuffer from emulated memory into the active OpenGL texture. * Loads framebuffer from emulated memory into the active OpenGL texture.
*/ */
void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
ScreenInfo& screen_info, bool right_eye) { ScreenInfo& screen_info, bool right_eye) {
if (framebuffer.address_right1 == 0 || framebuffer.address_right2 == 0) if (framebuffer.address_right1 == 0 || framebuffer.address_right2 == 0)
@ -601,7 +589,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
* Fills active OpenGL texture with the given RGB color. Since the color is solid, the texture can * Fills active OpenGL texture with the given RGB color. Since the color is solid, the texture can
* be 1x1 but will stretch across whatever it's rendered on. * be 1x1 but will stretch across whatever it's rendered on.
*/ */
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, void RendererVulkan::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b,
const TextureInfo& texture) { const TextureInfo& texture) {
state.texture_units[0].texture_2d = texture.resource.handle; state.texture_units[0].texture_2d = texture.resource.handle;
state.Apply(); state.Apply();
@ -619,7 +607,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
/** /**
* Initializes the OpenGL state and creates persistent objects. * Initializes the OpenGL state and creates persistent objects.
*/ */
void RendererOpenGL::InitOpenGLObjects() { void RendererVulkan::InitOpenGLObjects() {
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
0.0f); 0.0f);
@ -672,7 +660,7 @@ void RendererOpenGL::InitOpenGLObjects() {
state.Apply(); state.Apply();
} }
void RendererOpenGL::ReloadSampler() { void RendererVulkan::ReloadSampler() {
glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_MIN_FILTER, glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_MIN_FILTER,
Settings::values.filter_mode ? GL_LINEAR : GL_NEAREST); Settings::values.filter_mode ? GL_LINEAR : GL_NEAREST);
glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_MAG_FILTER, glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_MAG_FILTER,
@ -681,7 +669,7 @@ void RendererOpenGL::ReloadSampler() {
glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
void RendererOpenGL::ReloadShader() { void RendererVulkan::ReloadShader() {
// Link shaders and get variable locations // Link shaders and get variable locations
std::string shader_data; std::string shader_data;
if (GLES) { if (GLES) {
@ -754,7 +742,7 @@ void RendererOpenGL::ReloadShader() {
attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord"); attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
} }
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer) { const GPU::Regs::FramebufferConfig& framebuffer) {
GPU::Regs::PixelFormat format = framebuffer.color_format; GPU::Regs::PixelFormat format = framebuffer.color_format;
GLint internal_format; GLint internal_format;
@ -819,7 +807,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
* rotation. * rotation.
*/ */
void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y,
float w, float h) { float w, float h) {
const auto& texcoords = screen_info.display_texcoords; const auto& texcoords = screen_info.display_texcoords;
@ -851,7 +839,7 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
state.Apply(); state.Apply();
} }
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
float h) { float h) {
const auto& texcoords = screen_info.display_texcoords; const auto& texcoords = screen_info.display_texcoords;
@ -884,7 +872,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
* rotation. * rotation.
*/ */
void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
const ScreenInfo& screen_info_r, float x, const ScreenInfo& screen_info_r, float x,
float y, float w, float h) { float y, float w, float h) {
const auto& texcoords = screen_info_l.display_texcoords; const auto& texcoords = screen_info_l.display_texcoords;
@ -919,7 +907,7 @@ void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info
state.Apply(); state.Apply();
} }
void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l, void RendererVulkan::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
const ScreenInfo& screen_info_r, float x, float y, const ScreenInfo& screen_info_r, float x, float y,
float w, float h) { float w, float h) {
const auto& texcoords = screen_info_l.display_texcoords; const auto& texcoords = screen_info_l.display_texcoords;
@ -957,7 +945,7 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
/** /**
* Draws the emulated screens to the emulator window. * Draws the emulated screens to the emulator window.
*/ */
void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) { void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) {
if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) { if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) {
// Update background color before drawing // Update background color before drawing
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
@ -1123,7 +1111,7 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
} }
} }
void RendererOpenGL::TryPresent(int timeout_ms) { void RendererVulkan::TryPresent(int timeout_ms) {
const auto& layout = render_window.GetFramebufferLayout(); const auto& layout = render_window.GetFramebufferLayout();
auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms); auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms);
if (!frame) { if (!frame) {
@ -1164,9 +1152,9 @@ void RendererOpenGL::TryPresent(int timeout_ms) {
} }
/// Updates the framerate /// Updates the framerate
void RendererOpenGL::UpdateFramerate() {} void RendererVulkan::UpdateFramerate() {}
void RendererOpenGL::PrepareVideoDumping() { void RendererVulkan::PrepareVideoDumping() {
auto* mailbox = static_cast<OGLVideoDumpingMailbox*>(frame_dumper.mailbox.get()); auto* mailbox = static_cast<OGLVideoDumpingMailbox*>(frame_dumper.mailbox.get());
{ {
std::unique_lock lock(mailbox->swap_chain_lock); std::unique_lock lock(mailbox->swap_chain_lock);
@ -1175,7 +1163,7 @@ void RendererOpenGL::PrepareVideoDumping() {
frame_dumper.StartDumping(); frame_dumper.StartDumping();
} }
void RendererOpenGL::CleanupVideoDumping() { void RendererVulkan::CleanupVideoDumping() {
frame_dumper.StopDumping(); frame_dumper.StopDumping();
auto* mailbox = static_cast<OGLVideoDumpingMailbox*>(frame_dumper.mailbox.get()); auto* mailbox = static_cast<OGLVideoDumpingMailbox*>(frame_dumper.mailbox.get());
{ {
@ -1240,7 +1228,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
} }
/// Initialize the renderer /// Initialize the renderer
VideoCore::ResultStatus RendererOpenGL::Init() { VideoCore::ResultStatus RendererVulkan::Init() {
#ifndef ANDROID #ifndef ANDROID
if (!gladLoadGL()) { if (!gladLoadGL()) {
return VideoCore::ResultStatus::ErrorBelowGL33; return VideoCore::ResultStatus::ErrorBelowGL33;
@ -1284,6 +1272,6 @@ VideoCore::ResultStatus RendererOpenGL::Init() {
} }
/// Shutdown the renderer /// Shutdown the renderer
void RendererOpenGL::ShutDown() {} void RendererVulkan::ShutDown() {}
} // namespace OpenGL } // namespace OpenGL

View File

@ -62,8 +62,7 @@ private:
void RenderScreenshot(); void RenderScreenshot();
void RenderToMailbox(const Layout::FramebufferLayout& layout, void RenderToMailbox(const Layout::FramebufferLayout& layout,
std::unique_ptr<Frontend::TextureMailbox>& mailbox, bool flipped); std::unique_ptr<Frontend::TextureMailbox>& mailbox, bool flipped);
void ConfigureFramebufferTexture(TextureInfo& texture, void ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer);
const GPU::Regs::FramebufferConfig& framebuffer);
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h); void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h);
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
@ -78,7 +77,7 @@ private:
void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer, void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
ScreenInfo& screen_info, bool right_eye); ScreenInfo& screen_info, bool right_eye);
// Fills active OpenGL texture with the given RGB color. // Fills active OpenGL texture with the given RGB color.
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const ScreenInfo& screen);
VulkanState state; VulkanState state;

View File

@ -113,55 +113,67 @@ bool VKInstance::CreateDevice(vk::SurfaceKHR surface, bool validation_enabled) {
bool VKInstance::FindFeatures() bool VKInstance::FindFeatures()
{ {
auto available_features = physical_device.getFeatures(); auto available = physical_device.getFeatures();
// Not having geometry shaders or wide lines will cause issues with rendering. // Not having geometry shaders or wide lines will cause issues with rendering.
if (!available_features.geometryShader && !available_features.wideLines) { if (!available.geometryShader && !available.wideLines) {
LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Rendering will be limited"); LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Rendering will be limited");
} }
// Enable some common features other emulators like Dolphin use // Enable some common features other emulators like Dolphin use
device_features.dualSrcBlend = available_features.dualSrcBlend; vk_features.dualSrcBlend = available.dualSrcBlend;
device_features.geometryShader = available_features.geometryShader; vk_features.geometryShader = available.geometryShader;
device_features.samplerAnisotropy = available_features.samplerAnisotropy; vk_features.samplerAnisotropy = available.samplerAnisotropy;
device_features.logicOp = available_features.logicOp; vk_features.logicOp = available.logicOp;
device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics; vk_features.fragmentStoresAndAtomics = available.fragmentStoresAndAtomics;
device_features.sampleRateShading = available_features.sampleRateShading; vk_features.sampleRateShading = available.sampleRateShading;
device_features.largePoints = available_features.largePoints; vk_features.largePoints = available.largePoints;
device_features.shaderStorageImageMultisample = available_features.shaderStorageImageMultisample; vk_features.shaderStorageImageMultisample = available.shaderStorageImageMultisample;
device_features.occlusionQueryPrecise = available_features.occlusionQueryPrecise; vk_features.occlusionQueryPrecise = available.occlusionQueryPrecise;
device_features.shaderClipDistance = available_features.shaderClipDistance; vk_features.shaderClipDistance = available.shaderClipDistance;
device_features.depthClamp = available_features.depthClamp; vk_features.depthClamp = available.depthClamp;
device_features.textureCompressionBC = available_features.textureCompressionBC; vk_features.textureCompressionBC = available.textureCompressionBC;
// Enable timeline semaphore support // Enable newer Vulkan features
new_features.timelineSemaphore = true; vk12_features.timelineSemaphore = true;
vk13_features.dynamicRendering = true;
dynamic_state.extendedDynamicState = true;
dynamic_state2.extendedDynamicState2 = true;
dynamic_state2.extendedDynamicState2LogicOp = true;
dynamic_state2.extendedDynamicState2PatchControlPoints = true;
// Include features in device creation
features.setFeatures(vk_features);
features.setPNext(&vk12_features);
vk12_features.setPNext(&vk13_features);
vk13_features.setPNext(&dynamic_state);
dynamic_state.setPNext(&dynamic_state2);
return true; return true;
} }
bool VKInstance::FindExtensions() bool VKInstance::FindExtensions()
{ {
auto extensions = physical_device.enumerateDeviceExtensionProperties(); auto available = physical_device.enumerateDeviceExtensionProperties();
if (extensions.empty()) { if (available.empty()) {
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device."); LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
return false; return false;
} }
// List available device extensions // List available device extensions
for (const auto& prop : extensions) { for (const auto& prop : available) {
LOG_INFO(Render_Vulkan, "Vulkan extension: {}", prop.extensionName); LOG_INFO(Render_Vulkan, "Vulkan extension: {}", prop.extensionName);
} }
// Helper lambda for adding extensions // Helper lambda for adding extensions
auto AddExtension = [&](const char* name, bool required) { auto AddExtension = [&](const char* name, bool required) {
auto result = std::find_if(extensions.begin(), extensions.end(), [&](const auto& prop) { auto result = std::find_if(available.begin(), available.end(), [&](const auto& prop) {
return !std::strcmp(name, prop.extensionName); return !std::strcmp(name, prop.extensionName);
}); });
if (result != extensions.end()) { if (result != available.end()) {
LOG_INFO(Render_Vulkan, "Enabling extension: {}", name); LOG_INFO(Render_Vulkan, "Enabling extension: {}", name);
device_extensions.push_back(name); extensions.push_back(name);
return true; return true;
} }
@ -172,13 +184,14 @@ bool VKInstance::FindExtensions()
return false; return false;
}; };
// The swapchain extension is required // Add required extensions
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_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, true) ||
!AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, true)) {
return false; return false;
} }
// Add more extensions in the future...
return true; return true;
} }

View File

@ -52,10 +52,16 @@ public:
vk::UniqueDevice device; vk::UniqueDevice device;
// Extensions and features // Extensions and features
std::vector<const char*> device_extensions; std::vector<const char*> extensions;
vk::PhysicalDeviceFeatures device_features{}; vk::PhysicalDeviceFeatures2 features{};
vk::PhysicalDeviceVulkan12Features new_features{};
vk::PhysicalDeviceLimits device_limits; vk::PhysicalDeviceLimits device_limits;
// Features per vulkan version
vk::PhysicalDeviceFeatures vk_features{};
vk::PhysicalDeviceVulkan12Features vk12_features{};
vk::PhysicalDeviceVulkan13Features vk13_features{};
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state{};
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2{};
}; };
extern std::unique_ptr<VKInstance> g_vk_instace; extern std::unique_ptr<VKInstance> g_vk_instace;

View File

@ -314,13 +314,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
uniform_block_data.dirty = true; uniform_block_data.dirty = true;
} }
bool need_duplicate_texture = false;
auto CheckBarrier = [&need_duplicate_texture, &color_surface](VKTexture* handle) {
if (color_surface && &color_surface->texture == handle) {
need_duplicate_texture = true;
}
};
// Sync and bind the texture surfaces // Sync and bind the texture surfaces
const auto pica_textures = regs.texturing.GetTextures(); const auto pica_textures = regs.texturing.GetTextures();
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
@ -367,11 +360,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
vk::Extent2D(draw_rect.GetHeight(), draw_rect.GetHeight())); vk::Extent2D(draw_rect.GetHeight(), draw_rect.GetHeight()));
state.SetScissor(scissor); state.SetScissor(scissor);
// Draw the vertex batch // Apply pending state
bool succeeded = true;
shader_program_manager->UseTrivialVertexShader();
shader_program_manager->UseTrivialGeometryShader();
shader_program_manager->ApplyTo(state);
state.Apply(); state.Apply();
std::size_t max_vertices = 3 * (VERTEX_BUFFER_SIZE / (3 * sizeof(HardwareVertex))); std::size_t max_vertices = 3 * (VERTEX_BUFFER_SIZE / (3 * sizeof(HardwareVertex)));
@ -431,7 +420,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
depth_surface); depth_surface);
} }
return succeeded; return true;
} }
void RasterizerVulkan::NotifyPicaRegisterChanged(u32 id) { void RasterizerVulkan::NotifyPicaRegisterChanged(u32 id) {
@ -1141,11 +1130,11 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
void RasterizerVulkan::SetShader() { void RasterizerVulkan::SetShader() {
shader_program_manager->UseFragmentShader(Pica::g_state.regs); state.SetFragmentShader(Pica::g_state.regs);
} }
void RasterizerVulkan::SyncClipEnabled() { void RasterizerVulkan::SyncClipEnabled() {
state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0; //state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0;
} }
void RasterizerVulkan::SyncClipCoef() { void RasterizerVulkan::SyncClipCoef() {

View File

@ -31,7 +31,6 @@ class EmuWindow;
} }
namespace Vulkan { namespace Vulkan {
class ShaderProgramManager;
enum class UniformBindings : u32 { Common, VS, GS }; enum class UniformBindings : u32 { Common, VS, GS };
@ -112,6 +111,65 @@ static_assert(sizeof(VSUniformData) < 16384,
struct ScreenInfo; struct ScreenInfo;
struct VertexBase {
VertexBase() = default;
VertexBase(const Pica::Shader::OutputVertex& v, bool flip_quaternion) {
position[0] = v.pos.x.ToFloat32();
position[1] = v.pos.y.ToFloat32();
position[2] = v.pos.z.ToFloat32();
position[3] = v.pos.w.ToFloat32();
color[0] = v.color.x.ToFloat32();
color[1] = v.color.y.ToFloat32();
color[2] = v.color.z.ToFloat32();
color[3] = v.color.w.ToFloat32();
tex_coord0[0] = v.tc0.x.ToFloat32();
tex_coord0[1] = v.tc0.y.ToFloat32();
tex_coord1[0] = v.tc1.x.ToFloat32();
tex_coord1[1] = v.tc1.y.ToFloat32();
tex_coord2[0] = v.tc2.x.ToFloat32();
tex_coord2[1] = v.tc2.y.ToFloat32();
tex_coord0_w = v.tc0_w.ToFloat32();
normquat[0] = v.quat.x.ToFloat32();
normquat[1] = v.quat.y.ToFloat32();
normquat[2] = v.quat.z.ToFloat32();
normquat[3] = v.quat.w.ToFloat32();
view[0] = v.view.x.ToFloat32();
view[1] = v.view.y.ToFloat32();
view[2] = v.view.z.ToFloat32();
if (flip_quaternion) {
normquat = -normquat;
}
}
glm::vec4 position;
glm::vec4 color;
glm::vec2 tex_coord0;
glm::vec2 tex_coord1;
glm::vec2 tex_coord2;
float tex_coord0_w;
glm::vec4 normquat;
glm::vec3 view;
};
/// Structure that the hardware rendered vertices are composed of
struct HardwareVertex : public VertexBase {
HardwareVertex() = default;
HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) : VertexBase(v, flip_quaternion) {};
static constexpr auto binding_desc = vk::VertexInputBindingDescription(0, sizeof(VertexBase));
static constexpr std::array<vk::VertexInputAttributeDescription, 8> attribute_desc =
{
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, position)),
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, color)),
vk::VertexInputAttributeDescription(2, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord0)),
vk::VertexInputAttributeDescription(3, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord1)),
vk::VertexInputAttributeDescription(4, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord2)),
vk::VertexInputAttributeDescription(5, 0, vk::Format::eR32Sfloat, offsetof(VertexBase, tex_coord0_w)),
vk::VertexInputAttributeDescription(6, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, normquat)),
vk::VertexInputAttributeDescription(7, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexBase, view)),
};
};
class RasterizerVulkan : public VideoCore::RasterizerInterface { class RasterizerVulkan : public VideoCore::RasterizerInterface {
public: public:
explicit RasterizerVulkan(Frontend::EmuWindow& emu_window); explicit RasterizerVulkan(Frontend::EmuWindow& emu_window);
@ -140,68 +198,6 @@ public:
void SyncEntireState() override; void SyncEntireState() override;
private: private:
struct VertexBase
{
VertexBase() = default;
VertexBase(const Pica::Shader::OutputVertex& v, bool flip_quaternion) {
position[0] = v.pos.x.ToFloat32();
position[1] = v.pos.y.ToFloat32();
position[2] = v.pos.z.ToFloat32();
position[3] = v.pos.w.ToFloat32();
color[0] = v.color.x.ToFloat32();
color[1] = v.color.y.ToFloat32();
color[2] = v.color.z.ToFloat32();
color[3] = v.color.w.ToFloat32();
tex_coord0[0] = v.tc0.x.ToFloat32();
tex_coord0[1] = v.tc0.y.ToFloat32();
tex_coord1[0] = v.tc1.x.ToFloat32();
tex_coord1[1] = v.tc1.y.ToFloat32();
tex_coord2[0] = v.tc2.x.ToFloat32();
tex_coord2[1] = v.tc2.y.ToFloat32();
tex_coord0_w = v.tc0_w.ToFloat32();
normquat[0] = v.quat.x.ToFloat32();
normquat[1] = v.quat.y.ToFloat32();
normquat[2] = v.quat.z.ToFloat32();
normquat[3] = v.quat.w.ToFloat32();
view[0] = v.view.x.ToFloat32();
view[1] = v.view.y.ToFloat32();
view[2] = v.view.z.ToFloat32();
if (flip_quaternion) {
normquat = -normquat;
}
}
glm::vec4 position;
glm::vec4 color;
glm::vec2 tex_coord0;
glm::vec2 tex_coord1;
glm::vec2 tex_coord2;
float tex_coord0_w;
glm::vec4 normquat;
glm::vec3 view;
};
/// Structure that the hardware rendered vertices are composed of
struct HardwareVertex : public VertexBase
{
HardwareVertex() = default;
HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) : VertexBase(v, flip_quaternion) {};
static constexpr auto binding_desc = vk::VertexInputBindingDescription(0, sizeof(VertexBase));
static constexpr std::array<vk::VertexInputAttributeDescription, 8> attribute_desc =
{
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, position)),
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, color)),
vk::VertexInputAttributeDescription(2, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord0)),
vk::VertexInputAttributeDescription(3, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord1)),
vk::VertexInputAttributeDescription(4, 0, vk::Format::eR32G32Sfloat, offsetof(VertexBase, tex_coord2)),
vk::VertexInputAttributeDescription(5, 0, vk::Format::eR32Sfloat, offsetof(VertexBase, tex_coord0_w)),
vk::VertexInputAttributeDescription(6, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(VertexBase, normquat)),
vk::VertexInputAttributeDescription(7, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexBase, view)),
};
};
/// Syncs the clip enabled status to match the PICA register /// Syncs the clip enabled status to match the PICA register
void SyncClipEnabled(); void SyncClipEnabled();
@ -337,8 +333,6 @@ private:
bool dirty; bool dirty;
} uniform_block_data = {}; } uniform_block_data = {};
std::unique_ptr<ShaderProgramManager> shader_program_manager;
// They shall be big enough for about one frame. // They shall be big enough for about one frame.
static constexpr std::size_t VERTEX_BUFFER_SIZE = 16 * 1024 * 1024; static constexpr std::size_t VERTEX_BUFFER_SIZE = 16 * 1024 * 1024;
static constexpr std::size_t INDEX_BUFFER_SIZE = 1 * 1024 * 1024; static constexpr std::size_t INDEX_BUFFER_SIZE = 1 * 1024 * 1024;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstring>
#include <functional>
#include <optional>
#include <string>
#include <type_traits>
#include "common/hash.h"
#include "video_core/regs.h"
#include "video_core/shader/shader.h"
#include "video_core/renderer_vulkan/vk_shader_state.h"
namespace Vulkan {
namespace ShaderDecompiler {
struct ProgramResult {
std::string code;
};
}
/**
* Generates the GLSL vertex shader program source code that accepts vertices from software shader
* and directly passes them to the fragment shader.
* @param separable_shader generates shader that can be used for separate shader object
* @returns String of the shader source code
*/
ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader);
/**
* Generates the GLSL fragment shader program source code for the current Pica state
* @param config ShaderCacheKey object generated for the current Pica state, used for the shader
* configuration (NOTE: Use state in this struct only, not the Pica registers!)
* @param separable_shader generates shader that can be used for separate shader object
* @returns String of the shader source code
*/
ShaderDecompiler::ProgramResult GenerateFragmentShader(const PicaFSConfig& config);
} // namespace Vulkan

View File

@ -10,6 +10,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <vulkan/vulkan.hpp>
#include "common/hash.h" #include "common/hash.h"
#include "video_core/regs.h" #include "video_core/regs.h"
#include "video_core/shader/shader.h" #include "video_core/shader/shader.h"
@ -198,17 +199,14 @@ struct PicaFixedGSConfig : Common::HashableStruct<PicaGSConfigCommonRaw> {
} }
}; };
/** struct PipelineCacheKey {
* This struct combines the vertex and fragment states for a complete pipeline cache key vk::PipelineColorBlendAttachmentState blend_config;
*/
struct VKPipelineCacheKey {
VKPipelineCacheKey(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup) :
vertex_config(regs.vs, setup), geometry_config(regs),
fragment_config(PicaFSConfig::BuildFromRegs(regs)) {}
PicaVSConfig vertex_config;
PicaFixedGSConfig geometry_config;
PicaFSConfig fragment_config; PicaFSConfig fragment_config;
u64 Hash() const {
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(PipelineCacheKey));
return static_cast<size_t>(hash);
}
}; };
} // namespace Vulkan } // namespace Vulkan
@ -234,4 +232,11 @@ struct hash<Vulkan::PicaFixedGSConfig> {
return k.Hash(); return k.Hash();
} }
}; };
template <>
struct hash<Vulkan::PipelineCacheKey> {
size_t operator()(const Vulkan::PipelineCacheKey& k) const noexcept {
return k.Hash();
}
};
} // namespace std } // namespace std

View File

@ -7,8 +7,8 @@
#include "video_core/renderer_vulkan/vk_state.h" #include "video_core/renderer_vulkan/vk_state.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
#include "video_core/renderer_vulkan/vk_resource_cache.h" #include "video_core/renderer_vulkan/vk_resource_cache.h"
#include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_shader_gen.h"
namespace Vulkan { namespace Vulkan {
@ -67,20 +67,57 @@ void VulkanState::Create() {
// Create texture sampler // Create texture sampler
auto props = g_vk_instace->GetPhysicalDevice().getProperties(); auto props = g_vk_instace->GetPhysicalDevice().getProperties();
vk::SamplerCreateInfo sampler_info vk::SamplerCreateInfo sampler_info{
(
{}, vk::Filter::eNearest, vk::Filter::eNearest, {}, vk::Filter::eNearest, vk::Filter::eNearest,
vk::SamplerMipmapMode::eNearest, vk::SamplerAddressMode::eClampToEdge, vk::SamplerMipmapMode::eNearest, vk::SamplerAddressMode::eClampToEdge,
vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge,
{}, true, props.limits.maxSamplerAnisotropy, {}, true, props.limits.maxSamplerAnisotropy,
false, vk::CompareOp::eAlways, {}, {}, false, vk::CompareOp::eAlways, {}, {},
vk::BorderColor::eIntOpaqueBlack, false vk::BorderColor::eIntOpaqueBlack, false
); };
sampler = g_vk_instace->GetDevice().createSamplerUnique(sampler_info); sampler = g_vk_instace->GetDevice().createSamplerUnique(sampler_info);
dirty_flags |= DirtyFlags::All;
CompileTrivialShader();
// Define the descriptor sets we will be using
std::array<vk::DescriptorSetLayoutBinding, 2> ubo_set = {{
{ 0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex |
vk::ShaderStageFlagBits::eGeometry | vk::ShaderStageFlagBits::eFragment }, // shader_data
{ 1, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex } // pica_uniforms
}};
std::array<vk::DescriptorSetLayoutBinding, 4> texture_set = {{
{ 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment }, // tex0
{ 1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment }, // tex1
{ 2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment }, // tex2
{ 3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment }, // tex_cube
}};
std::array<vk::DescriptorSetLayoutBinding, 3> lut_set = {{
{ 0, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment }, // texture_buffer_lut_lf
{ 1, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment }, // texture_buffer_lut_rg
{ 2, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment } // texture_buffer_lut_rgba
}};
// Create and store descriptor set layouts
std::array<vk::DescriptorSetLayoutCreateInfo, DESCRIPTOR_SET_LAYOUT_COUNT> create_infos = {{
{ vk::DescriptorSetLayoutCreateFlags(), ubo_set },
{ vk::DescriptorSetLayoutCreateFlags(), texture_set },
{ vk::DescriptorSetLayoutCreateFlags(), lut_set }
}};
for (int i = 0; i < DESCRIPTOR_SET_LAYOUT_COUNT; i++) {
descriptor_layouts[i] = g_vk_instace->GetDevice().createDescriptorSetLayout(create_infos[i]);
}
// Create the standard descriptor set layout
vk::PipelineLayoutCreateInfo layout_info({}, descriptor_layouts);
pipeline_layout = g_vk_instace->GetDevice().createPipelineLayoutUnique(layout_info);
// Compile trivial vertex shader
auto source = GenerateTrivialVertexShader(true);
MakeShader(source.code, vk::ShaderStageFlagBits::eVertex);
dirty_flags |= DirtyFlags::All;
} }
void VulkanState::SetVertexBuffer(VKBuffer* buffer, vk::DeviceSize offset) { void VulkanState::SetVertexBuffer(VKBuffer* buffer, vk::DeviceSize offset) {
@ -231,11 +268,11 @@ void VulkanState::SetLogicOp(vk::LogicOp new_logic_op) {
void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) { void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) {
auto mask = static_cast<vk::ColorComponentFlags>(red | (green << 1) | (blue << 2) | (alpha << 3)); auto mask = static_cast<vk::ColorComponentFlags>(red | (green << 1) | (blue << 2) | (alpha << 3));
static_state.blend.setColorWriteMask(mask); pipeline_key.blend_config.setColorWriteMask(mask);
} }
void VulkanState::SetBlendEnable(bool enable) { void VulkanState::SetBlendEnable(bool enable) {
static_state.blend.setBlendEnable(enable); pipeline_key.blend_config.setBlendEnable(enable);
} }
void VulkanState::SetBlendCostants(float red, float green, float blue, float alpha) { void VulkanState::SetBlendCostants(float red, float green, float blue, float alpha) {
@ -286,7 +323,7 @@ void VulkanState::SetDepthTest(bool enable, vk::CompareOp compare) {
void VulkanState::SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::BlendFactor src_color, void VulkanState::SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::BlendFactor src_color,
vk::BlendFactor dst_color, vk::BlendFactor src_alpha, vk::BlendFactor dst_alpha) { vk::BlendFactor dst_color, vk::BlendFactor src_alpha, vk::BlendFactor dst_alpha) {
auto& blend = static_state.blend; auto& blend = pipeline_key.blend_config;
blend.setColorBlendOp(rgb_op); blend.setColorBlendOp(rgb_op);
blend.setAlphaBlendOp(alpha_op); blend.setAlphaBlendOp(alpha_op);
blend.setSrcColorBlendFactor(src_color); blend.setSrcColorBlendFactor(src_color);
@ -295,6 +332,136 @@ void VulkanState::SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::Blend
blend.setDstAlphaBlendFactor(dst_alpha); blend.setDstAlphaBlendFactor(dst_alpha);
} }
void VulkanState::SetFragmentShader(const Pica::Regs& regs) {
vk::Pipeline pipeline;
pipeline_key.fragment_config = PicaFSConfig::BuildFromRegs(regs);
auto it1 = pipelines.find(pipeline_key);
do {
// Try to use an already complete pipeline
if (it1 != pipelines.end()) {
pipeline = it1->second.get();
break;
}
// Maybe the shader has been compiled but the pipeline state changed?
auto shader = fragment_shaders.find(pipeline_key.fragment_config);
if (shader != fragment_shaders.end()) {
pipeline = MakePipeline(shader->second.get());
break;
}
// Re-compile shader module and create new pipeline
auto result = GenerateFragmentShader(pipeline_key.fragment_config);
auto module = MakeShader(result.code, vk::ShaderStageFlagBits::eFragment);
pipeline = MakePipeline(module);
} while (false);
// Bind the pipeline
auto command_buffer = g_vk_task_scheduler->GetCommandBuffer();
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
}
vk::ShaderModule VulkanState::MakeShader(const std::string& source, vk::ShaderStageFlagBits stage) {
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.SetOptimizationLevel(shaderc_optimization_level_performance);
options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2);
shaderc_shader_kind kind{};
std::string name{};
switch (stage) {
case vk::ShaderStageFlagBits::eVertex:
kind = shaderc_glsl_vertex_shader;
name = "vertex shader";
break;
case vk::ShaderStageFlagBits::eFragment:
kind = shaderc_glsl_fragment_shader;
name = "fragment shader";
break;
default:
LOG_CRITICAL(Render_Vulkan, "Unknown shader stage");
UNREACHABLE();
}
auto shader_module = compiler.CompileGlslToSpv(source.data(), kind, name.c_str(), options);
if (shader_module.GetCompilationStatus() != shaderc_compilation_status_success) {
LOG_CRITICAL(Render_Vulkan, shader_module.GetErrorMessage().c_str());
}
auto shader_code = std::vector<u32>{shader_module.cbegin(), shader_module.cend()};
vk::ShaderModuleCreateInfo shader_info{{}, shader_code};
auto& device = g_vk_instace->GetDevice();
auto shader = device.createShaderModuleUnique(shader_info);
if (stage == vk::ShaderStageFlagBits::eFragment) {
auto handle = shader.get();
fragment_shaders[pipeline_key.fragment_config] = std::move(shader);
return handle;
}
else if (stage == vk::ShaderStageFlagBits::eVertex) {
trivial_vertex_shader = std::move(shader);
return trivial_vertex_shader.get();
}
UNREACHABLE();
}
vk::Pipeline VulkanState::MakePipeline(vk::ShaderModule fragment) {
std::array<vk::PipelineShaderStageCreateInfo, 2> shader_stages {{
{ {}, vk::ShaderStageFlagBits::eVertex, trivial_vertex_shader.get(), "main" },
{ {}, vk::ShaderStageFlagBits::eFragment, fragment, "main" }
}};
vk::PipelineVertexInputStateCreateInfo vertex_input_info{
{}, HardwareVertex::binding_desc, HardwareVertex::attribute_desc
};
vk::PipelineInputAssemblyStateCreateInfo input_assembly{{}, vk::PrimitiveTopology::eTriangleList, false};
vk::PipelineRasterizationStateCreateInfo rasterizer{
{}, false, false, vk::PolygonMode::eFill, vk::CullModeFlagBits::eNone,
vk::FrontFace::eClockwise, false
};
vk::PipelineMultisampleStateCreateInfo multisampling{{}, vk::SampleCountFlagBits::e1};
vk::PipelineColorBlendStateCreateInfo color_blending{{}, false, vk::LogicOp::eCopy, pipeline_key.blend_config};
// Enable every required dynamic state
std::array<vk::DynamicState, 14> dynamic_states{
vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth,
vk::DynamicState::eDepthTestEnable, vk::DynamicState::eColorWriteEnableEXT,
vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilOp,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
vk::DynamicState::eCullMode, vk::DynamicState::eBlendConstants,
vk::DynamicState::eViewport, vk::DynamicState::eScissor,
vk::DynamicState::eLogicOpEXT, vk::DynamicState::eFrontFace
};
vk::PipelineDynamicStateCreateInfo dynamic_info{{}, dynamic_states};
vk::PipelineDepthStencilStateCreateInfo depth_info{
{}, true, true, vk::CompareOp::eGreaterOrEqual, false, true
};
vk::GraphicsPipelineCreateInfo pipeline_info{
{}, shader_stages, &vertex_input_info, &input_assembly, nullptr, nullptr,
&rasterizer, &multisampling, &depth_info, &color_blending, &dynamic_info,
pipeline_layout.get(), nullptr
};
auto& device = g_vk_instace->GetDevice();
auto result = device.createGraphicsPipelineUnique(nullptr, pipeline_info);
if (result.result == vk::Result::eSuccess) {
auto handle = result.value.get();
pipelines[pipeline_key] = std::move(result.value);
return handle;
}
return VK_NULL_HANDLE;
}
void VulkanState::Apply() { void VulkanState::Apply() {
// Update resources in descriptor sets if changed // Update resources in descriptor sets if changed
UpdateDescriptorSet(); UpdateDescriptorSet();
@ -372,24 +539,4 @@ void VulkanState::UpdateDescriptorSet() {
} }
} }
void VulkanState::CompileTrivialShader() {
auto source = OpenGL::GenerateTrivialVertexShader(true);
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.SetOptimizationLevel(shaderc_optimization_level_performance);
options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2);
auto shader_module = compiler.CompileGlslToSpv(source.code, shaderc_glsl_vertex_shader, "vertex shader", options);
if (shader_module.GetCompilationStatus() != shaderc_compilation_status_success) {
LOG_CRITICAL(Render_Vulkan, shader_module.GetErrorMessage().c_str());
}
auto shader_code = std::vector<u32>{ shader_module.cbegin(), shader_module.cend() };
vk::ShaderModuleCreateInfo shader_info { {}, shader_code };
auto& device = g_vk_instace->GetDevice();
trivial_vertex_shader = device.createShaderModuleUnique(shader_info);
}
} // namespace Vulkan } // namespace Vulkan

View File

@ -6,6 +6,9 @@
#include <array> #include <array>
#include <variant> #include <variant>
#include <xxhash.h>
#include "video_core/regs.h"
#include "video_core/renderer_vulkan/vk_shader_state.h"
#include "video_core/renderer_vulkan/vk_texture.h" #include "video_core/renderer_vulkan/vk_texture.h"
namespace Vulkan { namespace Vulkan {
@ -87,6 +90,7 @@ public:
void PushRenderTargets(VKTexture* color, VKTexture* depth_stencil); void PushRenderTargets(VKTexture* color, VKTexture* depth_stencil);
void PopRenderTargets(); void PopRenderTargets();
void SetRenderArea(vk::Rect2D render_area); void SetRenderArea(vk::Rect2D render_area);
void SetFragmentShader(const Pica::Regs& config);
void BeginRendering(); void BeginRendering();
void EndRendering(); void EndRendering();
@ -102,8 +106,8 @@ public:
private: private:
void UpdateDescriptorSet(); void UpdateDescriptorSet();
void GetPipeline(); vk::Pipeline MakePipeline(vk::ShaderModule fragment);
void CompileTrivialShader(); vk::ShaderModule MakeShader(const std::string& source, vk::ShaderStageFlagBits stage);
private: private:
struct Binding { struct Binding {
@ -145,13 +149,14 @@ private:
vk::StencilOp fail_op, pass_op, depth_fail_op; vk::StencilOp fail_op, pass_op, depth_fail_op;
vk::CompareOp compare_op; vk::CompareOp compare_op;
struct {
vk::PipelineColorBlendAttachmentState blend;
vk::PipelineDepthStencilStateCreateInfo depth_stencil;
} static_state;
// Pipeline cache // Pipeline cache
vk::UniqueShaderModule trivial_vertex_shader; vk::UniqueShaderModule trivial_vertex_shader;
vk::UniquePipelineLayout pipeline_layout;
std::vector<vk::DescriptorSetLayout> descriptor_layouts;
PipelineCacheKey pipeline_key;
std::unordered_map<PicaFSConfig, vk::UniqueShaderModule> fragment_shaders;
std::unordered_map<PipelineCacheKey, vk::UniquePipeline> pipelines;
}; };
} // namespace Vulkan } // namespace Vulkan