hal/gles: compressed ETC2 texture support

This commit is contained in:
Dzmitry Malyshau 2021-06-30 00:28:10 -04:00 committed by Dzmitry Malyshau
parent 45074b2939
commit 6f13eebb7b
14 changed files with 209 additions and 127 deletions

2
Cargo.lock generated
View File

@ -690,7 +690,7 @@ dependencies = [
[[package]]
name = "glow"
version = "0.10.0"
source = "git+https://github.com/grovesNL/glow?rev=57177a01b1dd91a82ccfd2d7b687fcc36116157c#57177a01b1dd91a82ccfd2d7b687fcc36116157c"
source = "git+https://github.com/grovesNL/glow?rev=0864897a28bbdd43f89f4fd8fdd4ed781b719f8a#0864897a28bbdd43f89f4fd8fdd4ed781b719f8a"
dependencies = [
"js-sys",
"slotmap",

View File

@ -20,6 +20,9 @@ default-members = ["wgpu", "player", "wgpu-hal", "wgpu-info"]
[patch."https://github.com/zakarumych/gpu-alloc"]
#gpu-alloc = { path = "../gpu-alloc/gpu-alloc" }
[patch."https://github.com/grovesNL/glow"]
#glow = { path = "../glow" }
[patch.crates-io]
#web-sys = { path = "../wasm-bindgen/crates/web-sys" }
#js-sys = { path = "../wasm-bindgen/crates/js-sys" }

View File

@ -658,7 +658,7 @@ impl NumericType {
Tf::Bc4RUnorm | Tf::Bc4RSnorm | Tf::EacRUnorm | Tf::EacRSnorm => {
(NumericDimension::Scalar, Sk::Float)
}
Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EtcRgUnorm | Tf::EtcRgSnorm => {
Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EacRgUnorm | Tf::EacRgSnorm => {
(NumericDimension::Vector(Vs::Bi), Sk::Float)
}
Tf::Bc6hRgbUfloat | Tf::Bc6hRgbSfloat | Tf::Etc2RgbUnorm | Tf::Etc2RgbUnormSrgb => {

View File

@ -38,7 +38,7 @@ gpu-descriptor = { version = "0.1", optional = true }
inplace_it = { version ="0.3.3", optional = true }
renderdoc-sys = { version = "0.7.1", optional = true }
# backend: Gles
glow = { git = "https://github.com/grovesNL/glow", rev = "57177a01b1dd91a82ccfd2d7b687fcc36116157c", optional = true }
glow = { git = "https://github.com/grovesNL/glow", rev = "0864897a28bbdd43f89f4fd8fdd4ed781b719f8a", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }

View File

@ -177,7 +177,7 @@ impl super::Adapter {
naga::back::glsl::Version::Embedded(value)
};
let mut features = wgt::Features::empty();
let mut features = wgt::Features::empty() | wgt::Features::TEXTURE_COMPRESSION_ETC2;
features.set(
wgt::Features::DEPTH_CLAMPING,
extensions.contains("GL_EXT_depth_clamp"),
@ -394,8 +394,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tf::Etc2RgbA1UnormSrgb
| Tf::EacRUnorm
| Tf::EacRSnorm
| Tf::EtcRgUnorm
| Tf::EtcRgSnorm
| Tf::EacRgUnorm
| Tf::EacRgSnorm
| Tf::Astc4x4RgbaUnorm
| Tf::Astc4x4RgbaUnormSrgb
| Tf::Astc5x4RgbaUnorm

View File

@ -294,12 +294,6 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
) where
T: Iterator<Item = crate::BufferTextureCopy>,
{
let format_info = dst.format.describe();
assert_eq!(
format_info.block_dimensions,
(1, 1),
"Compressed texture copies are TODO"
);
let (dst_raw, dst_target) = dst.inner.as_native();
for copy in regions {
self.cmd_buffer.commands.push(C::CopyBufferToTexture {
@ -307,11 +301,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
src_target: src.target,
dst: dst_raw,
dst_target,
dst_info: super::TextureCopyInfo {
external_format: dst.format_desc.external,
data_type: dst.format_desc.data_type,
texel_size: format_info.block_size,
},
dst_format: dst.format,
copy,
})
}
@ -326,22 +316,12 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
) where
T: Iterator<Item = crate::BufferTextureCopy>,
{
let format_info = src.format.describe();
assert_eq!(
format_info.block_dimensions,
(1, 1),
"Compressed texture copies are TODO"
);
let (src_raw, src_target) = src.inner.as_native();
for copy in regions {
self.cmd_buffer.commands.push(C::CopyTextureToBuffer {
src: src_raw,
src_target,
src_info: super::TextureCopyInfo {
external_format: src.format_desc.external,
data_type: src.format_desc.data_type,
texel_size: format_info.block_size,
},
src_format: src.format,
dst: dst.raw,
dst_target: dst.target,
copy,

View File

@ -73,16 +73,24 @@ impl super::AdapterShared {
| Tf::Bc6hRgbSfloat
| Tf::Bc6hRgbUfloat
| Tf::Bc7RgbaUnorm
| Tf::Bc7RgbaUnormSrgb
| Tf::Etc2RgbUnorm
| Tf::Etc2RgbUnormSrgb
| Tf::Etc2RgbA1Unorm
| Tf::Etc2RgbA1UnormSrgb
| Tf::EacRUnorm
| Tf::EacRSnorm
| Tf::EtcRgUnorm
| Tf::EtcRgSnorm
| Tf::Astc4x4RgbaUnorm
| Tf::Bc7RgbaUnormSrgb => unimplemented!(),
Tf::Etc2RgbUnorm => (glow::COMPRESSED_RGB8_ETC2, glow::RGB, 0),
Tf::Etc2RgbUnormSrgb => (glow::COMPRESSED_SRGB8_ETC2, glow::RGB, 0),
Tf::Etc2RgbA1Unorm => (
glow::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
glow::RGBA,
0,
),
Tf::Etc2RgbA1UnormSrgb => (
glow::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
glow::RGBA,
0,
),
Tf::EacRUnorm => (glow::COMPRESSED_R11_EAC, glow::RED, 0),
Tf::EacRSnorm => (glow::COMPRESSED_SIGNED_R11_EAC, glow::RED, 0),
Tf::EacRgUnorm => (glow::COMPRESSED_RG11_EAC, glow::RG, 0),
Tf::EacRgSnorm => (glow::COMPRESSED_SIGNED_RG11_EAC, glow::RG, 0),
Tf::Astc4x4RgbaUnorm
| Tf::Astc4x4RgbaUnormSrgb
| Tf::Astc5x4RgbaUnorm
| Tf::Astc5x4RgbaUnormSrgb

View File

@ -418,13 +418,6 @@ impl Fence {
}
}
#[derive(Debug)]
struct TextureCopyInfo {
external_format: u32,
data_type: u32,
texel_size: u8,
}
#[derive(Clone, Debug, PartialEq)]
struct StencilOps {
pass: u32,
@ -535,13 +528,13 @@ enum Command {
src_target: BindTarget,
dst: glow::Texture,
dst_target: BindTarget,
dst_info: TextureCopyInfo,
dst_format: wgt::TextureFormat,
copy: crate::BufferTextureCopy,
},
CopyTextureToBuffer {
src: glow::Texture,
src_target: BindTarget,
src_info: TextureCopyInfo,
src_format: wgt::TextureFormat,
dst: glow::Buffer,
dst_target: BindTarget,
copy: crate::BufferTextureCopy,

View File

@ -254,103 +254,196 @@ impl super::Queue {
src_target: _,
dst,
dst_target,
ref dst_info,
dst_format,
ref copy,
} => {
//TODO: compressed data
let row_texels = copy
let format_info = dst_format.describe();
let format_desc = self.shared.describe_texture_format(dst_format);
let row_texels = copy.buffer_layout.bytes_per_row.map_or(0, |bpr| {
format_info.block_dimensions.0 as u32 * bpr.get()
/ format_info.block_size as u32
});
let column_texels = copy
.buffer_layout
.bytes_per_row
.map_or(0, |bpr| bpr.get() / dst_info.texel_size as u32);
let column_texels = copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get());
.rows_per_image
.map_or(0, |rpi| format_info.block_dimensions.1 as u32 * rpi.get());
gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32);
gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32);
gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(src));
let unpack_data =
glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32);
gl.bind_texture(dst_target, Some(dst));
match dst_target {
glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => {
gl.tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
dst_info.external_format,
dst_info.data_type,
unpack_data,
);
}
glow::TEXTURE_2D => {
gl.tex_sub_image_2d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
dst_info.external_format,
dst_info.data_type,
unpack_data,
);
}
glow::TEXTURE_CUBE_MAP => {
let mut offset = copy.buffer_layout.offset as u32;
for face_index in 0..copy.size.depth_or_array_layers {
if format_info.block_dimensions == (1, 1) {
let unpack_data =
glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32);
match dst_target {
glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => {
gl.tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
format_desc.external,
format_desc.data_type,
unpack_data,
);
}
glow::TEXTURE_2D => {
gl.tex_sub_image_2d(
CUBEMAP_FACES[(copy.texture_base.origin.z + face_index) as usize],
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
dst_info.external_format,
dst_info.data_type,
glow::PixelUnpackData::BufferOffset(offset),
format_desc.external,
format_desc.data_type,
unpack_data,
);
offset += copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get())
* copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get());
}
glow::TEXTURE_CUBE_MAP => {
let mut offset = copy.buffer_layout.offset as u32;
for face_index in 0..copy.size.depth_or_array_layers {
gl.tex_sub_image_2d(
CUBEMAP_FACES
[(copy.texture_base.origin.z + face_index) as usize],
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
glow::PixelUnpackData::BufferOffset(offset),
);
offset += copy
.buffer_layout
.rows_per_image
.map_or(0, |rpi| rpi.get())
* copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get());
}
}
glow::TEXTURE_CUBE_MAP_ARRAY => {
//Note: not sure if this is correct!
gl.tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
format_desc.external,
format_desc.data_type,
unpack_data,
);
}
_ => unreachable!(),
}
glow::TEXTURE_CUBE_MAP_ARRAY => {
//Note: not sure if this is correct!
gl.tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
dst_info.external_format,
dst_info.data_type,
unpack_data,
);
} else {
let bytes_per_image =
copy.buffer_layout.rows_per_image.map_or(1, |rpi| rpi.get())
* copy.buffer_layout.bytes_per_row.map_or(1, |bpr| bpr.get());
let offset_end = copy.buffer_layout.offset as u32
+ bytes_per_image * copy.size.depth_or_array_layers;
let unpack_data = glow::CompressedPixelUnpackData::BufferRange(
copy.buffer_layout.offset as u32..offset_end,
);
match dst_target {
glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => {
gl.compressed_tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
format_desc.internal,
unpack_data,
);
}
glow::TEXTURE_2D => {
gl.compressed_tex_sub_image_2d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.internal,
unpack_data,
);
}
glow::TEXTURE_CUBE_MAP => {
let mut offset = copy.buffer_layout.offset as u32;
for face_index in 0..copy.size.depth_or_array_layers {
gl.compressed_tex_sub_image_2d(
CUBEMAP_FACES
[(copy.texture_base.origin.z + face_index) as usize],
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.internal,
glow::CompressedPixelUnpackData::BufferRange(
offset..offset + bytes_per_image,
),
);
offset += bytes_per_image;
}
}
glow::TEXTURE_CUBE_MAP_ARRAY => {
//Note: not sure if this is correct!
gl.compressed_tex_sub_image_3d(
dst_target,
copy.texture_base.mip_level as i32,
copy.texture_base.origin.x as i32,
copy.texture_base.origin.y as i32,
copy.texture_base.origin.z as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth_or_array_layers as i32,
format_desc.internal,
unpack_data,
);
}
_ => unreachable!(),
}
_ => unreachable!(),
}
}
C::CopyTextureToBuffer {
src,
src_target,
ref src_info,
src_format,
dst,
dst_target: _,
ref copy,
} => {
//TODO: compressed data
//TODO: cubemaps
let format_info = src_format.describe();
if format_info.block_dimensions != (1, 1) {
log::error!("Not implemented yet: compressed texture copy to buffer");
return;
}
if src_target == glow::TEXTURE_CUBE_MAP
|| src_target == glow::TEXTURE_CUBE_MAP_ARRAY
{
log::error!("Not implemented yet: cubemap texture copy to buffer");
return;
}
let format_desc = self.shared.describe_texture_format(src_format);
let row_texels = copy
.buffer_layout
.bytes_per_row
.map_or(copy.size.width, |bpr| {
bpr.get() / src_info.texel_size as u32
bpr.get() / format_info.block_size as u32
});
let column_texels = copy
.buffer_layout
@ -362,7 +455,7 @@ impl super::Queue {
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo));
for layer in 0..copy.size.depth_or_array_layers {
let offset = copy.buffer_layout.offset as u32
+ layer * column_texels * row_texels * src_info.texel_size as u32;
+ layer * column_texels * row_texels * format_info.block_size as u32;
if is_3d_target(src_target) {
//TODO: handle GLES without framebuffer_texture_3d
gl.framebuffer_texture_layer(
@ -386,8 +479,8 @@ impl super::Queue {
copy.texture_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
src_info.external_format,
src_info.data_type,
format_desc.external,
format_desc.data_type,
glow::PixelPackData::BufferOffset(offset),
);
}

View File

@ -215,8 +215,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tf::Etc2RgbA1UnormSrgb
| Tf::EacRUnorm
| Tf::EacRSnorm
| Tf::EtcRgUnorm
| Tf::EtcRgSnorm => {
| Tf::EacRgUnorm
| Tf::EacRgSnorm => {
if pc.format_eac_etc {
Tfc::SAMPLED_LINEAR
} else {
@ -990,8 +990,8 @@ impl super::PrivateCapabilities {
Tf::Etc2RgbA1UnormSrgb => ETC2_RGB8A1_sRGB,
Tf::EacRUnorm => EAC_R11Unorm,
Tf::EacRSnorm => EAC_R11Snorm,
Tf::EtcRgUnorm => EAC_RG11Unorm,
Tf::EtcRgSnorm => EAC_RG11Snorm,
Tf::EacRgUnorm => EAC_RG11Unorm,
Tf::EacRgSnorm => EAC_RG11Snorm,
Tf::Astc4x4RgbaUnorm => ASTC_4x4_LDR,
Tf::Astc4x4RgbaUnormSrgb => ASTC_4x4_sRGB,
Tf::Astc5x4RgbaUnorm => ASTC_5x4_LDR,

View File

@ -665,6 +665,7 @@ impl super::Instance {
alignments: phd_capabilities.to_hal_alignments(),
downlevel: wgt::DownlevelCapabilities {
flags: downlevel_flags,
limits: wgt::DownlevelLimits {},
shader_model: wgt::ShaderModel::Sm5, //TODO?
},
};

View File

@ -76,8 +76,8 @@ impl super::PrivateCapabilities {
Tf::Etc2RgbA1UnormSrgb => F::ETC2_R8G8B8A1_SRGB_BLOCK,
Tf::EacRUnorm => F::EAC_R11_UNORM_BLOCK,
Tf::EacRSnorm => F::EAC_R11_SNORM_BLOCK,
Tf::EtcRgUnorm => F::EAC_R11G11_UNORM_BLOCK,
Tf::EtcRgSnorm => F::EAC_R11G11_SNORM_BLOCK,
Tf::EacRgUnorm => F::EAC_R11G11_UNORM_BLOCK,
Tf::EacRgSnorm => F::EAC_R11G11_SNORM_BLOCK,
Tf::Astc4x4RgbaUnorm => F::ASTC_4X4_UNORM_BLOCK,
Tf::Astc4x4RgbaUnormSrgb => F::ASTC_4X4_SRGB_BLOCK,
Tf::Astc5x4RgbaUnorm => F::ASTC_5X4_UNORM_BLOCK,

View File

@ -1416,12 +1416,12 @@ pub enum TextureFormat {
/// [0, 255] converted to/from float [0, 1] in shader.
///
/// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
EtcRgUnorm = 60,
EacRgUnorm = 60,
/// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer R + 8 bit integer G.
/// [-127, 127] converted to/from float [-1, 1] in shader.
///
/// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
EtcRgSnorm = 61,
EacRgSnorm = 61,
/// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer RGBA.
/// [0, 255] converted to/from float [0, 1] in shader.
///
@ -1670,8 +1670,8 @@ impl TextureFormat {
//Self::Etc2RgbA8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic),
Self::EacRUnorm => (etc2, float, linear, (4, 4), 8, basic),
Self::EacRSnorm => (etc2, float, linear, (4, 4), 8, basic),
Self::EtcRgUnorm => (etc2, float, linear, (4, 4), 16, basic),
Self::EtcRgSnorm => (etc2, float, linear, (4, 4), 16, basic),
Self::EacRgUnorm => (etc2, float, linear, (4, 4), 16, basic),
Self::EacRgSnorm => (etc2, float, linear, (4, 4), 16, basic),
// ASTC compressed textures
Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic),

View File

@ -273,12 +273,16 @@ impl framework::Example for Skybox {
let skybox_format =
if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) {
log::info!("Using ASTC_LDR");
wgpu::TextureFormat::Astc4x4RgbaUnormSrgb
} else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ETC2) {
log::info!("Using ETC2");
wgpu::TextureFormat::Etc2RgbUnormSrgb
} else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_BC) {
log::info!("Using BC");
wgpu::TextureFormat::Bc1RgbaUnormSrgb
} else {
log::info!("Using plain");
wgpu::TextureFormat::Bgra8UnormSrgb
};