webgl: Support vertex array objects on macOS.

This commit is contained in:
Josh Matthews 2019-09-13 16:17:47 -04:00
parent 75bc72b29f
commit 0d88c13186
2 changed files with 72 additions and 11 deletions

View file

@ -158,15 +158,16 @@ impl GLContextWrapper {
pub fn apply_command( pub fn apply_command(
&self, &self,
cmd: WebGLCommand, cmd: WebGLCommand,
use_apple_vertex_array: bool,
backtrace: WebGLCommandBacktrace, backtrace: WebGLCommandBacktrace,
state: &mut GLState, state: &mut GLState,
) { ) {
match *self { match *self {
GLContextWrapper::Native(ref ctx) => { GLContextWrapper::Native(ref ctx) => {
WebGLImpl::apply(ctx, state, cmd, backtrace); WebGLImpl::apply(ctx, state, use_apple_vertex_array, cmd, backtrace);
}, },
GLContextWrapper::OSMesa(ref ctx) => { GLContextWrapper::OSMesa(ref ctx) => {
WebGLImpl::apply(ctx, state, cmd, backtrace); WebGLImpl::apply(ctx, state, false, cmd, backtrace);
}, },
} }
} }

View file

@ -13,7 +13,7 @@ use ipc_channel::ipc::{self, OpaqueIpcMessage};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods}; use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
use pixels::{self, PixelFormat}; use pixels::{self, PixelFormat};
use sparkle::gl; use sparkle::gl::{self, Gl};
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell; use std::cell::Cell;
use std::cell::RefCell; use std::cell::RefCell;
@ -30,6 +30,15 @@ pub use crate::webgl_mode::{ThreadMode, WebGLThreads};
struct GLContextData { struct GLContextData {
ctx: GLContextWrapper, ctx: GLContextWrapper,
state: GLState, state: GLState,
use_apple_vertex_arrays: bool,
}
// rust-offscreen-rendering-context creates a legacy OpenGL context on macOS when
// OpenGL 2 support is requested. Legacy contexts return GL errors for the vertex
// array object functions, but support a set of APPLE extension functions that
// provide VAO support instead.
fn needs_apple_vertex_arrays(gl: &gl::Gl, version: WebGLVersion) -> bool {
cfg!(target_os = "macos") && gl.get_type() == gl::GlType::Gl && version == WebGLVersion::WebGL1
} }
pub struct GLState { pub struct GLState {
@ -316,7 +325,12 @@ impl WebGLThread {
&mut self.bound_context_id, &mut self.bound_context_id,
); );
if let Some(data) = data { if let Some(data) = data {
data.ctx.apply_command(command, backtrace, &mut data.state); data.ctx.apply_command(
command,
data.use_apple_vertex_arrays,
backtrace,
&mut data.state,
);
} }
} }
@ -421,11 +435,13 @@ impl WebGLThread {
.0 as usize, .0 as usize,
); );
let (size, texture_id, limits) = ctx.get_info(); let (size, texture_id, limits) = ctx.get_info();
let use_apple_vertex_arrays = needs_apple_vertex_arrays(ctx.gl(), version);
self.contexts.insert( self.contexts.insert(
id, id,
GLContextData { GLContextData {
ctx, ctx,
state: Default::default(), state: Default::default(),
use_apple_vertex_arrays,
}, },
); );
@ -883,6 +899,7 @@ impl WebGLImpl {
pub fn apply<Native: NativeGLContextMethods>( pub fn apply<Native: NativeGLContextMethods>(
ctx: &GLContext<Native>, ctx: &GLContext<Native>,
state: &mut GLState, state: &mut GLState,
use_apple_vertex_array: bool,
command: WebGLCommand, command: WebGLCommand,
_backtrace: WebGLCommandBacktrace, _backtrace: WebGLCommandBacktrace,
) { ) {
@ -1304,11 +1321,37 @@ impl WebGLImpl {
WebGLCommand::Finish(ref sender) => Self::finish(ctx.gl(), sender), WebGLCommand::Finish(ref sender) => Self::finish(ctx.gl(), sender),
WebGLCommand::Flush => ctx.gl().flush(), WebGLCommand::Flush => ctx.gl().flush(),
WebGLCommand::GenerateMipmap(target) => ctx.gl().generate_mipmap(target), WebGLCommand::GenerateMipmap(target) => ctx.gl().generate_mipmap(target),
WebGLCommand::CreateVertexArray(ref chan) => Self::create_vertex_array(ctx.gl(), chan), WebGLCommand::CreateVertexArray(ref chan) => {
WebGLCommand::DeleteVertexArray(id) => ctx.gl().delete_vertex_arrays(&[id.get()]), Self::create_vertex_array(ctx.gl(), use_apple_vertex_array, chan)
WebGLCommand::BindVertexArray(id) => ctx },
.gl() WebGLCommand::DeleteVertexArray(id) => {
.bind_vertex_array(id.map_or(0, WebGLVertexArrayId::get)), let gl = ctx.gl();
let ids = [id.get()];
if use_apple_vertex_array {
match gl {
Gl::Gl(gl) => unsafe {
gl.DeleteVertexArraysAPPLE(ids.len() as gl::GLsizei, ids.as_ptr());
},
Gl::Gles(_) => unimplemented!("No GLES on macOS"),
}
} else {
gl.delete_vertex_arrays(&ids)
}
},
WebGLCommand::BindVertexArray(id) => {
let gl = ctx.gl();
let id = id.map_or(0, WebGLVertexArrayId::get);
if use_apple_vertex_array {
match gl {
Gl::Gl(gl) => unsafe {
gl.BindVertexArrayAPPLE(id);
},
Gl::Gles(_) => unimplemented!("No GLES on macOS"),
}
} else {
gl.bind_vertex_array(id)
}
},
WebGLCommand::GetParameterBool(param, ref sender) => { WebGLCommand::GetParameterBool(param, ref sender) => {
let mut value = [0]; let mut value = [0];
unsafe { unsafe {
@ -1847,8 +1890,25 @@ impl WebGLImpl {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn create_vertex_array(gl: &gl::Gl, chan: &WebGLSender<Option<WebGLVertexArrayId>>) { fn create_vertex_array(
let vao = gl.gen_vertex_arrays(1)[0]; gl: &gl::Gl,
use_apple_ext: bool,
chan: &WebGLSender<Option<WebGLVertexArrayId>>,
) {
let vao = if use_apple_ext {
match gl {
Gl::Gl(gl) => {
let mut ids = vec![0];
unsafe {
gl.GenVertexArraysAPPLE(ids.len() as gl::GLsizei, ids.as_mut_ptr());
}
ids[0]
},
Gl::Gles(_) => unimplemented!("No GLES on macOS"),
}
} else {
gl.gen_vertex_arrays(1)[0]
};
let vao = if vao == 0 { let vao = if vao == 0 {
None None
} else { } else {