--- /dev/null
+#ifndef MSP_GL_PROGRAM_BACKEND_H_
+#define MSP_GL_PROGRAM_BACKEND_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include "reflectdata.h"
+
+namespace Msp {
+namespace GL {
+
+class OpenGLProgram
+{
+ friend class OpenGLPipelineState;
+
+protected:
+ enum Stage
+ {
+ VERTEX,
+ GEOMETRY,
+ FRAGMENT,
+ MAX_STAGES
+ };
+
+ struct TransientData
+ {
+ std::map<std::string, unsigned> textures;
+ std::map<std::string, unsigned> blocks;
+ std::map<unsigned, int> spec_values;
+ };
+
+ struct UniformCall
+ {
+ using FuncPtr = void (*)(unsigned, unsigned, const void *);
+
+ unsigned location;
+ unsigned size;
+ FuncPtr func;
+
+ UniformCall(unsigned l, unsigned s, FuncPtr f): location(l), size(s), func(f) { }
+ };
+
+ unsigned id;
+ unsigned stage_ids[MAX_STAGES];
+ bool linked;
+ std::vector<UniformCall> uniform_calls;
+ std::string debug_name;
+
+ OpenGLProgram();
+ ~OpenGLProgram();
+
+ bool has_stages() const;
+ unsigned add_stage(Stage);
+ void add_glsl_stages(const GlslModule &, const std::map<std::string, int> &, TransientData &);
+ void compile_glsl_stage(const GlslModule &, unsigned);
+ void add_spirv_stages(const SpirVModule &, const std::map<std::string, int> &, TransientData &);
+
+ void finalize(const Module &);
+ void query_uniforms();
+ void query_uniform_blocks(const std::vector<ReflectData::UniformInfo *> &);
+ void query_attributes();
+ void apply_bindings(const TransientData &);
+
+ void set_debug_name(const std::string &);
+ void set_stage_debug_name(unsigned, Stage);
+};
+
+using ProgramBackend = OpenGLProgram;
+
+} // namespace GL
+} // namespace Msp
+
+#endif