gl_device.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstddef>
  7. #include <cstring>
  8. #include <limits>
  9. #include <optional>
  10. #include <vector>
  11. #include <glad/glad.h>
  12. #include "common/logging/log.h"
  13. #include "common/scope_exit.h"
  14. #include "core/settings.h"
  15. #include "video_core/renderer_opengl/gl_device.h"
  16. #include "video_core/renderer_opengl/gl_resource_manager.h"
  17. namespace OpenGL {
  18. namespace {
  19. // One uniform block is reserved for emulation purposes
  20. constexpr u32 ReservedUniformBlocks = 1;
  21. constexpr u32 NumStages = 5;
  22. constexpr std::array LimitUBOs = {
  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. constexpr std::array LimitSSBOs = {
  27. GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
  28. GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
  29. GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS};
  30. constexpr std::array LimitSamplers = {GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
  31. GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
  32. GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,
  33. GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
  34. GL_MAX_TEXTURE_IMAGE_UNITS,
  35. GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS};
  36. constexpr std::array LimitImages = {
  37. GL_MAX_VERTEX_IMAGE_UNIFORMS, GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,
  38. GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, GL_MAX_GEOMETRY_IMAGE_UNIFORMS,
  39. GL_MAX_FRAGMENT_IMAGE_UNIFORMS, GL_MAX_COMPUTE_IMAGE_UNIFORMS};
  40. template <typename T>
  41. T GetInteger(GLenum pname) {
  42. GLint temporary;
  43. glGetIntegerv(pname, &temporary);
  44. return static_cast<T>(temporary);
  45. }
  46. bool TestProgram(const GLchar* glsl) {
  47. const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
  48. GLint link_status;
  49. glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
  50. glDeleteProgram(shader);
  51. return link_status == GL_TRUE;
  52. }
  53. std::vector<std::string_view> GetExtensions() {
  54. GLint num_extensions;
  55. glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
  56. std::vector<std::string_view> extensions;
  57. extensions.reserve(num_extensions);
  58. for (GLint index = 0; index < num_extensions; ++index) {
  59. extensions.push_back(
  60. reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
  61. }
  62. return extensions;
  63. }
  64. bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) {
  65. return std::find(images.begin(), images.end(), extension) != images.end();
  66. }
  67. u32 Extract(u32& base, u32& num, u32 amount, std::optional<GLenum> limit = {}) {
  68. ASSERT(num >= amount);
  69. if (limit) {
  70. amount = std::min(amount, GetInteger<u32>(*limit));
  71. }
  72. num -= amount;
  73. return std::exchange(base, base + amount);
  74. }
  75. std::array<u32, Tegra::Engines::MaxShaderTypes> BuildMaxUniformBuffers() noexcept {
  76. std::array<u32, Tegra::Engines::MaxShaderTypes> max;
  77. std::transform(LimitUBOs.begin(), LimitUBOs.end(), max.begin(),
  78. [](GLenum pname) { return GetInteger<u32>(pname); });
  79. return max;
  80. }
  81. std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> BuildBaseBindings() noexcept {
  82. std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> bindings;
  83. static constexpr std::array<std::size_t, 5> stage_swizzle{0, 1, 2, 3, 4};
  84. const u32 total_ubos = GetInteger<u32>(GL_MAX_UNIFORM_BUFFER_BINDINGS);
  85. const u32 total_ssbos = GetInteger<u32>(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
  86. const u32 total_samplers = GetInteger<u32>(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
  87. u32 num_ubos = total_ubos - ReservedUniformBlocks;
  88. u32 num_ssbos = total_ssbos;
  89. u32 num_samplers = total_samplers;
  90. u32 base_ubo = ReservedUniformBlocks;
  91. u32 base_ssbo = 0;
  92. u32 base_samplers = 0;
  93. for (std::size_t i = 0; i < NumStages; ++i) {
  94. const std::size_t stage = stage_swizzle[i];
  95. bindings[stage] = {
  96. Extract(base_ubo, num_ubos, total_ubos / NumStages, LimitUBOs[stage]),
  97. Extract(base_ssbo, num_ssbos, total_ssbos / NumStages, LimitSSBOs[stage]),
  98. Extract(base_samplers, num_samplers, total_samplers / NumStages, LimitSamplers[stage])};
  99. }
  100. u32 num_images = GetInteger<u32>(GL_MAX_IMAGE_UNITS);
  101. u32 base_images = 0;
  102. // GL_MAX_IMAGE_UNITS is guaranteed by the spec to have a minimum value of 8.
  103. // Due to the limitation of GL_MAX_IMAGE_UNITS, reserve at least 4 image bindings on the
  104. // fragment stage, and at least 1 for the rest of the stages.
  105. // So far games are observed to use 1 image binding on vertex and 4 on fragment stages.
  106. // Reserve at least 4 image bindings on the fragment stage.
  107. bindings[4].image =
  108. Extract(base_images, num_images, std::max(4U, num_images / NumStages), LimitImages[4]);
  109. // This is guaranteed to be at least 1.
  110. const u32 total_extracted_images = num_images / (NumStages - 1);
  111. // Reserve the other image bindings.
  112. for (std::size_t i = 0; i < NumStages; ++i) {
  113. const std::size_t stage = stage_swizzle[i];
  114. if (stage == 4) {
  115. continue;
  116. }
  117. bindings[stage].image =
  118. Extract(base_images, num_images, total_extracted_images, LimitImages[stage]);
  119. }
  120. // Compute doesn't care about any of this.
  121. bindings[5] = {0, 0, 0, 0};
  122. return bindings;
  123. }
  124. bool IsASTCSupported() {
  125. static constexpr std::array targets = {GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY};
  126. static constexpr std::array formats = {
  127. GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
  128. GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
  129. GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
  130. GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
  131. GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
  132. GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
  133. GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
  134. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
  135. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
  136. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
  137. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
  138. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
  139. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
  140. GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
  141. };
  142. static constexpr std::array required_support = {
  143. GL_VERTEX_TEXTURE, GL_TESS_CONTROL_TEXTURE, GL_TESS_EVALUATION_TEXTURE,
  144. GL_GEOMETRY_TEXTURE, GL_FRAGMENT_TEXTURE, GL_COMPUTE_TEXTURE,
  145. };
  146. for (const GLenum target : targets) {
  147. for (const GLenum format : formats) {
  148. for (const GLenum support : required_support) {
  149. GLint value;
  150. glGetInternalformativ(target, format, support, 1, &value);
  151. if (value != GL_FULL_SUPPORT) {
  152. return false;
  153. }
  154. }
  155. }
  156. }
  157. return true;
  158. }
  159. } // Anonymous namespace
  160. Device::Device()
  161. : max_uniform_buffers{BuildMaxUniformBuffers()}, base_bindings{BuildBaseBindings()} {
  162. const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
  163. const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
  164. const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
  165. const std::vector extensions = GetExtensions();
  166. const bool is_nvidia = vendor == "NVIDIA Corporation";
  167. const bool is_amd = vendor == "ATI Technologies Inc.";
  168. bool disable_fast_buffer_sub_data = false;
  169. if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
  170. LOG_WARNING(
  171. Render_OpenGL,
  172. "Beta driver 443.24 is known to have issues. There might be performance issues.");
  173. disable_fast_buffer_sub_data = true;
  174. }
  175. uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
  176. shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
  177. max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
  178. max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
  179. has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
  180. GLAD_GL_NV_shader_thread_shuffle;
  181. has_shader_ballot = GLAD_GL_ARB_shader_ballot;
  182. has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
  183. has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
  184. has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
  185. has_astc = IsASTCSupported();
  186. has_variable_aoffi = TestVariableAoffi();
  187. has_component_indexing_bug = is_amd;
  188. has_precise_bug = TestPreciseBug();
  189. has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
  190. has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory;
  191. // At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive
  192. // uniform buffers as "push constants"
  193. has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
  194. use_assembly_shaders = Settings::values.use_assembly_shaders.GetValue() &&
  195. GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
  196. GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
  197. LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
  198. LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
  199. LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
  200. if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
  201. LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
  202. }
  203. }
  204. Device::Device(std::nullptr_t) {
  205. max_uniform_buffers.fill(std::numeric_limits<u32>::max());
  206. uniform_buffer_alignment = 4;
  207. shader_storage_alignment = 4;
  208. max_vertex_attributes = 16;
  209. max_varyings = 15;
  210. has_warp_intrinsics = true;
  211. has_shader_ballot = true;
  212. has_vertex_viewport_layer = true;
  213. has_image_load_formatted = true;
  214. has_texture_shadow_lod = true;
  215. has_variable_aoffi = true;
  216. }
  217. bool Device::TestVariableAoffi() {
  218. return TestProgram(R"(#version 430 core
  219. // This is a unit test, please ignore me on apitrace bug reports.
  220. uniform sampler2D tex;
  221. uniform ivec2 variable_offset;
  222. out vec4 output_attribute;
  223. void main() {
  224. output_attribute = textureOffset(tex, vec2(0), variable_offset);
  225. })");
  226. }
  227. bool Device::TestPreciseBug() {
  228. return !TestProgram(R"(#version 430 core
  229. in vec3 coords;
  230. out float out_value;
  231. uniform sampler2DShadow tex;
  232. void main() {
  233. precise float tmp_value = vec4(texture(tex, coords)).x;
  234. out_value = tmp_value;
  235. })");
  236. }
  237. } // namespace OpenGL