diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index e9194d3487..09c2ce3ea5 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -177,7 +177,7 @@ impl super::Adapter { naga::back::glsl::Version::Embedded(value) }; - let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE; + let mut features = wgt::Features::empty(); features.set( wgt::Features::DEPTH_CLAMPING, extensions.contains("GL_EXT_depth_clamp"), @@ -283,7 +283,7 @@ impl super::Adapter { impl crate::Adapter for super::Adapter { unsafe fn open( &self, - _features: wgt::Features, + features: wgt::Features, ) -> Result, crate::DeviceError> { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); @@ -300,6 +300,7 @@ impl crate::Adapter for super::Adapter { }, queue: super::Queue { shared: Arc::clone(&self.shared), + features, draw_fbo: gl .create_framebuffer() .map_err(|_| crate::DeviceError::OutOfMemory)?, diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 769078f023..e97e0fcbe9 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -18,6 +18,7 @@ struct TextureSlotDesc { #[derive(Default)] pub(super) struct State { topology: u32, + primitive: super::PrimitiveState, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, vertex_buffers: [(super::VertexBufferDesc, super::BufferBinding); crate::MAX_VERTEX_BUFFERS], @@ -27,6 +28,9 @@ pub(super) struct State { depth_bias: wgt::DepthBiasState, samplers: [Option; super::MAX_SAMPLERS], texture_slots: [TextureSlotDesc; super::MAX_TEXTURE_SLOTS], + render_size: wgt::Extent3d, + resolve_attachments: ArrayVec<[(u32, super::TextureView); crate::MAX_COLOR_TARGETS]>, + invalidate_attachments: ArrayVec<[u32; crate::MAX_COLOR_TARGETS + 2]>, has_pass_label: bool, dirty: Dirty, } @@ -223,12 +227,14 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { + //TODO: preserve `src.target` and `dst.target` + // at least for the buffers that require it. for copy in regions { self.cmd_buffer.commands.push(C::CopyBufferToBuffer { src: src.raw, - src_target: src.target, + src_target: glow::COPY_READ_BUFFER, dst: dst.raw, - dst_target: dst.target, + dst_target: glow::COPY_WRITE_BUFFER, copy, }) } @@ -357,6 +363,9 @@ impl crate::CommandEncoder for super::CommandEncoder { // render unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) { + self.state.render_size = desc.extent; + self.state.resolve_attachments.clear(); + self.state.invalidate_attachments.clear(); if let Some(label) = desc.label { let range = self.cmd_buffer.add_marker(label); self.cmd_buffer.commands.push(C::PushDebugGroup(range)); @@ -367,21 +376,44 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::ResetFramebuffer); for (i, cat) in desc.color_attachments.iter().enumerate() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; - self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: cat.target.view.clone(), }); + if let Some(ref rat) = cat.resolve_target { + self.state + .resolve_attachments + .push((attachment, rat.view.clone())); + } + if !cat.ops.contains(crate::AttachmentOp::STORE) { + self.state.invalidate_attachments.push(attachment); + } } if let Some(ref dsat) = desc.depth_stencil_attachment { - let attachment = match dsat.target.view.aspects { + let aspects = dsat.target.view.aspects; + let attachment = match aspects { crate::FormatAspect::DEPTH => glow::DEPTH_ATTACHMENT, crate::FormatAspect::STENCIL => glow::STENCIL_ATTACHMENT, _ => glow::DEPTH_STENCIL_ATTACHMENT, }; - self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: dsat.target.view.clone(), }); + if aspects.contains(crate::FormatAspect::DEPTH) + && !dsat.depth_ops.contains(crate::AttachmentOp::STORE) + { + self.state + .invalidate_attachments + .push(glow::DEPTH_ATTACHMENT); + } + if aspects.contains(crate::FormatAspect::STENCIL) + && !dsat.stencil_ops.contains(crate::AttachmentOp::STORE) + { + self.state + .invalidate_attachments + .push(glow::STENCIL_ATTACHMENT); + } } // set the draw buffers and states @@ -437,6 +469,19 @@ impl crate::CommandEncoder for super::CommandEncoder { } } unsafe fn end_render_pass(&mut self) { + for (attachment, dst) in self.state.resolve_attachments.drain(..) { + self.cmd_buffer.commands.push(C::ResolveAttachment { + attachment, + dst, + size: self.state.render_size, + }); + } + if !self.state.invalidate_attachments.is_empty() { + self.cmd_buffer.commands.push(C::InvalidateAttachments( + self.state.invalidate_attachments.clone(), + )); + self.state.invalidate_attachments.clear(); + } if self.state.has_pass_label { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; @@ -444,6 +489,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.dirty = Dirty::empty(); self.state.color_targets.clear(); self.state.vertex_attributes.clear(); + self.state.primitive = super::PrimitiveState::default(); } unsafe fn set_bind_group( @@ -562,6 +608,15 @@ impl crate::CommandEncoder for super::CommandEncoder { state_desc.stride = pipe_desc.stride; } + // set primitive state + let prim_state = conv::map_primitive_state(&pipeline.primitive); + if prim_state != self.state.primitive { + self.cmd_buffer + .commands + .push(C::SetPrimitive(prim_state.clone())); + self.state.primitive = prim_state; + } + // set depth/stencil states let mut aspects = crate::FormatAspect::empty(); if pipeline.depth_bias != self.state.depth_bias { diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 0fe545d856..8da57e2704 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -222,6 +222,22 @@ pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 { } } +pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::PrimitiveState { + //Note: state.polygon_mode is not supported, see `Features::NON_FILL_POLYGON_MODE` + super::PrimitiveState { + front_face: match state.front_face { + wgt::FrontFace::Cw => glow::CW, + wgt::FrontFace::Ccw => glow::CCW, + }, + cull_face: match state.cull_mode { + Some(wgt::Face::Front) => glow::FRONT, + Some(wgt::Face::Back) => glow::BACK, + None => 0, + }, + clamp_depth: state.clamp_depth, + } +} + pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { use wgt::TextureViewDimension as Tvd; match dim { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 55ad914e72..3a0d24a516 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -218,7 +218,13 @@ impl super::Device { } super::BindingRegister::StorageBuffers => { let index = gl.get_shader_storage_block_index(program, name).unwrap(); - gl.shader_storage_block_binding(program, index, slot as _); + log::error!( + "Unable to re-map shader storage block {} to {}", + name, + index + ); + //gl.shader_storage_block_binding(program, index, slot as _); + return Err(crate::DeviceError::Lost.into()); } super::BindingRegister::Textures | super::BindingRegister::Images => { let loc = gl.get_uniform_location(program, name).unwrap(); @@ -279,12 +285,18 @@ impl crate::Device for super::Device { glow::ARRAY_BUFFER }; - let mut map_flags = glow::MAP_PERSISTENT_BIT; + let mut map_flags = 0; if desc - .memory_flags - .contains(crate::MemoryFlag::PREFER_COHERENT) + .usage + .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) { - map_flags |= glow::MAP_COHERENT_BIT; + map_flags |= glow::MAP_PERSISTENT_BIT; + if desc + .memory_flags + .contains(crate::MemoryFlag::PREFER_COHERENT) + { + map_flags |= glow::MAP_COHERENT_BIT; + } } if desc.usage.contains(crate::BufferUse::MAP_READ) { map_flags |= glow::MAP_READ_BIT; @@ -321,18 +333,24 @@ impl crate::Device for super::Device { ) -> Result { let gl = &self.shared.context; + let is_coherent = buffer.map_flags & glow::MAP_COHERENT_BIT != 0; + let mut flags = buffer.map_flags | glow::MAP_UNSYNCHRONIZED_BIT; + if !is_coherent { + flags |= glow::MAP_FLUSH_EXPLICIT_BIT; + } + gl.bind_buffer(buffer.target, Some(buffer.raw)); let ptr = gl.map_buffer_range( buffer.target, range.start as i32, (range.end - range.start) as i32, - buffer.map_flags, + flags, ); gl.bind_buffer(buffer.target, None); Ok(crate::BufferMapping { ptr: NonNull::new(ptr).ok_or(crate::DeviceError::Lost)?, - is_coherent: buffer.map_flags & glow::MAP_COHERENT_BIT != 0, + is_coherent, }) } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { @@ -347,6 +365,7 @@ impl crate::Device for super::Device { I: Iterator, { let gl = &self.shared.context; + gl.bind_buffer(buffer.target, Some(buffer.raw)); for range in ranges { gl.flush_mapped_buffer_range( buffer.target, @@ -360,6 +379,7 @@ impl crate::Device for super::Device { I: Iterator, { let gl = &self.shared.context; + gl.bind_buffer(buffer.target, Some(buffer.raw)); for range in ranges { gl.invalidate_buffer_sub_data( buffer.target, @@ -402,6 +422,8 @@ impl crate::Device for super::Device { desc.size.height as i32, ); } + + gl.bind_renderbuffer(glow::RENDERBUFFER, None); super::TextureInner::Renderbuffer { raw } } else { let raw = gl.create_texture().unwrap(); @@ -453,6 +475,20 @@ impl crate::Device for super::Device { target } }; + + match desc.format.describe().sample_type { + wgt::TextureSampleType::Float { filterable: false } + | wgt::TextureSampleType::Uint + | wgt::TextureSampleType::Sint => { + // reset default filtering mode + gl.tex_parameter_i32(target, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + gl.tex_parameter_i32(target, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + } + wgt::TextureSampleType::Float { filterable: true } + | wgt::TextureSampleType::Depth => {} + } + + gl.bind_texture(target, None); super::TextureInner::Texture { raw, target } }; diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 33e9d83f36..a587ef9157 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -205,7 +205,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m message ); - if log_severity == log::Level::Error && false { + if cfg!(debug_assertions) && log_severity == log::Level::Error { std::process::exit(1); } } @@ -558,7 +558,7 @@ impl crate::Instance for Instance { if ret != 0 { log::error!("Error returned from ANativeWindow_setBuffersGeometry"); - return Err(w::InitError::UnsupportedWindowHandle); + return Err(crate::InstanceError); } } @@ -665,6 +665,7 @@ impl Surface { crate::SurfaceError::Lost })?; + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)); gl.blit_framebuffer( 0, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index f25b7ed993..21d7d82c02 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -97,6 +97,7 @@ pub struct Device { pub struct Queue { shared: Arc, + features: wgt::Features, draw_fbo: glow::Framebuffer, copy_fbo: glow::Framebuffer, temp_query_results: Vec, @@ -397,6 +398,15 @@ struct StencilState { back: StencilSide, } +#[derive(Clone, Debug, Default, PartialEq)] +struct PrimitiveState { + front_face: u32, + cull_face: u32, + clamp_depth: bool, +} + +type InvalidatedAttachments = arrayvec::ArrayVec<[u32; crate::MAX_COLOR_TARGETS + 2]>; + #[derive(Debug)] enum Command { Draw { @@ -474,10 +484,16 @@ enum Command { dst_offset: wgt::BufferAddress, }, ResetFramebuffer, - SetFramebufferAttachment { + BindAttachment { attachment: u32, view: TextureView, }, + ResolveAttachment { + attachment: u32, + dst: TextureView, + size: wgt::Extent3d, + }, + InvalidateAttachments(InvalidatedAttachments), SetDrawColorBuffers(u8), ClearColorF(u32, [f32; 4]), ClearColorU(u32, [u32; 4]), @@ -511,6 +527,7 @@ enum Command { attribute_desc: AttributeDesc, }, SetProgram(glow::Program), + SetPrimitive(PrimitiveState), SetBlendConstant([f32; 4]), SetColorTarget { draw_buffer_index: Option, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 214a644554..c7284290a9 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -26,6 +26,39 @@ impl super::Queue { gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); gl.disable(glow::BLEND); + gl.disable(glow::CULL_FACE); + gl.disable(glow::POLYGON_OFFSET_FILL); + if self.features.contains(wgt::Features::DEPTH_CLAMPING) { + gl.disable(glow::DEPTH_CLAMP); + } + } + + unsafe fn set_attachment(&self, fbo_target: u32, attachment: u32, view: &super::TextureView) { + let gl = &self.shared.context; + match view.inner { + super::TextureInner::Renderbuffer { raw } => { + gl.framebuffer_renderbuffer(fbo_target, attachment, glow::RENDERBUFFER, Some(raw)); + } + super::TextureInner::Texture { raw, target } => { + if is_3d_target(target) { + gl.framebuffer_texture_layer( + fbo_target, + attachment, + Some(raw), + view.mip_levels.start as i32, + view.array_layers.start as i32, + ); + } else { + gl.framebuffer_texture_2d( + fbo_target, + attachment, + target, + Some(raw), + view.mip_levels.start as i32, + ); + } + } + } } unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) { @@ -329,38 +362,39 @@ impl super::Queue { gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); } - C::SetFramebufferAttachment { + C::BindAttachment { attachment, ref view, - } => match view.inner { - super::TextureInner::Renderbuffer { raw } => { - gl.framebuffer_renderbuffer( - glow::DRAW_FRAMEBUFFER, - attachment, - glow::RENDERBUFFER, - Some(raw), - ); - } - super::TextureInner::Texture { raw, target } => { - if is_3d_target(target) { - gl.framebuffer_texture_layer( - glow::DRAW_FRAMEBUFFER, - attachment, - Some(raw), - view.mip_levels.start as i32, - view.array_layers.start as i32, - ); - } else { - gl.framebuffer_texture_2d( - glow::DRAW_FRAMEBUFFER, - attachment, - target, - Some(raw), - view.mip_levels.start as i32, - ); - } - } - }, + } => { + self.set_attachment(glow::DRAW_FRAMEBUFFER, attachment, view); + } + C::ResolveAttachment { + attachment, + ref dst, + ref size, + } => { + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)); + gl.read_buffer(attachment); + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)); + self.set_attachment(glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst); + gl.blit_framebuffer( + 0, + 0, + size.width as i32, + size.height as i32, + 0, + 0, + size.width as i32, + size.height as i32, + glow::COLOR_BUFFER_BIT, + glow::NEAREST, + ); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); + } + C::InvalidateAttachments(ref list) => { + gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list); + } C::SetDrawColorBuffers(count) => { let indices = (0..count as u32) .map(|i| glow::COLOR_ATTACHMENT0 + i) @@ -380,10 +414,10 @@ impl super::Queue { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, &mut color); } C::ClearDepth(depth) => { - gl.clear_buffer_depth_stencil(glow::DEPTH, 0, depth, 0); + gl.clear_buffer_f32_slice(glow::DEPTH, 0, &mut [depth]); } C::ClearStencil(value) => { - gl.clear_buffer_depth_stencil(glow::STENCIL, 0, 0.0, value as i32); + gl.clear_buffer_i32_slice(glow::STENCIL, 0, &mut [value as i32]); } C::BufferBarrier(raw, usage) => { let mut flags = 0; @@ -502,7 +536,12 @@ impl super::Queue { gl.depth_mask(depth.mask); } C::SetDepthBias(bias) => { - gl.polygon_offset(bias.constant as f32, bias.slope_scale); + if bias.is_enabled() { + gl.enable(glow::POLYGON_OFFSET_FILL); + gl.polygon_offset(bias.constant as f32, bias.slope_scale); + } else { + gl.disable(glow::POLYGON_OFFSET_FILL); + } } C::ConfigureDepthStencil(aspects) => { if aspects.contains(crate::FormatAspect::DEPTH) { @@ -519,6 +558,22 @@ impl super::Queue { C::SetProgram(program) => { gl.use_program(Some(program)); } + C::SetPrimitive(ref state) => { + gl.front_face(state.front_face); + if state.cull_face != 0 { + gl.enable(glow::CULL_FACE); + gl.cull_face(state.cull_face); + } else { + gl.disable(glow::CULL_FACE); + } + if self.features.contains(wgt::Features::DEPTH_CLAMPING) { + if state.clamp_depth { + gl.enable(glow::DEPTH_CLAMP); + } else { + gl.disable(glow::DEPTH_CLAMP); + } + } + } C::SetBlendConstant(c) => { gl.blend_color(c[0], c[1], c[2], c[3]); }