mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Add support for WebGL2 TexStorage2D
Adds initial support for the WebGL2 `TexStorage2D` call, adds support for the related texture enums and enables some of the texture tests. See: https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
This commit is contained in:
parent
3bedd44026
commit
8789a6a8d8
63 changed files with 1906 additions and 384 deletions
|
@ -18,6 +18,8 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
|
|||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
|
||||
use crate::dom::webgl_validations::tex_image_2d::{TexStorageValidator, TexStorageValidatorResult};
|
||||
use crate::dom::webgl_validations::WebGLValidator;
|
||||
use crate::dom::webglactiveinfo::WebGLActiveInfo;
|
||||
use crate::dom::webglbuffer::WebGLBuffer;
|
||||
use crate::dom::webglframebuffer::{WebGLFramebuffer, WebGLFramebufferAttachmentRoot};
|
||||
|
@ -838,6 +840,55 @@ impl WebGL2RenderingContext {
|
|||
self.base
|
||||
.send_command(WebGLCommand::VertexAttribU(index, x, y, z, w));
|
||||
}
|
||||
|
||||
fn tex_storage(
|
||||
&self,
|
||||
dimensions: u8,
|
||||
target: u32,
|
||||
levels: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
) {
|
||||
let expected_dimensions = match target {
|
||||
constants::TEXTURE_2D | constants::TEXTURE_CUBE_MAP => 2,
|
||||
constants::TEXTURE_3D | constants::TEXTURE_2D_ARRAY => 3,
|
||||
_ => return self.base.webgl_error(InvalidEnum),
|
||||
};
|
||||
if dimensions != expected_dimensions {
|
||||
return self.base.webgl_error(InvalidEnum);
|
||||
}
|
||||
|
||||
let validator = TexStorageValidator::new(
|
||||
&self.base,
|
||||
dimensions,
|
||||
target,
|
||||
levels,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
);
|
||||
let TexStorageValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
levels,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
} = match validator.validate() {
|
||||
Ok(result) => result,
|
||||
Err(_) => return, // NB: The validator sets the correct error for us.
|
||||
};
|
||||
|
||||
handle_potential_webgl_error!(
|
||||
self.base,
|
||||
texture.storage(target, levels, internal_format, width, height, depth),
|
||||
return
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
|
||||
|
@ -4138,6 +4189,31 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
|
|||
self.base.send_command(WebGLCommand::DrawBuffers(buffers));
|
||||
}
|
||||
}
|
||||
|
||||
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
|
||||
fn TexStorage2D(
|
||||
&self,
|
||||
target: u32,
|
||||
levels: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) {
|
||||
self.tex_storage(2, target, levels, internal_format, width, height, 1)
|
||||
}
|
||||
|
||||
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
|
||||
fn TexStorage3D(
|
||||
&self,
|
||||
target: u32,
|
||||
levels: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
) {
|
||||
self.tex_storage(3, target, levels, internal_format, width, height, depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
|||
use crate::dom::webgltexture::{ImageInfo, WebGLTexture};
|
||||
use crate::dom::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use canvas_traits::webgl::{TexDataType, TexFormat, WebGLError::*};
|
||||
use std::{self, fmt};
|
||||
use std::{self, cmp, fmt};
|
||||
|
||||
/// The errors that the texImage* family of functions can generate.
|
||||
#[derive(Debug)]
|
||||
|
@ -24,6 +24,10 @@ pub enum TexImageValidationError {
|
|||
NegativeLevel,
|
||||
/// A level too high to be allowed by the implementation was passed.
|
||||
LevelTooHigh,
|
||||
/// A level less than an allowed minimal value was passed.
|
||||
LevelTooLow,
|
||||
/// A depth less than an allowed minimal value was passed.
|
||||
DepthTooLow,
|
||||
/// A negative width and height was passed.
|
||||
NegativeDimension,
|
||||
/// A bigger with and height were passed than what the implementation
|
||||
|
@ -60,6 +64,8 @@ impl fmt::Display for TexImageValidationError {
|
|||
},
|
||||
NegativeLevel => "A negative level was passed",
|
||||
LevelTooHigh => "Level too high",
|
||||
LevelTooLow => "Level too low",
|
||||
DepthTooLow => "Depth too low",
|
||||
NegativeDimension => "Negative dimensions were passed",
|
||||
TextureTooBig => "Dimensions given are too big",
|
||||
InvalidDataType => "Invalid data type",
|
||||
|
@ -108,8 +114,8 @@ impl<'a> WebGLValidator for CommonTexImage2DValidator<'a> {
|
|||
// GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
// GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
|
||||
let target = match TexImageTarget::from_gl_constant(self.target) {
|
||||
Some(target) => target,
|
||||
None => {
|
||||
Some(target) if target.dimensions() == 2 => target,
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureTarget(self.target));
|
||||
},
|
||||
|
@ -140,8 +146,13 @@ impl<'a> WebGLValidator for CommonTexImage2DValidator<'a> {
|
|||
// GL_INVALID_ENUM is generated if internal_format is not an accepted
|
||||
// format.
|
||||
let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
|
||||
Some(format) => format,
|
||||
None => {
|
||||
Some(format)
|
||||
if format.required_webgl_version() <= self.context.webgl_version() &&
|
||||
format.usable_as_internal() =>
|
||||
{
|
||||
format
|
||||
},
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
|
@ -278,6 +289,7 @@ pub struct TexImage2DValidatorResult {
|
|||
pub border: u32,
|
||||
pub texture: DomRoot<WebGLTexture>,
|
||||
pub target: TexImageTarget,
|
||||
pub internal_format: TexFormat,
|
||||
pub format: TexFormat,
|
||||
pub data_type: TexDataType,
|
||||
}
|
||||
|
@ -303,16 +315,18 @@ impl<'a> WebGLValidator for TexImage2DValidator<'a> {
|
|||
// GL_INVALID_ENUM is generated if format or data_type is not an
|
||||
// accepted value.
|
||||
let data_type = match TexDataType::from_gl_constant(self.data_type) {
|
||||
Some(data_type) => data_type,
|
||||
None => {
|
||||
Some(data_type) if data_type.required_webgl_version() <= context.webgl_version() => {
|
||||
data_type
|
||||
},
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidDataType);
|
||||
},
|
||||
};
|
||||
|
||||
let format = match TexFormat::from_gl_constant(self.format) {
|
||||
Some(format) => format,
|
||||
None => {
|
||||
Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
|
@ -320,11 +334,16 @@ impl<'a> WebGLValidator for TexImage2DValidator<'a> {
|
|||
|
||||
// GL_INVALID_OPERATION is generated if format does not match
|
||||
// internal_format.
|
||||
if format != internal_format {
|
||||
if format != internal_format.to_unsized() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
// NOTE: In WebGL2 data type check should be done based on the internal
|
||||
// format, but in some functions this validator is called with the
|
||||
// regular unsized format as parameter (eg. TexSubImage2D). For now
|
||||
// it's left here to avoid duplication.
|
||||
//
|
||||
// GL_INVALID_OPERATION is generated if type is
|
||||
// GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 and format is
|
||||
// not GL_RGBA.
|
||||
|
@ -352,6 +371,7 @@ impl<'a> WebGLValidator for TexImage2DValidator<'a> {
|
|||
border: border,
|
||||
texture: texture,
|
||||
target: target,
|
||||
internal_format: internal_format,
|
||||
format: format,
|
||||
data_type: data_type,
|
||||
})
|
||||
|
@ -657,3 +677,113 @@ impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TexStorageValidator<'a> {
|
||||
common_validator: CommonTexImage2DValidator<'a>,
|
||||
dimensions: u8,
|
||||
depth: i32,
|
||||
}
|
||||
|
||||
pub struct TexStorageValidatorResult {
|
||||
pub texture: DomRoot<WebGLTexture>,
|
||||
pub target: TexImageTarget,
|
||||
pub levels: u32,
|
||||
pub internal_format: TexFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub depth: u32,
|
||||
}
|
||||
|
||||
impl<'a> TexStorageValidator<'a> {
|
||||
pub fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
dimensions: u8,
|
||||
target: u32,
|
||||
levels: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
) -> Self {
|
||||
TexStorageValidator {
|
||||
common_validator: CommonTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
levels,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
),
|
||||
dimensions,
|
||||
depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WebGLValidator for TexStorageValidator<'a> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = TexStorageValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.common_validator.context;
|
||||
let CommonTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border: _,
|
||||
} = self.common_validator.validate()?;
|
||||
|
||||
if self.depth < 1 {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::DepthTooLow);
|
||||
}
|
||||
if level < 1 {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::LevelTooLow);
|
||||
}
|
||||
|
||||
let dimensions_valid = match target {
|
||||
TexImageTarget::Texture2D | TexImageTarget::CubeMap => self.dimensions == 2,
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => self.dimensions == 3,
|
||||
_ => false,
|
||||
};
|
||||
if !dimensions_valid {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureTarget(
|
||||
target.as_gl_constant(),
|
||||
));
|
||||
}
|
||||
|
||||
if !internal_format.is_sized() {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
}
|
||||
|
||||
let max_level = log2(cmp::max(width, height) as u32) + 1;
|
||||
if level > max_level {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::LevelTooHigh);
|
||||
}
|
||||
|
||||
if texture.target().is_none() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureTargetNotBound(
|
||||
target.as_gl_constant(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(TexStorageValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
levels: level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth: self.depth as u32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,21 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use canvas_traits::gl_enums;
|
||||
|
||||
gl_enums! {
|
||||
pub enum TexImageTarget {
|
||||
Texture2D = WebGLRenderingContextConstants::TEXTURE_2D,
|
||||
CubeMapPositiveX = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
CubeMapNegativeX = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
CubeMapPositiveY = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
CubeMapNegativeY = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
CubeMapPositiveZ = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
CubeMapNegativeZ = WebGLRenderingContextConstants::TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
Texture2D = constants::TEXTURE_2D,
|
||||
Texture2DArray = constants::TEXTURE_2D_ARRAY,
|
||||
Texture3D = constants::TEXTURE_3D,
|
||||
CubeMap = constants::TEXTURE_CUBE_MAP,
|
||||
CubeMapPositiveX = constants::TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
CubeMapNegativeX = constants::TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
CubeMapPositiveY = constants::TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
CubeMapNegativeY = constants::TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
CubeMapPositiveZ = constants::TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
CubeMapNegativeZ = constants::TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,4 +27,11 @@ impl TexImageTarget {
|
|||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dimensions(self) -> u8 {
|
||||
match self {
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => 3,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
|
|||
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::TexImageSource;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
|
@ -353,7 +354,7 @@ impl WebGLRenderingContext {
|
|||
// Send a command to re-bind the TEXTURE_2D, if any.
|
||||
if let Some(texture) = self
|
||||
.textures
|
||||
.active_texture_slot(constants::TEXTURE_2D)
|
||||
.active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
|
||||
.unwrap()
|
||||
.get()
|
||||
{
|
||||
|
@ -477,8 +478,12 @@ impl WebGLRenderingContext {
|
|||
}
|
||||
|
||||
fn tex_parameter(&self, target: u32, param: u32, value: TexParameterValue) {
|
||||
let texture_slot =
|
||||
handle_potential_webgl_error!(self, self.textures.active_texture_slot(target), return);
|
||||
let texture_slot = handle_potential_webgl_error!(
|
||||
self,
|
||||
self.textures
|
||||
.active_texture_slot(target, self.webgl_version()),
|
||||
return
|
||||
);
|
||||
let texture =
|
||||
handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
|
||||
|
||||
|
@ -567,7 +572,7 @@ impl WebGLRenderingContext {
|
|||
texture: &WebGLTexture,
|
||||
target: TexImageTarget,
|
||||
level: u32,
|
||||
format: TexFormat,
|
||||
internal_format: TexFormat,
|
||||
size: Size2D<u32>,
|
||||
data_type: TexDataType,
|
||||
) -> bool {
|
||||
|
@ -595,7 +600,8 @@ impl WebGLRenderingContext {
|
|||
texture,
|
||||
target,
|
||||
data_type,
|
||||
format,
|
||||
internal_format,
|
||||
internal_format.to_unsized(),
|
||||
level,
|
||||
0,
|
||||
1,
|
||||
|
@ -707,12 +713,16 @@ impl WebGLRenderingContext {
|
|||
// or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied.
|
||||
// or FLOAT, a Float32Array must be supplied.
|
||||
// If the types do not match, an INVALID_OPERATION error is generated.
|
||||
let is_webgl2 = self.webgl_version() == WebGLVersion::WebGL2;
|
||||
let received_size = match *data {
|
||||
None => element_size,
|
||||
Some(ref buffer) => match buffer.get_array_type() {
|
||||
Type::Uint8 => 1,
|
||||
Type::Uint16 => 2,
|
||||
Type::Float32 => 4,
|
||||
Type::Int8 if is_webgl2 => 1,
|
||||
Type::Int16 if is_webgl2 => 2,
|
||||
Type::Int32 | Type::Uint32 if is_webgl2 => 4,
|
||||
_ => {
|
||||
self.webgl_error(InvalidOperation);
|
||||
return Err(());
|
||||
|
@ -744,6 +754,7 @@ impl WebGLRenderingContext {
|
|||
texture: &WebGLTexture,
|
||||
target: TexImageTarget,
|
||||
data_type: TexDataType,
|
||||
internal_format: TexFormat,
|
||||
format: TexFormat,
|
||||
level: u32,
|
||||
_border: u32,
|
||||
|
@ -779,9 +790,6 @@ impl WebGLRenderingContext {
|
|||
YAxisTreatment::AsIs
|
||||
};
|
||||
|
||||
let effective_internal_format = self
|
||||
.extension_manager
|
||||
.get_effective_tex_internal_format(format.as_gl_constant(), data_type.as_gl_constant());
|
||||
let effective_data_type = self
|
||||
.extension_manager
|
||||
.effective_type(data_type.as_gl_constant());
|
||||
|
@ -790,7 +798,7 @@ impl WebGLRenderingContext {
|
|||
self.send_command(WebGLCommand::TexImage2D {
|
||||
target: target.as_gl_constant(),
|
||||
level,
|
||||
effective_internal_format,
|
||||
internal_format,
|
||||
size: pixels.size,
|
||||
format,
|
||||
data_type,
|
||||
|
@ -837,11 +845,19 @@ impl WebGLRenderingContext {
|
|||
return self.webgl_error(InvalidValue);
|
||||
}
|
||||
|
||||
// NB: format and internal_format must match.
|
||||
if format != image_info.internal_format() || data_type != image_info.data_type().unwrap() {
|
||||
// The unsized format must be compatible with the sized internal format
|
||||
debug_assert!(!format.is_sized());
|
||||
if format != image_info.internal_format().to_unsized() {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
|
||||
// See https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.6
|
||||
if self.webgl_version() == WebGLVersion::WebGL1 {
|
||||
if data_type != image_info.data_type().unwrap() {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
}
|
||||
|
||||
let settings = self.texture_unpacking_settings.get();
|
||||
let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
|
||||
|
||||
|
@ -1572,6 +1588,10 @@ impl WebGLRenderingContext {
|
|||
Err(_) => return,
|
||||
};
|
||||
|
||||
if texture.is_immutable() {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
|
||||
let size = Size2D::new(width, height);
|
||||
let buff = IpcSharedMemory::from_bytes(data);
|
||||
let pixels = TexPixels::from_array(buff, size);
|
||||
|
@ -1987,7 +2007,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
constants::TEXTURE_BINDING_2D => unsafe {
|
||||
let texture = self
|
||||
.textures
|
||||
.active_texture_slot(constants::TEXTURE_2D)
|
||||
.active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
|
||||
.unwrap()
|
||||
.get();
|
||||
return optional_root_object_to_js_or_null!(*cx, texture);
|
||||
|
@ -1995,7 +2015,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
constants::TEXTURE_BINDING_CUBE_MAP => unsafe {
|
||||
let texture = self
|
||||
.textures
|
||||
.active_texture_slot(constants::TEXTURE_CUBE_MAP)
|
||||
.active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version())
|
||||
.unwrap()
|
||||
.get();
|
||||
return optional_root_object_to_js_or_null!(*cx, texture);
|
||||
|
@ -2182,7 +2202,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
fn GetTexParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal {
|
||||
let texture_slot = handle_potential_webgl_error!(
|
||||
self,
|
||||
self.textures.active_texture_slot(target),
|
||||
self.textures
|
||||
.active_texture_slot(target, self.webgl_version()),
|
||||
return NullValue()
|
||||
);
|
||||
let texture = handle_potential_webgl_error!(
|
||||
|
@ -2205,8 +2226,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
_ => {},
|
||||
}
|
||||
|
||||
match handle_potential_webgl_error!(self, TexParameter::from_u32(pname), return NullValue())
|
||||
{
|
||||
let texparam =
|
||||
handle_potential_webgl_error!(self, TexParameter::from_u32(pname), return NullValue());
|
||||
if self.webgl_version() < texparam.required_webgl_version() {
|
||||
self.webgl_error(InvalidEnum);
|
||||
return NullValue();
|
||||
}
|
||||
match texparam {
|
||||
TexParameter::Float(param) => {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender));
|
||||
|
@ -2431,8 +2457,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
|
||||
}
|
||||
|
||||
let texture_slot =
|
||||
handle_potential_webgl_error!(self, self.textures.active_texture_slot(target), return);
|
||||
let texture_slot = handle_potential_webgl_error!(
|
||||
self,
|
||||
self.textures
|
||||
.active_texture_slot(target, self.webgl_version()),
|
||||
return
|
||||
);
|
||||
|
||||
if let Some(texture) = texture {
|
||||
handle_potential_webgl_error!(self, texture.bind(target), return);
|
||||
|
@ -2444,8 +2474,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
fn GenerateMipmap(&self, target: u32) {
|
||||
let texture_slot =
|
||||
handle_potential_webgl_error!(self, self.textures.active_texture_slot(target), return);
|
||||
let texture_slot = handle_potential_webgl_error!(
|
||||
self,
|
||||
self.textures
|
||||
.active_texture_slot(target, self.webgl_version()),
|
||||
return
|
||||
);
|
||||
let texture =
|
||||
handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
|
||||
handle_potential_webgl_error!(self, texture.generate_mipmap());
|
||||
|
@ -2543,6 +2577,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
Err(_) => return,
|
||||
};
|
||||
|
||||
if texture.is_immutable() {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
|
||||
let framebuffer_format = match self.bound_draw_framebuffer.get() {
|
||||
Some(fb) => match fb.attachment(constants::COLOR_ATTACHMENT0) {
|
||||
Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => {
|
||||
|
@ -4203,6 +4241,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
height,
|
||||
level,
|
||||
border,
|
||||
internal_format,
|
||||
format,
|
||||
data_type,
|
||||
} = match validator.validate() {
|
||||
|
@ -4210,6 +4249,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
||||
};
|
||||
|
||||
if !internal_format.compatible_data_types().contains(&data_type) {
|
||||
return Ok(self.webgl_error(InvalidOperation));
|
||||
}
|
||||
if texture.is_immutable() {
|
||||
return Ok(self.webgl_error(InvalidOperation));
|
||||
}
|
||||
|
||||
let unpacking_alignment = self.texture_unpacking_alignment.get();
|
||||
|
||||
let expected_byte_length = match {
|
||||
|
@ -4245,7 +4291,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
|
||||
let size = Size2D::new(width, height);
|
||||
|
||||
if !self.validate_filterable_texture(&texture, target, level, format, size, data_type) {
|
||||
if !self.validate_filterable_texture(
|
||||
&texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
size,
|
||||
data_type,
|
||||
) {
|
||||
// FIXME(nox): What is the spec for this? No error is emitted ever
|
||||
// by validate_filterable_texture.
|
||||
return Ok(());
|
||||
|
@ -4255,6 +4308,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
&texture,
|
||||
target,
|
||||
data_type,
|
||||
internal_format,
|
||||
format,
|
||||
level,
|
||||
border,
|
||||
|
@ -4301,6 +4355,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
target,
|
||||
level,
|
||||
border,
|
||||
internal_format,
|
||||
format,
|
||||
data_type,
|
||||
..
|
||||
|
@ -4309,11 +4364,18 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
Err(_) => return Ok(()), // NB: The validator sets the correct error for us.
|
||||
};
|
||||
|
||||
if !internal_format.compatible_data_types().contains(&data_type) {
|
||||
return Ok(self.webgl_error(InvalidOperation));
|
||||
}
|
||||
if texture.is_immutable() {
|
||||
return Ok(self.webgl_error(InvalidOperation));
|
||||
}
|
||||
|
||||
if !self.validate_filterable_texture(
|
||||
&texture,
|
||||
target,
|
||||
level,
|
||||
format,
|
||||
internal_format,
|
||||
pixels.size,
|
||||
data_type,
|
||||
) {
|
||||
|
@ -4323,7 +4385,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
|
||||
self.tex_image_2d(
|
||||
&texture, target, data_type, format, level, border, 1, pixels,
|
||||
&texture,
|
||||
target,
|
||||
data_type,
|
||||
internal_format,
|
||||
format,
|
||||
level,
|
||||
border,
|
||||
1,
|
||||
pixels,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4354,7 +4424,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
let texture = handle_potential_webgl_error!(
|
||||
self,
|
||||
self.textures
|
||||
.active_texture_slot(constants::TEXTURE_2D)
|
||||
.active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
|
||||
.unwrap()
|
||||
.get()
|
||||
.ok_or(InvalidOperation),
|
||||
|
@ -4721,11 +4791,20 @@ impl Textures {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn active_texture_slot(&self, target: u32) -> WebGLResult<&MutNullableDom<WebGLTexture>> {
|
||||
pub fn active_texture_slot(
|
||||
&self,
|
||||
target: u32,
|
||||
webgl_version: WebGLVersion,
|
||||
) -> WebGLResult<&MutNullableDom<WebGLTexture>> {
|
||||
let active_unit = self.active_unit();
|
||||
let is_webgl2 = webgl_version == WebGLVersion::WebGL2;
|
||||
match target {
|
||||
constants::TEXTURE_2D => Ok(&active_unit.tex_2d),
|
||||
constants::TEXTURE_CUBE_MAP => Ok(&active_unit.tex_cube_map),
|
||||
WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY if is_webgl2 => {
|
||||
Ok(&active_unit.tex_2d_array)
|
||||
},
|
||||
WebGL2RenderingContextConstants::TEXTURE_3D if is_webgl2 => Ok(&active_unit.tex_3d),
|
||||
_ => Err(InvalidEnum),
|
||||
}
|
||||
}
|
||||
|
@ -4737,6 +4816,9 @@ impl Textures {
|
|||
let active_unit = self.active_unit();
|
||||
match target {
|
||||
TexImageTarget::Texture2D => active_unit.tex_2d.get(),
|
||||
TexImageTarget::Texture2DArray => active_unit.tex_2d_array.get(),
|
||||
TexImageTarget::Texture3D => active_unit.tex_3d.get(),
|
||||
TexImageTarget::CubeMap |
|
||||
TexImageTarget::CubeMapPositiveX |
|
||||
TexImageTarget::CubeMapNegativeX |
|
||||
TexImageTarget::CubeMapPositiveY |
|
||||
|
@ -4763,6 +4845,8 @@ impl Textures {
|
|||
struct TextureUnit {
|
||||
tex_2d: MutNullableDom<WebGLTexture>,
|
||||
tex_cube_map: MutNullableDom<WebGLTexture>,
|
||||
tex_2d_array: MutNullableDom<WebGLTexture>,
|
||||
tex_3d: MutNullableDom<WebGLTexture>,
|
||||
}
|
||||
|
||||
impl TextureUnit {
|
||||
|
@ -4770,6 +4854,11 @@ impl TextureUnit {
|
|||
let fields = [
|
||||
(&self.tex_2d, constants::TEXTURE_2D),
|
||||
(&self.tex_cube_map, constants::TEXTURE_CUBE_MAP),
|
||||
(
|
||||
&self.tex_2d_array,
|
||||
WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
|
||||
),
|
||||
(&self.tex_3d, WebGL2RenderingContextConstants::TEXTURE_3D),
|
||||
];
|
||||
for &(slot, target) in &fields {
|
||||
if slot.get().map_or(false, |t| texture == &*t) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
|
@ -37,6 +37,7 @@ pub struct WebGLTexture {
|
|||
/// The target to which this texture was bound the first time
|
||||
target: Cell<Option<u32>>,
|
||||
is_deleted: Cell<bool>,
|
||||
is_immutable: Cell<bool>,
|
||||
/// Stores information about mipmap levels and cubemap faces.
|
||||
#[ignore_malloc_size_of = "Arrays are cumbersome"]
|
||||
image_info_array: DomRefCell<[Option<ImageInfo>; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
|
||||
|
@ -59,6 +60,7 @@ impl WebGLTexture {
|
|||
id: id,
|
||||
target: Cell::new(None),
|
||||
is_deleted: Cell::new(false),
|
||||
is_immutable: Cell::new(false),
|
||||
face_count: Cell::new(0),
|
||||
base_mipmap_level: 0,
|
||||
min_filter: Cell::new(constants::NEAREST_MIPMAP_LINEAR),
|
||||
|
@ -221,6 +223,10 @@ impl WebGLTexture {
|
|||
self.is_deleted.get()
|
||||
}
|
||||
|
||||
pub fn is_immutable(&self) -> bool {
|
||||
self.is_immutable.get()
|
||||
}
|
||||
|
||||
pub fn target(&self) -> Option<u32> {
|
||||
self.target.get()
|
||||
}
|
||||
|
@ -366,13 +372,13 @@ impl WebGLTexture {
|
|||
|
||||
fn face_index_for_target(&self, target: &TexImageTarget) -> u8 {
|
||||
match *target {
|
||||
TexImageTarget::Texture2D => 0,
|
||||
TexImageTarget::CubeMapPositiveX => 0,
|
||||
TexImageTarget::CubeMapNegativeX => 1,
|
||||
TexImageTarget::CubeMapPositiveY => 2,
|
||||
TexImageTarget::CubeMapNegativeY => 3,
|
||||
TexImageTarget::CubeMapPositiveZ => 4,
|
||||
TexImageTarget::CubeMapNegativeZ => 5,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,6 +421,58 @@ impl WebGLTexture {
|
|||
pub fn detach_from_framebuffer(&self) {
|
||||
self.attached_framebuffer.set(None);
|
||||
}
|
||||
|
||||
pub fn storage(
|
||||
&self,
|
||||
target: TexImageTarget,
|
||||
levels: u32,
|
||||
internal_format: TexFormat,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
) -> WebGLResult<()> {
|
||||
// Handled by the caller
|
||||
assert!(!self.is_immutable());
|
||||
assert!(self.target().is_some());
|
||||
|
||||
let target_id = target.as_gl_constant();
|
||||
let command = match target {
|
||||
TexImageTarget::Texture2D | TexImageTarget::CubeMap => {
|
||||
WebGLCommand::TexStorage2D(target_id, levels, internal_format, width, height)
|
||||
},
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => {
|
||||
WebGLCommand::TexStorage3D(target_id, levels, internal_format, width, height, depth)
|
||||
},
|
||||
_ => unreachable!(), // handled by the caller
|
||||
};
|
||||
self.upcast::<WebGLObject>().context().send_command(command);
|
||||
|
||||
let mut width = width;
|
||||
let mut height = height;
|
||||
let mut depth = depth;
|
||||
for level in 0..levels {
|
||||
let image_info = ImageInfo {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
internal_format,
|
||||
data_type: None,
|
||||
};
|
||||
self.set_image_infos_at_level(level, image_info);
|
||||
|
||||
width = cmp::max(1, width / 2);
|
||||
height = cmp::max(1, height / 2);
|
||||
depth = cmp::max(1, depth / 2);
|
||||
}
|
||||
|
||||
self.is_immutable.set(true);
|
||||
|
||||
if let Some(fb) = self.attached_framebuffer.get() {
|
||||
fb.update_status();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLTexture {
|
||||
|
|
|
@ -310,10 +310,10 @@ interface mixin WebGL2RenderingContextBase
|
|||
GLsizei width, GLsizei height);
|
||||
|
||||
/* Texture objects */
|
||||
// void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
||||
// GLsizei height);
|
||||
// void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
||||
// GLsizei height, GLsizei depth);
|
||||
void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
||||
GLsizei height);
|
||||
void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLsizei depth);
|
||||
|
||||
//[Throws]
|
||||
//void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue