gl_device.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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 <optional>
  9. #include <vector>
  10. #include <glad/glad.h>
  11. #include "common/logging/log.h"
  12. #include "common/scope_exit.h"
  13. #include "video_core/renderer_opengl/gl_device.h"
  14. #include "video_core/renderer_opengl/gl_resource_manager.h"
  15. namespace OpenGL {
  16. namespace {
  17. // One uniform block is reserved for emulation purposes
  18. constexpr u32 ReservedUniformBlocks = 1;
  19. constexpr u32 NumStages = 5;
  20. constexpr std::array LimitUBOs = {GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
  21. GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,
  22. GL_MAX_GEOMETRY_UNIFORM_BLOCKS, GL_MAX_FRAGMENT_UNIFORM_BLOCKS};
  23. constexpr std::array LimitSSBOs = {
  24. GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
  25. GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
  26. GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS};
  27. constexpr std::array LimitSamplers = {
  28. GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
  29. GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
  30. GL_MAX_TEXTURE_IMAGE_UNITS};
  31. constexpr std::array LimitImages = {GL_MAX_VERTEX_IMAGE_UNIFORMS,
  32. GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,
  33. GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,
  34. GL_MAX_GEOMETRY_IMAGE_UNIFORMS, GL_MAX_FRAGMENT_IMAGE_UNIFORMS};
  35. template <typename T>
  36. T GetInteger(GLenum pname) {
  37. GLint temporary;
  38. glGetIntegerv(pname, &temporary);
  39. return static_cast<T>(temporary);
  40. }
  41. bool TestProgram(const GLchar* glsl) {
  42. const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
  43. GLint link_status;
  44. glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
  45. glDeleteProgram(shader);
  46. return link_status == GL_TRUE;
  47. }
  48. std::vector<std::string_view> GetExtensions() {
  49. GLint num_extensions;
  50. glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
  51. std::vector<std::string_view> extensions;
  52. extensions.reserve(num_extensions);
  53. for (GLint index = 0; index < num_extensions; ++index) {
  54. extensions.push_back(
  55. reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
  56. }
  57. return extensions;
  58. }
  59. bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) {
  60. return std::find(images.begin(), images.end(), extension) != images.end();
  61. }
  62. u32 Extract(u32& base, u32& num, u32 amount, std::optional<GLenum> limit = {}) {
  63. ASSERT(num >= amount);
  64. if (limit) {
  65. amount = std::min(amount, GetInteger<u32>(*limit));
  66. }
  67. num -= amount;
  68. return std::exchange(base, base + amount);
  69. }
  70. std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> BuildBaseBindings() noexcept {
  71. std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> bindings;
  72. static std::array<std::size_t, 5> stage_swizzle = {0, 1, 2, 3, 4};
  73. const u32 total_ubos = GetInteger<u32>(GL_MAX_UNIFORM_BUFFER_BINDINGS);
  74. const u32 total_ssbos = GetInteger<u32>(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
  75. const u32 total_samplers = GetInteger<u32>(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
  76. u32 num_ubos = total_ubos - ReservedUniformBlocks;
  77. u32 num_ssbos = total_ssbos;
  78. u32 num_samplers = total_samplers;
  79. u32 base_ubo = ReservedUniformBlocks;
  80. u32 base_ssbo = 0;
  81. u32 base_samplers = 0;
  82. for (std::size_t i = 0; i < NumStages; ++i) {
  83. const std::size_t stage = stage_swizzle[i];
  84. bindings[stage] = {
  85. Extract(base_ubo, num_ubos, total_ubos / NumStages, LimitUBOs[stage]),
  86. Extract(base_ssbo, num_ssbos, total_ssbos / NumStages, LimitSSBOs[stage]),
  87. Extract(base_samplers, num_samplers, total_samplers / NumStages, LimitSamplers[stage])};
  88. }
  89. u32 num_images = GetInteger<u32>(GL_MAX_IMAGE_UNITS);
  90. u32 base_images = 0;
  91. // Reserve more image bindings on fragment and vertex stages.
  92. bindings[4].image =
  93. Extract(base_images, num_images, num_images / NumStages + 2, LimitImages[4]);
  94. bindings[0].image =
  95. Extract(base_images, num_images, num_images / NumStages + 1, LimitImages[0]);
  96. // Reserve the other image bindings.
  97. const u32 total_extracted_images = num_images / (NumStages - 2);
  98. for (std::size_t i = 2; i < NumStages; ++i) {
  99. const std::size_t stage = stage_swizzle[i];
  100. bindings[stage].image =
  101. Extract(base_images, num_images, total_extracted_images, LimitImages[stage]);
  102. }
  103. // Compute doesn't care about any of this.
  104. bindings[5] = {0, 0, 0, 0};
  105. return bindings;
  106. }
  107. } // Anonymous namespace
  108. Device::Device() : base_bindings{BuildBaseBindings()} {
  109. const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
  110. const auto renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
  111. const std::vector extensions = GetExtensions();
  112. const bool is_nvidia = vendor == "NVIDIA Corporation";
  113. const bool is_amd = vendor == "ATI Technologies Inc.";
  114. const bool is_intel = vendor == "Intel";
  115. const bool is_intel_proprietary = is_intel && std::strstr(renderer, "Mesa") == nullptr;
  116. uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
  117. shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
  118. max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
  119. max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
  120. has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
  121. GLAD_GL_NV_shader_thread_shuffle;
  122. has_shader_ballot = GLAD_GL_ARB_shader_ballot;
  123. has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
  124. has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
  125. has_variable_aoffi = TestVariableAoffi();
  126. has_component_indexing_bug = is_amd;
  127. has_precise_bug = TestPreciseBug();
  128. has_broken_compute = is_intel_proprietary;
  129. has_fast_buffer_sub_data = is_nvidia;
  130. has_debug_tool = HasExtension(extensions, "GL_EXT_debug_tool");
  131. LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
  132. LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
  133. LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
  134. }
  135. Device::Device(std::nullptr_t) {
  136. uniform_buffer_alignment = 0;
  137. max_vertex_attributes = 16;
  138. max_varyings = 15;
  139. has_warp_intrinsics = true;
  140. has_shader_ballot = true;
  141. has_vertex_viewport_layer = true;
  142. has_image_load_formatted = true;
  143. has_variable_aoffi = true;
  144. has_component_indexing_bug = false;
  145. has_broken_compute = false;
  146. has_precise_bug = false;
  147. }
  148. bool Device::TestVariableAoffi() {
  149. return TestProgram(R"(#version 430 core
  150. // This is a unit test, please ignore me on apitrace bug reports.
  151. uniform sampler2D tex;
  152. uniform ivec2 variable_offset;
  153. out vec4 output_attribute;
  154. void main() {
  155. output_attribute = textureOffset(tex, vec2(0), variable_offset);
  156. })");
  157. }
  158. bool Device::TestPreciseBug() {
  159. return !TestProgram(R"(#version 430 core
  160. in vec3 coords;
  161. out float out_value;
  162. uniform sampler2DShadow tex;
  163. void main() {
  164. precise float tmp_value = vec4(texture(tex, coords)).x;
  165. out_value = tmp_value;
  166. })");
  167. }
  168. } // namespace OpenGL