Add support for some more WebGL2 renderbuffer functions

Adds support for the following WebGL2 calls:

- `RenderbufferStorageMultisample`
- `GetInternalFormativ`

See: https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
This commit is contained in:
Mátyás Mustoha 2020-03-03 14:44:33 +01:00 committed by Josh Matthews
parent 13a349603d
commit 5eaa9ef8cb
16 changed files with 256 additions and 74 deletions

View file

@ -42,7 +42,8 @@ use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{
webgl_channel, GLContextAttributes, WebGLCommand, WebGLResult, WebGLVersion,
webgl_channel, GLContextAttributes, InternalFormatParameter, WebGLCommand, WebGLResult,
WebGLVersion,
};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
@ -51,7 +52,7 @@ use js::jsapi::{JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value};
use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Uint32, Uint32Array};
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_layout_interface::HTMLCanvasDataSource;
use std::cell::Cell;
use std::cmp;
@ -3753,6 +3754,60 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
None => self.base.webgl_error(InvalidOperation),
}
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
#[allow(unsafe_code)]
fn GetInternalformatParameter(
&self,
cx: JSContext,
target: u32,
internal_format: u32,
pname: u32,
) -> JSVal {
if target != constants::RENDERBUFFER {
self.base.webgl_error(InvalidEnum);
return NullValue();
}
match handle_potential_webgl_error!(
self.base,
InternalFormatParameter::from_u32(pname),
return NullValue()
) {
InternalFormatParameter::IntVec(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap();
self.base
.send_command(WebGLCommand::GetInternalFormatIntVec(
target,
internal_format,
param,
sender,
));
rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
let _ = Int32Array::create(
*cx,
CreateWith::Slice(&receiver.recv().unwrap()),
rval.handle_mut(),
)
.unwrap();
ObjectValue(rval.get())
},
}
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
fn RenderbufferStorageMultisample(
&self,
target: u32,
samples: i32,
internal_format: u32,
width: i32,
height: i32,
) {
self.base
.renderbuffer_storage(target, samples, internal_format, width, height)
}
}
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {

View file

@ -14,7 +14,8 @@ use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use canvas_traits::webgl::{
webgl_channel, GlType, WebGLCommand, WebGLError, WebGLRenderbufferId, WebGLResult, WebGLVersion,
webgl_channel, GlType, InternalFormatIntVec, WebGLCommand, WebGLError, WebGLRenderbufferId,
WebGLResult, WebGLVersion,
};
use dom_struct::dom_struct;
use std::cell::Cell;
@ -133,11 +134,13 @@ impl WebGLRenderbuffer {
pub fn storage(
&self,
api_type: GlType,
sample_count: i32,
internal_format: u32,
width: i32,
height: i32,
) -> WebGLResult<()> {
let is_gles = api_type == GlType::Gles;
let webgl_version = self.upcast().context().webgl_version();
// Validate the internal_format, and save it for completeness
// validation.
@ -173,7 +176,7 @@ impl WebGLRenderbuffer {
constants::DEPTH_COMPONENT24 |
constants::DEPTH_COMPONENT32F |
constants::DEPTH24_STENCIL8 |
constants::DEPTH32F_STENCIL8 => match self.upcast().context().webgl_version() {
constants::DEPTH32F_STENCIL8 => match webgl_version {
WebGLVersion::WebGL1 => return Err(WebGLError::InvalidEnum),
_ => internal_format,
},
@ -221,6 +224,22 @@ impl WebGLRenderbuffer {
_ => return Err(WebGLError::InvalidEnum),
};
if webgl_version != WebGLVersion::WebGL1 {
let (sender, receiver) = webgl_channel().unwrap();
self.upcast::<WebGLObject>().context().send_command(
WebGLCommand::GetInternalFormatIntVec(
constants::RENDERBUFFER,
internal_format,
InternalFormatIntVec::Samples,
sender,
),
);
let samples = receiver.recv().unwrap();
if sample_count < 0 || sample_count as usize > samples.len() {
return Err(WebGLError::InvalidOperation);
}
}
self.internal_format.set(Some(internal_format));
self.is_initialized.set(false);
@ -228,17 +247,24 @@ impl WebGLRenderbuffer {
fb.update_status();
}
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::RenderbufferStorage(
let command = match sample_count {
0 => WebGLCommand::RenderbufferStorage(
constants::RENDERBUFFER,
actual_format,
width,
height,
));
),
_ => WebGLCommand::RenderbufferStorageMultisample(
constants::RENDERBUFFER,
sample_count,
actual_format,
width,
height,
),
};
self.upcast::<WebGLObject>().context().send_command(command);
self.size.set(Some((width, height)));
Ok(())
}

View file

@ -1476,6 +1476,40 @@ impl WebGLRenderingContext {
}
slot.set(framebuffer);
}
pub fn renderbuffer_storage(
&self,
target: u32,
samples: i32,
internal_format: u32,
width: i32,
height: i32,
) {
if target != constants::RENDERBUFFER {
return self.webgl_error(InvalidEnum);
}
let max = self.limits.max_renderbuffer_size;
if samples < 0 || width < 0 || width as u32 > max || height < 0 || height as u32 > max {
return self.webgl_error(InvalidValue);
}
let rb = handle_potential_webgl_error!(
self,
self.bound_renderbuffer.get().ok_or(InvalidOperation),
return
);
handle_potential_webgl_error!(
self,
rb.storage(self.api_type, samples, internal_format, width, height)
);
if let Some(fb) = self.bound_draw_framebuffer.get() {
fb.invalidate_renderbuffer(&*rb);
}
// FIXME: https://github.com/servo/servo/issues/13710
}
}
#[cfg(not(feature = "webgl_backtrace"))]
@ -4336,30 +4370,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
if target != constants::RENDERBUFFER {
return self.webgl_error(InvalidEnum);
}
let max = self.limits.max_renderbuffer_size;
if width < 0 || width as u32 > max || height < 0 || height as u32 > max {
return self.webgl_error(InvalidValue);
}
let rb = handle_potential_webgl_error!(
self,
self.bound_renderbuffer.get().ok_or(InvalidOperation),
return
);
handle_potential_webgl_error!(
self,
rb.storage(self.api_type, internal_format, width, height)
);
if let Some(fb) = self.bound_draw_framebuffer.get() {
fb.invalidate_renderbuffer(&*rb);
}
// FIXME: https://github.com/servo/servo/issues/13710
self.renderbuffer_storage(target, 0, internal_format, width, height)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6

View file

@ -316,9 +316,9 @@ interface mixin WebGL2RenderingContextBase
// void readBuffer(GLenum src);
/* Renderbuffer objects */
// any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
// void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
// GLsizei width, GLsizei height);
any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
/* Texture objects */
// void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,