Merge pull request #602 from mahkoh/jorth/multi-nvidia-fixes
metal: improve buffer allocation failures
This commit is contained in:
commit
8aeae2d2af
4 changed files with 304 additions and 67 deletions
|
|
@ -18,6 +18,7 @@ use {
|
||||||
},
|
},
|
||||||
dbus::{DbusError, SignalHandler},
|
dbus::{DbusError, SignalHandler},
|
||||||
drm_feedback::DrmFeedback,
|
drm_feedback::DrmFeedback,
|
||||||
|
format::Format,
|
||||||
gfx_api::{GfxError, SyncFile},
|
gfx_api::{GfxError, SyncFile},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_output::OutputId,
|
wl_output::OutputId,
|
||||||
|
|
@ -48,14 +49,15 @@ use {
|
||||||
smallmap::SmallMap,
|
smallmap::SmallMap,
|
||||||
syncqueue::SyncQueue,
|
syncqueue::SyncQueue,
|
||||||
},
|
},
|
||||||
video::{drm::DrmError, gbm::GbmError},
|
video::{Modifier, drm::DrmError, gbm::GbmError},
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
|
indexmap::IndexSet,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Display, Formatter},
|
||||||
future::pending,
|
future::pending,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -85,16 +87,6 @@ pub enum MetalError {
|
||||||
UpdateProperties(#[source] DrmError),
|
UpdateProperties(#[source] DrmError),
|
||||||
#[error("Could not create a render context")]
|
#[error("Could not create a render context")]
|
||||||
CreateRenderContex(#[source] GfxError),
|
CreateRenderContex(#[source] GfxError),
|
||||||
#[error("Could not allocate scanout buffer")]
|
|
||||||
ScanoutBuffer(#[source] GbmError),
|
|
||||||
#[error("addfb2 failed")]
|
|
||||||
Framebuffer(#[source] DrmError),
|
|
||||||
#[error("Could not import a framebuffer into the graphics API")]
|
|
||||||
ImportFb(#[source] GfxError),
|
|
||||||
#[error("Could not import a texture into the graphics API")]
|
|
||||||
ImportTexture(#[source] GfxError),
|
|
||||||
#[error("Could not import an image into the graphics API")]
|
|
||||||
ImportImage(#[source] GfxError),
|
|
||||||
#[error("Could not perform modeset")]
|
#[error("Could not perform modeset")]
|
||||||
Modeset(#[source] BackendConnectorTransactionError),
|
Modeset(#[source] BackendConnectorTransactionError),
|
||||||
#[error("Could not enable atomic modesetting")]
|
#[error("Could not enable atomic modesetting")]
|
||||||
|
|
@ -111,22 +103,12 @@ pub enum MetalError {
|
||||||
DevicePauseSignalHandler(#[source] DbusError),
|
DevicePauseSignalHandler(#[source] DbusError),
|
||||||
#[error("Could not create device-resumed signal handler")]
|
#[error("Could not create device-resumed signal handler")]
|
||||||
DeviceResumeSignalHandler(#[source] DbusError),
|
DeviceResumeSignalHandler(#[source] DbusError),
|
||||||
#[error("Device render context does not support required format {0}")]
|
|
||||||
MissingDevFormat(&'static str),
|
|
||||||
#[error("Render context does not support required format {0}")]
|
|
||||||
MissingRenderFormat(&'static str),
|
|
||||||
#[error("Device cannot scan out any buffers writable by its GFX API (format {0})")]
|
|
||||||
MissingDevModifier(&'static str),
|
|
||||||
#[error("Device GFX API cannot read any buffers writable by the render GFX API (format {0})")]
|
|
||||||
MissingRenderModifier(&'static str),
|
|
||||||
#[error("Could not render the frame")]
|
#[error("Could not render the frame")]
|
||||||
RenderFrame(#[source] GfxError),
|
RenderFrame(#[source] GfxError),
|
||||||
#[error("Could not copy frame to output device")]
|
#[error("Could not copy frame to output device")]
|
||||||
CopyToOutput(#[source] GfxError),
|
CopyToOutput(#[source] GfxError),
|
||||||
#[error("Could not perform atomic commit")]
|
#[error("Could not perform atomic commit")]
|
||||||
Commit(#[source] DrmError),
|
Commit(#[source] DrmError),
|
||||||
#[error("Could not clear framebuffer")]
|
|
||||||
Clear(#[source] GfxError),
|
|
||||||
#[error("The present configuration is out of date")]
|
#[error("The present configuration is out of date")]
|
||||||
OutOfDate,
|
OutOfDate,
|
||||||
#[error("Could not add connector to transaction")]
|
#[error("Could not add connector to transaction")]
|
||||||
|
|
@ -135,6 +117,119 @@ pub enum MetalError {
|
||||||
CalculateDrmState(#[source] BackendConnectorTransactionError),
|
CalculateDrmState(#[source] BackendConnectorTransactionError),
|
||||||
#[error("Could not calculate DRM change set")]
|
#[error("Could not calculate DRM change set")]
|
||||||
CalculateDrmChange(#[source] BackendConnectorTransactionError),
|
CalculateDrmChange(#[source] BackendConnectorTransactionError),
|
||||||
|
#[error("Could not create plane buffer")]
|
||||||
|
AllocateScanoutBuffer(#[source] Box<ScanoutBufferError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ScanoutBufferErrorKind {
|
||||||
|
#[error("Scanout device: The format is not supported")]
|
||||||
|
SodUnsupportedFormat,
|
||||||
|
#[error(
|
||||||
|
"Scanout device: The intersection of the modifiers supported by the plane and modifiers writable by the gfx API is empty"
|
||||||
|
)]
|
||||||
|
SodNoWritableModifier,
|
||||||
|
#[error("Scanout device: Buffer allocation failed")]
|
||||||
|
SodBufferAllocation(#[source] GbmError),
|
||||||
|
#[error("Scanout device: addfb2 failed")]
|
||||||
|
SodAddfb2(#[source] DrmError),
|
||||||
|
#[error("Scanout device: Could not import SCANOUT buffer into the gfx API")]
|
||||||
|
SodImportSodImage(#[source] GfxError),
|
||||||
|
#[error("Scanout device: Could not turn imported SCANOUT buffer into gfx API FB")]
|
||||||
|
SodImportFb(#[source] GfxError),
|
||||||
|
#[error("Scanout device: Could not clear SCANOUT buffer")]
|
||||||
|
SodClear(#[source] GfxError),
|
||||||
|
#[error("Scanout device: Could not turn imported SCANOUT buffer into gfx API texture")]
|
||||||
|
SodImportSodTexture(#[source] GfxError),
|
||||||
|
#[error("Render device: The format is not supported")]
|
||||||
|
RenderUnsupportedFormat,
|
||||||
|
#[error(
|
||||||
|
"Render device: The intersection of the modifiers readable by the scanout device and modifiers writable by the gfx API is empty"
|
||||||
|
)]
|
||||||
|
RenderNoWritableModifier,
|
||||||
|
#[error("Render device: Buffer allocation failed")]
|
||||||
|
RenderBufferAllocation(#[source] GbmError),
|
||||||
|
#[error("Render device: Could not import RENDER buffer into the gfx API")]
|
||||||
|
RenderImportImage(#[source] GfxError),
|
||||||
|
#[error("Render device: Could not turn imported RENDER buffer into gfx API FB")]
|
||||||
|
RenderImportFb(#[source] GfxError),
|
||||||
|
#[error("Render device: Could not clear RENDER buffer")]
|
||||||
|
RenderClear(#[source] GfxError),
|
||||||
|
#[error("Render device: Could not turn imported RENDER buffer into gfx API texture")]
|
||||||
|
RenderImportRenderTexture(#[source] GfxError),
|
||||||
|
#[error("Scanout device: Could not import RENDER buffer into the gfx API")]
|
||||||
|
SodImportRenderImage(#[source] GfxError),
|
||||||
|
#[error("Scanout device: Could not turn imported RENDER buffer into gfx API texture")]
|
||||||
|
SodImportRenderTexture(#[source] GfxError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScanoutBufferError {
|
||||||
|
dev: String,
|
||||||
|
format: &'static Format,
|
||||||
|
plane_modifiers: IndexSet<Modifier>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
cursor: bool,
|
||||||
|
dev_gfx_write_modifiers: Option<IndexSet<Modifier>>,
|
||||||
|
dev_gfx_read_modifiers: Option<IndexSet<Modifier>>,
|
||||||
|
dev_modifiers_possible: Option<IndexSet<Modifier>>,
|
||||||
|
dev_usage: Option<u32>,
|
||||||
|
dev_modifier: Option<Modifier>,
|
||||||
|
render_name: Option<String>,
|
||||||
|
render_gfx_write_modifiers: Option<IndexSet<Modifier>>,
|
||||||
|
render_modifiers_possible: Option<IndexSet<Modifier>>,
|
||||||
|
render_usage: Option<u32>,
|
||||||
|
render_modifier: Option<Modifier>,
|
||||||
|
kind: ScanoutBufferErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ScanoutBufferError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f)?;
|
||||||
|
writeln!(f, "scanout device: {}", self.dev)?;
|
||||||
|
writeln!(f, "format: {}", self.format.name)?;
|
||||||
|
writeln!(f, "plane modifiers: {:x?}", self.plane_modifiers)?;
|
||||||
|
writeln!(f, "size: {}x{}", self.width, self.height)?;
|
||||||
|
writeln!(f, "cursor: {}", self.cursor)?;
|
||||||
|
if let Some(v) = &self.dev_gfx_write_modifiers {
|
||||||
|
writeln!(f, "scanout gfx writable modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dev_modifiers_possible {
|
||||||
|
writeln!(f, "scanout dev possible modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dev_usage {
|
||||||
|
writeln!(f, "scanout dev gbm usage: {:x}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dev_modifier {
|
||||||
|
writeln!(f, "scanout dev modifier: {:x}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.render_name {
|
||||||
|
writeln!(f, "render device: {}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.render_gfx_write_modifiers {
|
||||||
|
writeln!(f, "render gfx writable modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.dev_gfx_read_modifiers {
|
||||||
|
writeln!(f, "scanout gfx readable modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.render_modifiers_possible {
|
||||||
|
writeln!(f, "render dev possible modifiers: {:x?}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.render_usage {
|
||||||
|
writeln!(f, "render dev gbm usage: {:x}", v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = &self.render_modifier {
|
||||||
|
writeln!(f, "render dev modifier: {:x}", v)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ScanoutBufferError {
|
||||||
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
|
Some(&self.kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetalBackend {
|
pub struct MetalBackend {
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,10 @@ impl MetalBackend {
|
||||||
Some(d) if d.id == id => d,
|
Some(d) if d.id == id => d,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
log::info!(
|
||||||
|
"Received logind response for drm device {}",
|
||||||
|
dev.devnode.to_bytes().as_bstr(),
|
||||||
|
);
|
||||||
let res = match res {
|
let res = match res {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,7 @@ impl MetalDeviceTransaction {
|
||||||
}
|
}
|
||||||
*plane = p.id;
|
*plane = p.id;
|
||||||
unused_planes.remove(&p.id);
|
unused_planes.remove(&p.id);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if crtc_planes.primary.is_none() {
|
if crtc_planes.primary.is_none() {
|
||||||
|
|
@ -417,11 +418,11 @@ impl MetalDeviceTransaction {
|
||||||
crtc.new.mode_blob = Some(Rc::new(blob));
|
crtc.new.mode_blob = Some(Rc::new(blob));
|
||||||
mode.clone()
|
mode.clone()
|
||||||
};
|
};
|
||||||
for plane in [crtc_planes.primary, crtc_planes.cursor] {
|
for plane_id in [&mut crtc_planes.primary, &mut crtc_planes.cursor] {
|
||||||
if plane.is_none() {
|
if plane_id.is_none() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let plane = slf.planes.get_mut(&plane).unwrap();
|
let plane = slf.planes.get_mut(plane_id).unwrap();
|
||||||
plane.new.assigned_crtc = crtc.obj.id;
|
plane.new.assigned_crtc = crtc.obj.id;
|
||||||
plane.changed.extend(crtc.changed.iter().cloned());
|
plane.changed.extend(crtc.changed.iter().cloned());
|
||||||
let (x, y, width, height, format, old_buffers);
|
let (x, y, width, height, format, old_buffers);
|
||||||
|
|
@ -483,7 +484,8 @@ impl MetalDeviceTransaction {
|
||||||
None => {
|
None => {
|
||||||
let modifiers = &plane.obj.formats.get(&format.drm).unwrap().modifiers;
|
let modifiers = &plane.obj.formats.get(&format.drm).unwrap().modifiers;
|
||||||
connector.changed.set(true);
|
connector.changed.set(true);
|
||||||
let buffers = slf
|
let is_cursor = plane.obj.ty == PlaneType::Cursor;
|
||||||
|
let res = slf
|
||||||
.dev
|
.dev
|
||||||
.dev
|
.dev
|
||||||
.backend
|
.backend
|
||||||
|
|
@ -494,15 +496,28 @@ impl MetalDeviceTransaction {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
render_ctx,
|
render_ctx,
|
||||||
plane.obj.ty == PlaneType::Cursor,
|
is_cursor,
|
||||||
)
|
)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
BackendConnectorTransactionError::AllocateScanoutBuffers(
|
BackendConnectorTransactionError::AllocateScanoutBuffers(
|
||||||
connector.obj.kernel_id(),
|
connector.obj.kernel_id(),
|
||||||
Box::new(e),
|
Box::new(e),
|
||||||
)
|
)
|
||||||
})?;
|
});
|
||||||
let buffers = Rc::new(buffers);
|
if let Err(e) = &res
|
||||||
|
&& is_cursor
|
||||||
|
{
|
||||||
|
log::error!(
|
||||||
|
"Could not allocate buffers for cursor plane of {}: {}",
|
||||||
|
connector.obj.kernel_id(),
|
||||||
|
ErrorFmt(e),
|
||||||
|
);
|
||||||
|
plane.new = DrmPlaneState::default();
|
||||||
|
unused_planes.insert(*plane_id, ());
|
||||||
|
*plane_id = DrmPlane::NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let buffers = Rc::new(res?);
|
||||||
plane.new.buffers = Some(buffers.clone());
|
plane.new.buffers = Some(buffers.clone());
|
||||||
new_buffers = Some(buffers.clone());
|
new_buffers = Some(buffers.clone());
|
||||||
buffers
|
buffers
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
backends::metal::{
|
backends::metal::{
|
||||||
MetalBackend, MetalError,
|
MetalBackend, MetalError, ScanoutBufferError, ScanoutBufferErrorKind,
|
||||||
present::{
|
present::{
|
||||||
DEFAULT_POST_COMMIT_MARGIN, DEFAULT_PRE_COMMIT_MARGIN, DirectScanoutCache,
|
DEFAULT_POST_COMMIT_MARGIN, DEFAULT_PRE_COMMIT_MARGIN, DirectScanoutCache,
|
||||||
POST_COMMIT_MARGIN_DELTA, PresentFb,
|
POST_COMMIT_MARGIN_DELTA, PresentFb,
|
||||||
|
|
@ -41,7 +41,7 @@ use {
|
||||||
asyncevent::AsyncEvent, binary_search_map::BinarySearchMap, bitflags::BitflagsExt,
|
asyncevent::AsyncEvent, binary_search_map::BinarySearchMap, bitflags::BitflagsExt,
|
||||||
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||||
geometric_decay::GeometricDecay, numcell::NumCell, on_change::OnChange,
|
geometric_decay::GeometricDecay, numcell::NumCell, on_change::OnChange,
|
||||||
opaque_cell::OpaqueCell, ordered_float::F64, oserror::OsError,
|
on_drop::OnDrop2, opaque_cell::OpaqueCell, ordered_float::F64, oserror::OsError,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
INVALID_MODIFIER, Modifier,
|
INVALID_MODIFIER, Modifier,
|
||||||
|
|
@ -88,6 +88,7 @@ pub struct MetalRenderContext {
|
||||||
pub dev_id: DrmDeviceId,
|
pub dev_id: DrmDeviceId,
|
||||||
pub gfx: Rc<dyn GfxContext>,
|
pub gfx: Rc<dyn GfxContext>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
|
pub devnode: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetalDrmDevice {
|
pub struct MetalDrmDevice {
|
||||||
|
|
@ -1083,6 +1084,11 @@ fn create_connector(
|
||||||
dev: &Rc<MetalDrmDevice>,
|
dev: &Rc<MetalDrmDevice>,
|
||||||
) -> Result<(Rc<MetalConnector>, ConnectorFutures), DrmError> {
|
) -> Result<(Rc<MetalConnector>, ConnectorFutures), DrmError> {
|
||||||
let display = create_connector_display_data(connector, dev)?;
|
let display = create_connector_display_data(connector, dev)?;
|
||||||
|
log::info!(
|
||||||
|
"Creating connector {} for device {}",
|
||||||
|
display.connector_id,
|
||||||
|
dev.devnode.as_bytes().as_bstr(),
|
||||||
|
);
|
||||||
let slf = Rc::new(MetalConnector {
|
let slf = Rc::new(MetalConnector {
|
||||||
id: connector,
|
id: connector,
|
||||||
kernel_id: Cell::new(display.connector_id),
|
kernel_id: Cell::new(display.connector_id),
|
||||||
|
|
@ -1799,6 +1805,11 @@ impl MetalBackend {
|
||||||
for c in removed_connectors {
|
for c in removed_connectors {
|
||||||
dev.futures.remove(&c);
|
dev.futures.remove(&c);
|
||||||
if let Some(c) = dev.connectors.remove(&c) {
|
if let Some(c) = dev.connectors.remove(&c) {
|
||||||
|
log::info!(
|
||||||
|
"Removing connector {} from device {}",
|
||||||
|
c.kernel_id.get(),
|
||||||
|
dev.dev.devnode.as_bytes().as_bstr(),
|
||||||
|
);
|
||||||
if let Some(lease_id) = c.lease.get()
|
if let Some(lease_id) = c.lease.get()
|
||||||
&& let Some(lease) = dev.dev.leases.remove(&lease_id)
|
&& let Some(lease) = dev.dev.leases.remove(&lease_id)
|
||||||
&& !lease.try_revoke()
|
&& !lease.try_revoke()
|
||||||
|
|
@ -1990,6 +2001,7 @@ impl MetalBackend {
|
||||||
dev_id: pending.id,
|
dev_id: pending.id,
|
||||||
gfx,
|
gfx,
|
||||||
gbm: gbm.clone(),
|
gbm: gbm.clone(),
|
||||||
|
devnode: pending.devnode.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut is_nvidia = false;
|
let mut is_nvidia = false;
|
||||||
|
|
@ -2455,6 +2467,7 @@ impl MetalBackend {
|
||||||
dev_id: dev.id,
|
dev_id: dev.id,
|
||||||
gfx,
|
gfx,
|
||||||
gbm: old_ctx.gbm.clone(),
|
gbm: old_ctx.gbm.clone(),
|
||||||
|
devnode: old_ctx.devnode.clone(),
|
||||||
}));
|
}));
|
||||||
if dev.is_render_device() {
|
if dev.is_render_device() {
|
||||||
self.make_render_device(dev, true);
|
self.make_render_device(dev, true);
|
||||||
|
|
@ -2467,7 +2480,11 @@ impl MetalBackend {
|
||||||
|
|
||||||
fn re_init_drm_device(&self, dev: &Rc<MetalDrmDeviceData>) {
|
fn re_init_drm_device(&self, dev: &Rc<MetalDrmDeviceData>) {
|
||||||
if let Err(e) = self.init_drm_device(dev) {
|
if let Err(e) = self.init_drm_device(dev) {
|
||||||
log::error!("Could not initialize device: {}", ErrorFmt(e));
|
log::error!(
|
||||||
|
"Could not initialize drm device {}: {}",
|
||||||
|
dev.dev.devnode.as_bytes().as_bstr(),
|
||||||
|
ErrorFmt(e),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for connector in dev.connectors.lock().values() {
|
for connector in dev.connectors.lock().values() {
|
||||||
if connector.connected() {
|
if connector.connected() {
|
||||||
|
|
@ -2552,7 +2569,11 @@ impl MetalBackend {
|
||||||
Ok(_) => break,
|
Ok(_) => break,
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
};
|
};
|
||||||
log::error!("Could not initialize DRM device: {}", ErrorFmt(&err));
|
log::error!(
|
||||||
|
"Could not initialize DRM device {}: {}",
|
||||||
|
dev.dev.devnode.as_bytes().as_bstr(),
|
||||||
|
ErrorFmt(&err),
|
||||||
|
);
|
||||||
let Some(q) = quirks.pop() else {
|
let Some(q) = quirks.pop() else {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
};
|
};
|
||||||
|
|
@ -2629,25 +2650,102 @@ impl MetalBackend {
|
||||||
damage_queue: DamageQueue,
|
damage_queue: DamageQueue,
|
||||||
blend_buffer: Option<Rc<dyn GfxBlendBuffer>>,
|
blend_buffer: Option<Rc<dyn GfxBlendBuffer>>,
|
||||||
) -> Result<RenderBuffer, MetalError> {
|
) -> Result<RenderBuffer, MetalError> {
|
||||||
|
let mut dev_gfx_write_modifiers = None;
|
||||||
|
let mut dev_gfx_read_modifiers = None;
|
||||||
|
let mut dev_modifiers_possible = None;
|
||||||
|
let mut dev_usage = None;
|
||||||
|
let mut dev_modifier = None;
|
||||||
|
let mut render_name = None;
|
||||||
|
let mut render_gfx_write_modifiers = None;
|
||||||
|
let mut render_modifiers_possible = None;
|
||||||
|
let mut render_usage = None;
|
||||||
|
let mut render_modifier = None;
|
||||||
|
self.create_scanout_buffer_(
|
||||||
|
dev,
|
||||||
|
format,
|
||||||
|
plane_modifiers,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
render_ctx,
|
||||||
|
cursor,
|
||||||
|
damage_queue,
|
||||||
|
blend_buffer,
|
||||||
|
&mut dev_gfx_write_modifiers,
|
||||||
|
&mut dev_gfx_read_modifiers,
|
||||||
|
&mut dev_modifiers_possible,
|
||||||
|
&mut dev_usage,
|
||||||
|
&mut dev_modifier,
|
||||||
|
&mut render_name,
|
||||||
|
&mut render_gfx_write_modifiers,
|
||||||
|
&mut render_modifiers_possible,
|
||||||
|
&mut render_usage,
|
||||||
|
&mut render_modifier,
|
||||||
|
)
|
||||||
|
.map_err(|kind| ScanoutBufferError {
|
||||||
|
dev: dev.devnode.as_bytes().as_bstr().to_string(),
|
||||||
|
format,
|
||||||
|
plane_modifiers: plane_modifiers.clone(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
cursor,
|
||||||
|
dev_gfx_write_modifiers,
|
||||||
|
dev_gfx_read_modifiers,
|
||||||
|
dev_modifiers_possible,
|
||||||
|
dev_usage,
|
||||||
|
dev_modifier,
|
||||||
|
render_name,
|
||||||
|
render_gfx_write_modifiers,
|
||||||
|
render_modifiers_possible,
|
||||||
|
render_usage,
|
||||||
|
render_modifier,
|
||||||
|
kind,
|
||||||
|
})
|
||||||
|
.map_err(Box::new)
|
||||||
|
.map_err(MetalError::AllocateScanoutBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_scanout_buffer_(
|
||||||
|
&self,
|
||||||
|
dev: &Rc<MetalDrmDevice>,
|
||||||
|
format: &'static Format,
|
||||||
|
plane_modifiers: &IndexSet<Modifier>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
render_ctx: &Rc<MetalRenderContext>,
|
||||||
|
cursor: bool,
|
||||||
|
damage_queue: DamageQueue,
|
||||||
|
blend_buffer: Option<Rc<dyn GfxBlendBuffer>>,
|
||||||
|
dbg_dev_gfx_write_modifiers: &mut Option<IndexSet<Modifier>>,
|
||||||
|
dbg_dev_gfx_read_modifiers: &mut Option<IndexSet<Modifier>>,
|
||||||
|
dbg_dev_modifiers_possible: &mut Option<IndexSet<Modifier>>,
|
||||||
|
dbg_dev_usage: &mut Option<u32>,
|
||||||
|
dbg_dev_modifier: &mut Option<Modifier>,
|
||||||
|
dbg_render_name: &mut Option<String>,
|
||||||
|
dbg_render_gfx_write_modifiers: &mut Option<IndexSet<Modifier>>,
|
||||||
|
dbg_render_modifiers_possible: &mut Option<IndexSet<Modifier>>,
|
||||||
|
dbg_render_usage: &mut Option<u32>,
|
||||||
|
dbg_render_modifier: &mut Option<Modifier>,
|
||||||
|
) -> Result<RenderBuffer, ScanoutBufferErrorKind> {
|
||||||
let dev_ctx = dev.ctx.get();
|
let dev_ctx = dev.ctx.get();
|
||||||
let dev_gfx_formats = dev_ctx.gfx.formats();
|
let dev_gfx_formats = dev_ctx.gfx.formats();
|
||||||
let dev_gfx_format = match dev_gfx_formats.get(&format.drm) {
|
let Some(dev_gfx_format) = dev_gfx_formats.get(&format.drm) else {
|
||||||
None => return Err(MetalError::MissingDevFormat(format.name)),
|
return Err(ScanoutBufferErrorKind::SodUnsupportedFormat);
|
||||||
Some(f) => f,
|
|
||||||
};
|
};
|
||||||
|
let send_dev_gfx_write_modifiers = OnDrop2::new(|| {
|
||||||
|
*dbg_dev_gfx_write_modifiers =
|
||||||
|
Some(dev_gfx_format.write_modifiers.keys().copied().collect())
|
||||||
|
});
|
||||||
let possible_modifiers: IndexMap<_, _> = dev_gfx_format
|
let possible_modifiers: IndexMap<_, _> = dev_gfx_format
|
||||||
.write_modifiers
|
.write_modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(m, _)| plane_modifiers.contains(*m))
|
.filter(|(m, _)| plane_modifiers.contains(*m))
|
||||||
.map(|(m, v)| (*m, v))
|
.map(|(m, v)| (*m, v))
|
||||||
.collect();
|
.collect();
|
||||||
|
let send_dev_modifiers_possible = OnDrop2::new(|| {
|
||||||
|
*dbg_dev_modifiers_possible = Some(possible_modifiers.keys().copied().collect())
|
||||||
|
});
|
||||||
if possible_modifiers.is_empty() {
|
if possible_modifiers.is_empty() {
|
||||||
log::warn!("Scanout modifiers: {:?}", plane_modifiers);
|
return Err(ScanoutBufferErrorKind::SodNoWritableModifier);
|
||||||
log::warn!(
|
|
||||||
"DEV GFX modifiers: {:?}",
|
|
||||||
dev_gfx_format.write_modifiers.keys()
|
|
||||||
);
|
|
||||||
return Err(MetalError::MissingDevModifier(format.name));
|
|
||||||
}
|
}
|
||||||
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
||||||
if !needs_render_usage(possible_modifiers.values().copied()) {
|
if !needs_render_usage(possible_modifiers.values().copied()) {
|
||||||
|
|
@ -2656,6 +2754,7 @@ impl MetalBackend {
|
||||||
if cursor {
|
if cursor {
|
||||||
usage |= GBM_BO_USE_LINEAR;
|
usage |= GBM_BO_USE_LINEAR;
|
||||||
};
|
};
|
||||||
|
*dbg_dev_usage = Some(usage);
|
||||||
let dev_bo = dev.gbm.create_bo(
|
let dev_bo = dev.gbm.create_bo(
|
||||||
&self.state.dma_buf_ids,
|
&self.state.dma_buf_ids,
|
||||||
width,
|
width,
|
||||||
|
|
@ -2666,19 +2765,20 @@ impl MetalBackend {
|
||||||
);
|
);
|
||||||
let dev_bo = match dev_bo {
|
let dev_bo = match dev_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodBufferAllocation(e)),
|
||||||
};
|
};
|
||||||
|
*dbg_dev_modifier = Some(dev_bo.dmabuf().modifier);
|
||||||
let drm_fb = match dev.master.add_fb(dev_bo.dmabuf(), None) {
|
let drm_fb = match dev.master.add_fb(dev_bo.dmabuf(), None) {
|
||||||
Ok(fb) => Rc::new(fb),
|
Ok(fb) => Rc::new(fb),
|
||||||
Err(e) => return Err(MetalError::Framebuffer(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodAddfb2(e)),
|
||||||
};
|
};
|
||||||
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(dev_bo.dmabuf()) {
|
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(dev_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodImportSodImage(e)),
|
||||||
};
|
};
|
||||||
let dev_fb = match dev_img.clone().to_framebuffer() {
|
let dev_fb = match dev_img.clone().to_framebuffer() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodImportFb(e)),
|
||||||
};
|
};
|
||||||
dev_fb
|
dev_fb
|
||||||
.clear(
|
.clear(
|
||||||
|
|
@ -2686,57 +2786,74 @@ impl MetalBackend {
|
||||||
ReleaseSync::None,
|
ReleaseSync::None,
|
||||||
self.state.color_manager.srgb_gamma22(),
|
self.state.color_manager.srgb_gamma22(),
|
||||||
)
|
)
|
||||||
.map_err(MetalError::Clear)?;
|
.map_err(ScanoutBufferErrorKind::SodClear)?;
|
||||||
|
let render_gfx_formats;
|
||||||
|
let render_possible_modifiers: IndexMap<_, _>;
|
||||||
|
let mut send_render_dev_name = None;
|
||||||
|
let mut send_render_gfx_write_modifiers = None;
|
||||||
|
let mut send_dev_gfx_read_modifiers = None;
|
||||||
|
let mut send_render_possible_modifiers = None;
|
||||||
let (dev_tex, render_tex, render_fb, render_bo) = if dev.id == render_ctx.dev_id {
|
let (dev_tex, render_tex, render_fb, render_bo) = if dev.id == render_ctx.dev_id {
|
||||||
let render_tex = match dev_img.to_texture() {
|
let render_tex = match dev_img.to_texture() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportTexture(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodImportSodTexture(e)),
|
||||||
};
|
};
|
||||||
(None, render_tex, None, None)
|
(None, render_tex, None, None)
|
||||||
} else {
|
} else {
|
||||||
|
send_render_dev_name = Some(OnDrop2::new(|| {
|
||||||
|
*dbg_render_name = Some(render_ctx.devnode.as_bytes().as_bstr().to_string());
|
||||||
|
}));
|
||||||
// Create a _bridge_ BO in the render device
|
// Create a _bridge_ BO in the render device
|
||||||
let render_gfx_formats = render_ctx.gfx.formats();
|
render_gfx_formats = render_ctx.gfx.formats();
|
||||||
let render_gfx_format = match render_gfx_formats.get(&format.drm) {
|
let render_gfx_format = match render_gfx_formats.get(&format.drm) {
|
||||||
None => return Err(MetalError::MissingRenderFormat(format.name)),
|
None => return Err(ScanoutBufferErrorKind::RenderUnsupportedFormat),
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
};
|
};
|
||||||
let possible_modifiers: IndexMap<_, _> = render_gfx_format
|
send_render_gfx_write_modifiers = Some(OnDrop2::new(|| {
|
||||||
|
*dbg_render_gfx_write_modifiers =
|
||||||
|
Some(render_gfx_format.write_modifiers.keys().copied().collect())
|
||||||
|
}));
|
||||||
|
send_dev_gfx_read_modifiers = Some(OnDrop2::new(|| {
|
||||||
|
*dbg_dev_gfx_read_modifiers = Some(dev_gfx_format.read_modifiers.clone());
|
||||||
|
}));
|
||||||
|
render_possible_modifiers = render_gfx_format
|
||||||
.write_modifiers
|
.write_modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(m, _)| dev_gfx_format.read_modifiers.contains(*m))
|
.filter(|(m, _)| dev_gfx_format.read_modifiers.contains(*m))
|
||||||
.map(|(m, v)| (*m, v))
|
.map(|(m, v)| (*m, v))
|
||||||
.collect();
|
.collect();
|
||||||
if possible_modifiers.is_empty() {
|
send_render_possible_modifiers = Some(OnDrop2::new(|| {
|
||||||
log::warn!(
|
*dbg_render_modifiers_possible =
|
||||||
"Render GFX modifiers: {:?}",
|
Some(render_possible_modifiers.keys().copied().collect())
|
||||||
render_gfx_format.write_modifiers.keys()
|
}));
|
||||||
);
|
if render_possible_modifiers.is_empty() {
|
||||||
log::warn!("DEV GFX modifiers: {:?}", dev_gfx_format.read_modifiers);
|
return Err(ScanoutBufferErrorKind::RenderNoWritableModifier);
|
||||||
return Err(MetalError::MissingRenderModifier(format.name));
|
|
||||||
}
|
}
|
||||||
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
||||||
if !needs_render_usage(possible_modifiers.values().copied()) {
|
if !needs_render_usage(render_possible_modifiers.values().copied()) {
|
||||||
usage &= !GBM_BO_USE_RENDERING;
|
usage &= !GBM_BO_USE_RENDERING;
|
||||||
}
|
}
|
||||||
|
*dbg_render_usage = Some(usage);
|
||||||
let render_bo = render_ctx.gbm.create_bo(
|
let render_bo = render_ctx.gbm.create_bo(
|
||||||
&self.state.dma_buf_ids,
|
&self.state.dma_buf_ids,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
format,
|
format,
|
||||||
possible_modifiers.keys(),
|
render_possible_modifiers.keys(),
|
||||||
usage,
|
usage,
|
||||||
);
|
);
|
||||||
let render_bo = match render_bo {
|
let render_bo = match render_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::RenderBufferAllocation(e)),
|
||||||
};
|
};
|
||||||
|
*dbg_render_modifier = Some(render_bo.dmabuf().modifier);
|
||||||
let render_img = match render_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
let render_img = match render_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportImage(e)),
|
||||||
};
|
};
|
||||||
let render_fb = match render_img.clone().to_framebuffer() {
|
let render_fb = match render_img.clone().to_framebuffer() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportFb(e)),
|
||||||
};
|
};
|
||||||
render_fb
|
render_fb
|
||||||
.clear(
|
.clear(
|
||||||
|
|
@ -2744,24 +2861,30 @@ impl MetalBackend {
|
||||||
ReleaseSync::None,
|
ReleaseSync::None,
|
||||||
self.state.color_manager.srgb_gamma22(),
|
self.state.color_manager.srgb_gamma22(),
|
||||||
)
|
)
|
||||||
.map_err(MetalError::Clear)?;
|
.map_err(ScanoutBufferErrorKind::RenderClear)?;
|
||||||
let render_tex = match render_img.to_texture() {
|
let render_tex = match render_img.to_texture() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportTexture(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportRenderTexture(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Import the bridge BO into the current device
|
// Import the bridge BO into the current device
|
||||||
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodImportRenderImage(e)),
|
||||||
};
|
};
|
||||||
let dev_tex = match dev_img.to_texture() {
|
let dev_tex = match dev_img.to_texture() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportTexture(e)),
|
Err(e) => return Err(ScanoutBufferErrorKind::SodImportRenderTexture(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
(Some(dev_tex), render_tex, Some(render_fb), Some(render_bo))
|
(Some(dev_tex), render_tex, Some(render_fb), Some(render_bo))
|
||||||
};
|
};
|
||||||
|
send_dev_gfx_write_modifiers.forget();
|
||||||
|
send_dev_modifiers_possible.forget();
|
||||||
|
send_render_dev_name.map(|o| o.forget());
|
||||||
|
send_render_gfx_write_modifiers.map(|o| o.forget());
|
||||||
|
send_dev_gfx_read_modifiers.map(|o| o.forget());
|
||||||
|
send_render_possible_modifiers.map(|o| o.forget());
|
||||||
Ok(RenderBuffer {
|
Ok(RenderBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue