diff --git a/iris-hostgl/src/calls.rs b/iris-hostgl/src/calls.rs index 76bd8696..48f6505b 100644 --- a/iris-hostgl/src/calls.rs +++ b/iris-hostgl/src/calls.rs @@ -2416,9 +2416,11 @@ pub fn run(x: &mut Exec, op: usize, c: &[u8]) -> Option { let c1 = get_count(a0 as u32); let n1 = x.count(c1)?; let mut o1 = vec![0 as u8; n1.max(1) + 16]; + if !x.color_matrix_query(a0, &mut o1) { let f = x.func(151)?; let g: extern "C" fn(u32, *mut u8) = unsafe { std::mem::transmute(f) }; g(a0, o1.as_mut_ptr()); + } x.get_limit(a0, &mut o1); x.put::(a1, &o1[..n1])?; x.image_done(); @@ -2620,9 +2622,11 @@ pub fn run(x: &mut Exec, op: usize, c: &[u8]) -> Option { let c1 = get_count(a0 as u32); let n1 = x.count(c1)?; let mut o1 = vec![0 as f64; n1.max(1) + 16]; + if !x.color_matrix_query(a0, &mut o1) { let f = x.func(166)?; let g: extern "C" fn(u32, *mut f64) = unsafe { std::mem::transmute(f) }; g(a0, o1.as_mut_ptr()); + } x.get_limit(a0, &mut o1); x.put::(a1, &o1[..n1])?; x.image_done(); @@ -2637,9 +2641,11 @@ pub fn run(x: &mut Exec, op: usize, c: &[u8]) -> Option { let c1 = get_count(a0 as u32); let n1 = x.count(c1)?; let mut o1 = vec![0 as f32; n1.max(1) + 16]; + if !x.color_matrix_query(a0, &mut o1) { let f = x.func(168)?; let g: extern "C" fn(u32, *mut f32) = unsafe { std::mem::transmute(f) }; g(a0, o1.as_mut_ptr()); + } x.get_limit(a0, &mut o1); x.put::(a1, &o1[..n1])?; x.image_done(); @@ -2742,9 +2748,11 @@ pub fn run(x: &mut Exec, op: usize, c: &[u8]) -> Option { let c1 = get_count(a0 as u32); let n1 = x.count(c1)?; let mut o1 = vec![0 as i32; n1.max(1) + 16]; + if !x.color_matrix_query(a0, &mut o1) { let f = x.func(176)?; let g: extern "C" fn(u32, *mut i32) = unsafe { std::mem::transmute(f) }; g(a0, o1.as_mut_ptr()); + } x.get_limit(a0, &mut o1); x.put::(a1, &o1[..n1])?; x.image_done(); diff --git a/iris-hostgl/src/exec.rs b/iris-hostgl/src/exec.rs index c1b3788d..65d9bf49 100644 --- a/iris-hostgl/src/exec.rs +++ b/iris-hostgl/src/exec.rs @@ -1315,6 +1315,43 @@ impl<'a> Exec<'a> { /// fixed-function emulation (`emul`) is written for the units we exercise; /// 8 is far above what IRIX-era software asks for (Quake III wants 2), and /// a ceiling is easier to raise later than a wrong answer is to find. + /// SGI_color_matrix's state, answered here when the host GL has no + /// colour matrix: Mesa's compatibility profile has no ARB_imaging, so it + /// refused these queries with GL_INVALID_ENUM and left the answer 0. + /// SGI's IRIS GL (IGLOO) asks for GL_MAX_COLOR_MATRIX_STACK_DEPTH when it + /// sets up a window, sizes a stack from it, and crashed on 0: on a Linux + /// host every IRIS GL program that asked for a stencil buffer died in + /// gconfig(). The answers are IMPACT's -- a stack of 2, 1 deep, holding + /// the identity -- and no error is raised. True when answered here. + pub fn color_matrix_query(&mut self, pname: u32, out: &mut [T]) -> bool { + const GL_COLOR_MATRIX: u32 = 0x80B1; + const GL_COLOR_MATRIX_STACK_DEPTH: u32 = 0x80B2; + const GL_MAX_COLOR_MATRIX_STACK_DEPTH: u32 = 0x80B3; + if !(GL_COLOR_MATRIX..=GL_MAX_COLOR_MATRIX_STACK_DEPTH).contains(&pname) + || !self.backend.lookup("glColorTable").is_null() + { + return false; + } + match pname { + GL_COLOR_MATRIX => { + for (i, v) in out.iter_mut().take(16).enumerate() { + *v = T::from_i64((i % 5 == 0) as i64); + } + } + GL_COLOR_MATRIX_STACK_DEPTH => { + if let Some(v) = out.first_mut() { + *v = T::from_i64(1); + } + } + _ => { + if let Some(v) = out.first_mut() { + *v = T::from_i64(2); + } + } + } + true + } + pub fn get_limit(&mut self, pname: u32, out: &mut [T]) { // The accumulation buffer is this library's (accum.rs), not the // host's, which has none to report. diff --git a/iris-hostgl/src/tests.rs b/iris-hostgl/src/tests.rs index 332854d5..6175b76b 100644 --- a/iris-hostgl/src/tests.rs +++ b/iris-hostgl/src/tests.rs @@ -1734,3 +1734,21 @@ fn texture_internal_format_is_answered_as_the_program_gave_it() { assert_eq!(v(0), 0x1908, "the proxy: GL_RGBA, as asked"); assert_eq!(v(4), 3, "the texture: 3, as given"); } + +/// SGI_color_matrix's limits answer as IMPACT's do on any host, and asking +/// raises no error: on a host without a colour matrix (Mesa) the answer was +/// 0 with GL_INVALID_ENUM, and SGI's IRIS GL crashed sizing its stack from it. +#[test] +fn color_matrix_limits_are_answered_and_raise_no_error() { + let mut g = Guest::new(512); + g.context(0x0040_000f, 16, 16); + let out = g.mem.alloc(16 * 4, 0); + let mut e = Enc::default(); + e.cmd("glGetIntegerv", &[V::I(0x80B3), V::A(out)]) // GL_MAX_COLOR_MATRIX_STACK_DEPTH + .cmd("glGetIntegerv", &[V::I(0x80B2), V::A(out + 4)]) // GL_COLOR_MATRIX_STACK_DEPTH + .cmd("glGetError", &[]); + assert_eq!(g.batch(&e.take()), Reply::Ok(0, 0), "no GL error from the queries"); + let v = |i: u64| i32::from_be_bytes(g.mem.get(out + i, 4).try_into().unwrap()); + assert!(v(0) >= 2, "a colour matrix stack of at least 2, as IMPACT's: {}", v(0)); + assert_eq!(v(4), 1, "one deep"); +} diff --git a/iris-hostgl/tools/glshim.py b/iris-hostgl/tools/glshim.py index fa451af8..f5f6cb80 100644 --- a/iris-hostgl/tools/glshim.py +++ b/iris-hostgl/tools/glshim.py @@ -553,6 +553,13 @@ def gen_rust(api): "glFogf": "x.fog(a0, &[a1])", "glFogi": "x.fog(a0, &[a1 as f32])", "glFogfv": "x.fog(a0, &v1)", + # SGI_color_matrix's state on a host without a colour matrix (Mesa's + # compatibility profile has no ARB_imaging): answered here, as IMPACT + # answers it, rather than refused (Exec::color_matrix_query). + "glGetBooleanv": "x.color_matrix_query(a0, &mut o1)", + "glGetIntegerv": "x.color_matrix_query(a0, &mut o1)", + "glGetFloatv": "x.color_matrix_query(a0, &mut o1)", + "glGetDoublev": "x.color_matrix_query(a0, &mut o1)", } # Calls that read the framebuffer: a multisampled drawable is resolved first.