rutabaga_gfx: kumquat: support GPU mappings

- dma-buf mmap does not work on Tesla V-100
- system blob does not work on Tesla V-100
- opaque fd mmap does not work on Tesla V-100
- Opaque fd + VK map does work on Tesla V-100

Since we need to make sure the Nvidia ICD is used
when calling VK map + unmap, we save and restore
VK_ICD_FILENAMES when loading gralloc.

This is not super-robust, but the perhaps the best
can that can be done on Nvidia.

BUG=b:300140266
TEST=see successful memory access with Nvidia

Change-Id: I4f4084921b6267b137e7aeeafbfb8839a120c63e
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5698370
Reviewed-by: Jason Macnak <natsu@google.com>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
This commit is contained in:
Gurchetan Singh 2024-07-10 17:09:11 -07:00 committed by crosvm LUCI
parent ea09e79921
commit 1eade7875e
3 changed files with 89 additions and 17 deletions

View file

@ -15,8 +15,11 @@ use rutabaga_gfx::kumquat_gpu_protocol::*;
use rutabaga_gfx::RutabagaDescriptor; use rutabaga_gfx::RutabagaDescriptor;
use rutabaga_gfx::RutabagaError; use rutabaga_gfx::RutabagaError;
use rutabaga_gfx::RutabagaFromRawDescriptor; use rutabaga_gfx::RutabagaFromRawDescriptor;
use rutabaga_gfx::RutabagaGralloc;
use rutabaga_gfx::RutabagaGrallocBackendFlags;
use rutabaga_gfx::RutabagaHandle; use rutabaga_gfx::RutabagaHandle;
use rutabaga_gfx::RutabagaIntoRawDescriptor; use rutabaga_gfx::RutabagaIntoRawDescriptor;
use rutabaga_gfx::RutabagaMappedRegion;
use rutabaga_gfx::RutabagaMapping; use rutabaga_gfx::RutabagaMapping;
use rutabaga_gfx::RutabagaMemoryMapping; use rutabaga_gfx::RutabagaMemoryMapping;
use rutabaga_gfx::RutabagaRawDescriptor; use rutabaga_gfx::RutabagaRawDescriptor;
@ -25,6 +28,7 @@ use rutabaga_gfx::RutabagaResult;
use rutabaga_gfx::RutabagaSharedMemory; use rutabaga_gfx::RutabagaSharedMemory;
use rutabaga_gfx::RutabagaStream; use rutabaga_gfx::RutabagaStream;
use rutabaga_gfx::RutabagaWriter; use rutabaga_gfx::RutabagaWriter;
use rutabaga_gfx::VulkanInfo;
use rutabaga_gfx::RUTABAGA_FLAG_FENCE; use rutabaga_gfx::RUTABAGA_FLAG_FENCE;
use rutabaga_gfx::RUTABAGA_FLAG_FENCE_HOST_SHAREABLE; use rutabaga_gfx::RUTABAGA_FLAG_FENCE_HOST_SHAREABLE;
use rutabaga_gfx::RUTABAGA_FLAG_INFO_RING_IDX; use rutabaga_gfx::RUTABAGA_FLAG_INFO_RING_IDX;
@ -34,22 +38,33 @@ use rutabaga_gfx::RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD;
use crate::virtgpu::defines::*; use crate::virtgpu::defines::*;
const VK_ICD_FILENAMES: &str = "VK_ICD_FILENAMES";
pub struct VirtGpuResource { pub struct VirtGpuResource {
resource_id: u32, resource_id: u32,
size: usize, size: usize,
handle: RutabagaHandle, handle: RutabagaHandle,
mapping: Option<RutabagaMemoryMapping>,
attached_fences: Vec<RutabagaHandle>, attached_fences: Vec<RutabagaHandle>,
vulkan_info: VulkanInfo,
system_mapping: Option<RutabagaMemoryMapping>,
gpu_mapping: Option<Box<dyn RutabagaMappedRegion>>,
} }
impl VirtGpuResource { impl VirtGpuResource {
pub fn new(resource_id: u32, size: usize, handle: RutabagaHandle) -> VirtGpuResource { pub fn new(
resource_id: u32,
size: usize,
handle: RutabagaHandle,
vulkan_info: VulkanInfo,
) -> VirtGpuResource {
VirtGpuResource { VirtGpuResource {
resource_id, resource_id,
size, size,
handle, handle,
mapping: None,
attached_fences: Vec::new(), attached_fences: Vec::new(),
vulkan_info,
system_mapping: None,
gpu_mapping: None,
} }
} }
} }
@ -61,6 +76,7 @@ pub struct VirtGpuKumquat {
stream: RutabagaStream, stream: RutabagaStream,
capsets: Map<u32, Vec<u8>>, capsets: Map<u32, Vec<u8>>,
resources: Map<u32, VirtGpuResource>, resources: Map<u32, VirtGpuResource>,
gralloc_opt: Option<RutabagaGralloc>,
} }
impl VirtGpuKumquat { impl VirtGpuKumquat {
@ -122,6 +138,7 @@ impl VirtGpuKumquat {
stream, stream,
capsets, capsets,
resources: Default::default(), resources: Default::default(),
gralloc_opt: None,
}) })
} }
@ -210,7 +227,7 @@ impl VirtGpuKumquat {
let resource = match protocols.remove(0) { let resource = match protocols.remove(0) {
KumquatGpuProtocol::RespResourceCreate(resp, handle) => { KumquatGpuProtocol::RespResourceCreate(resp, handle) => {
let size: usize = create_3d.size.try_into()?; let size: usize = create_3d.size.try_into()?;
VirtGpuResource::new(resp.resource_id, size, handle) VirtGpuResource::new(resp.resource_id, size, handle, resp.vulkan_info)
} }
_ => return Err(RutabagaError::Unsupported), _ => return Err(RutabagaError::Unsupported),
}; };
@ -268,7 +285,7 @@ impl VirtGpuKumquat {
let resource = match protocols.remove(0) { let resource = match protocols.remove(0) {
KumquatGpuProtocol::RespResourceCreate(resp, handle) => { KumquatGpuProtocol::RespResourceCreate(resp, handle) => {
let size: usize = create_blob.size.try_into()?; let size: usize = create_blob.size.try_into()?;
VirtGpuResource::new(resp.resource_id, size, handle) VirtGpuResource::new(resp.resource_id, size, handle, resp.vulkan_info)
} }
_ => { _ => {
return Err(RutabagaError::Unsupported); return Err(RutabagaError::Unsupported);
@ -308,12 +325,40 @@ impl VirtGpuKumquat {
.get_mut(&bo_handle) .get_mut(&bo_handle)
.ok_or(RutabagaError::InvalidResourceId)?; .ok_or(RutabagaError::InvalidResourceId)?;
if let Some(ref mapping) = resource.mapping { if let Some(ref system_mapping) = resource.system_mapping {
let rutabaga_mapping = mapping.as_rutabaga_mapping(); let rutabaga_mapping = system_mapping.as_rutabaga_mapping();
Ok(rutabaga_mapping)
} else if let Some(ref gpu_mapping) = resource.gpu_mapping {
let rutabaga_mapping = gpu_mapping.as_rutabaga_mapping();
Ok(rutabaga_mapping) Ok(rutabaga_mapping)
} else { } else {
let clone = resource.handle.try_clone()?; let clone = resource.handle.try_clone()?;
if clone.handle_type == RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD {
if self.gralloc_opt.is_none() {
// The idea is to make sure the gfxstream ICD isn't loaded when gralloc starts
// up. The Nvidia ICD should be loaded.
let vk_driver = std::env::var(VK_ICD_FILENAMES).unwrap();
std::env::remove_var(VK_ICD_FILENAMES);
self.gralloc_opt =
Some(RutabagaGralloc::new(RutabagaGrallocBackendFlags::new())?);
std::env::set_var(VK_ICD_FILENAMES, vk_driver);
}
if let Some(ref mut gralloc) = self.gralloc_opt {
let region = gralloc.import_and_map(
clone,
resource.vulkan_info,
resource.size as u64,
)?;
let rutabaga_mapping = region.as_rutabaga_mapping();
resource.gpu_mapping = Some(region);
Ok(rutabaga_mapping)
} else {
return Err(RutabagaError::SpecViolation("no gralloc"));
}
} else {
let mapping = RutabagaMemoryMapping::from_safe_descriptor( let mapping = RutabagaMemoryMapping::from_safe_descriptor(
clone.os_handle, clone.os_handle,
resource.size, resource.size,
@ -321,10 +366,11 @@ impl VirtGpuKumquat {
)?; )?;
let rutabaga_mapping = mapping.as_rutabaga_mapping(); let rutabaga_mapping = mapping.as_rutabaga_mapping();
resource.mapping = Some(mapping); resource.system_mapping = Some(mapping);
Ok(rutabaga_mapping) Ok(rutabaga_mapping)
} }
} }
}
pub fn unmap(&mut self, bo_handle: u32) -> RutabagaResult<()> { pub fn unmap(&mut self, bo_handle: u32) -> RutabagaResult<()> {
let resource = self let resource = self
@ -332,7 +378,8 @@ impl VirtGpuKumquat {
.get_mut(&bo_handle) .get_mut(&bo_handle)
.ok_or(RutabagaError::InvalidResourceId)?; .ok_or(RutabagaError::InvalidResourceId)?;
resource.mapping = None; resource.system_mapping = None;
resource.gpu_mapping = None;
Ok(()) Ok(())
} }
@ -582,7 +629,12 @@ impl VirtGpuKumquat {
self.stream self.stream
.write(KumquatGpuProtocolWrite::Cmd(attach_resource))?; .write(KumquatGpuProtocolWrite::Cmd(attach_resource))?;
let resource = VirtGpuResource::new(*resource_handle, VIRTGPU_KUMQUAT_PAGE_SIZE, handle); let resource = VirtGpuResource::new(
*resource_handle,
VIRTGPU_KUMQUAT_PAGE_SIZE,
handle,
Default::default(),
);
*bo_handle = self.allocate_id(); *bo_handle = self.allocate_id();
// Should ask the server about the size long-term. // Should ask the server about the size long-term.

View file

@ -99,6 +99,21 @@ unsafe impl MappedRegion for VulkanoMapping {
fn size(&self) -> usize { fn size(&self) -> usize {
self.size self.size
} }
/// Returns rutabaga mapping representation of the region
fn as_rutabaga_mapping(&self) -> RutabagaMapping {
let ptr: u64 = unsafe {
// Will not panic since the requested range of the device memory was verified on
// creation
let x = self.mapped_memory.write(0..self.size as u64).unwrap();
x.as_mut_ptr() as u64
};
RutabagaMapping {
ptr,
size: self.size as u64,
}
}
} }
trait DeviceExt { trait DeviceExt {

View file

@ -17,6 +17,8 @@ pub use sys::platform::descriptor::RawDescriptor;
pub use sys::platform::shm::round_up_to_page_size; pub use sys::platform::shm::round_up_to_page_size;
pub use sys::platform::wait_context::WaitContext; pub use sys::platform::wait_context::WaitContext;
use crate::rutabaga_utils::RutabagaMapping;
pub struct WaitEvent { pub struct WaitEvent {
pub connection_id: u64, pub connection_id: u64,
pub hung_up: bool, pub hung_up: bool,
@ -40,4 +42,7 @@ pub unsafe trait MappedRegion: Send + Sync {
/// Returns the size of the memory region in bytes. /// Returns the size of the memory region in bytes.
fn size(&self) -> usize; fn size(&self) -> usize;
/// Returns rutabaga mapping representation of the region
fn as_rutabaga_mapping(&self) -> RutabagaMapping;
} }