diff options
Diffstat (limited to 'components/canvas/webgl_thread.rs')
-rw-r--r-- | components/canvas/webgl_thread.rs | 1204 |
1 files changed, 0 insertions, 1204 deletions
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs deleted file mode 100644 index 907233a3b89..00000000000 --- a/components/canvas/webgl_thread.rs +++ /dev/null @@ -1,1204 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use canvas_traits::canvas::byte_swap; -use canvas_traits::webgl::*; -use euclid::Size2D; -use gleam::gl; -use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods}; -use std::collections::HashMap; -use std::mem; -use std::thread; -use super::gl_context::{GLContextFactory, GLContextWrapper}; -use webrender; -use webrender_api; - -/// WebGL Threading API entry point that lives in the constellation. -/// It allows to get a WebGLThread handle for each script pipeline. -pub use ::webgl_mode::WebGLThreads; - -/// A WebGLThread manages the life cycle and message multiplexing of -/// a set of WebGLContexts living in the same thread. -pub struct WebGLThread<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> { - /// Factory used to create a new GLContext shared with the WR/Main thread. - gl_factory: GLContextFactory, - /// Channel used to generate/update or delete `webrender_api::ImageKey`s. - webrender_api: webrender_api::RenderApi, - /// Map of live WebGLContexts. - contexts: HashMap<WebGLContextId, GLContextWrapper>, - /// Cached information for WebGLContexts. - cached_context_info: HashMap<WebGLContextId, WebGLContextInfo>, - /// Current bound context. - bound_context_id: Option<WebGLContextId>, - /// Id generator for new WebGLContexts. - next_webgl_id: usize, - /// Handler user to send WebVR commands. - webvr_compositor: Option<VR>, - /// Generic observer that listens WebGLContext creation, resize or removal events. - observer: OB, -} - -impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, OB> { - pub fn new(gl_factory: GLContextFactory, - webrender_api_sender: webrender_api::RenderApiSender, - webvr_compositor: Option<VR>, - observer: OB) -> Self { - WebGLThread { - gl_factory, - webrender_api: webrender_api_sender.create_api(), - contexts: HashMap::new(), - cached_context_info: HashMap::new(), - bound_context_id: None, - next_webgl_id: 0, - webvr_compositor, - observer: observer, - } - } - - /// Creates a new `WebGLThread` and returns a Sender to - /// communicate with it. - pub fn start(gl_factory: GLContextFactory, - webrender_api_sender: webrender_api::RenderApiSender, - webvr_compositor: Option<VR>, - observer: OB) - -> WebGLSender<WebGLMsg> { - let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap(); - let result = sender.clone(); - thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || { - let mut renderer = WebGLThread::new(gl_factory, - webrender_api_sender, - webvr_compositor, - observer); - let webgl_chan = WebGLChan(sender); - loop { - let msg = receiver.recv().unwrap(); - let exit = renderer.handle_msg(msg, &webgl_chan); - if exit { - return; - } - } - }).expect("Thread spawning failed"); - - result - } - - /// Handles a generic WebGLMsg message - #[inline] - fn handle_msg(&mut self, msg: WebGLMsg, webgl_chan: &WebGLChan) -> bool { - match msg { - WebGLMsg::CreateContext(size, attributes, result_sender) => { - let result = self.create_webgl_context(size, attributes); - result_sender.send(result.map(|(id, limits, share_mode)| - WebGLCreateContextResult { - sender: WebGLMsgSender::new(id, webgl_chan.clone()), - limits: limits, - share_mode: share_mode, - } - )).unwrap(); - }, - WebGLMsg::ResizeContext(ctx_id, size, sender) => { - self.resize_webgl_context(ctx_id, size, sender); - }, - WebGLMsg::RemoveContext(ctx_id) => { - self.remove_webgl_context(ctx_id); - }, - WebGLMsg::WebGLCommand(ctx_id, command) => { - self.handle_webgl_command(ctx_id, command); - }, - WebGLMsg::WebVRCommand(ctx_id, command) => { - self.handle_webvr_command(ctx_id, command); - }, - WebGLMsg::Lock(ctx_id, sender) => { - self.handle_lock(ctx_id, sender); - }, - WebGLMsg::Unlock(ctx_id) => { - self.handle_unlock(ctx_id); - }, - WebGLMsg::UpdateWebRenderImage(ctx_id, sender) => { - self.handle_update_wr_image(ctx_id, sender); - }, - WebGLMsg::Exit => { - return true; - } - } - - false - } - - /// Handles a WebGLCommand for a specific WebGLContext - fn handle_webgl_command(&mut self, context_id: WebGLContextId, command: WebGLCommand) { - if let Some(ctx) = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) { - ctx.apply_command(command); - } - } - - /// Handles a WebVRCommand for a specific WebGLContext - fn handle_webvr_command(&mut self, context_id: WebGLContextId, command: WebVRCommand) { - Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id); - let texture = match command { - WebVRCommand::SubmitFrame(..) => { - self.cached_context_info.get(&context_id) - }, - _ => None - }; - self.webvr_compositor.as_mut().unwrap().handle(command, texture.map(|t| (t.texture_id, t.size))); - } - - /// Handles a lock external callback received from webrender::ExternalImageHandler - fn handle_lock(&mut self, context_id: WebGLContextId, sender: WebGLSender<(u32, Size2D<i32>)>) { - let ctx = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) - .expect("WebGLContext not found in a WebGLMsg::Lock message"); - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - // Use a OpenGL Fence to perform the lock. - info.gl_sync = Some(ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)); - - sender.send((info.texture_id, info.size)).unwrap(); - } - - /// Handles an unlock external callback received from webrender::ExternalImageHandler - fn handle_unlock(&mut self, context_id: WebGLContextId) { - let ctx = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) - .expect("WebGLContext not found in a WebGLMsg::Unlock message"); - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - if let Some(gl_sync) = info.gl_sync.take() { - // glFlush must be called before glWaitSync. - ctx.gl().flush(); - // Wait until the GLSync object is signaled. - ctx.gl().wait_sync(gl_sync, 0, gl::TIMEOUT_IGNORED); - // Release the GLSync object. - ctx.gl().delete_sync(gl_sync); - } - } - - /// Creates a new WebGLContext - fn create_webgl_context(&mut self, - size: Size2D<i32>, - attributes: GLContextAttributes) - -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> { - // First try to create a shared context for the best performance. - // Fallback to readback mode if the shared context creation fails. - let result = self.gl_factory.new_shared_context(size, attributes) - .map(|r| (r, WebGLContextShareMode::SharedTexture)) - .or_else(|_| { - let ctx = self.gl_factory.new_context(size, attributes); - ctx.map(|r| (r, WebGLContextShareMode::Readback)) - }); - - // Creating a new GLContext may make the current bound context_id dirty. - // Clear it to ensure that make_current() is called in subsequent commands. - self.bound_context_id = None; - - match result { - Ok((ctx, share_mode)) => { - let id = WebGLContextId(self.next_webgl_id); - let (size, texture_id, limits) = ctx.get_info(); - self.next_webgl_id += 1; - self.contexts.insert(id, ctx); - self.cached_context_info.insert(id, WebGLContextInfo { - texture_id, - size, - alpha: attributes.alpha, - image_key: None, - share_mode, - gl_sync: None, - old_image_key: None, - very_old_image_key: None, - }); - - self.observer.on_context_create(id, texture_id, size); - - Ok((id, limits, share_mode)) - }, - Err(msg) => { - Err(msg.to_owned()) - } - } - } - - /// Resizes a WebGLContext - fn resize_webgl_context(&mut self, - context_id: WebGLContextId, - size: Size2D<i32>, - sender: WebGLSender<Result<(), String>>) { - let ctx = Self::make_current_if_needed_mut(context_id, &mut self.contexts, &mut self.bound_context_id); - match ctx.resize(size) { - Ok(_) => { - let (real_size, texture_id, _) = ctx.get_info(); - self.observer.on_context_resize(context_id, texture_id, real_size); - - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - // Update webgl texture size. Texture id may change too. - info.texture_id = texture_id; - info.size = real_size; - // WR doesn't support resizing and requires to create a new `ImageKey`. - // Mark the current image_key to be deleted later in the next epoch. - if let Some(image_key) = info.image_key.take() { - // If this executes, then we are in a new epoch since we last recreated the canvas, - // so `old_image_key` must be `None`. - debug_assert!(info.old_image_key.is_none()); - info.old_image_key = Some(image_key); - } - - sender.send(Ok(())).unwrap(); - }, - Err(msg) => { - sender.send(Err(msg.into())).unwrap(); - } - } - } - - /// Removes a WebGLContext and releases attached resources. - fn remove_webgl_context(&mut self, context_id: WebGLContextId) { - // Release webrender image keys. - if let Some(info) = self.cached_context_info.remove(&context_id) { - let mut updates = webrender_api::ResourceUpdates::new(); - - if let Some(image_key) = info.image_key { - updates.delete_image(image_key); - } - if let Some(image_key) = info.old_image_key { - updates.delete_image(image_key); - } - if let Some(image_key) = info.very_old_image_key { - updates.delete_image(image_key); - } - - self.webrender_api.update_resources(updates) - } - - // Release GL context. - if self.contexts.remove(&context_id).is_some() { - self.observer.on_context_delete(context_id); - } - - // Removing a GLContext may make the current bound context_id dirty. - self.bound_context_id = None; - } - - /// Handles the creation/update of webrender_api::ImageKeys fpr a specific WebGLContext. - /// This method is invoked from a UpdateWebRenderImage message sent by the layout thread. - /// If SharedTexture is used the UpdateWebRenderImage message is sent only after a WebGLContext creation or resize. - /// If Readback is used UpdateWebRenderImage message is sent always on each layout iteration in order to - /// submit the updated raw pixels. - fn handle_update_wr_image(&mut self, context_id: WebGLContextId, sender: WebGLSender<webrender_api::ImageKey>) { - let info = self.cached_context_info.get_mut(&context_id).unwrap(); - let webrender_api = &self.webrender_api; - - let image_key = match info.share_mode { - WebGLContextShareMode::SharedTexture => { - let size = info.size; - let alpha = info.alpha; - // Reuse existing ImageKey or generate a new one. - // When using a shared texture ImageKeys are only generated after a WebGLContext creation or resize. - *info.image_key.get_or_insert_with(|| { - Self::create_wr_external_image(webrender_api, size, alpha, context_id) - }) - }, - WebGLContextShareMode::Readback => { - let pixels = Self::raw_pixels(&self.contexts[&context_id], info.size); - match info.image_key.clone() { - Some(image_key) => { - // ImageKey was already created, but WR Images must - // be updated every frame in readback mode to send the new raw pixels. - Self::update_wr_readback_image(webrender_api, - info.size, - info.alpha, - image_key, - pixels); - - image_key - }, - None => { - // Generate a new ImageKey for Readback mode. - let image_key = Self::create_wr_readback_image(webrender_api, - info.size, - info.alpha, - pixels); - info.image_key = Some(image_key); - image_key - } - } - } - }; - - // Delete old image - if let Some(image_key) = mem::replace(&mut info.very_old_image_key, info.old_image_key.take()) { - let mut updates = webrender_api::ResourceUpdates::new(); - updates.delete_image(image_key); - self.webrender_api.update_resources(updates); - } - - // Send the ImageKey to the Layout thread. - sender.send(image_key).unwrap(); - } - - /// Gets a reference to a GLContextWrapper for a given WebGLContextId and makes it current if required. - fn make_current_if_needed<'a>(context_id: WebGLContextId, - contexts: &'a HashMap<WebGLContextId, GLContextWrapper>, - bound_id: &mut Option<WebGLContextId>) -> Option<&'a GLContextWrapper> { - contexts.get(&context_id).and_then(|ctx| { - if Some(context_id) != *bound_id { - ctx.make_current(); - *bound_id = Some(context_id); - } - - Some(ctx) - }) - } - - /// Gets a mutable reference to a GLContextWrapper for a WebGLContextId and makes it current if required. - fn make_current_if_needed_mut<'a>(context_id: WebGLContextId, - contexts: &'a mut HashMap<WebGLContextId, GLContextWrapper>, - bound_id: &mut Option<WebGLContextId>) -> &'a mut GLContextWrapper { - let ctx = contexts.get_mut(&context_id).expect("WebGLContext not found!"); - if Some(context_id) != *bound_id { - ctx.make_current(); - *bound_id = Some(context_id); - } - ctx - } - - /// Creates a `webrender_api::ImageKey` that uses shared textures. - fn create_wr_external_image(webrender_api: &webrender_api::RenderApi, - size: Size2D<i32>, - alpha: bool, - context_id: WebGLContextId) -> webrender_api::ImageKey { - let descriptor = Self::image_descriptor(size, alpha); - - let data = webrender_api::ExternalImageData { - id: webrender_api::ExternalImageId(context_id.0 as u64), - channel_index: 0, - image_type: webrender_api::ExternalImageType::Texture2DHandle, - }; - let data = webrender_api::ImageData::External(data); - - let image_key = webrender_api.generate_image_key(); - let mut updates = webrender_api::ResourceUpdates::new(); - updates.add_image(image_key, - descriptor, - data, - None); - webrender_api.update_resources(updates); - - image_key - } - - /// Creates a `webrender_api::ImageKey` that uses raw pixels. - fn create_wr_readback_image(webrender_api: &webrender_api::RenderApi, - size: Size2D<i32>, - alpha: bool, - data: Vec<u8>) -> webrender_api::ImageKey { - let descriptor = Self::image_descriptor(size, alpha); - let data = webrender_api::ImageData::new(data); - - let image_key = webrender_api.generate_image_key(); - let mut updates = webrender_api::ResourceUpdates::new(); - updates.add_image(image_key, - descriptor, - data, - None); - webrender_api.update_resources(updates); - - image_key - } - - /// Updates a `webrender_api::ImageKey` that uses raw pixels. - fn update_wr_readback_image(webrender_api: &webrender_api::RenderApi, - size: Size2D<i32>, - alpha: bool, - image_key: webrender_api::ImageKey, - data: Vec<u8>) { - let descriptor = Self::image_descriptor(size, alpha); - let data = webrender_api::ImageData::new(data); - - let mut updates = webrender_api::ResourceUpdates::new(); - updates.update_image(image_key, - descriptor, - data, - None); - webrender_api.update_resources(updates); - } - - /// Helper function to create a `webrender_api::ImageDescriptor`. - fn image_descriptor(size: Size2D<i32>, alpha: bool) -> webrender_api::ImageDescriptor { - webrender_api::ImageDescriptor { - width: size.width as u32, - height: size.height as u32, - stride: None, - format: if alpha { webrender_api::ImageFormat::BGRA8 } else { webrender_api::ImageFormat::RGB8 }, - offset: 0, - is_opaque: !alpha, - } - } - - /// Helper function to fetch the raw pixels used in readback mode. - fn raw_pixels(context: &GLContextWrapper, size: Size2D<i32>) -> Vec<u8> { - let width = size.width as usize; - let height = size.height as usize; - - let mut pixels = context.gl().read_pixels(0, 0, - size.width as gl::GLsizei, - size.height as gl::GLsizei, - gl::RGBA, gl::UNSIGNED_BYTE); - // flip image vertically (texture is upside down) - let orig_pixels = pixels.clone(); - let stride = width * 4; - for y in 0..height { - let dst_start = y * stride; - let src_start = (height - y - 1) * stride; - let src_slice = &orig_pixels[src_start .. src_start + stride]; - (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]); - } - byte_swap(&mut pixels); - pixels - } -} - -impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> Drop for WebGLThread<VR, OB> { - fn drop(&mut self) { - // Call remove_context functions in order to correctly delete WebRender image keys. - let context_ids: Vec<WebGLContextId> = self.contexts.keys().map(|id| *id).collect(); - for id in context_ids { - self.remove_webgl_context(id); - } - } -} - -/// Helper struct to store cached WebGLContext information. -struct WebGLContextInfo { - /// Render to texture identifier used by the WebGLContext. - texture_id: u32, - /// Size of the WebGLContext. - size: Size2D<i32>, - /// True if the WebGLContext uses an alpha channel. - alpha: bool, - /// Currently used WebRender image key. - image_key: Option<webrender_api::ImageKey>, - /// The sharing mode used to send the image to WebRender. - share_mode: WebGLContextShareMode, - /// GLSync Object used for a correct synchronization with Webrender external image callbacks. - gl_sync: Option<gl::GLsync>, - /// An old WebRender image key that can be deleted when the next epoch ends. - old_image_key: Option<webrender_api::ImageKey>, - /// An old WebRender image key that can be deleted when the current epoch ends. - very_old_image_key: Option<webrender_api::ImageKey>, -} - -/// Trait used to observe events in a WebGL Thread. -/// Used in webrender::ExternalImageHandler when multiple WebGL threads are used. -pub trait WebGLThreadObserver: Send + 'static { - fn on_context_create(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>); - fn on_context_resize(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>); - fn on_context_delete(&mut self, ctx_id: WebGLContextId); -} - -/// This trait is used as a bridge between the `WebGLThreads` implementation and -/// the WR ExternalImageHandler API implemented in the `WebGLExternalImageHandler` struct. -/// `WebGLExternalImageHandler<T>` takes care of type conversions between WR and WebGL info (e.g keys, uvs). -/// It uses this trait to notify lock/unlock messages and get the required info that WR needs. -/// `WebGLThreads` receives lock/unlock message notifications and takes care of sending -/// the unlock/lock messages to the appropiate `WebGLThread`. -pub trait WebGLExternalImageApi { - fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D<i32>); - fn unlock(&mut self, ctx_id: WebGLContextId); -} - -/// WebRender External Image Handler implementation -pub struct WebGLExternalImageHandler<T: WebGLExternalImageApi> { - handler: T, -} - -impl<T: WebGLExternalImageApi> WebGLExternalImageHandler<T> { - pub fn new(handler: T) -> Self { - Self { - handler: handler - } - } -} - -impl<T: WebGLExternalImageApi> webrender::ExternalImageHandler for WebGLExternalImageHandler<T> { - /// Lock the external image. Then, WR could start to read the image content. - /// The WR client should not change the image content until the unlock() call. - fn lock(&mut self, - key: webrender_api::ExternalImageId, - _channel_index: u8) -> webrender::ExternalImage { - let ctx_id = WebGLContextId(key.0 as _); - let (texture_id, size) = self.handler.lock(ctx_id); - - webrender::ExternalImage { - u0: 0.0, - u1: size.width as f32, - v1: 0.0, - v0: size.height as f32, - source: webrender::ExternalImageSource::NativeTexture(texture_id), - } - - } - /// Unlock the external image. The WR should not read the image content - /// after this call. - fn unlock(&mut self, - key: webrender_api::ExternalImageId, - _channel_index: u8) { - let ctx_id = WebGLContextId(key.0 as _); - self.handler.unlock(ctx_id); - } -} - -/// WebGL Commands Implementation -pub struct WebGLImpl; - -impl WebGLImpl { - pub fn apply<Native: NativeGLContextMethods>(ctx: &GLContext<Native>, command: WebGLCommand) { - match command { - WebGLCommand::GetContextAttributes(sender) => - sender.send(*ctx.borrow_attributes()).unwrap(), - WebGLCommand::ActiveTexture(target) => - ctx.gl().active_texture(target), - WebGLCommand::AttachShader(program_id, shader_id) => - ctx.gl().attach_shader(program_id.get(), shader_id.get()), - WebGLCommand::DetachShader(program_id, shader_id) => - ctx.gl().detach_shader(program_id.get(), shader_id.get()), - WebGLCommand::BindAttribLocation(program_id, index, name) => - ctx.gl().bind_attrib_location(program_id.get(), index, &name), - WebGLCommand::BlendColor(r, g, b, a) => - ctx.gl().blend_color(r, g, b, a), - WebGLCommand::BlendEquation(mode) => - ctx.gl().blend_equation(mode), - WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) => - ctx.gl().blend_equation_separate(mode_rgb, mode_alpha), - WebGLCommand::BlendFunc(src, dest) => - ctx.gl().blend_func(src, dest), - WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => - ctx.gl().blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha), - WebGLCommand::BufferData(buffer_type, data, usage) => - gl::buffer_data(ctx.gl(), buffer_type, &data, usage), - WebGLCommand::BufferSubData(buffer_type, offset, data) => - gl::buffer_sub_data(ctx.gl(), buffer_type, offset, &data), - WebGLCommand::Clear(mask) => - ctx.gl().clear(mask), - WebGLCommand::ClearColor(r, g, b, a) => - ctx.gl().clear_color(r, g, b, a), - WebGLCommand::ClearDepth(depth) => - ctx.gl().clear_depth(depth), - WebGLCommand::ClearStencil(stencil) => - ctx.gl().clear_stencil(stencil), - WebGLCommand::ColorMask(r, g, b, a) => - ctx.gl().color_mask(r, g, b, a), - WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y, width, height, border) => - ctx.gl().copy_tex_image_2d(target, level, internal_format, x, y, width, height, border), - WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) => - ctx.gl().copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height), - WebGLCommand::CullFace(mode) => - ctx.gl().cull_face(mode), - WebGLCommand::DepthFunc(func) => - ctx.gl().depth_func(func), - WebGLCommand::DepthMask(flag) => - ctx.gl().depth_mask(flag), - WebGLCommand::DepthRange(near, far) => - ctx.gl().depth_range(near, far), - WebGLCommand::Disable(cap) => - ctx.gl().disable(cap), - WebGLCommand::Enable(cap) => - ctx.gl().enable(cap), - WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => - ctx.gl().framebuffer_renderbuffer(target, attachment, renderbuffertarget, - rb.map_or(0, WebGLRenderbufferId::get)), - WebGLCommand::FramebufferTexture2D(target, attachment, textarget, texture, level) => - ctx.gl().framebuffer_texture_2d(target, attachment, textarget, - texture.map_or(0, WebGLTextureId::get), level), - WebGLCommand::FrontFace(mode) => - ctx.gl().front_face(mode), - WebGLCommand::DisableVertexAttribArray(attrib_id) => - ctx.gl().disable_vertex_attrib_array(attrib_id), - WebGLCommand::DrawArrays(mode, first, count) => - ctx.gl().draw_arrays(mode, first, count), - WebGLCommand::DrawElements(mode, count, type_, offset) => - ctx.gl().draw_elements(mode, count, type_, offset as u32), - WebGLCommand::EnableVertexAttribArray(attrib_id) => - ctx.gl().enable_vertex_attrib_array(attrib_id), - WebGLCommand::Hint(name, val) => - ctx.gl().hint(name, val), - WebGLCommand::IsEnabled(cap, chan) => - chan.send(ctx.gl().is_enabled(cap) != 0).unwrap(), - WebGLCommand::LineWidth(width) => - ctx.gl().line_width(width), - WebGLCommand::PixelStorei(name, val) => - ctx.gl().pixel_store_i(name, val), - WebGLCommand::PolygonOffset(factor, units) => - ctx.gl().polygon_offset(factor, units), - WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, chan) => - Self::read_pixels(ctx.gl(), x, y, width, height, format, pixel_type, chan), - WebGLCommand::RenderbufferStorage(target, format, width, height) => - ctx.gl().renderbuffer_storage(target, format, width, height), - WebGLCommand::SampleCoverage(value, invert) => - ctx.gl().sample_coverage(value, invert), - WebGLCommand::Scissor(x, y, width, height) => - ctx.gl().scissor(x, y, width, height), - WebGLCommand::StencilFunc(func, ref_, mask) => - ctx.gl().stencil_func(func, ref_, mask), - WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => - ctx.gl().stencil_func_separate(face, func, ref_, mask), - WebGLCommand::StencilMask(mask) => - ctx.gl().stencil_mask(mask), - WebGLCommand::StencilMaskSeparate(face, mask) => - ctx.gl().stencil_mask_separate(face, mask), - WebGLCommand::StencilOp(fail, zfail, zpass) => - ctx.gl().stencil_op(fail, zfail, zpass), - WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => - ctx.gl().stencil_op_separate(face, fail, zfail, zpass), - WebGLCommand::GetActiveAttrib(program_id, index, chan) => - Self::active_attrib(ctx.gl(), program_id, index, chan), - WebGLCommand::GetActiveUniform(program_id, index, chan) => - Self::active_uniform(ctx.gl(), program_id, index, chan), - WebGLCommand::GetAttribLocation(program_id, name, chan) => - Self::attrib_location(ctx.gl(), program_id, name, chan), - WebGLCommand::GetVertexAttrib(index, pname, chan) => - Self::vertex_attrib(ctx.gl(), index, pname, chan), - WebGLCommand::GetVertexAttribOffset(index, pname, chan) => - Self::vertex_attrib_offset(ctx.gl(), index, pname, chan), - WebGLCommand::GetBufferParameter(target, param_id, chan) => - Self::buffer_parameter(ctx.gl(), target, param_id, chan), - WebGLCommand::GetParameter(param_id, chan) => - Self::parameter(ctx.gl(), param_id, chan), - WebGLCommand::GetProgramParameter(program_id, param_id, chan) => - Self::program_parameter(ctx.gl(), program_id, param_id, chan), - WebGLCommand::GetShaderParameter(shader_id, param_id, chan) => - Self::shader_parameter(ctx.gl(), shader_id, param_id, chan), - WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, chan) => - Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan), - WebGLCommand::GetExtensions(chan) => - Self::get_extensions(ctx.gl(), chan), - WebGLCommand::GetUniformLocation(program_id, name, chan) => - Self::uniform_location(ctx.gl(), program_id, name, chan), - WebGLCommand::GetShaderInfoLog(shader_id, chan) => - Self::shader_info_log(ctx.gl(), shader_id, chan), - WebGLCommand::GetProgramInfoLog(program_id, chan) => - Self::program_info_log(ctx.gl(), program_id, chan), - WebGLCommand::CompileShader(shader_id, source) => - Self::compile_shader(ctx.gl(), shader_id, source), - WebGLCommand::CreateBuffer(chan) => - Self::create_buffer(ctx.gl(), chan), - WebGLCommand::CreateFramebuffer(chan) => - Self::create_framebuffer(ctx.gl(), chan), - WebGLCommand::CreateRenderbuffer(chan) => - Self::create_renderbuffer(ctx.gl(), chan), - WebGLCommand::CreateTexture(chan) => - Self::create_texture(ctx.gl(), chan), - WebGLCommand::CreateProgram(chan) => - Self::create_program(ctx.gl(), chan), - WebGLCommand::CreateShader(shader_type, chan) => - Self::create_shader(ctx.gl(), shader_type, chan), - WebGLCommand::DeleteBuffer(id) => - ctx.gl().delete_buffers(&[id.get()]), - WebGLCommand::DeleteFramebuffer(id) => - ctx.gl().delete_framebuffers(&[id.get()]), - WebGLCommand::DeleteRenderbuffer(id) => - ctx.gl().delete_renderbuffers(&[id.get()]), - WebGLCommand::DeleteTexture(id) => - ctx.gl().delete_textures(&[id.get()]), - WebGLCommand::DeleteProgram(id) => - ctx.gl().delete_program(id.get()), - WebGLCommand::DeleteShader(id) => - ctx.gl().delete_shader(id.get()), - WebGLCommand::BindBuffer(target, id) => - ctx.gl().bind_buffer(target, id.map_or(0, WebGLBufferId::get)), - WebGLCommand::BindFramebuffer(target, request) => - Self::bind_framebuffer(ctx.gl(), target, request, ctx), - WebGLCommand::BindRenderbuffer(target, id) => - ctx.gl().bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)), - WebGLCommand::BindTexture(target, id) => - ctx.gl().bind_texture(target, id.map_or(0, WebGLTextureId::get)), - WebGLCommand::LinkProgram(program_id) => - ctx.gl().link_program(program_id.get()), - WebGLCommand::Uniform1f(uniform_id, v) => - ctx.gl().uniform_1f(uniform_id, v), - WebGLCommand::Uniform1fv(uniform_id, v) => - ctx.gl().uniform_1fv(uniform_id, &v), - WebGLCommand::Uniform1i(uniform_id, v) => - ctx.gl().uniform_1i(uniform_id, v), - WebGLCommand::Uniform1iv(uniform_id, v) => - ctx.gl().uniform_1iv(uniform_id, &v), - WebGLCommand::Uniform2f(uniform_id, x, y) => - ctx.gl().uniform_2f(uniform_id, x, y), - WebGLCommand::Uniform2fv(uniform_id, v) => - ctx.gl().uniform_2fv(uniform_id, &v), - WebGLCommand::Uniform2i(uniform_id, x, y) => - ctx.gl().uniform_2i(uniform_id, x, y), - WebGLCommand::Uniform2iv(uniform_id, v) => - ctx.gl().uniform_2iv(uniform_id, &v), - WebGLCommand::Uniform3f(uniform_id, x, y, z) => - ctx.gl().uniform_3f(uniform_id, x, y, z), - WebGLCommand::Uniform3fv(uniform_id, v) => - ctx.gl().uniform_3fv(uniform_id, &v), - WebGLCommand::Uniform3i(uniform_id, x, y, z) => - ctx.gl().uniform_3i(uniform_id, x, y, z), - WebGLCommand::Uniform3iv(uniform_id, v) => - ctx.gl().uniform_3iv(uniform_id, &v), - WebGLCommand::Uniform4f(uniform_id, x, y, z, w) => - ctx.gl().uniform_4f(uniform_id, x, y, z, w), - WebGLCommand::Uniform4fv(uniform_id, v) => - ctx.gl().uniform_4fv(uniform_id, &v), - WebGLCommand::Uniform4i(uniform_id, x, y, z, w) => - ctx.gl().uniform_4i(uniform_id, x, y, z, w), - WebGLCommand::Uniform4iv(uniform_id, v) => - ctx.gl().uniform_4iv(uniform_id, &v), - WebGLCommand::UniformMatrix2fv(uniform_id, transpose, v) => - ctx.gl().uniform_matrix_2fv(uniform_id, transpose, &v), - WebGLCommand::UniformMatrix3fv(uniform_id, transpose, v) => - ctx.gl().uniform_matrix_3fv(uniform_id, transpose, &v), - WebGLCommand::UniformMatrix4fv(uniform_id, transpose, v) => - ctx.gl().uniform_matrix_4fv(uniform_id, transpose, &v), - WebGLCommand::UseProgram(program_id) => - ctx.gl().use_program(program_id.get()), - WebGLCommand::ValidateProgram(program_id) => - ctx.gl().validate_program(program_id.get()), - WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => - ctx.gl().vertex_attrib_4f(attrib_id, x, y, z, w), - WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => - ctx.gl().vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset), - WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset) => - ctx.gl().vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset), - WebGLCommand::Viewport(x, y, width, height) => - ctx.gl().viewport(x, y, width, height), - WebGLCommand::TexImage2D(target, level, internal, width, height, format, data_type, data) => - ctx.gl().tex_image_2d(target, level, internal, width, height, - /*border*/0, format, data_type, Some(&data)), - WebGLCommand::TexParameteri(target, name, value) => - ctx.gl().tex_parameter_i(target, name, value), - WebGLCommand::TexParameterf(target, name, value) => - ctx.gl().tex_parameter_f(target, name, value), - WebGLCommand::TexSubImage2D(target, level, xoffset, yoffset, x, y, width, height, data) => - ctx.gl().tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height, &data), - WebGLCommand::DrawingBufferWidth(sender) => - sender.send(ctx.borrow_draw_buffer().unwrap().size().width).unwrap(), - WebGLCommand::DrawingBufferHeight(sender) => - sender.send(ctx.borrow_draw_buffer().unwrap().size().height).unwrap(), - WebGLCommand::Finish(sender) => - Self::finish(ctx.gl(), sender), - WebGLCommand::Flush => - ctx.gl().flush(), - WebGLCommand::GenerateMipmap(target) => - ctx.gl().generate_mipmap(target), - WebGLCommand::CreateVertexArray(chan) => - Self::create_vertex_array(ctx.gl(), chan), - WebGLCommand::DeleteVertexArray(id) => - ctx.gl().delete_vertex_arrays(&[id.get()]), - WebGLCommand::BindVertexArray(id) => - ctx.gl().bind_vertex_array(id.map_or(0, WebGLVertexArrayId::get)), - } - - // TODO: update test expectations in order to enable debug assertions - //if cfg!(debug_assertions) { - let error = ctx.gl().get_error(); - assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error); - //} - } - - fn read_pixels(gl: &gl::Gl, x: i32, y: i32, width: i32, height: i32, format: u32, pixel_type: u32, - chan: WebGLSender<Vec<u8>>) { - let result = gl.read_pixels(x, y, width, height, format, pixel_type); - chan.send(result).unwrap() - } - - fn active_attrib(gl: &gl::Gl, - program_id: WebGLProgramId, - index: u32, - chan: WebGLSender<WebGLResult<(i32, u32, String)>>) { - let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES) as u32 { - Err(WebGLError::InvalidValue) - } else { - Ok(gl.get_active_attrib(program_id.get(), index)) - }; - chan.send(result).unwrap(); - } - - fn active_uniform(gl: &gl::Gl, - program_id: WebGLProgramId, - index: u32, - chan: WebGLSender<WebGLResult<(i32, u32, String)>>) { - let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS) as u32 { - Err(WebGLError::InvalidValue) - } else { - Ok(gl.get_active_uniform(program_id.get(), index)) - }; - chan.send(result).unwrap(); - } - - fn attrib_location(gl: &gl::Gl, - program_id: WebGLProgramId, - name: String, - chan: WebGLSender<Option<i32>> ) { - let attrib_location = gl.get_attrib_location(program_id.get(), &name); - - let attrib_location = if attrib_location == -1 { - None - } else { - Some(attrib_location) - }; - - chan.send(attrib_location).unwrap(); - } - - fn parameter(gl: &gl::Gl, - param_id: u32, - chan: WebGLSender<WebGLResult<WebGLParameter>>) { - let result = match param_id { - gl::ACTIVE_TEXTURE | - gl::ALPHA_BITS | - gl::BLEND_DST_ALPHA | - gl::BLEND_DST_RGB | - gl::BLEND_EQUATION_ALPHA | - gl::BLEND_EQUATION_RGB | - gl::BLEND_SRC_ALPHA | - gl::BLEND_SRC_RGB | - gl::BLUE_BITS | - gl::CULL_FACE_MODE | - gl::DEPTH_BITS | - gl::DEPTH_FUNC | - gl::FRONT_FACE | - //gl::GENERATE_MIPMAP_HINT | - gl::GREEN_BITS | - //gl::IMPLEMENTATION_COLOR_READ_FORMAT | - //gl::IMPLEMENTATION_COLOR_READ_TYPE | - gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS | - gl::MAX_CUBE_MAP_TEXTURE_SIZE | - //gl::MAX_FRAGMENT_UNIFORM_VECTORS | - gl::MAX_RENDERBUFFER_SIZE | - gl::MAX_TEXTURE_IMAGE_UNITS | - gl::MAX_TEXTURE_SIZE | - //gl::MAX_VARYING_VECTORS | - gl::MAX_VERTEX_ATTRIBS | - gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS | - //gl::MAX_VERTEX_UNIFORM_VECTORS | - gl::PACK_ALIGNMENT | - gl::RED_BITS | - gl::SAMPLE_BUFFERS | - gl::SAMPLES | - gl::STENCIL_BACK_FAIL | - gl::STENCIL_BACK_FUNC | - gl::STENCIL_BACK_PASS_DEPTH_FAIL | - gl::STENCIL_BACK_PASS_DEPTH_PASS | - gl::STENCIL_BACK_REF | - gl::STENCIL_BACK_VALUE_MASK | - gl::STENCIL_BACK_WRITEMASK | - gl::STENCIL_BITS | - gl::STENCIL_CLEAR_VALUE | - gl::STENCIL_FAIL | - gl::STENCIL_FUNC | - gl::STENCIL_PASS_DEPTH_FAIL | - gl::STENCIL_PASS_DEPTH_PASS | - gl::STENCIL_REF | - gl::STENCIL_VALUE_MASK | - gl::STENCIL_WRITEMASK | - gl::SUBPIXEL_BITS | - gl::UNPACK_ALIGNMENT => - //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL => - Ok(WebGLParameter::Int(gl.get_integer_v(param_id))), - - gl::BLEND | - gl::CULL_FACE | - gl::DEPTH_TEST | - gl::DEPTH_WRITEMASK | - gl::DITHER | - gl::POLYGON_OFFSET_FILL | - gl::SAMPLE_COVERAGE_INVERT | - gl::STENCIL_TEST => - //gl::UNPACK_FLIP_Y_WEBGL | - //gl::UNPACK_PREMULTIPLY_ALPHA_WEBGL => - Ok(WebGLParameter::Bool(gl.get_boolean_v(param_id) != 0)), - - gl::DEPTH_CLEAR_VALUE | - gl::LINE_WIDTH | - gl::POLYGON_OFFSET_FACTOR | - gl::POLYGON_OFFSET_UNITS | - gl::SAMPLE_COVERAGE_VALUE => - Ok(WebGLParameter::Float(gl.get_float_v(param_id))), - - gl::VERSION => Ok(WebGLParameter::String("WebGL 1.0".to_owned())), - gl::RENDERER | - gl::VENDOR => Ok(WebGLParameter::String("Mozilla/Servo".to_owned())), - gl::SHADING_LANGUAGE_VERSION => Ok(WebGLParameter::String("WebGL GLSL ES 1.0".to_owned())), - - // TODO(zbarsky, emilio): Implement support for the following valid parameters - // Float32Array - gl::ALIASED_LINE_WIDTH_RANGE | - //gl::ALIASED_POINT_SIZE_RANGE | - //gl::BLEND_COLOR | - gl::COLOR_CLEAR_VALUE | - gl::DEPTH_RANGE | - - // WebGLBuffer - gl::ARRAY_BUFFER_BINDING | - gl::ELEMENT_ARRAY_BUFFER_BINDING | - - // WebGLFrameBuffer - gl::FRAMEBUFFER_BINDING | - - // WebGLRenderBuffer - gl::RENDERBUFFER_BINDING | - - // WebGLProgram - gl::CURRENT_PROGRAM | - - // WebGLTexture - gl::TEXTURE_BINDING_2D | - gl::TEXTURE_BINDING_CUBE_MAP | - - // sequence<GlBoolean> - gl::COLOR_WRITEMASK | - - // Uint32Array - gl::COMPRESSED_TEXTURE_FORMATS | - - // Int32Array - gl::MAX_VIEWPORT_DIMS | - gl::SCISSOR_BOX | - gl::VIEWPORT => Err(WebGLError::InvalidEnum), - - // Invalid parameters - _ => Err(WebGLError::InvalidEnum) - }; - - chan.send(result).unwrap(); - } - - fn finish(gl: &gl::Gl, chan: WebGLSender<()>) { - gl.finish(); - chan.send(()).unwrap(); - } - - fn vertex_attrib(gl: &gl::Gl, - index: u32, - pname: u32, - chan: WebGLSender<WebGLResult<WebGLParameter>>) { - let result = if index >= gl.get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32 { - Err(WebGLError::InvalidValue) - } else { - match pname { - gl::VERTEX_ATTRIB_ARRAY_ENABLED | - gl::VERTEX_ATTRIB_ARRAY_NORMALIZED => - Ok(WebGLParameter::Bool(gl.get_vertex_attrib_iv(index, pname) != 0)), - gl::VERTEX_ATTRIB_ARRAY_SIZE | - gl::VERTEX_ATTRIB_ARRAY_STRIDE | - gl::VERTEX_ATTRIB_ARRAY_TYPE => - Ok(WebGLParameter::Int(gl.get_vertex_attrib_iv(index, pname))), - gl::CURRENT_VERTEX_ATTRIB => - Ok(WebGLParameter::FloatArray(gl.get_vertex_attrib_fv(index, pname))), - // gl::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING should return WebGLBuffer - _ => Err(WebGLError::InvalidEnum), - } - }; - - chan.send(result).unwrap(); - } - - fn vertex_attrib_offset(gl: &gl::Gl, - index: u32, - pname: u32, - chan: WebGLSender<WebGLResult<isize>>) { - let result = match pname { - gl::VERTEX_ATTRIB_ARRAY_POINTER => Ok(gl.get_vertex_attrib_pointer_v(index, pname)), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn buffer_parameter(gl: &gl::Gl, - target: u32, - param_id: u32, - chan: WebGLSender<WebGLResult<WebGLParameter>>) { - let result = match param_id { - gl::BUFFER_SIZE | - gl::BUFFER_USAGE => - Ok(WebGLParameter::Int(gl.get_buffer_parameter_iv(target, param_id))), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn program_parameter(gl: &gl::Gl, - program_id: WebGLProgramId, - param_id: u32, - chan: WebGLSender<WebGLResult<WebGLParameter>>) { - let result = match param_id { - gl::DELETE_STATUS | - gl::LINK_STATUS | - gl::VALIDATE_STATUS => - Ok(WebGLParameter::Bool(gl.get_program_iv(program_id.get(), param_id) != 0)), - gl::ATTACHED_SHADERS | - gl::ACTIVE_ATTRIBUTES | - gl::ACTIVE_UNIFORMS => - Ok(WebGLParameter::Int(gl.get_program_iv(program_id.get(), param_id))), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn shader_parameter(gl: &gl::Gl, - shader_id: WebGLShaderId, - param_id: u32, - chan: WebGLSender<WebGLResult<WebGLParameter>>) { - let result = match param_id { - gl::SHADER_TYPE => - Ok(WebGLParameter::Int(gl.get_shader_iv(shader_id.get(), param_id))), - gl::DELETE_STATUS | - gl::COMPILE_STATUS => - Ok(WebGLParameter::Bool(gl.get_shader_iv(shader_id.get(), param_id) != 0)), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn shader_precision_format(gl: &gl::Gl, - shader_type: u32, - precision_type: u32, - chan: WebGLSender<WebGLResult<(i32, i32, i32)>>) { - let result = match precision_type { - gl::LOW_FLOAT | - gl::MEDIUM_FLOAT | - gl::HIGH_FLOAT | - gl::LOW_INT | - gl::MEDIUM_INT | - gl::HIGH_INT => { - Ok(gl.get_shader_precision_format(shader_type, precision_type)) - }, - _=> { - Err(WebGLError::InvalidEnum) - } - }; - - chan.send(result).unwrap(); - } - - fn get_extensions(gl: &gl::Gl, chan: WebGLSender<String>) { - chan.send(gl.get_string(gl::EXTENSIONS)).unwrap(); - } - - fn uniform_location(gl: &gl::Gl, - program_id: WebGLProgramId, - name: String, - chan: WebGLSender<Option<i32>>) { - let location = gl.get_uniform_location(program_id.get(), &name); - let location = if location == -1 { - None - } else { - Some(location) - }; - - chan.send(location).unwrap(); - } - - - fn shader_info_log(gl: &gl::Gl, shader_id: WebGLShaderId, chan: WebGLSender<String>) { - let log = gl.get_shader_info_log(shader_id.get()); - chan.send(log).unwrap(); - } - - fn program_info_log(gl: &gl::Gl, program_id: WebGLProgramId, chan: WebGLSender<String>) { - let log = gl.get_program_info_log(program_id.get()); - chan.send(log).unwrap(); - } - - #[allow(unsafe_code)] - fn create_buffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLBufferId>>) { - let buffer = gl.gen_buffers(1)[0]; - let buffer = if buffer == 0 { - None - } else { - Some(unsafe { WebGLBufferId::new(buffer) }) - }; - chan.send(buffer).unwrap(); - } - - #[allow(unsafe_code)] - fn create_framebuffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLFramebufferId>>) { - let framebuffer = gl.gen_framebuffers(1)[0]; - let framebuffer = if framebuffer == 0 { - None - } else { - Some(unsafe { WebGLFramebufferId::new(framebuffer) }) - }; - chan.send(framebuffer).unwrap(); - } - - #[allow(unsafe_code)] - fn create_renderbuffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLRenderbufferId>>) { - let renderbuffer = gl.gen_renderbuffers(1)[0]; - let renderbuffer = if renderbuffer == 0 { - None - } else { - Some(unsafe { WebGLRenderbufferId::new(renderbuffer) }) - }; - chan.send(renderbuffer).unwrap(); - } - - #[allow(unsafe_code)] - fn create_texture(gl: &gl::Gl, chan: WebGLSender<Option<WebGLTextureId>>) { - let texture = gl.gen_textures(1)[0]; - let texture = if texture == 0 { - None - } else { - Some(unsafe { WebGLTextureId::new(texture) }) - }; - chan.send(texture).unwrap(); - } - - #[allow(unsafe_code)] - fn create_program(gl: &gl::Gl, chan: WebGLSender<Option<WebGLProgramId>>) { - let program = gl.create_program(); - let program = if program == 0 { - None - } else { - Some(unsafe { WebGLProgramId::new(program) }) - }; - chan.send(program).unwrap(); - } - - #[allow(unsafe_code)] - fn create_shader(gl: &gl::Gl, shader_type: u32, chan: WebGLSender<Option<WebGLShaderId>>) { - let shader = gl.create_shader(shader_type); - let shader = if shader == 0 { - None - } else { - Some(unsafe { WebGLShaderId::new(shader) }) - }; - chan.send(shader).unwrap(); - } - - #[allow(unsafe_code)] - fn create_vertex_array(gl: &gl::Gl, chan: WebGLSender<Option<WebGLVertexArrayId>>) { - let vao = gl.gen_vertex_arrays(1)[0]; - let vao = if vao == 0 { - None - } else { - Some(unsafe { WebGLVertexArrayId::new(vao) }) - }; - chan.send(vao).unwrap(); - } - - #[inline] - fn bind_framebuffer<Native: NativeGLContextMethods>(gl: &gl::Gl, - target: u32, - request: WebGLFramebufferBindingRequest, - ctx: &GLContext<Native>) { - let id = match request { - WebGLFramebufferBindingRequest::Explicit(id) => id.get(), - WebGLFramebufferBindingRequest::Default => - ctx.borrow_draw_buffer().unwrap().get_framebuffer(), - }; - - gl.bind_framebuffer(target, id); - } - - - #[inline] - fn compile_shader(gl: &gl::Gl, shader_id: WebGLShaderId, source: String) { - gl.shader_source(shader_id.get(), &[source.as_bytes()]); - gl.compile_shader(shader_id.get()); - } -} |