summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2019-01-29 22:15:55 -0500
committerGravatar GitHub2019-01-29 22:15:55 -0500
commit4c818b60e36462e800e96d9732ceb357ba4fc67a (patch)
tree765adbfe1b677d01d8148b5e1888ff6e1d571de7
parentMerge pull request #1960 from ReinUsesLisp/shader-ir-ldg (diff)
parentgl_shader_cache: Use explicit bindings (diff)
downloadyuzu-4c818b60e36462e800e96d9732ceb357ba4fc67a.tar.gz
yuzu-4c818b60e36462e800e96d9732ceb357ba4fc67a.tar.xz
yuzu-4c818b60e36462e800e96d9732ceb357ba4fc67a.zip
Merge pull request #1987 from ReinUsesLisp/explicit-shader-ldg
gl_shader_cache: Use explicit bindings
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp130
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h41
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp146
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h90
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp13
7 files changed, 194 insertions, 249 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ca421ef28..ee313cb2f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -297,11 +297,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
297 MICROPROFILE_SCOPE(OpenGL_Shader); 297 MICROPROFILE_SCOPE(OpenGL_Shader);
298 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 298 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
299 299
300 // Next available bindpoints to use when uploading the const buffers and textures to the GLSL 300 BaseBindings base_bindings;
301 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
302 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
303 u32 current_gmem_bindpoint = 0;
304 u32 current_texture_bindpoint = 0;
305 std::array<bool, Maxwell::NumClipDistances> clip_distances{}; 301 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
306 302
307 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 303 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
@@ -325,47 +321,35 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
325 const GLintptr offset = buffer_cache.UploadHostMemory( 321 const GLintptr offset = buffer_cache.UploadHostMemory(
326 &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment)); 322 &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
327 323
328 // Bind the buffer 324 // Bind the emulation info buffer
329 glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(stage), buffer_cache.GetHandle(), 325 glBindBufferRange(GL_UNIFORM_BUFFER, base_bindings.cbuf, buffer_cache.GetHandle(), offset,
330 offset, static_cast<GLsizeiptr>(sizeof(ubo))); 326 static_cast<GLsizeiptr>(sizeof(ubo)));
331 327
332 Shader shader{shader_cache.GetStageProgram(program)}; 328 Shader shader{shader_cache.GetStageProgram(program)};
329 const auto [program_handle, next_bindings] =
330 shader->GetProgramHandle(primitive_mode, base_bindings);
333 331
334 switch (program) { 332 switch (program) {
335 case Maxwell::ShaderProgram::VertexA: 333 case Maxwell::ShaderProgram::VertexA:
336 case Maxwell::ShaderProgram::VertexB: { 334 case Maxwell::ShaderProgram::VertexB:
337 shader_program_manager->UseProgrammableVertexShader( 335 shader_program_manager->UseProgrammableVertexShader(program_handle);
338 shader->GetProgramHandle(primitive_mode));
339 break; 336 break;
340 } 337 case Maxwell::ShaderProgram::Geometry:
341 case Maxwell::ShaderProgram::Geometry: { 338 shader_program_manager->UseProgrammableGeometryShader(program_handle);
342 shader_program_manager->UseProgrammableGeometryShader(
343 shader->GetProgramHandle(primitive_mode));
344 break; 339 break;
345 } 340 case Maxwell::ShaderProgram::Fragment:
346 case Maxwell::ShaderProgram::Fragment: { 341 shader_program_manager->UseProgrammableFragmentShader(program_handle);
347 shader_program_manager->UseProgrammableFragmentShader(
348 shader->GetProgramHandle(primitive_mode));
349 break; 342 break;
350 }
351 default: 343 default:
352 LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, 344 LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index,
353 shader_config.enable.Value(), shader_config.offset); 345 shader_config.enable.Value(), shader_config.offset);
354 UNREACHABLE(); 346 UNREACHABLE();
355 } 347 }
356 348
357 // Configure the const buffers for this shader stage. 349 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
358 current_constbuffer_bindpoint = 350 SetupConstBuffers(stage_enum, shader, program_handle, base_bindings);
359 SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode, 351 SetupGlobalRegions(stage_enum, shader, program_handle, base_bindings);
360 current_constbuffer_bindpoint); 352 SetupTextures(stage_enum, shader, program_handle, base_bindings);
361
362 // Configure global memory regions for this shader stage.
363 current_gmem_bindpoint = SetupGlobalRegions(static_cast<Maxwell::ShaderStage>(stage),
364 shader, primitive_mode, current_gmem_bindpoint);
365
366 // Configure the textures for this shader stage.
367 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
368 primitive_mode, current_texture_bindpoint);
369 353
370 // Workaround for Intel drivers. 354 // Workaround for Intel drivers.
371 // When a clip distance is enabled but not set in the shader it crops parts of the screen 355 // When a clip distance is enabled but not set in the shader it crops parts of the screen
@@ -380,6 +364,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
380 // VertexB was combined with VertexA, so we skip the VertexB iteration 364 // VertexB was combined with VertexA, so we skip the VertexB iteration
381 index++; 365 index++;
382 } 366 }
367
368 base_bindings = next_bindings;
383 } 369 }
384 370
385 SyncClipEnabled(clip_distances); 371 SyncClipEnabled(clip_distances);
@@ -929,8 +915,9 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
929 } 915 }
930} 916}
931 917
932u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, 918void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
933 GLenum primitive_mode, u32 current_bindpoint) { 919 const Shader& shader, GLuint program_handle,
920 BaseBindings base_bindings) {
934 MICROPROFILE_SCOPE(OpenGL_UBO); 921 MICROPROFILE_SCOPE(OpenGL_UBO);
935 const auto& gpu = Core::System::GetInstance().GPU(); 922 const auto& gpu = Core::System::GetInstance().GPU();
936 const auto& maxwell3d = gpu.Maxwell3D(); 923 const auto& maxwell3d = gpu.Maxwell3D();
@@ -978,92 +965,73 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
978 size = Common::AlignUp(size, sizeof(GLvec4)); 965 size = Common::AlignUp(size, sizeof(GLvec4));
979 ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); 966 ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
980 967
981 GLintptr const_buffer_offset = buffer_cache.UploadMemory( 968 const GLintptr const_buffer_offset = buffer_cache.UploadMemory(
982 buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment)); 969 buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
983 970
984 // Now configure the bindpoint of the buffer inside the shader
985 glUniformBlockBinding(shader->GetProgramHandle(primitive_mode),
986 shader->GetProgramResourceIndex(used_buffer),
987 current_bindpoint + bindpoint);
988
989 // Prepare values for multibind 971 // Prepare values for multibind
990 bind_buffers[bindpoint] = buffer_cache.GetHandle(); 972 bind_buffers[bindpoint] = buffer_cache.GetHandle();
991 bind_offsets[bindpoint] = const_buffer_offset; 973 bind_offsets[bindpoint] = const_buffer_offset;
992 bind_sizes[bindpoint] = size; 974 bind_sizes[bindpoint] = size;
993 } 975 }
994 976
995 glBindBuffersRange(GL_UNIFORM_BUFFER, current_bindpoint, static_cast<GLsizei>(entries.size()), 977 // The first binding is reserved for emulation values
978 const GLuint ubo_base_binding = base_bindings.cbuf + 1;
979 glBindBuffersRange(GL_UNIFORM_BUFFER, ubo_base_binding, static_cast<GLsizei>(entries.size()),
996 bind_buffers.data(), bind_offsets.data(), bind_sizes.data()); 980 bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
997
998 return current_bindpoint + static_cast<u32>(entries.size());
999} 981}
1000 982
1001u32 RasterizerOpenGL::SetupGlobalRegions(Maxwell::ShaderStage stage, Shader& shader, 983void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
1002 GLenum primitive_mode, u32 current_bindpoint) { 984 const Shader& shader, GLenum primitive_mode,
1003 for (const auto& global_region : shader->GetShaderEntries().global_memory_entries) { 985 BaseBindings base_bindings) {
1004 const auto& region = 986 // TODO(Rodrigo): Use ARB_multi_bind here
1005 global_cache.GetGlobalRegion(global_region, static_cast<Maxwell::ShaderStage>(stage)); 987 const auto& entries = shader->GetShaderEntries().global_memory_entries;
1006 const GLuint block_index{shader->GetProgramResourceIndex(global_region)}; 988
1007 ASSERT(block_index != GL_INVALID_INDEX); 989 for (u32 bindpoint = 0; bindpoint < static_cast<u32>(entries.size()); ++bindpoint) {
990 const auto& entry = entries[bindpoint];
991 const u32 current_bindpoint = base_bindings.gmem + bindpoint;
992 const auto& region = global_cache.GetGlobalRegion(entry, stage);
1008 993
1009 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle()); 994 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle());
1010 glShaderStorageBlockBinding(shader->GetProgramHandle(primitive_mode), block_index,
1011 current_bindpoint);
1012 ++current_bindpoint;
1013 } 995 }
1014
1015 return current_bindpoint;
1016} 996}
1017 997
1018u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, 998void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
1019 GLenum primitive_mode, u32 current_unit) { 999 GLuint program_handle, BaseBindings base_bindings) {
1020 MICROPROFILE_SCOPE(OpenGL_Texture); 1000 MICROPROFILE_SCOPE(OpenGL_Texture);
1021 const auto& gpu = Core::System::GetInstance().GPU(); 1001 const auto& gpu = Core::System::GetInstance().GPU();
1022 const auto& maxwell3d = gpu.Maxwell3D(); 1002 const auto& maxwell3d = gpu.Maxwell3D();
1023 const auto& entries = shader->GetShaderEntries().samplers; 1003 const auto& entries = shader->GetShaderEntries().samplers;
1024 1004
1025 ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units), 1005 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
1026 "Exceeded the number of active textures."); 1006 "Exceeded the number of active textures.");
1027 1007
1028 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 1008 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1029 const auto& entry = entries[bindpoint]; 1009 const auto& entry = entries[bindpoint];
1030 const u32 current_bindpoint = current_unit + bindpoint; 1010 const u32 current_bindpoint = base_bindings.sampler + bindpoint;
1031 1011 auto& unit = state.texture_units[current_bindpoint];
1032 // Bind the uniform to the sampler.
1033
1034 glProgramUniform1i(shader->GetProgramHandle(primitive_mode),
1035 shader->GetUniformLocation(entry), current_bindpoint);
1036 1012
1037 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); 1013 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
1038
1039 if (!texture.enabled) { 1014 if (!texture.enabled) {
1040 state.texture_units[current_bindpoint].texture = 0; 1015 unit.texture = 0;
1041 continue; 1016 continue;
1042 } 1017 }
1043 1018
1044 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); 1019 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
1020
1045 Surface surface = res_cache.GetTextureSurface(texture, entry); 1021 Surface surface = res_cache.GetTextureSurface(texture, entry);
1046 if (surface != nullptr) { 1022 if (surface != nullptr) {
1047 const GLuint handle = 1023 unit.texture =
1048 entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; 1024 entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
1049 const GLenum target = entry.IsArray() ? surface->TargetLayer() : surface->Target(); 1025 unit.target = entry.IsArray() ? surface->TargetLayer() : surface->Target();
1050 state.texture_units[current_bindpoint].texture = handle; 1026 unit.swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source);
1051 state.texture_units[current_bindpoint].target = target; 1027 unit.swizzle.g = MaxwellToGL::SwizzleSource(texture.tic.y_source);
1052 state.texture_units[current_bindpoint].swizzle.r = 1028 unit.swizzle.b = MaxwellToGL::SwizzleSource(texture.tic.z_source);
1053 MaxwellToGL::SwizzleSource(texture.tic.x_source); 1029 unit.swizzle.a = MaxwellToGL::SwizzleSource(texture.tic.w_source);
1054 state.texture_units[current_bindpoint].swizzle.g =
1055 MaxwellToGL::SwizzleSource(texture.tic.y_source);
1056 state.texture_units[current_bindpoint].swizzle.b =
1057 MaxwellToGL::SwizzleSource(texture.tic.z_source);
1058 state.texture_units[current_bindpoint].swizzle.a =
1059 MaxwellToGL::SwizzleSource(texture.tic.w_source);
1060 } else { 1030 } else {
1061 // Can occur when texture addr is null or its memory is unmapped/invalid 1031 // Can occur when texture addr is null or its memory is unmapped/invalid
1062 state.texture_units[current_bindpoint].texture = 0; 1032 unit.texture = 0;
1063 } 1033 }
1064 } 1034 }
1065
1066 return current_unit + static_cast<u32>(entries.size());
1067} 1035}
1068 1036
1069void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 1037void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 57ab2f627..a103692f9 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -127,35 +127,18 @@ private:
127 bool using_depth_fb = true, bool preserve_contents = true, 127 bool using_depth_fb = true, bool preserve_contents = true,
128 std::optional<std::size_t> single_color_target = {}); 128 std::optional<std::size_t> single_color_target = {});
129 129
130 /** 130 /// Configures the current constbuffers to use for the draw command.
131 * Configures the current constbuffers to use for the draw command. 131 void SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
132 * @param stage The shader stage to configure buffers for. 132 GLuint program_handle, BaseBindings base_bindings);
133 * @param shader The shader object that contains the specified stage. 133
134 * @param current_bindpoint The offset at which to start counting new buffer bindpoints. 134 /// Configures the current global memory entries to use for the draw command.
135 * @returns The next available bindpoint for use in the next shader stage. 135 void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
136 */ 136 const Shader& shader, GLenum primitive_mode,
137 u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 137 BaseBindings base_bindings);
138 GLenum primitive_mode, u32 current_bindpoint); 138
139 139 /// Configures the current textures to use for the draw command.
140 /** 140 void SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
141 * Configures the current global memory regions to use for the draw command. 141 GLuint program_handle, BaseBindings base_bindings);
142 * @param stage The shader stage to configure buffers for.
143 * @param shader The shader object that contains the specified stage.
144 * @param current_bindpoint The offset at which to start counting new buffer bindpoints.
145 * @returns The next available bindpoint for use in the next shader stage.
146 */
147 u32 SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
148 GLenum primitive_mode, u32 current_bindpoint);
149
150 /**
151 * Configures the current textures to use for the draw command.
152 * @param stage The shader stage to configure textures for.
153 * @param shader The shader object that contains the specified stage.
154 * @param current_unit The offset at which to start counting unused texture units.
155 * @returns The next available bindpoint for use in the next shader stage.
156 */
157 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
158 GLenum primitive_mode, u32 current_unit);
159 142
160 /// Syncs the viewport and depth range to match the guest state 143 /// Syncs the viewport and depth range to match the guest state
161 void SyncViewport(OpenGLState& current_state); 144 void SyncViewport(OpenGLState& current_state);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 54ec23f3a..90eda7814 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -34,36 +34,25 @@ static ProgramCode GetShaderCode(VAddr addr) {
34 return program_code; 34 return program_code;
35} 35}
36 36
37/// Helper function to set shader uniform block bindings for a single shader stage 37/// Gets the shader type from a Maxwell program type
38static void SetShaderUniformBlockBinding(GLuint shader, const char* name, 38constexpr GLenum GetShaderType(Maxwell::ShaderProgram program_type) {
39 Maxwell::ShaderStage binding, std::size_t expected_size) { 39 switch (program_type) {
40 const GLuint ub_index = glGetUniformBlockIndex(shader, name); 40 case Maxwell::ShaderProgram::VertexA:
41 if (ub_index == GL_INVALID_INDEX) { 41 case Maxwell::ShaderProgram::VertexB:
42 return; 42 return GL_VERTEX_SHADER;
43 case Maxwell::ShaderProgram::Geometry:
44 return GL_GEOMETRY_SHADER;
45 case Maxwell::ShaderProgram::Fragment:
46 return GL_FRAGMENT_SHADER;
47 default:
48 return GL_NONE;
43 } 49 }
44
45 GLint ub_size = 0;
46 glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
47 ASSERT_MSG(static_cast<std::size_t>(ub_size) == expected_size,
48 "Uniform block size did not match! Got {}, expected {}", ub_size, expected_size);
49 glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
50}
51
52/// Sets shader uniform block bindings for an entire shader program
53static void SetShaderUniformBlockBindings(GLuint shader) {
54 SetShaderUniformBlockBinding(shader, "vs_config", Maxwell::ShaderStage::Vertex,
55 sizeof(GLShader::MaxwellUniformData));
56 SetShaderUniformBlockBinding(shader, "gs_config", Maxwell::ShaderStage::Geometry,
57 sizeof(GLShader::MaxwellUniformData));
58 SetShaderUniformBlockBinding(shader, "fs_config", Maxwell::ShaderStage::Fragment,
59 sizeof(GLShader::MaxwellUniformData));
60} 50}
61 51
62CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) 52CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
63 : addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} { 53 : addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} {
64 54
65 GLShader::ProgramResult program_result; 55 GLShader::ProgramResult program_result;
66 GLenum gl_type{};
67 56
68 switch (program_type) { 57 switch (program_type) {
69 case Maxwell::ShaderProgram::VertexA: 58 case Maxwell::ShaderProgram::VertexA:
@@ -74,17 +63,14 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
74 case Maxwell::ShaderProgram::VertexB: 63 case Maxwell::ShaderProgram::VertexB:
75 CalculateProperties(); 64 CalculateProperties();
76 program_result = GLShader::GenerateVertexShader(setup); 65 program_result = GLShader::GenerateVertexShader(setup);
77 gl_type = GL_VERTEX_SHADER;
78 break; 66 break;
79 case Maxwell::ShaderProgram::Geometry: 67 case Maxwell::ShaderProgram::Geometry:
80 CalculateProperties(); 68 CalculateProperties();
81 program_result = GLShader::GenerateGeometryShader(setup); 69 program_result = GLShader::GenerateGeometryShader(setup);
82 gl_type = GL_GEOMETRY_SHADER;
83 break; 70 break;
84 case Maxwell::ShaderProgram::Fragment: 71 case Maxwell::ShaderProgram::Fragment:
85 CalculateProperties(); 72 CalculateProperties();
86 program_result = GLShader::GenerateFragmentShader(setup); 73 program_result = GLShader::GenerateFragmentShader(setup);
87 gl_type = GL_FRAGMENT_SHADER;
88 break; 74 break;
89 default: 75 default:
90 LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type)); 76 LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type));
@@ -92,71 +78,105 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
92 return; 78 return;
93 } 79 }
94 80
81 code = program_result.first;
95 entries = program_result.second; 82 entries = program_result.second;
96 shader_length = entries.shader_length; 83 shader_length = entries.shader_length;
84}
97 85
98 if (program_type != Maxwell::ShaderProgram::Geometry) { 86std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode,
99 OGLShader shader; 87 BaseBindings base_bindings) {
100 shader.Create(program_result.first.c_str(), gl_type); 88 GLuint handle{};
101 program.Create(true, shader.handle); 89 if (program_type == Maxwell::ShaderProgram::Geometry) {
102 SetShaderUniformBlockBindings(program.handle); 90 handle = GetGeometryShader(primitive_mode, base_bindings);
103 LabelGLObject(GL_PROGRAM, program.handle, addr);
104 } else { 91 } else {
105 // Store shader's code to lazily build it on draw 92 const auto [entry, is_cache_miss] = programs.try_emplace(base_bindings);
106 geometry_programs.code = program_result.first; 93 auto& program = entry->second;
94 if (is_cache_miss) {
95 std::string source = AllocateBindings(base_bindings);
96 source += code;
97
98 OGLShader shader;
99 shader.Create(source.c_str(), GetShaderType(program_type));
100 program.Create(true, shader.handle);
101 LabelGLObject(GL_PROGRAM, program.handle, addr);
102 }
103
104 handle = program.handle;
107 } 105 }
106
107 // Add const buffer and samplers offset reserved by this shader. One UBO binding is reserved for
108 // emulation values
109 base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + 1;
110 base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
111 base_bindings.sampler += static_cast<u32>(entries.samplers.size());
112
113 return {handle, base_bindings};
108} 114}
109 115
110GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { 116std::string CachedShader::AllocateBindings(BaseBindings base_bindings) {
111 const auto search{cbuf_resource_cache.find(buffer.GetHash())}; 117 std::string code = "#version 430 core\n";
112 if (search == cbuf_resource_cache.end()) { 118 code += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
113 const GLuint index{ 119
114 glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())}; 120 for (const auto& cbuf : entries.const_buffers) {
115 cbuf_resource_cache[buffer.GetHash()] = index; 121 code += fmt::format("#define CBUF_BINDING_{} {}\n", cbuf.GetIndex(), base_bindings.cbuf++);
116 return index;
117 } 122 }
118 123
119 return search->second; 124 for (const auto& gmem : entries.global_memory_entries) {
120} 125 code += fmt::format("#define GMEM_BINDING_{}_{} {}\n", gmem.GetCbufIndex(),
126 gmem.GetCbufOffset(), base_bindings.gmem++);
127 }
121 128
122GLuint CachedShader::GetProgramResourceIndex(const GLShader::GlobalMemoryEntry& global_mem) { 129 for (const auto& sampler : entries.samplers) {
123 const auto search{gmem_resource_cache.find(global_mem.GetHash())}; 130 code += fmt::format("#define SAMPLER_BINDING_{} {}\n", sampler.GetIndex(),
124 if (search == gmem_resource_cache.end()) { 131 base_bindings.sampler++);
125 const GLuint index{glGetProgramResourceIndex(program.handle, GL_SHADER_STORAGE_BLOCK,
126 global_mem.GetName().c_str())};
127 gmem_resource_cache[global_mem.GetHash()] = index;
128 return index;
129 } 132 }
130 133
131 return search->second; 134 return code;
132} 135}
133 136
134GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) { 137GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) {
135 const auto search{uniform_cache.find(sampler.GetHash())}; 138 const auto [entry, is_cache_miss] = geometry_programs.try_emplace(base_bindings);
136 if (search == uniform_cache.end()) { 139 auto& programs = entry->second;
137 const GLint index{glGetUniformLocation(program.handle, sampler.GetName().c_str())}; 140
138 uniform_cache[sampler.GetHash()] = index; 141 switch (primitive_mode) {
139 return index; 142 case GL_POINTS:
143 return LazyGeometryProgram(programs.points, base_bindings, "points", 1, "ShaderPoints");
144 case GL_LINES:
145 case GL_LINE_STRIP:
146 return LazyGeometryProgram(programs.lines, base_bindings, "lines", 2, "ShaderLines");
147 case GL_LINES_ADJACENCY:
148 case GL_LINE_STRIP_ADJACENCY:
149 return LazyGeometryProgram(programs.lines_adjacency, base_bindings, "lines_adjacency", 4,
150 "ShaderLinesAdjacency");
151 case GL_TRIANGLES:
152 case GL_TRIANGLE_STRIP:
153 case GL_TRIANGLE_FAN:
154 return LazyGeometryProgram(programs.triangles, base_bindings, "triangles", 3,
155 "ShaderTriangles");
156 case GL_TRIANGLES_ADJACENCY:
157 case GL_TRIANGLE_STRIP_ADJACENCY:
158 return LazyGeometryProgram(programs.triangles_adjacency, base_bindings,
159 "triangles_adjacency", 6, "ShaderTrianglesAdjacency");
160 default:
161 UNREACHABLE_MSG("Unknown primitive mode.");
162 return LazyGeometryProgram(programs.points, base_bindings, "points", 1, "ShaderPoints");
140 } 163 }
141
142 return search->second;
143} 164}
144 165
145GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, 166GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, BaseBindings base_bindings,
146 const std::string& glsl_topology, u32 max_vertices, 167 const std::string& glsl_topology, u32 max_vertices,
147 const std::string& debug_name) { 168 const std::string& debug_name) {
148 if (target_program.handle != 0) { 169 if (target_program.handle != 0) {
149 return target_program.handle; 170 return target_program.handle;
150 } 171 }
151 std::string source = "#version 430 core\n"; 172 std::string source = AllocateBindings(base_bindings);
152 source += "layout (" + glsl_topology + ") in;\n"; 173 source += "layout (" + glsl_topology + ") in;\n";
153 source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n'; 174 source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
154 source += geometry_programs.code; 175 source += code;
155 176
156 OGLShader shader; 177 OGLShader shader;
157 shader.Create(source.c_str(), GL_GEOMETRY_SHADER); 178 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
158 target_program.Create(true, shader.handle); 179 target_program.Create(true, shader.handle);
159 SetShaderUniformBlockBindings(target_program.handle);
160 LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); 180 LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name);
161 return target_program.handle; 181 return target_program.handle;
162}; 182};
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 62b1733b4..904d15dd0 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -7,6 +7,9 @@
7#include <array> 7#include <array>
8#include <map> 8#include <map>
9#include <memory> 9#include <memory>
10#include <tuple>
11
12#include <glad/glad.h>
10 13
11#include "common/assert.h" 14#include "common/assert.h"
12#include "common/common_types.h" 15#include "common/common_types.h"
@@ -23,6 +26,16 @@ class RasterizerOpenGL;
23using Shader = std::shared_ptr<CachedShader>; 26using Shader = std::shared_ptr<CachedShader>;
24using Maxwell = Tegra::Engines::Maxwell3D::Regs; 27using Maxwell = Tegra::Engines::Maxwell3D::Regs;
25 28
29struct BaseBindings {
30 u32 cbuf{};
31 u32 gmem{};
32 u32 sampler{};
33
34 bool operator<(const BaseBindings& rhs) const {
35 return std::tie(cbuf, gmem, sampler) < std::tie(rhs.cbuf, rhs.gmem, rhs.sampler);
36 }
37};
38
26class CachedShader final : public RasterizerCacheObject { 39class CachedShader final : public RasterizerCacheObject {
27public: 40public:
28 CachedShader(VAddr addr, Maxwell::ShaderProgram program_type); 41 CachedShader(VAddr addr, Maxwell::ShaderProgram program_type);
@@ -44,71 +57,42 @@ public:
44 } 57 }
45 58
46 /// Gets the GL program handle for the shader 59 /// Gets the GL program handle for the shader
47 GLuint GetProgramHandle(GLenum primitive_mode) { 60 std::tuple<GLuint, BaseBindings> GetProgramHandle(GLenum primitive_mode,
48 if (program_type != Maxwell::ShaderProgram::Geometry) { 61 BaseBindings base_bindings);
49 return program.handle;
50 }
51 switch (primitive_mode) {
52 case GL_POINTS:
53 return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
54 case GL_LINES:
55 case GL_LINE_STRIP:
56 return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines");
57 case GL_LINES_ADJACENCY:
58 case GL_LINE_STRIP_ADJACENCY:
59 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4,
60 "ShaderLinesAdjacency");
61 case GL_TRIANGLES:
62 case GL_TRIANGLE_STRIP:
63 case GL_TRIANGLE_FAN:
64 return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3,
65 "ShaderTriangles");
66 case GL_TRIANGLES_ADJACENCY:
67 case GL_TRIANGLE_STRIP_ADJACENCY:
68 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
69 6, "ShaderTrianglesAdjacency");
70 default:
71 UNREACHABLE_MSG("Unknown primitive mode.");
72 return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
73 }
74 }
75 62
76 /// Gets the GL program resource location for the specified resource, caching as needed 63private:
77 GLuint GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer); 64 // Geometry programs. These are needed because GLSL needs an input topology but it's not
65 // declared by the hardware. Workaround this issue by generating a different shader per input
66 // topology class.
67 struct GeometryPrograms {
68 OGLProgram points;
69 OGLProgram lines;
70 OGLProgram lines_adjacency;
71 OGLProgram triangles;
72 OGLProgram triangles_adjacency;
73 };
78 74
79 /// Gets the GL program resource location for the specified resource, caching as needed 75 std::string AllocateBindings(BaseBindings base_bindings);
80 GLuint GetProgramResourceIndex(const GLShader::GlobalMemoryEntry& global_mem);
81 76
82 /// Gets the GL uniform location for the specified resource, caching as needed 77 GLuint GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings);
83 GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
84 78
85private:
86 /// Generates a geometry shader or returns one that already exists. 79 /// Generates a geometry shader or returns one that already exists.
87 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, 80 GLuint LazyGeometryProgram(OGLProgram& target_program, BaseBindings base_bindings,
88 u32 max_vertices, const std::string& debug_name); 81 const std::string& glsl_topology, u32 max_vertices,
82 const std::string& debug_name);
89 83
90 void CalculateProperties(); 84 void CalculateProperties();
91 85
92 VAddr addr; 86 VAddr addr{};
93 std::size_t shader_length; 87 std::size_t shader_length{};
94 Maxwell::ShaderProgram program_type; 88 Maxwell::ShaderProgram program_type{};
95 GLShader::ShaderSetup setup; 89 GLShader::ShaderSetup setup;
96 GLShader::ShaderEntries entries; 90 GLShader::ShaderEntries entries;
97 91
98 // Non-geometry program. 92 std::string code;
99 OGLProgram program;
100 93
101 // Geometry programs. These are needed because GLSL needs an input topology but it's not 94 std::map<BaseBindings, OGLProgram> programs;
102 // declared by the hardware. Workaround this issue by generating a different shader per input 95 std::map<BaseBindings, GeometryPrograms> geometry_programs;
103 // topology class.
104 struct {
105 std::string code;
106 OGLProgram points;
107 OGLProgram lines;
108 OGLProgram lines_adjacency;
109 OGLProgram triangles;
110 OGLProgram triangles_adjacency;
111 } geometry_programs;
112 96
113 std::map<u32, GLuint> cbuf_resource_cache; 97 std::map<u32, GLuint> cbuf_resource_cache;
114 std::map<u32, GLuint> gmem_resource_cache; 98 std::map<u32, GLuint> gmem_resource_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index e072216f0..004245431 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -374,7 +374,8 @@ private:
374 void DeclareConstantBuffers() { 374 void DeclareConstantBuffers() {
375 for (const auto& entry : ir.GetConstantBuffers()) { 375 for (const auto& entry : ir.GetConstantBuffers()) {
376 const auto [index, size] = entry; 376 const auto [index, size] = entry;
377 code.AddLine("layout (std140) uniform " + GetConstBufferBlock(index) + " {"); 377 code.AddLine("layout (std140, binding = CBUF_BINDING_" + std::to_string(index) +
378 ") uniform " + GetConstBufferBlock(index) + " {");
378 code.AddLine(" vec4 " + GetConstBuffer(index) + "[MAX_CONSTBUFFER_ELEMENTS];"); 379 code.AddLine(" vec4 " + GetConstBuffer(index) + "[MAX_CONSTBUFFER_ELEMENTS];");
379 code.AddLine("};"); 380 code.AddLine("};");
380 code.AddNewLine(); 381 code.AddNewLine();
@@ -383,7 +384,10 @@ private:
383 384
384 void DeclareGlobalMemory() { 385 void DeclareGlobalMemory() {
385 for (const auto& entry : ir.GetGlobalMemoryBases()) { 386 for (const auto& entry : ir.GetGlobalMemoryBases()) {
386 code.AddLine("layout (std430) buffer " + GetGlobalMemoryBlock(entry) + " {"); 387 const std::string binding =
388 fmt::format("GMEM_BINDING_{}_{}", entry.cbuf_index, entry.cbuf_offset);
389 code.AddLine("layout (std430, binding = " + binding + ") buffer " +
390 GetGlobalMemoryBlock(entry) + " {");
387 code.AddLine(" float " + GetGlobalMemory(entry) + "[MAX_GLOBALMEMORY_ELEMENTS];"); 391 code.AddLine(" float " + GetGlobalMemory(entry) + "[MAX_GLOBALMEMORY_ELEMENTS];");
388 code.AddLine("};"); 392 code.AddLine("};");
389 code.AddNewLine(); 393 code.AddNewLine();
@@ -413,7 +417,8 @@ private:
413 if (sampler.IsShadow()) 417 if (sampler.IsShadow())
414 sampler_type += "Shadow"; 418 sampler_type += "Shadow";
415 419
416 code.AddLine("uniform " + sampler_type + ' ' + GetSampler(sampler) + ';'); 420 code.AddLine("layout (binding = SAMPLER_BINDING_" + std::to_string(sampler.GetIndex()) +
421 ") uniform " + sampler_type + ' ' + GetSampler(sampler) + ';');
417 } 422 }
418 if (!samplers.empty()) 423 if (!samplers.empty())
419 code.AddNewLine(); 424 code.AddNewLine();
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index e47bc3729..0856a1361 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -38,10 +38,6 @@ public:
38 return index; 38 return index;
39 } 39 }
40 40
41 u32 GetHash() const {
42 return (static_cast<u32>(stage) << 16) | index;
43 }
44
45private: 41private:
46 std::string name; 42 std::string name;
47 Maxwell::ShaderStage stage{}; 43 Maxwell::ShaderStage stage{};
@@ -62,10 +58,6 @@ public:
62 return stage; 58 return stage;
63 } 59 }
64 60
65 u32 GetHash() const {
66 return (static_cast<u32>(stage) << 16) | static_cast<u32>(GetIndex());
67 }
68
69private: 61private:
70 std::string name; 62 std::string name;
71 Maxwell::ShaderStage stage{}; 63 Maxwell::ShaderStage stage{};
@@ -93,10 +85,6 @@ public:
93 return stage; 85 return stage;
94 } 86 }
95 87
96 u32 GetHash() const {
97 return (static_cast<u32>(stage) << 24) | (cbuf_index << 16) | cbuf_offset;
98 }
99
100private: 88private:
101 u32 cbuf_index{}; 89 u32 cbuf_index{};
102 u32 cbuf_offset{}; 90 u32 cbuf_offset{};
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 446d1a93f..04e1db911 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -20,15 +20,14 @@ static constexpr u32 PROGRAM_OFFSET{10};
20ProgramResult GenerateVertexShader(const ShaderSetup& setup) { 20ProgramResult GenerateVertexShader(const ShaderSetup& setup) {
21 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); 21 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier);
22 22
23 std::string out = "#version 430 core\n"; 23 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
24 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
25 out += "// Shader Unique Id: VS" + id + "\n\n"; 24 out += "// Shader Unique Id: VS" + id + "\n\n";
26 out += GetCommonDeclarations(); 25 out += GetCommonDeclarations();
27 26
28 out += R"( 27 out += R"(
29layout (location = 0) out vec4 position; 28layout (location = 0) out vec4 position;
30 29
31layout(std140) uniform vs_config { 30layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
32 vec4 viewport_flip; 31 vec4 viewport_flip;
33 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding 32 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
34 uvec4 alpha_test; 33 uvec4 alpha_test;
@@ -78,7 +77,6 @@ void main() {
78} 77}
79 78
80ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { 79ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
81 // Version is intentionally skipped in shader generation, it's added by the lazy compilation.
82 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); 80 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier);
83 81
84 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; 82 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
@@ -89,7 +87,7 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
89layout (location = 0) in vec4 gs_position[]; 87layout (location = 0) in vec4 gs_position[];
90layout (location = 0) out vec4 position; 88layout (location = 0) out vec4 position;
91 89
92layout (std140) uniform gs_config { 90layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
93 vec4 viewport_flip; 91 vec4 viewport_flip;
94 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding 92 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
95 uvec4 alpha_test; 93 uvec4 alpha_test;
@@ -112,8 +110,7 @@ void main() {
112ProgramResult GenerateFragmentShader(const ShaderSetup& setup) { 110ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
113 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); 111 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier);
114 112
115 std::string out = "#version 430 core\n"; 113 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
116 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
117 out += "// Shader Unique Id: FS" + id + "\n\n"; 114 out += "// Shader Unique Id: FS" + id + "\n\n";
118 out += GetCommonDeclarations(); 115 out += GetCommonDeclarations();
119 116
@@ -129,7 +126,7 @@ layout (location = 7) out vec4 FragColor7;
129 126
130layout (location = 0) in vec4 position; 127layout (location = 0) in vec4 position;
131 128
132layout (std140) uniform fs_config { 129layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
133 vec4 viewport_flip; 130 vec4 viewport_flip;
134 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding 131 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
135 uvec4 alpha_test; 132 uvec4 alpha_test;