Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Bottom level categories:

#### Vulkan

- Work around Arm proprietary drivers (observed on r54p2, Mali-G715 / Pixel 9 Pro) ignoring negative viewport heights, which flipped every render pass vertically: on those drivers Y is now flipped in the vertex shader epilogue with positive-height viewports and inverted front-face winding. By @lexoliu in [#10057](https://github.com/gfx-rs/wgpu/issues/10057).
- Add OpenHarmony surface support via `VK_OHOS_surface`. Previously the Vulkan backend could not create a surface on OpenHarmony, leaving GLES as the only usable backend. By @ozongzi in [#9908](https://github.com/gfx-rs/wgpu/pull/9908).
- Stop passing an un-waited fence to `vkAcquireNextImageKHR` on non-Windows platforms, which triggered `VUID-vkAcquireNextImageKHR-fence-10066` validation errors every frame since v30.0.0. By @ErichDonGubler in [#9855](https://github.com/gfx-rs/wgpu/issues/9855).

Expand Down
12 changes: 12 additions & 0 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,13 @@ impl super::Instance {
super::Workarounds::FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16,
phd_capabilities.properties.vendor_id == db::nvidia::VENDOR,
);
workarounds.set(
super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT,
phd_capabilities
.driver
.as_ref()
.is_some_and(|driver| driver.driver_id == vk::DriverId::ARM_PROPRIETARY),
);
};

if let Some(driver) = phd_capabilities.driver {
Expand Down Expand Up @@ -2787,6 +2794,11 @@ impl super::Adapter {
spv::WriterFlags::LABEL_VARYINGS,
self.phd_capabilities.properties.vendor_id != crate::auxil::db::qualcomm::VENDOR,
);
flags.set(
spv::WriterFlags::ADJUST_COORDINATE_SPACE,
self.workarounds
.contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT),
);
flags.set(
spv::WriterFlags::FORCE_POINT_SIZE,
//Note: we could technically disable this when we are compiling separate entry points,
Expand Down
66 changes: 50 additions & 16 deletions wgpu-hal/src/vulkan/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,14 +862,31 @@ impl crate::CommandEncoder for super::CommandEncoder {
height: desc.extent.height,
},
};
let vk_viewports = [vk::Viewport {
x: 0.0,
y: desc.extent.height as f32,
width: desc.extent.width as f32,
height: -(desc.extent.height as f32),
min_depth: 0.0,
max_depth: 1.0,
}];
let vk_viewports = if self
.device
.workarounds
.contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT)
{
// The Y-flip happens in the vertex shader epilogue instead; see the
// workaround's documentation.
[vk::Viewport {
x: 0.0,
y: 0.0,
width: desc.extent.width as f32,
height: desc.extent.height as f32,
min_depth: 0.0,
max_depth: 1.0,
}]
} else {
[vk::Viewport {
x: 0.0,
y: desc.extent.height as f32,
width: desc.extent.width as f32,
height: -(desc.extent.height as f32),
min_depth: 0.0,
max_depth: 1.0,
}]
};

let raw_pass = self.device.make_render_pass(rp_key).unwrap();
fb_key.raw_pass = raw_pass;
Expand Down Expand Up @@ -1027,14 +1044,31 @@ impl crate::CommandEncoder for super::CommandEncoder {
};
}
unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {
let vk_viewports = [vk::Viewport {
x: rect.x,
y: rect.y + rect.h,
width: rect.w,
height: -rect.h, // flip Y
min_depth: depth_range.start,
max_depth: depth_range.end,
}];
let vk_viewports = if self
.device
.workarounds
.contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT)
{
// The Y-flip happens in the vertex shader epilogue instead; see the
// workaround's documentation.
[vk::Viewport {
x: rect.x,
y: rect.y,
width: rect.w,
height: rect.h,
min_depth: depth_range.start,
max_depth: depth_range.end,
}]
} else {
[vk::Viewport {
x: rect.x,
y: rect.y + rect.h,
width: rect.w,
height: -rect.h, // flip Y
min_depth: depth_range.start,
max_depth: depth_range.end,
}]
};
unsafe {
self.device
.raw
Expand Down
21 changes: 20 additions & 1 deletion wgpu-hal/src/vulkan/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2026,9 +2026,23 @@ impl crate::Device for super::Device {
None => None,
};

// Flipping Y in the vertex shader instead of the viewport inverts the
// winding of every triangle, so the front face must be inverted too.
let flip_winding = self
.shared
.workarounds
.contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT);
let front_face = if flip_winding {
match desc.primitive.front_face {
wgt::FrontFace::Ccw => wgt::FrontFace::Cw,
wgt::FrontFace::Cw => wgt::FrontFace::Ccw,
}
} else {
desc.primitive.front_face
};
let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
.polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
.front_face(conv::map_front_face(desc.primitive.front_face))
.front_face(conv::map_front_face(front_face))
.line_width(1.0)
.depth_clamp_enable(desc.primitive.unclipped_depth);
if let Some(face) = desc.primitive.cull_mode {
Expand Down Expand Up @@ -2066,6 +2080,11 @@ impl crate::Device for super::Device {
let s = &ds.stencil;
let front = conv::map_stencil_face(&s.front, s.read_mask, s.write_mask);
let back = conv::map_stencil_face(&s.back, s.read_mask, s.write_mask);
let (front, back) = if flip_winding {
(back, front)
} else {
(front, back)
};
Comment on lines 2080 to +2087
vk_depth_stencil = vk_depth_stencil
.stencil_test_enable(true)
.front(front)
Expand Down
7 changes: 7 additions & 0 deletions wgpu-hal/src/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,13 @@ bitflags::bitflags!(
/// As such, we need to make sure all calls to vkCmdFillBuffer are aligned to 16 bytes
/// if they cover a range of 4096 bytes or more.
const FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16 = 0x4;
/// Arm's proprietary driver (observed on r54p2, Mali-G715 / Pixel 9 Pro,
/// Android 16) rasterizes as if the viewport height were positive even when
/// a negative-height viewport is submitted, undoing the Y-flip wgpu relies
/// on to map WebGPU clip space onto Vulkan's. Flip Y in the vertex shader
/// epilogue instead, submit positive-height viewports, and invert the
/// front-face winding to keep culling and stencil facing correct.
const IGNORED_NEGATIVE_VIEWPORT_HEIGHT = 0x8;
}
);

Expand Down