diff options
Diffstat (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 151 |
1 files changed, 69 insertions, 82 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 6600ad528..9f7c837d6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -297,10 +297,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { MICROPROFILE_SCOPE(OpenGL_Shader); auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); - // Next available bindpoints to use when uploading the const buffers and textures to the GLSL - // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. - u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; - u32 current_texture_bindpoint = 0; + BaseBindings base_bindings; std::array<bool, Maxwell::NumClipDistances> clip_distances{}; for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { @@ -324,43 +321,35 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { const GLintptr offset = buffer_cache.UploadHostMemory( &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment)); - // Bind the buffer - glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(stage), buffer_cache.GetHandle(), - offset, static_cast<GLsizeiptr>(sizeof(ubo))); + // Bind the emulation info buffer + glBindBufferRange(GL_UNIFORM_BUFFER, base_bindings.cbuf, buffer_cache.GetHandle(), offset, + static_cast<GLsizeiptr>(sizeof(ubo))); Shader shader{shader_cache.GetStageProgram(program)}; + const auto [program_handle, next_bindings] = + shader->GetProgramHandle(primitive_mode, base_bindings); switch (program) { case Maxwell::ShaderProgram::VertexA: - case Maxwell::ShaderProgram::VertexB: { - shader_program_manager->UseProgrammableVertexShader( - shader->GetProgramHandle(primitive_mode)); + case Maxwell::ShaderProgram::VertexB: + shader_program_manager->UseProgrammableVertexShader(program_handle); break; - } - case Maxwell::ShaderProgram::Geometry: { - shader_program_manager->UseProgrammableGeometryShader( - shader->GetProgramHandle(primitive_mode)); + case Maxwell::ShaderProgram::Geometry: + shader_program_manager->UseProgrammableGeometryShader(program_handle); break; - } - case Maxwell::ShaderProgram::Fragment: { - shader_program_manager->UseProgrammableFragmentShader( - shader->GetProgramHandle(primitive_mode)); + case Maxwell::ShaderProgram::Fragment: + shader_program_manager->UseProgrammableFragmentShader(program_handle); break; - } default: LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, shader_config.enable.Value(), shader_config.offset); UNREACHABLE(); } - // Configure the const buffers for this shader stage. - current_constbuffer_bindpoint = - SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode, - current_constbuffer_bindpoint); - - // Configure the textures for this shader stage. - current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, - primitive_mode, current_texture_bindpoint); + const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); + SetupConstBuffers(stage_enum, shader, program_handle, base_bindings); + SetupGlobalRegions(stage_enum, shader, program_handle, base_bindings); + SetupTextures(stage_enum, shader, program_handle, base_bindings); // Workaround for Intel drivers. // When a clip distance is enabled but not set in the shader it crops parts of the screen @@ -375,6 +364,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { // VertexB was combined with VertexA, so we skip the VertexB iteration index++; } + + base_bindings = next_bindings; } SyncClipEnabled(clip_distances); @@ -486,9 +477,9 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { cached_pages.add({pages_interval, delta}); } -void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb, - bool using_depth_fb, bool preserve_contents, - std::optional<std::size_t> single_color_target) { +std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( + OpenGLState& current_state, bool using_color_fb, bool using_depth_fb, bool preserve_contents, + std::optional<std::size_t> single_color_target) { MICROPROFILE_SCOPE(OpenGL_Framebuffer); const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& regs = gpu.regs; @@ -500,7 +491,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us // Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or // single color targets). This is done because the guest registers may not change but the // host framebuffer may contain different attachments - return; + return current_depth_stencil_usage; } current_framebuffer_config_state = fb_config_state; @@ -570,12 +561,14 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us depth_surface->MarkAsModified(true, res_cache); fbkey.zeta = depth_surface->Texture().handle; - fbkey.stencil_enable = regs.stencil_enable; + fbkey.stencil_enable = regs.stencil_enable && + depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; } SetupCachedFramebuffer(fbkey, current_state); - SyncViewport(current_state); + + return current_depth_stencil_usage = {static_cast<bool>(depth_surface), fbkey.stencil_enable}; } void RasterizerOpenGL::Clear() { @@ -643,8 +636,8 @@ void RasterizerOpenGL::Clear() { return; } - ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, - regs.clear_buffers.RT.Value()); + const auto [clear_depth, clear_stencil] = ConfigureFramebuffers( + clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value()); if (regs.clear_flags.scissor) { SyncScissorTest(clear_state); } @@ -659,11 +652,11 @@ void RasterizerOpenGL::Clear() { glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); } - if (use_depth && use_stencil) { + if (clear_depth && clear_stencil) { glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); - } else if (use_depth) { + } else if (clear_depth) { glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); - } else if (use_stencil) { + } else if (clear_stencil) { glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); } } @@ -790,11 +783,6 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs return true; } -bool RasterizerOpenGL::AccelerateFill(const void* config) { - UNREACHABLE(); - return true; -} - bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) { if (!framebuffer_addr) { @@ -924,13 +912,14 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr } } -u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, - GLenum primitive_mode, u32 current_bindpoint) { +void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, + const Shader& shader, GLuint program_handle, + BaseBindings base_bindings) { MICROPROFILE_SCOPE(OpenGL_UBO); const auto& gpu = Core::System::GetInstance().GPU(); const auto& maxwell3d = gpu.Maxwell3D(); const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)]; - const auto& entries = shader->GetShaderEntries().const_buffer_entries; + const auto& entries = shader->GetShaderEntries().const_buffers; constexpr u64 max_binds = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers; std::array<GLuint, max_binds> bind_buffers; @@ -965,7 +954,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad } } else { // Buffer is accessed directly, upload just what we use - size = used_buffer.GetSize() * sizeof(float); + size = used_buffer.GetSize(); } // Align the actual size so it ends up being a multiple of vec4 to meet the OpenGL std140 @@ -973,75 +962,73 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad size = Common::AlignUp(size, sizeof(GLvec4)); ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); - GLintptr const_buffer_offset = buffer_cache.UploadMemory( + const GLintptr const_buffer_offset = buffer_cache.UploadMemory( buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment)); - // Now configure the bindpoint of the buffer inside the shader - glUniformBlockBinding(shader->GetProgramHandle(primitive_mode), - shader->GetProgramResourceIndex(used_buffer), - current_bindpoint + bindpoint); - // Prepare values for multibind bind_buffers[bindpoint] = buffer_cache.GetHandle(); bind_offsets[bindpoint] = const_buffer_offset; bind_sizes[bindpoint] = size; } - glBindBuffersRange(GL_UNIFORM_BUFFER, current_bindpoint, static_cast<GLsizei>(entries.size()), + // The first binding is reserved for emulation values + const GLuint ubo_base_binding = base_bindings.cbuf + 1; + glBindBuffersRange(GL_UNIFORM_BUFFER, ubo_base_binding, static_cast<GLsizei>(entries.size()), bind_buffers.data(), bind_offsets.data(), bind_sizes.data()); +} + +void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, + const Shader& shader, GLenum primitive_mode, + BaseBindings base_bindings) { + // TODO(Rodrigo): Use ARB_multi_bind here + const auto& entries = shader->GetShaderEntries().global_memory_entries; - return current_bindpoint + static_cast<u32>(entries.size()); + for (u32 bindpoint = 0; bindpoint < static_cast<u32>(entries.size()); ++bindpoint) { + const auto& entry = entries[bindpoint]; + const u32 current_bindpoint = base_bindings.gmem + bindpoint; + const auto& region = global_cache.GetGlobalRegion(entry, stage); + + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle()); + } } -u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, - GLenum primitive_mode, u32 current_unit) { +void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, + GLuint program_handle, BaseBindings base_bindings) { MICROPROFILE_SCOPE(OpenGL_Texture); const auto& gpu = Core::System::GetInstance().GPU(); const auto& maxwell3d = gpu.Maxwell3D(); - const auto& entries = shader->GetShaderEntries().texture_samplers; + const auto& entries = shader->GetShaderEntries().samplers; - ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units), + ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units), "Exceeded the number of active textures."); for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { const auto& entry = entries[bindpoint]; - const u32 current_bindpoint = current_unit + bindpoint; - - // Bind the uniform to the sampler. - - glProgramUniform1i(shader->GetProgramHandle(primitive_mode), - shader->GetUniformLocation(entry), current_bindpoint); + const u32 current_bindpoint = base_bindings.sampler + bindpoint; + auto& unit = state.texture_units[current_bindpoint]; const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); - if (!texture.enabled) { - state.texture_units[current_bindpoint].texture = 0; + unit.texture = 0; continue; } texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); + Surface surface = res_cache.GetTextureSurface(texture, entry); if (surface != nullptr) { - const GLuint handle = + unit.texture = entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; - const GLenum target = entry.IsArray() ? surface->TargetLayer() : surface->Target(); - state.texture_units[current_bindpoint].texture = handle; - state.texture_units[current_bindpoint].target = target; - state.texture_units[current_bindpoint].swizzle.r = - MaxwellToGL::SwizzleSource(texture.tic.x_source); - state.texture_units[current_bindpoint].swizzle.g = - MaxwellToGL::SwizzleSource(texture.tic.y_source); - state.texture_units[current_bindpoint].swizzle.b = - MaxwellToGL::SwizzleSource(texture.tic.z_source); - state.texture_units[current_bindpoint].swizzle.a = - MaxwellToGL::SwizzleSource(texture.tic.w_source); + unit.target = entry.IsArray() ? surface->TargetLayer() : surface->Target(); + unit.swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); + unit.swizzle.g = MaxwellToGL::SwizzleSource(texture.tic.y_source); + unit.swizzle.b = MaxwellToGL::SwizzleSource(texture.tic.z_source); + unit.swizzle.a = MaxwellToGL::SwizzleSource(texture.tic.w_source); } else { // Can occur when texture addr is null or its memory is unmapped/invalid - state.texture_units[current_bindpoint].texture = 0; + unit.texture = 0; } } - - return current_unit + static_cast<u32>(entries.size()); } void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |