renderer_vulkan: Add very basic pipeline and shader cache
This commit is contained in:
@ -82,6 +82,8 @@ add_library(video_core STATIC
|
||||
renderer_vulkan/vk_rasterizer.cpp
|
||||
renderer_vulkan/vk_rasterizer.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.h
|
||||
renderer_vulkan/vk_surface_params.cpp
|
||||
|
@ -29,24 +29,12 @@
|
||||
#include "core/tracer/recorder.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/renderer_opengl/post_processing_opengl.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
#include "video_core/renderer_vulkan/vk_state.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
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 {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
@ -371,13 +359,13 @@ RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
|
||||
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_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128));
|
||||
|
||||
/// Swap buffers (render frame)
|
||||
void RendererOpenGL::SwapBuffers() {
|
||||
void RendererVulkan::SwapBuffers() {
|
||||
// Maintain the rasterizer's state as a priority
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
state.Apply();
|
||||
@ -415,7 +403,7 @@ void RendererOpenGL::SwapBuffers() {
|
||||
}
|
||||
}
|
||||
|
||||
void RendererOpenGL::RenderScreenshot() {
|
||||
void RendererVulkan::RenderScreenshot() {
|
||||
if (VideoCore::g_renderer_screenshot_requested) {
|
||||
// Draw this frame to the screenshot framebuffer
|
||||
screenshot_framebuffer.Create();
|
||||
@ -449,7 +437,7 @@ void RendererOpenGL::RenderScreenshot() {
|
||||
}
|
||||
}
|
||||
|
||||
void RendererOpenGL::PrepareRendertarget() {
|
||||
void RendererVulkan::PrepareRendertarget() {
|
||||
for (int i : {0, 1, 2}) {
|
||||
int fb_id = i == 2 ? 1 : 0;
|
||||
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,
|
||||
bool flipped) {
|
||||
|
||||
@ -540,7 +528,7 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
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
|
||||
* 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) {
|
||||
state.texture_units[0].texture_2d = texture.resource.handle;
|
||||
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.
|
||||
*/
|
||||
void RendererOpenGL::InitOpenGLObjects() {
|
||||
void RendererVulkan::InitOpenGLObjects() {
|
||||
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
|
||||
0.0f);
|
||||
|
||||
@ -672,7 +660,7 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
void RendererOpenGL::ReloadSampler() {
|
||||
void RendererVulkan::ReloadSampler() {
|
||||
glSamplerParameteri(filter_sampler.handle, GL_TEXTURE_MIN_FILTER,
|
||||
Settings::values.filter_mode ? GL_LINEAR : GL_NEAREST);
|
||||
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);
|
||||
}
|
||||
|
||||
void RendererOpenGL::ReloadShader() {
|
||||
void RendererVulkan::ReloadShader() {
|
||||
// Link shaders and get variable locations
|
||||
std::string shader_data;
|
||||
if (GLES) {
|
||||
@ -754,7 +742,7 @@ void RendererOpenGL::ReloadShader() {
|
||||
attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
|
||||
}
|
||||
|
||||
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
const GPU::Regs::FramebufferConfig& framebuffer) {
|
||||
GPU::Regs::PixelFormat format = framebuffer.color_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
|
||||
* 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) {
|
||||
const auto& texcoords = screen_info.display_texcoords;
|
||||
|
||||
@ -851,7 +839,7 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
|
||||
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) {
|
||||
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
|
||||
* rotation.
|
||||
*/
|
||||
void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
|
||||
void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x,
|
||||
float y, float w, float h) {
|
||||
const auto& texcoords = screen_info_l.display_texcoords;
|
||||
@ -919,7 +907,7 @@ void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info
|
||||
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,
|
||||
float w, float h) {
|
||||
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.
|
||||
*/
|
||||
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)) {
|
||||
// Update background color before drawing
|
||||
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();
|
||||
auto frame = render_window.mailbox->TryGetPresentFrame(timeout_ms);
|
||||
if (!frame) {
|
||||
@ -1164,9 +1152,9 @@ void RendererOpenGL::TryPresent(int timeout_ms) {
|
||||
}
|
||||
|
||||
/// Updates the framerate
|
||||
void RendererOpenGL::UpdateFramerate() {}
|
||||
void RendererVulkan::UpdateFramerate() {}
|
||||
|
||||
void RendererOpenGL::PrepareVideoDumping() {
|
||||
void RendererVulkan::PrepareVideoDumping() {
|
||||
auto* mailbox = static_cast<OGLVideoDumpingMailbox*>(frame_dumper.mailbox.get());
|
||||
{
|
||||
std::unique_lock lock(mailbox->swap_chain_lock);
|
||||
@ -1175,7 +1163,7 @@ void RendererOpenGL::PrepareVideoDumping() {
|
||||
frame_dumper.StartDumping();
|
||||
}
|
||||
|
||||
void RendererOpenGL::CleanupVideoDumping() {
|
||||
void RendererVulkan::CleanupVideoDumping() {
|
||||
frame_dumper.StopDumping();
|
||||
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
|
||||
VideoCore::ResultStatus RendererOpenGL::Init() {
|
||||
VideoCore::ResultStatus RendererVulkan::Init() {
|
||||
#ifndef ANDROID
|
||||
if (!gladLoadGL()) {
|
||||
return VideoCore::ResultStatus::ErrorBelowGL33;
|
||||
@ -1284,6 +1272,6 @@ VideoCore::ResultStatus RendererOpenGL::Init() {
|
||||
}
|
||||
|
||||
/// Shutdown the renderer
|
||||
void RendererOpenGL::ShutDown() {}
|
||||
void RendererVulkan::ShutDown() {}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -62,8 +62,7 @@ private:
|
||||
void RenderScreenshot();
|
||||
void RenderToMailbox(const Layout::FramebufferLayout& layout,
|
||||
std::unique_ptr<Frontend::TextureMailbox>& mailbox, bool flipped);
|
||||
void ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
const GPU::Regs::FramebufferConfig& framebuffer);
|
||||
void ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer);
|
||||
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
|
||||
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);
|
||||
@ -78,7 +77,7 @@ private:
|
||||
void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
|
||||
ScreenInfo& screen_info, bool right_eye);
|
||||
// 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;
|
||||
|
||||
|
@ -113,55 +113,67 @@ bool VKInstance::CreateDevice(vk::SurfaceKHR surface, bool validation_enabled) {
|
||||
|
||||
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.
|
||||
if (!available_features.geometryShader && !available_features.wideLines) {
|
||||
if (!available.geometryShader && !available.wideLines) {
|
||||
LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Rendering will be limited");
|
||||
}
|
||||
|
||||
// Enable some common features other emulators like Dolphin use
|
||||
device_features.dualSrcBlend = available_features.dualSrcBlend;
|
||||
device_features.geometryShader = available_features.geometryShader;
|
||||
device_features.samplerAnisotropy = available_features.samplerAnisotropy;
|
||||
device_features.logicOp = available_features.logicOp;
|
||||
device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
|
||||
device_features.sampleRateShading = available_features.sampleRateShading;
|
||||
device_features.largePoints = available_features.largePoints;
|
||||
device_features.shaderStorageImageMultisample = available_features.shaderStorageImageMultisample;
|
||||
device_features.occlusionQueryPrecise = available_features.occlusionQueryPrecise;
|
||||
device_features.shaderClipDistance = available_features.shaderClipDistance;
|
||||
device_features.depthClamp = available_features.depthClamp;
|
||||
device_features.textureCompressionBC = available_features.textureCompressionBC;
|
||||
vk_features.dualSrcBlend = available.dualSrcBlend;
|
||||
vk_features.geometryShader = available.geometryShader;
|
||||
vk_features.samplerAnisotropy = available.samplerAnisotropy;
|
||||
vk_features.logicOp = available.logicOp;
|
||||
vk_features.fragmentStoresAndAtomics = available.fragmentStoresAndAtomics;
|
||||
vk_features.sampleRateShading = available.sampleRateShading;
|
||||
vk_features.largePoints = available.largePoints;
|
||||
vk_features.shaderStorageImageMultisample = available.shaderStorageImageMultisample;
|
||||
vk_features.occlusionQueryPrecise = available.occlusionQueryPrecise;
|
||||
vk_features.shaderClipDistance = available.shaderClipDistance;
|
||||
vk_features.depthClamp = available.depthClamp;
|
||||
vk_features.textureCompressionBC = available.textureCompressionBC;
|
||||
|
||||
// Enable timeline semaphore support
|
||||
new_features.timelineSemaphore = true;
|
||||
// Enable newer Vulkan features
|
||||
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;
|
||||
}
|
||||
|
||||
bool VKInstance::FindExtensions()
|
||||
{
|
||||
auto extensions = physical_device.enumerateDeviceExtensionProperties();
|
||||
if (extensions.empty()) {
|
||||
auto available = physical_device.enumerateDeviceExtensionProperties();
|
||||
if (available.empty()) {
|
||||
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// List available device extensions
|
||||
for (const auto& prop : extensions) {
|
||||
for (const auto& prop : available) {
|
||||
LOG_INFO(Render_Vulkan, "Vulkan extension: {}", prop.extensionName);
|
||||
}
|
||||
|
||||
// Helper lambda for adding extensions
|
||||
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);
|
||||
});
|
||||
|
||||
if (result != extensions.end()) {
|
||||
if (result != available.end()) {
|
||||
LOG_INFO(Render_Vulkan, "Enabling extension: {}", name);
|
||||
device_extensions.push_back(name);
|
||||
extensions.push_back(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -172,13 +184,14 @@ bool VKInstance::FindExtensions()
|
||||
return false;
|
||||
};
|
||||
|
||||
// The swapchain extension is required
|
||||
if (!AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true)) {
|
||||
// Add required extensions
|
||||
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;
|
||||
}
|
||||
|
||||
// Add more extensions in the future...
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -52,10 +52,16 @@ public:
|
||||
vk::UniqueDevice device;
|
||||
|
||||
// Extensions and features
|
||||
std::vector<const char*> device_extensions;
|
||||
vk::PhysicalDeviceFeatures device_features{};
|
||||
vk::PhysicalDeviceVulkan12Features new_features{};
|
||||
std::vector<const char*> extensions;
|
||||
vk::PhysicalDeviceFeatures2 features{};
|
||||
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;
|
||||
|
@ -314,13 +314,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
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
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
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()));
|
||||
state.SetScissor(scissor);
|
||||
|
||||
// Draw the vertex batch
|
||||
bool succeeded = true;
|
||||
shader_program_manager->UseTrivialVertexShader();
|
||||
shader_program_manager->UseTrivialGeometryShader();
|
||||
shader_program_manager->ApplyTo(state);
|
||||
// Apply pending state
|
||||
state.Apply();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RasterizerVulkan::NotifyPicaRegisterChanged(u32 id) {
|
||||
@ -1141,11 +1130,11 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
||||
|
||||
|
||||
void RasterizerVulkan::SetShader() {
|
||||
shader_program_manager->UseFragmentShader(Pica::g_state.regs);
|
||||
state.SetFragmentShader(Pica::g_state.regs);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -31,7 +31,6 @@ class EmuWindow;
|
||||
}
|
||||
|
||||
namespace Vulkan {
|
||||
class ShaderProgramManager;
|
||||
|
||||
enum class UniformBindings : u32 { Common, VS, GS };
|
||||
|
||||
@ -112,36 +111,7 @@ static_assert(sizeof(VSUniformData) < 16384,
|
||||
|
||||
struct ScreenInfo;
|
||||
|
||||
class RasterizerVulkan : public VideoCore::RasterizerInterface {
|
||||
public:
|
||||
explicit RasterizerVulkan(Frontend::EmuWindow& emu_window);
|
||||
~RasterizerVulkan() override = default;
|
||||
|
||||
void LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) override;
|
||||
|
||||
void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
|
||||
const Pica::Shader::OutputVertex& v2) override;
|
||||
void DrawTriangles() override;
|
||||
void NotifyPicaRegisterChanged(u32 id) override;
|
||||
void FlushAll() override;
|
||||
void FlushRegion(PAddr addr, u32 size) override;
|
||||
void InvalidateRegion(PAddr addr, u32 size) override;
|
||||
void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
|
||||
void ClearAll(bool flush) override;
|
||||
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
|
||||
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
|
||||
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
|
||||
bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr,
|
||||
u32 pixel_stride, Vulkan::ScreenInfo& screen_info) override;
|
||||
bool AccelerateDrawBatch(bool is_indexed) override;
|
||||
|
||||
/// Syncs entire status to match PICA registers
|
||||
void SyncEntireState() override;
|
||||
|
||||
private:
|
||||
struct VertexBase
|
||||
{
|
||||
struct VertexBase {
|
||||
VertexBase() = default;
|
||||
VertexBase(const Pica::Shader::OutputVertex& v, bool flip_quaternion) {
|
||||
position[0] = v.pos.x.ToFloat32();
|
||||
@ -180,11 +150,10 @@ private:
|
||||
float tex_coord0_w;
|
||||
glm::vec4 normquat;
|
||||
glm::vec3 view;
|
||||
};
|
||||
};
|
||||
|
||||
/// Structure that the hardware rendered vertices are composed of
|
||||
struct HardwareVertex : public VertexBase
|
||||
{
|
||||
/// 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));
|
||||
@ -199,9 +168,36 @@ private:
|
||||
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 {
|
||||
public:
|
||||
explicit RasterizerVulkan(Frontend::EmuWindow& emu_window);
|
||||
~RasterizerVulkan() override = default;
|
||||
|
||||
void LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) override;
|
||||
|
||||
void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
|
||||
const Pica::Shader::OutputVertex& v2) override;
|
||||
void DrawTriangles() override;
|
||||
void NotifyPicaRegisterChanged(u32 id) override;
|
||||
void FlushAll() override;
|
||||
void FlushRegion(PAddr addr, u32 size) override;
|
||||
void InvalidateRegion(PAddr addr, u32 size) override;
|
||||
void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
|
||||
void ClearAll(bool flush) override;
|
||||
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
|
||||
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
|
||||
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
|
||||
bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr,
|
||||
u32 pixel_stride, Vulkan::ScreenInfo& screen_info) override;
|
||||
bool AccelerateDrawBatch(bool is_indexed) override;
|
||||
|
||||
/// Syncs entire status to match PICA registers
|
||||
void SyncEntireState() override;
|
||||
|
||||
private:
|
||||
/// Syncs the clip enabled status to match the PICA register
|
||||
void SyncClipEnabled();
|
||||
|
||||
@ -337,8 +333,6 @@ private:
|
||||
bool dirty;
|
||||
} uniform_block_data = {};
|
||||
|
||||
std::unique_ptr<ShaderProgramManager> shader_program_manager;
|
||||
|
||||
// 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 INDEX_BUFFER_SIZE = 1 * 1024 * 1024;
|
||||
|
1616
src/video_core/renderer_vulkan/vk_shader_gen.cpp
Normal file
1616
src/video_core/renderer_vulkan/vk_shader_gen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
43
src/video_core/renderer_vulkan/vk_shader_gen.h
Normal file
43
src/video_core/renderer_vulkan/vk_shader_gen.h
Normal 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
|
@ -10,6 +10,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include "common/hash.h"
|
||||
#include "video_core/regs.h"
|
||||
#include "video_core/shader/shader.h"
|
||||
@ -198,17 +199,14 @@ struct PicaFixedGSConfig : Common::HashableStruct<PicaGSConfigCommonRaw> {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct combines the vertex and fragment states for a complete pipeline cache key
|
||||
*/
|
||||
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;
|
||||
struct PipelineCacheKey {
|
||||
vk::PipelineColorBlendAttachmentState blend_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
|
||||
@ -234,4 +232,11 @@ struct hash<Vulkan::PicaFixedGSConfig> {
|
||||
return k.Hash();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<Vulkan::PipelineCacheKey> {
|
||||
size_t operator()(const Vulkan::PipelineCacheKey& k) const noexcept {
|
||||
return k.Hash();
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "video_core/renderer_vulkan/vk_state.h"
|
||||
#include "video_core/renderer_vulkan/vk_task_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_resource_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||
#include "video_core/renderer_vulkan/vk_shader_gen.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
@ -67,20 +67,57 @@ void VulkanState::Create() {
|
||||
|
||||
// Create texture sampler
|
||||
auto props = g_vk_instace->GetPhysicalDevice().getProperties();
|
||||
vk::SamplerCreateInfo sampler_info
|
||||
(
|
||||
vk::SamplerCreateInfo sampler_info{
|
||||
{}, vk::Filter::eNearest, vk::Filter::eNearest,
|
||||
vk::SamplerMipmapMode::eNearest, vk::SamplerAddressMode::eClampToEdge,
|
||||
vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge,
|
||||
{}, true, props.limits.maxSamplerAnisotropy,
|
||||
false, vk::CompareOp::eAlways, {}, {},
|
||||
vk::BorderColor::eIntOpaqueBlack, false
|
||||
);
|
||||
|
||||
};
|
||||
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) {
|
||||
@ -231,11 +268,11 @@ void VulkanState::SetLogicOp(vk::LogicOp new_logic_op) {
|
||||
|
||||
void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) {
|
||||
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) {
|
||||
static_state.blend.setBlendEnable(enable);
|
||||
pipeline_key.blend_config.setBlendEnable(enable);
|
||||
}
|
||||
|
||||
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,
|
||||
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.setAlphaBlendOp(alpha_op);
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
// Update resources in descriptor sets if changed
|
||||
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
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include <array>
|
||||
#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"
|
||||
|
||||
namespace Vulkan {
|
||||
@ -87,6 +90,7 @@ public:
|
||||
void PushRenderTargets(VKTexture* color, VKTexture* depth_stencil);
|
||||
void PopRenderTargets();
|
||||
void SetRenderArea(vk::Rect2D render_area);
|
||||
void SetFragmentShader(const Pica::Regs& config);
|
||||
void BeginRendering();
|
||||
void EndRendering();
|
||||
|
||||
@ -102,8 +106,8 @@ public:
|
||||
|
||||
private:
|
||||
void UpdateDescriptorSet();
|
||||
void GetPipeline();
|
||||
void CompileTrivialShader();
|
||||
vk::Pipeline MakePipeline(vk::ShaderModule fragment);
|
||||
vk::ShaderModule MakeShader(const std::string& source, vk::ShaderStageFlagBits stage);
|
||||
|
||||
private:
|
||||
struct Binding {
|
||||
@ -145,13 +149,14 @@ private:
|
||||
vk::StencilOp fail_op, pass_op, depth_fail_op;
|
||||
vk::CompareOp compare_op;
|
||||
|
||||
struct {
|
||||
vk::PipelineColorBlendAttachmentState blend;
|
||||
vk::PipelineDepthStencilStateCreateInfo depth_stencil;
|
||||
} static_state;
|
||||
|
||||
// Pipeline cache
|
||||
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
|
||||
|
Reference in New Issue
Block a user