diff --git a/librashader-reflect/src/back/cross.rs b/librashader-reflect/src/back/cross.rs
index 5ec61bd..32cad71 100644
--- a/librashader-reflect/src/back/cross.rs
+++ b/librashader-reflect/src/back/cross.rs
@@ -6,14 +6,14 @@ use crate::reflect::cross::{CompiledAst, CrossReflect, GlslReflect, HlslReflect}
 use crate::reflect::ReflectShader;
 
 pub type GlVersion = spirv_cross::glsl::Version;
-pub struct GlslangCompileContext {
+pub struct GlslangGlslContext {
     pub texture_fixups: Vec<u32>,
     pub compiler: CompiledAst<spirv_cross::glsl::Target>
 }
 impl FromCompilation<GlslangCompilation> for GLSL {
     type Target = GLSL;
     type Options = GlVersion;
-    type Context = GlslangCompileContext;
+    type Context = GlslangGlslContext;
 
     fn from_compilation(
         compile: GlslangCompilation,
diff --git a/librashader-reflect/src/reflect/cross.rs b/librashader-reflect/src/reflect/cross.rs
index 83c72e0..1c692db 100644
--- a/librashader-reflect/src/reflect/cross.rs
+++ b/librashader-reflect/src/reflect/cross.rs
@@ -15,7 +15,7 @@ use spirv_cross::{glsl, hlsl, ErrorCode};
 
 use crate::back::targets::{GLSL, HLSL};
 use crate::back::{CompileShader, ShaderCompilerOutput};
-use crate::back::cross::GlslangCompileContext;
+use crate::back::cross::GlslangGlslContext;
 
 pub struct CrossReflect<T>
 where
@@ -291,7 +291,6 @@ where
         blame: SemanticErrorBlame,
     ) -> Result<(), ShaderReflectError> {
         let ranges = ast.get_active_buffer_ranges(resource.id)?;
-        eprintln!("{ranges:?}");
         for range in ranges {
             let name = ast.get_member_name(resource.base_type_id, range.index)?;
             let ubo_type = ast.get_type(resource.base_type_id)?;
@@ -333,6 +332,7 @@ where
                             meta.parameter_meta.insert(
                                 parameter.index,
                                 VariableMeta {
+                                    id: name,
                                     offset,
                                     components: typeinfo.size,
                                 },
@@ -360,6 +360,7 @@ where
                             meta.variable_meta.insert(
                                 *semantics,
                                 VariableMeta {
+                                    id: name,
                                     offset,
                                     components: typeinfo.size * typeinfo.columns,
                                 },
@@ -381,6 +382,7 @@ where
                     }
                 }
 
+                // this will break if range is both ubo and push buf whatever
                 let offset = offset_type(range.offset);
                 if let Some(meta) = meta.texture_size_meta.get_mut(&texture) {
                     if offset != meta.offset {
@@ -405,6 +407,7 @@ where
                                 SemanticErrorBlame::Vertex => BindingStage::VERTEX,
                                 SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
                             },
+                            id: name
                         },
                     );
                 }
@@ -683,7 +686,7 @@ where
 
 impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
     type Options = glsl::Version;
-    type Context = GlslangCompileContext;
+    type Context = GlslangGlslContext;
 
     fn compile(
         mut self,
@@ -745,9 +748,9 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
             ));
         }
         for res in &vertex_resources.uniform_buffers {
-            if flatten {
-                self.vertex.flatten_buffer_block(res.id)?;
-            }
+            // if flatten {
+            //     self.vertex.flatten_buffer_block(res.id)?;
+            // }
             self.vertex.set_name(res.id, "RARCH_UBO_VERTEX_INSTANCE")?;
             self.vertex.set_name(res.base_type_id, "RARCH_UBO_VERTEX")?;
             self.vertex
@@ -778,9 +781,9 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
         }
 
         for res in &fragment_resources.uniform_buffers {
-            if flatten {
-                self.fragment.flatten_buffer_block(res.id)?;
-            }
+            // if flatten {
+            //     self.fragment.flatten_buffer_block(res.id)?;
+            // }
             self.fragment
                 .set_name(res.id, "RARCH_UBO_FRAGMENT_INSTANCE")?;
             self.fragment
@@ -806,7 +809,7 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
         Ok(ShaderCompilerOutput {
             vertex: self.vertex.compile()?,
             fragment: self.fragment.compile()?,
-            context: GlslangCompileContext {
+            context: GlslangGlslContext {
                 texture_fixups,
                 compiler: CompiledAst {
                     vertex: self.vertex,
diff --git a/librashader-reflect/src/reflect/semantics.rs b/librashader-reflect/src/reflect/semantics.rs
index 5ea6345..2f3403c 100644
--- a/librashader-reflect/src/reflect/semantics.rs
+++ b/librashader-reflect/src/reflect/semantics.rs
@@ -122,6 +122,7 @@ pub struct VariableMeta {
     // this might bite us in the back because retroarch keeps separate UBO/push offsets.. eh
     pub offset: MemberOffset,
     pub components: u32,
+    pub id: String,
 }
 
 #[derive(Debug)]
@@ -129,6 +130,7 @@ pub struct TextureSizeMeta {
     // this might bite us in the back because retroarch keeps separate UBO/push offsets..
     pub offset: MemberOffset,
     pub stage_mask: BindingStage,
+    pub id: String,
 }
 
 #[derive(Debug)]
diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs
index 4619797..5faeca4 100644
--- a/librashader-runtime-gl/src/lib.rs
+++ b/librashader-runtime-gl/src/lib.rs
@@ -3,18 +3,19 @@ mod hello_triangle;
 use std::collections::HashMap;
 use std::error::Error;
 use std::path::Path;
-use gl::types::{GLenum, GLuint};
+use gl::types::{GLenum, GLint, GLsizeiptr, GLuint};
 use rustc_hash::FxHashMap;
+use spirv_cross::spirv::Decoration;
 
 use librashader::ShaderSource;
 use librashader_presets::ShaderPassConfig;
-use librashader_reflect::back::CompileShader;
-use librashader_reflect::back::cross::GlVersion;
+use librashader_reflect::back::{CompileShader, ShaderCompilerOutput};
+use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
 use librashader_reflect::back::targets::{FromCompilation, GLSL};
 use librashader_reflect::front::shaderc::GlslangCompilation;
 use librashader_reflect::reflect::cross::CrossReflect;
-use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
-use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, VariableSemantics};
+use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, ShaderReflection, UniformSemantic};
+use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableMeta, VariableSemantics};
 use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap};
 
 pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
@@ -52,7 +53,97 @@ pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSema
 
 }
 
+pub struct RingBuffer<T, const SIZE: usize> {
+    items: [T; SIZE],
+    index: usize
+}
 
+impl <T, const SIZE: usize> RingBuffer<T, SIZE>
+where T: Copy, T: Default
+{
+    pub fn new() -> Self {
+        Self {
+            items: [T::default(); SIZE],
+            index: 0
+        }
+    }
+}
+
+impl <T, const SIZE: usize> RingBuffer<T, SIZE> {
+    pub fn current(&self) -> &T {
+        &self.items[self.index]
+    }
+
+    pub fn next(&mut self) {
+        self.index += 1;
+        if self.index >= SIZE {
+            self.index = 0
+        }
+    }
+}
+
+
+#[derive(Debug)]
+pub struct Location<T> {
+    vertex: T,
+    fragment: T,
+}
+
+#[derive(Debug)]
+pub enum ParameterLocation {
+    Ubo(Location<GLint>),
+    Push(Location<GLint>),
+}
+pub struct FilterPass {
+    reflection: ShaderReflection,
+    compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
+    program: GLuint,
+    ubo_location: Location<GLuint>,
+    ubo_ring: Option<RingBuffer<GLuint, 16>>,
+    uniform_buffer: Vec<u8>,
+    push_buffer: Vec<u8>,
+    locations: FxHashMap<String, ParameterLocation>
+}
+
+pub struct FilterChain {
+    reflections: Vec<ShaderReflection>,
+    compiled: Vec<ShaderCompilerOutput<String, GlslangGlslContext>>,
+    programs: Vec<GLuint>,
+    ubo_location: Location<GLint>,
+}
+
+pub fn reflect_parameter(pipeline: GLuint, meta: &VariableMeta) -> ParameterLocation {
+    // todo: support both ubo and pushco
+    // todo: fix this.
+    match meta.offset {
+        MemberOffset::Ubo(_) => {
+            let vert_name = format!("RARCH_UBO_VERTEX_INSTANCE.{}\0", meta.id);
+            let frag_name = format!("RARCH_UBO_FRAGMENT_INSTANCE.{}\0", meta.id);
+            unsafe {
+                let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
+                let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
+
+                ParameterLocation::Ubo(Location {
+                    vertex,
+                    fragment
+                })
+            }
+        }
+        MemberOffset::PushConstant(_) => {
+            let vert_name = format!("RARCH_PUSH_VERTEX_INSTANCE.{}\0", meta.id);
+            let frag_name = format!("RARCH_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id);
+            unsafe {
+                let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
+                let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
+
+                ParameterLocation::Push(Location {
+                    vertex,
+                    fragment
+                })
+            }
+        }
+    }
+}
 // todo: init gl
 
 pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
@@ -96,41 +187,114 @@ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
         non_uniform_semantics: texture_semantics
     };
 
-    let mut reflections = Vec::new();
-    let mut compiled = Vec::new();
+    let mut filters = Vec::new();
 
     for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
         let reflection = reflect.reflect(index as u32, &semantics)?;
         let glsl = reflect.compile(GlVersion::V4_60)?;
 
+        let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?;
 
-        // shader_gl3: 1375
-        reflection.meta.texture_meta.get(&SemanticMap {
-            semantics: TextureSemantics::Source,
-            index: 0
-        }).unwrap().binding;
+        // todo: split this out.
+        let (program, ubo_location) = unsafe {
+            let vertex = gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str());
+            let fragment = gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str());
 
-        // unsafe {
-        //     let vertex = gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str());
-        //     let fragment = gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str());
-        //
-        //     let program = gl::CreateProgram();
-        //     gl::AttachShader(program, vertex);
-        //     gl::AttachShader(program, fragment);
-        //
-        // }
+            let program = gl::CreateProgram();
+            gl::AttachShader(program, vertex);
+            gl::AttachShader(program, fragment);
+
+            for res in &vertex_resources.stage_inputs {
+                let loc = glsl.context.compiler.vertex.get_decoration(res.id, Decoration::Location)?;
+                let loc_name = format!("RARCH_ATTRIBUTE_{loc}");
+                gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
+            }
+            gl::LinkProgram(program);
+            gl::DeleteShader(vertex);
+            gl::DeleteShader(fragment);
+
+            let mut status = 0;
+            gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
+            if status != 1 {
+                panic!("failed to link program")
+            }
+
+            for binding in &glsl.context.texture_fixups {
+                let loc_name = format!("RARCH_TEXTURE_{}", *binding);
+                unsafe {
+                    let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
+                    if location >= 0 {
+                        gl::Uniform1i(location, *binding as GLint);
+                    }
+                }
+            }
+
+            unsafe {
+                gl::UseProgram(0);
+                (program, Location {
+                    vertex: gl::GetUniformBlockIndex(program, b"RARCH_UBO_VERTEX\0".as_ptr().cast()),
+                    fragment:  gl::GetUniformBlockIndex(program, b"RARCH_UBO_FRAGMENT\0".as_ptr().cast()),
+                })
+            }
+        };
+
+        let ubo_ring = if let Some(ubo) = &reflection.ubo {
+            let size = ubo.size;
+            let mut ring: RingBuffer<GLuint, 16> = RingBuffer::new();
+            unsafe {
+                gl::GenBuffers(16, ring.items.as_mut_ptr());
+                for buffer in &ring.items {
+                    gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
+                    gl::BufferData(gl::UNIFORM_BUFFER, size as GLsizeiptr, std::ptr::null(), gl::STREAM_DRAW);
+                }
+                gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
+            }
+            Some(ring)
+        } else {
+            None
+        };
+
+        let uniform_buffer = vec![0; reflection.ubo.as_ref().map(|ubo| ubo.size as usize).unwrap_or(0)];
+        let push_buffer =  vec![0; reflection.push_constant.as_ref().map(|push| push.size as usize).unwrap_or(0)];
+
+        // todo: reflect indexed parameters
+        let mut locations = FxHashMap::default();
+        for param in reflection.meta.parameter_meta.values() {
+            locations.insert(param.id.clone(), reflect_parameter(program, param));
+        }
+
+        for param in reflection.meta.variable_meta.values() {
+            locations.insert(param.id.clone(), reflect_parameter(program, param));
+        }
 
 
-        compiled.push(glsl);
-        reflections.push(reflection);
+        eprintln!("{:#?}", semantics);
+        eprintln!("{:#?}", reflection.meta);
+        eprintln!("{:#?}", locations);
+        eprintln!("{:#?}", reflection.push_constant);
+        eprintln!("====fragment====");
+        eprintln!("{:#}", glsl.fragment);
+        eprintln!("====vertex====");
+        eprintln!("{:#}", glsl.vertex);
+
+        filters.push(FilterPass {
+            reflection,
+            compiled: glsl,
+            program,
+            ubo_location,
+            ubo_ring,
+            uniform_buffer,
+            push_buffer,
+            locations
+        });
     }
 
-    let mut glprogram: Vec<GLuint> = Vec::new();
-    for compilation in &compiled {
-        // compilation.context.compiler.vertex
-    }
+    // let mut glprogram: Vec<GLuint> = Vec::new();
+    // for compilation in &compiled {
+    //     // compilation.context.compiler.vertex
+    // }
 
-    eprintln!("{:#?}", reflections);
+//    eprintln!("{:#?}", reflections);
 
     // eprintln!("{:#?}", compiled./);
     // eprintln!("{:?}", preset);
@@ -164,13 +328,15 @@ mod tests {
     #[test]
     fn triangle() {
         let (glfw, window, events, shader, vao) = hello_triangle::setup();
+            load("../test/basic.slangp")
+                .unwrap();
         hello_triangle::do_loop(glfw, window, events, shader, vao);
     }
 
-    #[test]
-    fn load_preset() {
-
-        load("../test/basic.slangp")
-            .unwrap();
-    }
+    // #[test]
+    // fn load_preset() {
+    //
+    //     load("../test/basic.slangp")
+    //         .unwrap();
+    // }
 }