Skip to content

Commit

Permalink
Implement WebGL Backend
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Jul 19, 2021
1 parent 1090110 commit d5aab51
Show file tree
Hide file tree
Showing 16 changed files with 583 additions and 85 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions wgpu-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ license = "MIT OR Apache-2.0"

[features]
default = []
# Enable WebGL support for WASM builds
webgl = ["hal/gles"]
# Enable API tracing
trace = ["ron", "serde", "wgt/trace", "arrayvec/serde", "naga/serialize"]
# Enable API replaying
Expand Down
5 changes: 4 additions & 1 deletion wgpu-core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ fn main() {
metal: { all(not(wasm), apple) },
dx12: { all(not(wasm), windows) },
dx11: { all(false, not(wasm), windows) },
gl: { all(not(wasm), unix_wo_apple) },
gl: { any(
all(not(wasm), unix_wo_apple),
all(wasm, feature = "webgl")
) },
}
}
4 changes: 4 additions & 0 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4406,6 +4406,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
{
self.poll_devices::<hal::api::Dx11>(force_wait, &mut callbacks)?;
}
#[cfg(gl)]
{
self.poll_devices::<hal::api::Gles>(force_wait, &mut callbacks)?;
}

fire_map_callbacks(callbacks);

Expand Down
5 changes: 4 additions & 1 deletion wgpu-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,10 @@ macro_rules! gfx_select {
wgt::Backend::Dx12 => $global.$method::<$crate::api::Dx12>( $($param),* ),
//#[cfg(all(not(target_arch = "wasm32"), windows))]
//wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), unix, not(any(target_os = "ios", target_os = "macos"))))]
#[cfg(any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
all(target_arch = "wasm32", feature = "webgl")
))]
wgt::Backend::Gl => $global.$method::<$crate::api::Gles>( $($param),+ ),
other => panic!("Unexpected backend {:?}", other),

Expand Down
5 changes: 5 additions & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], option
#Note: it's only unused on Apple platforms
libloading = { version = "0.7", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }
web-sys = { version = "0.3", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext"] }
js-sys = { version = "0.3" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] }

Expand Down
83 changes: 66 additions & 17 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,25 +174,42 @@ impl super::Adapter {

let shading_language_version = {
let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION);
log::info!("SL version: {}", sl_version);
log::warn!("SL version: {}", sl_version);
let (sl_major, sl_minor) = Self::parse_version(&sl_version).ok()?;
let value = sl_major as u16 * 100 + sl_minor as u16 * 10;
naga::back::glsl::Version::Embedded(value)
};

let vertex_shader_storage_blocks =
gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) as u32;
let fragment_shader_storage_blocks =
gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS) as u32;
let vertex_shader_storage_blocks = if cfg!(target_arch = "wasm32") {
// TODO: find out actual value
0
} else {
gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) as u32
};
let fragment_shader_storage_blocks = if cfg!(target_arch = "wasm32") {
// TODO: find out actual value
0
} else {
gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS) as u32
};

let vertex_shader_storage_textures =
gl.get_parameter_i32(glow::MAX_VERTEX_IMAGE_UNIFORMS) as u32;
let fragment_shader_storage_textures =
gl.get_parameter_i32(glow::MAX_FRAGMENT_IMAGE_UNIFORMS) as u32;
let vertex_shader_storage_textures = if cfg!(target_arch = "wasm32") {
// TODO: find out actual value
8
} else {
gl.get_parameter_i32(glow::MAX_VERTEX_IMAGE_UNIFORMS) as u32
};
let fragment_shader_storage_textures = if cfg!(target_arch = "wasm32") {
8
} else {
gl.get_parameter_i32(glow::MAX_FRAGMENT_IMAGE_UNIFORMS) as u32
};

// WORKAROUND:
// In order to work around an issue with GL on RPI4 and similar, we ignore a zero vertex ssbo count if there are vertex sstos. (more info: https://github.com/gfx-rs/wgpu/pull/1607#issuecomment-874938961)
// The hardware does not want us to write to these SSBOs, but GLES cannot express that. We detect this case and disable writing to SSBOs.
// WORKAROUND: In order to work around an issue with GL on RPI4 and similar, we ignore a
// zero vertex ssbo count if there are vertex sstos. (more info:
// https://github.com/gfx-rs/wgpu/pull/1607#issuecomment-874938961) The hardware does not
// want us to write to these SSBOs, but GLES cannot express that. We detect this case and
// disable writing to SSBOs.
let vertex_ssbo_false_zero =
vertex_shader_storage_blocks == 0 && vertex_shader_storage_textures != 0;

Expand Down Expand Up @@ -249,14 +266,29 @@ impl super::Adapter {
gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS)
.min(gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS)) as u32;

let max_vertex_buffer_array_stride = if cfg!(target_arch = "wasm32") {
255 // https://www.khronos.org/registry/webgl/specs/latest/1.0/index.html#VERTEX_STRIDE
} else {
gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) as u32
};

let max_vertex_buffers = if cfg!(target_arch = "wasm32") {
// TODO: Not sure what the max vertex buffer count is for WebGL
8
} else {
gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32
};

let limits = wgt::Limits {
max_texture_dimension_1d: max_texture_size,
max_texture_dimension_2d: max_texture_size,
max_texture_dimension_3d: max_texture_3d_size,
max_texture_array_layers: gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) as u32,
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage,
max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage,
// max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage,
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
// max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage,
max_dynamic_storage_buffers_per_pipeline_layout: 4,
max_sampled_textures_per_shader_stage: super::MAX_TEXTURE_SLOTS as u32,
max_samplers_per_shader_stage: super::MAX_SAMPLERS as u32,
max_storage_buffers_per_shader_stage,
Expand All @@ -270,11 +302,10 @@ impl super::Adapter {
} else {
0
} as u32,
max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32,
max_vertex_buffers,
max_vertex_attributes: (gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32)
.min(super::MAX_VERTEX_ATTRIBUTES as u32),
max_vertex_buffer_array_stride: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE)
as u32,
max_vertex_buffer_array_stride,
max_push_constant_size: 0,
};

Expand All @@ -293,6 +324,15 @@ impl super::Adapter {
ver >= (3, 1),
);

#[cfg(not(target_arch = "wasm32"))]
{
private_caps.set(super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE, true);
private_caps.set(super::PrivateCapabilities::BUFFER_STORAGE, true);
}

#[cfg(target_arch = "wasm32")]
private_caps.set(super::PrivateCapabilities::EMULATE_BUFFER_MAP, true);

let downlevel_defaults = wgt::DownlevelLimits {};

Some(crate::ExposedAdapter {
Expand Down Expand Up @@ -367,6 +407,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
.map_err(|_| crate::DeviceError::OutOfMemory)?,
zero_buffer,
temp_query_results: Vec::new(),
index_buffer: None,
},
})
}
Expand Down Expand Up @@ -465,11 +506,13 @@ impl crate::Adapter<super::Api> for super::Adapter {
formats: if surface.enable_srgb {
vec![
wgt::TextureFormat::Rgba8UnormSrgb,
#[cfg(not(target_arch = "wasm32"))]
wgt::TextureFormat::Bgra8UnormSrgb,
]
} else {
vec![
wgt::TextureFormat::Rgba8Unorm,
#[cfg(not(target_arch = "wasm32"))]
wgt::TextureFormat::Bgra8Unorm,
]
},
Expand All @@ -494,6 +537,12 @@ impl crate::Adapter<super::Api> for super::Adapter {
}
}

// SAFE: Because wasm doesn't have threads
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for super::Adapter {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for super::Adapter {}

#[cfg(test)]
mod tests {
use super::super::Adapter;
Expand Down
6 changes: 2 additions & 4 deletions wgpu-hal/src/gles/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,12 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
) where
T: Iterator<Item = crate::BufferCopy>,
{
//TODO: preserve `src.target` and `dst.target`
// at least for the buffers that require it.
for copy in regions {
self.cmd_buffer.commands.push(C::CopyBufferToBuffer {
src: src.raw,
src_target: glow::COPY_READ_BUFFER,
src_target: src.target,
dst: dst.raw,
dst_target: glow::COPY_WRITE_BUFFER,
dst_target: dst.target,
copy,
})
}
Expand Down
Loading

0 comments on commit d5aab51

Please sign in to comment.