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::RutabagaError;
use rutabaga_gfx::RutabagaFromRawDescriptor;
use rutabaga_gfx::RutabagaGralloc;
use rutabaga_gfx::RutabagaGrallocBackendFlags;
use rutabaga_gfx::RutabagaHandle;
use rutabaga_gfx::RutabagaIntoRawDescriptor;
use rutabaga_gfx::RutabagaMappedRegion;
use rutabaga_gfx::RutabagaMapping;
use rutabaga_gfx::RutabagaMemoryMapping;
use rutabaga_gfx::RutabagaRawDescriptor;
@ -25,6 +28,7 @@ use rutabaga_gfx::RutabagaResult;
use rutabaga_gfx::RutabagaSharedMemory;
use rutabaga_gfx::RutabagaStream;
use rutabaga_gfx::RutabagaWriter;
use rutabaga_gfx::VulkanInfo;
use rutabaga_gfx::RUTABAGA_FLAG_FENCE;
use rutabaga_gfx::RUTABAGA_FLAG_FENCE_HOST_SHAREABLE;
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::*;
const VK_ICD_FILENAMES: &str = "VK_ICD_FILENAMES";
pub struct VirtGpuResource {
resource_id: u32,
size: usize,
handle: RutabagaHandle,
mapping: Option<RutabagaMemoryMapping>,
attached_fences: Vec<RutabagaHandle>,
vulkan_info: VulkanInfo,
system_mapping: Option<RutabagaMemoryMapping>,
gpu_mapping: Option<Box<dyn RutabagaMappedRegion>>,
}
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 {
resource_id,
size,
handle,
mapping: None,
attached_fences: Vec::new(),
vulkan_info,
system_mapping: None,
gpu_mapping: None,
}
}
}
@ -61,6 +76,7 @@ pub struct VirtGpuKumquat {
stream: RutabagaStream,
capsets: Map<u32, Vec<u8>>,
resources: Map<u32, VirtGpuResource>,
gralloc_opt: Option<RutabagaGralloc>,
}
impl VirtGpuKumquat {
@ -122,6 +138,7 @@ impl VirtGpuKumquat {
stream,
capsets,
resources: Default::default(),
gralloc_opt: None,
})
}
@ -210,7 +227,7 @@ impl VirtGpuKumquat {
let resource = match protocols.remove(0) {
KumquatGpuProtocol::RespResourceCreate(resp, handle) => {
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),
};
@ -268,7 +285,7 @@ impl VirtGpuKumquat {
let resource = match protocols.remove(0) {
KumquatGpuProtocol::RespResourceCreate(resp, handle) => {
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);
@ -308,21 +325,50 @@ impl VirtGpuKumquat {
.get_mut(&bo_handle)
.ok_or(RutabagaError::InvalidResourceId)?;
if let Some(ref mapping) = resource.mapping {
let rutabaga_mapping = mapping.as_rutabaga_mapping();
if let Some(ref system_mapping) = resource.system_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)
} else {
let clone = resource.handle.try_clone()?;
let mapping = RutabagaMemoryMapping::from_safe_descriptor(
clone.os_handle,
resource.size,
RUTABAGA_MAP_CACHE_CACHED | RUTABAGA_MAP_ACCESS_RW,
)?;
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);
}
let rutabaga_mapping = mapping.as_rutabaga_mapping();
resource.mapping = Some(mapping);
Ok(rutabaga_mapping)
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(
clone.os_handle,
resource.size,
RUTABAGA_MAP_CACHE_CACHED | RUTABAGA_MAP_ACCESS_RW,
)?;
let rutabaga_mapping = mapping.as_rutabaga_mapping();
resource.system_mapping = Some(mapping);
Ok(rutabaga_mapping)
}
}
}
@ -332,7 +378,8 @@ impl VirtGpuKumquat {
.get_mut(&bo_handle)
.ok_or(RutabagaError::InvalidResourceId)?;
resource.mapping = None;
resource.system_mapping = None;
resource.gpu_mapping = None;
Ok(())
}
@ -582,7 +629,12 @@ impl VirtGpuKumquat {
self.stream
.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();
// Should ask the server about the size long-term.

View file

@ -99,6 +99,21 @@ unsafe impl MappedRegion for VulkanoMapping {
fn size(&self) -> usize {
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 {

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::wait_context::WaitContext;
use crate::rutabaga_utils::RutabagaMapping;
pub struct WaitEvent {
pub connection_id: u64,
pub hung_up: bool,
@ -40,4 +42,7 @@ pub unsafe trait MappedRegion: Send + Sync {
/// Returns the size of the memory region in bytes.
fn size(&self) -> usize;
/// Returns rutabaga mapping representation of the region
fn as_rutabaga_mapping(&self) -> RutabagaMapping;
}