mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-05-14 03:18:02 +00:00
Add WGL context creation and OpenGL support (#4248)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
parent
ead6348b43
commit
2b985e2fad
@ -44,6 +44,12 @@ Bottom level categories:
|
||||
|
||||
- Update Naga to 9eb3a1dc (2023-10-12), which includes support for WGSL constant expressions. By @jimblandy in [#4233](https://github.com/gfx-rs/wgpu/pull/4233)
|
||||
|
||||
#### Support desktop OpenGL via WGL on Windows
|
||||
|
||||
Added creating of full OpenGL contexts to the GLES backend using WGL to support older devices.
|
||||
|
||||
By @Zoxc in [#4248](https://github.com/gfx-rs/wgpu/pull/4248)
|
||||
|
||||
#### Pass timestamp queries
|
||||
|
||||
Addition of `TimestampWrites` to compute and render passes to allow profiling.
|
||||
|
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -1233,7 +1233,7 @@ dependencies = [
|
||||
"glutin_egl_sys",
|
||||
"glutin_gles2_sys",
|
||||
"glutin_glx_sys",
|
||||
"glutin_wgl_sys",
|
||||
"glutin_wgl_sys 0.1.5",
|
||||
"libloading 0.7.4",
|
||||
"log",
|
||||
"objc",
|
||||
@ -1286,6 +1286,15 @@ dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glutin_wgl_sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef89398e90033fc6bc65e9bd42fd29bbbfd483bda5b56dc5562f455550618165"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-alloc"
|
||||
version = "0.6.0"
|
||||
@ -3353,6 +3362,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"glow",
|
||||
"glutin",
|
||||
"glutin_wgl_sys 0.4.0",
|
||||
"gpu-alloc",
|
||||
"gpu-allocator",
|
||||
"gpu-descriptor",
|
||||
@ -3365,6 +3375,7 @@ dependencies = [
|
||||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
|
17
README.md
17
README.md
@ -70,14 +70,14 @@ We have a [wiki](https://github.com/gfx-rs/wgpu/wiki) that serves as a knowledge
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| API | Windows | Linux & Android | macOS & iOS | Web (wasm) |
|
||||
| --------- | ------------------------------ | ------------------ | ------------------------- | ------------------------- |
|
||||
| Vulkan | :white_check_mark: | :white_check_mark: | :ok: (vulkan-portability) | |
|
||||
| Metal | | | :white_check_mark: | |
|
||||
| DX12 | :white_check_mark: (W10+ only) | | | |
|
||||
| DX11 | :hammer_and_wrench: | | | |
|
||||
| GLES3 | :ok: (angle) | :ok: | :ok: (angle; macOS only) | :ok: (WebGL2 Only) |
|
||||
| WebGPU | | | | :white_check_mark: |
|
||||
| API | Windows | Linux & Android | macOS & iOS | Web (wasm) |
|
||||
| ----------- | ------------------------------ | ------------------ | ------------------------- | ------------------------- |
|
||||
| Vulkan | :white_check_mark: | :white_check_mark: | :ok: (vulkan-portability) | |
|
||||
| Metal | | | :white_check_mark: | |
|
||||
| DX12 | :white_check_mark: (W10+ only) | | | |
|
||||
| DX11 | :hammer_and_wrench: | | | |
|
||||
| OpenGL | :ok: (Desktop GL 3.3+) | :ok: (GL ES 3.0+) | :ok: (angle; GL ES 3.0+) | :ok: (WebGL2) |
|
||||
| WebGPU | | | | :white_check_mark: |
|
||||
|
||||
:white_check_mark: = First Class Support — :ok: = Best Effort Support — :hammer_and_wrench: = Unsupported, but support in progress
|
||||
|
||||
@ -148,6 +148,7 @@ We have multiple methods of testing, each of which tests different qualities abo
|
||||
| DX11/Windows 10 | :construction: | — | using WARP |
|
||||
| Metal/MacOS | :heavy_check_mark: | — | using hardware runner |
|
||||
| Vulkan/Linux | :heavy_check_mark: | - | using swiftshader |
|
||||
| GL/Windows | | — | |
|
||||
| GLES/Linux | :heavy_check_mark: | — | using llvmpipe |
|
||||
| WebGL/Chrome | :heavy_check_mark: | — | using swiftshader |
|
||||
|
||||
|
33
tests/tests/multi-instance.rs
Normal file
33
tests/tests/multi-instance.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
async fn get() -> wgpu::Adapter {
|
||||
let adapter = {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all),
|
||||
..Default::default()
|
||||
});
|
||||
instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions::default())
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
log::info!("Selected adapter: {:?}", adapter.get_info());
|
||||
|
||||
adapter
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_instance() {
|
||||
{
|
||||
env_logger::init();
|
||||
|
||||
// Sequential instances.
|
||||
for _ in 0..3 {
|
||||
pollster::block_on(get());
|
||||
}
|
||||
|
||||
// Concurrent instances
|
||||
let _instances: Vec<_> = (0..3).map(|_| pollster::block_on(get())).collect();
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ targets = [
|
||||
default = ["link"]
|
||||
metal = ["naga/msl-out", "block"]
|
||||
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "smallvec"]
|
||||
gles = ["naga/glsl-out", "glow", "khronos-egl", "libloading"]
|
||||
gles = ["naga/glsl-out", "glow", "glutin_wgl_sys", "khronos-egl", "libloading"]
|
||||
dx11 = ["naga/hlsl-out", "d3d12", "libloading", "winapi/d3d11", "winapi/std", "winapi/d3d11_1", "winapi/d3d11_2", "winapi/d3d11sdklayers", "winapi/dxgi1_6"]
|
||||
dx12 = ["naga/hlsl-out", "d3d12", "bit-set", "libloading", "range-alloc", "winapi/std", "winapi/winbase", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
|
||||
# TODO: This is a separate feature until Mozilla okays windows-rs, see https://github.com/gfx-rs/wgpu/issues/3207 for the tracking issue.
|
||||
@ -59,6 +59,7 @@ parking_lot = ">=0.11,<0.13"
|
||||
profiling = { version = "1", default-features = false }
|
||||
raw-window-handle = "0.5"
|
||||
thiserror = "1"
|
||||
once_cell = "1.18.0"
|
||||
|
||||
# backends common
|
||||
arrayvec = "0.7"
|
||||
@ -95,6 +96,8 @@ bit-set = { version = "0.5", optional = true }
|
||||
range-alloc = { version = "0.1", optional = true }
|
||||
gpu-allocator = { version = "0.23", default_features = false, features = ["d3d12", "public-winapi"], optional = true }
|
||||
hassle-rs = { version = "0.10", optional = true }
|
||||
# backend: Gles
|
||||
glutin_wgl_sys = { version = "0.4", optional = true }
|
||||
|
||||
winapi = { version = "0.3", features = ["profileapi", "libloaderapi", "windef", "winuser", "dcomp"] }
|
||||
d3d12 = { version = "0.7", features = ["libloading"], optional = true }
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
extern crate wgpu_hal as hal;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(any(windows, target_arch = "wasm32")))]
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
println!("Initializing external GL context");
|
||||
@ -116,10 +116,10 @@ fn main() {
|
||||
fill_screen(&exposed, 640, 400);
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
#[cfg(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
|
||||
#[cfg(any(not(any(windows, target_arch = "wasm32")), target_os = "emscripten"))]
|
||||
fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height: u32) {
|
||||
use hal::{Adapter as _, CommandEncoder as _, Device as _, Queue as _};
|
||||
|
||||
|
@ -10,18 +10,6 @@ const GL_UNMASKED_VENDOR_WEBGL: u32 = 0x9245;
|
||||
const GL_UNMASKED_RENDERER_WEBGL: u32 = 0x9246;
|
||||
|
||||
impl super::Adapter {
|
||||
/// According to the OpenGL specification, the version information is
|
||||
/// expected to follow the following syntax:
|
||||
///
|
||||
/// ~~~bnf
|
||||
/// <major> ::= <number>
|
||||
/// <minor> ::= <number>
|
||||
/// <revision> ::= <number>
|
||||
/// <vendor-info> ::= <string>
|
||||
/// <release> ::= <major> "." <minor> ["." <release>]
|
||||
/// <version> ::= <release> [" " <vendor-info>]
|
||||
/// ~~~
|
||||
///
|
||||
/// Note that this function is intentionally lenient in regards to parsing,
|
||||
/// and will try to recover at least the first two version numbers without
|
||||
/// resulting in an `Err`.
|
||||
@ -59,6 +47,35 @@ impl super::Adapter {
|
||||
None => false,
|
||||
};
|
||||
|
||||
Self::parse_full_version(src).map(|(major, minor)| {
|
||||
(
|
||||
// Return WebGL 2.0 version as OpenGL ES 3.0
|
||||
if is_webgl && !is_glsl {
|
||||
major + 1
|
||||
} else {
|
||||
major
|
||||
},
|
||||
minor,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// According to the OpenGL specification, the version information is
|
||||
/// expected to follow the following syntax:
|
||||
///
|
||||
/// ~~~bnf
|
||||
/// <major> ::= <number>
|
||||
/// <minor> ::= <number>
|
||||
/// <revision> ::= <number>
|
||||
/// <vendor-info> ::= <string>
|
||||
/// <release> ::= <major> "." <minor> ["." <release>]
|
||||
/// <version> ::= <release> [" " <vendor-info>]
|
||||
/// ~~~
|
||||
///
|
||||
/// Note that this function is intentionally lenient in regards to parsing,
|
||||
/// and will try to recover at least the first two version numbers without
|
||||
/// resulting in an `Err`.
|
||||
pub(super) fn parse_full_version(src: &str) -> Result<(u8, u8), crate::InstanceError> {
|
||||
let (version, _vendor_info) = match src.find(' ') {
|
||||
Some(i) => (&src[..i], src[i + 1..].to_string()),
|
||||
None => (src, String::new()),
|
||||
@ -78,15 +95,7 @@ impl super::Adapter {
|
||||
});
|
||||
|
||||
match (major, minor) {
|
||||
(Some(major), Some(minor)) => Ok((
|
||||
// Return WebGL 2.0 version as OpenGL ES 3.0
|
||||
if is_webgl && !is_glsl {
|
||||
major + 1
|
||||
} else {
|
||||
major
|
||||
},
|
||||
minor,
|
||||
)),
|
||||
(Some(major), Some(minor)) => Ok((major, minor)),
|
||||
_ => Err(crate::InstanceError::new(format!(
|
||||
"unable to extract OpenGL version from {version:?}"
|
||||
))),
|
||||
@ -212,29 +221,75 @@ impl super::Adapter {
|
||||
log::info!("Renderer: {}", renderer);
|
||||
log::info!("Version: {}", version);
|
||||
|
||||
log::debug!("Extensions: {:#?}", extensions);
|
||||
let full_ver = Self::parse_full_version(&version).ok();
|
||||
let es_ver = full_ver
|
||||
.is_none()
|
||||
.then_some(())
|
||||
.and_then(|_| Self::parse_version(&version).ok());
|
||||
|
||||
let ver = Self::parse_version(&version).ok()?;
|
||||
if ver < (3, 0) {
|
||||
log::warn!(
|
||||
"Returned GLES context is {}.{}, when 3.0+ was requested",
|
||||
ver.0,
|
||||
ver.1
|
||||
);
|
||||
if es_ver.is_none() && full_ver.is_none() {
|
||||
log::warn!("Unable to parse OpenGL version");
|
||||
return None;
|
||||
}
|
||||
|
||||
let supports_storage = ver >= (3, 1);
|
||||
let supports_work_group_params = ver >= (3, 1);
|
||||
if let Some(es_ver) = es_ver {
|
||||
if es_ver < (3, 0) {
|
||||
log::warn!(
|
||||
"Returned GLES context is {}.{}, when 3.0+ was requested",
|
||||
es_ver.0,
|
||||
es_ver.1
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(full_ver) = full_ver {
|
||||
if full_ver < (3, 3) {
|
||||
log::warn!(
|
||||
"Returned GL context is {}.{}, when 3.3+ is needed",
|
||||
full_ver.0,
|
||||
full_ver.1
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let supported = |(req_es_major, req_es_minor), (req_full_major, req_full_minor)| {
|
||||
let es_supported = es_ver
|
||||
.map(|es_ver| es_ver >= (req_es_major, req_es_minor))
|
||||
.unwrap_or_default();
|
||||
|
||||
let full_supported = full_ver
|
||||
.map(|full_ver| full_ver >= (req_full_major, req_full_minor))
|
||||
.unwrap_or_default();
|
||||
|
||||
es_supported || full_supported
|
||||
};
|
||||
|
||||
let supports_storage =
|
||||
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_shader_storage_buffer_object");
|
||||
let supports_compute =
|
||||
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_compute_shader");
|
||||
let supports_work_group_params = supports_compute;
|
||||
|
||||
let shading_language_version = {
|
||||
let sl_version = unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
|
||||
log::info!("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 {
|
||||
version: value,
|
||||
is_webgl: cfg!(target_arch = "wasm32"),
|
||||
if full_ver.is_some() {
|
||||
let (sl_major, sl_minor) = Self::parse_full_version(&sl_version).ok()?;
|
||||
let mut value = sl_major as u16 * 100 + sl_minor as u16 * 10;
|
||||
// Naga doesn't think it supports GL 460+, so we cap it at 450
|
||||
if value > 450 {
|
||||
value = 450;
|
||||
}
|
||||
naga::back::glsl::Version::Desktop(value)
|
||||
} else {
|
||||
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 {
|
||||
version: value,
|
||||
is_webgl: cfg!(target_arch = "wasm32"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -242,7 +297,19 @@ impl super::Adapter {
|
||||
let is_angle = renderer.contains("ANGLE");
|
||||
|
||||
let vertex_shader_storage_blocks = if supports_storage {
|
||||
(unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) } as u32)
|
||||
let value =
|
||||
(unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) } as u32);
|
||||
|
||||
if value == 0 && extensions.contains("GL_ARB_shader_storage_buffer_object") {
|
||||
// The driver for AMD Radeon HD 5870 returns zero here, so assume the value matches the compute shader storage block count.
|
||||
// Windows doesn't recognize `GL_MAX_VERTEX_ATTRIB_STRIDE`.
|
||||
let new = (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_SHADER_STORAGE_BLOCKS) }
|
||||
as u32);
|
||||
log::warn!("Max vertex shader storage blocks is zero, but GL_ARB_shader_storage_buffer_object is specified. Assuming the compute value {new}");
|
||||
new
|
||||
} else {
|
||||
value
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@ -295,18 +362,21 @@ impl super::Adapter {
|
||||
| wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
|
||||
| wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES
|
||||
| wgt::DownlevelFlags::COMPARISON_SAMPLERS;
|
||||
downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, ver >= (3, 1));
|
||||
downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, supports_compute);
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE,
|
||||
max_storage_block_size != 0,
|
||||
);
|
||||
downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1));
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::INDIRECT_EXECUTION,
|
||||
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_multi_draw_indirect"),
|
||||
);
|
||||
//TODO: we can actually support positive `base_vertex` in the same way
|
||||
// as we emulate the `start_instance`. But we can't deal with negatives...
|
||||
downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2));
|
||||
downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, supported((3, 2), (3, 2)));
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::INDEPENDENT_BLEND,
|
||||
ver >= (3, 2) || extensions.contains("GL_EXT_draw_buffers_indexed"),
|
||||
supported((3, 2), (4, 0)) || extensions.contains("GL_EXT_draw_buffers_indexed"),
|
||||
);
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::VERTEX_STORAGE,
|
||||
@ -339,7 +409,7 @@ impl super::Adapter {
|
||||
);
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::MULTISAMPLED_SHADING,
|
||||
ver >= (3, 2) || extensions.contains("OES_sample_variables"),
|
||||
supported((3, 2), (4, 0)) || extensions.contains("OES_sample_variables"),
|
||||
);
|
||||
|
||||
let mut features = wgt::Features::empty()
|
||||
@ -369,9 +439,14 @@ impl super::Adapter {
|
||||
);
|
||||
features.set(
|
||||
wgt::Features::SHADER_PRIMITIVE_INDEX,
|
||||
ver >= (3, 2) || extensions.contains("OES_geometry_shader"),
|
||||
supported((3, 2), (3, 2))
|
||||
|| extensions.contains("OES_geometry_shader")
|
||||
|| extensions.contains("GL_ARB_geometry_shader4"),
|
||||
);
|
||||
features.set(
|
||||
wgt::Features::SHADER_EARLY_DEPTH_TEST,
|
||||
supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
|
||||
);
|
||||
features.set(wgt::Features::SHADER_EARLY_DEPTH_TEST, ver >= (3, 1));
|
||||
features.set(wgt::Features::SHADER_UNUSED_VERTEX_OUTPUT, true);
|
||||
let gles_bcn_exts = [
|
||||
"GL_EXT_texture_compression_s3tc_srgb",
|
||||
@ -443,16 +518,19 @@ impl super::Adapter {
|
||||
);
|
||||
private_caps.set(
|
||||
super::PrivateCapabilities::SHADER_BINDING_LAYOUT,
|
||||
ver >= (3, 1),
|
||||
supports_compute,
|
||||
);
|
||||
private_caps.set(
|
||||
super::PrivateCapabilities::SHADER_TEXTURE_SHADOW_LOD,
|
||||
extensions.contains("GL_EXT_texture_shadow_lod"),
|
||||
);
|
||||
private_caps.set(super::PrivateCapabilities::MEMORY_BARRIERS, ver >= (3, 1));
|
||||
private_caps.set(
|
||||
super::PrivateCapabilities::MEMORY_BARRIERS,
|
||||
supported((3, 1), (4, 2)),
|
||||
);
|
||||
private_caps.set(
|
||||
super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT,
|
||||
ver >= (3, 1),
|
||||
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_vertex_attrib_binding"),
|
||||
);
|
||||
private_caps.set(
|
||||
super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE,
|
||||
@ -483,7 +561,7 @@ impl super::Adapter {
|
||||
|
||||
let min_uniform_buffer_offset_alignment =
|
||||
(unsafe { gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT) } as u32);
|
||||
let min_storage_buffer_offset_alignment = if ver >= (3, 1) {
|
||||
let min_storage_buffer_offset_alignment = if supports_storage {
|
||||
(unsafe { gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) } as u32)
|
||||
} else {
|
||||
256
|
||||
@ -521,7 +599,7 @@ impl super::Adapter {
|
||||
max_uniform_buffer_binding_size: unsafe {
|
||||
gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
|
||||
} as u32,
|
||||
max_storage_buffer_binding_size: if ver >= (3, 1) {
|
||||
max_storage_buffer_binding_size: if supports_storage {
|
||||
unsafe { gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) }
|
||||
} else {
|
||||
0
|
||||
@ -539,7 +617,29 @@ impl super::Adapter {
|
||||
max_vertex_buffer_array_stride: if private_caps
|
||||
.contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
|
||||
{
|
||||
(unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) } as u32)
|
||||
if let Some(full_ver) = full_ver {
|
||||
if full_ver >= (4, 4) {
|
||||
// We can query `GL_MAX_VERTEX_ATTRIB_STRIDE` in OpenGL 4.4+
|
||||
let value =
|
||||
(unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) })
|
||||
as u32;
|
||||
|
||||
if value == 0 {
|
||||
// This should be at least 2048, but the driver for AMD Radeon HD 5870 on
|
||||
// Windows doesn't recognize `GL_MAX_VERTEX_ATTRIB_STRIDE`.
|
||||
|
||||
log::warn!("Max vertex attribute stride is 0. Assuming it is 2048");
|
||||
2048
|
||||
} else {
|
||||
value
|
||||
}
|
||||
} else {
|
||||
log::warn!("Max vertex attribute stride unknown. Assuming it is 2048");
|
||||
2048
|
||||
}
|
||||
} else {
|
||||
(unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) }) as u32
|
||||
}
|
||||
} else {
|
||||
!0
|
||||
},
|
||||
@ -624,6 +724,7 @@ impl super::Adapter {
|
||||
max_texture_size,
|
||||
next_shader_id: Default::default(),
|
||||
program_cache: Default::default(),
|
||||
es: es_ver.is_some(),
|
||||
}),
|
||||
},
|
||||
info: Self::make_info(vendor, renderer),
|
||||
@ -643,27 +744,73 @@ impl super::Adapter {
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn compile_shader(
|
||||
source: &str,
|
||||
gl: &glow::Context,
|
||||
shader_type: u32,
|
||||
es: bool,
|
||||
) -> Option<glow::Shader> {
|
||||
let source = if es {
|
||||
format!("#version 300 es\nprecision lowp float;\n{source}")
|
||||
} else {
|
||||
format!("#version 130\n{source}")
|
||||
};
|
||||
let shader = unsafe { gl.create_shader(shader_type) }.expect("Could not create shader");
|
||||
unsafe { gl.shader_source(shader, &source) };
|
||||
unsafe { gl.compile_shader(shader) };
|
||||
|
||||
if !unsafe { gl.get_shader_compile_status(shader) } {
|
||||
let msg = unsafe { gl.get_shader_info_log(shader) };
|
||||
if !msg.is_empty() {
|
||||
log::error!("\tShader compile error: {}", msg);
|
||||
}
|
||||
unsafe { gl.delete_shader(shader) };
|
||||
None
|
||||
} else {
|
||||
Some(shader)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn create_shader_clear_program(
|
||||
gl: &glow::Context,
|
||||
) -> (glow::Program, glow::UniformLocation) {
|
||||
es: bool,
|
||||
) -> Option<(glow::Program, glow::UniformLocation)> {
|
||||
let program = unsafe { gl.create_program() }.expect("Could not create shader program");
|
||||
let vertex =
|
||||
unsafe { gl.create_shader(glow::VERTEX_SHADER) }.expect("Could not create shader");
|
||||
unsafe { gl.shader_source(vertex, include_str!("./shaders/clear.vert")) };
|
||||
unsafe { gl.compile_shader(vertex) };
|
||||
let fragment =
|
||||
unsafe { gl.create_shader(glow::FRAGMENT_SHADER) }.expect("Could not create shader");
|
||||
unsafe { gl.shader_source(fragment, include_str!("./shaders/clear.frag")) };
|
||||
unsafe { gl.compile_shader(fragment) };
|
||||
let vertex = unsafe {
|
||||
Self::compile_shader(
|
||||
include_str!("./shaders/clear.vert"),
|
||||
gl,
|
||||
glow::VERTEX_SHADER,
|
||||
es,
|
||||
)?
|
||||
};
|
||||
let fragment = unsafe {
|
||||
Self::compile_shader(
|
||||
include_str!("./shaders/clear.frag"),
|
||||
gl,
|
||||
glow::FRAGMENT_SHADER,
|
||||
es,
|
||||
)?
|
||||
};
|
||||
unsafe { gl.attach_shader(program, vertex) };
|
||||
unsafe { gl.attach_shader(program, fragment) };
|
||||
unsafe { gl.link_program(program) };
|
||||
|
||||
let linked_ok = unsafe { gl.get_program_link_status(program) };
|
||||
let msg = unsafe { gl.get_program_info_log(program) };
|
||||
if !msg.is_empty() {
|
||||
log::warn!("Shader link error: {}", msg);
|
||||
}
|
||||
if !linked_ok {
|
||||
return None;
|
||||
}
|
||||
|
||||
let color_uniform_location = unsafe { gl.get_uniform_location(program, "color") }
|
||||
.expect("Could not find color uniform in shader clear shader");
|
||||
unsafe { gl.delete_shader(vertex) };
|
||||
unsafe { gl.delete_shader(fragment) };
|
||||
|
||||
(program, color_uniform_location)
|
||||
Some((program, color_uniform_location))
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,8 +835,11 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
|
||||
// Compile the shader program we use for doing manual clears to work around Mesa fastclear
|
||||
// bug.
|
||||
let (shader_clear_program, shader_clear_program_color_uniform_location) =
|
||||
unsafe { Self::create_shader_clear_program(gl) };
|
||||
|
||||
let (shader_clear_program, shader_clear_program_color_uniform_location) = unsafe {
|
||||
Self::create_shader_clear_program(gl, self.shared.es)
|
||||
.ok_or(crate::DeviceError::ResourceCreationFailed)?
|
||||
};
|
||||
|
||||
Ok(crate::OpenDevice {
|
||||
device: super::Device {
|
||||
@ -909,7 +1059,11 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
|
||||
Some(crate::SurfaceCapabilities {
|
||||
formats,
|
||||
present_modes: vec![wgt::PresentMode::Fifo], //TODO
|
||||
present_modes: if cfg!(windows) {
|
||||
vec![wgt::PresentMode::Fifo, wgt::PresentMode::Mailbox]
|
||||
} else {
|
||||
vec![wgt::PresentMode::Fifo] //TODO
|
||||
},
|
||||
composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], //TODO
|
||||
swap_chain_sizes: 2..=2,
|
||||
current_extent: None,
|
||||
|
@ -272,10 +272,6 @@ impl super::Device {
|
||||
entry_point: stage.entry_point.to_owned(),
|
||||
});
|
||||
}
|
||||
let glsl_version = match self.shared.shading_language_version {
|
||||
naga::back::glsl::Version::Embedded { version, .. } => version,
|
||||
naga::back::glsl::Version::Desktop(_) => unreachable!(),
|
||||
};
|
||||
let mut guard = self
|
||||
.shared
|
||||
.program_cache
|
||||
@ -295,7 +291,7 @@ impl super::Device {
|
||||
layout,
|
||||
label,
|
||||
multiview,
|
||||
glsl_version,
|
||||
self.shared.shading_language_version,
|
||||
self.shared.private_caps,
|
||||
)
|
||||
})
|
||||
@ -311,9 +307,13 @@ impl super::Device {
|
||||
layout: &super::PipelineLayout,
|
||||
#[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>,
|
||||
multiview: Option<std::num::NonZeroU32>,
|
||||
glsl_version: u16,
|
||||
glsl_version: naga::back::glsl::Version,
|
||||
private_caps: super::PrivateCapabilities,
|
||||
) -> Result<Arc<super::PipelineInner>, crate::PipelineError> {
|
||||
let glsl_version = match glsl_version {
|
||||
naga::back::glsl::Version::Embedded { version, .. } => format!("{version} es"),
|
||||
naga::back::glsl::Version::Desktop(version) => format!("{version}"),
|
||||
};
|
||||
let program = unsafe { gl.create_program() }.unwrap();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if let Some(label) = label {
|
||||
@ -343,7 +343,7 @@ impl super::Device {
|
||||
|
||||
// Create empty fragment shader if only vertex shader is present
|
||||
if has_stages == wgt::ShaderStages::VERTEX {
|
||||
let shader_src = format!("#version {glsl_version} es \n void main(void) {{}}",);
|
||||
let shader_src = format!("#version {glsl_version}\n void main(void) {{}}",);
|
||||
log::info!("Only vertex shader is present. Creating an empty fragment shader",);
|
||||
let shader = unsafe {
|
||||
Self::compile_shader(
|
||||
|
@ -289,55 +289,6 @@ fn choose_config(
|
||||
)))
|
||||
}
|
||||
|
||||
fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
|
||||
let source_str = match source {
|
||||
glow::DEBUG_SOURCE_API => "API",
|
||||
glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
|
||||
glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
|
||||
glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
|
||||
glow::DEBUG_SOURCE_APPLICATION => "Application",
|
||||
glow::DEBUG_SOURCE_OTHER => "Other",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let log_severity = match severity {
|
||||
glow::DEBUG_SEVERITY_HIGH => log::Level::Error,
|
||||
glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn,
|
||||
glow::DEBUG_SEVERITY_LOW => log::Level::Info,
|
||||
glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let type_str = match gltype {
|
||||
glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
|
||||
glow::DEBUG_TYPE_ERROR => "Error",
|
||||
glow::DEBUG_TYPE_MARKER => "Marker",
|
||||
glow::DEBUG_TYPE_OTHER => "Other",
|
||||
glow::DEBUG_TYPE_PERFORMANCE => "Performance",
|
||||
glow::DEBUG_TYPE_POP_GROUP => "Pop Group",
|
||||
glow::DEBUG_TYPE_PORTABILITY => "Portability",
|
||||
glow::DEBUG_TYPE_PUSH_GROUP => "Push Group",
|
||||
glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let _ = std::panic::catch_unwind(|| {
|
||||
log::log!(
|
||||
log_severity,
|
||||
"GLES: [{}/{}] ID {} : {}",
|
||||
source_str,
|
||||
type_str,
|
||||
id,
|
||||
message
|
||||
);
|
||||
});
|
||||
|
||||
if cfg!(debug_assertions) && log_severity == log::Level::Error {
|
||||
// Set canary and continue
|
||||
crate::VALIDATION_CANARY.set();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct EglContext {
|
||||
instance: Arc<EglInstance>,
|
||||
@ -1014,7 +965,7 @@ impl crate::Instance<super::Api> for Instance {
|
||||
if self.flags.contains(wgt::InstanceFlags::VALIDATION) && gl.supports_debug() {
|
||||
log::info!("Enabling GLES debug output");
|
||||
unsafe { gl.enable(glow::DEBUG_OUTPUT) };
|
||||
unsafe { gl.debug_message_callback(gl_debug_message_callback) };
|
||||
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
|
||||
}
|
||||
|
||||
inner.egl.unmake_current();
|
||||
@ -1094,8 +1045,9 @@ impl Surface {
|
||||
pub(super) unsafe fn present(
|
||||
&mut self,
|
||||
_suf_texture: super::Texture,
|
||||
gl: &glow::Context,
|
||||
context: &AdapterContext,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
let gl = unsafe { context.get_without_egl_lock() };
|
||||
let sc = self.swapchain.as_ref().unwrap();
|
||||
|
||||
self.egl
|
||||
|
@ -57,12 +57,14 @@ To address this, we invalidate the vertex buffers based on:
|
||||
*/
|
||||
|
||||
///cbindgen:ignore
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
|
||||
#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
|
||||
mod egl;
|
||||
#[cfg(target_os = "emscripten")]
|
||||
mod emscripten;
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
mod web;
|
||||
#[cfg(windows)]
|
||||
mod wgl;
|
||||
|
||||
mod adapter;
|
||||
mod command;
|
||||
@ -72,9 +74,9 @@ mod queue;
|
||||
|
||||
use crate::{CopyExtent, TextureDescriptor};
|
||||
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
|
||||
#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
|
||||
pub use self::egl::{AdapterContext, AdapterContextLock};
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
|
||||
#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
|
||||
use self::egl::{Instance, Surface};
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
@ -82,6 +84,11 @@ pub use self::web::AdapterContext;
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
use self::web::{Instance, Surface};
|
||||
|
||||
#[cfg(windows)]
|
||||
use self::wgl::AdapterContext;
|
||||
#[cfg(windows)]
|
||||
use self::wgl::{Instance, Surface};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
use glow::HasContext;
|
||||
@ -204,6 +211,7 @@ struct AdapterShared {
|
||||
max_texture_size: u32,
|
||||
next_shader_id: AtomicU32,
|
||||
program_cache: Mutex<ProgramCache>,
|
||||
es: bool,
|
||||
}
|
||||
|
||||
pub struct Adapter {
|
||||
@ -904,3 +912,53 @@ impl fmt::Debug for CommandEncoder {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||
fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
|
||||
let source_str = match source {
|
||||
glow::DEBUG_SOURCE_API => "API",
|
||||
glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
|
||||
glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
|
||||
glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
|
||||
glow::DEBUG_SOURCE_APPLICATION => "Application",
|
||||
glow::DEBUG_SOURCE_OTHER => "Other",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let log_severity = match severity {
|
||||
glow::DEBUG_SEVERITY_HIGH => log::Level::Error,
|
||||
glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn,
|
||||
glow::DEBUG_SEVERITY_LOW => log::Level::Info,
|
||||
glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let type_str = match gltype {
|
||||
glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
|
||||
glow::DEBUG_TYPE_ERROR => "Error",
|
||||
glow::DEBUG_TYPE_MARKER => "Marker",
|
||||
glow::DEBUG_TYPE_OTHER => "Other",
|
||||
glow::DEBUG_TYPE_PERFORMANCE => "Performance",
|
||||
glow::DEBUG_TYPE_POP_GROUP => "Pop Group",
|
||||
glow::DEBUG_TYPE_PORTABILITY => "Portability",
|
||||
glow::DEBUG_TYPE_PUSH_GROUP => "Push Group",
|
||||
glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let _ = std::panic::catch_unwind(|| {
|
||||
log::log!(
|
||||
log_severity,
|
||||
"GLES: [{}/{}] ID {} : {}",
|
||||
source_str,
|
||||
type_str,
|
||||
id,
|
||||
message
|
||||
);
|
||||
});
|
||||
|
||||
if cfg!(debug_assertions) && log_severity == log::Level::Error {
|
||||
// Set canary and continue
|
||||
crate::VALIDATION_CANARY.set();
|
||||
}
|
||||
}
|
||||
|
@ -1443,13 +1443,7 @@ impl crate::Queue<super::Api> for super::Queue {
|
||||
surface: &mut super::Surface,
|
||||
texture: super::Texture,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
|
||||
let gl = unsafe { &self.shared.context.get_without_egl_lock() };
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
let gl = &self.shared.context.glow_context;
|
||||
|
||||
unsafe { surface.present(texture, gl) }
|
||||
unsafe { surface.present(texture, &self.shared.context) }
|
||||
}
|
||||
|
||||
unsafe fn get_timestamp_period(&self) -> f32 {
|
||||
|
@ -1,5 +1,3 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
uniform vec4 color;
|
||||
//Hack: Some WebGL implementations don't find "color" otherwise.
|
||||
uniform vec4 color_workaround;
|
||||
|
@ -1,7 +1,5 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
// A triangle that fills the whole screen
|
||||
const vec2[3] TRIANGLE_POS = vec2[](
|
||||
vec2[3] TRIANGLE_POS = vec2[](
|
||||
vec2( 0.0, -3.0),
|
||||
vec2(-3.0, 1.0),
|
||||
vec2( 3.0, 1.0)
|
||||
|
@ -215,8 +215,9 @@ impl Surface {
|
||||
pub(super) unsafe fn present(
|
||||
&mut self,
|
||||
_suf_texture: super::Texture,
|
||||
gl: &glow::Context,
|
||||
context: &AdapterContext,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
let gl = &context.glow_context;
|
||||
let swapchain = self.swapchain.as_ref().ok_or(crate::SurfaceError::Other(
|
||||
"need to configure surface before presenting",
|
||||
))?;
|
||||
|
775
wgpu-hal/src/gles/wgl.rs
Normal file
775
wgpu-hal/src/gles/wgl.rs
Normal file
@ -0,0 +1,775 @@
|
||||
use glow::HasContext;
|
||||
use glutin_wgl_sys::wgl_extra::{
|
||||
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
|
||||
CONTEXT_PROFILE_MASK_ARB,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
ffi::{c_void, CStr, CString},
|
||||
io::Error,
|
||||
mem,
|
||||
os::raw::c_int,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use wgt::InstanceFlags;
|
||||
use winapi::{
|
||||
shared::{
|
||||
minwindef::{FALSE, HMODULE, LPARAM, LRESULT, UINT, WPARAM},
|
||||
windef::{HDC, HGLRC, HWND},
|
||||
},
|
||||
um::{
|
||||
libloaderapi::{GetModuleHandleA, GetProcAddress, LoadLibraryA},
|
||||
wingdi::{
|
||||
wglCreateContext, wglDeleteContext, wglGetCurrentContext, wglGetProcAddress,
|
||||
wglMakeCurrent, wglShareLists, ChoosePixelFormat, DescribePixelFormat, GetPixelFormat,
|
||||
SetPixelFormat, SwapBuffers, PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_SUPPORT_OPENGL,
|
||||
PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR,
|
||||
},
|
||||
winuser::{
|
||||
CreateWindowExA, DefWindowProcA, GetDC, RegisterClassExA, ReleaseDC, CS_OWNDC,
|
||||
WNDCLASSEXA,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// The amount of time to wait while trying to obtain a lock to the adapter context
|
||||
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
|
||||
|
||||
/// A wrapper around a `[`glow::Context`]` and the required WGL context that uses locking to
|
||||
/// guarantee exclusive access when shared with multiple threads.
|
||||
pub struct AdapterContext {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for AdapterContext {}
|
||||
unsafe impl Send for AdapterContext {}
|
||||
|
||||
impl AdapterContext {
|
||||
pub fn is_owned(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn raw_context(&self) -> *mut c_void {
|
||||
self.inner.lock().context.context as *mut _
|
||||
}
|
||||
|
||||
/// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to
|
||||
/// do rendering.
|
||||
#[track_caller]
|
||||
pub fn lock(&self) -> AdapterContextLock<'_> {
|
||||
let inner = self
|
||||
.inner
|
||||
// Don't lock forever. If it takes longer than 1 second to get the lock we've got a
|
||||
// deadlock and should panic to show where we got stuck
|
||||
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
|
||||
.expect("Could not lock adapter context. This is most-likely a deadlock.");
|
||||
|
||||
inner.context.make_current(inner.device).unwrap();
|
||||
|
||||
AdapterContextLock { inner }
|
||||
}
|
||||
}
|
||||
|
||||
/// A guard containing a lock to an [`AdapterContext`]
|
||||
pub struct AdapterContextLock<'a> {
|
||||
inner: MutexGuard<'a, Inner>,
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for AdapterContextLock<'a> {
|
||||
type Target = glow::Context;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner.gl
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for AdapterContextLock<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.inner.context.unmake_current().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct WglContext {
|
||||
context: HGLRC,
|
||||
}
|
||||
|
||||
impl WglContext {
|
||||
fn make_current(&self, device: HDC) -> Result<(), Error> {
|
||||
if unsafe { wglMakeCurrent(device, self.context) } == FALSE {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn unmake_current(&self) -> Result<(), Error> {
|
||||
if unsafe { wglGetCurrentContext().is_null() } {
|
||||
return Ok(());
|
||||
}
|
||||
if unsafe { wglMakeCurrent(ptr::null_mut(), ptr::null_mut()) } == FALSE {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WglContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if wglDeleteContext(self.context) == FALSE {
|
||||
log::error!("failed to delete WGL context {}", Error::last_os_error());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for WglContext {}
|
||||
unsafe impl Sync for WglContext {}
|
||||
|
||||
struct Inner {
|
||||
opengl_module: HMODULE,
|
||||
gl: glow::Context,
|
||||
device: HDC,
|
||||
context: WglContext,
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
srgb_capable: bool,
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Instance {}
|
||||
unsafe impl Sync for Instance {}
|
||||
|
||||
fn load_gl_func(name: &str, module: Option<HMODULE>) -> *const c_void {
|
||||
let addr = CString::new(name.as_bytes()).unwrap();
|
||||
let mut ptr = unsafe { wglGetProcAddress(addr.as_ptr()) };
|
||||
if ptr.is_null() {
|
||||
if let Some(module) = module {
|
||||
ptr = unsafe { GetProcAddress(module, addr.as_ptr()) };
|
||||
}
|
||||
}
|
||||
ptr.cast()
|
||||
}
|
||||
|
||||
fn extensions(extra: &Wgl, dc: HDC) -> HashSet<String> {
|
||||
if extra.GetExtensionsStringARB.is_loaded() {
|
||||
unsafe { CStr::from_ptr(extra.GetExtensionsStringARB(dc as *const _)) }
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
.split(' ')
|
||||
.map(|s| s.to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
unsafe fn setup_pixel_format(dc: HDC) -> Result<(), crate::InstanceError> {
|
||||
let mut format: PIXELFORMATDESCRIPTOR = unsafe { mem::zeroed() };
|
||||
format.nVersion = 1;
|
||||
format.nSize = mem::size_of_val(&format) as u16;
|
||||
format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
format.iPixelType = PFD_TYPE_RGBA;
|
||||
format.cColorBits = 8;
|
||||
|
||||
let index = unsafe { ChoosePixelFormat(dc, &format) };
|
||||
if index == 0 {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to choose pixel format"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
let current = unsafe { GetPixelFormat(dc) };
|
||||
|
||||
if index != current && unsafe { SetPixelFormat(dc, index, &format) } == FALSE {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to set pixel format"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
let index = unsafe { GetPixelFormat(dc) };
|
||||
if index == 0 {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to get pixel format index"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
if unsafe { DescribePixelFormat(dc, index, mem::size_of_val(&format) as UINT, &mut format) }
|
||||
== 0
|
||||
{
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to read pixel format"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
if format.dwFlags & PFD_SUPPORT_OPENGL == 0 || format.iPixelType != PFD_TYPE_RGBA {
|
||||
return Err(crate::InstanceError::new(String::from(
|
||||
"unsuitable pixel format",
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_global_device_context() -> Result<HDC, crate::InstanceError> {
|
||||
let instance = unsafe { GetModuleHandleA(ptr::null()) };
|
||||
if instance.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to get executable instance"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
// Use the address of `UNIQUE` as part of the window class name to ensure different
|
||||
// `wgpu` versions use different names.
|
||||
static UNIQUE: Mutex<u8> = Mutex::new(0);
|
||||
let class_addr: *const _ = &UNIQUE;
|
||||
let name = format!("wgpu Device Class {:x}\0", class_addr as usize);
|
||||
let name = CString::from_vec_with_nul(name.into_bytes()).unwrap();
|
||||
|
||||
// Use a wrapper function for compatibility with `windows-rs`.
|
||||
unsafe extern "system" fn wnd_proc(
|
||||
window: HWND,
|
||||
msg: UINT,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> LRESULT {
|
||||
unsafe { DefWindowProcA(window, msg, wparam, lparam) }
|
||||
}
|
||||
|
||||
let window_class = WNDCLASSEXA {
|
||||
cbSize: mem::size_of::<WNDCLASSEXA>() as u32,
|
||||
style: CS_OWNDC,
|
||||
lpfnWndProc: Some(wnd_proc),
|
||||
cbClsExtra: 0,
|
||||
cbWndExtra: 0,
|
||||
hInstance: instance,
|
||||
hIcon: ptr::null_mut(),
|
||||
hCursor: ptr::null_mut(),
|
||||
hbrBackground: ptr::null_mut(),
|
||||
lpszMenuName: ptr::null_mut(),
|
||||
lpszClassName: name.as_ptr(),
|
||||
hIconSm: ptr::null_mut(),
|
||||
};
|
||||
|
||||
let atom = unsafe { RegisterClassExA(&window_class) };
|
||||
|
||||
if atom == 0 {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to register window class"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
// Create a hidden window since we don't pass `WS_VISIBLE`.
|
||||
let window = unsafe {
|
||||
CreateWindowExA(
|
||||
0,
|
||||
name.as_ptr(),
|
||||
name.as_ptr(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
instance,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if window.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to create hidden instance window"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
let dc = unsafe { GetDC(window) };
|
||||
if dc.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to create memory device"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
unsafe { setup_pixel_format(dc)? };
|
||||
|
||||
// We intentionally leak the window class, window and device context handle to avoid
|
||||
// spawning a thread to destroy them. We cannot use `DestroyWindow` and `ReleaseDC` on
|
||||
// different threads.
|
||||
|
||||
Ok(dc)
|
||||
}
|
||||
|
||||
fn get_global_device_context() -> Result<HDC, crate::InstanceError> {
|
||||
#[derive(Clone, Copy)]
|
||||
struct SendDc(HDC);
|
||||
unsafe impl Sync for SendDc {}
|
||||
unsafe impl Send for SendDc {}
|
||||
|
||||
static GLOBAL: Lazy<Result<SendDc, crate::InstanceError>> =
|
||||
Lazy::new(|| create_global_device_context().map(SendDc));
|
||||
GLOBAL.clone().map(|dc| dc.0)
|
||||
}
|
||||
|
||||
impl crate::Instance<super::Api> for Instance {
|
||||
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
||||
let opengl_module = unsafe { LoadLibraryA("opengl32.dll\0".as_ptr() as *const _) };
|
||||
if opengl_module.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to load the OpenGL library"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
let dc = get_global_device_context()?;
|
||||
|
||||
let context = unsafe { wglCreateContext(dc) };
|
||||
if context.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to create initial OpenGL context"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
let context = WglContext { context };
|
||||
context.make_current(dc).map_err(|e| {
|
||||
crate::InstanceError::with_source(
|
||||
String::from("unable to set initial OpenGL context as current"),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
let extra = Wgl::load_with(|name| load_gl_func(name, None));
|
||||
let extentions = extensions(&extra, dc);
|
||||
|
||||
let can_use_profile = extentions.contains("WGL_ARB_create_context_profile")
|
||||
&& extra.CreateContextAttribsARB.is_loaded();
|
||||
|
||||
let context = if can_use_profile {
|
||||
let attributes = [
|
||||
CONTEXT_PROFILE_MASK_ARB as c_int,
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB as c_int,
|
||||
CONTEXT_FLAGS_ARB as c_int,
|
||||
if desc.flags.contains(InstanceFlags::DEBUG) {
|
||||
CONTEXT_DEBUG_BIT_ARB as c_int
|
||||
} else {
|
||||
0
|
||||
},
|
||||
0, // End of list
|
||||
];
|
||||
let context = unsafe {
|
||||
extra.CreateContextAttribsARB(dc as *const _, ptr::null(), attributes.as_ptr())
|
||||
};
|
||||
if context.is_null() {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("unable to create OpenGL context"),
|
||||
Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
WglContext {
|
||||
context: context as *mut _,
|
||||
}
|
||||
} else {
|
||||
context
|
||||
};
|
||||
|
||||
context.make_current(dc).map_err(|e| {
|
||||
crate::InstanceError::with_source(
|
||||
String::from("unable to set OpenGL context as current"),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
let gl = unsafe {
|
||||
glow::Context::from_loader_function(|name| load_gl_func(name, Some(opengl_module)))
|
||||
};
|
||||
|
||||
let extra = Wgl::load_with(|name| load_gl_func(name, None));
|
||||
let extentions = extensions(&extra, dc);
|
||||
|
||||
let srgb_capable = extentions.contains("WGL_EXT_framebuffer_sRGB")
|
||||
|| extentions.contains("WGL_ARB_framebuffer_sRGB")
|
||||
|| gl
|
||||
.supported_extensions()
|
||||
.contains("GL_ARB_framebuffer_sRGB");
|
||||
|
||||
if srgb_capable {
|
||||
unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) };
|
||||
}
|
||||
|
||||
if desc.flags.contains(InstanceFlags::VALIDATION) && gl.supports_debug() {
|
||||
log::info!("Enabling GL debug output");
|
||||
unsafe { gl.enable(glow::DEBUG_OUTPUT) };
|
||||
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
|
||||
}
|
||||
|
||||
context.unmake_current().map_err(|e| {
|
||||
crate::InstanceError::with_source(
|
||||
String::from("unable to unset the current WGL context"),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Instance {
|
||||
inner: Arc::new(Mutex::new(Inner {
|
||||
device: dc,
|
||||
opengl_module,
|
||||
gl,
|
||||
context,
|
||||
})),
|
||||
srgb_capable,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))]
|
||||
unsafe fn create_surface(
|
||||
&self,
|
||||
_display_handle: RawDisplayHandle,
|
||||
window_handle: RawWindowHandle,
|
||||
) -> Result<Surface, crate::InstanceError> {
|
||||
let window = if let RawWindowHandle::Win32(handle) = window_handle {
|
||||
handle
|
||||
} else {
|
||||
return Err(crate::InstanceError::new(format!(
|
||||
"unsupported window: {window_handle:?}"
|
||||
)));
|
||||
};
|
||||
Ok(Surface {
|
||||
window: window.hwnd as *mut _,
|
||||
presentable: true,
|
||||
swapchain: None,
|
||||
srgb_capable: self.srgb_capable,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
||||
|
||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||
unsafe {
|
||||
super::Adapter::expose(AdapterContext {
|
||||
inner: self.inner.clone(),
|
||||
})
|
||||
}
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceContextHandle {
|
||||
device: HDC,
|
||||
window: HWND,
|
||||
}
|
||||
|
||||
impl Drop for DeviceContextHandle {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ReleaseDC(self.window, self.device);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Swapchain {
|
||||
surface_context: WglContext,
|
||||
surface_gl: glow::Context,
|
||||
framebuffer: glow::Framebuffer,
|
||||
renderbuffer: glow::Renderbuffer,
|
||||
/// Extent because the window lies
|
||||
extent: wgt::Extent3d,
|
||||
format: wgt::TextureFormat,
|
||||
format_desc: super::TextureFormatDesc,
|
||||
#[allow(unused)]
|
||||
sample_type: wgt::TextureSampleType,
|
||||
}
|
||||
|
||||
pub struct Surface {
|
||||
window: HWND,
|
||||
pub(super) presentable: bool,
|
||||
swapchain: Option<Swapchain>,
|
||||
srgb_capable: bool,
|
||||
}
|
||||
|
||||
unsafe impl Send for Surface {}
|
||||
unsafe impl Sync for Surface {}
|
||||
|
||||
impl Surface {
|
||||
pub(super) unsafe fn present(
|
||||
&mut self,
|
||||
_suf_texture: super::Texture,
|
||||
context: &AdapterContext,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
let sc = self.swapchain.as_ref().unwrap();
|
||||
let dc = unsafe { GetDC(self.window) };
|
||||
if dc.is_null() {
|
||||
log::error!(
|
||||
"unable to get the device context from window: {}",
|
||||
Error::last_os_error()
|
||||
);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to get the device context from window",
|
||||
));
|
||||
}
|
||||
let dc = DeviceContextHandle {
|
||||
device: dc,
|
||||
window: self.window,
|
||||
};
|
||||
|
||||
// Hold the lock for the shared context as we're using resources from there.
|
||||
let _inner = context.inner.lock();
|
||||
|
||||
if let Err(e) = sc.surface_context.make_current(dc.device) {
|
||||
log::error!("unable to make the surface OpenGL context current: {e}",);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to make the surface OpenGL context current",
|
||||
));
|
||||
}
|
||||
|
||||
let gl = &sc.surface_gl;
|
||||
|
||||
// Note the Y-flipping here. GL's presentation is not flipped,
|
||||
// but main rendering is. Therefore, we Y-flip the output positions
|
||||
// in the shader, and also this blit.
|
||||
unsafe {
|
||||
gl.blit_framebuffer(
|
||||
0,
|
||||
sc.extent.height as i32,
|
||||
sc.extent.width as i32,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
sc.extent.width as i32,
|
||||
sc.extent.height as i32,
|
||||
glow::COLOR_BUFFER_BIT,
|
||||
glow::NEAREST,
|
||||
)
|
||||
};
|
||||
|
||||
if unsafe { SwapBuffers(dc.device) } == FALSE {
|
||||
log::error!("unable to swap buffers: {}", Error::last_os_error());
|
||||
return Err(crate::SurfaceError::Other("unable to swap buffers"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn supports_srgb(&self) -> bool {
|
||||
self.srgb_capable
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Surface<super::Api> for Surface {
|
||||
unsafe fn configure(
|
||||
&mut self,
|
||||
device: &super::Device,
|
||||
config: &crate::SurfaceConfiguration,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
// Remove the old configuration.
|
||||
unsafe { self.unconfigure(device) };
|
||||
|
||||
let format_desc = device.shared.describe_texture_format(config.format);
|
||||
let inner = &device.shared.context.inner.lock();
|
||||
|
||||
if let Err(e) = inner.context.make_current(inner.device) {
|
||||
log::error!("unable to make the shared OpenGL context current: {e}",);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to make the shared OpenGL context current",
|
||||
));
|
||||
}
|
||||
|
||||
let gl = &inner.gl;
|
||||
let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| {
|
||||
log::error!("Internal swapchain renderbuffer creation failed: {error}");
|
||||
crate::DeviceError::OutOfMemory
|
||||
})?;
|
||||
unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)) };
|
||||
unsafe {
|
||||
gl.renderbuffer_storage(
|
||||
glow::RENDERBUFFER,
|
||||
format_desc.internal,
|
||||
config.extent.width as _,
|
||||
config.extent.height as _,
|
||||
)
|
||||
};
|
||||
|
||||
// Create the swap chain OpenGL context
|
||||
|
||||
let dc = unsafe { GetDC(self.window) };
|
||||
if dc.is_null() {
|
||||
log::error!(
|
||||
"unable to get the device context from window: {}",
|
||||
Error::last_os_error()
|
||||
);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to get the device context from window",
|
||||
));
|
||||
}
|
||||
let dc = DeviceContextHandle {
|
||||
device: dc,
|
||||
window: self.window,
|
||||
};
|
||||
|
||||
if let Err(e) = unsafe { setup_pixel_format(dc.device) } {
|
||||
log::error!("unable to setup surface pixel format: {e}",);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to setup surface pixel format",
|
||||
));
|
||||
}
|
||||
|
||||
let context = unsafe { wglCreateContext(dc.device) };
|
||||
if context.is_null() {
|
||||
log::error!(
|
||||
"unable to create surface OpenGL context: {}",
|
||||
Error::last_os_error()
|
||||
);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to create surface OpenGL context",
|
||||
));
|
||||
}
|
||||
let surface_context = WglContext { context };
|
||||
|
||||
if unsafe { wglShareLists(inner.context.context, surface_context.context) } == FALSE {
|
||||
log::error!(
|
||||
"unable to share objects between OpenGL contexts: {}",
|
||||
Error::last_os_error()
|
||||
);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to share objects between OpenGL contexts",
|
||||
));
|
||||
}
|
||||
|
||||
if let Err(e) = surface_context.make_current(dc.device) {
|
||||
log::error!("unable to make the surface OpengL context current: {e}",);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to make the surface OpengL context current",
|
||||
));
|
||||
}
|
||||
|
||||
let extra = Wgl::load_with(|name| load_gl_func(name, None));
|
||||
let extentions = extensions(&extra, dc.device);
|
||||
if !(extentions.contains("WGL_EXT_swap_control") && extra.SwapIntervalEXT.is_loaded()) {
|
||||
log::error!("WGL_EXT_swap_control is unsupported");
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"WGL_EXT_swap_control is unsupported",
|
||||
));
|
||||
}
|
||||
|
||||
let vsync = match config.present_mode {
|
||||
wgt::PresentMode::Mailbox => false,
|
||||
wgt::PresentMode::Fifo => true,
|
||||
_ => {
|
||||
log::error!("unsupported present mode: {:?}", config.present_mode);
|
||||
return Err(crate::SurfaceError::Other("unsupported present mode"));
|
||||
}
|
||||
};
|
||||
|
||||
if unsafe { extra.SwapIntervalEXT(if vsync { 1 } else { 0 }) } == FALSE {
|
||||
log::error!("unable to set swap interval: {}", Error::last_os_error());
|
||||
return Err(crate::SurfaceError::Other("unable to set swap interval"));
|
||||
}
|
||||
|
||||
let surface_gl = unsafe {
|
||||
glow::Context::from_loader_function(|name| {
|
||||
load_gl_func(name, Some(inner.opengl_module))
|
||||
})
|
||||
};
|
||||
|
||||
// Check that the surface context OpenGL is new enough to support framebuffers.
|
||||
let version = unsafe { gl.get_parameter_string(glow::VERSION) };
|
||||
let version = super::Adapter::parse_full_version(&version);
|
||||
match version {
|
||||
Ok(version) => {
|
||||
if version < (3, 0) {
|
||||
log::error!(
|
||||
"surface context OpenGL version ({}.{}) too old",
|
||||
version.0,
|
||||
version.1
|
||||
);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"surface context OpenGL version too old",
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("unable to parse surface context OpenGL version: {e}",);
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"unable to parse surface context OpenGL version",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let framebuffer = unsafe { surface_gl.create_framebuffer() }.map_err(|error| {
|
||||
log::error!("Internal swapchain framebuffer creation failed: {error}");
|
||||
crate::DeviceError::OutOfMemory
|
||||
})?;
|
||||
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
|
||||
unsafe {
|
||||
surface_gl.framebuffer_renderbuffer(
|
||||
glow::READ_FRAMEBUFFER,
|
||||
glow::COLOR_ATTACHMENT0,
|
||||
glow::RENDERBUFFER,
|
||||
Some(renderbuffer),
|
||||
)
|
||||
};
|
||||
unsafe { surface_gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
|
||||
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
|
||||
|
||||
unsafe { surface_gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
|
||||
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
|
||||
|
||||
self.swapchain = Some(Swapchain {
|
||||
surface_context,
|
||||
surface_gl,
|
||||
renderbuffer,
|
||||
framebuffer,
|
||||
extent: config.extent,
|
||||
format: config.format,
|
||||
format_desc,
|
||||
sample_type: wgt::TextureSampleType::Float { filterable: false },
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn unconfigure(&mut self, device: &super::Device) {
|
||||
let gl = &device.shared.context.lock();
|
||||
if let Some(sc) = self.swapchain.take() {
|
||||
unsafe {
|
||||
gl.delete_renderbuffer(sc.renderbuffer);
|
||||
gl.delete_framebuffer(sc.framebuffer)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn acquire_texture(
|
||||
&mut self,
|
||||
_timeout_ms: Option<Duration>,
|
||||
) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
|
||||
let sc = self.swapchain.as_ref().unwrap();
|
||||
let texture = super::Texture {
|
||||
inner: super::TextureInner::Renderbuffer {
|
||||
raw: sc.renderbuffer,
|
||||
},
|
||||
drop_guard: None,
|
||||
array_layer_count: 1,
|
||||
mip_level_count: 1,
|
||||
format: sc.format,
|
||||
format_desc: sc.format_desc.clone(),
|
||||
copy_size: crate::CopyExtent {
|
||||
width: sc.extent.width,
|
||||
height: sc.extent.height,
|
||||
depth: 1,
|
||||
},
|
||||
};
|
||||
Ok(Some(crate::AcquiredSurfaceTexture {
|
||||
texture,
|
||||
suboptimal: false,
|
||||
}))
|
||||
}
|
||||
unsafe fn discard_texture(&mut self, _texture: super::Texture) {}
|
||||
}
|
@ -1178,7 +1178,7 @@ impl Limits {
|
||||
/// max_push_constant_size: 0,
|
||||
/// min_uniform_buffer_offset_alignment: 256,
|
||||
/// min_storage_buffer_offset_alignment: 256,
|
||||
/// max_inter_stage_shader_components: 60,
|
||||
/// max_inter_stage_shader_components: 31,
|
||||
/// max_compute_workgroup_storage_size: 0, // +
|
||||
/// max_compute_invocations_per_workgroup: 0, // +
|
||||
/// max_compute_workgroup_size_x: 0, // +
|
||||
@ -1204,6 +1204,9 @@ impl Limits {
|
||||
max_compute_workgroup_size_z: 0,
|
||||
max_compute_workgroups_per_dimension: 0,
|
||||
|
||||
// Value supported by Intel Celeron B830 on Windows (OpenGL 3.1)
|
||||
max_inter_stage_shader_components: 31,
|
||||
|
||||
// Most of the values should be the same as the downlevel defaults
|
||||
..Self::downlevel_defaults()
|
||||
}
|
||||
|
@ -61,10 +61,10 @@ features = ["raw-window-handle"]
|
||||
workspace = true
|
||||
features = ["metal"]
|
||||
|
||||
# We want the wgpu-core Direct3D backends on Windows.
|
||||
# We want the wgpu-core Direct3D backends and OpenGL (via WGL) on Windows.
|
||||
[target.'cfg(windows)'.dependencies.wgc]
|
||||
workspace = true
|
||||
features = ["dx11", "dx12"]
|
||||
features = ["dx11", "dx12", "gles"]
|
||||
|
||||
# We want the wgpu-core Vulkan backend on Unix (but not emscripten, macOS, iOS) and Windows.
|
||||
[target.'cfg(any(windows, all(unix, not(target_os = "emscripten"), not(target_os = "ios"), not(target_os = "macos"))))'.dependencies.wgc]
|
||||
|
Loading…
Reference in New Issue
Block a user