Merge pull request #739 from mahkoh/jorth/dma-queue
metal: add additional methods to handle displays attached to secondary devices
This commit is contained in:
commit
6db1f84cb2
21 changed files with 3831 additions and 644 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod allocator;
|
||||||
mod input;
|
mod input;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
mod present;
|
mod present;
|
||||||
|
|
@ -12,13 +13,15 @@ use {
|
||||||
InputDeviceClickMethod, InputDeviceGroupId, InputDeviceId, InputEvent, KeyState, Leds,
|
InputDeviceClickMethod, InputDeviceGroupId, InputDeviceId, InputEvent, KeyState, Leds,
|
||||||
TransformMatrix, transaction::BackendConnectorTransactionError,
|
TransformMatrix, transaction::BackendConnectorTransactionError,
|
||||||
},
|
},
|
||||||
backends::metal::video::{
|
backends::metal::{
|
||||||
MetalDrmDeviceData, MetalLeaseData, MetalRenderContext, PendingDrmDevice,
|
allocator::{RenderBufferError, ScanoutBufferError, ScanoutBufferErrors},
|
||||||
PersistentDisplayData,
|
video::{
|
||||||
|
MetalDrmDeviceData, MetalLeaseData, MetalRenderContext, PendingDrmDevice,
|
||||||
|
PersistentDisplayData,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
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,
|
||||||
|
|
@ -49,15 +52,14 @@ use {
|
||||||
smallmap::SmallMap,
|
smallmap::SmallMap,
|
||||||
syncqueue::SyncQueue,
|
syncqueue::SyncQueue,
|
||||||
},
|
},
|
||||||
video::{Modifier, drm::DrmError, gbm::GbmError},
|
video::{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, Display, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
future::pending,
|
future::pending,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -105,8 +107,6 @@ pub enum MetalError {
|
||||||
DeviceResumeSignalHandler(#[source] DbusError),
|
DeviceResumeSignalHandler(#[source] DbusError),
|
||||||
#[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")]
|
|
||||||
CopyToOutput(#[source] GfxError),
|
|
||||||
#[error("Could not perform atomic commit")]
|
#[error("Could not perform atomic commit")]
|
||||||
Commit(#[source] DrmError),
|
Commit(#[source] DrmError),
|
||||||
#[error("The present configuration is out of date")]
|
#[error("The present configuration is out of date")]
|
||||||
|
|
@ -117,119 +117,14 @@ 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")]
|
#[error("Could not create non-prime plane buffer")]
|
||||||
AllocateScanoutBuffer(#[source] Box<ScanoutBufferError>),
|
AllocateScanoutBuffer(#[source] Box<ScanoutBufferError>),
|
||||||
}
|
#[error("Could not create non-prime plane buffer")]
|
||||||
|
AllocateScanoutBufferPrime(#[source] ScanoutBufferErrors),
|
||||||
#[derive(Debug, Error)]
|
#[error("Could not copy frame to output device")]
|
||||||
pub enum ScanoutBufferErrorKind {
|
CopyToDev(#[source] RenderBufferError),
|
||||||
#[error("Scanout device: The format is not supported")]
|
#[error("The render device does not support the format")]
|
||||||
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,
|
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 {
|
||||||
|
|
|
||||||
1595
src/backends/metal/allocator.rs
Normal file
1595
src/backends/metal/allocator.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -131,6 +131,7 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_drm_device_removed(self: &Rc<Self>, dev: &Rc<MetalDrmDeviceData>) {
|
fn handle_drm_device_removed(self: &Rc<Self>, dev: &Rc<MetalDrmDeviceData>) {
|
||||||
|
self.state.copy_device_registry.remove(dev.dev.devnum);
|
||||||
log::info!("Device removed: {}", dev.dev.devnode.to_bytes().as_bstr());
|
log::info!("Device removed: {}", dev.dev.devnode.to_bytes().as_bstr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ use {
|
||||||
backend::Connector,
|
backend::Connector,
|
||||||
backends::metal::{
|
backends::metal::{
|
||||||
MetalError,
|
MetalError,
|
||||||
|
allocator::{RenderBuffer, RenderBufferCopy},
|
||||||
transaction::{DrmConnectorState, DrmPlaneState},
|
transaction::{DrmConnectorState, DrmPlaneState},
|
||||||
video::{
|
video::{MetalConnector, MetalCrtc, MetalHardwareCursorChange, MetalPlane},
|
||||||
MetalConnector, MetalCrtc, MetalHardwareCursorChange, MetalPlane, RenderBuffer,
|
|
||||||
RenderBufferCopy,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
cmm::cmm_description::ColorDescription,
|
cmm::cmm_description::ColorDescription,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
|
|
@ -557,7 +555,11 @@ impl MetalConnector {
|
||||||
let swap_buffers = c.cursor_swap_buffer.is_some();
|
let swap_buffers = c.cursor_swap_buffer.is_some();
|
||||||
self.cursor_swap_buffer.set(swap_buffers);
|
self.cursor_swap_buffer.set(swap_buffers);
|
||||||
if let Some(sf) = c.cursor_swap_buffer.take() {
|
if let Some(sf) = c.cursor_swap_buffer.take() {
|
||||||
let sf = c.cursor_buffer.copy_to_dev(cd, sf)?.present_block;
|
let sf = c
|
||||||
|
.cursor_buffer
|
||||||
|
.copy_to_dev(cd, None, sf)
|
||||||
|
.map_err(MetalError::CopyToDev)?
|
||||||
|
.present_block;
|
||||||
self.cursor_sync_file.set(sf);
|
self.cursor_sync_file.set(sf);
|
||||||
}
|
}
|
||||||
let mut cursor_changed = false;
|
let mut cursor_changed = false;
|
||||||
|
|
@ -588,13 +590,12 @@ impl MetalConnector {
|
||||||
}
|
}
|
||||||
let buffer_idx = (front_buffer % buffers.len() as u64) as usize;
|
let buffer_idx = (front_buffer % buffers.len() as u64) as usize;
|
||||||
let buffer = &buffers[buffer_idx];
|
let buffer = &buffers[buffer_idx];
|
||||||
let (width, height) = buffer.dev_fb.physical_size();
|
|
||||||
CursorProgrammingType::Enable {
|
CursorProgrammingType::Enable {
|
||||||
fb: buffer.drm.clone(),
|
fb: buffer.drm.clone(),
|
||||||
x: self.cursor_x.get(),
|
x: self.cursor_x.get(),
|
||||||
y: self.cursor_y.get(),
|
y: self.cursor_y.get(),
|
||||||
width,
|
width: buffer.width,
|
||||||
height,
|
height: buffer.height,
|
||||||
swap,
|
swap,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -862,7 +863,8 @@ impl MetalConnector {
|
||||||
match &direct_scanout_data {
|
match &direct_scanout_data {
|
||||||
None => {
|
None => {
|
||||||
let sf = buffer
|
let sf = buffer
|
||||||
.render_fb()
|
.render
|
||||||
|
.fb
|
||||||
.perform_render_pass(
|
.perform_render_pass(
|
||||||
AcquireSync::Unnecessary,
|
AcquireSync::Unnecessary,
|
||||||
ReleaseSync::Explicit,
|
ReleaseSync::Explicit,
|
||||||
|
|
@ -873,9 +875,11 @@ impl MetalConnector {
|
||||||
blend_cd,
|
blend_cd,
|
||||||
)
|
)
|
||||||
.map_err(MetalError::RenderFrame)?;
|
.map_err(MetalError::RenderFrame)?;
|
||||||
copy = buffer.copy_to_dev(cd, sf)?;
|
copy = buffer
|
||||||
|
.copy_to_dev(cd, Some(&latched.damage), sf)
|
||||||
|
.map_err(MetalError::CopyToDev)?;
|
||||||
fb = buffer.drm.clone();
|
fb = buffer.drm.clone();
|
||||||
tex = buffer.render_tex.clone();
|
tex = buffer.render.tex.clone();
|
||||||
}
|
}
|
||||||
Some(dsd) => {
|
Some(dsd) => {
|
||||||
let sf = match &dsd.acquire_sync {
|
let sf = match &dsd.acquire_sync {
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ use {
|
||||||
BackendConnectorTransactionError, BackendPreparedConnectorTransaction,
|
BackendConnectorTransactionError, BackendPreparedConnectorTransaction,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
backends::metal::video::{
|
backends::metal::{
|
||||||
FrontState, MetalConnector, MetalCrtc, MetalDrmDeviceData, MetalPlane, PlaneType,
|
allocator::RenderBuffer,
|
||||||
RenderBuffer,
|
video::{
|
||||||
|
FrontState, MetalConnector, MetalCrtc, MetalDrmDeviceData, MetalPlane, PlaneType,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
format::{ARGB8888, Format},
|
format::{ARGB8888, Format},
|
||||||
gfx_api::SyncFile,
|
gfx_api::SyncFile,
|
||||||
|
|
@ -464,7 +466,7 @@ impl MetalDeviceTransaction {
|
||||||
if b[0].width != width || b[0].height != height || b[0].format != format {
|
if b[0].width != width || b[0].height != height || b[0].format != format {
|
||||||
discard!();
|
discard!();
|
||||||
}
|
}
|
||||||
if !rc_eq(render_ctx, &b[0].render_ctx) {
|
if !rc_eq(render_ctx, &b[0].render.ctx) {
|
||||||
discard!();
|
discard!();
|
||||||
}
|
}
|
||||||
if !rc_eq(&dev_ctx, &b[0].dev_ctx) {
|
if !rc_eq(&dev_ctx, &b[0].dev_ctx) {
|
||||||
|
|
@ -472,7 +474,7 @@ impl MetalDeviceTransaction {
|
||||||
}
|
}
|
||||||
let modifiers = &plane.obj.formats.get(&format.drm).unwrap().modifiers;
|
let modifiers = &plane.obj.formats.get(&format.drm).unwrap().modifiers;
|
||||||
for b in &**b {
|
for b in &**b {
|
||||||
if !modifiers.contains(&b.dev_bo.dmabuf().modifier) {
|
if !modifiers.contains(&b.dev_bo().dmabuf().modifier) {
|
||||||
discard!();
|
discard!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +519,20 @@ impl MetalDeviceTransaction {
|
||||||
*plane_id = DrmPlane::NONE;
|
*plane_id = DrmPlane::NONE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let buffers = Rc::new(res?);
|
let res = res?;
|
||||||
|
if let Some(method) = res[0].prime.method() {
|
||||||
|
let plane = match plane.obj.ty {
|
||||||
|
PlaneType::Overlay => "overlay",
|
||||||
|
PlaneType::Primary => "primary",
|
||||||
|
PlaneType::Cursor => "cursor",
|
||||||
|
};
|
||||||
|
let dev = slf.dev.dev.devnode.as_bytes().as_bstr();
|
||||||
|
let connector = connector.obj.kernel_id();
|
||||||
|
log::info!(
|
||||||
|
"Using prime method {method} for {dev} {connector} ({plane})",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
@ -572,7 +587,7 @@ impl MetalDeviceTransaction {
|
||||||
match prev.copy_to_new(new_buffer, &cd) {
|
match prev.copy_to_new(new_buffer, &cd) {
|
||||||
Ok(sf) => Ok(sf),
|
Ok(sf) => Ok(sf),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not copy from old buffer: {}", ErrorFmt(&*e));
|
log::warn!("Could not copy from old buffer: {}", ErrorFmt(e));
|
||||||
new_buffer.clear(&cd)
|
new_buffer.clear(&cd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -582,7 +597,7 @@ impl MetalDeviceTransaction {
|
||||||
match res {
|
match res {
|
||||||
Ok(sf) => sync_files.extend(sf),
|
Ok(sf) => sync_files.extend(sf),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not clear new buffer: {}", ErrorFmt(&*e));
|
log::warn!("Could not clear new buffer: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -623,7 +638,7 @@ impl MetalDeviceTransaction {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Could not black out old buffer: {}",
|
"Could not black out old buffer: {}",
|
||||||
ErrorFmt(&*e),
|
ErrorFmt(e),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::BufferObject,
|
|
||||||
async_engine::{Phase, SpawnedFuture},
|
async_engine::{Phase, SpawnedFuture},
|
||||||
backend::{
|
backend::{
|
||||||
BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease,
|
BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease,
|
||||||
|
|
@ -14,7 +13,8 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
backends::metal::{
|
backends::metal::{
|
||||||
MetalBackend, MetalError, ScanoutBufferError, ScanoutBufferErrorKind,
|
MetalBackend, MetalError,
|
||||||
|
allocator::RenderBuffer,
|
||||||
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,
|
||||||
|
|
@ -22,18 +22,15 @@ use {
|
||||||
transaction::{DrmConnectorState, DrmCrtcState, DrmPlaneState, MetalDeviceTransaction},
|
transaction::{DrmConnectorState, DrmCrtcState, DrmPlaneState, MetalDeviceTransaction},
|
||||||
},
|
},
|
||||||
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
||||||
|
copy_device::{CopyDevice, CopyDeviceRegistry},
|
||||||
drm_feedback::DrmFeedback,
|
drm_feedback::DrmFeedback,
|
||||||
edid::{CtaDataBlock, Descriptor, EdidExtension},
|
edid::{CtaDataBlock, Descriptor, EdidExtension},
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
gfx_api::{
|
gfx_api::{GfxContext, GfxFramebuffer, SyncFile},
|
||||||
AcquireSync, GfxBlendBuffer, GfxContext, GfxFramebuffer, GfxTexture, ReleaseSync,
|
|
||||||
SyncFile, needs_render_usage,
|
|
||||||
},
|
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_output::OutputId,
|
wl_output::OutputId,
|
||||||
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY},
|
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY},
|
||||||
},
|
},
|
||||||
rect::{DamageQueue, Rect},
|
|
||||||
state::State,
|
state::State,
|
||||||
tree::OutputNode,
|
tree::OutputNode,
|
||||||
udev::UdevDevice,
|
udev::UdevDevice,
|
||||||
|
|
@ -41,32 +38,29 @@ 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, rc_eq::rc_eq,
|
opaque_cell::OpaqueCell, ordered_float::F64, oserror::OsError,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
INVALID_MODIFIER, Modifier,
|
INVALID_MODIFIER, Modifier,
|
||||||
dmabuf::DmaBufId,
|
dmabuf::DmaBufId,
|
||||||
drm::{
|
drm::{
|
||||||
ConnectorStatus, ConnectorType, DRM_CLIENT_CAP_ATOMIC, DrmBlob, DrmConnector,
|
ConnectorStatus, ConnectorType, DRM_CLIENT_CAP_ATOMIC, DrmBlob, DrmConnector,
|
||||||
DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFb, DrmFramebuffer, DrmLease,
|
DrmCrtc, DrmEncoder, DrmError, DrmEvent, DrmFb, DrmLease, DrmMaster, DrmModeInfo,
|
||||||
DrmMaster, DrmModeInfo, DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition,
|
DrmObject, DrmPlane, DrmProperty, DrmPropertyDefinition, DrmPropertyType,
|
||||||
DrmPropertyType, DrmVersion, HDMI_EOTF_TRADITIONAL_GAMMA_SDR, drm_mode_modeinfo,
|
DrmVersion, HDMI_EOTF_TRADITIONAL_GAMMA_SDR, drm_mode_modeinfo,
|
||||||
hdr_output_metadata,
|
hdr_output_metadata,
|
||||||
},
|
},
|
||||||
gbm::{GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT, GbmBo, GbmDevice},
|
gbm::GbmDevice,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
arrayvec::ArrayVec,
|
|
||||||
bstr::{BString, ByteSlice},
|
bstr::{BString, ByteSlice},
|
||||||
indexmap::{IndexMap, IndexSet, indexset},
|
indexmap::{IndexSet, indexset},
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
jay_config::video::GfxApi,
|
jay_config::video::GfxApi,
|
||||||
run_on_drop::on_drop,
|
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, OnceCell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
error::Error,
|
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem,
|
mem,
|
||||||
|
|
@ -91,6 +85,19 @@ pub struct MetalRenderContext {
|
||||||
pub gfx: Rc<dyn GfxContext>,
|
pub gfx: Rc<dyn GfxContext>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
pub devnode: CString,
|
pub devnode: CString,
|
||||||
|
pub copy_device: Rc<CopyDeviceHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyDeviceHolder {
|
||||||
|
pub registry: Rc<CopyDeviceRegistry>,
|
||||||
|
pub devnum: dev_t,
|
||||||
|
pub dev: OnceCell<Option<Rc<CopyDevice>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for CopyDeviceHolder {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("CopyDeviceHolder").finish_non_exhaustive()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetalDrmDevice {
|
pub struct MetalDrmDevice {
|
||||||
|
|
@ -112,6 +119,7 @@ pub struct MetalDrmDevice {
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
pub handle_events: HandleEvents,
|
pub handle_events: HandleEvents,
|
||||||
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
||||||
|
pub copy_device: Rc<CopyDeviceHolder>,
|
||||||
pub on_change: OnChange<crate::backend::DrmEvent>,
|
pub on_change: OnChange<crate::backend::DrmEvent>,
|
||||||
pub direct_scanout_enabled: Cell<Option<bool>>,
|
pub direct_scanout_enabled: Cell<Option<bool>>,
|
||||||
pub is_nvidia: bool,
|
pub is_nvidia: bool,
|
||||||
|
|
@ -588,7 +596,7 @@ impl HardwareCursorUpdate for MetalHardwareCursorChange<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer> {
|
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer> {
|
||||||
self.cursor_buffer.render_fb()
|
self.cursor_buffer.render.fb.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&mut self, x: i32, y: i32) {
|
fn set_position(&mut self, x: i32, y: i32) {
|
||||||
|
|
@ -1994,6 +2002,12 @@ impl MetalBackend {
|
||||||
Err(e) => return Err(MetalError::GbmDevice(e)),
|
Err(e) => return Err(MetalError::GbmDevice(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let copy_device = Rc::new(CopyDeviceHolder {
|
||||||
|
registry: self.state.copy_device_registry.clone(),
|
||||||
|
devnum: pending.devnum,
|
||||||
|
dev: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let gfx = match self.state.create_gfx_context(master, None) {
|
let gfx = match self.state.create_gfx_context(master, None) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
||||||
|
|
@ -2003,6 +2017,7 @@ impl MetalBackend {
|
||||||
gfx,
|
gfx,
|
||||||
gbm: gbm.clone(),
|
gbm: gbm.clone(),
|
||||||
devnode: pending.devnode.clone(),
|
devnode: pending.devnode.clone(),
|
||||||
|
copy_device: copy_device.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut is_nvidia = false;
|
let mut is_nvidia = false;
|
||||||
|
|
@ -2044,6 +2059,7 @@ impl MetalBackend {
|
||||||
handle_events: Cell::new(None),
|
handle_events: Cell::new(None),
|
||||||
},
|
},
|
||||||
ctx: CloneCell::new(ctx),
|
ctx: CloneCell::new(ctx),
|
||||||
|
copy_device,
|
||||||
on_change: Default::default(),
|
on_change: Default::default(),
|
||||||
direct_scanout_enabled: Default::default(),
|
direct_scanout_enabled: Default::default(),
|
||||||
is_nvidia,
|
is_nvidia,
|
||||||
|
|
@ -2469,6 +2485,7 @@ impl MetalBackend {
|
||||||
gfx,
|
gfx,
|
||||||
gbm: old_ctx.gbm.clone(),
|
gbm: old_ctx.gbm.clone(),
|
||||||
devnode: old_ctx.devnode.clone(),
|
devnode: old_ctx.devnode.clone(),
|
||||||
|
copy_device: old_ctx.copy_device.clone(),
|
||||||
}));
|
}));
|
||||||
if dev.is_render_device() {
|
if dev.is_render_device() {
|
||||||
self.make_render_device(dev, true);
|
self.make_render_device(dev, true);
|
||||||
|
|
@ -2603,315 +2620,6 @@ impl MetalBackend {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_scanout_buffers<const N: usize>(
|
|
||||||
&self,
|
|
||||||
dev: &Rc<MetalDrmDevice>,
|
|
||||||
format: &'static Format,
|
|
||||||
plane_modifiers: &IndexSet<Modifier>,
|
|
||||||
width: i32,
|
|
||||||
height: i32,
|
|
||||||
render_ctx: &Rc<MetalRenderContext>,
|
|
||||||
cursor: bool,
|
|
||||||
) -> Result<[RenderBuffer; N], MetalError> {
|
|
||||||
let mut blend_buffer = None;
|
|
||||||
if !cursor {
|
|
||||||
match render_ctx.gfx.acquire_blend_buffer(width, height) {
|
|
||||||
Ok(bb) => blend_buffer = Some(bb),
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("Could not create blend buffer: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut damage_queue = ArrayVec::from(DamageQueue::new::<N>());
|
|
||||||
let mut create = || {
|
|
||||||
self.create_scanout_buffer(
|
|
||||||
dev,
|
|
||||||
format,
|
|
||||||
plane_modifiers,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
render_ctx,
|
|
||||||
cursor,
|
|
||||||
damage_queue.pop().unwrap(),
|
|
||||||
blend_buffer.clone(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let mut array = ArrayVec::<_, N>::new();
|
|
||||||
for _ in 0..N {
|
|
||||||
array.push(create()?);
|
|
||||||
}
|
|
||||||
if let Some(buffer) = array.first() {
|
|
||||||
buffer.damage_full();
|
|
||||||
}
|
|
||||||
Ok(array.into_inner().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
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>>,
|
|
||||||
) -> 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_gfx_formats = dev_ctx.gfx.formats();
|
|
||||||
let Some(dev_gfx_format) = dev_gfx_formats.get(&format.drm) else {
|
|
||||||
return Err(ScanoutBufferErrorKind::SodUnsupportedFormat);
|
|
||||||
};
|
|
||||||
let send_dev_gfx_write_modifiers = on_drop(|| {
|
|
||||||
*dbg_dev_gfx_write_modifiers =
|
|
||||||
Some(dev_gfx_format.write_modifiers.keys().copied().collect())
|
|
||||||
});
|
|
||||||
let possible_modifiers: IndexMap<_, _> = dev_gfx_format
|
|
||||||
.write_modifiers
|
|
||||||
.iter()
|
|
||||||
.filter(|(m, _)| plane_modifiers.contains(*m))
|
|
||||||
.map(|(m, v)| (*m, v))
|
|
||||||
.collect();
|
|
||||||
let send_dev_modifiers_possible = on_drop(|| {
|
|
||||||
*dbg_dev_modifiers_possible = Some(possible_modifiers.keys().copied().collect())
|
|
||||||
});
|
|
||||||
if possible_modifiers.is_empty() {
|
|
||||||
return Err(ScanoutBufferErrorKind::SodNoWritableModifier);
|
|
||||||
}
|
|
||||||
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
|
||||||
if !needs_render_usage(possible_modifiers.values().copied()) {
|
|
||||||
usage &= !GBM_BO_USE_RENDERING;
|
|
||||||
}
|
|
||||||
if cursor {
|
|
||||||
usage |= GBM_BO_USE_LINEAR;
|
|
||||||
};
|
|
||||||
*dbg_dev_usage = Some(usage);
|
|
||||||
let dev_bo = dev.gbm.create_bo(
|
|
||||||
&self.state.dma_buf_ids,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format,
|
|
||||||
possible_modifiers.keys(),
|
|
||||||
usage,
|
|
||||||
);
|
|
||||||
let dev_bo = match dev_bo {
|
|
||||||
Ok(b) => b,
|
|
||||||
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) {
|
|
||||||
Ok(fb) => Rc::new(fb),
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodAddfb2(e)),
|
|
||||||
};
|
|
||||||
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(dev_bo.dmabuf()) {
|
|
||||||
Ok(img) => img,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodImportSodImage(e)),
|
|
||||||
};
|
|
||||||
let dev_fb = match dev_img.clone().to_framebuffer() {
|
|
||||||
Ok(fb) => fb,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodImportFb(e)),
|
|
||||||
};
|
|
||||||
dev_fb
|
|
||||||
.clear(
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::None,
|
|
||||||
self.state.color_manager.srgb_gamma22(),
|
|
||||||
)
|
|
||||||
.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 render_tex = match dev_img.to_texture() {
|
|
||||||
Ok(fb) => fb,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodImportSodTexture(e)),
|
|
||||||
};
|
|
||||||
(None, render_tex, None, None)
|
|
||||||
} else {
|
|
||||||
send_render_dev_name = Some(on_drop(|| {
|
|
||||||
*dbg_render_name = Some(render_ctx.devnode.as_bytes().as_bstr().to_string());
|
|
||||||
}));
|
|
||||||
// Create a _bridge_ BO in the render device
|
|
||||||
render_gfx_formats = render_ctx.gfx.formats();
|
|
||||||
let render_gfx_format = match render_gfx_formats.get(&format.drm) {
|
|
||||||
None => return Err(ScanoutBufferErrorKind::RenderUnsupportedFormat),
|
|
||||||
Some(f) => f,
|
|
||||||
};
|
|
||||||
send_render_gfx_write_modifiers = Some(on_drop(|| {
|
|
||||||
*dbg_render_gfx_write_modifiers =
|
|
||||||
Some(render_gfx_format.write_modifiers.keys().copied().collect())
|
|
||||||
}));
|
|
||||||
send_dev_gfx_read_modifiers = Some(on_drop(|| {
|
|
||||||
*dbg_dev_gfx_read_modifiers = Some(dev_gfx_format.read_modifiers.clone());
|
|
||||||
}));
|
|
||||||
render_possible_modifiers = render_gfx_format
|
|
||||||
.write_modifiers
|
|
||||||
.iter()
|
|
||||||
.filter(|(m, _)| dev_gfx_format.read_modifiers.contains(*m))
|
|
||||||
.map(|(m, v)| (*m, v))
|
|
||||||
.collect();
|
|
||||||
send_render_possible_modifiers = Some(on_drop(|| {
|
|
||||||
*dbg_render_modifiers_possible =
|
|
||||||
Some(render_possible_modifiers.keys().copied().collect())
|
|
||||||
}));
|
|
||||||
if render_possible_modifiers.is_empty() {
|
|
||||||
return Err(ScanoutBufferErrorKind::RenderNoWritableModifier);
|
|
||||||
}
|
|
||||||
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
|
||||||
if !needs_render_usage(render_possible_modifiers.values().copied()) {
|
|
||||||
usage &= !GBM_BO_USE_RENDERING;
|
|
||||||
}
|
|
||||||
*dbg_render_usage = Some(usage);
|
|
||||||
let render_bo = render_ctx.gbm.create_bo(
|
|
||||||
&self.state.dma_buf_ids,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format,
|
|
||||||
render_possible_modifiers.keys(),
|
|
||||||
usage,
|
|
||||||
);
|
|
||||||
let render_bo = match render_bo {
|
|
||||||
Ok(b) => b,
|
|
||||||
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()) {
|
|
||||||
Ok(img) => img,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportImage(e)),
|
|
||||||
};
|
|
||||||
let render_fb = match render_img.clone().to_framebuffer() {
|
|
||||||
Ok(fb) => fb,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportFb(e)),
|
|
||||||
};
|
|
||||||
render_fb
|
|
||||||
.clear(
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::None,
|
|
||||||
self.state.color_manager.srgb_gamma22(),
|
|
||||||
)
|
|
||||||
.map_err(ScanoutBufferErrorKind::RenderClear)?;
|
|
||||||
let render_tex = match render_img.to_texture() {
|
|
||||||
Ok(fb) => fb,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::RenderImportRenderTexture(e)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Import the bridge BO into the current device
|
|
||||||
let dev_img = match dev_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
|
||||||
Ok(img) => img,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodImportRenderImage(e)),
|
|
||||||
};
|
|
||||||
let dev_tex = match dev_img.to_texture() {
|
|
||||||
Ok(fb) => fb,
|
|
||||||
Err(e) => return Err(ScanoutBufferErrorKind::SodImportRenderTexture(e)),
|
|
||||||
};
|
|
||||||
|
|
||||||
(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 {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
locked: Cell::new(true),
|
|
||||||
format,
|
|
||||||
dev_ctx,
|
|
||||||
render_ctx: render_ctx.clone(),
|
|
||||||
drm: drm_fb,
|
|
||||||
damage_queue,
|
|
||||||
dev_bo,
|
|
||||||
_render_bo: render_bo,
|
|
||||||
blend_buffer,
|
|
||||||
dev_fb,
|
|
||||||
dev_tex,
|
|
||||||
render_tex,
|
|
||||||
render_fb,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_connector(&self, connector: &Rc<MetalConnector>, log_mode: bool) {
|
fn start_connector(&self, connector: &Rc<MetalConnector>, log_mode: bool) {
|
||||||
let dd = &*connector.display.borrow();
|
let dd = &*connector.display.borrow();
|
||||||
self.send_connected(connector, dd);
|
self.send_connected(connector, dd);
|
||||||
|
|
@ -2939,126 +2647,22 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl CopyDeviceHolder {
|
||||||
pub struct RenderBuffer {
|
pub fn get(&self) -> Option<Rc<CopyDevice>> {
|
||||||
pub width: i32,
|
self.dev
|
||||||
pub height: i32,
|
.get_or_init(
|
||||||
pub locked: Cell<bool>,
|
|| match self.registry.get(self.devnum)?.create_device().map(Some) {
|
||||||
pub format: &'static Format,
|
Ok(d) => d,
|
||||||
pub dev_ctx: Rc<MetalRenderContext>,
|
Err(e) => {
|
||||||
pub render_ctx: Rc<MetalRenderContext>,
|
log::error!(
|
||||||
pub drm: Rc<DrmFramebuffer>,
|
"Could not get copy device for {}: {}",
|
||||||
pub damage_queue: DamageQueue,
|
self.devnum,
|
||||||
pub dev_bo: GbmBo,
|
ErrorFmt(e),
|
||||||
pub _render_bo: Option<GbmBo>,
|
);
|
||||||
pub blend_buffer: Option<Rc<dyn GfxBlendBuffer>>,
|
None
|
||||||
// ctx = dev
|
}
|
||||||
// buffer location = dev
|
},
|
||||||
pub dev_fb: Rc<dyn GfxFramebuffer>,
|
|
||||||
// ctx = dev
|
|
||||||
// buffer location = render
|
|
||||||
pub dev_tex: Option<Rc<dyn GfxTexture>>,
|
|
||||||
// ctx = render
|
|
||||||
// buffer location = render
|
|
||||||
pub render_tex: Rc<dyn GfxTexture>,
|
|
||||||
// ctx = render
|
|
||||||
// buffer location = render
|
|
||||||
pub render_fb: Option<Rc<dyn GfxFramebuffer>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct RenderBufferCopy {
|
|
||||||
pub render_block: Option<SyncFile>,
|
|
||||||
pub present_block: Option<SyncFile>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderBufferCopy {
|
|
||||||
pub fn for_both(sf: Option<SyncFile>) -> Self {
|
|
||||||
Self {
|
|
||||||
render_block: sf.clone(),
|
|
||||||
present_block: sf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderBuffer {
|
|
||||||
pub fn render_fb(&self) -> Rc<dyn GfxFramebuffer> {
|
|
||||||
self.render_fb
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| self.dev_fb.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_to_dev(
|
|
||||||
&self,
|
|
||||||
cd: &Rc<ColorDescription>,
|
|
||||||
sync_file: Option<SyncFile>,
|
|
||||||
) -> Result<RenderBufferCopy, MetalError> {
|
|
||||||
let Some(tex) = &self.dev_tex else {
|
|
||||||
return Ok(RenderBufferCopy {
|
|
||||||
render_block: None,
|
|
||||||
present_block: sync_file,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
self.dev_fb
|
|
||||||
.copy_texture(
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::Explicit,
|
|
||||||
cd,
|
|
||||||
tex,
|
|
||||||
cd,
|
|
||||||
None,
|
|
||||||
AcquireSync::from_sync_file(sync_file),
|
|
||||||
ReleaseSync::None,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
.map_err(MetalError::CopyToOutput)
|
|
||||||
.map(RenderBufferCopy::for_both)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn damage_full(&self) {
|
|
||||||
let dmabuf = self.dev_bo.dmabuf();
|
|
||||||
let rect = Rect::new_sized_saturating(0, 0, dmabuf.width, dmabuf.height);
|
|
||||||
self.damage_queue.clear_all();
|
|
||||||
self.damage_queue.damage(&[rect]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&self, cd: &Rc<ColorDescription>) -> Result<Option<SyncFile>, Box<dyn Error>> {
|
|
||||||
self.dev_fb
|
|
||||||
.clear(AcquireSync::Unnecessary, ReleaseSync::Explicit, cd)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_to_new(
|
|
||||||
&self,
|
|
||||||
new: &Self,
|
|
||||||
cd: &Rc<ColorDescription>,
|
|
||||||
) -> Result<Option<SyncFile>, Box<dyn Error>> {
|
|
||||||
let old = self;
|
|
||||||
let copy_texture = |new: &Rc<dyn GfxFramebuffer>, old: &Rc<dyn GfxTexture>| {
|
|
||||||
new.copy_texture(
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::Explicit,
|
|
||||||
cd,
|
|
||||||
old,
|
|
||||||
cd,
|
|
||||||
None,
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::Explicit,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.map_err(Into::into)
|
|
||||||
};
|
|
||||||
if rc_eq(&old.dev_ctx, &new.dev_ctx) {
|
|
||||||
return copy_texture(&new.dev_fb, old.dev_tex.as_ref().unwrap_or(&old.render_tex));
|
|
||||||
}
|
|
||||||
let tex = new
|
|
||||||
.dev_ctx
|
|
||||||
.gfx
|
|
||||||
.clone()
|
.clone()
|
||||||
.dmabuf_img(old.dev_bo.dmabuf())?
|
|
||||||
.to_texture()?;
|
|
||||||
copy_texture(&new.dev_fb, &tex)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use {
|
||||||
clientmem::{self, ClientMemError},
|
clientmem::{self, ClientMemError},
|
||||||
cmm::{cmm_manager::ColorManager, cmm_primaries::Primaries},
|
cmm::{cmm_manager::ColorManager, cmm_primaries::Primaries},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
|
copy_device::CopyDeviceRegistry,
|
||||||
cpu_worker::{CpuWorker, CpuWorkerError},
|
cpu_worker::{CpuWorker, CpuWorkerError},
|
||||||
criteria::{
|
criteria::{
|
||||||
CritMatcherIds,
|
CritMatcherIds,
|
||||||
|
|
@ -363,6 +364,7 @@ fn start_compositor2(
|
||||||
outputs_without_hc: Default::default(),
|
outputs_without_hc: Default::default(),
|
||||||
udmabuf: Default::default(),
|
udmabuf: Default::default(),
|
||||||
gfx_ctx_changed: Default::default(),
|
gfx_ctx_changed: Default::default(),
|
||||||
|
copy_device_registry: Rc::new(CopyDeviceRegistry::new(&ring, &engine)),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
|
||||||
2039
src/copy_device.rs
Normal file
2039
src/copy_device.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -103,7 +103,7 @@ fn create_fd_data(ctx: &dyn GfxContext) -> (Vec<u8>, AHashMap<(u32, Modifier), u
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
let mut map = AHashMap::new();
|
let mut map = AHashMap::new();
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
for (format, info) in &*ctx.formats() {
|
for (format, info) in &**ctx.formats() {
|
||||||
for modifier in &info.read_modifiers {
|
for modifier in &info.read_modifiers {
|
||||||
vec.write_u32::<NativeEndian>(*format).unwrap();
|
vec.write_u32::<NativeEndian>(*format).unwrap();
|
||||||
vec.write_u32::<NativeEndian>(0).unwrap();
|
vec.write_u32::<NativeEndian>(0).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ pub struct CopyTexture {
|
||||||
pub cd: Rc<ColorDescription>,
|
pub cd: Rc<ColorDescription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct SyncFile(pub Rc<OwnedFd>);
|
pub struct SyncFile(pub Rc<OwnedFd>);
|
||||||
|
|
||||||
impl Deref for SyncFile {
|
impl Deref for SyncFile {
|
||||||
|
|
@ -747,7 +747,7 @@ pub trait GfxContext: Debug {
|
||||||
|
|
||||||
fn render_node(&self) -> Option<Rc<CString>>;
|
fn render_node(&self) -> Option<Rc<CString>>;
|
||||||
|
|
||||||
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>>;
|
fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>>;
|
||||||
|
|
||||||
fn fast_ram_access(&self) -> bool;
|
fn fast_ram_access(&self) -> bool;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,8 +187,8 @@ impl GlRenderContext {
|
||||||
self.render_node.clone()
|
self.render_node.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
pub fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
||||||
self.ctx.formats.clone()
|
&self.ctx.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dmabuf_fb(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Framebuffer>, RenderError> {
|
fn dmabuf_fb(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Framebuffer>, RenderError> {
|
||||||
|
|
@ -253,7 +253,7 @@ impl GfxContext for GlRenderContext {
|
||||||
Some(self.render_node())
|
Some(self.render_node())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
||||||
self.formats()
|
self.formats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -263,8 +263,8 @@ impl GfxContext for Context {
|
||||||
Some(self.0.device.render_node.clone())
|
Some(self.0.device.render_node.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
||||||
self.0.formats.clone()
|
&self.0.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fast_ram_access(&self) -> bool {
|
fn fast_ram_access(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ use {
|
||||||
drm::{Drm, sync_obj::SyncObjCtx},
|
drm::{Drm, sync_obj::SyncObjCtx},
|
||||||
gbm::{GBM_BO_USE_RENDERING, GbmDevice},
|
gbm::{GBM_BO_USE_RENDERING, GbmDevice},
|
||||||
},
|
},
|
||||||
vulkan_core::{API_VERSION, ApiVersionDisplay, Extensions, map_extension_properties},
|
vulkan_core::{
|
||||||
|
ApiVersionDisplay, Extensions, VULKAN_API_VERSION, map_extension_properties,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
|
|
@ -145,7 +147,7 @@ impl VulkanInstance {
|
||||||
let mut devices = vec![];
|
let mut devices = vec![];
|
||||||
for phy_dev in phy_devs {
|
for phy_dev in phy_devs {
|
||||||
let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
|
let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
|
||||||
if props.api_version < API_VERSION {
|
if props.api_version < VULKAN_API_VERSION {
|
||||||
devices.push((props, None, None));
|
devices.push((props, None, None));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +220,7 @@ impl VulkanInstance {
|
||||||
};
|
};
|
||||||
for phy_dev in phy_devs {
|
for phy_dev in phy_devs {
|
||||||
let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
|
let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
|
||||||
if props.api_version < API_VERSION {
|
if props.api_version < VULKAN_API_VERSION {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if props.device_type == PhysicalDeviceType::CPU {
|
if props.device_type == PhysicalDeviceType::CPU {
|
||||||
|
|
@ -618,7 +620,7 @@ fn log_device(
|
||||||
Ustr::from_ptr(props.device_name.as_ptr()).display()
|
Ustr::from_ptr(props.device_name.as_ptr()).display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if props.api_version < API_VERSION {
|
if props.api_version < VULKAN_API_VERSION {
|
||||||
log::warn!(" device does not support vulkan 1.3");
|
log::warn!(" device does not support vulkan 1.3");
|
||||||
}
|
}
|
||||||
if let Some(extensions) = extensions {
|
if let Some(extensions) = extensions {
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ impl ZwpLinuxBufferParamsV1 {
|
||||||
Some(ctx) => ctx,
|
Some(ctx) => ctx,
|
||||||
None => return Err(ZwpLinuxBufferParamsV1Error::NoRenderContext),
|
None => return Err(ZwpLinuxBufferParamsV1Error::NoRenderContext),
|
||||||
};
|
};
|
||||||
let formats = ctx.formats();
|
let formats = ctx.formats().clone();
|
||||||
let format = match formats.get(&format) {
|
let format = match formats.get(&format) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => return Err(ZwpLinuxBufferParamsV1Error::InvalidFormat(format)),
|
None => return Err(ZwpLinuxBufferParamsV1Error::InvalidFormat(format)),
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,8 @@ impl GfxContext for TestGfxCtx {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
fn formats(&self) -> &Rc<AHashMap<u32, GfxFormat>> {
|
||||||
self.formats.clone()
|
&self.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fast_ram_access(&self) -> bool {
|
fn fast_ram_access(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ mod clientmem;
|
||||||
mod cmm;
|
mod cmm;
|
||||||
mod compositor;
|
mod compositor;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod copy_device;
|
||||||
mod cpu_worker;
|
mod cpu_worker;
|
||||||
mod criteria;
|
mod criteria;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,9 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
||||||
if let Some(ctx) = render_ctx {
|
if let Some(ctx) = render_ctx {
|
||||||
let client_formats = ctx.ctx.formats();
|
let client_formats = ctx.ctx.formats();
|
||||||
let usable_formats = match &server_formats {
|
let usable_formats = match &server_formats {
|
||||||
None => client_formats,
|
None => client_formats.clone(),
|
||||||
Some(server_formats) => {
|
Some(server_formats) => {
|
||||||
Rc::new(cross_intersect_formats(&client_formats, server_formats))
|
Rc::new(cross_intersect_formats(client_formats, server_formats))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.render_ctx.set(Some(Rc::new(PortalServerRenderCtx {
|
self.render_ctx.set(Some(Rc::new(PortalServerRenderCtx {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use {
|
||||||
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
|
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
|
||||||
compositor::LIBEI_SOCKET,
|
compositor::LIBEI_SOCKET,
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
|
copy_device::CopyDeviceRegistry,
|
||||||
cpu_worker::CpuWorker,
|
cpu_worker::CpuWorker,
|
||||||
criteria::{clm::ClMatcherManager, tlm::TlMatcherManager},
|
criteria::{clm::ClMatcherManager, tlm::TlMatcherManager},
|
||||||
cursor::{Cursor, ServerCursors},
|
cursor::{Cursor, ServerCursors},
|
||||||
|
|
@ -292,6 +293,7 @@ pub struct State {
|
||||||
pub outputs_without_hc: NumCell<usize>,
|
pub outputs_without_hc: NumCell<usize>,
|
||||||
pub udmabuf: Rc<UdmabufHolder>,
|
pub udmabuf: Rc<UdmabufHolder>,
|
||||||
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
||||||
|
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
|
||||||
102
src/udmabuf.rs
102
src/udmabuf.rs
|
|
@ -7,7 +7,7 @@ use {
|
||||||
oserror::OsError, page_size::page_size,
|
oserror::OsError, page_size::page_size,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
LINEAR_MODIFIER, Modifier,
|
LINEAR_MODIFIER, LINEAR_STRIDE_ALIGN, Modifier,
|
||||||
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
||||||
drm::Drm,
|
drm::Drm,
|
||||||
},
|
},
|
||||||
|
|
@ -115,6 +115,63 @@ impl Udmabuf {
|
||||||
};
|
};
|
||||||
Ok(dmabuf)
|
Ok(dmabuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_dmabuf(
|
||||||
|
&self,
|
||||||
|
dma_buf_ids: &DmaBufIds,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<DmaBuf, UdmabufError> {
|
||||||
|
Ok(self.create_bo(dma_buf_ids, width, height, format)?.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_bo(
|
||||||
|
&self,
|
||||||
|
dma_buf_ids: &DmaBufIds,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<UdmabufBo, UdmabufError> {
|
||||||
|
let height = height as u64;
|
||||||
|
let width = width as u64;
|
||||||
|
if height > 1 << 16 || width > 1 << 16 {
|
||||||
|
return Err(UdmabufError::Overflow);
|
||||||
|
}
|
||||||
|
let stride = (width * format.bpp as u64).next_multiple_of(LINEAR_STRIDE_ALIGN);
|
||||||
|
let size_mask = page_size() as u64 - 1;
|
||||||
|
let size = (height * stride + size_mask) & !size_mask;
|
||||||
|
let memfd = match uapi::memfd_create("udmabuf", MFD_ALLOW_SEALING) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => return Err(UdmabufError::Memfd(e.into())),
|
||||||
|
};
|
||||||
|
if let Err(e) = uapi::ftruncate(memfd.raw(), size as _) {
|
||||||
|
return Err(UdmabufError::Truncate(e.into()));
|
||||||
|
}
|
||||||
|
if let Err(e) = uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK) {
|
||||||
|
return Err(UdmabufError::Seal(e.into()));
|
||||||
|
}
|
||||||
|
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
||||||
|
let mut planes = PlaneVec::new();
|
||||||
|
planes.push(DmaBufPlane {
|
||||||
|
offset: 0,
|
||||||
|
stride: stride as _,
|
||||||
|
fd: Rc::new(dmabuf),
|
||||||
|
});
|
||||||
|
let dmabuf = DmaBuf {
|
||||||
|
id: dma_buf_ids.next(),
|
||||||
|
width: width as _,
|
||||||
|
height: height as _,
|
||||||
|
format,
|
||||||
|
modifier: LINEAR_MODIFIER,
|
||||||
|
planes,
|
||||||
|
is_disjoint: Default::default(),
|
||||||
|
};
|
||||||
|
Ok(UdmabufBo {
|
||||||
|
buf: dmabuf,
|
||||||
|
size: size as _,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator for Udmabuf {
|
impl Allocator for Udmabuf {
|
||||||
|
|
@ -134,45 +191,12 @@ impl Allocator for Udmabuf {
|
||||||
if !modifiers.contains(&LINEAR_MODIFIER) {
|
if !modifiers.contains(&LINEAR_MODIFIER) {
|
||||||
return Err(UdmabufError::Modifier.into());
|
return Err(UdmabufError::Modifier.into());
|
||||||
}
|
}
|
||||||
let height = height as u64;
|
Ok(Rc::new(self.create_bo(
|
||||||
let width = width as u64;
|
dma_buf_ids,
|
||||||
if height > 1 << 16 || width > 1 << 16 {
|
width,
|
||||||
return Err(UdmabufError::Overflow.into());
|
height,
|
||||||
}
|
|
||||||
let stride_mask = 255;
|
|
||||||
let stride = (width * format.bpp as u64 + stride_mask) & !stride_mask;
|
|
||||||
let size_mask = page_size() as u64 - 1;
|
|
||||||
let size = (height * stride + size_mask) & !size_mask;
|
|
||||||
let memfd = match uapi::memfd_create("udmabuf", MFD_ALLOW_SEALING) {
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(e) => return Err(UdmabufError::Memfd(e.into()).into()),
|
|
||||||
};
|
|
||||||
if let Err(e) = uapi::ftruncate(memfd.raw(), size as _) {
|
|
||||||
return Err(UdmabufError::Truncate(e.into()).into());
|
|
||||||
}
|
|
||||||
if let Err(e) = uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK) {
|
|
||||||
return Err(UdmabufError::Seal(e.into()).into());
|
|
||||||
}
|
|
||||||
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
|
||||||
let mut planes = PlaneVec::new();
|
|
||||||
planes.push(DmaBufPlane {
|
|
||||||
offset: 0,
|
|
||||||
stride: stride as _,
|
|
||||||
fd: Rc::new(dmabuf),
|
|
||||||
});
|
|
||||||
let dmabuf = DmaBuf {
|
|
||||||
id: dma_buf_ids.next(),
|
|
||||||
width: width as _,
|
|
||||||
height: height as _,
|
|
||||||
format,
|
format,
|
||||||
modifier: LINEAR_MODIFIER,
|
)?))
|
||||||
planes,
|
|
||||||
is_disjoint: Default::default(),
|
|
||||||
};
|
|
||||||
Ok(Rc::new(UdmabufBo {
|
|
||||||
buf: dmabuf,
|
|
||||||
size: size as _,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_dmabuf(
|
fn import_dmabuf(
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,6 @@ pub type Modifier = u64;
|
||||||
|
|
||||||
pub const INVALID_MODIFIER: Modifier = 0x00ff_ffff_ffff_ffff;
|
pub const INVALID_MODIFIER: Modifier = 0x00ff_ffff_ffff_ffff;
|
||||||
pub const LINEAR_MODIFIER: Modifier = 0;
|
pub const LINEAR_MODIFIER: Modifier = 0;
|
||||||
|
|
||||||
|
// This is required by AMD and therefore everyone else uses this too.
|
||||||
|
pub const LINEAR_STRIDE_ALIGN: u64 = 256;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ impl VulkanCoreInstance {
|
||||||
.map(|c| c.as_ptr())
|
.map(|c| c.as_ptr())
|
||||||
.collect();
|
.collect();
|
||||||
let app_info = ApplicationInfo::default()
|
let app_info = ApplicationInfo::default()
|
||||||
.api_version(API_VERSION)
|
.api_version(VULKAN_API_VERSION)
|
||||||
.application_name(c"jay")
|
.application_name(c"jay")
|
||||||
.application_version(1);
|
.application_version(1);
|
||||||
let mut severity = DebugUtilsMessageSeverityFlagsEXT::empty()
|
let mut severity = DebugUtilsMessageSeverityFlagsEXT::empty()
|
||||||
|
|
@ -240,4 +240,4 @@ impl Display for ApiVersionDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const API_VERSION: u32 = API_VERSION_1_3;
|
pub const VULKAN_API_VERSION: u32 = API_VERSION_1_3;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue