renderer_opengl: State track assembly programs
This commit is contained in:
		@@ -42,6 +42,9 @@ GraphicsProgram::GraphicsProgram(TextureCache& texture_cache_, BufferCache& buff
 | 
			
		||||
    std::ranges::transform(infos, stage_infos.begin(),
 | 
			
		||||
                           [](const Shader::Info* info) { return info ? *info : Shader::Info{}; });
 | 
			
		||||
 | 
			
		||||
    for (size_t stage = 0; stage < 5; ++stage) {
 | 
			
		||||
        enabled_stages_mask |= (assembly_programs[stage].handle != 0 ? 1 : 0) << stage;
 | 
			
		||||
    }
 | 
			
		||||
    u32 num_textures{};
 | 
			
		||||
    u32 num_images{};
 | 
			
		||||
    for (size_t stage = 0; stage < base_uniform_bindings.size() - 1; ++stage) {
 | 
			
		||||
@@ -182,6 +185,9 @@ void GraphicsProgram::Configure(bool is_indexed) {
 | 
			
		||||
    const std::span indices_span(image_view_indices.data(), image_view_index);
 | 
			
		||||
    texture_cache.FillGraphicsImageViews(indices_span, image_view_ids);
 | 
			
		||||
 | 
			
		||||
    texture_cache.UpdateRenderTargets(false);
 | 
			
		||||
    state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
 | 
			
		||||
 | 
			
		||||
    ImageId* texture_buffer_index{image_view_ids.data()};
 | 
			
		||||
    const auto bind_stage_info{[&](size_t stage) {
 | 
			
		||||
        size_t index{};
 | 
			
		||||
@@ -240,14 +246,8 @@ void GraphicsProgram::Configure(bool is_indexed) {
 | 
			
		||||
    buffer_cache.UpdateGraphicsBuffers(is_indexed);
 | 
			
		||||
    buffer_cache.BindHostGeometryBuffers(is_indexed);
 | 
			
		||||
 | 
			
		||||
    // FIXME: Unhack this
 | 
			
		||||
    if (assembly_programs[0].handle != 0) {
 | 
			
		||||
        // TODO: State track this
 | 
			
		||||
        glEnable(GL_VERTEX_PROGRAM_NV);
 | 
			
		||||
        glEnable(GL_FRAGMENT_PROGRAM_NV);
 | 
			
		||||
        glBindProgramARB(GL_VERTEX_PROGRAM_NV, assembly_programs[0].handle);
 | 
			
		||||
        glBindProgramARB(GL_FRAGMENT_PROGRAM_NV, assembly_programs[4].handle);
 | 
			
		||||
        program_manager.BindProgram(0);
 | 
			
		||||
        program_manager.BindAssemblyPrograms(assembly_programs, enabled_stages_mask);
 | 
			
		||||
    } else {
 | 
			
		||||
        program_manager.BindProgram(program.handle);
 | 
			
		||||
    }
 | 
			
		||||
@@ -300,19 +300,6 @@ void GraphicsProgram::Configure(bool is_indexed) {
 | 
			
		||||
    if (image_binding != 0) {
 | 
			
		||||
        glBindImageTextures(0, image_binding, images.data());
 | 
			
		||||
    }
 | 
			
		||||
    texture_cache.UpdateRenderTargets(false);
 | 
			
		||||
 | 
			
		||||
    state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
 | 
			
		||||
    if (assembly_programs[0].handle != 0) {
 | 
			
		||||
        // TODO: State track this
 | 
			
		||||
        glEnable(GL_VERTEX_PROGRAM_NV);
 | 
			
		||||
        glEnable(GL_FRAGMENT_PROGRAM_NV);
 | 
			
		||||
        glBindProgramARB(GL_VERTEX_PROGRAM_NV, assembly_programs[0].handle);
 | 
			
		||||
        glBindProgramARB(GL_FRAGMENT_PROGRAM_NV, assembly_programs[4].handle);
 | 
			
		||||
        program_manager.BindProgram(0);
 | 
			
		||||
    } else {
 | 
			
		||||
        program_manager.BindProgram(program.handle);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenGL
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    OGLProgram program;
 | 
			
		||||
    std::array<OGLAssemblyProgram, 5> assembly_programs;
 | 
			
		||||
    u32 enabled_stages_mask{};
 | 
			
		||||
 | 
			
		||||
    std::array<Shader::Info, 5> stage_infos{};
 | 
			
		||||
    std::array<u32, 5> base_uniform_bindings{};
 | 
			
		||||
 
 | 
			
		||||
@@ -4,24 +4,69 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <span>
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
 | 
			
		||||
#pragma optimize("", off)
 | 
			
		||||
 | 
			
		||||
namespace OpenGL {
 | 
			
		||||
 | 
			
		||||
class ProgramManager {
 | 
			
		||||
    static constexpr size_t NUM_STAGES = 5;
 | 
			
		||||
 | 
			
		||||
    static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{
 | 
			
		||||
        GL_VERTEX_PROGRAM_NV,   GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV,
 | 
			
		||||
        GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    void BindProgram(GLuint program) {
 | 
			
		||||
        if (bound_program == program) {
 | 
			
		||||
        if (current_source_program == program) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bound_program = program;
 | 
			
		||||
        current_source_program = program;
 | 
			
		||||
        glUseProgram(program);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs,
 | 
			
		||||
                              u32 stage_mask) {
 | 
			
		||||
        const u32 changed_mask = current_assembly_mask ^ stage_mask;
 | 
			
		||||
        current_assembly_mask = stage_mask;
 | 
			
		||||
 | 
			
		||||
        if (changed_mask != 0) {
 | 
			
		||||
            for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
 | 
			
		||||
                if (((changed_mask >> stage) & 1) != 0) {
 | 
			
		||||
                    if (((stage_mask >> stage) & 1) != 0) {
 | 
			
		||||
                        glEnable(ASSEMBLY_PROGRAM_ENUMS[stage]);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        glDisable(ASSEMBLY_PROGRAM_ENUMS[stage]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
 | 
			
		||||
            if (current_assembly_programs[stage] != programs[stage].handle) {
 | 
			
		||||
                current_assembly_programs[stage] = programs[stage].handle;
 | 
			
		||||
                glBindProgramARB(ASSEMBLY_PROGRAM_ENUMS[stage], programs[stage].handle);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (current_source_program != 0) {
 | 
			
		||||
            current_source_program = 0;
 | 
			
		||||
            glUseProgram(0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RestoreGuestCompute() {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    GLuint bound_program = 0;
 | 
			
		||||
    GLuint current_source_program = 0;
 | 
			
		||||
 | 
			
		||||
    u32 current_assembly_mask = 0;
 | 
			
		||||
    std::array<GLuint, NUM_STAGES> current_assembly_programs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace OpenGL
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user