mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Add initial support for WebGL compressed textures
This commit is contained in:
parent
a14b952fa3
commit
7f0b820d4e
16 changed files with 792 additions and 37 deletions
|
@ -18,3 +18,5 @@ pub mod oestexturehalffloat;
|
|||
pub mod oestexturehalffloatlinear;
|
||||
pub mod oesvertexarrayobject;
|
||||
pub mod webglcolorbufferfloat;
|
||||
pub mod webglcompressedtextureetc1;
|
||||
pub mod webglcompressedtextures3tc;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::WEBGLCompressedTextureETC1Binding;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use canvas_traits::webgl::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WEBGLCompressedTextureETC1 {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl WEBGLCompressedTextureETC1 {
|
||||
fn new_inherited() -> WEBGLCompressedTextureETC1 {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for WEBGLCompressedTextureETC1 {
|
||||
type Extension = WEBGLCompressedTextureETC1;
|
||||
fn new(ctx: &WebGLRenderingContext) -> DomRoot<WEBGLCompressedTextureETC1> {
|
||||
reflect_dom_object(
|
||||
Box::new(WEBGLCompressedTextureETC1::new_inherited()),
|
||||
&*ctx.global(),
|
||||
WEBGLCompressedTextureETC1Binding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_OES_compressed_ETC1_RGB8_texture")
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.add_tex_compression_formats(&[TexCompression {
|
||||
format: TexFormat::CompressedRgbEtc1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::None,
|
||||
}]);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"WEBGL_compressed_texture_etc1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::WEBGLCompressedTextureS3TCBinding;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use canvas_traits::webgl::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WEBGLCompressedTextureS3TC {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl WEBGLCompressedTextureS3TC {
|
||||
fn new_inherited() -> WEBGLCompressedTextureS3TC {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for WEBGLCompressedTextureS3TC {
|
||||
type Extension = WEBGLCompressedTextureS3TC;
|
||||
fn new(ctx: &WebGLRenderingContext) -> DomRoot<WEBGLCompressedTextureS3TC> {
|
||||
reflect_dom_object(
|
||||
Box::new(WEBGLCompressedTextureS3TC::new_inherited()),
|
||||
&*ctx.global(),
|
||||
WEBGLCompressedTextureS3TCBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_EXT_texture_compression_s3tc") ||
|
||||
ext.supports_all_gl_extension(&[
|
||||
"GL_EXT_texture_compression_dxt1",
|
||||
"GL_ANGLE_texture_compression_dxt3",
|
||||
"GL_ANGLE_texture_compression_dxt5",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.add_tex_compression_formats(&[
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbS3tcDxt1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt3,
|
||||
bytes_per_block: 16,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt5,
|
||||
bytes_per_block: 16,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"WEBGL_compressed_texture_s3tc"
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ use crate::dom::oestexturefloat::OESTextureFloat;
|
|||
use crate::dom::oestexturehalffloat::OESTextureHalfFloat;
|
||||
use crate::dom::webglcolorbufferfloat::WEBGLColorBufferFloat;
|
||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgltexture::TexCompression;
|
||||
use canvas_traits::webgl::WebGLVersion;
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use gleam::gl::{self, GLenum};
|
||||
|
@ -82,6 +83,8 @@ struct WebGLExtensionFeatures {
|
|||
element_index_uint_enabled: bool,
|
||||
/// WebGL EXT_blend_minmax extension.
|
||||
blend_minmax_enabled: bool,
|
||||
/// WebGL supported texture compression formats enabled by extensions.
|
||||
tex_compression_formats: FnvHashMap<GLenum, TexCompression>,
|
||||
}
|
||||
|
||||
impl WebGLExtensionFeatures {
|
||||
|
@ -131,6 +134,7 @@ impl WebGLExtensionFeatures {
|
|||
disabled_get_vertex_attrib_names,
|
||||
element_index_uint_enabled,
|
||||
blend_minmax_enabled,
|
||||
tex_compression_formats: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,6 +229,13 @@ impl WebGLExtensions {
|
|||
.any(|name| features.gl_extensions.contains(*name))
|
||||
}
|
||||
|
||||
pub fn supports_all_gl_extension(&self, names: &[&str]) -> bool {
|
||||
let features = self.features.borrow();
|
||||
names
|
||||
.iter()
|
||||
.all(|name| features.gl_extensions.contains(*name))
|
||||
}
|
||||
|
||||
pub fn enable_tex_type(&self, data_type: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
|
@ -335,6 +346,35 @@ impl WebGLExtensions {
|
|||
.contains(&name)
|
||||
}
|
||||
|
||||
pub fn add_tex_compression_formats(&self, formats: &[TexCompression]) {
|
||||
let formats: FnvHashMap<GLenum, TexCompression> = formats
|
||||
.iter()
|
||||
.map(|&compression| (compression.format.as_gl_constant(), compression))
|
||||
.collect();
|
||||
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.tex_compression_formats
|
||||
.extend(formats.iter());
|
||||
}
|
||||
|
||||
pub fn get_tex_compression_format(&self, format_id: GLenum) -> Option<TexCompression> {
|
||||
self.features
|
||||
.borrow()
|
||||
.tex_compression_formats
|
||||
.get(&format_id)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn get_tex_compression_ids(&self) -> Vec<GLenum> {
|
||||
self.features
|
||||
.borrow()
|
||||
.tex_compression_formats
|
||||
.keys()
|
||||
.map(|&k| k)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn register_all_extensions(&self) {
|
||||
self.register::<ext::angleinstancedarrays::ANGLEInstancedArrays>();
|
||||
self.register::<ext::extblendminmax::EXTBlendMinmax>();
|
||||
|
@ -349,6 +389,8 @@ impl WebGLExtensions {
|
|||
self.register::<ext::oestexturehalffloatlinear::OESTextureHalfFloatLinear>();
|
||||
self.register::<ext::oesvertexarrayobject::OESVertexArrayObject>();
|
||||
self.register::<ext::webglcolorbufferfloat::WEBGLColorBufferFloat>();
|
||||
self.register::<ext::webglcompressedtextureetc1::WEBGLCompressedTextureETC1>();
|
||||
self.register::<ext::webglcompressedtextures3tc::WEBGLCompressedTextureS3TC>();
|
||||
}
|
||||
|
||||
pub fn enable_element_index_uint(&self) {
|
||||
|
|
|
@ -6,7 +6,8 @@ use super::types::TexImageTarget;
|
|||
use super::WebGLValidator;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgltexture::WebGLTexture;
|
||||
use crate::dom::webgltexture::{ImageInfo, WebGLTexture};
|
||||
use crate::dom::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use canvas_traits::webgl::{TexDataType, TexFormat, WebGLError::*};
|
||||
use std::{self, fmt};
|
||||
|
||||
|
@ -40,6 +41,10 @@ pub enum TexImageValidationError {
|
|||
InvalidBorder,
|
||||
/// Expected a power of two texture.
|
||||
NonPotTexture,
|
||||
/// Unrecognized texture compression format.
|
||||
InvalidCompressionFormat,
|
||||
/// Invalid X/Y texture offset parameters.
|
||||
InvalidOffsets,
|
||||
}
|
||||
|
||||
impl std::error::Error for TexImageValidationError {
|
||||
|
@ -61,6 +66,8 @@ impl std::error::Error for TexImageValidationError {
|
|||
InvalidTypeForFormat => "Invalid type for the given format",
|
||||
InvalidBorder => "Invalid border",
|
||||
NonPotTexture => "Expected a power of two texture",
|
||||
InvalidCompressionFormat => "Unrecognized texture compression format",
|
||||
InvalidOffsets => "Invalid X/Y texture offset parameters",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -357,3 +364,303 @@ impl<'a> WebGLValidator for TexImage2DValidator<'a> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommonCompressedTexImage2DValidator<'a> {
|
||||
common_validator: CommonTexImage2DValidator<'a>,
|
||||
data_len: usize,
|
||||
}
|
||||
|
||||
impl<'a> CommonCompressedTexImage2DValidator<'a> {
|
||||
pub fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CommonCompressedTexImage2DValidator {
|
||||
common_validator: CommonTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
compression_format,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
),
|
||||
data_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommonCompressedTexImage2DValidatorResult {
|
||||
pub texture: DomRoot<WebGLTexture>,
|
||||
pub target: TexImageTarget,
|
||||
pub level: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub compression: TexCompression,
|
||||
}
|
||||
|
||||
fn valid_s3tc_dimension(level: u32, side_length: u32, block_size: u32) -> bool {
|
||||
(side_length % block_size == 0) || (level > 0 && [0, 1, 2].contains(&side_length))
|
||||
}
|
||||
|
||||
fn valid_compressed_data_len(
|
||||
data_len: usize,
|
||||
width: u32,
|
||||
height: u32,
|
||||
compression: &TexCompression,
|
||||
) -> bool {
|
||||
let block_width = compression.block_width as u32;
|
||||
let block_height = compression.block_height as u32;
|
||||
|
||||
let required_blocks_hor = (width + block_width - 1) / block_width;
|
||||
let required_blocks_ver = (height + block_height - 1) / block_height;
|
||||
let required_blocks = required_blocks_hor * required_blocks_ver;
|
||||
|
||||
let required_bytes = required_blocks * compression.bytes_per_block as u32;
|
||||
data_len == required_bytes as usize
|
||||
}
|
||||
|
||||
fn is_subimage_blockaligned(
|
||||
xoffset: u32,
|
||||
yoffset: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
compression: &TexCompression,
|
||||
tex_info: &ImageInfo,
|
||||
) -> bool {
|
||||
let block_width = compression.block_width as u32;
|
||||
let block_height = compression.block_height as u32;
|
||||
|
||||
(xoffset % block_width == 0 && yoffset % block_height == 0) &&
|
||||
(width % block_width == 0 || xoffset + width == tex_info.width()) &&
|
||||
(height % block_height == 0 || yoffset + height == tex_info.height())
|
||||
}
|
||||
|
||||
impl<'a> WebGLValidator for CommonCompressedTexImage2DValidator<'a> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
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()?;
|
||||
|
||||
// GL_INVALID_ENUM is generated if internalformat is not a supported
|
||||
// format returned in GL_COMPRESSED_TEXTURE_FORMATS.
|
||||
let compression = context
|
||||
.extension_manager()
|
||||
.get_tex_compression_format(internal_format.as_gl_constant());
|
||||
let compression = match compression {
|
||||
Some(compression) => compression,
|
||||
None => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidCompressionFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_VALUE is generated if imageSize is not consistent with the
|
||||
// format, dimensions, and contents of the specified compressed image data.
|
||||
if !valid_compressed_data_len(self.data_len, width, height, &compression) {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompressedTexImage2DValidator<'a> {
|
||||
compression_validator: CommonCompressedTexImage2DValidator<'a>,
|
||||
}
|
||||
|
||||
impl<'a> CompressedTexImage2DValidator<'a> {
|
||||
pub fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CompressedTexImage2DValidator {
|
||||
compression_validator: CommonCompressedTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
compression_format,
|
||||
data_len,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WebGLValidator for CompressedTexImage2DValidator<'a> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.compression_validator.common_validator.context;
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
} = self.compression_validator.validate()?;
|
||||
|
||||
// GL_INVALID_OPERATION is generated if parameter combinations are not
|
||||
// supported by the specific compressed internal format as specified
|
||||
// in the specific texture compression extension.
|
||||
let compression_valid = match compression.validation {
|
||||
TexCompressionValidation::S3TC => {
|
||||
let valid_width =
|
||||
valid_s3tc_dimension(level, width, compression.block_width as u32);
|
||||
let valid_height =
|
||||
valid_s3tc_dimension(level, height, compression.block_height as u32);
|
||||
valid_width && valid_height
|
||||
},
|
||||
TexCompressionValidation::None => true,
|
||||
};
|
||||
if !compression_valid {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompressedTexSubImage2DValidator<'a> {
|
||||
compression_validator: CommonCompressedTexImage2DValidator<'a>,
|
||||
xoffset: i32,
|
||||
yoffset: i32,
|
||||
}
|
||||
|
||||
impl<'a> CompressedTexSubImage2DValidator<'a> {
|
||||
pub fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
xoffset: i32,
|
||||
yoffset: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CompressedTexSubImage2DValidator {
|
||||
compression_validator: CommonCompressedTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
compression_format,
|
||||
data_len,
|
||||
),
|
||||
xoffset,
|
||||
yoffset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.compression_validator.common_validator.context;
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
} = self.compression_validator.validate()?;
|
||||
|
||||
let tex_info = texture.image_info_for_target(&target, level);
|
||||
|
||||
// GL_INVALID_VALUE is generated if:
|
||||
// - xoffset or yoffset is less than 0
|
||||
// - x offset plus the width is greater than the texture width
|
||||
// - y offset plus the height is greater than the texture height
|
||||
if self.xoffset < 0 ||
|
||||
(self.xoffset as u32 + width) > tex_info.width() ||
|
||||
self.yoffset < 0 ||
|
||||
(self.yoffset as u32 + height) > tex_info.height()
|
||||
{
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::InvalidOffsets);
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if format does not match
|
||||
// internal_format.
|
||||
if compression.format != tex_info.internal_format().unwrap() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if parameter combinations are not
|
||||
// supported by the specific compressed internal format as specified
|
||||
// in the specific texture compression extension.
|
||||
let compression_valid = match compression.validation {
|
||||
TexCompressionValidation::S3TC => is_subimage_blockaligned(
|
||||
self.xoffset as u32,
|
||||
self.yoffset as u32,
|
||||
width,
|
||||
height,
|
||||
&compression,
|
||||
&tex_info,
|
||||
),
|
||||
TexCompressionValidation::None => true,
|
||||
};
|
||||
if !compression_valid {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,10 @@ use crate::dom::htmliframeelement::HTMLIFrameElement;
|
|||
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage};
|
||||
use crate::dom::webgl_extensions::WebGLExtensions;
|
||||
use crate::dom::webgl_validations::tex_image_2d::{
|
||||
CommonTexImage2DValidator, CommonTexImage2DValidatorResult,
|
||||
CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
|
||||
CommonTexImage2DValidatorResult, CompressedTexImage2DValidator,
|
||||
CompressedTexSubImage2DValidator, TexImage2DValidator, TexImage2DValidatorResult,
|
||||
};
|
||||
use crate::dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult};
|
||||
use crate::dom::webgl_validations::types::TexImageTarget;
|
||||
use crate::dom::webgl_validations::WebGLValidator;
|
||||
use crate::dom::webglactiveinfo::WebGLActiveInfo;
|
||||
|
@ -1227,9 +1228,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
return Int32Value(constants::UNSIGNED_BYTE as i32);
|
||||
},
|
||||
constants::COMPRESSED_TEXTURE_FORMATS => {
|
||||
// FIXME(nox): https://github.com/servo/servo/issues/20594
|
||||
let format_ids = self.extension_manager.get_tex_compression_ids();
|
||||
|
||||
rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
|
||||
let _ = Uint32Array::create(cx, CreateWith::Slice(&[]), rval.handle_mut()).unwrap();
|
||||
let _ = Uint32Array::create(cx, CreateWith::Slice(&format_ids), rval.handle_mut())
|
||||
.unwrap();
|
||||
return ObjectValue(rval.get());
|
||||
},
|
||||
constants::VERSION => {
|
||||
|
@ -1756,36 +1759,116 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
#[allow(unsafe_code)]
|
||||
fn CompressedTexImage2D(
|
||||
&self,
|
||||
_target: u32,
|
||||
_level: i32,
|
||||
_internal_format: u32,
|
||||
_width: i32,
|
||||
_height: i32,
|
||||
_border: i32,
|
||||
_data: CustomAutoRooterGuard<ArrayBufferView>,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
data: CustomAutoRooterGuard<ArrayBufferView>,
|
||||
) {
|
||||
// FIXME: No compressed texture format is currently supported, so error out as per
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#COMPRESSED_TEXTURE_SUPPORT
|
||||
self.webgl_error(InvalidEnum);
|
||||
let validator = CompressedTexImage2DValidator::new(
|
||||
self,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
internal_format,
|
||||
data.len(),
|
||||
);
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
} = match validator.validate() {
|
||||
Ok(result) => result,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() });
|
||||
let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
|
||||
|
||||
handle_potential_webgl_error!(
|
||||
self,
|
||||
texture.initialize(
|
||||
target,
|
||||
pixels.size.width,
|
||||
pixels.size.height,
|
||||
1,
|
||||
compression.format,
|
||||
level,
|
||||
Some(TexDataType::UnsignedByte)
|
||||
)
|
||||
);
|
||||
|
||||
self.send_command(WebGLCommand::CompressedTexImage2D {
|
||||
target: target.as_gl_constant(),
|
||||
level,
|
||||
internal_format,
|
||||
size: Size2D::new(width, height),
|
||||
data: pixels.data.into(),
|
||||
});
|
||||
|
||||
if let Some(fb) = self.bound_framebuffer.get() {
|
||||
fb.invalidate_texture(&*texture);
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
#[allow(unsafe_code)]
|
||||
fn CompressedTexSubImage2D(
|
||||
&self,
|
||||
_target: u32,
|
||||
_level: i32,
|
||||
_xoffset: i32,
|
||||
_yoffset: i32,
|
||||
_width: i32,
|
||||
_height: i32,
|
||||
_format: u32,
|
||||
_data: CustomAutoRooterGuard<ArrayBufferView>,
|
||||
target: u32,
|
||||
level: i32,
|
||||
xoffset: i32,
|
||||
yoffset: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: u32,
|
||||
data: CustomAutoRooterGuard<ArrayBufferView>,
|
||||
) {
|
||||
// FIXME: No compressed texture format is currently supported, so error out as per
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#COMPRESSED_TEXTURE_SUPPORT
|
||||
self.webgl_error(InvalidEnum);
|
||||
let validator = CompressedTexSubImage2DValidator::new(
|
||||
self,
|
||||
target,
|
||||
level,
|
||||
xoffset,
|
||||
yoffset,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
data.len(),
|
||||
);
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture: _,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
..
|
||||
} = match validator.validate() {
|
||||
Ok(result) => result,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() });
|
||||
let pixels = TexPixels::from_array(buff, Size2D::new(width, height));
|
||||
|
||||
self.send_command(WebGLCommand::CompressedTexSubImage2D {
|
||||
target: target.as_gl_constant(),
|
||||
level: level as i32,
|
||||
xoffset,
|
||||
yoffset,
|
||||
size: Size2D::new(width, height),
|
||||
format,
|
||||
data: pixels.data.into(),
|
||||
});
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||
|
|
|
@ -470,7 +470,24 @@ impl ImageInfo {
|
|||
}
|
||||
|
||||
fn is_compressed_format(&self) -> bool {
|
||||
// TODO: Once Servo supports compressed formats, check for them here
|
||||
false
|
||||
match self.internal_format {
|
||||
Some(format) => format.is_compressed(),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
|
||||
pub enum TexCompressionValidation {
|
||||
None,
|
||||
S3TC,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
|
||||
pub struct TexCompression {
|
||||
pub format: TexFormat,
|
||||
pub bytes_per_block: u8,
|
||||
pub block_width: u8,
|
||||
pub block_height: u8,
|
||||
pub validation: TexCompressionValidation,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
/*
|
||||
* WebGL IDL definitions from the Khronos specification:
|
||||
* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
|
||||
*/
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface WEBGLCompressedTextureETC1 {
|
||||
/* Compressed Texture Format */
|
||||
const GLenum COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
|
||||
}; // interface WEBGLCompressedTextureETC1
|
|
@ -0,0 +1,16 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
/*
|
||||
* WebGL IDL definitions from the Khronos specification:
|
||||
* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
||||
*/
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface WEBGLCompressedTextureS3TC {
|
||||
/* Compressed Texture Formats */
|
||||
const GLenum COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
||||
const GLenum COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
||||
const GLenum COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
||||
const GLenum COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
||||
}; // interface WEBGLCompressedTextureS3TC
|
Loading…
Add table
Add a link
Reference in a new issue