render: implement a vulkan renderer
This commit is contained in:
parent
4ba8550da8
commit
cf332e8436
66 changed files with 4287 additions and 239 deletions
|
|
@ -9,7 +9,6 @@ use {
|
|||
edid::Descriptor,
|
||||
format::{Format, ARGB8888, XRGB8888},
|
||||
gfx_api::{GfxContext, GfxFramebuffer, GfxTexture},
|
||||
gfx_apis::create_gfx_context,
|
||||
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||
renderer::RenderResult,
|
||||
state::State,
|
||||
|
|
@ -34,6 +33,7 @@ use {
|
|||
ahash::{AHashMap, AHashSet},
|
||||
bstr::{BString, ByteSlice},
|
||||
indexmap::{indexset, IndexSet},
|
||||
jay_config::video::GfxApi,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
ffi::CString,
|
||||
|
|
@ -75,7 +75,8 @@ pub struct MetalDrmDevice {
|
|||
pub cursor_height: u64,
|
||||
pub gbm: GbmDevice,
|
||||
pub handle_events: HandleEvents,
|
||||
pub ctx: Rc<MetalRenderContext>,
|
||||
pub ctx: CloneCell<Rc<MetalRenderContext>>,
|
||||
pub on_change: OnChange<crate::backend::DrmEvent>,
|
||||
}
|
||||
|
||||
impl BackendDrmDevice for MetalDrmDevice {
|
||||
|
|
@ -84,19 +85,27 @@ impl BackendDrmDevice for MetalDrmDevice {
|
|||
}
|
||||
|
||||
fn event(&self) -> Option<crate::backend::DrmEvent> {
|
||||
None
|
||||
self.on_change.events.pop()
|
||||
}
|
||||
|
||||
fn on_change(&self, _cb: Rc<dyn Fn()>) {
|
||||
// nothing
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.on_change.on_change.set(Some(cb));
|
||||
}
|
||||
|
||||
fn dev_t(&self) -> dev_t {
|
||||
self.devnum
|
||||
}
|
||||
|
||||
fn make_render_device(self: Rc<Self>) {
|
||||
self.backend.make_render_device(&self, true);
|
||||
fn make_render_device(&self) {
|
||||
self.backend.make_render_device(&self, false);
|
||||
}
|
||||
|
||||
fn set_gfx_api(&self, api: GfxApi) {
|
||||
self.backend.set_gfx_api(self, api)
|
||||
}
|
||||
|
||||
fn gtx_api(&self) -> GfxApi {
|
||||
self.ctx.get().gfx.gfx_api()
|
||||
}
|
||||
|
||||
fn version(&self) -> Result<DrmVersion, DrmError> {
|
||||
|
|
@ -162,8 +171,6 @@ pub struct MetalConnector {
|
|||
|
||||
pub connector_id: ConnectorId,
|
||||
|
||||
pub events: SyncQueue<ConnectorEvent>,
|
||||
|
||||
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
||||
pub next_buffer: NumCell<usize>,
|
||||
|
||||
|
|
@ -182,7 +189,7 @@ pub struct MetalConnector {
|
|||
|
||||
pub crtc: CloneCell<Option<Rc<MetalCrtc>>>,
|
||||
|
||||
pub on_change: OnChange,
|
||||
pub on_change: OnChange<ConnectorEvent>,
|
||||
|
||||
pub present_trigger: AsyncEvent,
|
||||
|
||||
|
|
@ -271,12 +278,30 @@ impl Debug for ConnectorFutures {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OnChange {
|
||||
pub struct OnChange<T> {
|
||||
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
pub events: SyncQueue<T>,
|
||||
}
|
||||
|
||||
impl Debug for OnChange {
|
||||
impl<T> OnChange<T> {
|
||||
pub fn send_event(&self, event: T) {
|
||||
self.events.push(event);
|
||||
if let Some(cb) = self.on_change.get() {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for OnChange<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
on_change: Default::default(),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for OnChange<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self.on_change.get() {
|
||||
None => f.write_str("None"),
|
||||
|
|
@ -311,7 +336,8 @@ impl MetalConnector {
|
|||
}) as _),
|
||||
_ => None,
|
||||
};
|
||||
self.send_event(ConnectorEvent::HardwareCursor(hc));
|
||||
self.on_change
|
||||
.send_event(ConnectorEvent::HardwareCursor(hc));
|
||||
}
|
||||
|
||||
fn connected(&self) -> bool {
|
||||
|
|
@ -321,13 +347,6 @@ impl MetalConnector {
|
|||
&& self.primary_plane.get().is_some()
|
||||
}
|
||||
|
||||
fn send_event(&self, event: ConnectorEvent) {
|
||||
self.events.push(event);
|
||||
if let Some(oc) = self.on_change.on_change.get() {
|
||||
oc();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schedule_present(&self) {
|
||||
self.present_trigger.trigger();
|
||||
}
|
||||
|
|
@ -370,7 +389,7 @@ impl MetalConnector {
|
|||
!self.cursor_enabled.get(),
|
||||
);
|
||||
if let Some(tex) = &buffer.dev_tex {
|
||||
buffer.dev_fb.copy_texture(&self.state, tex, 0, 0, false);
|
||||
buffer.dev_fb.copy_texture(tex, 0, 0);
|
||||
}
|
||||
for fr in rr.frame_requests.drain(..) {
|
||||
fr.send_done();
|
||||
|
|
@ -393,7 +412,7 @@ impl MetalConnector {
|
|||
let buffer = &buffers[self.cursor_front_buffer.get() % buffers.len()];
|
||||
if swap_buffer {
|
||||
if let Some(tex) = &buffer.dev_tex {
|
||||
buffer.dev_fb.copy_texture(&self.state, tex, 0, 0, true);
|
||||
buffer.dev_fb.copy_texture(tex, 0, 0);
|
||||
}
|
||||
}
|
||||
let (width, height) = buffer.dev_fb.size();
|
||||
|
|
@ -445,7 +464,7 @@ impl Connector for MetalConnector {
|
|||
}
|
||||
|
||||
fn event(&self) -> Option<ConnectorEvent> {
|
||||
self.events.pop()
|
||||
self.on_change.events.pop()
|
||||
}
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
|
|
@ -577,7 +596,6 @@ fn create_connector(
|
|||
dev: dev.clone(),
|
||||
backend: backend.clone(),
|
||||
connector_id: backend.state.connector_ids.next(),
|
||||
events: Default::default(),
|
||||
buffers: Default::default(),
|
||||
next_buffer: Default::default(),
|
||||
enabled: Cell::new(true),
|
||||
|
|
@ -910,7 +928,7 @@ impl MetalBackend {
|
|||
if let Some(r) = ctx
|
||||
.gfx
|
||||
.reset_status()
|
||||
.or_else(|| dev.ctx.gfx.reset_status())
|
||||
.or_else(|| dev.ctx.get().gfx.reset_status())
|
||||
{
|
||||
fatal!("EGL context has been reset: {:?}", r);
|
||||
}
|
||||
|
|
@ -988,9 +1006,9 @@ impl MetalBackend {
|
|||
dev.futures.remove(&c);
|
||||
if let Some(c) = dev.connectors.remove(&c) {
|
||||
if c.connect_sent.get() {
|
||||
c.send_event(ConnectorEvent::Disconnected);
|
||||
c.on_change.send_event(ConnectorEvent::Disconnected);
|
||||
}
|
||||
c.send_event(ConnectorEvent::Removed);
|
||||
c.on_change.send_event(ConnectorEvent::Removed);
|
||||
}
|
||||
}
|
||||
let mut preserve = Preserve::default();
|
||||
|
|
@ -1012,7 +1030,7 @@ impl MetalBackend {
|
|||
|| old.connection != ConnectorStatus::Connected
|
||||
|| !old.is_same_monitor(&dd)
|
||||
{
|
||||
c.send_event(ConnectorEvent::Disconnected);
|
||||
c.on_change.send_event(ConnectorEvent::Disconnected);
|
||||
c.connect_sent.set(false);
|
||||
} else if preserve_any {
|
||||
preserve.connectors.insert(c.id);
|
||||
|
|
@ -1054,15 +1072,17 @@ impl MetalBackend {
|
|||
modes.push(mode);
|
||||
}
|
||||
}
|
||||
connector.send_event(ConnectorEvent::Connected(MonitorInfo {
|
||||
modes,
|
||||
manufacturer: dd.monitor_manufacturer.clone(),
|
||||
product: dd.monitor_name.clone(),
|
||||
serial_number: dd.monitor_serial_number.clone(),
|
||||
initial_mode: dd.mode.clone().unwrap().to_backend(),
|
||||
width_mm: dd.mm_width as _,
|
||||
height_mm: dd.mm_height as _,
|
||||
}));
|
||||
connector
|
||||
.on_change
|
||||
.send_event(ConnectorEvent::Connected(MonitorInfo {
|
||||
modes,
|
||||
manufacturer: dd.monitor_manufacturer.clone(),
|
||||
product: dd.monitor_name.clone(),
|
||||
serial_number: dd.monitor_serial_number.clone(),
|
||||
initial_mode: dd.mode.clone().unwrap().to_backend(),
|
||||
width_mm: dd.mm_width as _,
|
||||
height_mm: dd.mm_height as _,
|
||||
}));
|
||||
connector.connect_sent.set(true);
|
||||
connector.send_hardware_cursor();
|
||||
}
|
||||
|
|
@ -1115,7 +1135,7 @@ impl MetalBackend {
|
|||
}
|
||||
}
|
||||
|
||||
let gfx = match create_gfx_context(master) {
|
||||
let gfx = match self.state.create_gfx_context(master, None) {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
||||
};
|
||||
|
|
@ -1148,7 +1168,8 @@ impl MetalBackend {
|
|||
handle_events: HandleEvents {
|
||||
handle_events: Cell::new(None),
|
||||
},
|
||||
ctx,
|
||||
ctx: CloneCell::new(ctx),
|
||||
on_change: Default::default(),
|
||||
});
|
||||
|
||||
let (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?;
|
||||
|
|
@ -1440,28 +1461,68 @@ impl MetalBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_render_device(&self, dev: &Rc<MetalDrmDevice>, log: bool) -> bool {
|
||||
if let Some(ctx) = self.ctx.get() {
|
||||
if ctx.dev_id == dev.id {
|
||||
return true;
|
||||
fn make_render_device(&self, dev: &MetalDrmDevice, force: bool) {
|
||||
if !force {
|
||||
if let Some(ctx) = self.ctx.get() {
|
||||
if ctx.dev_id == dev.id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.state.set_render_ctx(Some(dev.ctx.gfx.clone()));
|
||||
self.ctx.set(Some(dev.ctx.clone()));
|
||||
let mut preserve = Preserve::default();
|
||||
let ctx = dev.ctx.get();
|
||||
self.state.set_render_ctx(Some(ctx.gfx.clone()));
|
||||
self.ctx.set(Some(ctx));
|
||||
for dev in self.device_holder.drm_devices.lock().values() {
|
||||
if let Err(e) = self.init_drm_device(dev, &mut preserve) {
|
||||
if log {
|
||||
log::error!("Could not initialize device: {}", ErrorFmt(e));
|
||||
}
|
||||
self.re_init_drm_device(&dev);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_gfx_api(&self, dev: &MetalDrmDevice, api: GfxApi) {
|
||||
if dev.ctx.get().gfx.gfx_api() == api {
|
||||
return;
|
||||
}
|
||||
let gfx = match self.state.create_gfx_context(&dev.master, Some(api)) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Could not create a new graphics context for device {:?}: {}",
|
||||
dev.devnode,
|
||||
ErrorFmt(e)
|
||||
);
|
||||
return;
|
||||
}
|
||||
for connector in dev.connectors.lock().values() {
|
||||
if connector.connected() {
|
||||
self.start_connector(connector, false);
|
||||
}
|
||||
};
|
||||
dev.on_change
|
||||
.send_event(crate::backend::DrmEvent::GfxApiChanged);
|
||||
dev.ctx.set(Rc::new(MetalRenderContext {
|
||||
dev_id: dev.id,
|
||||
gfx,
|
||||
}));
|
||||
let mut is_render_ctx = false;
|
||||
if let Some(render_ctx) = self.ctx.get() {
|
||||
if render_ctx.dev_id == dev.id {
|
||||
is_render_ctx = true;
|
||||
}
|
||||
}
|
||||
if is_render_ctx {
|
||||
self.make_render_device(dev, true);
|
||||
} else {
|
||||
if let Some(dev) = self.device_holder.drm_devices.get(&dev.devnum) {
|
||||
self.re_init_drm_device(&dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn re_init_drm_device(&self, dev: &Rc<MetalDrmDeviceData>) {
|
||||
let mut preserve = Preserve::default();
|
||||
if let Err(e) = self.init_drm_device(dev, &mut preserve) {
|
||||
log::error!("Could not initialize device: {}", ErrorFmt(e));
|
||||
}
|
||||
for connector in dev.connectors.lock().values() {
|
||||
if connector.connected() {
|
||||
self.start_connector(connector, false);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn init_drm_device(
|
||||
|
|
@ -1616,7 +1677,8 @@ impl MetalBackend {
|
|||
render_ctx: &MetalRenderContext,
|
||||
cursor: bool,
|
||||
) -> Result<RenderBuffer, MetalError> {
|
||||
let dev_gfx_formats = dev.ctx.gfx.formats();
|
||||
let ctx = dev.ctx.get();
|
||||
let dev_gfx_formats = ctx.gfx.formats();
|
||||
let dev_gfx_format = match dev_gfx_formats.get(&format.drm) {
|
||||
None => return Err(MetalError::MissingDevFormat(format.name)),
|
||||
Some(f) => f,
|
||||
|
|
@ -1647,7 +1709,7 @@ impl MetalBackend {
|
|||
Ok(fb) => Rc::new(fb),
|
||||
Err(e) => return Err(MetalError::Framebuffer(e)),
|
||||
};
|
||||
let dev_img = match dev.ctx.gfx.clone().dmabuf_img(dev_bo.dmabuf()) {
|
||||
let dev_img = match ctx.gfx.clone().dmabuf_img(dev_bo.dmabuf()) {
|
||||
Ok(img) => img,
|
||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||
};
|
||||
|
|
@ -1708,7 +1770,7 @@ impl MetalBackend {
|
|||
};
|
||||
|
||||
// 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 ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
||||
Ok(img) => img,
|
||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use {
|
|||
fixed::Fixed,
|
||||
format::XRGB8888,
|
||||
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
||||
gfx_apis::create_gfx_context,
|
||||
renderer::RenderResult,
|
||||
state::State,
|
||||
time::now_usec,
|
||||
|
|
@ -50,6 +49,7 @@ use {
|
|||
Event, XEvent, Xcon, XconError,
|
||||
},
|
||||
},
|
||||
jay_config::video::GfxApi,
|
||||
std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
|
|
@ -181,7 +181,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
|||
Err(e) => return Err(XBackendError::DrmDeviceFstat(e)),
|
||||
};
|
||||
let gbm = GbmDevice::new(&drm)?;
|
||||
let ctx = match create_gfx_context(&drm) {
|
||||
let ctx = match state.create_gfx_context(&drm, None) {
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(XBackendError::CreateEgl(e)),
|
||||
};
|
||||
|
|
@ -976,11 +976,20 @@ impl BackendDrmDevice for XDrmDevice {
|
|||
self.dev
|
||||
}
|
||||
|
||||
fn make_render_device(self: Rc<Self>) {
|
||||
fn make_render_device(&self) {
|
||||
log::warn!("make_render_device is not supported by the X backend");
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn set_gfx_api(&self, _api: GfxApi) {
|
||||
log::warn!("set_gfx_api is not supported by the X backend");
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn gtx_api(&self) -> GfxApi {
|
||||
self.backend.ctx.gfx_api()
|
||||
}
|
||||
|
||||
fn version(&self) -> Result<DrmVersion, DrmError> {
|
||||
self.backend.gbm.drm.version()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue