diff --git a/alvr/client_core/resources/staging_vertex.glsl b/alvr/client_core/resources/staging_vertex.glsl index be190bf6a8..10df236a61 100644 --- a/alvr/client_core/resources/staging_vertex.glsl +++ b/alvr/client_core/resources/staging_vertex.glsl @@ -1,8 +1,11 @@ #version 300 es +uniform int view_idx; + out vec2 uv; void main() { - uv = vec2(gl_VertexID & 1, gl_VertexID >> 1); - gl_Position = vec4((uv - 0.5f) * 2.f, 0, 1); + vec2 screen_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1); + gl_Position = vec4((screen_uv - 0.5f) * 2.f, 0, 1); + uv = vec2((screen_uv.x + float(view_idx)) / 2.f, screen_uv.y); } diff --git a/alvr/client_core/resources/stream.wgsl b/alvr/client_core/resources/stream.wgsl index c7ee43ee42..922e8359db 100644 --- a/alvr/client_core/resources/stream.wgsl +++ b/alvr/client_core/resources/stream.wgsl @@ -12,8 +12,6 @@ override FIX_LIMITED_RANGE: bool; override ENABLE_SRGB_CORRECTION: bool; override ENCODING_GAMMA: f32; -var view_idx: u32; - struct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f, @@ -27,8 +25,8 @@ fn vertex_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput { var result: VertexOutput; let screen_uv = vec2f(f32(vertex_index & 1), f32(vertex_index >> 1)); - result.position = vec4f((screen_uv - vec2f(0.5, 0.5)) * 2.0, 0.0, 1.0); - result.uv = vec2f((screen_uv.x + f32(view_idx)) / 2.0, screen_uv.y); + result.position = vec4f((screen_uv - 0.5) * 2.0, 0.0, 1.0); + result.uv = vec2f(screen_uv.x, screen_uv.y); return result; } diff --git a/alvr/client_core/src/graphics/staging.rs b/alvr/client_core/src/graphics/staging.rs index 2ffe683b77..426f551bc8 100644 --- a/alvr/client_core/src/graphics/staging.rs +++ b/alvr/client_core/src/graphics/staging.rs @@ -51,16 +51,17 @@ fn create_program( pub struct StagingRenderer { context: Rc, program: gl::Program, + view_idx_uloc: gl::UniformLocation, surface_texture: gl::Texture, - framebuffer: gl::Framebuffer, + framebuffers: [gl::Framebuffer; 2], viewport_size: IVec2, } impl StagingRenderer { pub fn new( context: Rc, - staging_texture: gl::Texture, - resolution: UVec2, + staging_textures: [gl::Texture; 2], + view_resolution: UVec2, ) -> Self { let gl = &context.gl_context; context.make_current(); @@ -75,23 +76,32 @@ impl StagingRenderer { // This is an external surface and storage should not be initialized let surface_texture = ck!(gl.create_texture().unwrap()); - let framebuffer = ck!(gl.create_framebuffer().unwrap()); - ck!(gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(framebuffer))); - ck!(gl.framebuffer_texture_2d( - gl::DRAW_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - Some(staging_texture), - 0, - )); + let mut framebuffers = vec![]; + for tex in staging_textures { + let framebuffer = ck!(gl.create_framebuffer().unwrap()); + ck!(gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(framebuffer))); + ck!(gl.framebuffer_texture_2d( + gl::DRAW_FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + gl::TEXTURE_2D, + Some(tex), + 0, + )); + + framebuffers.push(framebuffer); + } + ck!(gl.bind_framebuffer(gl::FRAMEBUFFER, None)); + let view_idx_uloc = ck!(gl.get_uniform_location(program, "view_idx")).unwrap(); + Self { context, program, surface_texture, - framebuffer, - viewport_size: resolution.as_ivec2(), + view_idx_uloc, + framebuffers: framebuffers.try_into().unwrap(), + viewport_size: view_resolution.as_ivec2(), } } } @@ -109,12 +119,15 @@ impl StagingRenderer { ck!(gl.viewport(0, 0, self.viewport_size.x, self.viewport_size.y)); - ck!(gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(self.framebuffer))); + for (i, framebuffer) in self.framebuffers.iter().enumerate() { + ck!(gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(*framebuffer))); - ck!(gl.active_texture(gl::TEXTURE0)); - ck!(gl.bind_texture(GL_TEXTURE_EXTERNAL_OES, Some(self.surface_texture))); - ck!(gl.bind_sampler(0, None)); - ck!(gl.draw_arrays(gl::TRIANGLE_STRIP, 0, 4)); + ck!(gl.active_texture(gl::TEXTURE0)); + ck!(gl.bind_texture(GL_TEXTURE_EXTERNAL_OES, Some(self.surface_texture))); + ck!(gl.bind_sampler(0, None)); + ck!(gl.uniform_1_i32(Some(&self.view_idx_uloc), i as i32)); + ck!(gl.draw_arrays(gl::TRIANGLE_STRIP, 0, 4)); + } }, ); } @@ -128,7 +141,9 @@ impl Drop for StagingRenderer { unsafe { ck!(gl.delete_program(self.program)); ck!(gl.delete_texture(self.surface_texture)); - ck!(gl.delete_framebuffer(self.framebuffer)); + for framebuffer in &self.framebuffers { + ck!(gl.delete_framebuffer(*framebuffer)); + } } } } diff --git a/alvr/client_core/src/graphics/stream.rs b/alvr/client_core/src/graphics/stream.rs index b6053aab70..778919d73e 100644 --- a/alvr/client_core/src/graphics/stream.rs +++ b/alvr/client_core/src/graphics/stream.rs @@ -7,17 +7,21 @@ use wgpu::{ include_wgsl, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, ColorTargetState, ColorWrites, FragmentState, LoadOp, PipelineCompilationOptions, PipelineLayoutDescriptor, PrimitiveState, - PrimitiveTopology, PushConstantRange, RenderPassColorAttachment, RenderPassDescriptor, - RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, - StoreOp, TextureSampleType, TextureView, TextureViewDescriptor, TextureViewDimension, - VertexState, + PrimitiveTopology, RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, + RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, StoreOp, + TextureSampleType, TextureView, TextureViewDescriptor, TextureViewDimension, VertexState, }; +#[derive(Debug)] +struct ViewObjects { + bind_group: BindGroup, + render_target: Vec, +} + struct RenderObjects { staging_renderer: StagingRenderer, pipeline: RenderPipeline, - bind_group: BindGroup, - render_targets: [Vec; 2], + views_objects: [ViewObjects; 2], } pub struct StreamRenderer { @@ -73,13 +77,9 @@ impl StreamRenderer { } } else { let device = &context.device; - let gl = &context.gl_context; - let staging_resolution = UVec2::new(view_resolution.x * 2, view_resolution.y); let target_format = super::gl_format_to_wgpu(target_format); - let staging_texture = super::create_texture(device, staging_resolution, target_format); - let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor { label: None, entries: &[ @@ -120,10 +120,7 @@ impl StreamRenderer { layout: Some(&device.create_pipeline_layout(&PipelineLayoutDescriptor { label: None, bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[PushConstantRange { - stages: ShaderStages::VERTEX_FRAGMENT, - range: 0..4, - }], + push_constant_ranges: &[], })), vertex: VertexState { module: &shader_module, @@ -156,63 +153,70 @@ impl StreamRenderer { multiview: None, }); - let bind_group = device.create_bind_group(&BindGroupDescriptor { - label: None, - layout: &bind_group_layout, - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView( - &staging_texture.create_view(&TextureViewDescriptor::default()), - ), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&device.create_sampler( - &SamplerDescriptor { - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - ..Default::default() - }, - )), - }, - ], + let sampler = device.create_sampler(&SamplerDescriptor { + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + ..Default::default() }); - let render_targets = [ - super::create_gl_swapchain( - device, - &swapchain_textures[0], - view_resolution, - target_format, - ), - super::create_gl_swapchain( + let mut view_objects = vec![]; + let mut staging_textures_gl = vec![]; + for i in 0..2 { + let staging_texture = + super::create_texture(&device, view_resolution, target_format); + + let staging_texture_gl = unsafe { + staging_texture.as_hal::(|tex| { + let gles::TextureInner::Texture { raw, .. } = tex.unwrap().inner else { + panic!("invalid texture type"); + }; + raw + }) + }; + + let bind_group = device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bind_group_layout, + entries: &[ + BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView( + &staging_texture.create_view(&TextureViewDescriptor::default()), + ), + }, + BindGroupEntry { + binding: 1, + resource: BindingResource::Sampler(&sampler), + }, + ], + }); + + let render_target = super::create_gl_swapchain( device, - &swapchain_textures[1], + &swapchain_textures[i], view_resolution, target_format, - ), - ]; + ); - let staging_texture_gl = unsafe { - staging_texture.as_hal::(|tex| { - let gles::TextureInner::Texture { raw, .. } = tex.unwrap().inner else { - panic!("invalid texture type"); - }; - raw - }) - }; + view_objects.push(ViewObjects { + bind_group, + render_target, + }); + staging_textures_gl.push(staging_texture_gl); + } - let staging_renderer = - StagingRenderer::new(Rc::clone(&context), staging_texture_gl, staging_resolution); + let staging_renderer = StagingRenderer::new( + Rc::clone(&context), + staging_textures_gl.try_into().unwrap(), + view_resolution, + ); Self { context, render_objects: Some(RenderObjects { staging_renderer, pipeline, - bind_group, - render_targets, + views_objects: view_objects.try_into().unwrap(), }), } } @@ -235,7 +239,7 @@ impl StreamRenderer { let mut render_pass = encoder.begin_render_pass(&RenderPassDescriptor { label: None, color_attachments: &[Some(RenderPassColorAttachment { - view: &self.render_objects.as_ref().unwrap().render_targets[view_idx] + view: &render_objects.views_objects[view_idx].render_target [*swapchain_idx as usize], resolve_target: None, ops: wgpu::Operations { @@ -246,17 +250,12 @@ impl StreamRenderer { ..Default::default() }); - render_pass.set_pipeline(&self.render_objects.as_ref().unwrap().pipeline); + render_pass.set_pipeline(&render_objects.pipeline); render_pass.set_bind_group( 0, - &self.render_objects.as_ref().unwrap().bind_group, + &render_objects.views_objects[view_idx].bind_group, &[], ); - render_pass.set_push_constants( - ShaderStages::VERTEX_FRAGMENT, - 0, - &(view_idx as u32).to_le_bytes(), - ); render_pass.draw(0..4, 0..1); }