Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PbrRoutine not working on Meta Quest #586

Open
zarik5 opened this issue Mar 20, 2024 · 0 comments
Open

PbrRoutine not working on Meta Quest #586

zarik5 opened this issue Mar 20, 2024 · 0 comments

Comments

@zarik5
Copy link
Contributor

zarik5 commented Mar 20, 2024

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:
Screenshot_20240320_114040
The floor quad is supposed to be green.

Reference code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant