use js_sys::Uint32Array;
use web_sys::WebGl2RenderingContext as Gl;
use crate::rendering::render_target::RenderTargetData;
use crate::rendering::StoreOp;
use crate::runtime::state::{ContextUpdate, DepthStencilAttachmentDescriptor, DynamicState};
use crate::runtime::Connection;
use crate::task::{ContextId, GpuTask, Progress};
#[derive(Clone)]
pub struct RenderPass<T> {
pub(crate) id: u64,
pub(crate) context_id: u64,
pub(crate) render_target: RenderTargetData,
pub(crate) task: T,
}
pub struct RenderPassContext {
connection: *mut Connection,
render_pass_id: u64,
}
impl RenderPassContext {
pub fn render_pass_id(&self) -> u64 {
self.render_pass_id
}
pub(crate) fn connection_mut(&mut self) -> &mut Connection {
unsafe { &mut *self.connection }
}
pub unsafe fn unpack(&self) -> (&Gl, &DynamicState) {
(*self.connection).unpack()
}
pub unsafe fn unpack_mut(&mut self) -> (&mut Gl, &mut DynamicState) {
(*self.connection).unpack_mut()
}
}
unsafe impl<T, O> GpuTask<Connection> for RenderPass<T>
where
T: GpuTask<RenderPassContext, Output = O>,
{
type Output = O;
fn context_id(&self) -> ContextId {
ContextId::Id(self.context_id)
}
fn progress(&mut self, connection: &mut Connection) -> Progress<Self::Output> {
let (gl, state) = unsafe { connection.unpack_mut() };
match &self.render_target {
RenderTargetData::Default => {
state.bind_draw_framebuffer(None).apply(gl).unwrap();
self.task.progress(&mut RenderPassContext {
connection,
render_pass_id: self.id,
})
}
RenderTargetData::Custom(data) => {
state
.framebuffer_cache_mut()
.bind_or_create(data, gl)
.set_draw_buffers(data.draw_buffers());
for i in 0..data.color_count {
data.load_ops[i].perform(gl);
}
if &data.depth_stencil_attachment != &DepthStencilAttachmentDescriptor::None {
data.load_ops[16].perform(gl);
}
let output = self.task.progress(&mut RenderPassContext {
connection,
render_pass_id: self.id,
});
let mut invalidate_buffers = [0; 17];
let mut invalidate_counter = 0;
for i in 0..data.color_count {
if data.store_ops[i] == StoreOp::DontCare {
invalidate_buffers[invalidate_counter] = Gl::COLOR_ATTACHMENT0 + i as u32;
invalidate_counter += 1;
}
}
if let Some(buffer_id) = match &data.depth_stencil_attachment {
DepthStencilAttachmentDescriptor::DepthStencil(_) => {
Some(Gl::DEPTH_STENCIL_ATTACHMENT)
}
DepthStencilAttachmentDescriptor::Depth(_) => Some(Gl::DEPTH_ATTACHMENT),
DepthStencilAttachmentDescriptor::Stencil(_) => Some(Gl::STENCIL_ATTACHMENT),
DepthStencilAttachmentDescriptor::None => None,
} {
if data.store_ops[16] == StoreOp::DontCare {
invalidate_buffers[invalidate_counter] = buffer_id;
invalidate_counter += 1;
}
}
if invalidate_counter > 0 {
let (gl, _) = unsafe { connection.unpack() };
let array =
unsafe { Uint32Array::view(&invalidate_buffers[0..invalidate_counter]) };
gl.invalidate_framebuffer(Gl::DRAW_FRAMEBUFFER, array.as_ref())
.unwrap();
}
output
}
}
}
}