summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-11-22 21:22:01 -0300
committerGravatar ReinUsesLisp2019-11-22 21:28:50 -0300
commitdc2e83fa31a7bd3a7e1f1deb6f41cdb62be5f46e (patch)
treea13fcc82edee9bdb0a0bfb29ce9a55ce857037f8 /src
parentgl_state: Skip null texture binds (diff)
downloadyuzu-dc2e83fa31a7bd3a7e1f1deb6f41cdb62be5f46e.tar.gz
yuzu-dc2e83fa31a7bd3a7e1f1deb6f41cdb62be5f46e.tar.xz
yuzu-dc2e83fa31a7bd3a7e1f1deb6f41cdb62be5f46e.zip
gl_device: Reserve base bindings on limited devices
SSBOs and other resources are limited per pipeline on Intel and AMD. Heuristically reserve resources per stage having in mind the reported OpenGL limits.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp112
1 files changed, 76 insertions, 36 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 3adf57c96..a95bd4b2c 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -5,7 +5,9 @@
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <cstddef> 7#include <cstddef>
8#include <optional>
8#include <vector> 9#include <vector>
10
9#include <glad/glad.h> 11#include <glad/glad.h>
10 12
11#include "common/logging/log.h" 13#include "common/logging/log.h"
@@ -20,6 +22,27 @@ namespace {
20// One uniform block is reserved for emulation purposes 22// One uniform block is reserved for emulation purposes
21constexpr u32 ReservedUniformBlocks = 1; 23constexpr u32 ReservedUniformBlocks = 1;
22 24
25constexpr u32 NumStages = 5;
26
27constexpr std::array LimitUBOs = {GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
28 GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,
29 GL_MAX_GEOMETRY_UNIFORM_BLOCKS, GL_MAX_FRAGMENT_UNIFORM_BLOCKS};
30
31constexpr std::array LimitSSBOs = {
32 GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
33 GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
34 GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS};
35
36constexpr std::array LimitSamplers = {
37 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
38 GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
39 GL_MAX_TEXTURE_IMAGE_UNITS};
40
41constexpr std::array LimitImages = {GL_MAX_VERTEX_IMAGE_UNIFORMS,
42 GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,
43 GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,
44 GL_MAX_GEOMETRY_IMAGE_UNIFORMS, GL_MAX_FRAGMENT_IMAGE_UNIFORMS};
45
23template <typename T> 46template <typename T>
24T GetInteger(GLenum pname) { 47T GetInteger(GLenum pname) {
25 GLint temporary; 48 GLint temporary;
@@ -51,54 +74,71 @@ bool HasExtension(const std::vector<std::string_view>& images, std::string_view
51 return std::find(images.begin(), images.end(), extension) != images.end(); 74 return std::find(images.begin(), images.end(), extension) != images.end();
52} 75}
53 76
54constexpr Device::BaseBindings operator+(Device::BaseBindings lhs, Device::BaseBindings rhs) { 77u32 Extract(u32& base, u32& num, u32 amount, std::optional<GLenum> limit = {}) {
55 return Device::BaseBindings{lhs.uniform_buffer + rhs.uniform_buffer, 78 ASSERT(num >= amount);
56 lhs.shader_storage_buffer + rhs.shader_storage_buffer, 79 if (limit) {
57 lhs.sampler + rhs.sampler, lhs.image + rhs.image}; 80 amount = std::min(amount, GetInteger<u32>(*limit));
81 }
82 num -= amount;
83 return std::exchange(base, base + amount);
58} 84}
59 85
60Device::BaseBindings BuildBaseBindings(GLenum uniform_blocks, GLenum shader_storage_blocks, 86std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> BuildBaseBindings() noexcept {
61 GLenum texture_image_units, GLenum image_uniforms) noexcept { 87 std::array<Device::BaseBindings, Tegra::Engines::MaxShaderTypes> bindings;
62 return Device::BaseBindings{ 88
63 GetInteger<u32>(uniform_blocks) - ReservedUniformBlocks, 89 static std::array<std::size_t, 5> stage_swizzle = {0, 1, 2, 3, 4};
64 GetInteger<u32>(shader_storage_blocks), 90 const u32 total_ubos = GetInteger<u32>(GL_MAX_UNIFORM_BUFFER_BINDINGS);
65 GetInteger<u32>(texture_image_units), 91 const u32 total_ssbos = GetInteger<u32>(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
66 GetInteger<u32>(image_uniforms), 92 const u32 total_samplers = GetInteger<u32>(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
67 }; 93
94 u32 num_ubos = total_ubos - ReservedUniformBlocks;
95 u32 num_ssbos = total_ssbos;
96 u32 num_samplers = total_samplers;
97
98 u32 base_ubo = ReservedUniformBlocks;
99 u32 base_ssbo = 0;
100 u32 base_samplers = 0;
101
102 for (std::size_t i = 0; i < NumStages; ++i) {
103 const std::size_t stage = stage_swizzle[i];
104 bindings[stage] = {
105 Extract(base_ubo, num_ubos, total_ubos / NumStages, LimitUBOs[stage]),
106 Extract(base_ssbo, num_ssbos, total_ssbos / NumStages, LimitSSBOs[stage]),
107 Extract(base_samplers, num_samplers, total_samplers / NumStages, LimitSamplers[stage])};
108 }
109
110 u32 num_images = GetInteger<u32>(GL_MAX_IMAGE_UNITS);
111 u32 base_images = 0;
112
113 // Reserve more image bindings on fragment and vertex stages.
114 bindings[4].image =
115 Extract(base_images, num_images, num_images / NumStages + 2, LimitImages[4]);
116 bindings[0].image =
117 Extract(base_images, num_images, num_images / NumStages + 1, LimitImages[0]);
118
119 // Reserve the other image bindings.
120 const u32 total_extracted_images = num_images / (NumStages - 2);
121 for (std::size_t i = 2; i < NumStages; ++i) {
122 const std::size_t stage = stage_swizzle[i];
123 bindings[stage].image =
124 Extract(base_images, num_images, total_extracted_images, LimitImages[stage]);
125 }
126
127 // Compute doesn't care about any of this.
128 bindings[5] = {0, 0, 0, 0};
129
130 return bindings;
68} 131}
69 132
70} // Anonymous namespace 133} // Anonymous namespace
71 134
72Device::Device() { 135Device::Device() : base_bindings{BuildBaseBindings()} {
73 const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); 136 const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
74 const std::vector extensions = GetExtensions(); 137 const std::vector extensions = GetExtensions();
75 138
76 const bool is_nvidia = vendor == "NVIDIA Corporation"; 139 const bool is_nvidia = vendor == "NVIDIA Corporation";
77 const bool is_intel = vendor == "Intel"; 140 const bool is_intel = vendor == "Intel";
78 141
79 // Reserve the first UBO for emulation bindings
80 base_bindings[0] = BaseBindings{ReservedUniformBlocks, 0, 0, 0};
81 base_bindings[1] = base_bindings[0] + BuildBaseBindings(GL_MAX_VERTEX_UNIFORM_BLOCKS,
82 GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
83 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
84 GL_MAX_VERTEX_IMAGE_UNIFORMS);
85 base_bindings[2] =
86 base_bindings[1] + BuildBaseBindings(GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
87 GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
88 GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,
89 GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS);
90 base_bindings[3] =
91 base_bindings[2] + BuildBaseBindings(GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,
92 GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
93 GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,
94 GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS);
95 base_bindings[4] = base_bindings[3] + BuildBaseBindings(GL_MAX_GEOMETRY_UNIFORM_BLOCKS,
96 GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
97 GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,
98 GL_MAX_GEOMETRY_IMAGE_UNIFORMS);
99 // Compute doesn't need any of that
100 base_bindings[5] = BaseBindings{0, 0, 0, 0};
101
102 uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); 142 uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
103 shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); 143 shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
104 max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); 144 max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);