gl_state: Remove program tracking
This commit is contained in:
		| @@ -99,14 +99,11 @@ void oglEnablei(GLenum cap, bool state, GLuint index) { | |||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
|  |  | ||||||
| RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | ||||||
|                                    ScreenInfo& info) |                                    ScreenInfo& info, GLShader::ProgramManager& program_manager) | ||||||
|     : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device}, |     : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device}, | ||||||
|       shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system}, |       shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system}, | ||||||
|       screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} { |       screen_info{info}, program_manager{program_manager}, buffer_cache{*this, system, device, | ||||||
|     shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |                                                                         STREAM_BUFFER_SIZE} { | ||||||
|     state.draw.shader_program = 0; |  | ||||||
|     state.Apply(); |  | ||||||
|  |  | ||||||
|     CheckExtensions(); |     CheckExtensions(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -228,10 +225,10 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||||||
|         if (!gpu.regs.IsShaderConfigEnabled(index)) { |         if (!gpu.regs.IsShaderConfigEnabled(index)) { | ||||||
|             switch (program) { |             switch (program) { | ||||||
|             case Maxwell::ShaderProgram::Geometry: |             case Maxwell::ShaderProgram::Geometry: | ||||||
|                 shader_program_manager->UseTrivialGeometryShader(); |                 program_manager.UseGeometryShader(0); | ||||||
|                 break; |                 break; | ||||||
|             case Maxwell::ShaderProgram::Fragment: |             case Maxwell::ShaderProgram::Fragment: | ||||||
|                 shader_program_manager->UseTrivialFragmentShader(); |                 program_manager.UseFragmentShader(0); | ||||||
|                 break; |                 break; | ||||||
|             default: |             default: | ||||||
|                 break; |                 break; | ||||||
| @@ -262,13 +259,13 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||||||
|         switch (program) { |         switch (program) { | ||||||
|         case Maxwell::ShaderProgram::VertexA: |         case Maxwell::ShaderProgram::VertexA: | ||||||
|         case Maxwell::ShaderProgram::VertexB: |         case Maxwell::ShaderProgram::VertexB: | ||||||
|             shader_program_manager->UseProgrammableVertexShader(program_handle); |             program_manager.UseVertexShader(program_handle); | ||||||
|             break; |             break; | ||||||
|         case Maxwell::ShaderProgram::Geometry: |         case Maxwell::ShaderProgram::Geometry: | ||||||
|             shader_program_manager->UseProgrammableGeometryShader(program_handle); |             program_manager.UseGeometryShader(program_handle); | ||||||
|             break; |             break; | ||||||
|         case Maxwell::ShaderProgram::Fragment: |         case Maxwell::ShaderProgram::Fragment: | ||||||
|             shader_program_manager->UseProgrammableFragmentShader(program_handle); |             program_manager.UseFragmentShader(program_handle); | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             UNIMPLEMENTED_MSG("Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, |             UNIMPLEMENTED_MSG("Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, | ||||||
| @@ -550,7 +547,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | |||||||
|     bind_ubo_pushbuffer.Bind(); |     bind_ubo_pushbuffer.Bind(); | ||||||
|     bind_ssbo_pushbuffer.Bind(); |     bind_ssbo_pushbuffer.Bind(); | ||||||
|  |  | ||||||
|     shader_program_manager->ApplyTo(state); |     program_manager.Update(); | ||||||
|     state.Apply(); |     state.Apply(); | ||||||
|  |  | ||||||
|     if (texture_cache.TextureBarrier()) { |     if (texture_cache.TextureBarrier()) { | ||||||
| @@ -613,8 +610,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | |||||||
|     const ProgramVariant variant(launch_desc.block_dim_x, launch_desc.block_dim_y, |     const ProgramVariant variant(launch_desc.block_dim_x, launch_desc.block_dim_y, | ||||||
|                                  launch_desc.block_dim_z, launch_desc.shared_alloc, |                                  launch_desc.block_dim_z, launch_desc.shared_alloc, | ||||||
|                                  launch_desc.local_pos_alloc); |                                  launch_desc.local_pos_alloc); | ||||||
|     state.draw.shader_program = kernel->GetHandle(variant); |     glUseProgramStages(program_manager.GetHandle(), GL_COMPUTE_SHADER_BIT, | ||||||
|     state.draw.program_pipeline = 0; |                        kernel->GetHandle(variant)); | ||||||
|  |  | ||||||
|     const std::size_t buffer_size = |     const std::size_t buffer_size = | ||||||
|         Tegra::Engines::KeplerCompute::NumConstBuffers * |         Tegra::Engines::KeplerCompute::NumConstBuffers * | ||||||
| @@ -632,9 +629,6 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | |||||||
|     bind_ubo_pushbuffer.Bind(); |     bind_ubo_pushbuffer.Bind(); | ||||||
|     bind_ssbo_pushbuffer.Bind(); |     bind_ssbo_pushbuffer.Bind(); | ||||||
|  |  | ||||||
|     state.ApplyShaderProgram(); |  | ||||||
|     state.ApplyProgramPipeline(); |  | ||||||
|  |  | ||||||
|     glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); |     glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); | ||||||
|     ++num_queued_commands; |     ++num_queued_commands; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ struct DrawParameters; | |||||||
| class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { | class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { | ||||||
| public: | public: | ||||||
|     explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, |     explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | ||||||
|                               ScreenInfo& info); |                               ScreenInfo& info, GLShader::ProgramManager& program_manager); | ||||||
|     ~RasterizerOpenGL() override; |     ~RasterizerOpenGL() override; | ||||||
|  |  | ||||||
|     void Draw(bool is_indexed, bool is_instanced) override; |     void Draw(bool is_indexed, bool is_instanced) override; | ||||||
| @@ -218,8 +218,7 @@ private: | |||||||
|  |  | ||||||
|     Core::System& system; |     Core::System& system; | ||||||
|     ScreenInfo& screen_info; |     ScreenInfo& screen_info; | ||||||
|  |     GLShader::ProgramManager& program_manager; | ||||||
|     std::unique_ptr<GLShader::ProgramManager> shader_program_manager; |  | ||||||
|  |  | ||||||
|     static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |     static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | ||||||
|     OGLBufferCache buffer_cache; |     OGLBufferCache buffer_cache; | ||||||
|   | |||||||
| @@ -123,7 +123,6 @@ void OGLProgram::Release() { | |||||||
|  |  | ||||||
|     MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); |     MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); | ||||||
|     glDeleteProgram(handle); |     glDeleteProgram(handle); | ||||||
|     OpenGLState::GetCurState().ResetProgram(handle).Apply(); |  | ||||||
|     handle = 0; |     handle = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -141,7 +140,6 @@ void OGLPipeline::Release() { | |||||||
|  |  | ||||||
|     MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); |     MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); | ||||||
|     glDeleteProgramPipelines(1, &handle); |     glDeleteProgramPipelines(1, &handle); | ||||||
|     OpenGLState::GetCurState().ResetPipeline(handle).Apply(); |  | ||||||
|     handle = 0; |     handle = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,27 +10,21 @@ namespace OpenGL::GLShader { | |||||||
|  |  | ||||||
| using Tegra::Engines::Maxwell3D; | using Tegra::Engines::Maxwell3D; | ||||||
|  |  | ||||||
| ProgramManager::ProgramManager() { | ProgramManager::~ProgramManager() = default; | ||||||
|  |  | ||||||
|  | void ProgramManager::Create() { | ||||||
|     pipeline.Create(); |     pipeline.Create(); | ||||||
| } | } | ||||||
|  |  | ||||||
| ProgramManager::~ProgramManager() = default; | void ProgramManager::Update() { | ||||||
|  |  | ||||||
| void ProgramManager::ApplyTo(OpenGLState& state) { |  | ||||||
|     UpdatePipeline(); |  | ||||||
|     state.draw.shader_program = 0; |  | ||||||
|     state.draw.program_pipeline = pipeline.handle; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProgramManager::UpdatePipeline() { |  | ||||||
|     // Avoid updating the pipeline when values have no changed |     // Avoid updating the pipeline when values have no changed | ||||||
|     if (old_state == current_state) { |     if (old_state == current_state) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Workaround for AMD bug |     // Workaround for AMD bug | ||||||
|     constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | |     static constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | | ||||||
|                                      GL_FRAGMENT_SHADER_BIT}; |                                             GL_FRAGMENT_SHADER_BIT}; | ||||||
|     glUseProgramStages(pipeline.handle, all_used_stages, 0); |     glUseProgramStages(pipeline.handle, all_used_stages, 0); | ||||||
|  |  | ||||||
|     glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader); |     glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader); | ||||||
|   | |||||||
| @@ -29,25 +29,26 @@ static_assert(sizeof(MaxwellUniformData) < 16384, | |||||||
|  |  | ||||||
| class ProgramManager { | class ProgramManager { | ||||||
| public: | public: | ||||||
|     explicit ProgramManager(); |  | ||||||
|     ~ProgramManager(); |     ~ProgramManager(); | ||||||
|  |  | ||||||
|     void ApplyTo(OpenGLState& state); |     void Create(); | ||||||
|  |  | ||||||
|     void UseProgrammableVertexShader(GLuint program) { |     void Update(); | ||||||
|  |  | ||||||
|  |     void UseVertexShader(GLuint program) { | ||||||
|         current_state.vertex_shader = program; |         current_state.vertex_shader = program; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UseProgrammableGeometryShader(GLuint program) { |     void UseGeometryShader(GLuint program) { | ||||||
|         current_state.geometry_shader = program; |         current_state.geometry_shader = program; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UseProgrammableFragmentShader(GLuint program) { |     void UseFragmentShader(GLuint program) { | ||||||
|         current_state.fragment_shader = program; |         current_state.fragment_shader = program; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UseTrivialGeometryShader() { |     GLuint GetHandle() const { | ||||||
|         current_state.geometry_shader = 0; |         return pipeline.handle; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UseTrivialFragmentShader() { |     void UseTrivialFragmentShader() { | ||||||
| @@ -70,8 +71,6 @@ private: | |||||||
|         GLuint geometry_shader{}; |         GLuint geometry_shader{}; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     void UpdatePipeline(); |  | ||||||
|  |  | ||||||
|     OGLPipeline pipeline; |     OGLPipeline pipeline; | ||||||
|     PipelineState current_state; |     PipelineState current_state; | ||||||
|     PipelineState old_state; |     PipelineState old_state; | ||||||
|   | |||||||
| @@ -85,36 +85,6 @@ void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) { | |||||||
|  |  | ||||||
| OpenGLState::OpenGLState() = default; | OpenGLState::OpenGLState() = default; | ||||||
|  |  | ||||||
| void OpenGLState::ApplyShaderProgram() { | void OpenGLState::Apply() {} | ||||||
|     if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) { |  | ||||||
|         glUseProgram(draw.shader_program); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyProgramPipeline() { |  | ||||||
|     if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) { |  | ||||||
|         glBindProgramPipeline(draw.program_pipeline); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::Apply() { |  | ||||||
|     MICROPROFILE_SCOPE(OpenGL_State); |  | ||||||
|     ApplyShaderProgram(); |  | ||||||
|     ApplyProgramPipeline(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| OpenGLState& OpenGLState::ResetProgram(GLuint handle) { |  | ||||||
|     if (draw.shader_program == handle) { |  | ||||||
|         draw.shader_program = 0; |  | ||||||
|     } |  | ||||||
|     return *this; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| OpenGLState& OpenGLState::ResetPipeline(GLuint handle) { |  | ||||||
|     if (draw.program_pipeline == handle) { |  | ||||||
|         draw.program_pipeline = 0; |  | ||||||
|     } |  | ||||||
|     return *this; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } // namespace OpenGL | } // namespace OpenGL | ||||||
|   | |||||||
| @@ -13,11 +13,6 @@ namespace OpenGL { | |||||||
|  |  | ||||||
| class OpenGLState { | class OpenGLState { | ||||||
| public: | public: | ||||||
|     struct { |  | ||||||
|         GLuint shader_program = 0;   // GL_CURRENT_PROGRAM |  | ||||||
|         GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING |  | ||||||
|     } draw; |  | ||||||
|  |  | ||||||
|     OpenGLState(); |     OpenGLState(); | ||||||
|  |  | ||||||
|     /// Get the currently active OpenGL state |     /// Get the currently active OpenGL state | ||||||
| @@ -28,13 +23,6 @@ public: | |||||||
|     /// Apply this state as the current OpenGL state |     /// Apply this state as the current OpenGL state | ||||||
|     void Apply(); |     void Apply(); | ||||||
|  |  | ||||||
|     void ApplyShaderProgram(); |  | ||||||
|     void ApplyProgramPipeline(); |  | ||||||
|  |  | ||||||
|     /// Resets any references to the given resource |  | ||||||
|     OpenGLState& ResetProgram(GLuint handle); |  | ||||||
|     OpenGLState& ResetPipeline(GLuint handle); |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     static OpenGLState cur_state; |     static OpenGLState cur_state; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
| #include "core/telemetry_session.h" | #include "core/telemetry_session.h" | ||||||
| #include "video_core/morton.h" | #include "video_core/morton.h" | ||||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||||
| #include "video_core/renderer_opengl/renderer_opengl.h" | #include "video_core/renderer_opengl/renderer_opengl.h" | ||||||
|  |  | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| @@ -158,9 +159,13 @@ public: | |||||||
|  |  | ||||||
| namespace { | namespace { | ||||||
|  |  | ||||||
| constexpr char vertex_shader[] = R"( | constexpr char VERTEX_SHADER[] = R"( | ||||||
| #version 430 core | #version 430 core | ||||||
|  |  | ||||||
|  | out gl_PerVertex { | ||||||
|  |     vec4 gl_Position; | ||||||
|  | }; | ||||||
|  |  | ||||||
| layout (location = 0) in vec2 vert_position; | layout (location = 0) in vec2 vert_position; | ||||||
| layout (location = 1) in vec2 vert_tex_coord; | layout (location = 1) in vec2 vert_tex_coord; | ||||||
| layout (location = 0) out vec2 frag_tex_coord; | layout (location = 0) out vec2 frag_tex_coord; | ||||||
| @@ -181,7 +186,7 @@ void main() { | |||||||
| } | } | ||||||
| )"; | )"; | ||||||
|  |  | ||||||
| constexpr char fragment_shader[] = R"( | constexpr char FRAGMENT_SHADER[] = R"( | ||||||
| #version 430 core | #version 430 core | ||||||
|  |  | ||||||
| layout (location = 0) in vec2 frag_tex_coord; | layout (location = 0) in vec2 frag_tex_coord; | ||||||
| @@ -426,10 +431,19 @@ void RendererOpenGL::InitOpenGLObjects() { | |||||||
|     glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, |     glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, | ||||||
|                  0.0f); |                  0.0f); | ||||||
|  |  | ||||||
|     // Link shaders and get variable locations |     // Create shader programs | ||||||
|     shader.CreateFromSource(vertex_shader, nullptr, fragment_shader); |     OGLShader vertex_shader; | ||||||
|     state.draw.shader_program = shader.handle; |     vertex_shader.Create(VERTEX_SHADER, GL_VERTEX_SHADER); | ||||||
|     state.Apply(); |  | ||||||
|  |     OGLShader fragment_shader; | ||||||
|  |     fragment_shader.Create(FRAGMENT_SHADER, GL_FRAGMENT_SHADER); | ||||||
|  |  | ||||||
|  |     vertex_program.Create(true, false, vertex_shader.handle); | ||||||
|  |     fragment_program.Create(true, false, fragment_shader.handle); | ||||||
|  |  | ||||||
|  |     // Create program pipeline | ||||||
|  |     program_manager.Create(); | ||||||
|  |     glBindProgramPipeline(program_manager.GetHandle()); | ||||||
|  |  | ||||||
|     // Generate VBO handle for drawing |     // Generate VBO handle for drawing | ||||||
|     vertex_buffer.Create(); |     vertex_buffer.Create(); | ||||||
| @@ -468,7 +482,8 @@ void RendererOpenGL::CreateRasterizer() { | |||||||
|     if (rasterizer) { |     if (rasterizer) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info); |     rasterizer = | ||||||
|  |         std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info, program_manager); | ||||||
| } | } | ||||||
|  |  | ||||||
| void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | ||||||
| @@ -517,7 +532,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||||||
|     // Set projection matrix |     // Set projection matrix | ||||||
|     const std::array ortho_matrix = |     const std::array ortho_matrix = | ||||||
|         MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); |         MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||||||
|     glUniformMatrix3x2fv(ModelViewMatrixLocation, 1, GL_FALSE, ortho_matrix.data()); |     glProgramUniformMatrix3x2fv(vertex_program.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||||||
|  |                                 std::data(ortho_matrix)); | ||||||
|  |  | ||||||
|     const auto& texcoords = screen_info.display_texcoords; |     const auto& texcoords = screen_info.display_texcoords; | ||||||
|     auto left = texcoords.left; |     auto left = texcoords.left; | ||||||
| @@ -562,6 +578,11 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||||||
|     state.Apply(); |     state.Apply(); | ||||||
|  |  | ||||||
|     // TODO: Signal state tracker about these changes |     // TODO: Signal state tracker about these changes | ||||||
|  |     program_manager.UseVertexShader(vertex_program.handle); | ||||||
|  |     program_manager.UseGeometryShader(0); | ||||||
|  |     program_manager.UseFragmentShader(fragment_program.handle); | ||||||
|  |     program_manager.Update(); | ||||||
|  |  | ||||||
|     glEnable(GL_CULL_FACE); |     glEnable(GL_CULL_FACE); | ||||||
|     if (screen_info.display_srgb) { |     if (screen_info.display_srgb) { | ||||||
|         glEnable(GL_FRAMEBUFFER_SRGB); |         glEnable(GL_FRAMEBUFFER_SRGB); | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
| #include "common/math_util.h" | #include "common/math_util.h" | ||||||
| #include "video_core/renderer_base.h" | #include "video_core/renderer_base.h" | ||||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||||
| #include "video_core/renderer_opengl/gl_state.h" | #include "video_core/renderer_opengl/gl_state.h" | ||||||
|  |  | ||||||
| namespace Core { | namespace Core { | ||||||
| @@ -95,12 +96,16 @@ private: | |||||||
|  |  | ||||||
|     // OpenGL object IDs |     // OpenGL object IDs | ||||||
|     OGLBuffer vertex_buffer; |     OGLBuffer vertex_buffer; | ||||||
|     OGLProgram shader; |     OGLProgram vertex_program; | ||||||
|  |     OGLProgram fragment_program; | ||||||
|     OGLFramebuffer screenshot_framebuffer; |     OGLFramebuffer screenshot_framebuffer; | ||||||
|  |  | ||||||
|     /// Display information for Switch screen |     /// Display information for Switch screen | ||||||
|     ScreenInfo screen_info; |     ScreenInfo screen_info; | ||||||
|  |  | ||||||
|  |     /// Global dummy shader pipeline | ||||||
|  |     GLShader::ProgramManager program_manager; | ||||||
|  |  | ||||||
|     /// OpenGL framebuffer data |     /// OpenGL framebuffer data | ||||||
|     std::vector<u8> gl_framebuffer_data; |     std::vector<u8> gl_framebuffer_data; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user