gl_device.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 <vector>
  8. #include <glad/glad.h>
  9. #include "common/logging/log.h"
  10. #include "common/scope_exit.h"
  11. #include "video_core/renderer_opengl/gl_device.h"
  12. #include "video_core/renderer_opengl/gl_resource_manager.h"
  13. namespace OpenGL {
  14. namespace {
  15. template <typename T>
  16. T GetInteger(GLenum pname) {
  17. GLint temporary;
  18. glGetIntegerv(pname, &temporary);
  19. return static_cast<T>(temporary);
  20. }
  21. bool TestProgram(const GLchar* glsl) {
  22. const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
  23. GLint link_status;
  24. glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
  25. glDeleteProgram(shader);
  26. return link_status == GL_TRUE;
  27. }
  28. std::vector<std::string_view> GetExtensions() {
  29. GLint num_extensions;
  30. glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
  31. std::vector<std::string_view> extensions;
  32. extensions.reserve(num_extensions);
  33. for (GLint index = 0; index < num_extensions; ++index) {
  34. extensions.push_back(
  35. reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
  36. }
  37. return extensions;
  38. }
  39. bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) {
  40. return std::find(images.begin(), images.end(), extension) != images.end();
  41. }
  42. } // Anonymous namespace
  43. Device::Device() {
  44. const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
  45. const std::vector extensions = GetExtensions();
  46. const bool is_nvidia = vendor == "NVIDIA Corporation";
  47. uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
  48. shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
  49. max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
  50. max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
  51. has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
  52. GLAD_GL_NV_shader_thread_shuffle;
  53. has_shader_ballot = GLAD_GL_ARB_shader_ballot;
  54. has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
  55. has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
  56. has_variable_aoffi = TestVariableAoffi();
  57. has_component_indexing_bug = TestComponentIndexingBug();
  58. has_precise_bug = TestPreciseBug();
  59. has_fast_buffer_sub_data = is_nvidia;
  60. LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
  61. LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
  62. LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
  63. }
  64. Device::Device(std::nullptr_t) {
  65. uniform_buffer_alignment = 0;
  66. max_vertex_attributes = 16;
  67. max_varyings = 15;
  68. has_warp_intrinsics = true;
  69. has_shader_ballot = true;
  70. has_vertex_viewport_layer = true;
  71. has_image_load_formatted = true;
  72. has_variable_aoffi = true;
  73. has_component_indexing_bug = false;
  74. has_precise_bug = false;
  75. }
  76. bool Device::TestVariableAoffi() {
  77. return TestProgram(R"(#version 430 core
  78. // This is a unit test, please ignore me on apitrace bug reports.
  79. uniform sampler2D tex;
  80. uniform ivec2 variable_offset;
  81. out vec4 output_attribute;
  82. void main() {
  83. output_attribute = textureOffset(tex, vec2(0), variable_offset);
  84. })");
  85. }
  86. bool Device::TestComponentIndexingBug() {
  87. const GLchar* COMPONENT_TEST = R"(#version 430 core
  88. layout (std430, binding = 0) buffer OutputBuffer {
  89. uint output_value;
  90. };
  91. layout (std140, binding = 0) uniform InputBuffer {
  92. uvec4 input_value[4096];
  93. };
  94. layout (location = 0) uniform uint idx;
  95. void main() {
  96. output_value = input_value[idx >> 2][idx & 3];
  97. })";
  98. const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &COMPONENT_TEST)};
  99. SCOPE_EXIT({ glDeleteProgram(shader); });
  100. glUseProgram(shader);
  101. OGLVertexArray vao;
  102. vao.Create();
  103. glBindVertexArray(vao.handle);
  104. constexpr std::array<GLuint, 8> values{0, 0, 0, 0, 0x1236327, 0x985482, 0x872753, 0x2378432};
  105. OGLBuffer ubo;
  106. ubo.Create();
  107. glNamedBufferData(ubo.handle, sizeof(values), values.data(), GL_STATIC_DRAW);
  108. glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo.handle);
  109. OGLBuffer ssbo;
  110. ssbo.Create();
  111. glNamedBufferStorage(ssbo.handle, sizeof(GLuint), nullptr, GL_CLIENT_STORAGE_BIT);
  112. for (GLuint index = 4; index < 8; ++index) {
  113. glInvalidateBufferData(ssbo.handle);
  114. glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo.handle);
  115. glProgramUniform1ui(shader, 0, index);
  116. glDrawArrays(GL_POINTS, 0, 1);
  117. GLuint result;
  118. glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
  119. if (result != values.at(index)) {
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. bool Device::TestPreciseBug() {
  126. return !TestProgram(R"(#version 430 core
  127. in vec3 coords;
  128. out float out_value;
  129. uniform sampler2DShadow tex;
  130. void main() {
  131. precise float tmp_value = vec4(texture(tex, coords)).x;
  132. out_value = tmp_value;
  133. })");
  134. }
  135. } // namespace OpenGL