Improve OpenGL 3.1 support (#4272)

Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
Zoxc 2023-10-30 06:35:24 +01:00 committed by GitHub
parent ff1ba0b4fe
commit ac896cf223
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 174 additions and 41 deletions

View File

@ -222,6 +222,25 @@ impl super::Adapter {
.is_none()
.then_some(())
.and_then(|_| Self::parse_version(&version).ok());
let web_gl = cfg!(target_arch = "wasm32");
if let Some(full_ver) = full_ver {
let core_profile = (full_ver >= (3, 2)).then_some(unsafe {
gl.get_parameter_i32(glow::CONTEXT_PROFILE_MASK)
& glow::CONTEXT_CORE_PROFILE_BIT as i32
!= 0
});
log::trace!(
"Profile: {}",
core_profile
.map(|core_profile| if core_profile {
"Core"
} else {
"Compatibility"
})
.unwrap_or("Legacy")
);
}
if es_ver.is_none() && full_ver.is_none() {
log::warn!("Unable to parse OpenGL version");
@ -584,6 +603,14 @@ impl super::Adapter {
},
);
private_caps.set(super::PrivateCapabilities::QUERY_BUFFERS, query_buffers);
private_caps.set(
super::PrivateCapabilities::TEXTURE_STORAGE,
supported((3, 0), (4, 2)),
);
private_caps.set(
super::PrivateCapabilities::DEBUG_FNS,
supported((3, 2), (4, 3)) && !web_gl,
);
let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32;
let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32;

View File

@ -535,13 +535,6 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
.push(glow::STENCIL_ATTACHMENT);
}
}
if !rendering_to_external_framebuffer {
// set the draw buffers and states
self.cmd_buffer
.commands
.push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
}
}
}
@ -586,6 +579,14 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
);
}
}
if !rendering_to_external_framebuffer {
// set the draw buffers and states
self.cmd_buffer
.commands
.push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
}
if let Some(ref dsat) = desc.depth_stencil_attachment {
let clear_depth = !dsat.depth_ops.contains(crate::AttachmentOps::LOAD);
let clear_stencil = !dsat.stencil_ops.contains(crate::AttachmentOps::LOAD);

View File

@ -1,7 +1,8 @@
use super::conv;
use super::{conv, PrivateCapabilities};
use crate::auxil::map_naga_stage;
use glow::HasContext;
use std::{
cmp::max,
convert::TryInto,
ptr,
sync::{Arc, Mutex},
@ -28,9 +29,12 @@ struct CompilationContext<'a> {
impl CompilationContext<'_> {
fn consume_reflection(
self,
gl: &glow::Context,
module: &naga::Module,
ep_info: &naga::valid::FunctionInfo,
reflection_info: naga::back::glsl::ReflectionInfo,
naga_stage: naga::ShaderStage,
program: glow::Program,
) {
for (handle, var) in module.global_variables.iter() {
if ep_info[handle].is_empty() {
@ -83,6 +87,20 @@ impl CompilationContext<'_> {
self.sampler_map[texture_linear_index as usize] = Some(sampler_linear_index);
}
}
for (name, location) in reflection_info.varying {
match naga_stage {
naga::ShaderStage::Vertex => {
assert_eq!(location.index, 0);
unsafe { gl.bind_attrib_location(program, location.location, &name) }
}
naga::ShaderStage::Fragment => {
assert_eq!(location.index, 0);
unsafe { gl.bind_frag_data_location(program, location.location, &name) }
}
naga::ShaderStage::Compute => {}
}
}
}
}
@ -176,6 +194,8 @@ impl super::Device {
}
Ok(raw)
} else {
log::error!("\tShader compilation failed: {}", msg);
unsafe { gl.delete_shader(raw) };
Err(crate::PipelineError::Linkage(
map_naga_stage(naga_stage),
msg,
@ -188,6 +208,7 @@ impl super::Device {
naga_stage: naga::ShaderStage,
stage: &crate::ProgrammableStage<super::Api>,
context: CompilationContext,
program: glow::Program,
) -> Result<glow::Shader, crate::PipelineError> {
use naga::back::glsl;
let pipeline_options = glsl::PipelineOptions {
@ -205,9 +226,9 @@ impl super::Device {
.ok_or(crate::PipelineError::EntryPoint(naga_stage))?;
use naga::proc::BoundsCheckPolicy;
// The image bounds checks require the TEXTURE_LEVELS feature available in GL core 1.3+.
// The image bounds checks require the TEXTURE_LEVELS feature available in GL core 4.3+.
let version = gl.version();
let image_check = if !version.is_embedded && (version.major, version.minor) >= (1, 3) {
let image_check = if !version.is_embedded && (version.major, version.minor) >= (4, 3) {
BoundsCheckPolicy::ReadZeroSkipWrite
} else {
BoundsCheckPolicy::Unchecked
@ -244,9 +265,12 @@ impl super::Device {
log::debug!("Naga generated shader:\n{}", output);
context.consume_reflection(
gl,
&shader.module,
shader.info.get_entry_point(entry_point_index),
reflection_info,
naga_stage,
program,
);
unsafe { Self::compile_shader(gl, &output, naga_stage, stage.module.label.as_deref()) }
@ -308,7 +332,7 @@ impl super::Device {
#[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>,
multiview: Option<std::num::NonZeroU32>,
glsl_version: naga::back::glsl::Version,
private_caps: super::PrivateCapabilities,
private_caps: PrivateCapabilities,
) -> Result<Arc<super::PipelineInner>, crate::PipelineError> {
let glsl_version = match glsl_version {
naga::back::glsl::Version::Embedded { version, .. } => format!("{version} es"),
@ -337,7 +361,7 @@ impl super::Device {
multiview,
};
let shader = Self::create_shader(gl, naga_stage, stage, context)?;
let shader = Self::create_shader(gl, naga_stage, stage, context, program)?;
shaders_to_delete.push(shader);
}
@ -748,13 +772,64 @@ impl crate::Device<super::Api> for super::Device {
};
} else {
unsafe {
gl.tex_storage_2d(
target,
desc.mip_level_count as i32,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
)
if self
.shared
.private_caps
.contains(PrivateCapabilities::TEXTURE_STORAGE)
{
gl.tex_storage_2d(
target,
desc.mip_level_count as i32,
format_desc.internal,
desc.size.width as i32,
desc.size.height as i32,
)
} else if target == glow::TEXTURE_CUBE_MAP {
let mut width = desc.size.width;
let mut height = desc.size.width;
for i in 0..desc.mip_level_count {
for face in [
glow::TEXTURE_CUBE_MAP_POSITIVE_X,
glow::TEXTURE_CUBE_MAP_NEGATIVE_X,
glow::TEXTURE_CUBE_MAP_POSITIVE_Y,
glow::TEXTURE_CUBE_MAP_NEGATIVE_Y,
glow::TEXTURE_CUBE_MAP_POSITIVE_Z,
glow::TEXTURE_CUBE_MAP_NEGATIVE_Z,
] {
gl.tex_image_2d(
face,
i as i32,
format_desc.internal as i32,
width as i32,
height as i32,
0,
format_desc.external,
format_desc.data_type,
None,
);
}
width = max(1, width / 2);
height = max(1, height / 2);
}
} else {
let mut width = desc.size.width;
let mut height = desc.size.width;
for i in 0..desc.mip_level_count {
gl.tex_image_2d(
target,
i as i32,
format_desc.internal as i32,
width as i32,
height as i32,
0,
format_desc.external,
format_desc.data_type,
None,
);
width = max(1, width / 2);
height = max(1, height / 2);
}
}
};
}

View File

@ -163,6 +163,10 @@ bitflags::bitflags! {
const TEXTURE_FLOAT_LINEAR = 1 << 10;
/// Supports query buffer objects.
const QUERY_BUFFERS = 1 << 11;
/// Supports `glTexStorage2D`, etc.
const TEXTURE_STORAGE = 1 << 12;
/// Supports `push_debug_group`, `pop_debug_group` and `debug_message_insert`.
const DEBUG_FNS = 1 << 13;
}
}

View File

@ -3,10 +3,8 @@ use arrayvec::ArrayVec;
use glow::HasContext;
use std::{mem, slice, sync::Arc};
#[cfg(not(target_arch = "wasm32"))]
const DEBUG_ID: u32 = 0;
#[cfg(not(target_arch = "wasm32"))]
fn extract_marker<'a>(data: &'a [u8], range: &std::ops::Range<u32>) -> &'a str {
std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap()
}
@ -992,6 +990,14 @@ impl super::Queue {
&& is_srgb
{
unsafe { self.perform_shader_clear(gl, draw_buffer, *color) };
} else if draw_buffer < 32 {
// Prefer `clear_color` as `clear_buffer_f32_slice` crashes on Sandy Bridge
// on Windows.
unsafe {
gl.draw_buffers(&[glow::COLOR_ATTACHMENT0 + draw_buffer]);
gl.clear_color(color[0], color[1], color[2], color[3]);
gl.clear(glow::COLOR_BUFFER_BIT);
}
} else {
unsafe { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color) };
}
@ -1364,34 +1370,45 @@ impl super::Queue {
)
};
}
#[cfg(not(target_arch = "wasm32"))]
C::InsertDebugMarker(ref range) => {
let marker = extract_marker(data_bytes, range);
unsafe {
gl.debug_message_insert(
glow::DEBUG_SOURCE_APPLICATION,
glow::DEBUG_TYPE_MARKER,
DEBUG_ID,
glow::DEBUG_SEVERITY_NOTIFICATION,
marker,
)
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
gl.debug_message_insert(
glow::DEBUG_SOURCE_APPLICATION,
glow::DEBUG_TYPE_MARKER,
DEBUG_ID,
glow::DEBUG_SEVERITY_NOTIFICATION,
marker,
)
}
};
}
#[cfg(target_arch = "wasm32")]
C::InsertDebugMarker(_) => (),
#[cfg_attr(target_arch = "wasm32", allow(unused))]
C::PushDebugGroup(ref range) => {
#[cfg(not(target_arch = "wasm32"))]
let marker = extract_marker(data_bytes, range);
#[cfg(not(target_arch = "wasm32"))]
unsafe {
gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker)
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker)
}
};
}
C::PopDebugGroup => {
#[cfg(not(target_arch = "wasm32"))]
unsafe {
gl.pop_debug_group()
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
gl.pop_debug_group()
}
};
}
C::SetPushConstants {
@ -1476,17 +1493,26 @@ impl crate::Queue<super::Api> for super::Queue {
// this at the beginning of the loop in case something outside of wgpu modified
// this state prior to commit.
unsafe { self.reset_state(gl) };
#[cfg(not(target_arch = "wasm32"))]
if let Some(ref label) = cmd_buf.label {
unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
}
}
for command in cmd_buf.commands.iter() {
unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
}
#[cfg(not(target_arch = "wasm32"))]
if cmd_buf.label.is_some() {
if cmd_buf.label.is_some()
&& self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
unsafe { gl.pop_debug_group() };
}
}