PbrRoutine not working on Meta Quest
zmerp opened this issue · 0 comments
zmerp commented
I'm trying to run rend3 on the Meta Quest with OpenXR. But I'm encountering issues rendering any geometry, it always appears black.
Here is the relevant part of my code.
For initializing wgpu:
// This constructor is mainly used for interop with OpenXR XR_KHR_vulkan_enable2
pub fn new_vulkan_external(callbacks: VulkanInitCallbacks) -> Result<Self> {
let entry = unsafe { ash::Entry::load()? };
#[cfg(target_os = "android")]
let android_sdk_version = android_system_properties::AndroidSystemProperties::new()
.get("ro.build.version.sdk")
.to_any()?
.parse::<u32>()?;
#[cfg(not(target_os = "android"))]
let android_sdk_version = 0;
let api_version = entry
.try_enumerate_instance_version()?
.unwrap_or(vk::API_VERSION_1_0);
let application_info = vk::ApplicationInfo::builder().api_version(api_version);
let mut flags = InstanceFlags::empty();
if cfg!(debug_assertions) {
flags |= InstanceFlags::VALIDATION;
flags |= InstanceFlags::DEBUG;
}
let instance_extensions = <hal::api::Vulkan as hal::Api>::Instance::desired_extensions(
&entry,
api_version,
flags,
)?;
let instance_extensions_ptrs = instance_extensions
.iter()
.map(|x| x.as_ptr())
.collect::<Vec<_>>();
// todo: contribute better way to get layers from wgpu
let layers_ptrs = entry
.enumerate_instance_layer_properties()
.unwrap()
.iter()
.filter_map(|props| {
let name = unsafe { CStr::from_ptr(props.layer_name.as_ptr()) };
if name.to_str().unwrap() == "VK_LAYER_KHRONOS_validation" {
Some(props.layer_name.as_ptr())
} else {
None
}
})
.collect::<Vec<_>>();
// todo: debug utils
let instance_create_info = vk::InstanceCreateInfo::builder()
.application_info(&application_info)
.enabled_extension_names(&instance_extensions_ptrs)
.enabled_layer_names(&layers_ptrs)
.build();
let instance_ptr = (callbacks.create_instance)(
unsafe { mem::transmute(entry.static_fn().get_instance_proc_addr) },
&instance_create_info as *const _ as *const c_void,
)?;
let instance_vk = unsafe {
ash::Instance::load(entry.static_fn(), vk::Instance::from_raw(instance_ptr as _))
};
let hal_instance = unsafe {
<hal::api::Vulkan as hal::Api>::Instance::from_raw(
entry.clone(),
instance_vk.clone(),
api_version,
android_sdk_version,
None,
instance_extensions,
flags,
false,
Some(Box::new(())),
)?
};
let physical_device_ptr = (callbacks.get_physical_device)(instance_ptr)?;
let physical_device_vk = vk::PhysicalDevice::from_raw(physical_device_ptr as _);
let exposed_adapter = hal_instance.expose_adapter(physical_device_vk).to_any()?;
assert!(exposed_adapter.features.contains(*REQUIRED_FEATURES));
// code below is mostly copied from
// https://github.com/gfx-rs/wgpu/blob/f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e/wgpu-hal/src/vulkan/adapter.rs#L1597-L1598
let mut device_extensions = exposed_adapter
.adapter
.required_device_extensions(*REQUIRED_FEATURES);
if cfg!(target_os = "android") {
// For importing decoder images into Vulkan
device_extensions.extend([
vk::ExtQueueFamilyForeignFn::name(),
vk::KhrExternalMemoryFn::name(),
vk::AndroidExternalMemoryAndroidHardwareBufferFn::name(),
]);
};
let device_extensions_ptrs = device_extensions
.iter()
.map(|ext| ext.as_ptr())
.collect::<Vec<_>>();
let mut physical_device_features = exposed_adapter
.adapter
.physical_device_features(&device_extensions, *REQUIRED_FEATURES);
let queue_family_index = 0; // This is what wgpu uses
let queue_create_infos = [vk::DeviceQueueCreateInfo::builder()
.queue_family_index(queue_family_index)
.queue_priorities(&[1.0])
.build()];
let queue_index = 0;
let device_create_info = vk::DeviceCreateInfo::builder()
.queue_create_infos(&queue_create_infos)
.enabled_extension_names(&device_extensions_ptrs);
let device_create_info = physical_device_features
.add_to_device_create_builder(device_create_info)
.build();
let device_ptr = (callbacks.create_device)(
unsafe { mem::transmute(entry.static_fn().get_instance_proc_addr) },
physical_device_ptr,
&device_create_info as *const _ as *const c_void,
)?;
let device_vk = unsafe {
ash::Device::load(instance_vk.fp_v1_0(), vk::Device::from_raw(device_ptr as _))
};
let open_device = unsafe {
exposed_adapter.adapter.device_from_raw(
device_vk,
false,
&device_extensions,
*REQUIRED_FEATURES,
queue_family_index,
queue_index,
)?
};
let instance = unsafe { Instance::from_hal::<hal::api::Vulkan>(hal_instance) };
let adapter = unsafe { instance.create_adapter_from_hal(exposed_adapter) };
let (device, queue) = unsafe {
adapter.create_device_from_hal(
open_device,
&DeviceDescriptor {
label: None,
required_features: *REQUIRED_FEATURES,
required_limits: adapter.limits(),
},
None,
)?
};
Ok(Self {
instance: Arc::new(instance),
adapter: Arc::new(adapter),
device: Arc::new(device),
queue: Arc::new(queue),
backend_handles: VulkanBackend {},
})
}
rend3 initialization:
let iad = InstanceAdapterDevice {
instance: Arc::clone(&graphics_context.instance),
adapter: Arc::clone(&graphics_context.adapter),
device: Arc::clone(&graphics_context.device),
queue: Arc::clone(&graphics_context.queue),
profile: RendererProfile::CpuDriven,
info: ExtendedAdapterInfo {
name: graphics_context.adapter.get_info().name,
vendor: match graphics_context.adapter.get_info().vendor {
0x1002 => Vendor::Amd,
0x10DE => Vendor::Nv,
0x13B5 => Vendor::Arm,
0x1414 => Vendor::Microsoft,
0x14E4 => Vendor::Broadcom,
0x5143 => Vendor::Qualcomm,
0x8086 => Vendor::Intel,
v => Vendor::Unknown(v as usize),
},
device: graphics_context.adapter.get_info().device as usize,
device_type: graphics_context.adapter.get_info().device_type,
backend: graphics_context.adapter.get_info().backend,
},
};
let renderer = Renderer::new(iad, Handedness::Left, None)?;
let mut shader_preprocessor = ShaderPreProcessor::new();
rend3_routine::builtin_shaders(&mut shader_preprocessor);
let base_rendergraph = BaseRenderGraph::new(&renderer, &shader_preprocessor);
let mut data_core = renderer.data_core.lock();
let pbr_routine = PbrRoutine::new(
&renderer,
&mut data_core,
&shader_preprocessor,
&base_rendergraph.interfaces,
&base_rendergraph.gpu_culler.culling_buffer_map_handle,
);
drop(data_core);
// let skybox_routine = SkyboxRoutine::new(
// &renderer,
// &shader_preprocessor,
// &base_rendergraph.interfaces,
// );
let tonemapping_routine = TonemappingRoutine::new(
&renderer,
&shader_preprocessor,
&base_rendergraph.interfaces,
TextureFormat::Rgba8UnormSrgb,
);
let floor_vertices = [
Vec3::new(1.0, 0.0, 1.0),
Vec3::new(-1.0, 0.0, 1.0),
Vec3::new(-1.0, 0.0, -1.0),
Vec3::new(1.0, 0.0, -1.0),
];
let floor_indices = [0, 1, 2, 2, 3, 0];
let floor_plane = MeshBuilder::new(floor_vertices.to_vec(), Handedness::Left)
.with_indices(floor_indices.to_vec())
.build()?;
let floor_mesh = renderer.add_mesh(floor_plane).unwrap();
let floor_material = renderer.add_material(PbrMaterial {
albedo: AlbedoComponent::Value(Vec4::new(0.0, 1.0, 0.0, 1.0)),
unlit: true,
..PbrMaterial::default()
});
let floor_object = Object {
mesh_kind: ObjectMeshKind::Static(floor_mesh),
material: floor_material,
transform: Mat4::IDENTITY,
};
let _floor_handle = renderer.add_object(floor_object);
Ok(Self {
renderer,
base_rendergraph,
pbr_routine,
// skybox_routine,
tonemapping_routine,
swapchains,
swapchain_resolution,
_floor_handle,
})
render:
self.renderer.set_camera_data(Camera {
projection: CameraProjection::Raw(projection_from_fov(fov)),
view: Mat4::from_rotation_translation(pose.orientation, pose.position).inverse(),
});
// Apply scene changes
self.renderer.swap_instruction_buffers();
let mut eval_output = self.renderer.evaluate_instructions();
// self.skybox_routine.evaluate(&self.renderer);
// Build render graph
let mut graph = RenderGraph::new();
let frame_handle = graph.add_imported_render_target(
&self.swapchains[view_index][swapchain_index],
0..1,
0..1,
ViewportRect::from_size(self.swapchain_resolution),
);
self.base_rendergraph.add_to_graph(
&mut graph,
BaseRenderGraphInputs {
eval_output: &eval_output,
routines: BaseRenderGraphRoutines {
pbr: &self.pbr_routine,
skybox: None, // Some(&self.skybox_routine),
tonemapping: &self.tonemapping_routine,
},
target: OutputRenderTarget {
handle: frame_handle,
resolution: self.swapchain_resolution,
samples: SampleCount::One,
},
},
BaseRenderGraphSettings {
ambient_color: Vec4::ZERO,
clear_color: Vec4::new(1.0, 0.0, 0.0, 1.0),
},
);
graph.execute(&self.renderer, &mut eval_output);
This is the resulting screenshot:
The floor quad is supposed to be green.