mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #7682 - ecoal95:webgl-texture2d, r=jdm
webgl: Support texImage2D with a canvas as an argument This involved some refactoring of the 2d context code, which lead to some more test passed there. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7682) <!-- Reviewable:end -->
This commit is contained in:
commit
0f8c1b4601
11 changed files with 457 additions and 83 deletions
|
@ -143,6 +143,10 @@ impl CanvasRenderingContext2D {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||||
|
self.ipc_renderer.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn mark_as_dirty(&self) {
|
fn mark_as_dirty(&self) {
|
||||||
let canvas = self.canvas.root();
|
let canvas = self.canvas.root();
|
||||||
let node = NodeCast::from_ref(canvas.r());
|
let node = NodeCast::from_ref(canvas.r());
|
||||||
|
@ -245,6 +249,7 @@ impl CanvasRenderingContext2D {
|
||||||
// Pixels come from cache in BGRA order and drawImage expects RGBA so we
|
// Pixels come from cache in BGRA order and drawImage expects RGBA so we
|
||||||
// have to swap the color values
|
// have to swap the color values
|
||||||
byte_swap(&mut data);
|
byte_swap(&mut data);
|
||||||
|
let size = Size2D::new(size.width as f64, size.height as f64);
|
||||||
(data, size)
|
(data, size)
|
||||||
},
|
},
|
||||||
None => return Err(InvalidState),
|
None => return Err(InvalidState),
|
||||||
|
@ -338,7 +343,7 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
fn fetch_image_data(&self,
|
fn fetch_image_data(&self,
|
||||||
image_element: &HTMLImageElement)
|
image_element: &HTMLImageElement)
|
||||||
-> Option<(Vec<u8>, Size2D<f64>)> {
|
-> Option<(Vec<u8>, Size2D<i32>)> {
|
||||||
let url = match image_element.get_url() {
|
let url = match image_element.get_url() {
|
||||||
Some(url) => url,
|
Some(url) => url,
|
||||||
None => return None,
|
None => return None,
|
||||||
|
@ -351,7 +356,7 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_size = Size2D::new(img.width as f64, img.height as f64);
|
let image_size = Size2D::new(img.width as i32, img.height as i32);
|
||||||
let image_data = match img.format {
|
let image_data = match img.format {
|
||||||
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
||||||
PixelFormat::K8 => panic!("K8 color type not supported"),
|
PixelFormat::K8 => panic!("K8 color type not supported"),
|
||||||
|
@ -362,28 +367,6 @@ impl CanvasRenderingContext2D {
|
||||||
Some((image_data, image_size))
|
Some((image_data, image_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ecoal95): Move this to `HTMLCanvasElement`, and support WebGL contexts
|
|
||||||
fn fetch_canvas_data(&self,
|
|
||||||
canvas_element: &HTMLCanvasElement,
|
|
||||||
source_rect: Rect<f64>)
|
|
||||||
-> Option<(Vec<u8>, Size2D<f64>)> {
|
|
||||||
let context = match canvas_element.get_or_init_2d_context() {
|
|
||||||
Some(context) => context,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let canvas_size = canvas_element.get_size();
|
|
||||||
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
|
||||||
|
|
||||||
let renderer = context.r().get_ipc_renderer();
|
|
||||||
let (sender, receiver) = ipc::channel::<Vec<u8>>().unwrap();
|
|
||||||
// Reads pixels from source canvas
|
|
||||||
renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(source_rect.to_i32(),
|
|
||||||
image_size, sender))).unwrap();
|
|
||||||
|
|
||||||
Some((receiver.recv().unwrap(), image_size))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn request_image_from_cache(&self, url: Url) -> ImageResponse {
|
fn request_image_from_cache(&self, url: Url) -> ImageResponse {
|
||||||
let canvas = self.canvas.root();
|
let canvas = self.canvas.root();
|
||||||
|
@ -975,26 +958,20 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => {
|
||||||
let canvas_element = canvas.r();
|
let canvas = canvas.r();
|
||||||
|
let _ = canvas.get_or_init_2d_context();
|
||||||
|
|
||||||
let canvas_size = canvas_element.get_size();
|
match canvas.fetch_all_data() {
|
||||||
let source_rect = Rect::new(Point2D::zero(),
|
|
||||||
Size2D::new(canvas_size.width as f64, canvas_size.height as f64));
|
|
||||||
|
|
||||||
match self.fetch_canvas_data(&canvas_element, source_rect) {
|
|
||||||
Some((data, size)) => (data, size),
|
Some((data, size)) => (data, size),
|
||||||
None => return Err(InvalidState),
|
None => return Err(InvalidState),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => {
|
||||||
let canvas = context.r().Canvas();
|
let canvas = context.r().Canvas();
|
||||||
let canvas_element = canvas.r();
|
let canvas = canvas.r();
|
||||||
|
let _ = canvas.get_or_init_2d_context();
|
||||||
|
|
||||||
let canvas_size = canvas_element.get_size();
|
match canvas.fetch_all_data() {
|
||||||
let source_rect = Rect::new(Point2D::zero(),
|
|
||||||
Size2D::new(canvas_size.width as f64, canvas_size.height as f64));
|
|
||||||
|
|
||||||
match self.fetch_canvas_data(&canvas_element, source_rect) {
|
|
||||||
Some((data, size)) => (data, size),
|
Some((data, size)) => (data, size),
|
||||||
None => return Err(InvalidState),
|
None => return Err(InvalidState),
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +981,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
||||||
return Ok(CanvasPattern::new(self.global.root().r(),
|
return Ok(CanvasPattern::new(self.global.root().r(),
|
||||||
image_data,
|
image_data,
|
||||||
Size2D::new(image_size.width as i32, image_size.height as i32),
|
image_size,
|
||||||
rep));
|
rep));
|
||||||
}
|
}
|
||||||
return Err(Syntax);
|
return Err(Syntax);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use canvas_traits::CanvasMsg;
|
use canvas_traits::{CanvasMsg, FromLayoutMsg};
|
||||||
use dom::attr::Attr;
|
use dom::attr::Attr;
|
||||||
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
|
||||||
|
@ -22,11 +22,12 @@ use dom::node::{Node, NodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
|
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use js::jsapi::{HandleValue, JSContext};
|
use js::jsapi::{HandleValue, JSContext};
|
||||||
use offscreen_gl_context::GLContextAttributes;
|
use offscreen_gl_context::GLContextAttributes;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
use std::iter::repeat;
|
||||||
use util::str::{DOMString, parse_unsigned_integer};
|
use util::str::{DOMString, parse_unsigned_integer};
|
||||||
|
|
||||||
const DEFAULT_WIDTH: u32 = 300;
|
const DEFAULT_WIDTH: u32 = 300;
|
||||||
|
@ -114,27 +115,23 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn get_renderer_id(&self) -> Option<usize> {
|
unsafe fn get_renderer_id(&self) -> Option<usize> {
|
||||||
let ref canvas = *self.unsafe_get();
|
let ref canvas = *self.unsafe_get();
|
||||||
if let Some(context) = canvas.context.get() {
|
canvas.context.get().map(|context| {
|
||||||
match context {
|
match context {
|
||||||
CanvasContext::Context2d(context) => Some(context.to_layout().get_renderer_id()),
|
CanvasContext::Context2d(context) => context.to_layout().get_renderer_id(),
|
||||||
CanvasContext::WebGL(context) => Some(context.to_layout().get_renderer_id()),
|
CanvasContext::WebGL(context) => context.to_layout().get_renderer_id(),
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn get_ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
|
unsafe fn get_ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
|
||||||
let ref canvas = *self.unsafe_get();
|
let ref canvas = *self.unsafe_get();
|
||||||
if let Some(context) = canvas.context.get() {
|
canvas.context.get().map(|context| {
|
||||||
match context {
|
match context {
|
||||||
CanvasContext::Context2d(context) => Some(context.to_layout().get_ipc_renderer()),
|
CanvasContext::Context2d(context) => context.to_layout().get_ipc_renderer(),
|
||||||
CanvasContext::WebGL(context) => Some(context.to_layout().get_ipc_renderer()),
|
CanvasContext::WebGL(context) => context.to_layout().get_ipc_renderer(),
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -150,6 +147,15 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
|
||||||
|
|
||||||
|
|
||||||
impl HTMLCanvasElement {
|
impl HTMLCanvasElement {
|
||||||
|
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
|
||||||
|
self.context.get().map(|context| {
|
||||||
|
match context {
|
||||||
|
CanvasContext::Context2d(context) => context.root().r().ipc_renderer(),
|
||||||
|
CanvasContext::WebGL(context) => context.root().r().ipc_renderer(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
|
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
|
||||||
if self.context.get().is_none() {
|
if self.context.get().is_none() {
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
|
@ -200,6 +206,26 @@ impl HTMLCanvasElement {
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
self.height.get() != 0 && self.width.get() != 0
|
self.height.get() != 0 && self.width.get() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
|
||||||
|
let size = self.get_size();
|
||||||
|
|
||||||
|
if size.width == 0 || size.height == 0 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = if let Some(renderer) = self.ipc_renderer() {
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendPixelContents(sender));
|
||||||
|
renderer.send(msg).unwrap();
|
||||||
|
|
||||||
|
receiver.recv().unwrap().to_vec()
|
||||||
|
} else {
|
||||||
|
repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((data, size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
||||||
|
|
|
@ -124,6 +124,27 @@ impl WebGLRenderingContext {
|
||||||
self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap();
|
self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||||
|
self.ipc_renderer.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn webgl_error(&self, err: WebGLError) {
|
||||||
|
// If an error has been detected no further errors must be
|
||||||
|
// recorded until `getError` has been called
|
||||||
|
if self.last_error.get().is_none() {
|
||||||
|
self.last_error.set(Some(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bound_texture_for(&self, target: u32) -> Option<JS<WebGLTexture>> {
|
||||||
|
match target {
|
||||||
|
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
||||||
|
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mark_as_dirty(&self) {
|
fn mark_as_dirty(&self) {
|
||||||
let canvas = self.canvas.root();
|
let canvas = self.canvas.root();
|
||||||
let node = NodeCast::from_ref(canvas.r());
|
let node = NodeCast::from_ref(canvas.r());
|
||||||
|
@ -845,8 +866,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
},
|
},
|
||||||
// TODO(ecoal95): Getting canvas data is implemented in CanvasRenderingContext2D, but
|
// TODO(ecoal95): Getting canvas data is implemented in CanvasRenderingContext2D, but
|
||||||
// we need to refactor it moving it to `HTMLCanvasElement` and supporting WebGLContext
|
// we need to refactor it moving it to `HTMLCanvasElement` and supporting WebGLContext
|
||||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(_rooted_canvas)
|
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(canvas) => {
|
||||||
=> unimplemented!(),
|
let canvas = canvas.r();
|
||||||
|
if let Some((mut data, size)) = canvas.fetch_all_data() {
|
||||||
|
byte_swap(&mut data);
|
||||||
|
(data, size)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLVideoElement(_rooted_video)
|
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLVideoElement(_rooted_video)
|
||||||
=> unimplemented!(),
|
=> unimplemented!(),
|
||||||
};
|
};
|
||||||
|
@ -898,26 +926,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl WebGLRenderingContext {
|
|
||||||
pub fn webgl_error(&self, err: WebGLError) {
|
|
||||||
// If an error has been detected no further errors must be
|
|
||||||
// recorded until `getError` has been called
|
|
||||||
if self.last_error.get().is_none() {
|
|
||||||
self.last_error.set(Some(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bound_texture_for(&self, target: u32) -> Option<JS<WebGLTexture>> {
|
|
||||||
match target {
|
|
||||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
|
||||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutCanvasWebGLRenderingContextHelpers {
|
pub trait LayoutCanvasWebGLRenderingContextHelpers {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn get_renderer_id(&self) -> usize;
|
unsafe fn get_renderer_id(&self) -> usize;
|
||||||
|
|
|
@ -402,6 +402,9 @@ prefs:"layout.viewport.enabled" == viewport_rule.html viewport_rule_ref.html
|
||||||
|
|
||||||
== webgl-context/clearcolor.html webgl-context/clearcolor_ref.html
|
== webgl-context/clearcolor.html webgl-context/clearcolor_ref.html
|
||||||
== webgl-context/draw_arrays_simple.html webgl-context/draw_arrays_simple_ref.html
|
== webgl-context/draw_arrays_simple.html webgl-context/draw_arrays_simple_ref.html
|
||||||
|
== webgl-context/tex_image_2d_canvas.html webgl-context/tex_image_2d_canvas_ref.html
|
||||||
|
== webgl-context/tex_image_2d_canvas2d.html webgl-context/tex_image_2d_canvas_ref.html
|
||||||
|
== webgl-context/tex_image_2d_canvas_no_context.html webgl-context/tex_image_2d_canvas_no_context_ref.html
|
||||||
== webgl-context/tex_image_2d_simple.html webgl-context/tex_image_2d_simple_ref.html
|
== webgl-context/tex_image_2d_simple.html webgl-context/tex_image_2d_simple_ref.html
|
||||||
|
|
||||||
flaky_macos == white_space_intrinsic_sizes_a.html white_space_intrinsic_sizes_ref.html
|
flaky_macos == white_space_intrinsic_sizes_a.html white_space_intrinsic_sizes_ref.html
|
||||||
|
|
111
tests/ref/webgl-context/tex_image_2d_canvas.html
Normal file
111
tests/ref/webgl-context/tex_image_2d_canvas.html
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL texture test</title>
|
||||||
|
<!--
|
||||||
|
This test should show a 256x256 red square
|
||||||
|
-->
|
||||||
|
<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>
|
||||||
|
// We paint an offscreen red square and pass it as a texture to the on-screen canvas
|
||||||
|
var first_context = document.createElement('canvas').getContext('webgl');
|
||||||
|
|
||||||
|
first_context.canvas.width = first_context.canvas.height = 256;
|
||||||
|
first_context.clearColor(1, 0, 0, 1);
|
||||||
|
first_context.clear(first_context.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// pass the first canvas as texture
|
||||||
|
var tex = gl.createTexture();
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, first_context.canvas);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
console.log(gl.getError() == gl.NO_ERROR);
|
||||||
|
</script>
|
||||||
|
</html>
|
111
tests/ref/webgl-context/tex_image_2d_canvas2d.html
Normal file
111
tests/ref/webgl-context/tex_image_2d_canvas2d.html
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL texture test</title>
|
||||||
|
<!--
|
||||||
|
This test should show a 256x256 red square
|
||||||
|
-->
|
||||||
|
<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>
|
||||||
|
// We paint an offscreen red square with a 2d canvas and pass it as a texture to the on-screen canvas
|
||||||
|
var first_context = document.createElement('canvas').getContext('2d');
|
||||||
|
|
||||||
|
first_context.canvas.width = first_context.canvas.height = 256;
|
||||||
|
first_context.fillStyle = "red";
|
||||||
|
first_context.fillRect(0, 0, 256, 256);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// pass the first canvas as texture
|
||||||
|
var tex = gl.createTexture();
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, first_context.canvas);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
console.log(gl.getError() == gl.NO_ERROR);
|
||||||
|
</script>
|
||||||
|
</html>
|
111
tests/ref/webgl-context/tex_image_2d_canvas_no_context.html
Normal file
111
tests/ref/webgl-context/tex_image_2d_canvas_no_context.html
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL texture test</title>
|
||||||
|
<!--
|
||||||
|
This test should show a 256x256 red square
|
||||||
|
with a 128x128 white square embedded in the
|
||||||
|
middle
|
||||||
|
-->
|
||||||
|
<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>
|
||||||
|
// When passed a canvas with size but without context as a texture the
|
||||||
|
// source should be considered a white bitmap with the given size
|
||||||
|
var canvas_without_context = document.createElement('canvas');
|
||||||
|
canvas_without_context.width = canvas_without_context.height = 256;
|
||||||
|
|
||||||
|
var gl = document.getElementById('c').getContext('webgl');
|
||||||
|
|
||||||
|
// Clear with a non-white color
|
||||||
|
gl.clearColor(1, 0, 0, 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([
|
||||||
|
-0.5, 0.5, // top left
|
||||||
|
0.5, 0.5, // top right
|
||||||
|
-0.5, -0.5, // bottom left
|
||||||
|
-0.5, -0.5, // bottom left
|
||||||
|
0.5, 0.5, // top right
|
||||||
|
0.5, -0.5 // 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);
|
||||||
|
|
||||||
|
// pass the first canvas as texture
|
||||||
|
var tex = gl.createTexture();
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas_without_context);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
console.log(gl.getError() == gl.NO_ERROR);
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL texture test</title>
|
||||||
|
<!--
|
||||||
|
This test should show a 256x256 red square
|
||||||
|
with a 128x128 white square embedded in the
|
||||||
|
middle
|
||||||
|
-->
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0 }
|
||||||
|
.a {
|
||||||
|
width: 256px;
|
||||||
|
height: 256px;
|
||||||
|
background: red;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.b {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
background: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 64px;
|
||||||
|
left: 64px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="a"><div class="b"></div></div>
|
11
tests/ref/webgl-context/tex_image_2d_canvas_ref.html
Normal file
11
tests/ref/webgl-context/tex_image_2d_canvas_ref.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL texture test</title>
|
||||||
|
<!--
|
||||||
|
This test should show a 256x256 red square
|
||||||
|
-->
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0 }
|
||||||
|
div { width: 256px; height: 256px; background: red; }
|
||||||
|
</style>
|
||||||
|
<div></div>
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.composite.globalAlpha.canvaspattern.html]
|
|
||||||
type: testharness
|
|
||||||
[Canvas test: 2d.composite.globalAlpha.canvaspattern]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.pattern.basic.zerocanvas.html]
|
|
||||||
type: testharness
|
|
||||||
[Canvas test: 2d.pattern.basic.zerocanvas]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue