// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_shader_manager.h" namespace OpenGL { ProgramManager::ProgramManager(const Device& device) { use_assembly_programs = device.UseAssemblyShaders(); if (use_assembly_programs) { glEnable(GL_COMPUTE_PROGRAM_NV); } else { graphics_pipeline.Create(); glBindProgramPipeline(graphics_pipeline.handle); } } ProgramManager::~ProgramManager() = default; void ProgramManager::BindCompute(GLuint program) { if (use_assembly_programs) { glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program); } else { is_graphics_bound = false; glUseProgram(program); } } void ProgramManager::BindGraphicsPipeline() { if (use_assembly_programs) { UpdateAssemblyPrograms(); } else { UpdateSourcePrograms(); } } void ProgramManager::BindHostPipeline(GLuint pipeline) { if (use_assembly_programs) { if (geometry_enabled) { geometry_enabled = false; old_state.geometry = 0; glDisable(GL_GEOMETRY_PROGRAM_NV); } } else { if (!is_graphics_bound) { glUseProgram(0); } } glBindProgramPipeline(pipeline); } void ProgramManager::RestoreGuestPipeline() { if (use_assembly_programs) { glBindProgramPipeline(0); } else { glBindProgramPipeline(graphics_pipeline.handle); } } void ProgramManager::UpdateAssemblyPrograms() { const auto update_state = [](GLenum stage, bool& enabled, GLuint current, GLuint old) { if (current == old) { return; } if (current == 0) { if (enabled) { enabled = false; glDisable(stage); } return; } if (!enabled) { enabled = true; glEnable(stage); } glBindProgramARB(stage, current); }; update_state(GL_VERTEX_PROGRAM_NV, vertex_enabled, current_state.vertex, old_state.vertex); update_state(GL_GEOMETRY_PROGRAM_NV, geometry_enabled, current_state.geometry, old_state.geometry); update_state(GL_FRAGMENT_PROGRAM_NV, fragment_enabled, current_state.fragment, old_state.fragment); old_state = current_state; } void ProgramManager::UpdateSourcePrograms() { if (!is_graphics_bound) { is_graphics_bound = true; glUseProgram(0); } const GLuint handle = graphics_pipeline.handle; const auto update_state = [handle](GLenum stage, GLuint current, GLuint old) { if (current == old) { return; } glUseProgramStages(handle, stage, current); }; update_state(GL_VERTEX_SHADER_BIT, current_state.vertex, old_state.vertex); update_state(GL_GEOMETRY_SHADER_BIT, current_state.geometry, old_state.geometry); update_state(GL_FRAGMENT_SHADER_BIT, current_state.fragment, old_state.fragment); old_state = current_state; } void MaxwellUniformData::SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell) { const auto& regs = maxwell.regs; // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. y_direction = regs.screen_y_control.y_negate == 0 ? 1.0f : -1.0f; } } // namespace OpenGL