From 6bf0376ac6e3753a4d1c056bf1de6495c26c09c6 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 27 Oct 2026 19:35:49 +0300 Subject: [PATCH 1/4] move unstable code out of lib.rs --- src/iter.rs | 22 ++++++++++++++++++++++ src/lib.rs | 24 ++---------------------- 2 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 src/iter.rs diff --git a/src/iter.rs b/src/iter.rs new file mode 100644 index 0000000..88be085 --- /dev/null +++ b/src/iter.rs @@ -0,0 +1,22 @@ +use std::convert::identity; + +pub(crate) fn loop_list(iter: impl IntoIterator) -> impl Iterator { + loop_list_ex(iter, identity, identity) +} + +pub(crate) fn loop_list_ex( + iter: impl IntoIterator, + mut fa: impl FnMut(T) -> U, + mut fb: impl FnMut(T) -> U, +) -> impl Iterator { + gen move { + let mut iter = iter.into_iter(); + let Some(first) = iter.next() else { return }; + yield fa(first.clone()); + for item in iter { + yield fb(item.clone()); + yield fa(item); + } + yield fb(first); + } +} diff --git a/src/lib.rs b/src/lib.rs index 0873c0b..99e79e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,13 @@ #![feature(gen_blocks)] -use std::{convert::identity, error::Error, f32::consts::PI}; +use std::{error::Error, f32::consts::PI}; use glam::{Mat4, UVec2, Vec2, Vec3, vec3}; use rand_distr::Distribution as _; use crate::{ camera::OrbitalCamera, + iter::loop_list, ray::Ray, render::{ DEPTH_FORMAT, OUTPUT_FORMAT, @@ -118,27 +119,6 @@ pub fn new_tripod(device: &wgpu::Device) -> Mesh { ) } -fn loop_list(iter: impl IntoIterator) -> impl Iterator { - loop_list_ex(iter, identity, identity) -} - -fn loop_list_ex( - iter: impl IntoIterator, - mut fa: impl FnMut(T) -> U, - mut fb: impl FnMut(T) -> U, -) -> impl Iterator { - gen move { - let mut iter = iter.into_iter(); - let Some(first) = iter.next() else { return }; - yield fa(first.clone()); - for item in iter { - yield fb(item.clone()); - yield fa(item); - } - yield fb(first); - } -} - impl OrbitalCamera { fn make_ray(&self, rng: &mut impl rand::Rng) -> Ray { let off: f32 = rand_distr::StandardUniform.sample(rng); From 2e663f2d23d10416f01a091d9c623e8bd06035c7 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 27 Oct 2026 19:36:53 +0300 Subject: [PATCH 2/4] update `bytemuck` --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 879b203..6194248 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,9 +165,9 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" dependencies = [ "bytemuck_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 5c3ab54..4fbd998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ debug = false opt-level = 3 [dependencies] -bytemuck = "1.24.0" +bytemuck = "1.25.2" glam = { version = "0.30.9", features = ["bytemuck", "approx"] } pollster = "0.4.0" rand = "0.9.2" From e40a7290489c01a8c191513974d92a729dea50af Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 27 Oct 2026 19:38:05 +0300 Subject: [PATCH 3/4] replace custom FFI with Diplomat adapted from: qt-wgpu-skel: * 751408ea92268a16a6931862cb00e8dbccb4e47e replace custom FFI with Diplomat * 46ce52c2bf2f8ab76a68c284a2f70556a29d7c3b reduce the unsafe part to the GPU initialization * 784e99b31c4ae3ab0f97ec26045511d00683d66b move the GPU initialization out of the bridge --- CMakeLists.txt | 2 + Cargo.lock | 87 +++++++++++++++++------ Cargo.toml | 8 ++- diplomat.cmake | 8 +++ src/lib.rs | 164 ++++++++++++++++++++++++++++---------------- ui/CMakeLists.txt | 1 - ui/Cargo.toml | 15 ---- ui/impl.cmake | 29 +++++++- ui/src/api.cxx | 57 --------------- ui/src/api.hxx | 76 -------------------- ui/src/lib.rs | 49 ------------- ui/src/viewport.cxx | 2 +- ui/src/viewport.hxx | 4 +- 13 files changed, 216 insertions(+), 286 deletions(-) create mode 100644 diplomat.cmake delete mode 100644 ui/Cargo.toml delete mode 100644 ui/src/api.cxx delete mode 100644 ui/src/api.hxx delete mode 100644 ui/src/lib.rs diff --git a/CMakeLists.txt b/CMakeLists.txt index 5470e0c..b53f761 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ find_package(Qt6 REQUIRED COMPONENTS Gui Widgets) find_program(CARGO cargo REQUIRED) set(CARGO_TARGET_DIR "${CMAKE_SOURCE_DIR}/target" CACHE PATH "Path to the Cargo target directory") +include(diplomat.cmake) + qt_standard_project_setup() add_subdirectory(ui) diff --git a/Cargo.lock b/Cargo.lock index 6194248..1cd7292 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -354,6 +354,38 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +[[package]] +name = "diplomat" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a80510e6103d35c5cd031c0e3f21165b32742c301ee3dafdbb5904c6dca46a" +dependencies = [ + "diplomat_core", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "diplomat-runtime" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d981121ba76150987fda68185b37853c0b928a55dfdc28897348cd068440be" + +[[package]] +name = "diplomat_core" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5c594efd1d097105255fc325c430a517c97b7b7c69f8727f653593e1ce726" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "smallvec", + "strck", + "syn 3.0.9", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -442,7 +474,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -892,7 +924,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1182,6 +1214,8 @@ version = "0.1.0" dependencies = [ "approx", "bytemuck", + "diplomat", + "diplomat-runtime", "glam", "pollster", "rand", @@ -1191,17 +1225,6 @@ dependencies = [ "winit", ] -[[package]] -name = "photon-light-impl" -version = "0.1.0" -dependencies = [ - "glam", - "photon-light", - "pollster", - "raw-window-handle", - "wgpu", -] - [[package]] name = "pin-project" version = "1.1.10" @@ -1219,7 +1242,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1530,7 +1553,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1609,6 +1632,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strck" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42316e70da376f3d113a68d138a60d8a9883c604fe97942721ec2068dab13a9f" +dependencies = [ + "unicode-ident", +] + [[package]] name = "strict-num" version = "0.1.1" @@ -1626,6 +1658,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -1661,7 +1704,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1672,7 +1715,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1841,7 +1884,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -2174,7 +2217,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2185,7 +2228,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2517,5 +2560,5 @@ checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] diff --git a/Cargo.toml b/Cargo.toml index 4fbd998..95fe38c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ -[workspace] -members = ["ui"] - [package] name = "photon-light" version = "0.1.0" edition = "2024" +[lib] +crate-type = ["lib", "staticlib"] + [profile.dev] panic = 'abort' @@ -26,6 +26,8 @@ rand_distr = "0.5.1" rand_pcg = "0.9.0" wgpu = "27.0.1" winit = "0.30.12" +diplomat = "0.17.0" +diplomat-runtime = "0.16.1" [dev-dependencies] approx = "0.5.1" diff --git a/diplomat.cmake b/diplomat.cmake new file mode 100644 index 0000000..70a752f --- /dev/null +++ b/diplomat.cmake @@ -0,0 +1,8 @@ +set(crates "${CMAKE_BINARY_DIR}/crates") +set(diplomat "${crates}/bin/diplomat-tool") + +if(NOT IS_EXECUTABLE "${diplomat}") + message(CONFIGURE_LOG "Downloading Diplomat...") + file(MAKE_DIRECTORY "${crates}") + execute_process(COMMAND ${CARGO} install --root "${crates}" diplomat-tool@0.17.0) +endif() diff --git a/src/lib.rs b/src/lib.rs index 99e79e9..942ae73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use std::{error::Error, f32::consts::PI}; use glam::{Mat4, UVec2, Vec2, Vec3, vec3}; use rand_distr::Distribution as _; +use wgpu::rwh::{RawDisplayHandle, RawWindowHandle}; use crate::{ camera::OrbitalCamera, @@ -16,73 +17,103 @@ use crate::{ trace::{Hit, Lambertian, Reflector, Scene, Source, Sphere}, }; +pub use crate::ffi::{RedrawArgs, SphericalPosition, UseNormal}; + mod camera; +mod iter; mod ray; mod render; mod shape; mod trace; -#[derive(Debug, Clone, Copy, PartialEq)] -#[repr(C)] -pub struct SphericalPosition { - pub yaw: f32, - pub pitch: f32, - pub distance: f32, -} +#[diplomat::bridge] +mod ffi { + use std::{f32::consts::PI, num::NonZero, ptr::NonNull}; -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum UseNormal { - Light, - Camera, -} + use glam::uvec2; + use wgpu::rwh::{XcbDisplayHandle, XcbWindowHandle}; -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct RedrawArgs { - pub camera_position: SphericalPosition, - pub light_position: SphericalPosition, - pub light_radius: f32, - pub light_spread: f32, - pub accum_sigma: f32, - pub accum_scale: f32, - pub reflections: u8, - pub use_normal: UseNormal, - pub show_axes: bool, - pub show_shapes: bool, - pub show_hit_emission: bool, - pub show_miss_emission: bool, - pub show_direct_hit: bool, - pub show_indirect_hit: bool, - pub show_light: bool, -} + #[derive(Debug, Clone, Copy, PartialEq)] + pub struct SphericalPosition { + pub yaw: f32, + pub pitch: f32, + pub distance: f32, + } -impl Default for RedrawArgs { - fn default() -> Self { - Self { - camera_position: SphericalPosition { - yaw: PI / 4., - pitch: 0.5f32.sqrt().atan(), - distance: 3.0, - }, - light_position: SphericalPosition { - yaw: 0.0, - pitch: PI / 3., - distance: 1.0, - }, - light_radius: 0.125, - light_spread: 0.125, - accum_sigma: 0.025, - accum_scale: 0.01, - reflections: 2, - use_normal: UseNormal::Light, - show_axes: true, - show_shapes: true, - show_hit_emission: false, - show_miss_emission: false, - show_direct_hit: false, - show_indirect_hit: false, - show_light: true, + #[derive(Debug)] + pub enum UseNormal { + Light, + Camera, + } + + #[derive(Debug, Clone, Copy)] + pub struct RedrawArgs { + pub camera_position: SphericalPosition, + pub light_position: SphericalPosition, + pub light_radius: f32, + pub light_spread: f32, + pub accum_sigma: f32, + pub accum_scale: f32, + pub reflections: u8, + pub use_normal: UseNormal, + pub show_axes: bool, + pub show_shapes: bool, + pub show_hit_emission: bool, + pub show_miss_emission: bool, + pub show_direct_hit: bool, + pub show_indirect_hit: bool, + pub show_light: bool, + } + + impl Default for RedrawArgs { + fn default() -> Self { + Self { + camera_position: SphericalPosition { + yaw: PI / 4., + pitch: 0.5f32.sqrt().atan(), + distance: 3.0, + }, + light_position: SphericalPosition { + yaw: 0.0, + pitch: PI / 3., + distance: 1.0, + }, + light_radius: 0.125, + light_spread: 0.125, + accum_sigma: 0.025, + accum_scale: 0.01, + reflections: 2, + use_normal: UseNormal::Light, + show_axes: true, + show_shapes: true, + show_hit_emission: false, + show_miss_emission: false, + show_direct_hit: false, + show_indirect_hit: false, + show_light: true, + } + } + } + + #[diplomat::opaque_mut] + pub struct Core(crate::Core); + + impl Core { + pub fn from_xcb(connection: usize, window: u32, width: u32, height: u32) -> Box { + let display = + XcbDisplayHandle::new(Some(NonNull::new(connection as *mut _).unwrap()), 0); + let window = XcbWindowHandle::new(NonZero::new(window).unwrap()); + let gpu = unsafe { crate::Gpu::new_raw(display, window) }; + let size = uvec2(width, height); + Box::new(Self(crate::Core::new(gpu, size))) + } + + pub fn configure(&mut self, width: u32, height: u32) { + self.0.configure(uvec2(width, height)); + } + + pub fn redraw(&mut self, args: &RedrawArgs) { + self.0.redraw(args); } } } @@ -93,6 +124,23 @@ pub struct Gpu { surface: wgpu::Surface<'static>, } +impl Gpu { + unsafe fn new_raw( + display: impl Into, + window: impl Into, + ) -> Self { + let target = wgpu::SurfaceTargetUnsafe::RawHandle { + raw_display_handle: display.into(), + raw_window_handle: window.into(), + }; + let gpu = pollster::block_on(init_gpu_inner(|instance| unsafe { + instance.create_surface_unsafe(target) + })) + .unwrap(); + gpu + } +} + pub struct Core { device: wgpu::Device, queue: wgpu::Queue, diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 191380f..abc617e 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -1,7 +1,6 @@ include(impl.cmake) qt_add_executable(photon-light - src/api.cxx src/main.cxx src/main_window.cxx src/main_window.ui diff --git a/ui/Cargo.toml b/ui/Cargo.toml deleted file mode 100644 index e12ba36..0000000 --- a/ui/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "photon-light-impl" -version = "0.1.0" -edition = "2024" - -[lib] -crate-type = ["staticlib"] - -[dependencies] -photon-light = {path = "../"} - -glam = { version = "0.30" } -pollster = "0.4.0" -raw-window-handle = "0.6.2" -wgpu = "27.0.1" diff --git a/ui/impl.cmake b/ui/impl.cmake index de4d266..636739e 100644 --- a/ui/impl.cmake +++ b/ui/impl.cmake @@ -1,19 +1,25 @@ # build the Rust side as a static library -set(impl_basename "${CARGO_TARGET_DIR}/release/libphoton_light_impl") +set(impl_basename "${CARGO_TARGET_DIR}/release/libphoton_light") set(cargo_cmake_args) +set(diplomat_cmake_args) if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.27") list(APPEND cargo_cmake_args DEPENDS_EXPLICIT_ONLY) + list(APPEND diplomat_cmake_args DEPENDS_EXPLICIT_ONLY) endif() if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.28") list(APPEND cargo_cmake_args JOB_SERVER_AWARE TRUE) endif() +if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.31") + list(APPEND diplomat_cmake_args CODEGEN) +endif() + add_custom_command( OUTPUT "${impl_basename}.a" - COMMAND env "CARGO_TARGET_DIR=${CARGO_TARGET_DIR}" ${CARGO} build --release --package photon-light-impl + COMMAND env "CARGO_TARGET_DIR=${CARGO_TARGET_DIR}" ${CARGO} build --release --package photon-light WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" DEPFILE "${impl_basename}.d" USES_TERMINAL @@ -31,3 +37,22 @@ add_library(photon_light_impl STATIC IMPORTED) set_target_properties(photon_light_impl PROPERTIES IMPORTED_LOCATION "${impl_basename}.a" ) + +# generate the bindings +set(bindings_dir "${CMAKE_CURRENT_BINARY_DIR}/include") +file(MAKE_DIRECTORY "${bindings_dir}") +set(bindings + "${bindings_dir}/Core.hpp" +) + +add_custom_command( + OUTPUT ${bindings} + COMMAND ${diplomat} cpp "${bindings_dir}" + MAIN_DEPENDENCY "${CMAKE_SOURCE_DIR}/src/lib.rs" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + VERBATIM + ${diplomat_cmake_args} +) + +target_sources(photon_light_impl INTERFACE ${bindings}) +target_include_directories(photon_light_impl INTERFACE "${bindings_dir}") diff --git a/ui/src/api.cxx b/ui/src/api.cxx deleted file mode 100644 index aaa2b64..0000000 --- a/ui/src/api.cxx +++ /dev/null @@ -1,57 +0,0 @@ -#include "api.hxx" - -#include -#include - -namespace ffi { -extern "C" Core* rt4_viewport_create(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height); -extern "C" void rt4_viewport_destroy(Core* viewport); -extern "C" void rt4_viewport_configure(Core* viewport, std::uint32_t width, std::uint32_t height); -extern "C" void rt4_viewport_redraw(Core* viewport, const RedrawArgs* args); -} // namespace ffi - -BoxCore::BoxCore(BoxCore&& b) - : ptr(std::exchange(b.ptr, {})) { -} - -BoxCore::~BoxCore() { - reset(); -} - -BoxCore& BoxCore::operator=(BoxCore&& b) { - if (&b == this) - return *this; - std::swap(ptr, b.ptr); - b.reset(); - return *this; -} - -BoxCore BoxCore::from_xcb(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height) { - if (!connection) - throw std::logic_error("attempt to use a null connection"); - if (!window) - throw std::logic_error("attempt to use a null window"); - BoxCore out; - out.ptr.ptr = ffi::rt4_viewport_create(connection, window, width, height); - return out; -} - -void BoxCore::reset() { - auto viewport = std::exchange(ptr, {}); - if (viewport) - ffi::rt4_viewport_destroy(viewport.use()); -} - -ffi::Core* MutCore::use() const { - if (!ptr) - throw std::logic_error("attempt to use a null Core"); - return ptr; -} - -void MutCore::configure(std::uint32_t width, std::uint32_t height) const { - rt4_viewport_configure(use(), width, height); -} - -void MutCore::redraw(const RedrawArgs& args) const { - rt4_viewport_redraw(use(), &args); -} diff --git a/ui/src/api.hxx b/ui/src/api.hxx deleted file mode 100644 index d46272e..0000000 --- a/ui/src/api.hxx +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include - -struct xcb_connection_t; - -namespace ffi { -struct Core; - -struct SphericalPosition { - float yaw = 0.; - float pitch = 0.; - float distance = 1.; -}; - -enum class UseNormal: std::uint8_t { - Light, - Camera, -}; - -struct RedrawArgs { - SphericalPosition camera_position; - SphericalPosition light_position; - float light_radius = 1.; - float light_spread = 0.; - float accum_sigma = 1.; - float accum_scale = 1.; - std::uint8_t reflections = 0; - UseNormal use_normal = UseNormal::Light; - bool show_axes = true; - bool show_shapes = true; - bool show_hit_emission = true; - bool show_miss_emission = true; - bool show_direct_hit = true; - bool show_indirect_hit = true; - bool show_light = true; -}; -} // namespace ffi - -using ffi::UseNormal; -using ffi::RedrawArgs; -using ffi::SphericalPosition; - -class MutCore { - friend class BoxCore; - -public: - explicit operator bool() const { return ptr; } - - void configure(std::uint32_t width, std::uint32_t height) const; - void redraw(const RedrawArgs& args) const; - -private: - ffi::Core* ptr = nullptr; - ffi::Core* use() const; -}; - -class BoxCore { -public: - BoxCore() = default; - BoxCore(const BoxCore&) = delete; - BoxCore(BoxCore&&); - BoxCore& operator=(const BoxCore&) = delete; - BoxCore& operator=(BoxCore&&); - ~BoxCore(); - - explicit operator bool() const { return !!ptr; } - const MutCore* operator->() const { return &ptr; } - - void reset(); - - static BoxCore from_xcb(xcb_connection_t* connection, std::uint32_t window, std::uint32_t width, std::uint32_t height); - -private: - MutCore ptr; -}; diff --git a/ui/src/lib.rs b/ui/src/lib.rs deleted file mode 100644 index ed5dce1..0000000 --- a/ui/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::{ffi::c_void, num::NonZero, ptr::NonNull}; - -use glam::{UVec2, uvec2}; -use raw_window_handle::{RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, XcbWindowHandle}; - -use photon_light::{Core, RedrawArgs, init_gpu_inner}; - -unsafe fn create_viewport( - display: impl Into, - window: impl Into, - size: UVec2, -) -> Box { - let target = wgpu::SurfaceTargetUnsafe::RawHandle { - raw_display_handle: display.into(), - raw_window_handle: window.into(), - }; - let gpu = pollster::block_on(init_gpu_inner(|instance| unsafe { - instance.create_surface_unsafe(target) - })) - .unwrap(); - Box::new(Core::new(gpu, size)) -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_create( - connection: NonNull, - window: NonZero, - width: u32, - height: u32, -) -> Box { - let display = XcbDisplayHandle::new(Some(connection), 0); - let window = XcbWindowHandle::new(window); - unsafe { create_viewport(display, window, uvec2(width, height)) } -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_destroy(viewport: Box) { - drop(viewport); -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_configure(viewport: &mut Core, width: u32, height: u32) { - viewport.configure(uvec2(width, height)); -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn rt4_viewport_redraw(viewport: &mut Core, args: &RedrawArgs) { - viewport.redraw(args); -} diff --git a/ui/src/viewport.cxx b/ui/src/viewport.cxx index e681bd9..60d638c 100644 --- a/ui/src/viewport.cxx +++ b/ui/src/viewport.cxx @@ -63,7 +63,7 @@ void Viewport::recreate() try { const QSize device_size = size() * devicePixelRatio(); core.reset(); - core = BoxCore::from_xcb(xcb_connection, x11_window, device_size.width(), device_size.height()); + core = Core::from_xcb((std::uintptr_t)xcb_connection, x11_window, device_size.width(), device_size.height()); } catch (const std::exception& e) { fprintf(stderr, "failed to recreate the viewport: %s", e.what()); } diff --git a/ui/src/viewport.hxx b/ui/src/viewport.hxx index 95839b9..5d1d738 100644 --- a/ui/src/viewport.hxx +++ b/ui/src/viewport.hxx @@ -2,7 +2,7 @@ #include -#include "api.hxx" +#include "Core.hpp" class Viewport : public QWidget { Q_OBJECT @@ -20,7 +20,7 @@ protected: void resizeEvent(QResizeEvent* event) override; private: - BoxCore core; + std::unique_ptr core; RedrawArgs args = {}; void recreate(); From e345fb0b52ca6b78405e86a633e0128c5f586083 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 26 Oct 2026 18:42:02 +0300 Subject: [PATCH 4/4] move ui/impl.cmake to src/ Now that there is no separate UI-specific wrapper, it belongs to the implementation rather than to the UI, probably cherry-picked from: qt-wgpu-skel:9742916bd6932498e87b12d514ac209595ad216c --- CMakeLists.txt | 1 + ui/impl.cmake => src/CMakeLists.txt | 9 +++++++-- ui/CMakeLists.txt | 2 -- 3 files changed, 8 insertions(+), 4 deletions(-) rename ui/impl.cmake => src/CMakeLists.txt (88%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b53f761..0db45da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,4 +13,5 @@ include(diplomat.cmake) qt_standard_project_setup() +add_subdirectory(src) add_subdirectory(ui) diff --git a/ui/impl.cmake b/src/CMakeLists.txt similarity index 88% rename from ui/impl.cmake rename to src/CMakeLists.txt index 636739e..c366673 100644 --- a/ui/impl.cmake +++ b/src/CMakeLists.txt @@ -32,7 +32,7 @@ add_custom_target(build_impl DEPENDS "${impl_basename}.a" ) -add_library(photon_light_impl STATIC IMPORTED) +add_library(photon_light_impl STATIC IMPORTED GLOBAL) set_target_properties(photon_light_impl PROPERTIES IMPORTED_LOCATION "${impl_basename}.a" @@ -48,11 +48,16 @@ set(bindings add_custom_command( OUTPUT ${bindings} COMMAND ${diplomat} cpp "${bindings_dir}" - MAIN_DEPENDENCY "${CMAKE_SOURCE_DIR}/src/lib.rs" + MAIN_DEPENDENCY "lib.rs" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" VERBATIM ${diplomat_cmake_args} ) +# HACK ensure CMake *actually adds* the command above +add_custom_target(codegen_impl + DEPENDS ${bindings} +) + target_sources(photon_light_impl INTERFACE ${bindings}) target_include_directories(photon_light_impl INTERFACE "${bindings_dir}") diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index abc617e..c77b221 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -1,5 +1,3 @@ -include(impl.cmake) - qt_add_executable(photon-light src/main.cxx src/main_window.cxx