diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 9522fd344344e04f6b5fbb71611dec5fd35723fa..31ccf4ab86b8fd1c4e7a7c45dc152ceca329ff68 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -121,12 +121,16 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
 }
 
 GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
-                                         const std::string& glsl_topology,
+                                         const std::string& glsl_topology, u32 max_vertices,
                                          const std::string& debug_name) {
     if (target_program.handle != 0) {
         return target_program.handle;
     }
-    const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"};
+    std::string source = "#version 430 core\n";
+    source += "layout (" + glsl_topology + ") in;\n";
+    source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
+    source += geometry_programs.code;
+
     OGLShader shader;
     shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
     target_program.Create(true, shader.handle);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index a210f1731d614b60ba376ad79b15e50cba3bbf05..8fd0b7e88004a59704e4fa32ce8daec7fab77d34 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -46,22 +46,23 @@ public:
         }
         switch (primitive_mode) {
         case GL_POINTS:
-            return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints");
+            return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
         case GL_LINES:
         case GL_LINE_STRIP:
-            return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines");
+            return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines");
         case GL_LINES_ADJACENCY:
         case GL_LINE_STRIP_ADJACENCY:
-            return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency",
+            return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4,
                                        "ShaderLinesAdjacency");
         case GL_TRIANGLES:
         case GL_TRIANGLE_STRIP:
         case GL_TRIANGLE_FAN:
-            return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles");
+            return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3,
+                                       "ShaderTriangles");
         case GL_TRIANGLES_ADJACENCY:
         case GL_TRIANGLE_STRIP_ADJACENCY:
             return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
-                                       "ShaderLines");
+                                       6, "ShaderTrianglesAdjacency");
         default:
             UNREACHABLE_MSG("Unknown primitive mode.");
         }
@@ -76,7 +77,7 @@ public:
 private:
     /// Generates a geometry shader or returns one that already exists.
     GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
-                               const std::string& debug_name);
+                               u32 max_vertices, const std::string& debug_name);
 
     VAddr addr;
     Maxwell::ShaderProgram program_type;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 09b003c598b77a019e8e89260f856f9ea8749548..bce7465b5aa368b1fab4780971ed0f5c4c4e92d2 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -494,10 +494,10 @@ public:
             // instruction for now.
             if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
                 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
-                // shader. These instructions use a dirty register as buffer index. To avoid some
-                // drivers from complaining for the out of boundary writes, guard them.
-                const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " +
-                                            std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'};
+                // shader. These instructions use a dirty register as buffer index, to avoid some
+                // drivers from complaining about out of boundary writes, guard them.
+                const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
+                                            std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
                 shader.AddLine("amem[" + buf_index + "][" +
                                std::to_string(static_cast<u32>(attribute)) + ']' +
                                GetSwizzle(elem) + " = " + src + ';');
@@ -811,7 +811,11 @@ private:
                                   std::optional<Register> vertex = {}) {
         auto GeometryPass = [&](const std::string& name) {
             if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
-                return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']';
+                // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games set
+                // an 0x80000000 index for those and the shader fails to build. Find out why this
+                // happens and what's its intent.
+                return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) +
+                       " % MAX_VERTEX_INPUT]";
             }
             return name;
         };
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 9d17edd63133860293d117a2a97fc9561404e9aa..eea090e52e3e0a7860b61222adcf8a013e77ff3d 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -82,8 +82,8 @@ void main() {
 }
 
 ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
-    std::string out = "#version 430 core\n";
-    out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
+    // Version is intentionally skipped in shader generation, it's added by the lazy compilation.
+    std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
     out += Decompiler::GetCommonDeclarations();
     out += "bool exec_geometry();\n";