1 // Copyright 2020 yuzu Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <condition_variable> 8 #include <memory> 9 #include <shared_mutex> 10 #include <thread> 11 12 // This header includes both Vulkan and OpenGL headers, this has to be fixed 13 // Unfortunately, including OpenGL will include Windows.h that defines macros that can cause issues. 14 // Forcefully include glad early and undefine macros 15 #include <glad/glad.h> 16 #ifdef CreateEvent 17 #undef CreateEvent 18 #endif 19 #ifdef CreateSemaphore 20 #undef CreateSemaphore 21 #endif 22 23 #include "common/common_types.h" 24 #include "video_core/renderer_opengl/gl_device.h" 25 #include "video_core/renderer_opengl/gl_resource_manager.h" 26 #include "video_core/renderer_opengl/gl_shader_decompiler.h" 27 #include "video_core/renderer_vulkan/vk_device.h" 28 #include "video_core/renderer_vulkan/vk_pipeline_cache.h" 29 #include "video_core/renderer_vulkan/vk_scheduler.h" 30 31 namespace Core::Frontend { 32 class EmuWindow; 33 class GraphicsContext; 34 } // namespace Core::Frontend 35 36 namespace Tegra { 37 class GPU; 38 } 39 40 namespace Vulkan { 41 class VKPipelineCache; 42 } 43 44 namespace VideoCommon::Shader { 45 46 class AsyncShaders { 47 public: 48 enum class Backend { 49 OpenGL, 50 GLASM, 51 Vulkan, 52 }; 53 54 struct ResultPrograms { 55 OpenGL::OGLProgram opengl; 56 OpenGL::OGLAssemblyProgram glasm; 57 }; 58 59 struct Result { 60 u64 uid; 61 VAddr cpu_address; 62 Backend backend; 63 ResultPrograms program; 64 std::vector<u64> code; 65 std::vector<u64> code_b; 66 Tegra::Engines::ShaderType shader_type; 67 }; 68 69 explicit AsyncShaders(Core::Frontend::EmuWindow& emu_window_); 70 ~AsyncShaders(); 71 72 /// Start up shader worker threads 73 void AllocateWorkers(); 74 75 /// Clear the shader queue and kill all worker threads 76 void FreeWorkers(); 77 78 // Force end all threads 79 void KillWorkers(); 80 81 /// Check to see if any shaders have actually been compiled 82 [[nodiscard]] bool HasCompletedWork() const; 83 84 /// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build 85 /// every shader async as some shaders are only built and executed once. We try to "guess" which 86 /// shader would be used only once 87 [[nodiscard]] bool IsShaderAsync(const Tegra::GPU& gpu) const; 88 89 /// Pulls completed compiled shaders 90 [[nodiscard]] std::vector<Result> GetCompletedWork(); 91 92 void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type, 93 u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset, 94 CompilerSettings compiler_settings, const Registry& registry, 95 VAddr cpu_addr); 96 97 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device, 98 Vulkan::VKScheduler& scheduler, 99 Vulkan::VKDescriptorPool& descriptor_pool, 100 Vulkan::VKUpdateDescriptorQueue& update_descriptor_queue, 101 Vulkan::VKRenderPassCache& renderpass_cache, 102 std::vector<VkDescriptorSetLayoutBinding> bindings, 103 Vulkan::SPIRVProgram program, Vulkan::GraphicsPipelineCacheKey key); 104 105 private: 106 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context); 107 108 /// Check our worker queue to see if we have any work queued already 109 [[nodiscard]] bool HasWorkQueued() const; 110 111 struct WorkerParams { 112 Backend backend; 113 // For OGL 114 const OpenGL::Device* device; 115 Tegra::Engines::ShaderType shader_type; 116 u64 uid; 117 std::vector<u64> code; 118 std::vector<u64> code_b; 119 u32 main_offset; 120 CompilerSettings compiler_settings; 121 std::optional<Registry> registry; 122 VAddr cpu_address; 123 124 // For Vulkan 125 Vulkan::VKPipelineCache* pp_cache; 126 const Vulkan::VKDevice* vk_device; 127 Vulkan::VKScheduler* scheduler; 128 Vulkan::VKDescriptorPool* descriptor_pool; 129 Vulkan::VKUpdateDescriptorQueue* update_descriptor_queue; 130 Vulkan::VKRenderPassCache* renderpass_cache; 131 std::vector<VkDescriptorSetLayoutBinding> bindings; 132 Vulkan::SPIRVProgram program; 133 Vulkan::GraphicsPipelineCacheKey key; 134 }; 135 136 std::condition_variable cv; 137 mutable std::mutex queue_mutex; 138 mutable std::shared_mutex completed_mutex; 139 std::atomic<bool> is_thread_exiting{}; 140 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; 141 std::vector<std::thread> worker_threads; 142 std::queue<WorkerParams> pending_queue; 143 std::vector<Result> finished_work; 144 Core::Frontend::EmuWindow& emu_window; 145 }; 146 147 } // namespace VideoCommon::Shader 148