mirror of
https://github.com/servo/servo.git
synced 2025-06-14 19:34:29 +00:00
webgl: finish, flush, detachShader, generateMipmap, Uniform1i
This commit is contained in:
parent
d0f692b2c5
commit
3fd7634f54
14 changed files with 634 additions and 12 deletions
|
@ -266,6 +266,14 @@ macro_rules! make_nonzero_dimension_setter(
|
|||
/// For use on non-jsmanaged types
|
||||
/// Use #[derive(JSTraceable)] on JS managed types
|
||||
macro_rules! no_jsmanaged_fields(
|
||||
([$ty:ident; $count:expr]) => (
|
||||
impl $crate::dom::bindings::trace::JSTraceable for [$ty; $count] {
|
||||
#[inline]
|
||||
fn trace(&self, _: *mut ::js::jsapi::JSTracer) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
);
|
||||
($($ty:ident),+) => (
|
||||
$(
|
||||
impl $crate::dom::bindings::trace::JSTraceable for $ty {
|
||||
|
|
|
@ -94,7 +94,10 @@ impl WebGLProgram {
|
|||
let shader_slot = match shader.gl_type() {
|
||||
constants::FRAGMENT_SHADER => &self.fragment_shader,
|
||||
constants::VERTEX_SHADER => &self.vertex_shader,
|
||||
_ => return Err(WebGLError::InvalidOperation),
|
||||
_ => {
|
||||
error!("detachShader: Unexpected shader type");
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(emilio): Differentiate between same shader already assigned and other previous
|
||||
|
@ -110,6 +113,32 @@ impl WebGLProgram {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// glDetachShader
|
||||
pub fn detach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
|
||||
let shader_slot = match shader.gl_type() {
|
||||
constants::FRAGMENT_SHADER => &self.fragment_shader,
|
||||
constants::VERTEX_SHADER => &self.vertex_shader,
|
||||
_ => {
|
||||
error!("detachShader: Unexpected shader type");
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
};
|
||||
|
||||
match shader_slot.get() {
|
||||
Some(ref attached_shader) if attached_shader.id() != shader.id() =>
|
||||
return Err(WebGLError::InvalidOperation),
|
||||
None =>
|
||||
return Err(WebGLError::InvalidOperation),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
shader_slot.set(None);
|
||||
|
||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DetachShader(self.id, shader.id()))).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glBindAttribLocation
|
||||
pub fn bind_attrib_location(&self, index: u32, name: DOMString) -> WebGLResult<()> {
|
||||
if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN {
|
||||
|
|
|
@ -181,6 +181,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
Root::from_ref(&*self.canvas)
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
|
||||
fn Flush(&self) {
|
||||
self.ipc_renderer
|
||||
.send(CanvasMsg::WebGL(WebGLCommand::Flush))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
|
||||
fn Finish(&self) {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.ipc_renderer
|
||||
.send(CanvasMsg::WebGL(WebGLCommand::Finish(sender)))
|
||||
.unwrap();
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1
|
||||
fn DrawingBufferWidth(&self) -> i32 {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
|
@ -331,6 +347,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn DetachShader(&self, program: Option<&WebGLProgram>, shader: Option<&WebGLShader>) {
|
||||
if let Some(program) = program {
|
||||
if let Some(shader) = shader {
|
||||
handle_potential_webgl_error!(self, program.detach_shader(shader));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn BindAttribLocation(&self, program: Option<&WebGLProgram>,
|
||||
index: u32, name: DOMString) {
|
||||
|
@ -414,6 +439,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
fn GenerateMipmap(&self, target: u32) {
|
||||
let slot = match target {
|
||||
constants::TEXTURE_2D => &self.bound_texture_2d,
|
||||
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
|
||||
|
||||
_ => return self.webgl_error(InvalidEnum),
|
||||
};
|
||||
|
||||
match slot.get() {
|
||||
Some(texture) => handle_potential_webgl_error!(self, texture.generate_mipmap()),
|
||||
None => self.webgl_error(InvalidOperation)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
|
||||
fn BufferData(&self, _cx: *mut JSContext, target: u32, data: Option<*mut JSObject>, usage: u32) {
|
||||
|
@ -949,6 +989,25 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
|
||||
fn Uniform1i(&self,
|
||||
uniform: Option<&WebGLUniformLocation>,
|
||||
val: i32) {
|
||||
let uniform = match uniform {
|
||||
Some(uniform) => uniform,
|
||||
None => return,
|
||||
};
|
||||
|
||||
match self.current_program.get() {
|
||||
Some(ref program) if program.id() == uniform.program_id() => {},
|
||||
_ => return self.webgl_error(InvalidOperation),
|
||||
};
|
||||
|
||||
self.ipc_renderer
|
||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1i(uniform.id(), val)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
|
||||
fn Uniform1fv(&self,
|
||||
uniform: Option<&WebGLUniformLocation>,
|
||||
|
@ -1107,7 +1166,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
internal_format: u32,
|
||||
format: u32,
|
||||
data_type: u32,
|
||||
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement >) {
|
||||
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) {
|
||||
let texture = match target {
|
||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
||||
|
@ -1169,11 +1228,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
=> unimplemented!(),
|
||||
};
|
||||
|
||||
if size.width < 0 || size.height < 0 || level < 0 {
|
||||
self.webgl_error(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
// TODO(emilio): Invert axis, convert colorspace, premultiply alpha if requested
|
||||
let msg = WebGLCommand::TexImage2D(target, level, internal_format as i32,
|
||||
size.width, size.height,
|
||||
format, data_type, pixels);
|
||||
|
||||
// depth is always 1 when coming from html elements
|
||||
handle_potential_webgl_error!(self, texture.unwrap().initialize(size.width as u32,
|
||||
size.height as u32,
|
||||
1,
|
||||
internal_format,
|
||||
level as u32));
|
||||
|
||||
self.ipc_renderer
|
||||
.send(CanvasMsg::WebGL(msg))
|
||||
.unwrap()
|
||||
|
|
|
@ -99,7 +99,7 @@ impl WebGLShader {
|
|||
let validator = ShaderValidator::for_webgl(self.gl_type,
|
||||
SHADER_OUTPUT_FORMAT,
|
||||
&BuiltInResources::default()).unwrap();
|
||||
match validator.compile_and_translate(&[source.as_bytes()]) {
|
||||
match validator.compile_and_translate(&[source]) {
|
||||
Ok(translated_source) => {
|
||||
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
|
||||
// will succeed.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// 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::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use dom::bindings::codegen::Bindings::WebGLTextureBinding;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
|
@ -12,6 +13,7 @@ use dom::bindings::reflector::reflect_dom_object;
|
|||
use dom::webglobject::WebGLObject;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use std::cell::Cell;
|
||||
use std::cmp;
|
||||
use webrender_traits::{WebGLCommand, WebGLError, WebGLResult};
|
||||
|
||||
pub enum TexParameterValue {
|
||||
|
@ -19,6 +21,11 @@ pub enum TexParameterValue {
|
|||
Int(i32),
|
||||
}
|
||||
|
||||
const MAX_LEVEL_COUNT: usize = 31;
|
||||
const MAX_FACE_COUNT: usize = 6;
|
||||
|
||||
no_jsmanaged_fields!([ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]);
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WebGLTexture {
|
||||
webgl_object: WebGLObject,
|
||||
|
@ -26,6 +33,13 @@ pub struct WebGLTexture {
|
|||
/// The target to which this texture was bound the first time
|
||||
target: Cell<Option<u32>>,
|
||||
is_deleted: Cell<bool>,
|
||||
is_initialized: Cell<bool>,
|
||||
/// Stores information about mipmap levels and cubemap faces.
|
||||
#[ignore_heap_size_of = "Arrays are cumbersome"]
|
||||
image_info_array: DOMRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
|
||||
/// Face count can only be 1 or 6
|
||||
face_count: Cell<u8>,
|
||||
base_mipmap_level: u32,
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
renderer: IpcSender<CanvasMsg>,
|
||||
}
|
||||
|
@ -37,6 +51,10 @@ impl WebGLTexture {
|
|||
id: id,
|
||||
target: Cell::new(None),
|
||||
is_deleted: Cell::new(false),
|
||||
is_initialized: Cell::new(false),
|
||||
face_count: Cell::new(0),
|
||||
base_mipmap_level: 0,
|
||||
image_info_array: DOMRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
|
||||
renderer: renderer,
|
||||
}
|
||||
}
|
||||
|
@ -63,11 +81,22 @@ impl WebGLTexture {
|
|||
|
||||
// NB: Only valid texture targets come here
|
||||
pub fn bind(&self, target: u32) -> WebGLResult<()> {
|
||||
if self.is_deleted.get() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if let Some(previous_target) = self.target.get() {
|
||||
if target != previous_target {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
} else {
|
||||
// This is the first time binding
|
||||
let face_count = match target {
|
||||
constants::TEXTURE_2D => 1,
|
||||
constants::TEXTURE_CUBE_MAP => 6,
|
||||
_ => return Err(WebGLError::InvalidOperation)
|
||||
};
|
||||
self.face_count.set(face_count);
|
||||
self.target.set(Some(target));
|
||||
}
|
||||
|
||||
|
@ -76,6 +105,58 @@ impl WebGLTexture {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn initialize(&self, width: u32, height: u32, depth: u32, internal_format: u32, level: u32) -> WebGLResult<()> {
|
||||
let image_info = ImageInfo {
|
||||
width: width,
|
||||
height: height,
|
||||
depth: depth,
|
||||
internal_format: Some(internal_format),
|
||||
is_initialized: true,
|
||||
};
|
||||
self.set_image_infos_at_level(level, image_info);
|
||||
|
||||
self.is_initialized.set(true);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_mipmap(&self) -> WebGLResult<()> {
|
||||
let target = match self.target.get() {
|
||||
Some(target) => target,
|
||||
None => {
|
||||
error!("Cannot generate mipmap on texture that has no target!");
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
};
|
||||
|
||||
let base_image_info = self.base_image_info().unwrap();
|
||||
|
||||
if !base_image_info.is_initialized() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if target == constants::TEXTURE_CUBE_MAP && !self.is_cube_complete() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !base_image_info.is_power_of_two() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if base_image_info.is_compressed_format() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GenerateMipmap(target))).unwrap();
|
||||
|
||||
if self.base_mipmap_level + base_image_info.get_max_mimap_levels() == 0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
let last_level = self.base_mipmap_level + base_image_info.get_max_mimap_levels() - 1;
|
||||
self.populate_mip_chain(self.base_mipmap_level, last_level)
|
||||
}
|
||||
|
||||
pub fn delete(&self) {
|
||||
if !self.is_deleted.get() {
|
||||
self.is_deleted.set(true);
|
||||
|
@ -145,6 +226,84 @@ impl WebGLTexture {
|
|||
_ => Err(WebGLError::InvalidEnum),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> {
|
||||
let base_image_info = self.image_info_at_face(0, first_level);
|
||||
if !base_image_info.is_initialized() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
let mut ref_width = base_image_info.width;
|
||||
let mut ref_height = base_image_info.height;
|
||||
|
||||
if ref_width == 0 || ref_height == 0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
for level in (first_level + 1)..last_level {
|
||||
if ref_width == 1 && ref_height == 1 {
|
||||
break;
|
||||
}
|
||||
|
||||
ref_width = cmp::max(1, ref_width / 2);
|
||||
ref_height = cmp::max(1, ref_height / 2);
|
||||
|
||||
let image_info = ImageInfo {
|
||||
width: ref_width,
|
||||
height: ref_height,
|
||||
depth: 0,
|
||||
internal_format: base_image_info.internal_format,
|
||||
is_initialized: base_image_info.is_initialized(),
|
||||
};
|
||||
|
||||
self.set_image_infos_at_level(level, image_info);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_cube_complete(&self) -> bool {
|
||||
let image_info = self.base_image_info().unwrap();
|
||||
if !image_info.is_defined() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let ref_width = image_info.width;
|
||||
let ref_format = image_info.internal_format;
|
||||
|
||||
for face in 0..self.face_count.get() {
|
||||
let current_image_info = self.image_info_at_face(face, self.base_mipmap_level);
|
||||
if !current_image_info.is_defined() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compares height with width to enforce square dimensions
|
||||
if current_image_info.internal_format != ref_format ||
|
||||
current_image_info.width != ref_width ||
|
||||
current_image_info.height != ref_width {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn image_info_at_face(&self, face: u8, level: u32) -> ImageInfo {
|
||||
let pos = (level * self.face_count.get() as u32) + face as u32;
|
||||
self.image_info_array.borrow()[pos as usize]
|
||||
}
|
||||
|
||||
fn set_image_infos_at_level(&self, level: u32, image_info: ImageInfo) {
|
||||
for face in 0..self.face_count.get() {
|
||||
let pos = (level * self.face_count.get() as u32) + face as u32;
|
||||
self.image_info_array.borrow_mut()[pos as usize] = image_info;
|
||||
}
|
||||
}
|
||||
|
||||
fn base_image_info(&self) -> Option<ImageInfo> {
|
||||
assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT);
|
||||
|
||||
Some(self.image_info_at_face(0, self.base_mipmap_level))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLTexture {
|
||||
|
@ -152,3 +311,50 @@ impl Drop for WebGLTexture {
|
|||
self.delete();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug, JSTraceable, HeapSizeOf)]
|
||||
struct ImageInfo {
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
internal_format: Option<u32>,
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
impl ImageInfo {
|
||||
fn new() -> ImageInfo {
|
||||
ImageInfo {
|
||||
width: 0,
|
||||
height: 0,
|
||||
depth: 0,
|
||||
internal_format: None,
|
||||
is_initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_power_of_two(&self) -> bool {
|
||||
self.width.is_power_of_two() && self.height.is_power_of_two() && self.depth.is_power_of_two()
|
||||
}
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
|
||||
fn is_defined(&self) -> bool {
|
||||
!self.internal_format.is_none()
|
||||
}
|
||||
|
||||
fn get_max_mimap_levels(&self) -> u32 {
|
||||
let largest = cmp::max(cmp::max(self.width, self.height), self.depth);
|
||||
if largest == 0 {
|
||||
return 0;
|
||||
}
|
||||
// FloorLog2(largest) + 1
|
||||
(largest as f64).log2() as u32 + 1
|
||||
}
|
||||
|
||||
fn is_compressed_format(&self) -> bool {
|
||||
// TODO: Once Servo supports compressed formats, check for them here
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -548,7 +548,7 @@ interface WebGLRenderingContextBase
|
|||
void depthFunc(GLenum func);
|
||||
void depthMask(GLboolean flag);
|
||||
void depthRange(GLclampf zNear, GLclampf zFar);
|
||||
//void detachShader(WebGLProgram? program, WebGLShader? shader);
|
||||
void detachShader(WebGLProgram? program, WebGLShader? shader);
|
||||
void disable(GLenum cap);
|
||||
//void disableVertexAttribArray(GLuint index);
|
||||
void drawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
|
@ -556,8 +556,8 @@ interface WebGLRenderingContextBase
|
|||
|
||||
void enable(GLenum cap);
|
||||
void enableVertexAttribArray(GLuint index);
|
||||
//void finish();
|
||||
//void flush();
|
||||
void finish();
|
||||
void flush();
|
||||
//void framebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
// GLenum renderbuffertarget,
|
||||
// WebGLRenderbuffer? renderbuffer);
|
||||
|
@ -565,7 +565,7 @@ interface WebGLRenderingContextBase
|
|||
// WebGLTexture? texture, GLint level);
|
||||
void frontFace(GLenum mode);
|
||||
|
||||
//void generateMipmap(GLenum target);
|
||||
void generateMipmap(GLenum target);
|
||||
|
||||
//WebGLActiveInfo? getActiveAttrib(WebGLProgram? program, GLuint index);
|
||||
//WebGLActiveInfo? getActiveUniform(WebGLProgram? program, GLuint index);
|
||||
|
@ -647,7 +647,7 @@ interface WebGLRenderingContextBase
|
|||
void uniform1f(WebGLUniformLocation? location, GLfloat x);
|
||||
//void uniform1fv(WebGLUniformLocation? location, Float32Array v);
|
||||
void uniform1fv(WebGLUniformLocation? location, sequence<GLfloat> v);
|
||||
//void uniform1i(WebGLUniformLocation? location, GLint x);
|
||||
void uniform1i(WebGLUniformLocation? location, GLint x);
|
||||
//void uniform1iv(WebGLUniformLocation? location, Int32Array v);
|
||||
//void uniform1iv(WebGLUniformLocation? location, sequence<long> v);
|
||||
//void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y);
|
||||
|
@ -717,4 +717,3 @@ interface WebGLRenderingContext
|
|||
{
|
||||
};
|
||||
WebGLRenderingContext implements WebGLRenderingContextBase;
|
||||
|
||||
|
|
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -73,7 +73,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
[[package]]
|
||||
name = "angle"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#ebe29683474ac13a448cc03f772d33179c030cc2"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#eefe3506ae13e8ace811ca544fd6b4a5f0db0a04"
|
||||
dependencies = [
|
||||
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -57,7 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
[[package]]
|
||||
name = "angle"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#ebe29683474ac13a448cc03f772d33179c030cc2"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#eefe3506ae13e8ace811ca544fd6b4a5f0db0a04"
|
||||
dependencies = [
|
||||
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
2
ports/gonk/Cargo.lock
generated
2
ports/gonk/Cargo.lock
generated
|
@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
[[package]]
|
||||
name = "angle"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#ebe29683474ac13a448cc03f772d33179c030cc2"
|
||||
source = "git+https://github.com/emilio/angle?branch=servo#eefe3506ae13e8ace811ca544fd6b4a5f0db0a04"
|
||||
dependencies = [
|
||||
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
BIN
tests/html/rust-power-of-two.png
Normal file
BIN
tests/html/rust-power-of-two.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
160
tests/html/test_webgl_texture_mipmaps.html
Normal file
160
tests/html/test_webgl_texture_mipmaps.html
Normal file
|
@ -0,0 +1,160 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebGL Texture Mipmap</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="text-align: center">
|
||||
SE<canvas id="canvas" width="128" height="128"></canvas>VO
|
||||
</div>
|
||||
<script id="vertexshader" type="x-shader">
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
|
||||
varying vec2 vTextureCoord;
|
||||
|
||||
uniform float uTime;
|
||||
|
||||
void main() {
|
||||
vTextureCoord = aTextureCoord;
|
||||
mat4 rotMat = mat4(sin(uTime), 0.0, 0.0, 0.0,
|
||||
0.0, sin(uTime), 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
gl_Position = rotMat * vec4(aVertexPosition, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
<script id="fragmentshader" type="x-shader">
|
||||
precision mediump float;
|
||||
varying vec2 vTextureCoord;
|
||||
|
||||
uniform sampler2D uSampler;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(uSampler, vTextureCoord);
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var canvas;
|
||||
function initWebGL()
|
||||
{
|
||||
canvas = document.getElementById("canvas");
|
||||
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||
if (!gl) return null; // can't initialize WebGL
|
||||
return gl;
|
||||
}
|
||||
|
||||
var gl = initWebGL();
|
||||
|
||||
// Setup Shaders:
|
||||
var v = document.getElementById("vertexshader").firstChild.nodeValue;
|
||||
var f = document.getElementById("fragmentshader").firstChild.nodeValue;
|
||||
|
||||
var vs = gl.createShader(gl.VERTEX_SHADER);
|
||||
gl.shaderSource(vs, v);
|
||||
gl.compileShader(vs);
|
||||
|
||||
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
|
||||
console.log(gl.getShaderInfoLog(vs));
|
||||
}
|
||||
|
||||
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fs, f);
|
||||
gl.compileShader(fs);
|
||||
|
||||
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
|
||||
console.log(gl.getShaderInfoLog(fs));
|
||||
}
|
||||
|
||||
program = gl.createProgram();
|
||||
gl.attachShader(program, vs);
|
||||
gl.attachShader(program, fs);
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
console.log(gl.getProgramInfoLog(program));
|
||||
}
|
||||
|
||||
gl.useProgram(program);
|
||||
|
||||
program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
|
||||
gl.enableVertexAttribArray(program.aVertexPosition);
|
||||
|
||||
program.aTextureCoord = gl.getAttribLocation(program, "aTextureCoord");
|
||||
gl.enableVertexAttribArray(program.aTextureCoord);
|
||||
|
||||
var rustTexture = gl.createTexture();
|
||||
var rustImage = new Image();
|
||||
rustImage.onload = function() { handleTextureLoaded(rustImage, rustTexture); }
|
||||
rustImage.src = "rust-power-of-two.png";
|
||||
|
||||
|
||||
// Setup Geometry
|
||||
var vertices = new Float32Array([
|
||||
-1.0, -1.0,
|
||||
-1.0, 1.0,
|
||||
1.0, -1.0,
|
||||
1.0, 1.0 // Square-Coordinates
|
||||
]);
|
||||
|
||||
var textureCoords = new Float32Array([
|
||||
0.0, 0.0,
|
||||
0.0, 1.0,
|
||||
1.0, 0.0,
|
||||
1.0, 1.0
|
||||
]);
|
||||
|
||||
vbuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||
|
||||
uvbuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, uvbuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW);
|
||||
|
||||
itemSize = 2; // we have 2 coordinates (x,y)
|
||||
numItems = vertices.length / itemSize; // number of vertices
|
||||
|
||||
// Viewport
|
||||
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
|
||||
program.time = gl.getUniformLocation(program, "uTime");
|
||||
|
||||
var start_time = new Date().getTime() / 1000;
|
||||
|
||||
setInterval(function () {
|
||||
gl.clearColor(1, 0, 0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
// Draw
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
|
||||
gl.vertexAttribPointer(program.aVertexPosition, itemSize, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, uvbuffer);
|
||||
gl.vertexAttribPointer(program.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, rustTexture);
|
||||
var dt = new Date().getTime() / 1000 - start_time;
|
||||
gl.uniform1f(program.time, dt);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, numItems);
|
||||
}, 15);
|
||||
|
||||
function handleTextureLoaded(image, texture) {
|
||||
console.log("handleTextureLoaded, image = " + image);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -5635,6 +5635,18 @@
|
|||
"url": "/_mozilla/mozilla/webgl/tex_image_2d_canvas_no_context.html"
|
||||
}
|
||||
],
|
||||
"mozilla/webgl/tex_image_2d_mipmap.html": [
|
||||
{
|
||||
"path": "mozilla/webgl/tex_image_2d_mipmap.html",
|
||||
"references": [
|
||||
[
|
||||
"/_mozilla/mozilla/webgl/tex_image_2d_simple_ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
"url": "/_mozilla/mozilla/webgl/tex_image_2d_mipmap.html"
|
||||
}
|
||||
],
|
||||
"mozilla/webgl/tex_image_2d_simple.html": [
|
||||
{
|
||||
"path": "mozilla/webgl/tex_image_2d_simple.html",
|
||||
|
@ -12069,6 +12081,18 @@
|
|||
"url": "/_mozilla/mozilla/webgl/tex_image_2d_canvas_no_context.html"
|
||||
}
|
||||
],
|
||||
"mozilla/webgl/tex_image_2d_mipmap.html": [
|
||||
{
|
||||
"path": "mozilla/webgl/tex_image_2d_mipmap.html",
|
||||
"references": [
|
||||
[
|
||||
"/_mozilla/mozilla/webgl/tex_image_2d_simple_ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
"url": "/_mozilla/mozilla/webgl/tex_image_2d_mipmap.html"
|
||||
}
|
||||
],
|
||||
"mozilla/webgl/tex_image_2d_simple.html": [
|
||||
{
|
||||
"path": "mozilla/webgl/tex_image_2d_simple.html",
|
||||
|
|
116
tests/wpt/mozilla/tests/mozilla/webgl/tex_image_2d_mipmap.html
Normal file
116
tests/wpt/mozilla/tests/mozilla/webgl/tex_image_2d_mipmap.html
Normal file
|
@ -0,0 +1,116 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<link rel="match" href="tex_image_2d_simple_ref.html"></link>
|
||||
<meta charset="utf-8">
|
||||
<title>WebGL texture test</title>
|
||||
<!--
|
||||
This test should show a 256x256 rust logo
|
||||
-->
|
||||
<style>
|
||||
html, body { margin: 0 }
|
||||
</style>
|
||||
<canvas id="c" width="256" height="256"></canvas>
|
||||
<script id="vertex_shader" type="x-shader/x-vertex">
|
||||
precision mediump float;
|
||||
attribute vec2 a_texCoord;
|
||||
attribute vec2 a_position;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(a_position, 0, 1);
|
||||
v_texCoord = a_texCoord;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="fragment_shader" type="x-shader/x-fragment">
|
||||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(u_image, v_texCoord);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var gl = document.getElementById('c').getContext('webgl');
|
||||
|
||||
// Clear white
|
||||
gl.clearColor(1, 1, 1, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
// Create the program
|
||||
var vertex_shader = gl.createShader(gl.VERTEX_SHADER),
|
||||
fragment_shader = gl.createShader(gl.FRAGMENT_SHADER),
|
||||
program = gl.createProgram();
|
||||
|
||||
gl.shaderSource(vertex_shader,
|
||||
document.getElementById('vertex_shader').textContent);
|
||||
gl.shaderSource(fragment_shader,
|
||||
document.getElementById('fragment_shader').textContent);
|
||||
gl.compileShader(vertex_shader);
|
||||
gl.compileShader(fragment_shader);
|
||||
gl.attachShader(program, vertex_shader);
|
||||
gl.attachShader(program, fragment_shader);
|
||||
console.log(gl.getShaderInfoLog(vertex_shader));
|
||||
console.log(gl.getShaderInfoLog(fragment_shader));
|
||||
gl.linkProgram(program);
|
||||
gl.useProgram(program);
|
||||
|
||||
// Get the position from the fragment shader
|
||||
var position = gl.getAttribLocation(program, "a_position");
|
||||
var tex_position = gl.getAttribLocation(program, "a_texCoord");
|
||||
|
||||
var texture_coordinates = new Float32Array([
|
||||
0.0, 0.0,
|
||||
1.0, 0.0,
|
||||
0.0, 1.0,
|
||||
0.0, 1.0,
|
||||
1.0, 0.0,
|
||||
1.0, 1.0
|
||||
]);
|
||||
|
||||
var texture_buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, texture_buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, texture_coordinates, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(tex_position);
|
||||
gl.vertexAttribPointer(tex_position, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
var square_data = new Float32Array([
|
||||
-1.0, 1.0, // top left
|
||||
1.0, 1.0, // top right
|
||||
-1.0, -1.0, // bottom left
|
||||
-1.0, -1.0, // bottom left
|
||||
1.0, 1.0, // top right
|
||||
1.0, -1.0 // bottom right
|
||||
]);
|
||||
|
||||
// Create a buffer for the square with the square
|
||||
// vertex data
|
||||
var square_buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, square_buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, square_data, gl.STATIC_DRAW);
|
||||
|
||||
gl.enableVertexAttribArray(position);
|
||||
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
// Load the texture and draw
|
||||
var image = new Image();
|
||||
image.width = image.height = 256;
|
||||
// Base-64 to allow the reftest to finish
|
||||
image.src = "img/rust-logo-256x256.png";
|
||||
|
||||
image.onload = function () {
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
|
||||
console.log(gl.getError() == gl.NO_ERROR);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>WebGL texture test</title>
|
||||
<!--
|
||||
This test should show a 256x256 rust logo
|
||||
-->
|
||||
<style>
|
||||
html, body { margin: 0 }
|
||||
</style>
|
||||
<img src="img/rust-logo-256x256.png">
|
Loading…
Add table
Add a link
Reference in a new issue