gl_device.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include <cstddef>
  6. #include <cstdlib>
  7. #include <optional>
  8. #include <span>
  9. #include <stdexcept>
  10. #include <vector>
  11. #include <glad/glad.h>
  12. #include "common/literals.h"
  13. #include "common/logging/log.h"
  14. #include "common/polyfill_ranges.h"
  15. #include "common/settings.h"
  16. #include "shader_recompiler/stage.h"
  17. #include "video_core/renderer_opengl/gl_device.h"
  18. #include "video_core/renderer_opengl/gl_resource_manager.h"
  19. using namespace Common::Literals;
  20. namespace OpenGL {
  21. namespace {
  22. constexpr std::array LIMIT_UBOS = {
  23. GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
  24. GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, GL_MAX_GEOMETRY_UNIFORM_BLOCKS,
  25. GL_MAX_FRAGMENT_UNIFORM_BLOCKS, GL_MAX_COMPUTE_UNIFORM_BLOCKS,
  26. };
  27. template <typename T>
  28. T GetInteger(GLenum pname) {
  29. GLint temporary;
  30. glGetIntegerv(pname, &temporary);
  31. return static_cast<T>(temporary);
  32. }
  33. bool TestProgram(const GLchar* glsl) {
  34. const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
  35. GLint link_status;
  36. glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
  37. glDeleteProgram(shader);
  38. return link_status == GL_TRUE;
  39. }
  40. std::vector<std::string_view> GetExtensions() {
  41. GLint num_extensions;
  42. glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
  43. std::vector<std::string_view> extensions;
  44. extensions.reserve(num_extensions);
  45. for (GLint index = 0; index < num_extensions; ++index) {
  46. extensions.push_back(
  47. reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
  48. }
  49. return extensions;
  50. }
  51. bool HasExtension(std::span<const std::string_view> extensions, std::string_view extension) {
  52. return std::ranges::find(extensions, extension) != extensions.end();
  53. }
  54. std::array<u32, Shader::MaxStageTypes> BuildMaxUniformBuffers() noexcept {
  55. std::array<u32, Shader::MaxStageTypes> max;
  56. std::ranges::transform(LIMIT_UBOS, max.begin(), &GetInteger<u32>);
  57. return max;
  58. }
  59. bool IsASTCSupported() {
  60. static constexpr std::array targets{
  61. GL_TEXTURE_2D,
  62. GL_TEXTURE_2D_ARRAY,
  63. };
  64. static constexpr std::array formats{
  65. GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
  66. GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
  67. GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
  68. GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
  69. GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
  70. GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
  71. GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
  72. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
  73. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
  74. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
  75. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
  76. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
  77. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
  78. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
  79. };
  80. static constexpr std::array required_support{
  81. GL_VERTEX_TEXTURE, GL_TESS_CONTROL_TEXTURE, GL_TESS_EVALUATION_TEXTURE,
  82. GL_GEOMETRY_TEXTURE, GL_FRAGMENT_TEXTURE, GL_COMPUTE_TEXTURE,
  83. };
  84. for (const GLenum target : targets) {
  85. for (const GLenum format : formats) {
  86. for (const GLenum support : required_support) {
  87. GLint value;
  88. glGetInternalformativ(target, format, support, 1, &value);
  89. if (value != GL_FULL_SUPPORT) {
  90. return false;
  91. }
  92. }
  93. }
  94. }
  95. return true;
  96. }
  97. static bool HasSlowSoftwareAstc(std::string_view vendor_name, std::string_view renderer) {
  98. // ifdef for Unix reduces string comparisons for non-Windows drivers, and Intel
  99. #ifdef YUZU_UNIX
  100. // Sorted vaguely by how likely a vendor is to appear
  101. if (vendor_name == "AMD") {
  102. // RadeonSI
  103. return true;
  104. }
  105. if (vendor_name == "Intel") {
  106. // Must be inside YUZU_UNIX ifdef as the Windows driver uses the same vendor string
  107. // iris, crocus
  108. const bool is_intel_dg = (renderer.find("DG") != std::string_view::npos);
  109. return is_intel_dg;
  110. }
  111. if (vendor_name == "nouveau") {
  112. return true;
  113. }
  114. if (vendor_name == "X.Org") {
  115. // R600
  116. return true;
  117. }
  118. #endif
  119. if (vendor_name == "Collabora Ltd") {
  120. // Zink
  121. return true;
  122. }
  123. if (vendor_name == "Microsoft Corporation") {
  124. // d3d12
  125. return true;
  126. }
  127. if (vendor_name == "Mesa/X.org") {
  128. // llvmpipe, softpipe, virgl
  129. return true;
  130. }
  131. return false;
  132. }
  133. [[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) {
  134. const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
  135. return nsight || HasExtension(extensions, "GL_EXT_debug_tool") ||
  136. Settings::values.renderer_debug.GetValue();
  137. }
  138. } // Anonymous namespace
  139. Device::Device(Core::Frontend::EmuWindow& emu_window) {
  140. if (!GLAD_GL_VERSION_4_6) {
  141. LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
  142. throw std::runtime_error{"Insufficient version"};
  143. }
  144. vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
  145. const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
  146. const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
  147. const std::vector extensions = GetExtensions();
  148. const bool is_nvidia = vendor_name == "NVIDIA Corporation";
  149. const bool is_amd = vendor_name == "ATI Technologies Inc.";
  150. const bool is_intel = vendor_name == "Intel";
  151. const bool has_slow_software_astc =
  152. !is_nvidia && !is_amd && HasSlowSoftwareAstc(vendor_name, renderer);
  153. #ifdef __unix__
  154. constexpr bool is_linux = true;
  155. #else
  156. constexpr bool is_linux = false;
  157. #endif
  158. bool disable_fast_buffer_sub_data = false;
  159. if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
  160. LOG_WARNING(
  161. Render_OpenGL,
  162. "Beta driver 443.24 is known to have issues. There might be performance issues.");
  163. disable_fast_buffer_sub_data = true;
  164. }
  165. max_uniform_buffers = BuildMaxUniformBuffers();
  166. uniform_buffer_alignment = GetInteger<size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
  167. shader_storage_alignment = GetInteger<size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
  168. max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
  169. max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
  170. max_compute_shared_memory_size = GetInteger<u32>(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
  171. max_glasm_storage_buffer_blocks = GetInteger<u32>(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS);
  172. has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
  173. GLAD_GL_NV_shader_thread_shuffle;
  174. has_shader_ballot = GLAD_GL_ARB_shader_ballot;
  175. has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
  176. has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
  177. has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
  178. has_astc = !has_slow_software_astc && IsASTCSupported();
  179. has_variable_aoffi = TestVariableAoffi();
  180. has_component_indexing_bug = false;
  181. has_precise_bug = TestPreciseBug();
  182. has_broken_texture_view_formats = (!is_linux && is_intel);
  183. has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
  184. has_derivative_control = GLAD_GL_ARB_derivative_control;
  185. has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory;
  186. has_debugging_tool_attached = IsDebugToolAttached(extensions);
  187. has_depth_buffer_float = HasExtension(extensions, "GL_NV_depth_buffer_float");
  188. has_geometry_shader_passthrough = GLAD_GL_NV_geometry_shader_passthrough;
  189. has_nv_gpu_shader_5 = GLAD_GL_NV_gpu_shader5;
  190. has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64");
  191. has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float;
  192. has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2;
  193. has_draw_texture = GLAD_GL_NV_draw_texture;
  194. warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel;
  195. need_fastmath_off = is_nvidia;
  196. can_report_memory = GLAD_GL_NVX_gpu_memory_info;
  197. // At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive
  198. // uniform buffers as "push constants"
  199. has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
  200. shader_backend = Settings::values.shader_backend.GetValue();
  201. use_assembly_shaders = shader_backend == Settings::ShaderBackend::Glasm &&
  202. GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
  203. GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
  204. if (shader_backend == Settings::ShaderBackend::Glasm && !use_assembly_shaders) {
  205. LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
  206. shader_backend = Settings::ShaderBackend::Glsl;
  207. }
  208. if (shader_backend == Settings::ShaderBackend::Glsl && is_nvidia) {
  209. const std::string_view driver_version = version.substr(13);
  210. const int version_major =
  211. std::atoi(driver_version.substr(0, driver_version.find(".")).data());
  212. if (version_major >= 495) {
  213. has_cbuf_ftou_bug = true;
  214. has_bool_ref_bug = true;
  215. }
  216. }
  217. has_lmem_perf_bug = is_nvidia;
  218. strict_context_required = emu_window.StrictContextRequired();
  219. // Blocks Intel OpenGL drivers on Windows from using asynchronous shader compilation.
  220. // Blocks EGL on Wayland from using asynchronous shader compilation.
  221. const bool blacklist_async_shaders = (is_intel && !is_linux) || strict_context_required;
  222. use_asynchronous_shaders =
  223. Settings::values.use_asynchronous_shaders.GetValue() && !blacklist_async_shaders;
  224. use_driver_cache = is_nvidia;
  225. supports_conditional_barriers = !is_intel;
  226. LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
  227. LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
  228. LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
  229. LOG_INFO(Render_OpenGL, "Renderer_BrokenTextureViewFormats: {}",
  230. has_broken_texture_view_formats);
  231. if (Settings::values.use_asynchronous_shaders.GetValue() && !use_asynchronous_shaders) {
  232. LOG_WARNING(Render_OpenGL, "Asynchronous shader compilation enabled but not supported");
  233. }
  234. }
  235. std::string Device::GetVendorName() const {
  236. if (vendor_name == "NVIDIA Corporation") {
  237. return "NVIDIA";
  238. }
  239. if (vendor_name == "ATI Technologies Inc.") {
  240. return "AMD";
  241. }
  242. if (vendor_name == "Intel") {
  243. // For Mesa, `Intel` is an overloaded vendor string that could mean crocus or iris.
  244. // Simply return `INTEL` for those as well as the Windows driver.
  245. return "Intel";
  246. }
  247. if (vendor_name == "Intel Open Source Technology Center") {
  248. return "i965";
  249. }
  250. if (vendor_name == "Mesa Project") {
  251. return "i915";
  252. }
  253. if (vendor_name == "Mesa/X.org") {
  254. // This vendor string is overloaded between llvmpipe, softpipe, and virgl, so just return
  255. // MESA instead of one of those driver names.
  256. return "Mesa";
  257. }
  258. if (vendor_name == "AMD") {
  259. return "RadeonSI";
  260. }
  261. if (vendor_name == "nouveau") {
  262. return "Nouveau";
  263. }
  264. if (vendor_name == "X.Org") {
  265. return "R600";
  266. }
  267. if (vendor_name == "Collabora Ltd") {
  268. return "Zink";
  269. }
  270. if (vendor_name == "Intel Corporation") {
  271. return "OpenSWR";
  272. }
  273. if (vendor_name == "Microsoft Corporation") {
  274. return "D3D12";
  275. }
  276. if (vendor_name == "NVIDIA") {
  277. // Mesa's tegra driver reports `NVIDIA`. Only present in this list because the default
  278. // strategy would have returned `NVIDIA` here for this driver, the same result as the
  279. // proprietary driver.
  280. return "Tegra";
  281. }
  282. return vendor_name;
  283. }
  284. bool Device::TestVariableAoffi() {
  285. return TestProgram(R"(#version 430 core
  286. // This is a unit test, please ignore me on apitrace bug reports.
  287. uniform sampler2D tex;
  288. uniform ivec2 variable_offset;
  289. out vec4 output_attribute;
  290. void main() {
  291. output_attribute = textureOffset(tex, vec2(0), variable_offset);
  292. })");
  293. }
  294. bool Device::TestPreciseBug() {
  295. return !TestProgram(R"(#version 430 core
  296. in vec3 coords;
  297. out float out_value;
  298. uniform sampler2DShadow tex;
  299. void main() {
  300. precise float tmp_value = vec4(texture(tex, coords)).x;
  301. out_value = tmp_value;
  302. })");
  303. }
  304. u64 Device::GetCurrentDedicatedVideoMemory() const {
  305. GLint cur_avail_mem_kb = 0;
  306. glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &cur_avail_mem_kb);
  307. return static_cast<u64>(cur_avail_mem_kb) * 1_KiB;
  308. }
  309. } // namespace OpenGL