mirror of
https://github.com/servo/servo.git
synced 2025-06-11 01:50:10 +00:00
Associate bound WebGLTextures with texture units.
This commit is contained in:
parent
7574d26476
commit
b9710a59b5
2 changed files with 123 additions and 32 deletions
|
@ -110,6 +110,18 @@ macro_rules! object_binding_to_js_or_null {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! optional_root_object_to_js_or_null {
|
||||||
|
($cx: expr, $binding:expr) => {
|
||||||
|
{
|
||||||
|
rooted!(in($cx) let mut rval = NullValue());
|
||||||
|
if let Some(object) = $binding {
|
||||||
|
object.to_jsval($cx, rval.handle_mut());
|
||||||
|
}
|
||||||
|
rval.get()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool {
|
fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool {
|
||||||
match (arg1, arg2) {
|
match (arg1, arg2) {
|
||||||
(constants::CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
|
(constants::CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
|
||||||
|
@ -130,6 +142,41 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about the bound textures of a WebGL texture unit.
|
||||||
|
#[must_root]
|
||||||
|
#[derive(HeapSizeOf, JSTraceable)]
|
||||||
|
struct TextureUnitBindings {
|
||||||
|
bound_texture_2d: MutNullableDom<WebGLTexture>,
|
||||||
|
bound_texture_cube_map: MutNullableDom<WebGLTexture>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextureUnitBindings {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bound_texture_2d: MutNullableDom::new(None),
|
||||||
|
bound_texture_cube_map: MutNullableDom::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the slot associated to the given texture.
|
||||||
|
/// Returns the GL target of the cleared slot, if any.
|
||||||
|
fn clear_slot(&self, texture: &WebGLTexture) -> Option<u32> {
|
||||||
|
let fields = [(&self.bound_texture_2d, constants::TEXTURE_2D),
|
||||||
|
(&self.bound_texture_cube_map, constants::TEXTURE_CUBE_MAP)];
|
||||||
|
|
||||||
|
fields.iter().find(|field| {
|
||||||
|
match field.0.get() {
|
||||||
|
Some(t) => t.id() == texture.id(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}).and_then(|field| {
|
||||||
|
field.0.set(None);
|
||||||
|
Some(field.1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct WebGLRenderingContext {
|
pub struct WebGLRenderingContext {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
@ -147,8 +194,8 @@ pub struct WebGLRenderingContext {
|
||||||
texture_unpacking_alignment: Cell<u32>,
|
texture_unpacking_alignment: Cell<u32>,
|
||||||
bound_framebuffer: MutNullableDom<WebGLFramebuffer>,
|
bound_framebuffer: MutNullableDom<WebGLFramebuffer>,
|
||||||
bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>,
|
bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>,
|
||||||
bound_texture_2d: MutNullableDom<WebGLTexture>,
|
bound_textures: DomRefCell<FnvHashMap<u32, TextureUnitBindings>>,
|
||||||
bound_texture_cube_map: MutNullableDom<WebGLTexture>,
|
bound_texture_unit: Cell<u32>,
|
||||||
bound_buffer_array: MutNullableDom<WebGLBuffer>,
|
bound_buffer_array: MutNullableDom<WebGLBuffer>,
|
||||||
bound_buffer_element_array: MutNullableDom<WebGLBuffer>,
|
bound_buffer_element_array: MutNullableDom<WebGLBuffer>,
|
||||||
bound_attrib_buffers: DomRefCell<FnvHashMap<u32, Dom<WebGLBuffer>>>,
|
bound_attrib_buffers: DomRefCell<FnvHashMap<u32, Dom<WebGLBuffer>>>,
|
||||||
|
@ -190,8 +237,8 @@ impl WebGLRenderingContext {
|
||||||
texture_unpacking_settings: Cell::new(CONVERT_COLORSPACE),
|
texture_unpacking_settings: Cell::new(CONVERT_COLORSPACE),
|
||||||
texture_unpacking_alignment: Cell::new(4),
|
texture_unpacking_alignment: Cell::new(4),
|
||||||
bound_framebuffer: MutNullableDom::new(None),
|
bound_framebuffer: MutNullableDom::new(None),
|
||||||
bound_texture_2d: MutNullableDom::new(None),
|
bound_textures: DomRefCell::new(Default::default()),
|
||||||
bound_texture_cube_map: MutNullableDom::new(None),
|
bound_texture_unit: Cell::new(constants::TEXTURE0),
|
||||||
bound_buffer_array: MutNullableDom::new(None),
|
bound_buffer_array: MutNullableDom::new(None),
|
||||||
bound_buffer_element_array: MutNullableDom::new(None),
|
bound_buffer_element_array: MutNullableDom::new(None),
|
||||||
bound_attrib_buffers: DomRefCell::new(Default::default()),
|
bound_attrib_buffers: DomRefCell::new(Default::default()),
|
||||||
|
@ -227,18 +274,36 @@ impl WebGLRenderingContext {
|
||||||
&self.limits
|
&self.limits
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bound_texture_for_target(&self, target: &TexImageTarget) -> Option<DomRoot<WebGLTexture>> {
|
fn bound_texture(&self, target: u32) -> Option<DomRoot<WebGLTexture>> {
|
||||||
match *target {
|
match target {
|
||||||
TexImageTarget::Texture2D => self.bound_texture_2d.get(),
|
constants::TEXTURE_2D => {
|
||||||
TexImageTarget::CubeMapPositiveX |
|
self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|t| {
|
||||||
TexImageTarget::CubeMapNegativeX |
|
t.bound_texture_2d.get()
|
||||||
TexImageTarget::CubeMapPositiveY |
|
})
|
||||||
TexImageTarget::CubeMapNegativeY |
|
},
|
||||||
TexImageTarget::CubeMapPositiveZ |
|
constants::TEXTURE_CUBE_MAP => {
|
||||||
TexImageTarget::CubeMapNegativeZ => self.bound_texture_cube_map.get(),
|
self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|t| {
|
||||||
|
t.bound_texture_cube_map.get()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bound_texture_for_target(&self, target: &TexImageTarget) -> Option<DomRoot<WebGLTexture>> {
|
||||||
|
self.bound_textures.borrow().get(&self.bound_texture_unit.get()).and_then(|binding| {
|
||||||
|
match *target {
|
||||||
|
TexImageTarget::Texture2D => binding.bound_texture_2d.get(),
|
||||||
|
TexImageTarget::CubeMapPositiveX |
|
||||||
|
TexImageTarget::CubeMapNegativeX |
|
||||||
|
TexImageTarget::CubeMapPositiveY |
|
||||||
|
TexImageTarget::CubeMapNegativeY |
|
||||||
|
TexImageTarget::CubeMapPositiveZ |
|
||||||
|
TexImageTarget::CubeMapNegativeZ => binding.bound_texture_cube_map.get(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn borrow_bound_attrib_buffers(&self) -> Ref<FnvHashMap<u32, Dom<WebGLBuffer>>> {
|
pub fn borrow_bound_attrib_buffers(&self) -> Ref<FnvHashMap<u32, Dom<WebGLBuffer>>> {
|
||||||
self.bound_attrib_buffers.borrow()
|
self.bound_attrib_buffers.borrow()
|
||||||
}
|
}
|
||||||
|
@ -280,7 +345,7 @@ impl WebGLRenderingContext {
|
||||||
// Right now offscreen_gl_context generates a new FBO and the bound texture is changed
|
// Right now offscreen_gl_context generates a new FBO and the bound texture is changed
|
||||||
// in order to create a new render to texture attachment.
|
// in order to create a new render to texture attachment.
|
||||||
// Send a command to re-bind the TEXTURE_2D, if any.
|
// Send a command to re-bind the TEXTURE_2D, if any.
|
||||||
if let Some(texture) = self.bound_texture_2d.get() {
|
if let Some(texture) = self.bound_texture(constants::TEXTURE_2D) {
|
||||||
self.send_command(WebGLCommand::BindTexture(constants::TEXTURE_2D, Some(texture.id())));
|
self.send_command(WebGLCommand::BindTexture(constants::TEXTURE_2D, Some(texture.id())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,8 +421,8 @@ impl WebGLRenderingContext {
|
||||||
|
|
||||||
fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) {
|
fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) {
|
||||||
let texture = match target {
|
let texture = match target {
|
||||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
constants::TEXTURE_2D |
|
||||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
constants::TEXTURE_CUBE_MAP => self.bound_texture(target),
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
};
|
};
|
||||||
if let Some(texture) = texture {
|
if let Some(texture) = texture {
|
||||||
|
@ -1194,11 +1259,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
return object_binding_to_js_or_null!(cx, &self.bound_framebuffer),
|
return object_binding_to_js_or_null!(cx, &self.bound_framebuffer),
|
||||||
constants::RENDERBUFFER_BINDING =>
|
constants::RENDERBUFFER_BINDING =>
|
||||||
return object_binding_to_js_or_null!(cx, &self.bound_renderbuffer),
|
return object_binding_to_js_or_null!(cx, &self.bound_renderbuffer),
|
||||||
constants::TEXTURE_BINDING_2D =>
|
constants::TEXTURE_BINDING_2D => {
|
||||||
return object_binding_to_js_or_null!(cx, &self.bound_texture_2d),
|
let texture = self.bound_texture(constants::TEXTURE_2D);
|
||||||
constants::TEXTURE_BINDING_CUBE_MAP =>
|
return optional_root_object_to_js_or_null!(cx, texture)
|
||||||
return object_binding_to_js_or_null!(cx, &self.bound_texture_cube_map),
|
},
|
||||||
|
constants::TEXTURE_BINDING_CUBE_MAP => {
|
||||||
|
let texture = self.bound_texture(constants::TEXTURE_CUBE_MAP);
|
||||||
|
return optional_root_object_to_js_or_null!(cx, texture)
|
||||||
|
},
|
||||||
// In readPixels we currently support RGBA/UBYTE only. If
|
// In readPixels we currently support RGBA/UBYTE only. If
|
||||||
// we wanted to support other formats, we could ask the
|
// we wanted to support other formats, we could ask the
|
||||||
// driver, but we would need to check for
|
// driver, but we would need to check for
|
||||||
|
@ -1318,6 +1386,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
|
||||||
fn ActiveTexture(&self, texture: u32) {
|
fn ActiveTexture(&self, texture: u32) {
|
||||||
|
self.bound_texture_unit.set(texture);
|
||||||
self.send_command(WebGLCommand::ActiveTexture(texture));
|
self.send_command(WebGLCommand::ActiveTexture(texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,9 +1544,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
|
fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
|
||||||
|
let mut bound_textures = self.bound_textures.borrow_mut();
|
||||||
|
let binding = bound_textures.entry(self.bound_texture_unit.get())
|
||||||
|
.or_insert(TextureUnitBindings::new());
|
||||||
let slot = match target {
|
let slot = match target {
|
||||||
constants::TEXTURE_2D => &self.bound_texture_2d,
|
constants::TEXTURE_2D => &binding.bound_texture_2d,
|
||||||
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
|
constants::TEXTURE_CUBE_MAP => &binding.bound_texture_cube_map,
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1495,14 +1567,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
fn GenerateMipmap(&self, target: u32) {
|
fn GenerateMipmap(&self, target: u32) {
|
||||||
let slot = match target {
|
let texture = match target {
|
||||||
constants::TEXTURE_2D => &self.bound_texture_2d,
|
constants::TEXTURE_2D |
|
||||||
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
|
constants::TEXTURE_CUBE_MAP => self.bound_texture(target),
|
||||||
|
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
};
|
};
|
||||||
|
|
||||||
match slot.get() {
|
match texture {
|
||||||
Some(texture) => handle_potential_webgl_error!(self, texture.generate_mipmap()),
|
Some(texture) => handle_potential_webgl_error!(self, texture.generate_mipmap()),
|
||||||
None => self.webgl_error(InvalidOperation)
|
None => self.webgl_error(InvalidOperation)
|
||||||
}
|
}
|
||||||
|
@ -1940,10 +2011,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
|
fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
|
||||||
if let Some(texture) = texture {
|
if let Some(texture) = texture {
|
||||||
handle_object_deletion!(self, self.bound_texture_2d, texture,
|
// From the GLES 2.0.25 spec, page 85:
|
||||||
Some(WebGLCommand::BindTexture(constants::TEXTURE_2D, None)));
|
//
|
||||||
handle_object_deletion!(self, self.bound_texture_cube_map, texture,
|
// "If a texture that is currently bound to one of the targets
|
||||||
Some(WebGLCommand::BindTexture(constants::TEXTURE_CUBE_MAP, None)));
|
// TEXTURE_2D, or TEXTURE_CUBE_MAP is deleted, it is as though
|
||||||
|
// BindTexture had been executed with the same target and texture
|
||||||
|
// zero."
|
||||||
|
//
|
||||||
|
// The same texture may be bound to multiple texture units.
|
||||||
|
let mut bound_unit = self.bound_texture_unit.get();
|
||||||
|
for (texture_unit, binding) in self.bound_textures.borrow().iter() {
|
||||||
|
if let Some(target) = binding.clear_slot(texture) {
|
||||||
|
if *texture_unit != bound_unit {
|
||||||
|
self.send_command(WebGLCommand::ActiveTexture(*texture_unit));
|
||||||
|
bound_unit = *texture_unit;
|
||||||
|
}
|
||||||
|
self.send_command(WebGLCommand::BindTexture(target, None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore bound texture unit if it has been changed.
|
||||||
|
if self.bound_texture_unit.get() != bound_unit {
|
||||||
|
self.send_command(WebGLCommand::ActiveTexture(self.bound_texture_unit.get()));
|
||||||
|
}
|
||||||
|
|
||||||
// From the GLES 2.0.25 spec, page 113:
|
// From the GLES 2.0.25 spec, page 113:
|
||||||
//
|
//
|
||||||
|
|
|
@ -55,6 +55,7 @@ fn is_unrooted_ty(cx: &LateContext, ty: &ty::TyS, in_new_function: bool) -> bool
|
||||||
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Entry"])
|
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Entry"])
|
||||||
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "OccupiedEntry"])
|
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "OccupiedEntry"])
|
||||||
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "VacantEntry"])
|
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "VacantEntry"])
|
||||||
|
|| match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Iter"])
|
||||||
|| match_def_path(cx, did.did, &["std", "collections", "hash", "set", "Iter"]) {
|
|| match_def_path(cx, did.did, &["std", "collections", "hash", "set", "Iter"]) {
|
||||||
// Structures which are semantically similar to an &ptr.
|
// Structures which are semantically similar to an &ptr.
|
||||||
false
|
false
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue