diff --git a/src/backend/renderer/multigpu/mod.rs b/src/backend/renderer/multigpu/mod.rs index fb09bece20d8..254ca4f576a6 100644 --- a/src/backend/renderer/multigpu/mod.rs +++ b/src/backend/renderer/multigpu/mod.rs @@ -356,13 +356,10 @@ impl GpuManager { /// - `target_api` should be the [`GpuManager`] used for the `target_device`. /// - `render_device` should referr to the gpu node rendering operations will take place upon. /// - `target_device` should referr to the gpu node the composited buffer will end up upon - /// - `allocator` should referr to an `Allocator`, that works guaranteed with the `render_device` - /// to do offscreen composition on. Dma copies will be used, if buffers returned by the allocator - /// also work on the `target_device`. /// - `copy_format` denotes the format buffers will be allocated in for offscreen rendering. #[instrument(level = "trace", skip(render_api, target_api), follows_from = [&render_api.span, &target_api.span])] #[profiling::function] - pub fn cross_renderer<'render, 'target, B: GraphicsApi, Alloc: Allocator>( + pub fn cross_renderer<'render, 'target, B: GraphicsApi>( render_api: &'render mut Self, target_api: &'target mut GpuManager, render_device: &DrmNode, @@ -767,16 +764,51 @@ impl AsMut<::Renderer> } } +impl<'render, 'target, R: GraphicsApi, T: GraphicsApi> MultiRenderer<'render, 'target, R, T> { + /// Converts this renderer into a reference of the target-device's renderer, + /// if it diverges from the render-device. + pub fn target_as_ref(&self) -> Option<&::Renderer> { + self.target.as_ref().map(|data| data.device.renderer()) + } + + /// Converts this renderer into a mutable reference of the target-device's renderer, + /// if it diverges from the render-device. + pub fn target_as_mut(&mut self) -> Option<&mut ::Renderer> { + self.target.as_mut().map(|data| data.device.renderer_mut()) + } + + /// Converts this `MultiRenderer` into a `single_renderer` for the provided target device. + /// + /// Will return the current renderer, if it is already a single-device render. + pub fn into_target(self) -> MultiRenderer<'target, 'target, T, T> { + if let Some(target) = self.target { + MultiRenderer { + render: target.device, + target: None, + other_renderers: Vec::new(), + span: self.span, + } + } else { + // Safety: We know R == T and thus 'render == 'target, if target is `None`. + unsafe { + std::mem::transmute::< + MultiRenderer<'render, 'target, R, T>, + MultiRenderer<'target, 'target, T, T>, + >(self) + } + } + } +} + /// A Framebuffer of a [`MultiRenderer`]. -pub struct MultiFramebuffer<'buffer, R: GraphicsApi, T: GraphicsApi>(MultiFramebufferInternal<'buffer, R, T>); -enum MultiFramebufferInternal<'buffer, R: GraphicsApi, T: GraphicsApi> { - Render(<::Renderer as RendererSuper>::Framebuffer<'buffer>), +pub struct MultiFramebuffer<'buffer, T: GraphicsApi>(MultiFramebufferInternal<'buffer, T>); +enum MultiFramebufferInternal<'buffer, T: GraphicsApi> { + Render(<::Renderer as RendererSuper>::Framebuffer<'buffer>), Target(<::Renderer as RendererSuper>::Framebuffer<'buffer>), } -impl<'buffer, R: GraphicsApi, T: GraphicsApi> fmt::Debug for MultiFramebuffer<'buffer, R, T> +impl<'buffer, T: GraphicsApi> fmt::Debug for MultiFramebuffer<'buffer, T> where - <::Renderer as RendererSuper>::Framebuffer<'buffer>: fmt::Debug, <::Renderer as RendererSuper>::Framebuffer<'buffer>: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -787,7 +819,7 @@ where } } -impl Texture for MultiFramebuffer<'_, R, T> { +impl Texture for MultiFramebuffer<'_, T> { fn size(&self) -> Size { match &self.0 { MultiFramebufferInternal::Render(framebuffer) => framebuffer.size(), @@ -817,6 +849,28 @@ impl Texture for MultiFramebuffer<'_, R, T> { } } +impl<'a, T: GraphicsApi> AsRef<<::Renderer as RendererSuper>::Framebuffer<'a>> + for MultiFramebuffer<'a, T> +{ + fn as_ref(&self) -> &<::Renderer as RendererSuper>::Framebuffer<'a> { + match &self.0 { + MultiFramebufferInternal::Render(fb) => fb, + MultiFramebufferInternal::Target(fb) => fb, + } + } +} + +impl<'a, T: GraphicsApi> AsMut<<::Renderer as RendererSuper>::Framebuffer<'a>> + for MultiFramebuffer<'a, T> +{ + fn as_mut(&mut self) -> &mut <::Renderer as RendererSuper>::Framebuffer<'a> { + match &mut self.0 { + MultiFramebufferInternal::Render(fb) => fb, + MultiFramebufferInternal::Target(fb) => fb, + } + } +} + /// [`Frame`] implementation of a [`MultiRenderer`]. /// /// Leaking the frame will potentially keep it from doing necessary copies @@ -960,10 +1014,8 @@ where impl Offscreen for MultiRenderer<'_, '_, R, T> where ::Renderer: Offscreen, - ::Renderer: Offscreen, // We need these because the Bind-impl does and Offscreen requires Bind ::Renderer: Bind, - ::Renderer: Bind, // We need these because the Renderer-impl does and Offscreen requires Bind, which requires Unbind, which requires Renderer R: 'static, R::Error: 'static, @@ -988,10 +1040,14 @@ where .create_buffer(format, size) .map_err(Error::Target) } else { - self.render - .renderer_mut() - .create_buffer(format, size) - .map_err(Error::Render) + // SAFETY: We know this is safe, because `self.target` can only be `None` if R == T. + let renderer = unsafe { + std::mem::transmute::< + &mut ::Renderer, + &mut ::Renderer, + >(self.render.renderer_mut()) + }; + renderer.create_buffer(format, size).map_err(Error::Target) } } } @@ -999,7 +1055,6 @@ where impl Bind for MultiRenderer<'_, '_, R, T> where ::Renderer: Bind, - ::Renderer: Bind, // We need this because the Renderer-impl does and Bind requires Unbind, which requires Renderer R: 'static, R::Error: 'static, @@ -1025,12 +1080,18 @@ where .map(MultiFramebuffer) .map_err(Error::Target) } else { - self.render - .renderer_mut() + // SAFETY: We know this is safe, because `self.target` can only be `None` if R == T. + let renderer = unsafe { + std::mem::transmute::< + &mut ::Renderer, + &mut ::Renderer, + >(self.render.renderer_mut()) + }; + renderer .bind(bind) .map(MultiFramebufferInternal::Render) .map(MultiFramebuffer) - .map_err(Error::Render) + .map_err(Error::Target) } } @@ -1038,7 +1099,13 @@ where if let Some(target) = self.target.as_ref() { Bind::::supported_formats(target.device.renderer()) } else { - Bind::::supported_formats(self.render.renderer()) + // SAFETY: We know this is safe, because `self.target` can only be `None` if R == T. + let renderer = unsafe { + std::mem::transmute::<&::Renderer, &::Renderer>( + self.render.renderer(), + ) + }; + Bind::::supported_formats(renderer) } } } @@ -1058,7 +1125,7 @@ where { type Error = Error; type TextureId = MultiTexture; - type Framebuffer<'buffer> = MultiFramebuffer<'buffer, R, T>; + type Framebuffer<'buffer> = MultiFramebuffer<'buffer, T>; type Frame<'frame, 'buffer> = MultiFrame<'render, 'target, 'frame, 'buffer, R, T> where @@ -1195,11 +1262,19 @@ where let mut target = None; let mut new_framebuffer = None; let frame = match &mut framebuffer.0 { - MultiFramebufferInternal::Render(framebuffer) => self - .render - .renderer_mut() - .render(framebuffer, size, dst_transform) - .map_err(Error::Render)?, + MultiFramebufferInternal::Render(framebuffer) => { + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let framebuffer = unsafe { + std::mem::transmute::< + &mut <::Renderer as RendererSuper>::Framebuffer<'buffer>, + &mut <::Renderer as RendererSuper>::Framebuffer<'buffer>, + >(framebuffer) + }; + self.render + .renderer_mut() + .render(framebuffer, size, dst_transform) + .map_err(Error::Render)? + } MultiFramebufferInternal::Target(target_framebuffer) => { let (target_device, render_framebuffer, texture, format) = target_state.unwrap(); target = Some(TargetFrameData { @@ -2759,7 +2834,7 @@ where #[profiling::function] fn copy_framebuffer( &mut self, - framebuffer: &MultiFramebuffer<'_, R, T>, + framebuffer: &MultiFramebuffer<'_, T>, region: Rectangle, format: Fourcc, ) -> Result::Error> { @@ -2773,12 +2848,20 @@ where .map(|mapping| MultiTextureMapping(TextureMappingInternal::Either(mapping))) .map_err(Error::Target) } - MultiFramebufferInternal::Render(fb) => self - .render - .renderer_mut() - .copy_framebuffer(fb, region, format) - .map(|mapping| MultiTextureMapping(TextureMappingInternal::Or(mapping))) - .map_err(Error::Render), + MultiFramebufferInternal::Render(fb) => { + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let fb = unsafe { + std::mem::transmute::< + &<::Renderer as RendererSuper>::Framebuffer<'_>, + &<::Renderer as RendererSuper>::Framebuffer<'_>, + >(fb) + }; + self.render + .renderer_mut() + .copy_framebuffer(fb, region, format) + .map(|mapping| MultiTextureMapping(TextureMappingInternal::Or(mapping))) + .map_err(Error::Render) + } } } @@ -2834,7 +2917,7 @@ where } } -impl<'frame, 'buffer, R: GraphicsApi, T: GraphicsApi> BlitFrame> +impl<'frame, 'buffer, R: GraphicsApi, T: GraphicsApi> BlitFrame> for MultiFrame<'_, '_, 'frame, 'buffer, R, T> where <::Renderer as RendererSuper>::Frame<'frame, 'buffer>: @@ -2853,7 +2936,7 @@ where #[profiling::function] fn blit_to( &mut self, - to: &mut MultiFramebuffer<'buffer, R, T>, + to: &mut MultiFramebuffer<'buffer, T>, src: Rectangle, dst: Rectangle, filter: TextureFilter, @@ -2874,6 +2957,13 @@ where let MultiFramebufferInternal::Render(ref mut to_fb) = &mut to.0 else { unreachable!() }; + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let to_fb = unsafe { + std::mem::transmute::< + &mut <::Renderer as RendererSuper>::Framebuffer<'_>, + &mut <::Renderer as RendererSuper>::Framebuffer<'_>, + >(to_fb) + }; self.frame .as_mut() .unwrap() @@ -2886,7 +2976,7 @@ where #[profiling::function] fn blit_from( &mut self, - from: &MultiFramebuffer<'buffer, R, T>, + from: &MultiFramebuffer<'buffer, T>, src: Rectangle, dst: Rectangle, filter: TextureFilter, @@ -2907,6 +2997,13 @@ where let MultiFramebufferInternal::Render(ref from_fb) = &from.0 else { unreachable!() }; + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let from_fb = unsafe { + std::mem::transmute::< + &<::Renderer as RendererSuper>::Framebuffer<'_>, + &<::Renderer as RendererSuper>::Framebuffer<'_>, + >(from_fb) + }; self.frame .as_mut() .unwrap() @@ -2934,8 +3031,8 @@ where #[profiling::function] fn blit( &mut self, - from: &MultiFramebuffer<'_, R, T>, - to: &mut MultiFramebuffer<'_, R, T>, + from: &MultiFramebuffer<'_, T>, + to: &mut MultiFramebuffer<'_, T>, src: Rectangle, dst: Rectangle, filter: TextureFilter, @@ -2959,6 +3056,20 @@ where let MultiFramebufferInternal::Render(ref mut to_fb) = &mut to.0 else { unreachable!() }; + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let from_fb = unsafe { + std::mem::transmute::< + &<::Renderer as RendererSuper>::Framebuffer<'_>, + &<::Renderer as RendererSuper>::Framebuffer<'_>, + >(from_fb) + }; + // SAFETY: We know this is fine, because target can only be `None` (and thus this framebuffer be of variant `Render`), if R == T. + let to_fb = unsafe { + std::mem::transmute::< + &mut <::Renderer as RendererSuper>::Framebuffer<'_>, + &mut <::Renderer as RendererSuper>::Framebuffer<'_>, + >(to_fb) + }; self.render .renderer_mut() .blit(from_fb, to_fb, src, dst, filter)