hal/gles: primitive state and framebuffer operations

This commit is contained in:
Dzmitry Malyshau
2021-06-26 02:15:47 -04:00
parent 952173efde
commit bf61908824
7 changed files with 231 additions and 50 deletions

View File

@@ -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<super::Api> for super::Adapter {
unsafe fn open(
&self,
_features: wgt::Features,
features: wgt::Features,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let gl = &self.shared.context;
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
@@ -300,6 +300,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
},
queue: super::Queue {
shared: Arc::clone(&self.shared),
features,
draw_fbo: gl
.create_framebuffer()
.map_err(|_| crate::DeviceError::OutOfMemory)?,

View File

@@ -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<glow::Sampler>; 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<super::Api> for super::CommandEncoder {
) where
T: Iterator<Item = crate::BufferCopy>,
{
//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<super::Api> for super::CommandEncoder {
// render
unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<super::Api>) {
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<super::Api> 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<super::Api> 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<super::Api> 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<super::Api> 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 {

View File

@@ -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 {

View File

@@ -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<super::Api> 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<super::Api> for super::Device {
) -> Result<crate::BufferMapping, crate::DeviceError> {
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<super::Api> for super::Device {
I: Iterator<Item = crate::MemoryRange>,
{
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<super::Api> for super::Device {
I: Iterator<Item = crate::MemoryRange>,
{
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<super::Api> 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<super::Api> 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 }
};

View File

@@ -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<super::Api> 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,

View File

@@ -97,6 +97,7 @@ pub struct Device {
pub struct Queue {
shared: Arc<AdapterShared>,
features: wgt::Features,
draw_fbo: glow::Framebuffer,
copy_fbo: glow::Framebuffer,
temp_query_results: Vec<u64>,
@@ -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<u32>,

View File

@@ -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]);
}