refactor(frame): narrow make_device's unsafe to the FFI calls themselves
First slice of the `unsafe_op_in_unsafe_fn` work on the Windows-gated code, and a
deliberate demonstration of the shape the rest should take.
`cargo fix` is NOT the tool here. Its suggestion for this lint wraps the entire
function body:
pub unsafe fn make_device(..) -> Result<..> { unsafe {
..40 lines..
}}
One block spanning everything, `{ unsafe {` / `}}` bracing, and — the actual problem
— zero change in how much code runs unchecked. It makes the status quo explicit
rather than smaller, which is the opposite of the goal.
Narrowed by hand instead: four blocks, each around the FFI call that needs it
(`D3D11CreateDevice`, two `SetGPUThreadPriority`, `SetMaximumFrameLatency`), each
with its own SAFETY note. The `Option` handling, the `?`, the `if let Ok(..)` casts
and the `tracing!` calls are back outside, where the compiler checks them. Roughly 40
unchecked lines become 6.
Fixed two of my own mistakes in the same pass: `elevate_process_gpu_priority` and
`auto_priority_gate` are ALREADY safe fns, and I had wrapped their calls in `unsafe`
out of momentum. Unnecessary `unsafe` is not free — it is the same "this is scary"
noise the lint exists to remove, and the compiler only warns about it. That mistake
is a good argument against doing the remaining ~590 sites mechanically.
pf-frame drops 23 -> 19 E0133. The remaining three functions in this file need a
different answer, not just narrowing: `enable_inc_base_priority` takes no arguments
and touches only the current process's own token, so it has NO caller contract and
should become a SAFE fn with unsafe blocks inside — which removes an `unsafe fn`
rather than decorating it. Same likely for `hags_enabled(LUID)`, whose only argument
is a plain value.
Verified on Windows .47: pf-frame checks clean at EXITCODE=0, no errors, no
unused-unsafe warnings.
This commit is contained in:
+21
-14
@@ -101,17 +101,21 @@ pub fn pack_luid(luid: LUID) -> i64 {
|
|||||||
pub unsafe fn make_device(adapter: &IDXGIAdapter1) -> Result<(ID3D11Device, ID3D11DeviceContext)> {
|
pub unsafe fn make_device(adapter: &IDXGIAdapter1) -> Result<(ID3D11Device, ID3D11DeviceContext)> {
|
||||||
let mut device: Option<ID3D11Device> = None;
|
let mut device: Option<ID3D11Device> = None;
|
||||||
let mut context: Option<ID3D11DeviceContext> = None;
|
let mut context: Option<ID3D11DeviceContext> = None;
|
||||||
D3D11CreateDevice(
|
// SAFETY: `adapter` is live for the call (caller contract). The two out-params are local
|
||||||
adapter,
|
// `Option`s the callee only writes, and both are checked below before use.
|
||||||
D3D_DRIVER_TYPE_UNKNOWN,
|
unsafe {
|
||||||
HMODULE::default(),
|
D3D11CreateDevice(
|
||||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
adapter,
|
||||||
Some(&[D3D_FEATURE_LEVEL_11_0]),
|
D3D_DRIVER_TYPE_UNKNOWN,
|
||||||
D3D11_SDK_VERSION,
|
HMODULE::default(),
|
||||||
Some(&mut device),
|
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||||
None,
|
Some(&[D3D_FEATURE_LEVEL_11_0]),
|
||||||
Some(&mut context),
|
D3D11_SDK_VERSION,
|
||||||
)
|
Some(&mut device),
|
||||||
|
None,
|
||||||
|
Some(&mut context),
|
||||||
|
)
|
||||||
|
}
|
||||||
.context("D3D11CreateDevice")?;
|
.context("D3D11CreateDevice")?;
|
||||||
let device = device.context("null D3D11 device")?;
|
let device = device.context("null D3D11 device")?;
|
||||||
let context = context.context("null D3D11 context")?;
|
let context = context.context("null D3D11 context")?;
|
||||||
@@ -127,14 +131,17 @@ pub unsafe fn make_device(adapter: &IDXGIAdapter1) -> Result<(ID3D11Device, ID3D
|
|||||||
elevate_process_gpu_priority();
|
elevate_process_gpu_priority();
|
||||||
if let Ok(dxgi_dev) = device.cast::<IDXGIDevice>() {
|
if let Ok(dxgi_dev) = device.cast::<IDXGIDevice>() {
|
||||||
// The absolute max GPU thread priority (0x4000001E; the same value Sunshine/Apollo use); fall back to relative +7.
|
// The absolute max GPU thread priority (0x4000001E; the same value Sunshine/Apollo use); fall back to relative +7.
|
||||||
if dxgi_dev.SetGPUThreadPriority(0x4000_001E).is_err()
|
// SAFETY: `dxgi_dev` is a live interface just obtained by a checked `cast`; both calls take
|
||||||
&& dxgi_dev.SetGPUThreadPriority(7).is_err()
|
// a scalar and only report failure through their return value.
|
||||||
|
if unsafe { dxgi_dev.SetGPUThreadPriority(0x4000_001E) }.is_err()
|
||||||
|
&& unsafe { dxgi_dev.SetGPUThreadPriority(7) }.is_err()
|
||||||
{
|
{
|
||||||
tracing::warn!("SetGPUThreadPriority failed (run as admin/SYSTEM for GPU priority)");
|
tracing::warn!("SetGPUThreadPriority failed (run as admin/SYSTEM for GPU priority)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(dxgi1) = device.cast::<IDXGIDevice1>() {
|
if let Ok(dxgi1) = device.cast::<IDXGIDevice1>() {
|
||||||
let _ = dxgi1.SetMaximumFrameLatency(1);
|
// SAFETY: `dxgi1` is a live interface from a checked `cast`; the arg is a scalar.
|
||||||
|
let _ = unsafe { dxgi1.SetMaximumFrameLatency(1) };
|
||||||
}
|
}
|
||||||
// REALTIME auto-gate (gpu-contention §5.C / latency plan T2.3) — needs the device's adapter,
|
// REALTIME auto-gate (gpu-contention §5.C / latency plan T2.3) — needs the device's adapter,
|
||||||
// so it runs here, after creation; internally once-per-process.
|
// so it runs here, after creation; internally once-per-process.
|
||||||
|
|||||||
Reference in New Issue
Block a user