diff --git a/include/platform/mir/graphics/platform.h b/include/platform/mir/graphics/platform.h index 4f8373bbc5..193e3988dc 100644 --- a/include/platform/mir/graphics/platform.h +++ b/include/platform/mir/graphics/platform.h @@ -387,7 +387,7 @@ class GBMDisplayAllocator : public DisplayAllocator virtual auto make_surface(DRMFormat format, std::span modifiers) -> std::unique_ptr = 0; }; -class DmaBufBuffer; +class DMABufBuffer; class DmaBufDisplayAllocator : public DisplayAllocator { @@ -396,7 +396,7 @@ class DmaBufDisplayAllocator : public DisplayAllocator { }; - virtual auto framebuffer_for(std::shared_ptr buffer) + virtual auto framebuffer_for(std::shared_ptr buffer) -> std::unique_ptr = 0; }; diff --git a/src/platforms/atomic-kms/server/kms/display_buffer.cpp b/src/platforms/atomic-kms/server/kms/display_buffer.cpp index 4c5c17777d..e188226466 100644 --- a/src/platforms/atomic-kms/server/kms/display_buffer.cpp +++ b/src/platforms/atomic-kms/server/kms/display_buffer.cpp @@ -37,10 +37,13 @@ #include #include #include +#include #include +#include #include #include +#include namespace mg = mir::graphics; namespace mga = mir::graphics::atomic; @@ -56,7 +59,8 @@ mga::DisplaySink::DisplaySink( std::vector> const& outputs, geom::Rectangle const& area, glm::mat2 const& transformation) - : gbm{std::move(gbm)}, + : DmaBufDisplayAllocator(drm_fd), + gbm{std::move(gbm)}, listener(listener), outputs(outputs), event_handler{std::move(event_handler)}, @@ -335,6 +339,78 @@ void mga::DisplaySink::set_next_image(std::unique_ptr content) } } +auto mga::DmaBufDisplayAllocator::framebuffer_for(std::shared_ptr buffer) -> std::unique_ptr +{ + auto plane_descriptors = buffer->planes(); + + assert(plane_descriptors.size() <= 4); + + auto width = buffer->size().width; + auto height = buffer->size().height; + auto pixel_format = buffer->format(); + + uint32_t bo_handles[4] = {0}; + uint32_t pitches[4] = {0}; + uint32_t offsets[4] = {0}; + + for (std::size_t i = 0; i < std::min(4zu, plane_descriptors.size()); i++) + { + bo_handles[i] = plane_descriptors[i].dma_buf; + pitches[i] = plane_descriptors[i].stride; + offsets[i] = plane_descriptors[i].offset; + } + + auto fb_id = std::shared_ptr{ + new uint32_t{0}, + [drm_fd = drm_fd()](uint32_t* fb_id) + { + if (*fb_id) + { + drmModeRmFB(drm_fd, *fb_id); + } + delete fb_id; + }}; + + int ret = drmModeAddFB2( + drm_fd(), + width.as_uint32_t(), + height.as_uint32_t(), + pixel_format, + bo_handles, + pitches, + offsets, + fb_id.get(), + 0); + + if (ret) + return {}; + + struct AtomicKmsFbHandle : public mg::FBHandle + { + AtomicKmsFbHandle(std::shared_ptr fb_handle, geometry::Size size) : + kms_fb_id{fb_handle}, + size_{size} + { + } + + virtual auto size() const -> geometry::Size override + { + return size_; + } + + virtual operator uint32_t() const override + { + return *kms_fb_id; + } + + private: + std::shared_ptr kms_fb_id; + geometry::Size size_; + }; + + return std::make_unique(fb_id, buffer->size()); +} + auto mga::DisplaySink::maybe_create_allocator(DisplayAllocator::Tag const& type_tag) -> DisplayAllocator* { @@ -354,5 +430,13 @@ auto mga::DisplaySink::maybe_create_allocator(DisplayAllocator::Tag const& type_ } return gbm_allocator.get(); } + if(dynamic_cast(&type_tag)) + { + if (!bypass_allocator) + { + bypass_allocator = std::make_shared(drm_fd()); + } + return bypass_allocator.get(); + } return nullptr; } diff --git a/src/platforms/atomic-kms/server/kms/display_sink.h b/src/platforms/atomic-kms/server/kms/display_sink.h index 7257ce5263..8f7ce8a2d3 100644 --- a/src/platforms/atomic-kms/server/kms/display_sink.h +++ b/src/platforms/atomic-kms/server/kms/display_sink.h @@ -26,6 +26,7 @@ #include "platform_common.h" #include "kms_framebuffer.h" +#include #include #include #include @@ -50,8 +51,28 @@ namespace atomic class Platform; class KMSOutput; -class DisplaySink : public graphics::DisplaySink, - public graphics::DisplaySyncGroup +class DmaBufDisplayAllocator : public graphics::DmaBufDisplayAllocator +{ + public: + DmaBufDisplayAllocator(mir::Fd drm_fd) : drm_fd_{drm_fd} + { + } + + virtual auto framebuffer_for(std::shared_ptr buffer) -> std::unique_ptr override; + + auto drm_fd() -> mir::Fd const + { + return drm_fd_; + } + + private: + mir::Fd const drm_fd_; +}; + +class DisplaySink : + public graphics::DisplaySink, + public graphics::DisplaySyncGroup, + public DmaBufDisplayAllocator { public: DisplaySink( @@ -103,6 +124,7 @@ class DisplaySink : public graphics::DisplaySink, std::shared_ptr const event_handler; + std::shared_ptr bypass_allocator; std::shared_ptr kms_allocator; std::unique_ptr gbm_allocator; diff --git a/src/platforms/gbm-kms/server/buffer_allocator.cpp b/src/platforms/gbm-kms/server/buffer_allocator.cpp index be849f4120..cbb7f7c315 100644 --- a/src/platforms/gbm-kms/server/buffer_allocator.cpp +++ b/src/platforms/gbm-kms/server/buffer_allocator.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -552,9 +553,35 @@ auto mgg::GLRenderingProvider::surface_for_sink( config); } -auto mgg::GLRenderingProvider::make_framebuffer_provider(DisplaySink& /*sink*/) +auto mgg::GLRenderingProvider::make_framebuffer_provider(DisplaySink& sink) -> std::unique_ptr { + if(auto* allocator = sink.acquire_compatible_allocator()) + { + struct FooFramebufferProvider: public FramebufferProvider + { + public: + FooFramebufferProvider(DmaBufDisplayAllocator* allocator) : allocator{allocator} + { + } + + auto buffer_to_framebuffer(std::shared_ptr buffer) -> std::unique_ptr override + { + if(auto dma_buf = std::dynamic_pointer_cast(buffer)) + { + return allocator->framebuffer_for(dma_buf); + } + + return {}; + } + + private: + DmaBufDisplayAllocator* allocator; + }; + + return std::make_unique(allocator); + } + // TODO: Make this not a null implementation, so bypass/overlays can work again class NullFramebufferProvider : public FramebufferProvider { diff --git a/src/server/compositor/default_display_buffer_compositor.cpp b/src/server/compositor/default_display_buffer_compositor.cpp index 84415efb62..cfffb43bb9 100644 --- a/src/server/compositor/default_display_buffer_compositor.cpp +++ b/src/server/compositor/default_display_buffer_compositor.cpp @@ -27,9 +27,13 @@ #include "mir/renderer/renderer.h" #include "occlusion.h" +#define MIR_LOG_COMPONENT "compositor" +#include "mir/log.h" + namespace mc = mir::compositor; namespace mg = mir::graphics; + mc::DefaultDisplayBufferCompositor::DefaultDisplayBufferCompositor( mg::DisplaySink& display_sink, graphics::GLRenderingProvider& gl_provider, @@ -110,11 +114,14 @@ bool mc::DefaultDisplayBufferCompositor::composite(mc::SceneElementSequence&& sc if (framebuffers.size() == renderable_list.size() && display_sink.overlay(framebuffers)) { + mir::log_debug("Bypass path\n"); report->renderables_in_frame(this, renderable_list); renderer->suspend(); } else { + mir::log_debug("composite path\n"); + renderer->set_output_transform(display_sink.transformation()); renderer->set_viewport(view_area); diff --git a/src/server/compositor/multi_threaded_compositor.cpp b/src/server/compositor/multi_threaded_compositor.cpp index 7c7d5960c1..6c6a075113 100644 --- a/src/server/compositor/multi_threaded_compositor.cpp +++ b/src/server/compositor/multi_threaded_compositor.cpp @@ -197,7 +197,7 @@ class CompositingFunctor void wait_until_stopped() { stop(); - if (stopped_future.wait_for(10s) != std::future_status::ready) + if (stopped_future.wait_for(10h) != std::future_status::ready) BOOST_THROW_EXCEPTION(std::runtime_error("Compositor thread failed to stop")); stopped_future.get();