blob: 6208fde7bc9da3088db7ce989866c2e2c8685720 [file] [log] [blame]
// Copyright © 2019 piet-gpu developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This is a Windows-specific error mechanism (adapted from piet-dx12),
//! but we should adapt it to be more general.
use winapi::shared::winerror;
pub enum Error {
Hresult(winerror::HRESULT),
ExplainedHr(&'static str, winerror::HRESULT),
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::Hresult(hr) => write!(f, "hresult {:x}", hr),
Error::ExplainedHr(exp, hr) => {
write!(f, "{}: ", exp)?;
write_hr(f, *hr)
}
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl std::error::Error for Error {}
/// Strings for errors we're likely to see.
///
/// See https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-error
fn err_str_for_hr(hr: winerror::HRESULT) -> Option<&'static str> {
Some(match hr as u32 {
0x80004005 => "E_FAIL",
0x80070057 => "E_INVALIDARG",
0x887a0001 => "DXGI_ERROR_INVALID_CALL",
0x887a0002 => "DXGI_ERROR_NOT_FOUND",
0x887a0004 => "DXGI_ERROR_UNSUPPORTED",
0x887a0005 => "DXGI_ERROR_DEVICE_REMOVED",
0x887a0006 => "DXGI_ERROR_DEVICE_HUNG",
_ => return None,
})
}
fn write_hr(f: &mut std::fmt::Formatter, hr: winerror::HRESULT) -> std::fmt::Result {
if let Some(err_str) = err_str_for_hr(hr) {
write!(f, "{:x} ({})", hr, err_str)
} else {
write!(f, "{:x}", hr)
}
}
pub type D3DResult<T> = (T, winerror::HRESULT);
pub fn error_if_failed_else_value<T>(result: D3DResult<T>) -> Result<T, Error> {
let (result_value, hresult) = result;
if winerror::SUCCEEDED(hresult) {
Ok(result_value)
} else {
Err(Error::Hresult(hresult))
}
}
pub fn error_if_failed_else_unit(hresult: winerror::HRESULT) -> Result<(), Error> {
error_if_failed_else_value(((), hresult))
}
pub fn explain_error(hresult: winerror::HRESULT, explanation: &'static str) -> Result<(), Error> {
if winerror::SUCCEEDED(hresult) {
Ok(())
} else {
Err(Error::ExplainedHr(explanation, hresult))
}
}