vulkan: implement software rendering
This commit is contained in:
parent
bb29303c98
commit
0a5ee8fa36
10 changed files with 140 additions and 31 deletions
|
|
@ -108,6 +108,11 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
|
||||||
("flags", "EGLint"),
|
("flags", "EGLint"),
|
||||||
][..],
|
][..],
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"eglQueryDeviceStringEXT",
|
||||||
|
"*const c::c_char",
|
||||||
|
&[("device", "EGLDeviceEXT"), ("name", "EGLint")][..],
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
writeln!(f, "use std::ptr;")?;
|
writeln!(f, "use std::ptr;")?;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,21 @@ pub fn create_gfx_context(
|
||||||
let mut apis = [GfxApi::OpenGl, GfxApi::Vulkan];
|
let mut apis = [GfxApi::OpenGl, GfxApi::Vulkan];
|
||||||
apis.sort_by_key(|&a| if a == api { -1 } else { a as i32 });
|
apis.sort_by_key(|&a| if a == api { -1 } else { a as i32 });
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for api in apis {
|
for software in [false, true] {
|
||||||
let res = create_gfx_context_(eng, ring, drm, api, caps_thread);
|
for api in apis {
|
||||||
match res {
|
let res = create_gfx_context_(eng, ring, drm, api, caps_thread, software);
|
||||||
Ok(_) => return res,
|
match res {
|
||||||
Err(e) => {
|
Ok(_) => {
|
||||||
log::warn!("Could not create {:?} API: {}", api, ErrorFmt(&e));
|
log::info!("Created a {api:?} renderer");
|
||||||
last_err = Some(e);
|
if software {
|
||||||
|
log::warn!("Renderer uses software rendering");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not create {:?} API: {}", api, ErrorFmt(&e));
|
||||||
|
last_err = Some(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,10 +52,11 @@ fn create_gfx_context_(
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
api: GfxApi,
|
api: GfxApi,
|
||||||
caps_thread: Option<&PrCapsThread>,
|
caps_thread: Option<&PrCapsThread>,
|
||||||
|
software: bool,
|
||||||
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
match api {
|
match api {
|
||||||
GfxApi::OpenGl => gl::create_gfx_context(drm),
|
GfxApi::OpenGl => gl::create_gfx_context(drm, software),
|
||||||
GfxApi::Vulkan => vulkan::create_graphics_context(eng, ring, drm, caps_thread),
|
GfxApi::Vulkan => vulkan::create_graphics_context(eng, ring, drm, caps_thread, software),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,14 @@ pub mod sys {
|
||||||
|
|
||||||
static INIT: Lazy<Result<(), Arc<RenderError>>> = Lazy::new(|| egl::init().map_err(Arc::new));
|
static INIT: Lazy<Result<(), Arc<RenderError>>> = Lazy::new(|| egl::init().map_err(Arc::new));
|
||||||
|
|
||||||
pub(super) fn create_gfx_context(drm: &Drm) -> Result<Rc<dyn GfxContext>, GfxError> {
|
pub(super) fn create_gfx_context(
|
||||||
|
drm: &Drm,
|
||||||
|
software: bool,
|
||||||
|
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
if let Err(e) = &*INIT {
|
if let Err(e) = &*INIT {
|
||||||
return Err(GfxError(Box::new(e.clone())));
|
return Err(GfxError(Box::new(e.clone())));
|
||||||
}
|
}
|
||||||
GlRenderContext::from_drm_device(drm)
|
GlRenderContext::from_drm_device(drm, software)
|
||||||
.map(|v| Rc::new(v) as Rc<dyn GfxContext>)
|
.map(|v| Rc::new(v) as Rc<dyn GfxContext>)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
@ -200,6 +203,10 @@ enum RenderError {
|
||||||
AccessFailed(#[source] Box<dyn Error + Sync + Send>),
|
AccessFailed(#[source] Box<dyn Error + Sync + Send>),
|
||||||
#[error("OpenGL does not support blend buffers")]
|
#[error("OpenGL does not support blend buffers")]
|
||||||
NoBlendBuffer,
|
NoBlendBuffer,
|
||||||
|
#[error("Hardware renderer was requested but EGL device is a software renderer")]
|
||||||
|
NoHardwareRenderer,
|
||||||
|
#[error("Could not query display device")]
|
||||||
|
QueryDisplayDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
gfx_apis::gl::{
|
gfx_apis::gl::{
|
||||||
RenderError,
|
RenderError,
|
||||||
egl::{
|
egl::{
|
||||||
PROCS,
|
EXTS, PROCS,
|
||||||
context::EglContext,
|
context::EglContext,
|
||||||
image::EglImage,
|
image::EglImage,
|
||||||
sys::{
|
sys::{
|
||||||
|
|
@ -26,9 +26,10 @@ use {
|
||||||
},
|
},
|
||||||
ext::{
|
ext::{
|
||||||
ANDROID_NATIVE_FENCE_SYNC, DisplayExt, EXT_CREATE_CONTEXT_ROBUSTNESS,
|
ANDROID_NATIVE_FENCE_SYNC, DisplayExt, EXT_CREATE_CONTEXT_ROBUSTNESS,
|
||||||
EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS, GL_OES_EGL_IMAGE, GL_OES_EGL_IMAGE_EXTERNAL,
|
EXT_DEVICE_QUERY, EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS, GL_OES_EGL_IMAGE,
|
||||||
GlExt, KHR_FENCE_SYNC, KHR_IMAGE_BASE, KHR_NO_CONFIG_CONTEXT,
|
GL_OES_EGL_IMAGE_EXTERNAL, GlExt, KHR_FENCE_SYNC, KHR_IMAGE_BASE,
|
||||||
KHR_SURFACELESS_CONTEXT, KHR_WAIT_SYNC, MESA_CONFIGLESS_CONTEXT, get_display_ext,
|
KHR_NO_CONFIG_CONTEXT, KHR_SURFACELESS_CONTEXT, KHR_WAIT_SYNC,
|
||||||
|
MESA_CONFIGLESS_CONTEXT, MESA_DEVICE_SOFTWARE, get_device_ext, get_display_ext,
|
||||||
get_gl_ext,
|
get_gl_ext,
|
||||||
},
|
},
|
||||||
proc::ExtProc,
|
proc::ExtProc,
|
||||||
|
|
@ -70,7 +71,10 @@ pub struct EglDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EglDisplay {
|
impl EglDisplay {
|
||||||
pub(in crate::gfx_apis::gl) fn create(drm: &Drm) -> Result<Rc<Self>, RenderError> {
|
pub(in crate::gfx_apis::gl) fn create(
|
||||||
|
drm: &Drm,
|
||||||
|
software: bool,
|
||||||
|
) -> Result<Rc<Self>, RenderError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let Some(egl) = EGL.as_ref() else {
|
let Some(egl) = EGL.as_ref() else {
|
||||||
return Err(RenderError::LoadEgl);
|
return Err(RenderError::LoadEgl);
|
||||||
|
|
@ -108,6 +112,11 @@ impl EglDisplay {
|
||||||
if (egl.eglInitialize)(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
|
if (egl.eglInitialize)(dpy.dpy, &mut major, &mut minor) != EGL_TRUE {
|
||||||
return Err(RenderError::Initialize);
|
return Err(RenderError::Initialize);
|
||||||
}
|
}
|
||||||
|
if !software && EXTS.contains(EXT_DEVICE_QUERY) {
|
||||||
|
if get_device_ext(procs, dpy.dpy)?.contains(MESA_DEVICE_SOFTWARE) {
|
||||||
|
return Err(RenderError::NoHardwareRenderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
dpy.exts = get_display_ext(dpy.dpy);
|
dpy.exts = get_display_ext(dpy.dpy);
|
||||||
if !dpy.exts.intersects(KHR_IMAGE_BASE) {
|
if !dpy.exts.intersects(KHR_IMAGE_BASE) {
|
||||||
return Err(RenderError::ImageBase);
|
return Err(RenderError::ImageBase);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ egl_transparent!(EGLImageKHR);
|
||||||
egl_transparent!(EGLContext);
|
egl_transparent!(EGLContext);
|
||||||
egl_transparent!(EGLClientBuffer);
|
egl_transparent!(EGLClientBuffer);
|
||||||
egl_transparent!(EGLLabelKHR);
|
egl_transparent!(EGLLabelKHR);
|
||||||
|
egl_transparent!(EGLDeviceEXT);
|
||||||
|
|
||||||
pub type EGLDEBUGPROCKHR = unsafe extern "C" fn(
|
pub type EGLDEBUGPROCKHR = unsafe extern "C" fn(
|
||||||
error: EGLenum,
|
error: EGLenum,
|
||||||
|
|
@ -53,6 +54,7 @@ pub const EGL_PLATFORM_GBM_KHR: EGLint = 0x31D7;
|
||||||
pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098;
|
pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098;
|
||||||
pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: EGLint = 0x3138;
|
pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: EGLint = 0x3138;
|
||||||
pub const EGL_LOSE_CONTEXT_ON_RESET_EXT: EGLint = 0x31BF;
|
pub const EGL_LOSE_CONTEXT_ON_RESET_EXT: EGLint = 0x31BF;
|
||||||
|
pub const EGL_DEVICE_EXT: EGLint = 0x322C;
|
||||||
|
|
||||||
pub const GL_GUILTY_CONTEXT_RESET_ARB: GLenum = 0x8253;
|
pub const GL_GUILTY_CONTEXT_RESET_ARB: GLenum = 0x8253;
|
||||||
pub const GL_INNOCENT_CONTEXT_RESET_ARB: GLenum = 0x8254;
|
pub const GL_INNOCENT_CONTEXT_RESET_ARB: GLenum = 0x8254;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ use {
|
||||||
RenderError,
|
RenderError,
|
||||||
egl::sys::{EGL_EXTENSIONS, EGLDisplay},
|
egl::sys::{EGL_EXTENSIONS, EGLDisplay},
|
||||||
gl::sys::GL_EXTENSIONS,
|
gl::sys::GL_EXTENSIONS,
|
||||||
sys::{EGL, GLESV2},
|
proc::ExtProc,
|
||||||
|
sys::{EGL, EGL_DEVICE_EXT, EGL_TRUE, EGLDeviceEXT, GLESV2},
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
|
|
@ -53,6 +54,7 @@ bitflags! {
|
||||||
EXT_PLATFORM_BASE = 1 << 1,
|
EXT_PLATFORM_BASE = 1 << 1,
|
||||||
KHR_PLATFORM_GBM = 1 << 2,
|
KHR_PLATFORM_GBM = 1 << 2,
|
||||||
KHR_DEBUG = 1 << 3,
|
KHR_DEBUG = 1 << 3,
|
||||||
|
EXT_DEVICE_QUERY = 1 << 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_client_ext() -> ClientExt {
|
pub fn get_client_ext() -> ClientExt {
|
||||||
|
|
@ -60,6 +62,7 @@ pub fn get_client_ext() -> ClientExt {
|
||||||
("EGL_EXT_platform_base", EXT_PLATFORM_BASE),
|
("EGL_EXT_platform_base", EXT_PLATFORM_BASE),
|
||||||
("EGL_KHR_platform_gbm", KHR_PLATFORM_GBM),
|
("EGL_KHR_platform_gbm", KHR_PLATFORM_GBM),
|
||||||
("EGL_KHR_debug", KHR_DEBUG),
|
("EGL_KHR_debug", KHR_DEBUG),
|
||||||
|
("EGL_EXT_device_query", EXT_DEVICE_QUERY),
|
||||||
];
|
];
|
||||||
match unsafe { get_dpy_extensions(EGLDisplay::none()) } {
|
match unsafe { get_dpy_extensions(EGLDisplay::none()) } {
|
||||||
Some(exts) => get_typed_ext(&exts, EXT_CLIENT_EXTENSION, &map),
|
Some(exts) => get_typed_ext(&exts, EXT_CLIENT_EXTENSION, &map),
|
||||||
|
|
@ -127,3 +130,24 @@ pub fn get_gl_ext() -> Result<GlExt, RenderError> {
|
||||||
_ => Ok(GlExt::none()),
|
_ => Ok(GlExt::none()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
DevExt: u32;
|
||||||
|
MESA_DEVICE_SOFTWARE = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device_ext(procs: &ExtProc, dpy: EGLDisplay) -> Result<DevExt, RenderError> {
|
||||||
|
let map = [("EGL_MESA_device_software", MESA_DEVICE_SOFTWARE)];
|
||||||
|
unsafe {
|
||||||
|
let mut device = 0;
|
||||||
|
if procs.eglQueryDisplayAttribEXT(dpy, EGL_DEVICE_EXT, &mut device) != EGL_TRUE {
|
||||||
|
return Err(RenderError::QueryDisplayDevice);
|
||||||
|
}
|
||||||
|
let device = EGLDeviceEXT(device as _);
|
||||||
|
let ext = procs.eglQueryDeviceStringEXT(device, EGL_EXTENSIONS);
|
||||||
|
match get_extensions(ext) {
|
||||||
|
Some(exts) => Ok(get_typed_ext(&exts, DevExt::none(), &map)),
|
||||||
|
_ => Ok(DevExt::none()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,15 @@ impl GlRenderContext {
|
||||||
self.ctx.reset_status()
|
self.ctx.reset_status()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::gfx_apis::gl) fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
pub(in crate::gfx_apis::gl) fn from_drm_device(
|
||||||
|
drm: &Drm,
|
||||||
|
software: bool,
|
||||||
|
) -> Result<Self, RenderError> {
|
||||||
let node = drm
|
let node = drm
|
||||||
.get_render_node()?
|
.get_render_node()?
|
||||||
.ok_or(RenderError::NoRenderNode)
|
.ok_or(RenderError::NoRenderNode)
|
||||||
.map(Rc::new)?;
|
.map(Rc::new)?;
|
||||||
let dpy = EglDisplay::create(drm)?;
|
let dpy = EglDisplay::create(drm, software)?;
|
||||||
if !dpy.formats.contains_key(&XRGB8888.drm) {
|
if !dpy.formats.contains_key(&XRGB8888.drm) {
|
||||||
return Err(RenderError::XRGB888);
|
return Err(RenderError::XRGB888);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ pub enum VulkanError {
|
||||||
EnumeratePhysicalDevices(#[source] vk::Result),
|
EnumeratePhysicalDevices(#[source] vk::Result),
|
||||||
#[error("Could not find a vulkan device that matches dev_t {0}")]
|
#[error("Could not find a vulkan device that matches dev_t {0}")]
|
||||||
NoDeviceFound(dev_t),
|
NoDeviceFound(dev_t),
|
||||||
|
#[error("There is no vulkan software renderer")]
|
||||||
|
NoSoftwareRenderer,
|
||||||
#[error("Could not load image properties")]
|
#[error("Could not load image properties")]
|
||||||
LoadImageProperties(#[source] vk::Result),
|
LoadImageProperties(#[source] vk::Result),
|
||||||
#[error("Device does not support rending and texturing from the XRGB8888 format")]
|
#[error("Device does not support rending and texturing from the XRGB8888 format")]
|
||||||
|
|
@ -214,6 +216,12 @@ pub enum VulkanError {
|
||||||
NonVulkanBuffer,
|
NonVulkanBuffer,
|
||||||
#[error("Mixed vulkan device use")]
|
#[error("Mixed vulkan device use")]
|
||||||
MixedVulkanDeviceUse,
|
MixedVulkanDeviceUse,
|
||||||
|
#[error("Could not allocate GBM BO")]
|
||||||
|
AllocGbm(#[source] GbmError),
|
||||||
|
#[error("Could not retrieve file description flags")]
|
||||||
|
GetFl(#[source] OsError),
|
||||||
|
#[error("GBM implementation cannot be used with software renderer")]
|
||||||
|
SoftwareRendererNotUsable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<VulkanError> for GfxError {
|
impl From<VulkanError> for GfxError {
|
||||||
|
|
@ -230,18 +238,19 @@ pub fn create_graphics_context(
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
caps_thread: Option<&PrCapsThread>,
|
caps_thread: Option<&PrCapsThread>,
|
||||||
|
software: bool,
|
||||||
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
let instance = VulkanInstance::new(Level::Info, *VULKAN_VALIDATION)?;
|
let instance = VulkanInstance::new(Level::Info, *VULKAN_VALIDATION)?;
|
||||||
let device = 'device: {
|
let device = 'device: {
|
||||||
if let Some(t) = caps_thread {
|
if let Some(t) = caps_thread {
|
||||||
match unsafe { t.run(|| instance.create_device(drm, true)) } {
|
match unsafe { t.run(|| instance.create_device(drm, true, software)) } {
|
||||||
Ok(d) => break 'device d,
|
Ok(d) => break 'device d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not create high-priority device: {}", ErrorFmt(e));
|
log::warn!("Could not create high-priority device: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instance.create_device(drm, false)?
|
instance.create_device(drm, false, software)?
|
||||||
};
|
};
|
||||||
let renderer = device.create_renderer(eng, ring)?;
|
let renderer = device.create_renderer(eng, ring)?;
|
||||||
Ok(Rc::new(Context(renderer)))
|
Ok(Rc::new(Context(renderer)))
|
||||||
|
|
@ -249,7 +258,7 @@ pub fn create_graphics_context(
|
||||||
|
|
||||||
pub fn create_vulkan_allocator(drm: &Drm) -> Result<Rc<dyn Allocator>, AllocatorError> {
|
pub fn create_vulkan_allocator(drm: &Drm) -> Result<Rc<dyn Allocator>, AllocatorError> {
|
||||||
let instance = VulkanInstance::new(Level::Debug, *VULKAN_VALIDATION)?;
|
let instance = VulkanInstance::new(Level::Debug, *VULKAN_VALIDATION)?;
|
||||||
let device = instance.create_device(drm, false)?;
|
let device = instance.create_device(drm, false, false)?;
|
||||||
let allocator = device.create_bo_allocator(drm)?;
|
let allocator = device.create_bo_allocator(drm)?;
|
||||||
Ok(Rc::new(allocator))
|
Ok(Rc::new(allocator))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
allocator::BufferObject,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError,
|
VulkanError,
|
||||||
|
|
@ -9,10 +10,11 @@ use {
|
||||||
map_extension_properties,
|
map_extension_properties,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::on_drop::OnDrop,
|
utils::{bitflags::BitflagsExt, on_drop::OnDrop},
|
||||||
video::{
|
video::{
|
||||||
|
dmabuf::DmaBufIds,
|
||||||
drm::{Drm, sync_obj::SyncObjCtx},
|
drm::{Drm, sync_obj::SyncObjCtx},
|
||||||
gbm::GbmDevice,
|
gbm::{GBM_BO_USE_RENDERING, GbmDevice},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -37,7 +39,7 @@ use {
|
||||||
PhysicalDeviceDrmPropertiesEXT, PhysicalDeviceDynamicRenderingFeatures,
|
PhysicalDeviceDrmPropertiesEXT, PhysicalDeviceDynamicRenderingFeatures,
|
||||||
PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceProperties,
|
PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceProperties,
|
||||||
PhysicalDeviceProperties2, PhysicalDeviceSynchronization2Features,
|
PhysicalDeviceProperties2, PhysicalDeviceSynchronization2Features,
|
||||||
PhysicalDeviceTimelineSemaphoreFeatures,
|
PhysicalDeviceTimelineSemaphoreFeatures, PhysicalDeviceType,
|
||||||
PhysicalDeviceUniformBufferStandardLayoutFeatures, PhysicalDeviceVulkan12Properties,
|
PhysicalDeviceUniformBufferStandardLayoutFeatures, PhysicalDeviceVulkan12Properties,
|
||||||
Queue, QueueFamilyProperties2, QueueFlags, QueueGlobalPriorityKHR,
|
Queue, QueueFamilyProperties2, QueueFlags, QueueGlobalPriorityKHR,
|
||||||
},
|
},
|
||||||
|
|
@ -49,7 +51,7 @@ use {
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
},
|
},
|
||||||
uapi::Ustr,
|
uapi::{Ustr, c::O_RDWR},
|
||||||
vk::QueueFamilyGlobalPriorityPropertiesKHR,
|
vk::QueueFamilyGlobalPriorityPropertiesKHR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -208,6 +210,24 @@ impl VulkanInstance {
|
||||||
Err(VulkanError::NoDeviceFound(dev))
|
Err(VulkanError::NoDeviceFound(dev))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_software_renderer(&self) -> Result<PhysicalDevice, VulkanError> {
|
||||||
|
let phy_devs = unsafe { self.instance.enumerate_physical_devices() };
|
||||||
|
let phy_devs = match phy_devs {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => return Err(VulkanError::EnumeratePhysicalDevices(e)),
|
||||||
|
};
|
||||||
|
for phy_dev in phy_devs {
|
||||||
|
let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
|
||||||
|
if props.api_version < API_VERSION {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if props.device_type == PhysicalDeviceType::CPU {
|
||||||
|
return Ok(phy_dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(VulkanError::NoSoftwareRenderer)
|
||||||
|
}
|
||||||
|
|
||||||
fn find_queues(
|
fn find_queues(
|
||||||
&self,
|
&self,
|
||||||
phy_dev: PhysicalDevice,
|
phy_dev: PhysicalDevice,
|
||||||
|
|
@ -316,6 +336,7 @@ impl VulkanInstance {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
mut high_priority: bool,
|
mut high_priority: bool,
|
||||||
|
software: bool,
|
||||||
) -> Result<Rc<VulkanDevice>, VulkanError> {
|
) -> Result<Rc<VulkanDevice>, VulkanError> {
|
||||||
let render_node = drm
|
let render_node = drm
|
||||||
.get_render_node()
|
.get_render_node()
|
||||||
|
|
@ -323,7 +344,10 @@ impl VulkanInstance {
|
||||||
.ok_or(VulkanError::NoRenderNode)
|
.ok_or(VulkanError::NoRenderNode)
|
||||||
.map(Rc::new)?;
|
.map(Rc::new)?;
|
||||||
let gbm = GbmDevice::new(drm).map_err(VulkanError::Gbm)?;
|
let gbm = GbmDevice::new(drm).map_err(VulkanError::Gbm)?;
|
||||||
let phy_dev = self.find_dev(drm)?;
|
let phy_dev = match software {
|
||||||
|
true => self.find_software_renderer()?,
|
||||||
|
false => self.find_dev(drm)?,
|
||||||
|
};
|
||||||
let extensions = self.get_device_extensions(phy_dev)?;
|
let extensions = self.get_device_extensions(phy_dev)?;
|
||||||
for &ext in REQUIRED_DEVICE_EXTENSIONS {
|
for &ext in REQUIRED_DEVICE_EXTENSIONS {
|
||||||
if extensions.not_contains_key(ext) {
|
if extensions.not_contains_key(ext) {
|
||||||
|
|
@ -440,6 +464,23 @@ impl VulkanInstance {
|
||||||
if !supports_xrgb8888 {
|
if !supports_xrgb8888 {
|
||||||
return Err(VulkanError::XRGB8888);
|
return Err(VulkanError::XRGB8888);
|
||||||
}
|
}
|
||||||
|
if software {
|
||||||
|
let bo = gbm
|
||||||
|
.create_bo(
|
||||||
|
&DmaBufIds::default(),
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
XRGB8888,
|
||||||
|
formats.get(&XRGB8888.drm).unwrap().modifiers.keys(),
|
||||||
|
GBM_BO_USE_RENDERING,
|
||||||
|
)
|
||||||
|
.map_err(VulkanError::AllocGbm)?;
|
||||||
|
let fl = uapi::fcntl_getfl(bo.dmabuf().planes[0].fd.raw())
|
||||||
|
.map_err(|e| VulkanError::GetFl(e.into()))?;
|
||||||
|
if fl.not_contains(O_RDWR) {
|
||||||
|
return Err(VulkanError::SoftwareRendererNotUsable);
|
||||||
|
}
|
||||||
|
}
|
||||||
destroy_device.forget();
|
destroy_device.forget();
|
||||||
let external_memory_fd = external_memory_fd::Device::new(&self.instance, &device);
|
let external_memory_fd = external_memory_fd::Device::new(&self.instance, &device);
|
||||||
let external_semaphore_fd = external_semaphore_fd::Device::new(&self.instance, &device);
|
let external_semaphore_fd = external_semaphore_fd::Device::new(&self.instance, &device);
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ impl GbmDevice {
|
||||||
if modifiers.is_empty() {
|
if modifiers.is_empty() {
|
||||||
return Err(GbmError::NoModifier);
|
return Err(GbmError::NoModifier);
|
||||||
}
|
}
|
||||||
let (modifiers, n_modifiers) = if modifiers == [INVALID_MODIFIER] {
|
let (modifiers_ptr, n_modifiers) = if modifiers == [INVALID_MODIFIER] {
|
||||||
(ptr::null(), 0)
|
(ptr::null(), 0)
|
||||||
} else {
|
} else {
|
||||||
usage &= !GBM_BO_USE_LINEAR;
|
usage &= !GBM_BO_USE_LINEAR;
|
||||||
|
|
@ -246,7 +246,7 @@ impl GbmDevice {
|
||||||
width as _,
|
width as _,
|
||||||
height as _,
|
height as _,
|
||||||
format.drm,
|
format.drm,
|
||||||
modifiers,
|
modifiers_ptr,
|
||||||
n_modifiers,
|
n_modifiers,
|
||||||
usage,
|
usage,
|
||||||
);
|
);
|
||||||
|
|
@ -255,8 +255,8 @@ impl GbmDevice {
|
||||||
}
|
}
|
||||||
let bo = BoHolder { bo };
|
let bo = BoHolder { bo };
|
||||||
let mut dma = export_bo(dma_buf_ids, bo.bo)?;
|
let mut dma = export_bo(dma_buf_ids, bo.bo)?;
|
||||||
if modifiers.is_null() {
|
if let [modifier] = *modifiers {
|
||||||
dma.modifier = INVALID_MODIFIER;
|
dma.modifier = modifier;
|
||||||
}
|
}
|
||||||
Ok(GbmBo { bo, dmabuf: dma })
|
Ok(GbmBo { bo, dmabuf: dma })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue