mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Refactor downlevel support a bit, implement blending for hal/gles
This commit is contained in:
committed by
Dzmitry Malyshau
parent
13b0a61dc8
commit
91df157462
@@ -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<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -77,7 +77,6 @@ pub struct CommandBuffer<A: hal::Api> {
|
||||
pub(crate) used_swap_chains: SmallVec<[Stored<id::SwapChainId>; 1]>,
|
||||
pub(crate) buffer_memory_init_actions: Vec<MemoryInitTrackerAction<id::BufferId>>,
|
||||
limits: wgt::Limits,
|
||||
downlevel: wgt::DownlevelCapabilities,
|
||||
support_fill_buffer_texture: bool,
|
||||
#[cfg(feature = "trace")]
|
||||
pub(crate) commands: Option<Vec<crate::device::trace::Command>>,
|
||||
@@ -88,7 +87,7 @@ impl<A: HalApi> CommandBuffer<A> {
|
||||
encoder: A::CommandEncoder,
|
||||
device_id: Stored<id::DeviceId>,
|
||||
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<A: HalApi> CommandBuffer<A> {
|
||||
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 {
|
||||
|
||||
@@ -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<A: HalApi> Device<A> {
|
||||
}
|
||||
}
|
||||
|
||||
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<life::LifetimeTracker<A>>,
|
||||
_token: &mut Token<'token, Self>,
|
||||
@@ -1729,13 +1741,7 @@ impl<A: HalApi> Device<A> {
|
||||
}
|
||||
}
|
||||
|
||||
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<A: HalApi> Device<A> {
|
||||
.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<hal::DeviceError> 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))]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<super::Api> 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<super::Api> 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<super::Api> 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<super::Api> 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<super::Api> 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<super::Api> 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<super::Api> 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));
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ impl crate::Device<super::Api> 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<super::Api> for super::Device {
|
||||
|
||||
unsafe fn create_command_encoder(
|
||||
&self,
|
||||
desc: &crate::CommandEncoderDescriptor<super::Api>,
|
||||
_desc: &crate::CommandEncoderDescriptor<super::Api>,
|
||||
) -> Result<super::CommandEncoder, crate::DeviceError> {
|
||||
Ok(super::CommandEncoder {
|
||||
cmd_buffer: super::CommandBuffer::default(),
|
||||
@@ -585,7 +585,7 @@ impl crate::Device<super::Api> 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<super::Api> for super::Device {
|
||||
|
||||
unsafe fn create_shader_module(
|
||||
&self,
|
||||
desc: &crate::ShaderModuleDescriptor,
|
||||
_desc: &crate::ShaderModuleDescriptor,
|
||||
shader: crate::ShaderInput,
|
||||
) -> Result<super::ShaderModule, crate::ShaderError> {
|
||||
Ok(super::ShaderModule {
|
||||
@@ -670,8 +670,6 @@ impl crate::Device<super::Api> 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<super::Api> 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()
|
||||
|
||||
@@ -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<BlendDesc>,
|
||||
}
|
||||
|
||||
pub struct RenderPipeline {
|
||||
inner: PipelineInner,
|
||||
//blend_targets: Vec<pso::ColorBlendDesc>,
|
||||
primitive: wgt::PrimitiveState,
|
||||
vertex_buffers: Box<[VertexBufferDesc]>,
|
||||
vertex_attributes: Box<[AttributeDesc]>,
|
||||
primitive: wgt::PrimitiveState,
|
||||
color_targets: Box<[ColorTargetDesc]>,
|
||||
depth: Option<DepthState>,
|
||||
depth_bias: Option<wgt::DepthBiasState>,
|
||||
depth_bias: wgt::DepthBiasState,
|
||||
stencil: Option<StencilState>,
|
||||
}
|
||||
|
||||
@@ -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<u32>,
|
||||
desc: ColorTargetDesc,
|
||||
},
|
||||
InsertDebugMarker(Range<u32>),
|
||||
PushDebugGroup(Range<u32>),
|
||||
PopDebugGroup,
|
||||
|
||||
@@ -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::<ArrayVec<[_; crate::MAX_COLOR_TARGETS]>>();
|
||||
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<super::Api> 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user