mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #13872 - anholt:webgl-fbo, r=emilio
webgl: Add basic support for framebuffer attachments This is by no means a complete implementation, but I've slowed down on working on it, so I think we should look at what it takes to merge the current code. There are some major features missing, like initializing renderbuffers to 0 (uninitialized memory leak), tracking the attachments' attributes (width/height/format) for parameter requests, and lots of missing glCheckFramebufferStatus() validation. On the other hand, this is enough to run some demos using FBOs. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #13639 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13872) <!-- Reviewable:end -->
This commit is contained in:
commit
fbec79e920
23 changed files with 625 additions and 112 deletions
|
@ -4,15 +4,27 @@
|
|||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use canvas_traits::CanvasMsg;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::WebGLFramebufferBinding;
|
||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::bindings::js::{HeapGCValue, JS, Root};
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::webglobject::WebGLObject;
|
||||
use dom::webglrenderbuffer::WebGLRenderbuffer;
|
||||
use dom::webgltexture::WebGLTexture;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use std::cell::Cell;
|
||||
use webrender_traits::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId};
|
||||
use webrender_traits::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLResult, WebGLError};
|
||||
|
||||
#[must_root]
|
||||
#[derive(JSTraceable, Clone, HeapSizeOf)]
|
||||
enum WebGLFramebufferAttachment {
|
||||
Renderbuffer(JS<WebGLRenderbuffer>),
|
||||
Texture(JS<WebGLTexture>),
|
||||
}
|
||||
|
||||
impl HeapGCValue for WebGLFramebufferAttachment {}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WebGLFramebuffer {
|
||||
|
@ -21,8 +33,16 @@ pub struct WebGLFramebuffer {
|
|||
/// target can only be gl::FRAMEBUFFER at the moment
|
||||
target: Cell<Option<u32>>,
|
||||
is_deleted: Cell<bool>,
|
||||
status: Cell<u32>,
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
renderer: IpcSender<CanvasMsg>,
|
||||
|
||||
// The attachment points for textures and renderbuffers on this
|
||||
// FBO.
|
||||
color: DOMRefCell<Option<WebGLFramebufferAttachment>>,
|
||||
depth: DOMRefCell<Option<WebGLFramebufferAttachment>>,
|
||||
stencil: DOMRefCell<Option<WebGLFramebufferAttachment>>,
|
||||
depthstencil: DOMRefCell<Option<WebGLFramebufferAttachment>>,
|
||||
}
|
||||
|
||||
impl WebGLFramebuffer {
|
||||
|
@ -35,6 +55,11 @@ impl WebGLFramebuffer {
|
|||
target: Cell::new(None),
|
||||
is_deleted: Cell::new(false),
|
||||
renderer: renderer,
|
||||
status: Cell::new(constants::FRAMEBUFFER_UNSUPPORTED),
|
||||
color: DOMRefCell::new(None),
|
||||
depth: DOMRefCell::new(None),
|
||||
stencil: DOMRefCell::new(None),
|
||||
depthstencil: DOMRefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +89,11 @@ impl WebGLFramebuffer {
|
|||
}
|
||||
|
||||
pub fn bind(&self, target: u32) {
|
||||
// Update the framebuffer status on binding. It may have
|
||||
// changed if its attachments were resized or deleted while
|
||||
// we've been unbound.
|
||||
self.update_status();
|
||||
|
||||
self.target.set(Some(target));
|
||||
let cmd = WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Explicit(self.id));
|
||||
self.renderer.send(CanvasMsg::WebGL(cmd)).unwrap();
|
||||
|
@ -80,10 +110,188 @@ impl WebGLFramebuffer {
|
|||
self.is_deleted.get()
|
||||
}
|
||||
|
||||
fn update_status(&self) {
|
||||
let has_c = self.color.borrow().is_some();
|
||||
let has_z = self.depth.borrow().is_some();
|
||||
let has_s = self.stencil.borrow().is_some();
|
||||
let has_zs = self.depthstencil.borrow().is_some();
|
||||
|
||||
// From the WebGL spec, 6.6 ("Framebuffer Object Attachments"):
|
||||
//
|
||||
// "In the WebGL API, it is an error to concurrently attach
|
||||
// renderbuffers to the following combinations of
|
||||
// attachment points:
|
||||
//
|
||||
// DEPTH_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
|
||||
// STENCIL_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
|
||||
// DEPTH_ATTACHMENT + STENCIL_ATTACHMENT
|
||||
//
|
||||
// If any of the constraints above are violated, then:
|
||||
//
|
||||
// checkFramebufferStatus must return FRAMEBUFFER_UNSUPPORTED."
|
||||
if (has_zs && (has_z || has_s)) ||
|
||||
(has_z && has_s) {
|
||||
self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if has_c || has_z || has_zs || has_s {
|
||||
self.status.set(constants::FRAMEBUFFER_COMPLETE);
|
||||
} else {
|
||||
self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_status(&self) -> u32 {
|
||||
// Until we build support for attaching renderbuffers or
|
||||
// textures, all user FBOs are incomplete.
|
||||
return constants::FRAMEBUFFER_UNSUPPORTED;
|
||||
return self.status.get();
|
||||
}
|
||||
|
||||
pub fn renderbuffer(&self, attachment: u32, rb: Option<&WebGLRenderbuffer>) -> WebGLResult<()> {
|
||||
let binding = match attachment {
|
||||
constants::COLOR_ATTACHMENT0 => &self.color,
|
||||
constants::DEPTH_ATTACHMENT => &self.depth,
|
||||
constants::STENCIL_ATTACHMENT => &self.stencil,
|
||||
constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
let rb_id = match rb {
|
||||
Some(rb) => {
|
||||
*binding.borrow_mut() = Some(WebGLFramebufferAttachment::Renderbuffer(JS::from_ref(rb)));
|
||||
Some(rb.id())
|
||||
}
|
||||
|
||||
_ => {
|
||||
*binding.borrow_mut() = None;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::FramebufferRenderbuffer(constants::FRAMEBUFFER,
|
||||
attachment,
|
||||
constants::RENDERBUFFER,
|
||||
rb_id))).unwrap();
|
||||
|
||||
self.update_status();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn texture2d(&self, attachment: u32, textarget: u32, texture: Option<&WebGLTexture>,
|
||||
level: i32) -> WebGLResult<()> {
|
||||
let binding = match attachment {
|
||||
constants::COLOR_ATTACHMENT0 => &self.color,
|
||||
constants::DEPTH_ATTACHMENT => &self.depth,
|
||||
constants::STENCIL_ATTACHMENT => &self.stencil,
|
||||
constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
let tex_id = match texture {
|
||||
// Note, from the GLES 2.0.25 spec, page 113:
|
||||
// "If texture is zero, then textarget and level are ignored."
|
||||
Some(texture) => {
|
||||
*binding.borrow_mut() = Some(WebGLFramebufferAttachment::Texture(JS::from_ref(texture)));
|
||||
|
||||
// From the GLES 2.0.25 spec, page 113:
|
||||
//
|
||||
// "level specifies the mipmap level of the texture image
|
||||
// to be attached to the framebuffer and must be
|
||||
// 0. Otherwise, INVALID_VALUE is generated."
|
||||
if level != 0 {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
// "If texture is not zero, then texture must either
|
||||
// name an existing texture object with an target of
|
||||
// textarget, or texture must name an existing cube
|
||||
// map texture and textarget must be one of:
|
||||
// TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
// TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
// TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
// TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
// TEXTURE_CUBE_MAP_NEGATIVE_Y, or
|
||||
// TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise,
|
||||
// INVALID_OPERATION is generated."
|
||||
let is_cube = match textarget {
|
||||
constants::TEXTURE_2D => false,
|
||||
|
||||
constants::TEXTURE_CUBE_MAP_POSITIVE_X => true,
|
||||
constants::TEXTURE_CUBE_MAP_POSITIVE_Y => true,
|
||||
constants::TEXTURE_CUBE_MAP_POSITIVE_Z => true,
|
||||
constants::TEXTURE_CUBE_MAP_NEGATIVE_X => true,
|
||||
constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => true,
|
||||
constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => true,
|
||||
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
match texture.target() {
|
||||
Some(constants::TEXTURE_CUBE_MAP) if is_cube => {}
|
||||
Some(_) if !is_cube => {}
|
||||
_ => return Err(WebGLError::InvalidOperation),
|
||||
}
|
||||
|
||||
Some(texture.id())
|
||||
}
|
||||
|
||||
_ => {
|
||||
*binding.borrow_mut() = None;
|
||||
self.update_status();
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::FramebufferTexture2D(constants::FRAMEBUFFER,
|
||||
attachment,
|
||||
textarget,
|
||||
tex_id,
|
||||
level))).unwrap();
|
||||
|
||||
self.update_status();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) {
|
||||
let attachments = [&self.color,
|
||||
&self.depth,
|
||||
&self.stencil,
|
||||
&self.depthstencil];
|
||||
|
||||
for attachment in &attachments {
|
||||
let matched = {
|
||||
match *attachment.borrow() {
|
||||
Some(WebGLFramebufferAttachment::Renderbuffer(ref att_rb))
|
||||
if rb.id() == att_rb.id() => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
if matched {
|
||||
*attachment.borrow_mut() = None;
|
||||
self.update_status();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detach_texture(&self, texture: &WebGLTexture) {
|
||||
let attachments = [&self.color,
|
||||
&self.depth,
|
||||
&self.stencil,
|
||||
&self.depthstencil];
|
||||
|
||||
for attachment in &attachments {
|
||||
let matched = {
|
||||
match *attachment.borrow() {
|
||||
Some(WebGLFramebufferAttachment::Texture(ref att_texture))
|
||||
if texture.id() == att_texture.id() => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
if matched {
|
||||
*attachment.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target(&self) -> Option<u32> {
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use canvas_traits::CanvasMsg;
|
||||
use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding;
|
||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::webglobject::WebGLObject;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use std::cell::Cell;
|
||||
use webrender_traits::{WebGLCommand, WebGLRenderbufferId};
|
||||
use webrender_traits::{WebGLCommand, WebGLRenderbufferId, WebGLResult, WebGLError};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WebGLRenderbuffer {
|
||||
|
@ -19,6 +20,7 @@ pub struct WebGLRenderbuffer {
|
|||
id: WebGLRenderbufferId,
|
||||
ever_bound: Cell<bool>,
|
||||
is_deleted: Cell<bool>,
|
||||
internal_format: Cell<Option<u32>>,
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
renderer: IpcSender<CanvasMsg>,
|
||||
}
|
||||
|
@ -33,6 +35,7 @@ impl WebGLRenderbuffer {
|
|||
ever_bound: Cell::new(false),
|
||||
is_deleted: Cell::new(false),
|
||||
renderer: renderer,
|
||||
internal_format: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,4 +84,28 @@ impl WebGLRenderbuffer {
|
|||
pub fn ever_bound(&self) -> bool {
|
||||
self.ever_bound.get()
|
||||
}
|
||||
|
||||
pub fn storage(&self, internal_format: u32, width: i32, height: i32) -> WebGLResult<()> {
|
||||
// Validate the internal_format, and save it for completeness
|
||||
// validation.
|
||||
match internal_format {
|
||||
constants::RGBA4 |
|
||||
constants::DEPTH_STENCIL |
|
||||
constants::DEPTH_COMPONENT16 |
|
||||
constants::STENCIL_INDEX8 =>
|
||||
self.internal_format.set(Some(internal_format)),
|
||||
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
// FIXME: Check that w/h are < MAX_RENDERBUFFER_SIZE
|
||||
|
||||
// FIXME: Invalidate completeness after the call
|
||||
|
||||
let msg = CanvasMsg::WebGL(WebGLCommand::RenderbufferStorage(constants::RENDERBUFFER,
|
||||
internal_format, width, height));
|
||||
self.renderer.send(msg).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,11 +74,17 @@ macro_rules! handle_potential_webgl_error {
|
|||
//
|
||||
// and similar text occurs for other object types.
|
||||
macro_rules! handle_object_deletion {
|
||||
($binding:expr, $object:ident) => {
|
||||
($self_:expr, $binding:expr, $object:ident, $unbind_command:expr) => {
|
||||
if let Some(bound_object) = $binding.get() {
|
||||
if bound_object.id() == $object.id() {
|
||||
$binding.set(None);
|
||||
}
|
||||
|
||||
if let Some(command) = $unbind_command {
|
||||
$self_.ipc_renderer
|
||||
.send(CanvasMsg::WebGL(command))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -804,13 +810,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
|
||||
self.bound_framebuffer.set(framebuffer);
|
||||
if let Some(framebuffer) = framebuffer {
|
||||
framebuffer.bind(target)
|
||||
if framebuffer.is_deleted() {
|
||||
// From the WebGL spec:
|
||||
//
|
||||
// "An attempt to bind a deleted framebuffer will
|
||||
// generate an INVALID_OPERATION error, and the
|
||||
// current binding will remain untouched."
|
||||
return self.webgl_error(InvalidOperation);
|
||||
} else {
|
||||
framebuffer.bind(target);
|
||||
self.bound_framebuffer.set(Some(framebuffer));
|
||||
}
|
||||
} else {
|
||||
// Bind the default framebuffer
|
||||
let cmd = WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default);
|
||||
self.ipc_renderer.send(CanvasMsg::WebGL(cmd)).unwrap();
|
||||
self.bound_framebuffer.set(framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1241,8 +1257,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
|
||||
fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
|
||||
if let Some(buffer) = buffer {
|
||||
handle_object_deletion!(self.bound_buffer_array, buffer);
|
||||
handle_object_deletion!(self.bound_buffer_element_array, buffer);
|
||||
handle_object_deletion!(self, self.bound_buffer_array, buffer,
|
||||
Some(WebGLCommand::BindBuffer(constants::ARRAY_BUFFER, None)));
|
||||
handle_object_deletion!(self, self.bound_buffer_element_array, buffer,
|
||||
Some(WebGLCommand::BindBuffer(constants::ELEMENT_ARRAY_BUFFER, None)));
|
||||
buffer.delete()
|
||||
}
|
||||
}
|
||||
|
@ -1250,7 +1268,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
|
||||
fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
|
||||
if let Some(framebuffer) = framebuffer {
|
||||
handle_object_deletion!(self.bound_framebuffer, framebuffer);
|
||||
handle_object_deletion!(self, self.bound_framebuffer, framebuffer,
|
||||
Some(WebGLCommand::BindFramebuffer(constants::FRAMEBUFFER,
|
||||
WebGLFramebufferBindingRequest::Default)));
|
||||
framebuffer.delete()
|
||||
}
|
||||
}
|
||||
|
@ -1258,7 +1278,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
|
||||
fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
|
||||
if let Some(renderbuffer) = renderbuffer {
|
||||
handle_object_deletion!(self.bound_renderbuffer, renderbuffer);
|
||||
handle_object_deletion!(self, self.bound_renderbuffer, renderbuffer,
|
||||
Some(WebGLCommand::BindRenderbuffer(constants::RENDERBUFFER, None)));
|
||||
// From the GLES 2.0.25 spec, page 113:
|
||||
//
|
||||
// "If a renderbuffer object is deleted while its
|
||||
// image is attached to the currently bound
|
||||
// framebuffer, then it is as if
|
||||
// FramebufferRenderbuffer had been called, with a
|
||||
// renderbuffer of 0, for each attachment point to
|
||||
// which this image was attached in the currently
|
||||
// bound framebuffer."
|
||||
//
|
||||
if let Some(fb) = self.bound_framebuffer.get() {
|
||||
fb.detach_renderbuffer(renderbuffer);
|
||||
}
|
||||
|
||||
renderbuffer.delete()
|
||||
}
|
||||
}
|
||||
|
@ -1266,8 +1301,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
|
||||
if let Some(texture) = texture {
|
||||
handle_object_deletion!(self.bound_texture_2d, texture);
|
||||
handle_object_deletion!(self.bound_texture_cube_map, texture);
|
||||
handle_object_deletion!(self, self.bound_texture_2d, texture,
|
||||
Some(WebGLCommand::BindTexture(constants::TEXTURE_2D, None)));
|
||||
handle_object_deletion!(self, self.bound_texture_cube_map, texture,
|
||||
Some(WebGLCommand::BindTexture(constants::TEXTURE_CUBE_MAP, None)));
|
||||
|
||||
// From the GLES 2.0.25 spec, page 113:
|
||||
//
|
||||
// "If a texture object is deleted while its image is
|
||||
// attached to the currently bound framebuffer, then
|
||||
// it is as if FramebufferTexture2D had been called,
|
||||
// with a texture of 0, for each attachment point to
|
||||
// which this image was attached in the currently
|
||||
// bound framebuffer."
|
||||
if let Some(fb) = self.bound_framebuffer.get() {
|
||||
fb.detach_texture(texture);
|
||||
}
|
||||
texture.delete()
|
||||
}
|
||||
}
|
||||
|
@ -1275,7 +1324,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
|
||||
if let Some(program) = program {
|
||||
handle_object_deletion!(self.current_program, program);
|
||||
// FIXME: We should call glUseProgram(0), but
|
||||
// WebGLCommand::UseProgram() doesn't take an Option
|
||||
// currently. This is also a problem for useProgram(null)
|
||||
handle_object_deletion!(self, self.current_program, program, None);
|
||||
program.delete()
|
||||
}
|
||||
}
|
||||
|
@ -2526,6 +2578,82 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
fn TexParameteri(&self, target: u32, name: u32, value: i32) {
|
||||
self.tex_parameter(target, name, TexParameterValue::Int(value))
|
||||
}
|
||||
|
||||
fn CheckFramebufferStatus(&self, target: u32) -> u32 {
|
||||
// From the GLES 2.0.25 spec, 4.4 ("Framebuffer Objects"):
|
||||
//
|
||||
// "If target is not FRAMEBUFFER, INVALID_ENUM is
|
||||
// generated. If CheckFramebufferStatus generates an
|
||||
// error, 0 is returned."
|
||||
if target != constants::FRAMEBUFFER {
|
||||
self.webgl_error(InvalidEnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
match self.bound_framebuffer.get() {
|
||||
Some(fb) => return fb.check_status(),
|
||||
None => return constants::FRAMEBUFFER_COMPLETE,
|
||||
}
|
||||
}
|
||||
|
||||
fn RenderbufferStorage(&self, target: u32, internal_format: u32,
|
||||
width: i32, height: i32) {
|
||||
// From the GLES 2.0.25 spec:
|
||||
//
|
||||
// "target must be RENDERBUFFER."
|
||||
if target != constants::RENDERBUFFER {
|
||||
return self.webgl_error(InvalidOperation)
|
||||
}
|
||||
|
||||
// From the GLES 2.0.25 spec:
|
||||
//
|
||||
// "If either width or height is greater than the value of
|
||||
// MAX_RENDERBUFFER_SIZE , the error INVALID_VALUE is
|
||||
// generated."
|
||||
//
|
||||
// and we have to throw out negative-size values as well just
|
||||
// like for TexImage.
|
||||
//
|
||||
// FIXME: Handle max_renderbuffer_size, which doesn't seem to
|
||||
// be in limits.
|
||||
if width < 0 || height < 0 {
|
||||
return self.webgl_error(InvalidValue);
|
||||
}
|
||||
|
||||
match self.bound_renderbuffer.get() {
|
||||
Some(rb) => handle_potential_webgl_error!(self, rb.storage(internal_format, width, height)),
|
||||
None => self.webgl_error(InvalidOperation),
|
||||
};
|
||||
|
||||
// FIXME: We need to clear the renderbuffer before it can be
|
||||
// accessed. See https://github.com/servo/servo/issues/13710
|
||||
}
|
||||
|
||||
fn FramebufferRenderbuffer(&self, target: u32, attachment: u32,
|
||||
renderbuffertarget: u32,
|
||||
rb: Option<&WebGLRenderbuffer>) {
|
||||
if target != constants::FRAMEBUFFER || renderbuffertarget != constants::RENDERBUFFER {
|
||||
return self.webgl_error(InvalidEnum);
|
||||
}
|
||||
|
||||
match self.bound_framebuffer.get() {
|
||||
Some(fb) => handle_potential_webgl_error!(self, fb.renderbuffer(attachment, rb)),
|
||||
None => self.webgl_error(InvalidOperation),
|
||||
};
|
||||
}
|
||||
|
||||
fn FramebufferTexture2D(&self, target: u32, attachment: u32,
|
||||
textarget: u32, texture: Option<&WebGLTexture>,
|
||||
level: i32) {
|
||||
if target != constants::FRAMEBUFFER {
|
||||
return self.webgl_error(InvalidEnum);
|
||||
}
|
||||
|
||||
match self.bound_framebuffer.get() {
|
||||
Some(fb) => handle_potential_webgl_error!(self, fb.texture2d(attachment, textarget, texture, level)),
|
||||
None => self.webgl_error(InvalidOperation),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LayoutCanvasWebGLRenderingContextHelpers {
|
||||
|
|
|
@ -501,7 +501,7 @@ interface WebGLRenderingContextBase
|
|||
[Throws]
|
||||
void bufferSubData(GLenum target, GLintptr offset, object? data);
|
||||
|
||||
//[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
|
||||
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
|
||||
void clear(GLbitfield mask);
|
||||
void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
void clearDepth(GLclampf depth);
|
||||
|
@ -566,11 +566,11 @@ interface WebGLRenderingContextBase
|
|||
void enableVertexAttribArray(GLuint index);
|
||||
void finish();
|
||||
void flush();
|
||||
//void framebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
// GLenum renderbuffertarget,
|
||||
// WebGLRenderbuffer? renderbuffer);
|
||||
//void framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
|
||||
// WebGLTexture? texture, GLint level);
|
||||
void framebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
GLenum renderbuffertarget,
|
||||
WebGLRenderbuffer? renderbuffer);
|
||||
void framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
|
||||
WebGLTexture? texture, GLint level);
|
||||
void frontFace(GLenum mode);
|
||||
|
||||
void generateMipmap(GLenum target);
|
||||
|
@ -626,8 +626,8 @@ interface WebGLRenderingContextBase
|
|||
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, object? pixels);
|
||||
|
||||
//void renderbufferStorage(GLenum target, GLenum internalformat,
|
||||
// GLsizei width, GLsizei height);
|
||||
void renderbufferStorage(GLenum target, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
void sampleCoverage(GLclampf value, GLboolean invert);
|
||||
void scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue