Remove the WindowAdapter from the renderer constructor

This allows disentangling the native window creation from the renderer
creation, which is rather ugly and complicated on the C++ side.
This commit is contained in:
Simon Hausmann 2023-05-15 14:47:28 +02:00 committed by Simon Hausmann
parent dd5ef9993f
commit fe4a434ce4
13 changed files with 170 additions and 173 deletions

View file

@ -256,6 +256,8 @@ public:
} }
} }
const cbindgen_private::WindowAdapterRcOpaque &handle() const { return inner; }
private: private:
cbindgen_private::WindowAdapterRcOpaque inner; cbindgen_private::WindowAdapterRcOpaque inner;
}; };

View file

@ -31,7 +31,6 @@ namespace platform {
template<typename R> template<typename R>
concept Renderer = requires(R r) concept Renderer = requires(R r)
{ {
r.init(static_cast<const cbindgen_private::WindowAdapterRcOpaque *>(nullptr));
cbindgen_private::RendererPtr { r.renderer_handle() }; cbindgen_private::RendererPtr { r.renderer_handle() };
}; };
@ -82,8 +81,8 @@ class WindowAdapter : public AbstractWindowAdapter
// Note that we do not have ownership (there is no reference increase for this) // Note that we do not have ownership (there is no reference increase for this)
// because it would otherwise be a reference loop // because it would otherwise be a reference loop
cbindgen_private::WindowAdapterRcOpaque self {}; cbindgen_private::WindowAdapterRcOpaque self {};
std::unique_ptr<R> m_renderer;
// Whether this WindowAdapter was already given to the slint runtime // Whether this WindowAdapter was already given to the slint runtime
const R m_renderer;
bool was_initialized = false; bool was_initialized = false;
private: private:
@ -93,7 +92,7 @@ private:
cbindgen_private::slint_window_adapter_new( cbindgen_private::slint_window_adapter_new(
this, [](void *wa) { delete reinterpret_cast<const WA *>(wa); }, this, [](void *wa) { delete reinterpret_cast<const WA *>(wa); },
[](void *wa) { [](void *wa) {
return reinterpret_cast<const WA *>(wa)->m_renderer.renderer_handle(); return reinterpret_cast<const WA *>(wa)->m_renderer->renderer_handle();
}, },
[](void *wa) { reinterpret_cast<const WA *>(wa)->show(); }, [](void *wa) { reinterpret_cast<const WA *>(wa)->show(); },
[](void *wa) { reinterpret_cast<const WA *>(wa)->hide(); }, [](void *wa) { reinterpret_cast<const WA *>(wa)->hide(); },
@ -102,20 +101,18 @@ private:
return reinterpret_cast<const WA *>(wa)->physical_size(); return reinterpret_cast<const WA *>(wa)->physical_size();
}, },
&self); &self);
m_renderer.init(&self);
was_initialized = true; was_initialized = true;
return self; return self;
} }
public: public:
/// Construct a WindowAdapter. The arguments are forwarded to initialize the renderer /// Construct a WindowAdapter
template<typename... Args> explicit WindowAdapter() { }
explicit WindowAdapter(Args... a) : m_renderer(std::forward<Args>(a)...)
{ void set_renderer(std::unique_ptr<R> renderer) { m_renderer = std::move(renderer); }
}
/// Return a reference to the renderer that can be used to do the rendering. /// Return a reference to the renderer that can be used to do the rendering.
const R &renderer() const { return m_renderer; } const R &renderer() const { return *m_renderer; }
/// Return the slint::Window associated with this window. /// Return the slint::Window associated with this window.
/// ///
@ -207,23 +204,12 @@ class SoftwareRenderer
mutable cbindgen_private::SoftwareRendererOpaque inner; mutable cbindgen_private::SoftwareRendererOpaque inner;
public: public:
virtual ~SoftwareRenderer() virtual ~SoftwareRenderer() { cbindgen_private::slint_software_renderer_drop(inner); };
{
if (inner) {
cbindgen_private::slint_software_renderer_drop(inner);
}
};
SoftwareRenderer(const SoftwareRenderer &) = delete; SoftwareRenderer(const SoftwareRenderer &) = delete;
SoftwareRenderer &operator=(const SoftwareRenderer &) = delete; SoftwareRenderer &operator=(const SoftwareRenderer &) = delete;
SoftwareRenderer() = default; SoftwareRenderer(int max_buffer_age)
/// \private
void init(const cbindgen_private::WindowAdapterRcOpaque *win, int max_buffer_age) const
{ {
if (inner) { inner = cbindgen_private::slint_software_renderer_new(max_buffer_age);
cbindgen_private::slint_software_renderer_drop(inner);
}
inner = cbindgen_private::slint_software_renderer_new(max_buffer_age, win);
} }
/// \private /// \private
@ -238,9 +224,11 @@ public:
/// ///
/// The stride is the amount of pixels between two lines in the buffer. /// The stride is the amount of pixels between two lines in the buffer.
/// It is must be at least as large as the width of the window. /// It is must be at least as large as the width of the window.
void render(std::span<slint::Rgb8Pixel> buffer, std::size_t pixel_stride) const void render(const Window &window, std::span<slint::Rgb8Pixel> buffer,
std::size_t pixel_stride) const
{ {
cbindgen_private::slint_software_renderer_render_rgb8(inner, buffer.data(), buffer.size(), cbindgen_private::slint_software_renderer_render_rgb8(
inner, &window.window_handle().handle(), buffer.data(), buffer.size(),
pixel_stride); pixel_stride);
} }
}; };
@ -325,33 +313,17 @@ public:
/// Use render to perform the rendering. /// Use render to perform the rendering.
class SkiaRenderer class SkiaRenderer
{ {
mutable cbindgen_private::SkiaRendererOpaque inner = nullptr; mutable cbindgen_private::SkiaRendererOpaque inner;
NativeWindowHandle window_handle;
PhysicalSize initial_size;
public: public:
virtual ~SkiaRenderer() virtual ~SkiaRenderer() { cbindgen_private::slint_skia_renderer_drop(inner); }
{
if (inner) {
cbindgen_private::slint_skia_renderer_drop(inner);
}
};
SkiaRenderer(const SkiaRenderer &) = delete; SkiaRenderer(const SkiaRenderer &) = delete;
SkiaRenderer &operator=(const SkiaRenderer &) = delete; SkiaRenderer &operator=(const SkiaRenderer &) = delete;
/// Constructs a new Skia renderer for the given window - referenced by the provided /// Constructs a new Skia renderer for the given window - referenced by the provided
/// WindowHandle - and the specified initial size. /// WindowHandle - and the specified initial size.
SkiaRenderer(NativeWindowHandle &&window_handle, PhysicalSize initial_size) SkiaRenderer(const NativeWindowHandle &window_handle, PhysicalSize initial_size)
: window_handle(std::move(window_handle)), initial_size(initial_size)
{ {
} inner = cbindgen_private::slint_skia_renderer_new(window_handle.inner, initial_size);
/// \private
void init(const cbindgen_private::WindowAdapterRcOpaque *win) const
{
if (inner) {
cbindgen_private::slint_skia_renderer_drop(inner);
}
inner = cbindgen_private::slint_skia_renderer_new(win, window_handle.inner, initial_size);
} }
/// \private /// \private
@ -360,9 +332,9 @@ public:
return cbindgen_private::slint_skia_renderer_handle(inner); return cbindgen_private::slint_skia_renderer_handle(inner);
} }
void render(PhysicalSize size) const void render(const Window &window, PhysicalSize size) const
{ {
cbindgen_private::slint_skia_renderer_render(inner, size); cbindgen_private::slint_skia_renderer_render(inner, &window.window_handle().handle(), size);
} }
void resize(PhysicalSize size) const void resize(PhysicalSize size) const

View file

@ -160,19 +160,14 @@ pub extern "C" fn slint_platform_update_timers_and_animations() {
type SoftwareRendererOpaque = *const c_void; type SoftwareRendererOpaque = *const c_void;
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_software_renderer_new( pub unsafe extern "C" fn slint_software_renderer_new(buffer_age: u32) -> SoftwareRendererOpaque {
buffer_age: u32,
window: &WindowAdapterRcOpaque,
) -> SoftwareRendererOpaque {
let window = core::mem::transmute::<&WindowAdapterRcOpaque, &Rc<dyn WindowAdapter>>(window);
let weak = Rc::downgrade(window);
let repaint_buffer_type = match buffer_age { let repaint_buffer_type = match buffer_age {
0 => RepaintBufferType::NewBuffer, 0 => RepaintBufferType::NewBuffer,
1 => RepaintBufferType::ReusedBuffer, 1 => RepaintBufferType::ReusedBuffer,
2 => RepaintBufferType::SwappedBuffers, 2 => RepaintBufferType::SwappedBuffers,
_ => unreachable!(), _ => unreachable!(),
}; };
Box::into_raw(Box::new(SoftwareRenderer::new(repaint_buffer_type, weak))) Box::into_raw(Box::new(SoftwareRenderer::new_without_window(repaint_buffer_type)))
as SoftwareRendererOpaque as SoftwareRendererOpaque
} }
@ -184,12 +179,16 @@ pub unsafe extern "C" fn slint_software_renderer_drop(r: SoftwareRendererOpaque)
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_software_renderer_render_rgb8( pub unsafe extern "C" fn slint_software_renderer_render_rgb8(
r: SoftwareRendererOpaque, r: SoftwareRendererOpaque,
window_adapter: *const WindowAdapterRcOpaque,
buffer: *mut Rgb8Pixel, buffer: *mut Rgb8Pixel,
buffer_len: usize, buffer_len: usize,
pixel_stride: usize, pixel_stride: usize,
) { ) {
let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len); let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len);
(*(r as *const SoftwareRenderer)).render(buffer, pixel_stride); let renderer = &*(r as *const SoftwareRenderer);
let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
renderer.set_window(window_adapter.window());
renderer.render(buffer, pixel_stride);
} }
#[no_mangle] #[no_mangle]
@ -288,16 +287,11 @@ pub unsafe extern "C" fn slint_raw_window_handle_drop(handle: CppRawHandleOpaque
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_skia_renderer_new( pub unsafe extern "C" fn slint_skia_renderer_new(
window_adapter: &WindowAdapterRcOpaque,
handle_opaque: CppRawHandleOpaque, handle_opaque: CppRawHandleOpaque,
size: IntSize, size: IntSize,
) -> SkiaRendererOpaque { ) -> SkiaRendererOpaque {
let window_adapter =
core::mem::transmute::<&WindowAdapterRcOpaque, &Rc<dyn WindowAdapter>>(window_adapter);
let weak = Rc::downgrade(window_adapter);
let boxed_renderer: Box<SkiaRenderer> = Box::new( let boxed_renderer: Box<SkiaRenderer> = Box::new(
SkiaRenderer::new( SkiaRenderer::new(
weak,
&*(handle_opaque as *const CppRawHandle), &*(handle_opaque as *const CppRawHandle),
&*(handle_opaque as *const CppRawHandle), &*(handle_opaque as *const CppRawHandle),
PhysicalSize { width: size.width, height: size.height }, PhysicalSize { width: size.width, height: size.height },
@ -331,9 +325,15 @@ pub unsafe extern "C" fn slint_skia_renderer_resize(r: SkiaRendererOpaque, size:
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_skia_renderer_render(r: SkiaRendererOpaque, size: IntSize) { pub unsafe extern "C" fn slint_skia_renderer_render(
r: SkiaRendererOpaque,
window: *const WindowAdapterRcOpaque,
size: IntSize,
) {
let window_adapter = &*(window as *const Rc<dyn WindowAdapter>);
let r = &*(r as *const SkiaRenderer); let r = &*(r as *const SkiaRenderer);
r.render(PhysicalSize { width: size.width, height: size.height }).unwrap(); r.render(window_adapter.window(), PhysicalSize { width: size.width, height: size.height })
.unwrap();
} }
#[no_mangle] #[no_mangle]

View file

@ -19,22 +19,46 @@ struct Geometry
uint32_t height = 0; uint32_t height = 0;
}; };
struct NativeWindowHandle struct MyWindowAdapter : public slint_platform::WindowAdapter<slint_platform::SkiaRenderer>
{ {
HWND hwnd; HWND hwnd;
};
struct MyWindowAdapter : NativeWindowHandle,
public slint_platform::WindowAdapter<slint_platform::SkiaRenderer>
{
Geometry geometry = { 0, 0, 600, 300 }; Geometry geometry = { 0, 0, 600, 300 };
MyWindowAdapter(HWND winId) MyWindowAdapter(HWND winId)
: NativeWindowHandle { MyWindowAdapter::create_window(winId) },
slint_platform::WindowAdapter<slint_platform::SkiaRenderer>(
slint_platform::NativeWindowHandle::from_win32(hwnd, GetModuleHandleW(nullptr)),
slint::PhysicalSize({ 600, 300 }))
{ {
HINSTANCE hInstance = GetModuleHandleW(nullptr);
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = MyWindowAdapter::windowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
hwnd = CreateWindowEx(0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_CHILDWINDOW, // Window style
// Size and position
0, 0, 600, 300,
winId,
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
set_renderer(std::make_unique<slint_platform::SkiaRenderer>(
slint_platform::NativeWindowHandle::from_win32(hwnd, hInstance),
slint::PhysicalSize({ 600, 300 })));
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
} }
@ -61,7 +85,7 @@ struct MyWindowAdapter : NativeWindowHandle,
void render() void render()
{ {
renderer().render(physical_size()); renderer().render(window(), physical_size());
if (has_active_animations()) if (has_active_animations())
request_redraw(); request_redraw();
} }
@ -205,37 +229,4 @@ struct MyWindowAdapter : NativeWindowHandle,
} }
private: private:
static HWND create_window(HWND parentWindow)
{
HINSTANCE hInstance = GetModuleHandleW(nullptr);
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = MyWindowAdapter::windowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_CHILDWINDOW, // Window style
// Size and position
0, 0, 600, 300,
parentWindow,
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
return hwnd;
}
}; };

View file

@ -54,11 +54,11 @@ class MyWindow : public QWindow, public slint_platform::WindowAdapter<slint_plat
public: public:
MyWindow(QWindow *parentWindow = nullptr) MyWindow(QWindow *parentWindow = nullptr)
: QWindow(parentWindow), : QWindow(parentWindow), slint_platform::WindowAdapter<slint_platform::SkiaRenderer>()
slint_platform::WindowAdapter<slint_platform::SkiaRenderer>(
window_handle_for_qt_window(this),
slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) }))
{ {
set_renderer(std::make_unique<slint_platform::SkiaRenderer>(
window_handle_for_qt_window(this),
slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) })));
} }
/*void keyEvent(QKeyEvent *event) override /*void keyEvent(QKeyEvent *event) override
@ -71,7 +71,7 @@ public:
slint_platform::update_timers_and_animations(); slint_platform::update_timers_and_animations();
auto windowSize = slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) }); auto windowSize = slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) });
renderer().render(windowSize); renderer().render(window(), windowSize);
if (has_active_animations()) { if (has_active_animations()) {
requestUpdate(); requestUpdate();

View file

@ -24,15 +24,11 @@ pub enum SlintUserEvent {
} }
mod renderer { mod renderer {
use std::rc::Weak;
use i_slint_core::api::PhysicalSize; use i_slint_core::api::PhysicalSize;
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::window::WindowAdapter;
pub(crate) trait WinitCompatibleRenderer { pub(crate) trait WinitCompatibleRenderer {
fn new( fn new(
window_adapter_weak: &Weak<dyn WindowAdapter>,
window_builder: winit::window::WindowBuilder, window_builder: winit::window::WindowBuilder,
#[cfg(target_arch = "wasm32")] canvas_id: &str, #[cfg(target_arch = "wasm32")] canvas_id: &str,
) -> Result<(Self, winit::window::Window), PlatformError> ) -> Result<(Self, winit::window::Window), PlatformError>
@ -42,7 +38,11 @@ mod renderer {
fn show(&self) -> Result<(), PlatformError>; fn show(&self) -> Result<(), PlatformError>;
fn hide(&self) -> Result<(), PlatformError>; fn hide(&self) -> Result<(), PlatformError>;
fn render(&self, size: PhysicalSize) -> Result<(), PlatformError>; fn render(
&self,
window: &i_slint_core::api::Window,
size: PhysicalSize,
) -> Result<(), PlatformError>;
fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer; fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer;

View file

@ -1,12 +1,9 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com> // Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::rc::Weak;
use i_slint_core::api::PhysicalSize as PhysicalWindowSize; use i_slint_core::api::PhysicalSize as PhysicalWindowSize;
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::renderer::Renderer; use i_slint_core::renderer::Renderer;
use i_slint_core::window::WindowAdapter;
use i_slint_renderer_femtovg::FemtoVGRenderer; use i_slint_renderer_femtovg::FemtoVGRenderer;
mod glcontext; mod glcontext;
@ -17,7 +14,6 @@ pub struct GlutinFemtoVGRenderer {
impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer { impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
fn new( fn new(
window_adapter_weak: &Weak<dyn WindowAdapter>,
window_builder: winit::window::WindowBuilder, window_builder: winit::window::WindowBuilder,
#[cfg(target_arch = "wasm32")] canvas_id: &str, #[cfg(target_arch = "wasm32")] canvas_id: &str,
) -> Result<(Self, winit::window::Window), PlatformError> { ) -> Result<(Self, winit::window::Window), PlatformError> {
@ -30,7 +26,7 @@ impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
) )
})?; })?;
let renderer = FemtoVGRenderer::new(window_adapter_weak, opengl_context)?; let renderer = FemtoVGRenderer::new(opengl_context)?;
Ok((Self { renderer }, winit_window)) Ok((Self { renderer }, winit_window))
} }
@ -43,8 +39,12 @@ impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
self.renderer.hide() self.renderer.hide()
} }
fn render(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> { fn render(
self.renderer.render(size) &self,
window: &i_slint_core::api::Window,
size: PhysicalWindowSize,
) -> Result<(), PlatformError> {
self.renderer.render(window, size)
} }
fn as_core_renderer(&self) -> &dyn Renderer { fn as_core_renderer(&self) -> &dyn Renderer {

View file

@ -1,11 +1,8 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com> // Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::rc::Weak;
use i_slint_core::api::PhysicalSize as PhysicalWindowSize; use i_slint_core::api::PhysicalSize as PhysicalWindowSize;
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::window::WindowAdapter;
pub struct SkiaRenderer { pub struct SkiaRenderer {
renderer: i_slint_renderer_skia::SkiaRenderer, renderer: i_slint_renderer_skia::SkiaRenderer,
@ -13,7 +10,6 @@ pub struct SkiaRenderer {
impl super::WinitCompatibleRenderer for SkiaRenderer { impl super::WinitCompatibleRenderer for SkiaRenderer {
fn new( fn new(
window_adapter_weak: &Weak<dyn WindowAdapter>,
window_builder: winit::window::WindowBuilder, window_builder: winit::window::WindowBuilder,
) -> Result<(Self, winit::window::Window), PlatformError> { ) -> Result<(Self, winit::window::Window), PlatformError> {
let winit_window = crate::event_loop::with_window_target(|event_loop| { let winit_window = crate::event_loop::with_window_target(|event_loop| {
@ -38,7 +34,6 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
})?; })?;
let renderer = i_slint_renderer_skia::SkiaRenderer::new( let renderer = i_slint_renderer_skia::SkiaRenderer::new(
window_adapter_weak.clone(),
&winit_window, &winit_window,
&winit_window, &winit_window,
PhysicalWindowSize::new(width, height), PhysicalWindowSize::new(width, height),
@ -55,8 +50,12 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
self.renderer.hide() self.renderer.hide()
} }
fn render(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> { fn render(
self.renderer.render(size) &self,
window: &i_slint_core::api::Window,
size: PhysicalWindowSize,
) -> Result<(), PlatformError> {
self.renderer.render(window, size)
} }
fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer { fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {

View file

@ -8,9 +8,7 @@ use i_slint_core::graphics::Rgb8Pixel;
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::software_renderer::PremultipliedRgbaColor; use i_slint_core::software_renderer::PremultipliedRgbaColor;
pub use i_slint_core::software_renderer::SoftwareRenderer; pub use i_slint_core::software_renderer::SoftwareRenderer;
use i_slint_core::window::WindowAdapter;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Weak;
pub struct WinitSoftwareRenderer { pub struct WinitSoftwareRenderer {
renderer: SoftwareRenderer, renderer: SoftwareRenderer,
@ -19,7 +17,6 @@ pub struct WinitSoftwareRenderer {
impl super::WinitCompatibleRenderer for WinitSoftwareRenderer { impl super::WinitCompatibleRenderer for WinitSoftwareRenderer {
fn new( fn new(
window_adapter_weak: &Weak<dyn WindowAdapter>,
window_builder: winit::window::WindowBuilder, window_builder: winit::window::WindowBuilder,
) -> Result<(Self, winit::window::Window), PlatformError> { ) -> Result<(Self, winit::window::Window), PlatformError> {
let winit_window = crate::event_loop::with_window_target(|event_loop| { let winit_window = crate::event_loop::with_window_target(|event_loop| {
@ -35,9 +32,8 @@ impl super::WinitCompatibleRenderer for WinitSoftwareRenderer {
Ok(( Ok((
Self { Self {
renderer: SoftwareRenderer::new( renderer: SoftwareRenderer::new_without_window(
i_slint_core::software_renderer::RepaintBufferType::NewBuffer, i_slint_core::software_renderer::RepaintBufferType::NewBuffer,
window_adapter_weak.clone(),
), ),
canvas: RefCell::new(canvas), canvas: RefCell::new(canvas),
}, },
@ -53,10 +49,16 @@ impl super::WinitCompatibleRenderer for WinitSoftwareRenderer {
Ok(()) Ok(())
} }
fn render(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> { fn render(
&self,
window: &i_slint_core::api::Window,
size: PhysicalWindowSize,
) -> Result<(), PlatformError> {
let width = size.width as usize; let width = size.width as usize;
let height = size.height as usize; let height = size.height as usize;
self.renderer.set_window(window);
let softbuffer_buffer = if std::env::var_os("SLINT_LINE_BY_LINE").is_none() { let softbuffer_buffer = if std::env::var_os("SLINT_LINE_BY_LINE").is_none() {
let mut buffer = vec![PremultipliedRgbaColor::default(); width * height]; let mut buffer = vec![PremultipliedRgbaColor::default(); width * height];
self.renderer.render(buffer.as_mut_slice(), width); self.renderer.render(buffer.as_mut_slice(), width);

View file

@ -153,7 +153,6 @@ impl WinitWindowAdapter {
) )
.and_then(|builder| { .and_then(|builder| {
R::new( R::new(
&(self_weak.clone() as _),
builder, builder,
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
canvas_id, canvas_id,
@ -277,7 +276,8 @@ impl WinitWindowAdapter {
self.pending_redraw.set(false); self.pending_redraw.set(false);
let renderer = self.renderer(); let renderer = self.renderer();
renderer.render(physical_size_to_slint(&self.winit_window().inner_size()))?; renderer
.render(self.window(), physical_size_to_slint(&self.winit_window().inner_size()))?;
Ok(self.pending_redraw.get()) Ok(self.pending_redraw.get())
} }

View file

@ -121,7 +121,7 @@ pub struct SoftwareRenderer {
/// This is the area which was dirty on the previous frame. /// This is the area which was dirty on the previous frame.
/// Only used if repaint_buffer_type == RepaintBufferType::SwappedBuffers /// Only used if repaint_buffer_type == RepaintBufferType::SwappedBuffers
prev_frame_dirty: Cell<DirtyRegion>, prev_frame_dirty: Cell<DirtyRegion>,
window: Weak<dyn crate::window::WindowAdapter>, window: RefCell<Option<Weak<dyn crate::window::WindowAdapter>>>,
} }
impl SoftwareRenderer { impl SoftwareRenderer {
@ -131,12 +131,17 @@ impl SoftwareRenderer {
/// ///
/// The `window` parameter can be coming from [`Rc::new_cyclic()`](alloc::rc::Rc::new_cyclic()) /// The `window` parameter can be coming from [`Rc::new_cyclic()`](alloc::rc::Rc::new_cyclic())
/// since the `WindowAdapter` most likely own the Renderer /// since the `WindowAdapter` most likely own the Renderer
#[doc(hidden)]
#[deprecated(
since = "1.0.3",
note = "Use MinimalSoftwareWindow instead of constructing a SoftwareRenderer Directly"
)]
pub fn new( pub fn new(
repaint_buffer_type: RepaintBufferType, repaint_buffer_type: RepaintBufferType,
window: Weak<dyn crate::window::WindowAdapter>, window: Weak<dyn crate::window::WindowAdapter>,
) -> Self { ) -> Self {
Self { Self {
window: window.clone(), window: RefCell::new(Some(window.clone())),
repaint_buffer_type, repaint_buffer_type,
partial_cache: Default::default(), partial_cache: Default::default(),
force_dirty: Default::default(), force_dirty: Default::default(),
@ -145,6 +150,32 @@ impl SoftwareRenderer {
} }
} }
/// Create a new Renderer for a given window.
///
/// The `repaint_buffer_type` parameter specify what kind of buffer are passed to [`Self::render`]
///
/// The `window` parameter can be coming from [`Rc::new_cyclic()`](alloc::rc::Rc::new_cyclic())
/// since the `WindowAdapter` most likely own the Renderer
#[doc(hidden)]
pub fn new_without_window(repaint_buffer_type: RepaintBufferType) -> Self {
Self {
window: RefCell::new(None),
repaint_buffer_type,
partial_cache: Default::default(),
force_dirty: Default::default(),
force_screen_refresh: Default::default(),
prev_frame_dirty: Default::default(),
}
}
/// Sets the window to be use for future rendering operations. Call this before calling
/// rendering.
#[doc(hidden)]
pub fn set_window(&self, window: &crate::api::Window) {
*self.window.borrow_mut() =
Some(Rc::downgrade(&WindowInner::from_pub(window).window_adapter().clone()));
}
/// Internal function to apply a dirty region depending on the dirty_tracking_policy. /// Internal function to apply a dirty region depending on the dirty_tracking_policy.
/// Returns the region to actually draw. /// Returns the region to actually draw.
fn apply_dirty_region( fn apply_dirty_region(
@ -180,7 +211,12 @@ impl SoftwareRenderer {
/// ///
/// returns the dirty region for this frame (not including the extra_draw_region) /// returns the dirty region for this frame (not including the extra_draw_region)
pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize) -> PhysicalRegion { pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize) -> PhysicalRegion {
let window = self.window.upgrade().expect("render() called on a destroyed Window"); let window = self
.window
.borrow()
.as_ref()
.and_then(|w| w.upgrade())
.expect("render() called on a destroyed Window");
let window_inner = WindowInner::from_pub(window.window()); let window_inner = WindowInner::from_pub(window.window());
let factor = ScaleFactor::new(window_inner.scale_factor()); let factor = ScaleFactor::new(window_inner.scale_factor());
let (size, background) = if let Some(window_item) = let (size, background) = if let Some(window_item) =
@ -272,7 +308,12 @@ impl SoftwareRenderer {
/// # } /// # }
/// ``` /// ```
pub fn render_by_line(&self, line_buffer: impl LineBufferProvider) -> PhysicalRegion { pub fn render_by_line(&self, line_buffer: impl LineBufferProvider) -> PhysicalRegion {
let window = self.window.upgrade().expect("render() called on a destroyed Window"); let window = self
.window
.borrow()
.as_ref()
.and_then(|w| w.upgrade())
.expect("render() called on a destroyed Window");
let window_inner = WindowInner::from_pub(window.window()); let window_inner = WindowInner::from_pub(window.window());
let component_rc = window_inner.component(); let component_rc = window_inner.component();
let component = crate::component::ComponentRc::borrow_pin(&component_rc); let component = crate::component::ComponentRc::borrow_pin(&component_rc);
@ -1933,7 +1974,7 @@ impl MinimalSoftwareWindow {
pub fn new(repaint_buffer_type: RepaintBufferType) -> Rc<Self> { pub fn new(repaint_buffer_type: RepaintBufferType) -> Rc<Self> {
Rc::new_cyclic(|w: &Weak<Self>| Self { Rc::new_cyclic(|w: &Weak<Self>| Self {
window: Window::new(w.clone()), window: Window::new(w.clone()),
renderer: SoftwareRenderer::new(repaint_buffer_type, w.clone()), renderer: SoftwareRenderer::new_without_window(repaint_buffer_type),
needs_redraw: Default::default(), needs_redraw: Default::default(),
size: Default::default(), size: Default::default(),
}) })
@ -1947,6 +1988,7 @@ impl MinimalSoftwareWindow {
/// Return true if something was redrawn. /// Return true if something was redrawn.
pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool { pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
if self.needs_redraw.replace(false) { if self.needs_redraw.replace(false) {
self.renderer.set_window(&self.window);
render_callback(&self.renderer); render_callback(&self.renderer);
true true
} else { } else {

View file

@ -6,7 +6,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::pin::Pin; use std::pin::Pin;
use std::rc::{Rc, Weak}; use std::rc::Rc;
use i_slint_core::api::{ use i_slint_core::api::{
PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState,
@ -20,7 +20,7 @@ use i_slint_core::lengths::{
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::renderer::Renderer; use i_slint_core::renderer::Renderer;
use i_slint_core::sharedfontdb; use i_slint_core::sharedfontdb;
use i_slint_core::window::{WindowAdapter, WindowInner}; use i_slint_core::window::WindowInner;
use i_slint_core::Brush; use i_slint_core::Brush;
type PhysicalLength = euclid::Length<f32, PhysicalPx>; type PhysicalLength = euclid::Length<f32, PhysicalPx>;
@ -54,7 +54,6 @@ pub unsafe trait OpenGLContextWrapper {
/// Use the FemtoVG renderer when implementing a custom Slint platform where you deliver events to /// Use the FemtoVG renderer when implementing a custom Slint platform where you deliver events to
/// Slint and want the scene to be rendered using OpenGL and the FemtoVG renderer. /// Slint and want the scene to be rendered using OpenGL and the FemtoVG renderer.
pub struct FemtoVGRenderer { pub struct FemtoVGRenderer {
window_adapter_weak: Weak<dyn WindowAdapter>,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
canvas: CanvasRc, canvas: CanvasRc,
graphics_cache: itemrenderer::ItemGraphicsCache, graphics_cache: itemrenderer::ItemGraphicsCache,
@ -65,14 +64,11 @@ pub struct FemtoVGRenderer {
} }
impl FemtoVGRenderer { impl FemtoVGRenderer {
/// Creates a new renderer is associated with the provided window adapter and an implementation /// Creates a new renderer is associated with an implementation
/// of the OpenGLContextWrapper trait. The trait serves the purpose of giving the renderer control /// of the OpenGLContextWrapper trait. The trait serves the purpose of giving the renderer control
/// over when the make the context current, how to retrieve the address of GL functions, and when /// over when the make the context current, how to retrieve the address of GL functions, and when
/// to swap back and front buffers. /// to swap back and front buffers.
pub fn new( pub fn new(opengl_context: impl OpenGLContextWrapper + 'static) -> Result<Self, PlatformError> {
window_adapter_weak: &Weak<dyn WindowAdapter>,
opengl_context: impl OpenGLContextWrapper + 'static,
) -> Result<Self, PlatformError> {
let opengl_context = Box::new(opengl_context); let opengl_context = Box::new(opengl_context);
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let gl_renderer = unsafe { let gl_renderer = unsafe {
@ -116,7 +112,6 @@ impl FemtoVGRenderer {
let canvas = Rc::new(RefCell::new(femtovg_canvas)); let canvas = Rc::new(RefCell::new(femtovg_canvas));
Ok(Self { Ok(Self {
window_adapter_weak: window_adapter_weak.clone(),
rendering_notifier: Default::default(), rendering_notifier: Default::default(),
canvas, canvas,
graphics_cache: Default::default(), graphics_cache: Default::default(),
@ -154,6 +149,7 @@ impl FemtoVGRenderer {
/// Render the scene using OpenGL. This function assumes that the context is current. /// Render the scene using OpenGL. This function assumes that the context is current.
pub fn render( pub fn render(
&self, &self,
window: &i_slint_core::api::Window,
size: PhysicalWindowSize, size: PhysicalWindowSize,
) -> Result<(), i_slint_core::platform::PlatformError> { ) -> Result<(), i_slint_core::platform::PlatformError> {
self.opengl_context.ensure_current()?; self.opengl_context.ensure_current()?;
@ -161,12 +157,12 @@ impl FemtoVGRenderer {
let width = size.width; let width = size.width;
let height = size.height; let height = size.height;
let window_adapter = self.window_adapter_weak.upgrade().unwrap(); let window_inner = WindowInner::from_pub(window);
let window = WindowInner::from_pub(window_adapter.window()); let scale = window_inner.scale_factor().ceil();
let scale = window.scale_factor().ceil();
window.draw_contents(|components| -> Result<(), PlatformError> { window_inner.draw_contents(|components| -> Result<(), PlatformError> {
let window_background_brush = window.window_item().map(|w| w.as_pin_ref().background()); let window_background_brush =
window_inner.window_item().map(|w| w.as_pin_ref().background());
{ {
let mut femtovg_canvas = self.canvas.borrow_mut(); let mut femtovg_canvas = self.canvas.borrow_mut();
@ -203,13 +199,11 @@ impl FemtoVGRenderer {
})?; })?;
} }
let window_adapter = self.window_adapter_weak.upgrade().unwrap();
let mut item_renderer = self::itemrenderer::GLItemRenderer::new( let mut item_renderer = self::itemrenderer::GLItemRenderer::new(
&self.canvas, &self.canvas,
&self.graphics_cache, &self.graphics_cache,
&self.texture_cache, &self.texture_cache,
window_adapter.window(), window,
width, width,
height, height,
); );
@ -220,7 +214,7 @@ impl FemtoVGRenderer {
Some(brush @ _) => { Some(brush @ _) => {
item_renderer.draw_rect( item_renderer.draw_rect(
i_slint_core::lengths::logical_size_from_api( i_slint_core::lengths::logical_size_from_api(
size.to_logical(window.scale_factor()), size.to_logical(window_inner.scale_factor()),
), ),
brush, brush,
); );

View file

@ -5,7 +5,7 @@
#![doc(html_logo_url = "https://slint-ui.com/logo/slint-logo-square-light.svg")] #![doc(html_logo_url = "https://slint-ui.com/logo/slint-logo-square-light.svg")]
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::{Rc, Weak}; use std::rc::Rc;
use i_slint_core::api::{ use i_slint_core::api::{
GraphicsAPI, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState, GraphicsAPI, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState,
@ -19,7 +19,7 @@ use i_slint_core::lengths::{
LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx, ScaleFactor, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx, ScaleFactor,
}; };
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::window::{WindowAdapter, WindowInner}; use i_slint_core::window::WindowInner;
use i_slint_core::Brush; use i_slint_core::Brush;
type PhysicalLength = euclid::Length<f32, PhysicalPx>; type PhysicalLength = euclid::Length<f32, PhysicalPx>;
@ -54,7 +54,6 @@ cfg_if::cfg_if! {
/// Use the SkiaRenderer when implementing a custom Slint platform where you deliver events to /// Use the SkiaRenderer when implementing a custom Slint platform where you deliver events to
/// Slint and want the scene to be rendered using Skia as underlying graphics library. /// Slint and want the scene to be rendered using Skia as underlying graphics library.
pub struct SkiaRenderer { pub struct SkiaRenderer {
window_adapter_weak: Weak<dyn WindowAdapter>,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
image_cache: ItemCache<Option<skia_safe::Image>>, image_cache: ItemCache<Option<skia_safe::Image>>,
path_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>, path_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>,
@ -65,7 +64,6 @@ pub struct SkiaRenderer {
impl SkiaRenderer { impl SkiaRenderer {
/// Creates a new renderer is associated with the provided window adapter. /// Creates a new renderer is associated with the provided window adapter.
pub fn new( pub fn new(
window_adapter_weak: Weak<dyn WindowAdapter>,
native_window: &impl raw_window_handle::HasRawWindowHandle, native_window: &impl raw_window_handle::HasRawWindowHandle,
native_display: &impl raw_window_handle::HasRawDisplayHandle, native_display: &impl raw_window_handle::HasRawDisplayHandle,
size: PhysicalWindowSize, size: PhysicalWindowSize,
@ -73,7 +71,6 @@ impl SkiaRenderer {
let surface = DefaultSurface::new(&native_window, &native_display, size)?; let surface = DefaultSurface::new(&native_window, &native_display, size)?;
Ok(Self { Ok(Self {
window_adapter_weak,
rendering_notifier: Default::default(), rendering_notifier: Default::default(),
image_cache: Default::default(), image_cache: Default::default(),
path_cache: Default::default(), path_cache: Default::default(),
@ -113,10 +110,10 @@ impl SkiaRenderer {
/// Render the scene in the previously associated window. The size parameter must match the size of the window. /// Render the scene in the previously associated window. The size parameter must match the size of the window.
pub fn render( pub fn render(
&self, &self,
window: &i_slint_core::api::Window,
size: PhysicalWindowSize, size: PhysicalWindowSize,
) -> Result<(), i_slint_core::platform::PlatformError> { ) -> Result<(), i_slint_core::platform::PlatformError> {
let window_adapter = self.window_adapter_weak.upgrade().unwrap(); let window_inner = WindowInner::from_pub(window);
let window_inner = WindowInner::from_pub(window_adapter.window());
self.surface.render(size, |skia_canvas, gr_context| { self.surface.render(size, |skia_canvas, gr_context| {
window_inner.draw_contents(|components| { window_inner.draw_contents(|components| {
@ -141,11 +138,9 @@ impl SkiaRenderer {
let mut box_shadow_cache = Default::default(); let mut box_shadow_cache = Default::default();
let window_adapter = self.window_adapter_weak.upgrade().unwrap();
let mut item_renderer = itemrenderer::SkiaRenderer::new( let mut item_renderer = itemrenderer::SkiaRenderer::new(
skia_canvas, skia_canvas,
window_adapter.window(), window,
&self.image_cache, &self.image_cache,
&self.path_cache, &self.path_cache,
&mut box_shadow_cache, &mut box_shadow_cache,