hal/egl: add coherence preference, hook up EGL_KHR_debug message callbacks

This commit is contained in:
Dzmitry Malyshau
2021-06-25 16:58:01 -04:00
committed by Dzmitry Malyshau
parent c7356e124e
commit 8fd6b36e6c
10 changed files with 189 additions and 133 deletions

View File

@@ -239,7 +239,7 @@ impl<A: hal::Api> Example<A> {
label: Some("stage"),
size: texture_data.len() as wgt::BufferAddress,
usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::COPY_SRC,
memory_flags: hal::MemoryFlag::TRANSIENT,
memory_flags: hal::MemoryFlag::TRANSIENT | hal::MemoryFlag::PREFER_COHERENT,
};
let staging_buffer = unsafe { device.create_buffer(&staging_buffer_desc).unwrap() };
unsafe {
@@ -342,7 +342,7 @@ impl<A: hal::Api> Example<A> {
label: Some("global"),
size: mem::size_of::<Globals>() as wgt::BufferAddress,
usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::UNIFORM,
memory_flags: hal::MemoryFlag::empty(),
memory_flags: hal::MemoryFlag::PREFER_COHERENT,
};
let global_buffer = unsafe {
let buffer = device.create_buffer(&global_buffer_desc).unwrap();
@@ -363,7 +363,7 @@ impl<A: hal::Api> Example<A> {
label: Some("local"),
size: (MAX_BUNNIES as wgt::BufferAddress) * wgt::BIND_BUFFER_ALIGNMENT,
usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::UNIFORM,
memory_flags: hal::MemoryFlag::empty(),
memory_flags: hal::MemoryFlag::PREFER_COHERENT,
};
let local_buffer = unsafe { device.create_buffer(&local_buffer_desc).unwrap() };
@@ -474,6 +474,10 @@ impl<A: hal::Api> Example<A> {
})
}
fn is_empty(&self) -> bool {
self.bunnies.is_empty()
}
fn exit(mut self) {
unsafe {
{
@@ -732,11 +736,12 @@ fn main() {
}
},
winit::event::Event::RedrawRequested(_) => {
let ex = example.as_mut().unwrap();
{
accum_time += last_frame_inst.elapsed().as_secs_f32();
last_frame_inst = Instant::now();
frame_count += 1;
if frame_count == 100 {
if frame_count == 100 && !ex.is_empty() {
println!(
"Avg frame time {}ms",
accum_time * 1000.0 / frame_count as f32
@@ -745,7 +750,7 @@ fn main() {
frame_count = 0;
}
}
example.as_mut().unwrap().render();
ex.render();
}
winit::event::Event::LoopDestroyed => {
example.take().unwrap().exit();

View File

@@ -167,13 +167,13 @@ impl super::Adapter {
let ver = Self::parse_version(&version).ok()?;
let extensions = gl.supported_extensions();
log::info!("Extensions: {:?}", extensions);
log::debug!("Extensions: {:#?}", extensions);
let shading_language_version = {
let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION);
log::info!("SL version: {}", sl_version);
let (sl_major, sl_minor) = Self::parse_version(&version).ok()?;
let value = (sl_major * 100 + sl_minor * 10) as u16;
let (sl_major, sl_minor) = Self::parse_version(&sl_version).ok()?;
let value = sl_major as u16 * 100 + sl_minor as u16 * 10;
naga::back::glsl::Version::Embedded(value)
};

View File

@@ -403,23 +403,22 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
// issue the clears
for (i, cat) in desc.color_attachments.iter().enumerate() {
if !cat.ops.contains(crate::AttachmentOp::LOAD) {
let draw_buffer = glow::DRAW_BUFFER0 + i as u32;
let c = &cat.clear_value;
self.cmd_buffer
.commands
.push(match cat.target.view.sample_type {
wgt::TextureSampleType::Float { .. } => C::ClearColorF(
draw_buffer,
[c.r as f32, c.g as f32, c.r as f32, c.a as f32],
i as u32,
[c.r as f32, c.g as f32, c.b as f32, c.a as f32],
),
wgt::TextureSampleType::Depth => unimplemented!(),
wgt::TextureSampleType::Uint => C::ClearColorU(
draw_buffer,
[c.r as u32, c.g as u32, c.r as u32, c.a as u32],
i as u32,
[c.r as u32, c.g as u32, c.b as u32, c.a as u32],
),
wgt::TextureSampleType::Sint => C::ClearColorI(
draw_buffer,
[c.r as i32, c.g as i32, c.r as i32, c.a as i32],
i as u32,
[c.r as i32, c.g as i32, c.b as i32, c.a as i32],
),
});
}

View File

@@ -275,19 +275,19 @@ impl crate::Device<super::Api> for super::Device {
} else {
glow::ARRAY_BUFFER
};
let map_coherent = false;
let map_flags = glow::MAP_PERSISTENT_BIT
| if map_coherent {
glow::MAP_COHERENT_BIT
} else {
0
};
let mut storage_flags = 0;
let mut 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) {
storage_flags |= map_flags | glow::MAP_READ_BIT;
map_flags |= glow::MAP_READ_BIT;
}
if desc.usage.contains(crate::BufferUse::MAP_WRITE) {
storage_flags |= map_flags | glow::MAP_WRITE_BIT;
map_flags |= glow::MAP_WRITE_BIT;
}
let raw = gl.create_buffer().unwrap();
@@ -296,7 +296,7 @@ impl crate::Device<super::Api> for super::Device {
.size
.try_into()
.map_err(|_| crate::DeviceError::OutOfMemory)?;
gl.buffer_storage(target, raw_size, None, storage_flags);
gl.buffer_storage(target, raw_size, None, map_flags);
gl.bind_buffer(target, None);
Ok(super::Buffer {
@@ -513,11 +513,63 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &crate::SamplerDescriptor,
) -> Result<super::Sampler, crate::DeviceError> {
use super::Sampled;
let gl = &self.shared.context;
let raw = gl.create_sampler().unwrap();
super::SamplerBinding(raw).configure_sampling(gl, desc);
let (min, mag) =
conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter);
gl.sampler_parameter_i32(raw, glow::TEXTURE_MIN_FILTER, min as i32);
gl.sampler_parameter_i32(raw, glow::TEXTURE_MAG_FILTER, mag as i32);
gl.sampler_parameter_i32(
raw,
glow::TEXTURE_WRAP_S,
conv::map_address_mode(desc.address_modes[0]) as i32,
);
gl.sampler_parameter_i32(
raw,
glow::TEXTURE_WRAP_T,
conv::map_address_mode(desc.address_modes[1]) as i32,
);
gl.sampler_parameter_i32(
raw,
glow::TEXTURE_WRAP_R,
conv::map_address_mode(desc.address_modes[2]) as i32,
);
if let Some(border_color) = desc.border_color {
let mut border = match border_color {
wgt::SamplerBorderColor::TransparentBlack => [0.0; 4],
wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0],
wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4],
};
gl.sampler_parameter_f32_slice(raw, glow::TEXTURE_BORDER_COLOR, &mut border);
}
if let Some(ref range) = desc.lod_clamp {
gl.sampler_parameter_f32(raw, glow::TEXTURE_MIN_LOD, range.start);
gl.sampler_parameter_f32(raw, glow::TEXTURE_MAX_LOD, range.end);
}
//TODO: `desc.anisotropy_clamp` depends on the downlevel flag
// gl.sampler_parameter_f32(rawow::TEXTURE_MAX_ANISOTROPY, aniso as f32);
//set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0);
if let Some(compare) = desc.compare {
gl.sampler_parameter_i32(
raw,
glow::TEXTURE_COMPARE_MODE,
glow::COMPARE_REF_TO_TEXTURE as i32,
);
gl.sampler_parameter_i32(
raw,
glow::TEXTURE_COMPARE_FUNC,
conv::map_compare_func(compare) as i32,
);
}
Ok(super::Sampler { raw })
}

View File

@@ -1,7 +1,7 @@
use glow::HasContext;
use parking_lot::Mutex;
use std::{os::raw, ptr, sync::Arc};
use std::{ffi::CStr, os::raw, ptr, sync::Arc};
const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8;
const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
@@ -41,6 +41,56 @@ extern "C" {
) -> i32;
}
type EglLabel = *const raw::c_void;
type EGLDEBUGPROCKHR = Option<
unsafe extern "system" fn(
error: egl::Enum,
command: *const raw::c_char,
message_type: u32,
thread_label: EglLabel,
object_label: EglLabel,
message: *const raw::c_char,
),
>;
const EGL_DEBUG_MSG_CRITICAL_KHR: u32 = 0x33B9;
const EGL_DEBUG_MSG_ERROR_KHR: u32 = 0x33BA;
const EGL_DEBUG_MSG_WARN_KHR: u32 = 0x33BB;
const EGL_DEBUG_MSG_INFO_KHR: u32 = 0x33BC;
type EglDebugMessageControlFun =
unsafe extern "system" fn(proc: EGLDEBUGPROCKHR, attrib_list: *const egl::Attrib) -> raw::c_int;
unsafe extern "system" fn egl_debug_proc(
error: egl::Enum,
command_raw: *const raw::c_char,
message_type: u32,
_thread_label: EglLabel,
_object_label: EglLabel,
message_raw: *const raw::c_char,
) {
let log_severity = match message_type {
EGL_DEBUG_MSG_CRITICAL_KHR | EGL_DEBUG_MSG_ERROR_KHR => log::Level::Error,
EGL_DEBUG_MSG_WARN_KHR => log::Level::Warn,
EGL_DEBUG_MSG_INFO_KHR => log::Level::Info,
_ => log::Level::Debug,
};
let command = CStr::from_ptr(command_raw).to_string_lossy();
let message = if message_raw.is_null() {
"".into()
} else {
CStr::from_ptr(message_raw).to_string_lossy()
};
log::log!(
log_severity,
"EGL '{}' code 0x{:x}: {}",
command,
error,
message,
);
}
fn open_x_display() -> Option<(ptr::NonNull<raw::c_void>, libloading::Library)> {
log::info!("Loading X11 library to get the current display");
unsafe {
@@ -112,7 +162,7 @@ fn choose_config(
Err(crate::InstanceError)
}
fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
let source_str = match source {
glow::DEBUG_SOURCE_API => "API",
glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
@@ -146,12 +196,16 @@ fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, mess
log::log!(
log_severity,
"[{}/{}] ID {} : {}",
"GLES: [{}/{}] ID {} : {}",
source_str,
type_str,
id,
message
);
if log_severity == log::Level::Error {
std::process::exit(1);
}
}
#[derive(Debug)]
@@ -181,11 +235,10 @@ impl Inner {
.query_string(Some(display), egl::EXTENSIONS)
.unwrap()
.to_string_lossy();
log::info!(
"Display vendor {:?}, version {:?}, extensions: {:?}",
vendor,
version,
display_extensions
log::info!("Display vendor {:?}, version {:?}", vendor, version,);
log::debug!(
"Display extensions: {:#?}",
display_extensions.split_whitespace().collect::<Vec<_>>()
);
if log::max_level() >= log::LevelFilter::Trace {
@@ -211,7 +264,7 @@ impl Inner {
egl::CONTEXT_CLIENT_VERSION,
3, // Request GLES 3.0 or higher
];
if flags.contains(crate::InstanceFlag::VALIDATION)
if flags.contains(crate::InstanceFlag::DEBUG)
&& wsi_library.is_none()
&& !cfg!(target_os = "android")
{
@@ -294,7 +347,10 @@ impl crate::Instance<super::Api> for Instance {
Ok(ext) => ext.to_string_lossy().into_owned(),
Err(_) => String::new(),
};
log::info!("Client extensions: {:?}", client_ext_str);
log::debug!(
"Client extensions: {:#?}",
client_ext_str.split_whitespace().collect::<Vec<_>>()
);
let mut wsi_library = None;
@@ -335,6 +391,26 @@ impl crate::Instance<super::Api> for Instance {
egl.get_display(egl::DEFAULT_DISPLAY).unwrap()
};
if desc.flags.contains(crate::InstanceFlag::VALIDATION)
&& client_ext_str.contains(&"EGL_KHR_debug")
{
log::info!("Enabling EGL debug output");
let function: EglDebugMessageControlFun =
std::mem::transmute(egl.get_proc_address("eglDebugMessageControlKHR").unwrap());
let attributes = [
EGL_DEBUG_MSG_CRITICAL_KHR as egl::Attrib,
1,
EGL_DEBUG_MSG_ERROR_KHR as egl::Attrib,
1,
EGL_DEBUG_MSG_WARN_KHR as egl::Attrib,
1,
EGL_DEBUG_MSG_INFO_KHR as egl::Attrib,
1,
egl::ATTRIB_NONE,
];
(function)(Some(egl_debug_proc), attributes.as_ptr());
}
let inner = Inner::create(desc.flags, egl, display, wsi_library.as_ref())?;
Ok(Instance {
@@ -356,6 +432,7 @@ impl crate::Instance<super::Api> for Instance {
#[cfg(not(any(target_os = "android", target_os = "macos")))]
let (mut temp_xlib_handle, mut temp_xcb_handle);
#[allow(trivial_casts)]
let native_window_ptr = match has_handle.raw_window_handle() {
#[cfg(not(any(target_os = "android", target_os = "macos")))]
Rwh::Xlib(handle) => {
@@ -396,9 +473,13 @@ impl crate::Instance<super::Api> for Instance {
)
.unwrap();
let new_inner =
Inner::create(inner.egl.clone(), display, self.wsi_library.as_ref())
.map_err(|_| w::InitError::UnsupportedWindowHandle)?;
let new_inner = Inner::create(
self.flags,
inner.egl.clone(),
display,
self.wsi_library.as_ref(),
)
.map_err(|_| crate::InstanceError)?;
let old_inner = std::mem::replace(inner.deref_mut(), new_inner);
inner.wl_display = Some(handle.display);
@@ -526,9 +607,10 @@ impl crate::Instance<super::Api> for Instance {
.map_or(ptr::null(), |p| p as *const _)
});
if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() {
if self.flags.contains(crate::InstanceFlag::VALIDATION) && gl.supports_debug() {
log::info!("Enabling GLES debug output");
gl.enable(glow::DEBUG_OUTPUT);
gl.debug_message_callback(debug_message_callback);
gl.debug_message_callback(gl_debug_message_callback);
}
super::Adapter::expose(gl).into_iter().collect()
@@ -581,7 +663,6 @@ 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

@@ -62,95 +62,6 @@ bitflags::bitflags! {
type BindTarget = u32;
trait Sampled {
unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32);
// see https://github.com/grovesNL/glow/issues/170
unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]);
unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32);
unsafe fn configure_sampling(&self, gl: &glow::Context, desc: &crate::SamplerDescriptor) {
let (min, mag) =
conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter);
self.set_param_int(gl, glow::TEXTURE_MIN_FILTER, min as i32);
self.set_param_int(gl, glow::TEXTURE_MAG_FILTER, mag as i32);
self.set_param_int(
gl,
glow::TEXTURE_WRAP_S,
conv::map_address_mode(desc.address_modes[0]) as i32,
);
self.set_param_int(
gl,
glow::TEXTURE_WRAP_T,
conv::map_address_mode(desc.address_modes[1]) as i32,
);
self.set_param_int(
gl,
glow::TEXTURE_WRAP_R,
conv::map_address_mode(desc.address_modes[2]) as i32,
);
if let Some(border_color) = desc.border_color {
let mut border = match border_color {
wgt::SamplerBorderColor::TransparentBlack => [0.0; 4],
wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0],
wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4],
};
self.set_param_float_vec(gl, glow::TEXTURE_BORDER_COLOR, &mut border);
}
if let Some(ref range) = desc.lod_clamp {
self.set_param_float(gl, glow::TEXTURE_MIN_LOD, range.start);
self.set_param_float(gl, glow::TEXTURE_MAX_LOD, range.end);
}
//TODO: `desc.anisotropy_clamp` depends on the downlevel flag
// self.set_param_float(glow::TEXTURE_MAX_ANISOTROPY, aniso as f32);
//set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0);
if let Some(compare) = desc.compare {
self.set_param_int(
gl,
glow::TEXTURE_COMPARE_MODE,
glow::COMPARE_REF_TO_TEXTURE as i32,
);
self.set_param_int(
gl,
glow::TEXTURE_COMPARE_FUNC,
conv::map_compare_func(compare) as i32,
);
}
}
}
struct SamplerBinding(glow::Sampler);
impl Sampled for SamplerBinding {
unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) {
gl.sampler_parameter_f32(self.0, key, value);
}
unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) {
gl.sampler_parameter_f32_slice(self.0, key, values);
}
unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) {
gl.sampler_parameter_i32(self.0, key, value);
}
}
struct SampledTextureBinding(BindTarget);
impl Sampled for SampledTextureBinding {
unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) {
gl.tex_parameter_f32(self.0, key, value);
}
unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) {
gl.tex_parameter_f32_slice(self.0, key, values);
}
unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) {
gl.tex_parameter_i32(self.0, key, value);
}
}
#[derive(Debug, Clone, Copy)]
enum VertexAttribKind {
Float, // glVertexAttribPointer

View File

@@ -20,6 +20,7 @@ impl super::Queue {
unsafe fn reset_state(&self) {
let gl = &self.shared.context;
gl.use_program(None);
gl.bind_framebuffer(glow::FRAMEBUFFER, None);
gl.polygon_offset(0.0, 0.0);
gl.disable(glow::DEPTH_TEST);
gl.disable(glow::STENCIL_TEST);

View File

@@ -554,6 +554,7 @@ impl From<wgt::TextureFormat> for FormatAspect {
bitflags!(
pub struct MemoryFlag: u32 {
const TRANSIENT = 1;
const PREFER_COHERENT = 2;
}
);

View File

@@ -140,6 +140,7 @@ impl crate::Device<super::Api> for super::Device {
let mut options = mtl::MTLResourceOptions::empty();
options |= if map_read || map_write {
// `crate::MemoryFlag::PREFER_COHERENT` is ignored here
mtl::MTLResourceOptions::StorageModeShared
} else {
mtl::MTLResourceOptions::StorageModePrivate

View File

@@ -557,6 +557,11 @@ impl crate::Device<super::Api> for super::Device {
.intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE)
{
let mut flags = gpu_alloc::UsageFlags::HOST_ACCESS;
flags.set(
gpu_alloc::UsageFlags::COHERENT,
desc.memory_flags
.contains(crate::MemoryFlag::PREFER_COHERENT),
);
flags.set(
gpu_alloc::UsageFlags::DOWNLOAD,
desc.usage.contains(crate::BufferUse::MAP_READ),