Skip to content

Commit

Permalink
Add support for some more WebGL2 renderbuffer functions
Browse files Browse the repository at this point in the history
Adds support for the following WebGL2 calls:

- `RenderbufferStorageMultisample`
- `GetInternalFormativ`

See: https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
  • Loading branch information
mmatyas authored and jdm committed Mar 13, 2020
1 parent 13a3496 commit 5eaa9ef
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 70 deletions.
31 changes: 31 additions & 0 deletions components/canvas/webgl_thread.rs
Expand Up @@ -13,6 +13,7 @@ use canvas_traits::webgl::DOMToTextureCommand;
use canvas_traits::webgl::GLContextAttributes;
use canvas_traits::webgl::GLLimits;
use canvas_traits::webgl::GlType;
use canvas_traits::webgl::InternalFormatIntVec;
use canvas_traits::webgl::ProgramLinkInfo;
use canvas_traits::webgl::SwapChainId;
use canvas_traits::webgl::TexDataType;
Expand Down Expand Up @@ -1211,6 +1212,13 @@ impl WebGLImpl {
WebGLCommand::RenderbufferStorage(target, format, width, height) => {
gl.renderbuffer_storage(target, format, width, height)
},
WebGLCommand::RenderbufferStorageMultisample(
target,
samples,
format,
width,
height,
) => gl.renderbuffer_storage_multisample(target, samples, format, width, height),
WebGLCommand::SampleCoverage(value, invert) => gl.sample_coverage(value, invert),
WebGLCommand::Scissor(x, y, width, height) => {
// FIXME(nox): Kinda unfortunate that some u32 values could
Expand Down Expand Up @@ -1666,6 +1674,29 @@ impl WebGLImpl {
.send(gl.get_tex_parameter_iv(target, param as u32))
.unwrap();
},
WebGLCommand::GetInternalFormatIntVec(target, internal_format, param, ref sender) => {
match param {
InternalFormatIntVec::Samples => {
let mut count = [0; 1];
gl.get_internal_format_iv(
target,
internal_format,
gl::NUM_SAMPLE_COUNTS,
&mut count,
);
assert!(count[0] >= 0);

let mut values = vec![0; count[0] as usize];
gl.get_internal_format_iv(
target,
internal_format,
param as u32,
&mut values,
);
sender.send(values).unwrap()
},
}
},
WebGLCommand::TexParameteri(target, param, value) => {
gl.tex_parameter_i(target, param as u32, value)
},
Expand Down
10 changes: 10 additions & 0 deletions components/canvas_traits/webgl.rs
Expand Up @@ -330,6 +330,7 @@ pub enum WebGLCommand {
TransformFeedbackVaryings(WebGLProgramId, Vec<String>, u32),
PolygonOffset(f32, f32),
RenderbufferStorage(u32, u32, i32, i32),
RenderbufferStorageMultisample(u32, i32, u32, i32, i32),
ReadPixels(Rect<u32>, u32, u32, IpcBytesSender),
ReadPixelsPP(Rect<i32>, u32, u32, usize),
SampleCoverage(f32, bool),
Expand Down Expand Up @@ -458,6 +459,7 @@ pub enum WebGLCommand {
GetCurrentVertexAttrib(u32, WebGLSender<[f32; 4]>),
GetTexParameterFloat(u32, TexParameterFloat, WebGLSender<f32>),
GetTexParameterInt(u32, TexParameterInt, WebGLSender<i32>),
GetInternalFormatIntVec(u32, u32, InternalFormatIntVec, WebGLSender<Vec<i32>>),
TexParameteri(u32, u32, i32),
TexParameterf(u32, u32, f32),
DrawArrays {
Expand Down Expand Up @@ -913,6 +915,14 @@ parameters! {
}
}

parameters! {
InternalFormatParameter {
IntVec(InternalFormatIntVec {
Samples = gl::SAMPLES,
}),
}
}

#[macro_export]
macro_rules! gl_enums {
($(pub enum $name:ident { $($variant:ident = $mod:ident::$constant:ident,)+ })*) => {
Expand Down
59 changes: 57 additions & 2 deletions components/script/dom/webgl2renderingcontext.rs
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
40 changes: 33 additions & 7 deletions components/script/dom/webglrenderbuffer.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
},
Expand Down Expand Up @@ -221,24 +224,47 @@ 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);

if let Some(fb) = self.attached_framebuffer.get() {
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(())
}

Expand Down
59 changes: 35 additions & 24 deletions components/script/dom/webglrenderingcontext.rs
Expand Up @@ -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"))]
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions components/script/dom/webidls/WebGL2RenderingContext.webidl
Expand Up @@ -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,
Expand Down

0 comments on commit 5eaa9ef

Please sign in to comment.