From 91df1574629128081a40b7c26eee2e7a589dabc3 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 00:52:12 -0400 Subject: [PATCH] Refactor downlevel support a bit, implement blending for hal/gles --- wgpu-core/src/command/compute.rs | 18 +---- wgpu-core/src/command/mod.rs | 4 +- wgpu-core/src/device/mod.rs | 37 ++++++++-- wgpu-core/src/pipeline.rs | 13 ++-- wgpu-hal/src/gles/adapter.rs | 6 +- wgpu-hal/src/gles/command.rs | 89 +++++++++++++++++++---- wgpu-hal/src/gles/conv.rs | 40 ++++++++++ wgpu-hal/src/gles/device.rs | 30 ++++++-- wgpu-hal/src/gles/mod.rs | 49 +++++++++++-- wgpu-hal/src/gles/queue.rs | 121 +++++++++++++++++++++++++++++-- wgpu-types/src/lib.rs | 16 ++-- 11 files changed, 344 insertions(+), 79 deletions(-) diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index a9cec8ac43..c698dc0860 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -11,7 +11,7 @@ use crate::{ resource::{Buffer, Texture}, track::{StatefulTrackerSubset, TrackerSet, UsageConflict, UseExtendError}, validation::{check_buffer_usage, MissingBufferUsageError}, - Label, DOWNLEVEL_ERROR_WARNING_MESSAGE, + Label, }; use hal::CommandEncoder as _; @@ -149,11 +149,6 @@ pub enum ComputePassErrorInner { MissingBufferUsage(#[from] MissingBufferUsageError), #[error("cannot pop debug group, because number of pushed debug groups is zero")] InvalidPopDebugGroup, - #[error( - "Compute shaders are not supported by the underlying platform. {}", - DOWNLEVEL_ERROR_WARNING_MESSAGE - )] - ComputeShadersUnsupported, #[error(transparent)] Dispatch(#[from] DispatchError), #[error(transparent)] @@ -276,17 +271,6 @@ impl Global { }); } - if !cmd_buf - .downlevel - .flags - .contains(wgt::DownlevelFlags::COMPUTE_SHADERS) - { - return Err(ComputePassError { - scope: PassErrorScope::Pass(encoder_id), - inner: ComputePassErrorInner::ComputeShadersUnsupported, - }); - } - let (_, mut token) = hub.render_bundles.read(&mut token); let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index d40b99132b..9a2292f202 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -77,7 +77,6 @@ pub struct CommandBuffer { pub(crate) used_swap_chains: SmallVec<[Stored; 1]>, pub(crate) buffer_memory_init_actions: Vec>, limits: wgt::Limits, - downlevel: wgt::DownlevelCapabilities, support_fill_buffer_texture: bool, #[cfg(feature = "trace")] pub(crate) commands: Option>, @@ -88,7 +87,7 @@ impl CommandBuffer { encoder: A::CommandEncoder, device_id: Stored, limits: wgt::Limits, - downlevel: wgt::DownlevelCapabilities, + _downlevel: wgt::DownlevelCapabilities, features: wgt::Features, #[cfg(feature = "trace")] enable_tracing: bool, label: &Label, @@ -106,7 +105,6 @@ impl CommandBuffer { used_swap_chains: Default::default(), buffer_memory_init_actions: Default::default(), limits, - downlevel, support_fill_buffer_texture: features.contains(wgt::Features::CLEAR_COMMANDS), #[cfg(feature = "trace")] commands: if enable_tracing { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 7de5970bc2..555c0501a7 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -8,6 +8,7 @@ use crate::{ track::{BufferState, TextureSelector, TextureState, TrackerSet, UsageConflict}, validation::{self, check_buffer_usage, check_texture_usage}, FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, Stored, SubmissionIndex, + DOWNLEVEL_ERROR_WARNING_MESSAGE, }; use arrayvec::ArrayVec; @@ -319,6 +320,17 @@ impl Device { } } + pub(crate) fn require_downlevel_flags( + &self, + flags: wgt::DownlevelFlags, + ) -> Result<(), MissingDownlevelFlags> { + if self.downlevel.flags.contains(flags) { + Ok(()) + } else { + Err(MissingDownlevelFlags(flags)) + } + } + fn lock_life_internal<'this, 'token: 'this>( tracker: &'this Mutex>, _token: &mut Token<'token, Self>, @@ -1729,13 +1741,7 @@ impl Device { } } - if !self - .downlevel - .flags - .contains(wgt::DownlevelFlags::COMPUTE_SHADERS) - { - return Err(pipeline::CreateComputePipelineError::ComputeShadersUnsupported); - } + self.require_downlevel_flags(wgt::DownlevelFlags::COMPUTE_SHADERS)?; let mut derived_group_layouts = ArrayVec::<[binding_model::BindEntryMap; hal::MAX_BIND_GROUPS]>::new(); @@ -1858,6 +1864,16 @@ impl Device { .map_or(&[][..], |fragment| &fragment.targets); let depth_stencil_state = desc.depth_stencil.as_ref(); + if !color_targets.is_empty() && { + let first = &color_targets[0]; + color_targets[1..] + .iter() + .any(|ct| ct.write_mask != first.write_mask || ct.blend != first.blend) + } { + log::error!("Color targets: {:?}", color_targets); + self.require_downlevel_flags(wgt::DownlevelFlags::INDEPENDENT_BLENDING)?; + } + let mut io = validation::StageIo::default(); let mut validated_stages = wgt::ShaderStage::empty(); @@ -2405,6 +2421,13 @@ impl From for DeviceError { #[error("Features {0:?} are required but not enabled on the device")] pub struct MissingFeatures(pub wgt::Features); +#[derive(Clone, Debug, Error)] +#[error( + "Downlevel flags {0:?} are required but not supported on the device. {}", + DOWNLEVEL_ERROR_WARNING_MESSAGE +)] +pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags); + #[derive(Clone, Debug)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 6d9510a5f0..9d32afd0b6 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -1,9 +1,9 @@ use crate::{ binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError}, - device::{DeviceError, MissingFeatures, RenderPassContext}, + device::{DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, hub::Resource, id::{DeviceId, PipelineLayoutId, ShaderModuleId}, - validation, Label, LifeGuard, Stored, DOWNLEVEL_ERROR_WARNING_MESSAGE, + validation, Label, LifeGuard, Stored, }; use std::borrow::Cow; use thiserror::Error; @@ -109,11 +109,8 @@ pub enum CreateComputePipelineError { Stage(#[from] validation::StageError), #[error("Internal error: {0}")] Internal(String), - #[error( - "Compute shaders are not supported by the underlying platform. {}", - DOWNLEVEL_ERROR_WARNING_MESSAGE - )] - ComputeShadersUnsupported, + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } #[derive(Debug)] @@ -258,6 +255,8 @@ pub enum CreateRenderPipelineError { ConservativeRasterizationNonFillPolygonMode, #[error(transparent)] MissingFeatures(#[from] MissingFeatures), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error("error matching {stage:?} shader requirements against the pipeline")] Stage { stage: wgt::ShaderStage, diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 1c96a9376e..6ab35ad74d 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -52,7 +52,7 @@ impl super::Adapter { None => false, }; - let (version, vendor_info) = match src.find(' ') { + let (version, _vendor_info) = match src.find(' ') { Some(i) => (&src[..i], src[i + 1..].to_string()), None => (src, String::new()), }; @@ -196,6 +196,10 @@ impl super::Adapter { ); downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1)); downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2)); + downlevel_flags.set( + wgt::DownlevelFlags::INDEPENDENT_BLENDING, + ver >= (3, 2) || extensions.contains("GL_EXT_draw_buffers_indexed"), + ); let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 24806fb21a..8d7423b94a 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -14,9 +14,11 @@ pub(super) struct State { topology: u32, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, - vertex_buffers: [super::VertexBufferDesc; crate::MAX_VERTEX_BUFFERS], + vertex_buffers: [(super::VertexBufferDesc, super::BufferBinding); crate::MAX_VERTEX_BUFFERS], vertex_attributes: ArrayVec<[super::AttributeDesc; super::MAX_VERTEX_ATTRIBUTES]>, + color_targets: ArrayVec<[super::ColorTargetDesc; crate::MAX_COLOR_TARGETS]>, stencil: super::StencilState, + depth_bias: wgt::DepthBiasState, has_pass_label: bool, dirty: Dirty, } @@ -63,18 +65,19 @@ impl super::CommandEncoder { fn rebind_vertex_attributes(&mut self, first_instance: u32) { for attribute in self.state.vertex_attributes.iter() { - let vb = self.state.vertex_buffers[attribute.buffer_index as usize].clone(); + let (buffer_desc, buffer) = + self.state.vertex_buffers[attribute.buffer_index as usize].clone(); - let mut vat = attribute.clone(); - vat.offset += vb.offset as u32; - - if vb.step == wgt::InputStepMode::Instance { - vat.offset += vb.stride * first_instance; + let mut attribute_desc = attribute.clone(); + if buffer_desc.step == wgt::InputStepMode::Instance { + attribute_desc.offset += buffer_desc.stride * first_instance; } - self.cmd_buffer - .commands - .push(C::SetVertexAttribute(vat, vb)); + self.cmd_buffer.commands.push(C::SetVertexAttribute { + buffer_desc, + buffer, + attribute_desc, + }); } } @@ -391,6 +394,8 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.has_pass_label = false; } self.state.dirty = Dirty::empty(); + self.state.color_targets.clear(); + self.state.vertex_attributes.clear(); } unsafe fn set_bind_group( @@ -426,11 +431,15 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); self.state.dirty |= Dirty::VERTEX_BUFFERS; + self.cmd_buffer + .commands + .push(C::SetProgram(pipeline.inner.program)); + self.state.vertex_attributes.clear(); for vat in pipeline.vertex_attributes.iter() { self.state.vertex_attributes.push(vat.clone()); } - for (state_desc, pipe_desc) in self + for (&mut (ref mut state_desc, _), pipe_desc) in self .state .vertex_buffers .iter_mut() @@ -440,7 +449,19 @@ impl crate::CommandEncoder for super::CommandEncoder { state_desc.stride = pipe_desc.stride; } + let mut aspects = crate::FormatAspect::empty(); + if pipeline.depth_bias != self.state.depth_bias { + self.state.depth_bias = pipeline.depth_bias; + self.cmd_buffer + .commands + .push(C::SetDepthBias(pipeline.depth_bias)); + } + if let Some(ref depth) = pipeline.depth { + aspects |= crate::FormatAspect::DEPTH; + self.cmd_buffer.commands.push(C::SetDepth(depth.clone())); + } if let Some(ref stencil) = pipeline.stencil { + aspects |= crate::FormatAspect::STENCIL; self.state.stencil = stencil.clone(); self.rebind_stencil_func(); if stencil.front.ops == stencil.back.ops @@ -464,6 +485,34 @@ impl crate::CommandEncoder for super::CommandEncoder { }); } } + self.cmd_buffer + .commands + .push(C::ConfigureDepthStencil(aspects)); + + if self.state.color_targets[..] != pipeline.color_targets[..] { + if pipeline + .color_targets + .iter() + .skip(1) + .any(|ct| *ct != pipeline.color_targets[0]) + { + for (index, ct) in pipeline.color_targets.iter().enumerate() { + self.cmd_buffer.commands.push(C::SetColorTarget { + draw_buffer_index: Some(index as u32), + desc: ct.clone(), + }); + } + } else { + self.cmd_buffer.commands.push(C::SetColorTarget { + draw_buffer_index: None, + desc: pipeline.color_targets.first().cloned().unwrap_or_default(), + }); + } + } + self.state.color_targets.clear(); + for ct in pipeline.color_targets.iter() { + self.state.color_targets.push(ct.clone()); + } } unsafe fn set_index_buffer<'a>( @@ -483,7 +532,7 @@ impl crate::CommandEncoder for super::CommandEncoder { binding: crate::BufferBinding<'a, super::Api>, ) { self.state.dirty |= Dirty::VERTEX_BUFFERS; - let vb = &mut self.state.vertex_buffers[index as usize]; + let vb = &mut self.state.vertex_buffers[index as usize].1; vb.raw = binding.buffer.raw; vb.offset = binding.offset; } @@ -511,7 +560,15 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.stencil.back.reference = value; self.rebind_stencil_func(); } - unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {} + unsafe fn set_blend_constants(&mut self, color: &wgt::Color) { + let color = [ + color.r as f32, + color.g as f32, + color.b as f32, + color.a as f32, + ]; + self.cmd_buffer.commands.push(C::SetBlendConstant(color)); + } unsafe fn draw( &mut self, @@ -628,7 +685,11 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.dirty = Dirty::empty(); } - unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { + self.cmd_buffer + .commands + .push(C::SetProgram(pipeline.inner.program)); + } unsafe fn dispatch(&mut self, count: [u32; 3]) { self.cmd_buffer.commands.push(C::Dispatch(count)); diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index a415fb5b38..cc75b68d5f 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -273,3 +273,43 @@ pub(super) fn map_stencil(state: &wgt::StencilState) -> super::StencilState { }, } } + +fn map_blend_factor(factor: wgt::BlendFactor) -> u32 { + use wgt::BlendFactor as Bf; + match factor { + Bf::Zero => glow::ZERO, + Bf::One => glow::ONE, + Bf::Src => glow::SRC_COLOR, + Bf::OneMinusSrc => glow::ONE_MINUS_SRC_COLOR, + Bf::Dst => glow::DST_COLOR, + Bf::OneMinusDst => glow::ONE_MINUS_DST_COLOR, + Bf::SrcAlpha => glow::SRC_ALPHA, + Bf::OneMinusSrcAlpha => glow::ONE_MINUS_SRC_ALPHA, + Bf::DstAlpha => glow::DST_ALPHA, + Bf::OneMinusDstAlpha => glow::ONE_MINUS_DST_ALPHA, + Bf::Constant => glow::CONSTANT_COLOR, + Bf::OneMinusConstant => glow::ONE_MINUS_CONSTANT_COLOR, + Bf::SrcAlphaSaturated => glow::SRC_ALPHA_SATURATE, + } +} + +fn map_blend_component(component: &wgt::BlendComponent) -> super::BlendComponent { + super::BlendComponent { + src: map_blend_factor(component.src_factor), + dst: map_blend_factor(component.dst_factor), + equation: match component.operation { + wgt::BlendOperation::Add => glow::FUNC_ADD, + wgt::BlendOperation::Subtract => glow::FUNC_SUBTRACT, + wgt::BlendOperation::ReverseSubtract => glow::FUNC_REVERSE_SUBTRACT, + wgt::BlendOperation::Min => glow::MIN, + wgt::BlendOperation::Max => glow::MAX, + }, + } +} + +pub(super) fn map_blend(blend: &wgt::BlendState) -> super::BlendDesc { + super::BlendDesc { + color: map_blend_component(&blend.color), + alpha: map_blend_component(&blend.alpha), + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index a3042a809e..8da560e492 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -465,7 +465,7 @@ impl crate::Device for super::Device { super::TextureInner::Renderbuffer { raw, .. } => { gl.delete_renderbuffer(raw); } - super::TextureInner::Texture { raw, target } => { + super::TextureInner::Texture { raw, .. } => { gl.delete_texture(raw); } } @@ -514,7 +514,7 @@ impl crate::Device for super::Device { unsafe fn create_command_encoder( &self, - desc: &crate::CommandEncoderDescriptor, + _desc: &crate::CommandEncoderDescriptor, ) -> Result { Ok(super::CommandEncoder { cmd_buffer: super::CommandBuffer::default(), @@ -585,7 +585,7 @@ impl crate::Device for super::Device { group_infos: group_infos.into_boxed_slice(), }) } - unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {} + unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: super::PipelineLayout) {} unsafe fn create_bind_group( &self, @@ -640,7 +640,7 @@ impl crate::Device for super::Device { unsafe fn create_shader_module( &self, - desc: &crate::ShaderModuleDescriptor, + _desc: &crate::ShaderModuleDescriptor, shader: crate::ShaderInput, ) -> Result { Ok(super::ShaderModule { @@ -670,8 +670,6 @@ impl crate::Device for super::Device { let mut attributes = Vec::new(); for (index, vb_layout) in desc.vertex_buffers.iter().enumerate() { buffers.push(super::VertexBufferDesc { - raw: 0, - offset: 0, step: vb_layout.step_mode, stride: vb_layout.array_stride as u32, }); @@ -688,16 +686,34 @@ impl crate::Device for super::Device { (buffers.into_boxed_slice(), attributes.into_boxed_slice()) }; + let color_targets = { + let mut targets = Vec::new(); + for ct in desc.color_targets.iter() { + targets.push(super::ColorTargetDesc { + mask: ct.write_mask, + blend: ct.blend.as_ref().map(conv::map_blend), + }); + } + //Note: if any of the states are different, and `INDEPENDENT_BLEND` flag + // is not exposed, then this pipeline will not bind correctly. + targets.into_boxed_slice() + }; + Ok(super::RenderPipeline { inner, primitive: desc.primitive, vertex_buffers, vertex_attributes, + color_targets, depth: desc.depth_stencil.as_ref().map(|ds| super::DepthState { function: conv::map_compare_func(ds.depth_compare), mask: ds.depth_write_enabled, }), - depth_bias: desc.depth_stencil.as_ref().map(|ds| ds.bias), + depth_bias: desc + .depth_stencil + .as_ref() + .map(|ds| ds.bias) + .unwrap_or_default(), stencil: desc .depth_stencil .as_ref() diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 31ae5368df..53dd24e8a1 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - #[cfg(not(target_arch = "wasm32"))] mod egl; @@ -319,9 +317,13 @@ struct AttributeDesc { } #[derive(Clone, Debug, Default)] -struct VertexBufferDesc { +struct BufferBinding { raw: glow::Buffer, offset: wgt::BufferAddress, +} + +#[derive(Clone, Debug, Default)] +struct VertexBufferDesc { step: wgt::InputStepMode, stride: u32, } @@ -343,19 +345,39 @@ struct PipelineInner { uniforms: Box<[UniformDesc]>, } +#[derive(Clone, Debug)] struct DepthState { function: u32, mask: bool, } +#[derive(Clone, Debug, PartialEq)] +struct BlendComponent { + src: u32, + dst: u32, + equation: u32, +} + +#[derive(Clone, Debug, PartialEq)] +struct BlendDesc { + alpha: BlendComponent, + color: BlendComponent, +} + +#[derive(Clone, Debug, Default, PartialEq)] +struct ColorTargetDesc { + mask: wgt::ColorWrite, + blend: Option, +} + pub struct RenderPipeline { inner: PipelineInner, - //blend_targets: Vec, + primitive: wgt::PrimitiveState, vertex_buffers: Box<[VertexBufferDesc]>, vertex_attributes: Box<[AttributeDesc]>, - primitive: wgt::PrimitiveState, + color_targets: Box<[ColorTargetDesc]>, depth: Option, - depth_bias: Option, + depth_bias: wgt::DepthBiasState, stencil: Option, } @@ -560,7 +582,20 @@ enum Command { write_mask: u32, ops: StencilOps, }, - SetVertexAttribute(AttributeDesc, VertexBufferDesc), + SetDepth(DepthState), + SetDepthBias(wgt::DepthBiasState), + ConfigureDepthStencil(crate::FormatAspect), + SetVertexAttribute { + buffer: BufferBinding, + buffer_desc: VertexBufferDesc, + attribute_desc: AttributeDesc, + }, + SetProgram(glow::Program), + SetBlendConstant([f32; 4]), + SetColorTarget { + draw_buffer_index: Option, + desc: ColorTargetDesc, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 3f914b2665..9f51204c53 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -17,6 +17,16 @@ fn is_3d_target(target: super::BindTarget) -> bool { } impl super::Queue { + unsafe fn reset_state(&self) { + let gl = &self.shared.context; + gl.use_program(None); + gl.polygon_offset(0.0, 0.0); + gl.disable(glow::DEPTH_TEST); + gl.disable(glow::STENCIL_TEST); + gl.disable(glow::SCISSOR_TEST); + gl.disable(glow::BLEND); + } + unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) { let gl = &self.shared.context; match *command { @@ -161,7 +171,7 @@ impl super::Queue { } C::CopyBufferToTexture { src, - src_target, + src_target: _, dst, dst_target, ref dst_info, @@ -213,7 +223,7 @@ impl super::Queue { src_target, ref src_info, dst, - dst_target, + dst_target: _, ref copy, } => { //TODO: compressed data @@ -355,6 +365,9 @@ impl super::Queue { .map(|i| glow::COLOR_ATTACHMENT0 + i) .collect::>(); gl.draw_buffers(&indices); + for draw_buffer in 0..count as u32 { + gl.disable_draw_buffer(glow::BLEND, draw_buffer); + } } C::ClearColorF(draw_buffer, mut color) => { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, &mut color); @@ -438,6 +451,7 @@ impl super::Queue { } C::SetScissor(ref rect) => { gl.scissor(rect.x, rect.y, rect.w, rect.h); + gl.enable(glow::SCISSOR_TEST); } C::SetStencilFunc { face, @@ -455,29 +469,119 @@ impl super::Queue { gl.stencil_mask_separate(face, write_mask); gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass); } - C::SetVertexAttribute(ref vat, ref vb) => { - gl.bind_buffer(glow::ARRAY_BUFFER, Some(vb.raw)); - let offset = vat.offset as i32 + vb.offset as i32; + C::SetVertexAttribute { + ref buffer_desc, + ref buffer, + attribute_desc: ref vat, + } => { + gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer.raw)); + let offset = vat.offset as i32 + buffer.offset as i32; match vat.format_desc.attrib_kind { super::VertexAttribKind::Float => gl.vertex_attrib_pointer_f32( vat.location, vat.format_desc.element_count, vat.format_desc.element_format, true, // always normalized - vb.stride as i32, + buffer_desc.stride as i32, offset, ), super::VertexAttribKind::Integer => gl.vertex_attrib_pointer_i32( vat.location, vat.format_desc.element_count, vat.format_desc.element_format, - vb.stride as i32, + buffer_desc.stride as i32, offset, ), } - gl.vertex_attrib_divisor(vat.location, vb.step as u32); + gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32); gl.enable_vertex_attrib_array(vat.location); } + C::SetDepth(ref depth) => { + gl.depth_func(depth.function); + gl.depth_mask(depth.mask); + } + C::SetDepthBias(bias) => { + gl.polygon_offset(bias.constant as f32, bias.slope_scale); + } + C::ConfigureDepthStencil(aspects) => { + if aspects.contains(crate::FormatAspect::DEPTH) { + gl.enable(glow::DEPTH_TEST); + } else { + gl.disable(glow::DEPTH_TEST); + } + if aspects.contains(crate::FormatAspect::STENCIL) { + gl.enable(glow::STENCIL_TEST); + } else { + gl.disable(glow::STENCIL_TEST); + } + } + C::SetProgram(program) => { + gl.use_program(Some(program)); + } + C::SetBlendConstant(c) => { + gl.blend_color(c[0], c[1], c[2], c[3]); + } + C::SetColorTarget { + draw_buffer_index, + desc: super::ColorTargetDesc { mask, ref blend }, + } => { + use wgt::ColorWrite as Cw; + if let Some(index) = draw_buffer_index { + gl.color_mask_draw_buffer( + index, + mask.contains(Cw::RED), + mask.contains(Cw::GREEN), + mask.contains(Cw::BLUE), + mask.contains(Cw::ALPHA), + ); + if let Some(ref blend) = *blend { + gl.enable_draw_buffer(index, glow::BLEND); + if blend.color != blend.alpha { + gl.blend_equation_separate_draw_buffer( + index, + blend.color.equation, + blend.alpha.equation, + ); + gl.blend_func_separate_draw_buffer( + index, + blend.color.src, + blend.color.dst, + blend.alpha.src, + blend.alpha.dst, + ); + } else { + gl.blend_equation_draw_buffer(index, blend.color.equation); + gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst); + } + } else { + gl.disable_draw_buffer(index, glow::BLEND); + } + } else { + gl.color_mask( + mask.contains(Cw::RED), + mask.contains(Cw::GREEN), + mask.contains(Cw::BLUE), + mask.contains(Cw::ALPHA), + ); + if let Some(ref blend) = *blend { + gl.enable(glow::BLEND); + if blend.color != blend.alpha { + gl.blend_equation_separate(blend.color.equation, blend.alpha.equation); + gl.blend_func_separate( + blend.color.src, + blend.color.dst, + blend.alpha.src, + blend.alpha.dst, + ); + } else { + gl.blend_equation(blend.color.equation); + gl.blend_func(blend.color.src, blend.color.dst); + } + } else { + gl.disable(glow::BLEND); + } + } + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( @@ -505,6 +609,7 @@ impl crate::Queue for super::Queue { command_buffers: &[&super::CommandBuffer], signal_fence: Option<(&mut super::Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { + self.reset_state(); for cmd_buf in command_buffers.iter() { for command in cmd_buf.commands.iter() { self.process(command, &cmd_buf.data_bytes, &cmd_buf.data_words); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 99fffc8ef1..94016d881f 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -625,24 +625,24 @@ bitflags::bitflags! { const INDIRECT_EXECUTION = 0x0000_0004; /// Supports non-zero `base_vertex` parameter to indexed draw calls. const BASE_VERTEX = 0x0000_0008; - /// Supports non-zero `base_instance` parameter to draw calls. - const BASE_INSTANCE = 0x0000_0010; /// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil attachment. - const READ_ONLY_DEPTH_STENCIL = 0x0000_0020; + const READ_ONLY_DEPTH_STENCIL = 0x0000_0010; /// Supports: /// - copy_image_to_image /// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage - const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0040; + const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0020; /// Supports textures with mipmaps which have a non power of two size. - const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0080; + const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0040; /// Supports textures that are cube arrays. - const CUBE_ARRAY_TEXTURES = 0x0000_0100; + const CUBE_ARRAY_TEXTURES = 0x0000_0080; /// Supports comparison samplers. - const COMPARISON_SAMPLERS = 0x0000_0200; + const COMPARISON_SAMPLERS = 0x0000_0100; + /// Supports different blending modes per color target. + const INDEPENDENT_BLENDING = 0x0000_0200; /// Supports samplers with anisotropic filtering const ANISOTROPIC_FILTERING = 0x0001_0000; /// All flags are in their compliant state. - const COMPLIANT = 0x0000_02FF; + const COMPLIANT = 0x0000_13FF; } }