librashader-runtime-gl 0.11.4

RetroArch shaders for all.
Documentation
use crate::binding::UniformLocation;
use crate::error;
use crate::error::FilterChainError;
use crate::gl::UboRing;
use glow::HasContext;
use librashader_reflect::reflect::semantics::BufferReflection;
use librashader_runtime::ringbuffer::InlineRingBuffer;
use librashader_runtime::ringbuffer::RingBuffer;
use librashader_runtime::uniforms::UniformStorageAccess;

pub struct Gl3UboRing<const SIZE: usize> {
    ring: InlineRingBuffer<glow::Buffer, SIZE>,
}

impl<const SIZE: usize> UboRing<SIZE> for Gl3UboRing<SIZE> {
    fn new(ctx: &glow::Context, buffer_size: u32) -> error::Result<Self> {
        let items: [glow::Buffer; SIZE] = array_init::try_array_init(|_| unsafe {
            ctx.create_buffer().map(|buffer| {
                ctx.bind_buffer(glow::UNIFORM_BUFFER, Some(buffer));
                ctx.buffer_data_size(glow::UNIFORM_BUFFER, buffer_size as i32, glow::STREAM_DRAW);
                ctx.bind_buffer(glow::UNIFORM_BUFFER, None);
                buffer
            })
        })
        .map_err(FilterChainError::GlError)?;

        let ring: InlineRingBuffer<glow::Buffer, SIZE> = InlineRingBuffer::from_array(items);
        Ok(Gl3UboRing { ring })
    }

    fn bind_for_frame(
        &mut self,
        ctx: &glow::Context,
        ubo: &BufferReflection<u32>,
        ubo_location: &UniformLocation<Option<u32>>,
        storage: &impl UniformStorageAccess,
    ) {
        let buffer = *self.ring.current();

        unsafe {
            ctx.bind_buffer(glow::UNIFORM_BUFFER, Some(buffer));
            ctx.buffer_sub_data_u8_slice(
                glow::UNIFORM_BUFFER,
                0,
                &storage.ubo_slice()[0..ubo.size as usize],
            );
            ctx.bind_buffer(glow::UNIFORM_BUFFER, None);

            if let Some(vertex) = ubo_location
                .vertex
                .filter(|vertex| *vertex != glow::INVALID_INDEX)
            {
                ctx.bind_buffer_base(glow::UNIFORM_BUFFER, vertex, Some(buffer));
            }
            if let Some(fragment) = ubo_location
                .fragment
                .filter(|fragment| *fragment != glow::INVALID_INDEX)
            {
                ctx.bind_buffer_base(glow::UNIFORM_BUFFER, fragment, Some(buffer));
            }
        }
        self.ring.next()
    }
}