diff --git a/include/platform/mir/graphics/display_buffer.h b/include/platform/mir/graphics/display_buffer.h index 8b7a1536020..fded042eae5 100644 --- a/include/platform/mir/graphics/display_buffer.h +++ b/include/platform/mir/graphics/display_buffer.h @@ -17,6 +17,7 @@ #ifndef MIR_GRAPHICS_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_DISPLAY_BUFFER_H_ +#include "mir/graphics/platform.h" #include #include #include @@ -61,9 +62,9 @@ class DisplayBuffer /** The size in pixels of the underlying display */ virtual auto pixel_size() const -> geometry::Size = 0; - /** This will render renderlist to the screen and post the result to the + /** This will render renderlist to the screen and post the result to the * screen if there is a hardware optimization that can be done. - * \param [in] renderlist + * \param [in] renderlist * The renderables that should appear on the screen if the hardware * is capable of optmizing that list somehow. If what you want * displayed on the screen cannot be represented by a RenderableList, @@ -98,8 +99,56 @@ class DisplayBuffer */ virtual glm::mat2 transformation() const = 0; - virtual auto display_provider() const -> std::shared_ptr = 0; + /** + * Attempt to acquire a platform-specific provider from this DisplayBuffer + * + * Any given platform is not guaranteed to implement any specific interface, + * and the set of supported interfaces may depend on the runtime environment. + * + * Since this may result in a runtime probe the call may be costly, and the + * result should be saved rather than re-acquiring an interface each time. + * + * \tparam Allocator + * \return On success: a non-null pointer to an Allocator implementation. + * The lifetime of this Allocator implementation is bound + * to that of the parent DisplayBuffer. + * On failure: nullptr + */ + template + auto acquire_allocator() -> Allocator* + { + static_assert( + std::is_convertible_v, + "Can only acquire a DisplayAllocator; Provider must implement DisplayAllocator"); + + if (auto const base_interface = maybe_create_allocator(typename Allocator::Tag{})) + { + if (auto const requested_interface = dynamic_cast(base_interface)) + { + return requested_interface; + } + BOOST_THROW_EXCEPTION((std::logic_error{ + "Implementation error! Platform returned object that does not support requested interface"})); + } + return nullptr; + } + protected: + /** + * Acquire a specific hardware interface + * + * This should perform any runtime checks necessary to verify the requested interface is + * expected to work and return a pointer to an implementation of that interface. + * + * \param type_tag [in] An instance of the Tag type for the requested interface. + * Implementations are expected to dynamic_cast<> this to + * discover the specific interface being requested. + * \return A pointer to an implementation of the DisplayAllocator-derived + * interface that corresponds to the most-derived type of tag_type. + */ + virtual auto maybe_create_allocator(DisplayAllocator::Tag const& type_tag) + -> DisplayAllocator* = 0; + DisplayBuffer() = default; DisplayBuffer(DisplayBuffer const& c) = delete; DisplayBuffer& operator=(DisplayBuffer const& c) = delete; diff --git a/include/platform/mir/graphics/platform.h b/include/platform/mir/graphics/platform.h index a0fe6450981..f13eba4a674 100644 --- a/include/platform/mir/graphics/platform.h +++ b/include/platform/mir/graphics/platform.h @@ -62,8 +62,6 @@ class DisplayConfigurationPolicy; class GraphicBufferAllocator; class GLConfig; -class DisplayInterfaceProvider; - namespace probe { /** @@ -130,9 +128,9 @@ class RenderingProvider }; /** - * Check how well this Renderer can support a particular display target - */ - virtual auto suitability_for_display(std::shared_ptr const& target) + * Check how well this Renderer can support a particular display target + */ + virtual auto suitability_for_display(DisplayBuffer& target) -> probe::Result = 0; /** @@ -141,7 +139,7 @@ class RenderingProvider virtual auto suitability_for_allocator(std::shared_ptr const& target) -> probe::Result = 0; - virtual auto make_framebuffer_provider(std::shared_ptr target) + virtual auto make_framebuffer_provider(DisplayBuffer& target) -> std::unique_ptr = 0; }; @@ -161,7 +159,7 @@ class GLRenderingProvider : public RenderingProvider virtual auto as_texture(std::shared_ptr buffer) -> std::shared_ptr = 0; virtual auto surface_for_output( - std::shared_ptr framebuffer_provider, + DisplayBuffer& target, geometry::Size size, GLConfig const& config) -> std::unique_ptr = 0; }; @@ -258,6 +256,19 @@ class DisplayProvider }; +class DisplayAllocator +{ +public: + class Tag + { + public: + Tag() = default; + virtual ~Tag() = default; + }; + + virtual ~DisplayAllocator() = default; +}; + class Framebuffer { public: @@ -270,13 +281,20 @@ class Framebuffer virtual auto size() const -> geometry::Size = 0; }; - class CPUAddressableDisplayProvider : public DisplayProvider { public: class Tag : public DisplayProvider::Tag { }; +}; + +class CPUAddressableDisplayAllocator : public DisplayAllocator +{ +public: + class Tag : public DisplayAllocator::Tag + { + }; class MappableFB : public Framebuffer, @@ -308,15 +326,28 @@ class GBMDisplayProvider : public DisplayProvider * the provided device is a Rendernode associated with the display hardware */ virtual auto is_same_device(mir::udev::Device const& render_device) const -> bool = 0; - + + /** + * Check if this DisplayBuffer is driven by this DisplayProvider + */ + virtual auto on_this_device(DisplayBuffer& target) const -> bool = 0; + /** * Get the GBM device for this display */ virtual auto gbm_device() const -> std::shared_ptr = 0; +}; + +class GBMDisplayAllocator : public DisplayAllocator +{ +public: + class Tag : public DisplayAllocator::Tag + { + }; - /** - * Formats supported for output - */ + /** + * Formats supported for output + */ virtual auto supported_formats() const -> std::vector = 0; /** @@ -335,7 +366,7 @@ class GBMDisplayProvider : public DisplayProvider /** * Commit the current EGL front buffer as a KMS-displayable Framebuffer * - * Like the underlying gbm_sufrace_lock_front_buffer GBM API, it is a this + * Like the underlying gbm_sufrace_lock_front_buffer GBM API, this * must be called after at least one call to eglSwapBuffers, and at most * once per eglSwapBuffers call. * @@ -351,10 +382,10 @@ class GBMDisplayProvider : public DisplayProvider class DmaBufBuffer; -class DmaBufDisplayProvider : public DisplayProvider +class DmaBufDisplayAllocator : public DisplayAllocator { public: - class Tag : public DisplayProvider::Tag + class Tag : public DisplayAllocator::Tag { }; @@ -374,6 +405,14 @@ class EGLStreamDisplayProvider : public DisplayProvider }; virtual auto get_egl_display() const -> EGLDisplay = 0; +}; + +class EGLStreamDisplayAllocator : public DisplayAllocator +{ +public: + class Tag : public DisplayAllocator::Tag + { + }; virtual auto claim_stream() -> EGLStreamKHR = 0; }; @@ -386,6 +425,14 @@ class GenericEGLDisplayProvider : public DisplayProvider }; virtual auto get_egl_display() -> EGLDisplay = 0; +}; + +class GenericEGLDisplayAllocator : public DisplayAllocator +{ +public: + class Tag : public DisplayAllocator::Tag + { + }; class EGLFramebuffer : public graphics::Framebuffer { @@ -398,14 +445,21 @@ class GenericEGLDisplayProvider : public DisplayProvider virtual auto alloc_framebuffer(GLConfig const& config, EGLContext share_context) -> std::unique_ptr = 0; }; -class DisplayInterfaceProvider : public std::enable_shared_from_this +class DisplayPlatform { public: - DisplayInterfaceProvider() = default; - virtual ~DisplayInterfaceProvider() = default; + DisplayPlatform() = default; + DisplayPlatform(DisplayPlatform const& p) = delete; + DisplayPlatform& operator=(DisplayPlatform const& p) = delete; + + virtual ~DisplayPlatform() = default; - DisplayInterfaceProvider(DisplayInterfaceProvider const&) = delete; - auto operator=(DisplayInterfaceProvider const&) -> DisplayInterfaceProvider& = delete; + /** + * Creates the display subsystem. + */ + virtual UniqueModulePtr create_display( + std::shared_ptr const& initial_conf_policy, + std::shared_ptr const& gl_config) = 0; /** * Attempt to acquire a platform-specific interface from this DisplayPlatform @@ -421,13 +475,13 @@ class DisplayInterfaceProvider : public std::enable_shared_from_this{nullptr} */ template - auto acquire_interface() -> std::shared_ptr + auto acquire_provider() -> std::shared_ptr { static_assert( std::is_convertible_v, "Can only acquire a Display interface; Interface must implement DisplayProvider"); - if (auto const base_interface = maybe_create_interface(typename Interface::Tag{})) + if (auto const base_interface = maybe_create_provider(typename Interface::Tag{})) { if (auto const requested_interface = std::dynamic_pointer_cast(base_interface)) { @@ -437,7 +491,7 @@ class DisplayInterfaceProvider : public std::enable_shared_from_this this to * discover the specific interface being requested. * \return A pointer to an implementation of the DisplayProvider-derived * interface that corresponds to the most-derived type of tag_type. */ - virtual auto maybe_create_interface(DisplayProvider::Tag const& type_tag) + virtual auto maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr = 0; }; -class DisplayPlatform : public std::enable_shared_from_this -{ -public: - DisplayPlatform() = default; - DisplayPlatform(DisplayPlatform const& p) = delete; - DisplayPlatform& operator=(DisplayPlatform const& p) = delete; - - virtual ~DisplayPlatform() = default; - - /** - * Creates the display subsystem. - */ - virtual UniqueModulePtr create_display( - std::shared_ptr const& initial_conf_policy, - std::shared_ptr const& gl_config) = 0; - - static auto interface_for(std::shared_ptr platform) - -> std::shared_ptr - { - return platform->interface_for(); - } -protected: - virtual auto interface_for() -> std::shared_ptr = 0; -}; - struct SupportedDevice { /** @@ -520,7 +545,7 @@ typedef mir::UniqueModulePtr(*CreateDisplayPlatf typedef mir::UniqueModulePtr(*CreateRenderPlatform)( mir::graphics::SupportedDevice const& device, - std::vector> const& displays, + std::vector> const& platforms, mir::options::Option const& options, mir::EmergencyCleanupRegistry& emergency_cleanup_registry); @@ -533,7 +558,7 @@ typedef std::vector(*PlatformProbe)( mir::options::ProgramOption const& options); typedef std::vector(*RenderProbe)( - std::span> const&, + std::span> const&, mir::ConsoleServices&, std::shared_ptr const&, mir::options::ProgramOption const&); @@ -574,7 +599,7 @@ mir::UniqueModulePtr create_display_platform( mir::UniqueModulePtr create_rendering_platform( mir::graphics::SupportedDevice const& device, - std::vector> const& displays, + std::vector> const& targets, mir::options::Option const& options, mir::EmergencyCleanupRegistry& emergency_cleanup_registry); @@ -597,7 +622,7 @@ auto probe_display_platform( mir::options::ProgramOption const& options) -> std::vector; auto probe_rendering_platform( - std::span> const& display_providers, + std::span> const& targets, mir::ConsoleServices& console, std::shared_ptr const& udev, mir::options::ProgramOption const& options) -> std::vector; diff --git a/src/platforms/common/server/cpu_addressable_fb.h b/src/platforms/common/server/cpu_addressable_fb.h index a836b51243f..eb105e58b38 100644 --- a/src/platforms/common/server/cpu_addressable_fb.h +++ b/src/platforms/common/server/cpu_addressable_fb.h @@ -24,7 +24,7 @@ namespace mir::graphics { -class CPUAddressableFB : public FBHandle, public CPUAddressableDisplayProvider::MappableFB +class CPUAddressableFB : public FBHandle, public CPUAddressableDisplayAllocator::MappableFB { public: CPUAddressableFB( diff --git a/src/platforms/common/server/cpu_copy_output_surface.cpp b/src/platforms/common/server/cpu_copy_output_surface.cpp index 5001f282304..57fd72cc990 100644 --- a/src/platforms/common/server/cpu_copy_output_surface.cpp +++ b/src/platforms/common/server/cpu_copy_output_surface.cpp @@ -95,7 +95,7 @@ auto create_current_context(EGLDisplay dpy, EGLContext share_ctx) return ctx; } -auto select_format_from(mg::CPUAddressableDisplayProvider const& provider) -> mg::DRMFormat +auto select_format_from(mg::CPUAddressableDisplayAllocator const& provider) -> mg::DRMFormat { std::optional best_format; for (auto const format : provider.supported_formats()) @@ -127,7 +127,7 @@ class mgc::CPUCopyOutputSurface::Impl Impl( EGLDisplay dpy, EGLContext share_ctx, - std::shared_ptr allocator, + mg::CPUAddressableDisplayAllocator& allocator, geom::Size size); void bind(); @@ -141,7 +141,7 @@ class mgc::CPUCopyOutputSurface::Impl auto layout() const -> Layout; private: - std::shared_ptr const allocator; + mg::CPUAddressableDisplayAllocator& allocator; EGLDisplay const dpy; EGLContext const ctx; geometry::Size const size_; @@ -153,9 +153,9 @@ class mgc::CPUCopyOutputSurface::Impl mgc::CPUCopyOutputSurface::CPUCopyOutputSurface( EGLDisplay dpy, EGLContext share_ctx, - std::shared_ptr allocator, + mg::CPUAddressableDisplayAllocator& allocator, geom::Size size) - : impl{std::make_unique(dpy, share_ctx, std::move(allocator), size)} + : impl{std::make_unique(dpy, share_ctx, allocator, size)} { } @@ -194,13 +194,13 @@ auto mgc::CPUCopyOutputSurface::layout() const -> Layout mgc::CPUCopyOutputSurface::Impl::Impl( EGLDisplay dpy, EGLContext share_ctx, - std::shared_ptr allocator, + mg::CPUAddressableDisplayAllocator& allocator, geom::Size size) - : allocator{std::move(allocator)}, + : allocator{allocator}, dpy{dpy}, ctx{create_current_context(dpy, share_ctx)}, size_{size}, - format{select_format_from(*this->allocator)} + format{select_format_from(allocator)} { glBindRenderbuffer(GL_RENDERBUFFER, colour_buffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, size_.width.as_int(), size_.height.as_int()); @@ -264,7 +264,7 @@ void mgc::CPUCopyOutputSurface::Impl::release_current() auto mgc::CPUCopyOutputSurface::Impl::commit() -> std::unique_ptr { - auto fb = allocator->alloc_fb(size_, format); + auto fb = allocator.alloc_fb(size_, format); glBindFramebuffer(GL_FRAMEBUFFER, fbo); { /* TODO: We can usefully put this *into* DRMFormat */ diff --git a/src/platforms/common/server/cpu_copy_output_surface.h b/src/platforms/common/server/cpu_copy_output_surface.h index fc38036b8af..4592bf59556 100644 --- a/src/platforms/common/server/cpu_copy_output_surface.h +++ b/src/platforms/common/server/cpu_copy_output_surface.h @@ -35,7 +35,7 @@ class CPUCopyOutputSurface : public gl::OutputSurface CPUCopyOutputSurface( EGLDisplay dpy, EGLContext share_ctx, - std::shared_ptr allocator, + CPUAddressableDisplayAllocator& allocator, geometry::Size size); ~CPUCopyOutputSurface() override; @@ -55,7 +55,6 @@ class CPUCopyOutputSurface : public gl::OutputSurface private: class Impl; std::unique_ptr const impl; - std::shared_ptr const allocator; }; } } \ No newline at end of file diff --git a/src/platforms/common/server/kms_cpu_addressable_display_provider.cpp b/src/platforms/common/server/kms_cpu_addressable_display_provider.cpp index e64c9f24603..c7973f4e717 100644 --- a/src/platforms/common/server/kms_cpu_addressable_display_provider.cpp +++ b/src/platforms/common/server/kms_cpu_addressable_display_provider.cpp @@ -39,31 +39,31 @@ auto drm_get_cap_checked(mir::Fd const& drm_fd, uint64_t cap) -> uint64_t namespace mg = mir::graphics; namespace geom = mir::geometry; -mg::kms::CPUAddressableDisplayProvider::CPUAddressableDisplayProvider(mir::Fd drm_fd) +mg::kms::CPUAddressableDisplayAllocator::CPUAddressableDisplayAllocator(mir::Fd drm_fd) : drm_fd{std::move(drm_fd)}, supports_modifiers{drm_get_cap_checked(this->drm_fd, DRM_CAP_ADDFB2_MODIFIERS) == 1} { } -auto mg::kms::CPUAddressableDisplayProvider::supported_formats() const +auto mg::kms::CPUAddressableDisplayAllocator::supported_formats() const -> std::vector { // TODO: Pull out of DRM info return {mg::DRMFormat{DRM_FORMAT_XRGB8888}, mg::DRMFormat{DRM_FORMAT_ARGB8888}}; } -auto mg::kms::CPUAddressableDisplayProvider::alloc_fb( +auto mg::kms::CPUAddressableDisplayAllocator::alloc_fb( geom::Size size, DRMFormat format) -> std::unique_ptr { return std::make_unique(drm_fd, supports_modifiers, format, size); } -auto mir::graphics::kms::CPUAddressableDisplayProvider::create_if_supported(mir::Fd const& drm_fd) --> std::shared_ptr +auto mir::graphics::kms::CPUAddressableDisplayAllocator::create_if_supported(mir::Fd const& drm_fd) +-> std::shared_ptr { if (drm_get_cap_checked(drm_fd, DRM_CAP_DUMB_BUFFER)) { - return std::shared_ptr(new CPUAddressableDisplayProvider{drm_fd}); + return std::shared_ptr(new CPUAddressableDisplayAllocator{drm_fd}); } else { diff --git a/src/platforms/common/server/kms_cpu_addressable_display_provider.h b/src/platforms/common/server/kms_cpu_addressable_display_provider.h index 26ec2428526..0d577a960d7 100644 --- a/src/platforms/common/server/kms_cpu_addressable_display_provider.h +++ b/src/platforms/common/server/kms_cpu_addressable_display_provider.h @@ -26,12 +26,12 @@ namespace graphics { namespace kms { -class CPUAddressableDisplayProvider : public graphics::CPUAddressableDisplayProvider +class CPUAddressableDisplayAllocator : public graphics::CPUAddressableDisplayAllocator { public: - /// Create an CPUAddressableDisplayProvider if and only if supported by the device + /// Create an CPUAddressableDisplayAllocator if and only if supported by the device /// \return the provider, or an empty pointer - static auto create_if_supported(mir::Fd const& drm_fd) -> std::shared_ptr; + static auto create_if_supported(mir::Fd const& drm_fd) -> std::shared_ptr; auto supported_formats() const -> std::vector override; @@ -40,7 +40,7 @@ class CPUAddressableDisplayProvider : public graphics::CPUAddressableDisplayProv -> std::unique_ptr override; private: - explicit CPUAddressableDisplayProvider(mir::Fd drm_fd); + explicit CPUAddressableDisplayAllocator(mir::Fd drm_fd); mir::Fd const drm_fd; bool const supports_modifiers; diff --git a/src/platforms/common/server/kms_framebuffer.h b/src/platforms/common/server/kms_framebuffer.h index 3bf50e84dea..9ca9ca8bf0e 100644 --- a/src/platforms/common/server/kms_framebuffer.h +++ b/src/platforms/common/server/kms_framebuffer.h @@ -27,7 +27,7 @@ class FBHandle : public Framebuffer { public: virtual ~FBHandle() = default; - + virtual operator uint32_t() const = 0; }; diff --git a/src/platforms/eglstream-kms/server/CMakeLists.txt b/src/platforms/eglstream-kms/server/CMakeLists.txt index 346f11c9775..3e5604e0cae 100644 --- a/src/platforms/eglstream-kms/server/CMakeLists.txt +++ b/src/platforms/eglstream-kms/server/CMakeLists.txt @@ -24,8 +24,6 @@ add_library(mirplatformgraphicseglstreamkmsobjects OBJECT drm_event_handler.h threaded_drm_event_handler.h threaded_drm_event_handler.cpp - eglstream_interface_provider.h - eglstream_interface_provider.cpp ) target_link_libraries(mirplatformgraphicseglstreamkmsobjects diff --git a/src/platforms/eglstream-kms/server/buffer_allocator.cpp b/src/platforms/eglstream-kms/server/buffer_allocator.cpp index f0f158356fa..93481b65d01 100644 --- a/src/platforms/eglstream-kms/server/buffer_allocator.cpp +++ b/src/platforms/eglstream-kms/server/buffer_allocator.cpp @@ -730,11 +730,11 @@ auto mir::graphics::eglstream::GLRenderingProvider::as_texture(std::shared_ptr target, + DisplayBuffer& target, geom::Size size, mg::GLConfig const& gl_config) -> std::unique_ptr { - if (auto stream_platform = target->acquire_interface()) + if (auto stream_platform = target.acquire_allocator()) { try { @@ -752,14 +752,14 @@ auto mge::GLRenderingProvider::surface_for_output( err.what()); } } - if (auto cpu_provider = target->acquire_interface()) + if (auto cpu_provider = target.acquire_allocator()) { auto fb_context = ctx->make_share_context(); fb_context->make_current(); return std::make_unique( dpy, static_cast(*ctx), - cpu_provider, + *cpu_provider, size); } BOOST_THROW_EXCEPTION((std::runtime_error{"DisplayInterfaceProvider does not support any viable output interface"})); @@ -777,21 +777,20 @@ auto mge::GLRenderingProvider::suitability_for_allocator(std::shared_ptr const& target) -> probe::Result +auto mge::GLRenderingProvider::suitability_for_display(DisplayBuffer& target) -> probe::Result { - if (target->acquire_interface()) + if (target.acquire_allocator()) { return probe::best; } - if (target->acquire_interface()) + if (target.acquire_allocator()) { return probe::supported; } return probe::unsupported; } -auto mge::GLRenderingProvider::make_framebuffer_provider(std::shared_ptr /*target*/) +auto mge::GLRenderingProvider::make_framebuffer_provider(DisplayBuffer& /*target*/) -> std::unique_ptr { // TODO: *Can* we provide overlay support? diff --git a/src/platforms/eglstream-kms/server/buffer_allocator.h b/src/platforms/eglstream-kms/server/buffer_allocator.h index 9eb80b2a311..a2102006ec4 100644 --- a/src/platforms/eglstream-kms/server/buffer_allocator.h +++ b/src/platforms/eglstream-kms/server/buffer_allocator.h @@ -102,12 +102,12 @@ class GLRenderingProvider : public graphics::GLRenderingProvider auto suitability_for_allocator(std::shared_ptr const& target) -> probe::Result override; - auto suitability_for_display(std::shared_ptr const& target) -> probe::Result override; + auto suitability_for_display(DisplayBuffer& target) -> probe::Result override; - auto make_framebuffer_provider(std::shared_ptr target) -> std::unique_ptr override; + auto make_framebuffer_provider(DisplayBuffer& target) -> std::unique_ptr override; auto surface_for_output( - std::shared_ptr provider, + DisplayBuffer& target, geometry::Size size, GLConfig const& gl_config) -> std::unique_ptr override; private: diff --git a/src/platforms/eglstream-kms/server/display.cpp b/src/platforms/eglstream-kms/server/display.cpp index 1e89d5fb9ac..67c99db910c 100644 --- a/src/platforms/eglstream-kms/server/display.cpp +++ b/src/platforms/eglstream-kms/server/display.cpp @@ -21,6 +21,7 @@ #include "display.h" #include "egl_output.h" #include "kms_framebuffer.h" +#include "kms_cpu_addressable_display_provider.h" #include "kms-utils/drm_mode_resources.h" #include "mir/graphics/platform.h" @@ -123,11 +124,11 @@ EGLContext create_context(EGLDisplay display, EGLConfig config, EGLContext share class DisplayBuffer : public mg::DisplaySyncGroup, - public mg::DisplayBuffer + public mg::DisplayBuffer, + public mg::EGLStreamDisplayAllocator { public: DisplayBuffer( - std::shared_ptr owner, mir::Fd drm_node, EGLDisplay dpy, EGLContext ctx, @@ -135,8 +136,7 @@ class DisplayBuffer std::shared_ptr event_handler, std::shared_ptr output, std::shared_ptr display_report) - : owner{std::move(owner)}, - dpy{dpy}, + : dpy{dpy}, ctx{create_context(dpy, config, ctx)}, output{output}, drm_node{std::move(drm_node)}, @@ -352,9 +352,23 @@ class DisplayBuffer return std::chrono::milliseconds{0}; } - auto display_provider() const -> std::shared_ptr override + auto claim_stream() -> EGLStreamKHR override { - return std::make_shared(*owner, output_stream); + return output_stream; + } + + auto maybe_create_allocator(mg::DisplayAllocator::Tag const& type_tag) -> mg::DisplayAllocator* override + { + if (dynamic_cast(&type_tag)) + { + return this; + } + if (dynamic_cast(&type_tag)) + { + kms_allocator = mg::kms::CPUAddressableDisplayAllocator::create_if_supported(drm_node); + return kms_allocator.get(); + } + return nullptr; } void set_next_image(std::unique_ptr content) override @@ -410,7 +424,6 @@ class DisplayBuffer } private: - std::shared_ptr const owner; EGLDisplay dpy; EGLContext ctx; std::shared_ptr output; @@ -420,6 +433,7 @@ class DisplayBuffer std::future pending_flip; mg::EGLExtensions::LazyDisplayExtensions nv_stream; std::shared_ptr const display_report; + std::shared_ptr kms_allocator; /// Used only for the KMS case std::shared_ptr next_swap{nullptr}; @@ -441,14 +455,12 @@ mge::KMSDisplayConfiguration create_display_configuration( } mge::Display::Display( - std::shared_ptr provider, mir::Fd drm_node, EGLDisplay display, std::shared_ptr const& configuration_policy, GLConfig const& gl_conf, std::shared_ptr display_report) - : provider{std::move(provider)}, - drm_node{drm_node}, + : drm_node{drm_node}, display{display}, config{choose_config(display, gl_conf)}, context{create_context(display, config)}, @@ -498,7 +510,6 @@ void mge::Display::configure(DisplayConfiguration const& conf) output->configure(output->current_mode_index); active_sync_groups.emplace_back( std::make_unique<::DisplayBuffer>( - provider, drm_node, display, context, diff --git a/src/platforms/eglstream-kms/server/display.h b/src/platforms/eglstream-kms/server/display.h index b8ec32579d9..cecde0734a5 100644 --- a/src/platforms/eglstream-kms/server/display.h +++ b/src/platforms/eglstream-kms/server/display.h @@ -17,8 +17,6 @@ #ifndef MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_ #define MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_ -#include "eglstream_interface_provider.h" - #include "mir/graphics/display.h" #include "kms_display_configuration.h" #include "mir/fd.h" @@ -42,7 +40,6 @@ class Display : public mir::graphics::Display { public: Display( - std::shared_ptr provider, mir::Fd drm_node, EGLDisplay display, std::shared_ptr const& configuration_policy, @@ -67,7 +64,6 @@ class Display : public mir::graphics::Display std::shared_ptr create_hardware_cursor() override; private: - std::shared_ptr const provider; mir::Fd const drm_node; EGLDisplay display; EGLConfig config; diff --git a/src/platforms/eglstream-kms/server/eglstream_interface_provider.cpp b/src/platforms/eglstream-kms/server/eglstream_interface_provider.cpp deleted file mode 100644 index 7d2c3e0b7d4..00000000000 --- a/src/platforms/eglstream-kms/server/eglstream_interface_provider.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "eglstream_interface_provider.h" -#include "mir/graphics/platform.h" -#include "kms_cpu_addressable_display_provider.h" - -#include -#include - -#include - -namespace mg = mir::graphics; - -namespace -{ -class DisplayProviderImpl : public mg::EGLStreamDisplayProvider -{ -public: - DisplayProviderImpl(EGLDisplay dpy, std::optional stream); - - auto get_egl_display() const -> EGLDisplay override; - - auto claim_stream() -> EGLStreamKHR override; -private: - EGLDisplay dpy; - std::optional stream; -}; - -DisplayProviderImpl::DisplayProviderImpl(EGLDisplay dpy, std::optional stream) - : dpy{dpy}, - stream{stream} -{ -} - -auto DisplayProviderImpl::get_egl_display() const -> EGLDisplay -{ - return dpy; -} - -auto DisplayProviderImpl::claim_stream() -> EGLStreamKHR -{ - if (stream) - { - return *std::exchange(stream, std::nullopt); - } - BOOST_THROW_EXCEPTION((std::logic_error{"No EGLStream to claim (either incorrect object, or stream already claimed)"})); -} -} - -mg::eglstream::InterfaceProvider::InterfaceProvider(EGLDisplay dpy, mir::Fd drm_fd) - : dpy{dpy}, - drm_fd{drm_fd} -{ -} - -mg::eglstream::InterfaceProvider::InterfaceProvider(InterfaceProvider const& from, EGLStreamKHR with_stream) - : dpy{from.dpy}, - stream{with_stream}, - drm_fd{from.drm_fd} -{ -} - -auto mg::eglstream::InterfaceProvider::maybe_create_interface(DisplayProvider::Tag const& tag) - -> std::shared_ptr -{ - if (dynamic_cast(&tag)) - { - return std::make_shared(dpy, stream); - } - if (dynamic_cast(&tag)) - { - return mg::kms::CPUAddressableDisplayProvider::create_if_supported(drm_fd); - } - return nullptr; -} diff --git a/src/platforms/eglstream-kms/server/platform.cpp b/src/platforms/eglstream-kms/server/platform.cpp index d82f74ce761..482aca9835b 100644 --- a/src/platforms/eglstream-kms/server/platform.cpp +++ b/src/platforms/eglstream-kms/server/platform.cpp @@ -21,7 +21,7 @@ #include "display.h" #include "mir/graphics/platform.h" #include "utils.h" -#include "eglstream_interface_provider.h" +#include "kms_cpu_addressable_display_provider.h" #include "one_shot_device_observer.h" @@ -244,8 +244,6 @@ mge::DisplayPlatform::DisplayPlatform( "Wanted 1.4, got " + std::to_string(std::get<0>(egl_version)) + "." + std::to_string(std::get<1>(egl_version))})); } - - provider = std::make_shared(display, drm_node); } mge::DisplayPlatform::~DisplayPlatform() @@ -262,7 +260,6 @@ auto mge::DisplayPlatform::create_display( -> UniqueModulePtr { return mir::make_module_ptr( - provider, drm_node, display, configuration_policy, @@ -270,7 +267,36 @@ auto mge::DisplayPlatform::create_display( display_report); } -auto mge::DisplayPlatform::interface_for() -> std::shared_ptr +namespace +{ +class StreamProvider : public mg::EGLStreamDisplayProvider { - return provider; +public: + explicit StreamProvider(EGLDisplay dpy) + : dpy{dpy} + { + } + + auto get_egl_display() const -> EGLDisplay override + { + return dpy; + } + +private: + EGLDisplay const dpy; +}; +} + +auto mge::DisplayPlatform::maybe_create_provider(DisplayProvider::Tag const& type_tag) + -> std::shared_ptr +{ + if (dynamic_cast(&type_tag)) + { + return std::make_shared(display); + } + if (dynamic_cast(&type_tag)) + { + return std::make_shared(); + } + return nullptr; } diff --git a/src/platforms/eglstream-kms/server/platform.h b/src/platforms/eglstream-kms/server/platform.h index 1eee5f51cf1..ca17d127dc6 100644 --- a/src/platforms/eglstream-kms/server/platform.h +++ b/src/platforms/eglstream-kms/server/platform.h @@ -38,8 +38,6 @@ namespace graphics { namespace eglstream { -class InterfaceProvider; - class RenderingPlatform : public graphics::RenderingPlatform { public: @@ -73,11 +71,10 @@ class DisplayPlatform : public graphics::DisplayPlatform ->UniqueModulePtr override; private: - auto interface_for() -> std::shared_ptr override; + auto maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr override; std::unique_ptr drm_device; EGLDisplay display; - std::shared_ptr provider; mir::Fd drm_node; std::shared_ptr const display_report; }; diff --git a/src/platforms/eglstream-kms/server/platform_symbols.cpp b/src/platforms/eglstream-kms/server/platform_symbols.cpp index c9ac198e100..8b30182e57e 100644 --- a/src/platforms/eglstream-kms/server/platform_symbols.cpp +++ b/src/platforms/eglstream-kms/server/platform_symbols.cpp @@ -49,7 +49,7 @@ namespace mge = mir::graphics::eglstream; auto create_rendering_platform( mg::SupportedDevice const& device, - std::vector> const& /*displays*/, + std::vector> const& /*displays*/, mo::Option const&, mir::EmergencyCleanupRegistry&) -> mir::UniqueModulePtr { @@ -91,7 +91,7 @@ void add_graphics_platform_options(boost::program_options::options_description& } auto probe_rendering_platform( - std::span> const& displays, + std::span> const& displays, mir::ConsoleServices& /*console*/, std::shared_ptr const& udev, mo::ProgramOption const& /*options*/) -> std::vector @@ -103,14 +103,14 @@ auto probe_rendering_platform( std::vector> eglstream_providers; for (auto const& display_provider : displays) { - if (auto provider = display_provider->acquire_interface()) + if (auto provider = display_provider->acquire_provider()) { // We can optimally drive an EGLStream display mir::log_debug("EGLStream-capable display found"); maximum_suitability = mg::probe::best; eglstream_providers.push_back(provider); } - if (display_provider->acquire_interface()) + if (display_provider->acquire_provider()) { /* We *can* support this output, but with slower buffer copies * If another platform supports this device better, let it. diff --git a/src/platforms/gbm-kms/server/CMakeLists.txt b/src/platforms/gbm-kms/server/CMakeLists.txt index 3122c903661..edc88ce2e42 100644 --- a/src/platforms/gbm-kms/server/CMakeLists.txt +++ b/src/platforms/gbm-kms/server/CMakeLists.txt @@ -8,6 +8,8 @@ add_library( buffer_allocator.h surfaceless_egl_context.h surfaceless_egl_context.cpp + gbm_display_allocator.h + gbm_display_allocator.cpp ) target_include_directories( diff --git a/src/platforms/gbm-kms/server/buffer_allocator.cpp b/src/platforms/gbm-kms/server/buffer_allocator.cpp index ee6b2b59e25..73f26644aed 100644 --- a/src/platforms/gbm-kms/server/buffer_allocator.cpp +++ b/src/platforms/gbm-kms/server/buffer_allocator.cpp @@ -262,7 +262,7 @@ class GBMOutputSurface : public mg::gl::OutputSurface EGLDisplay dpy, EGLContext share_context, mg::GLConfig const& config, - mg::GBMDisplayProvider& display, + mg::GBMDisplayAllocator& display, mg::DRMFormat format, mir::geometry::Size size) : GBMOutputSurface( @@ -386,9 +386,9 @@ class GBMOutputSurface : public mg::gl::OutputSurface EGLContext share_context, mg::DRMFormat format, mg::GLConfig const& config, - mg::GBMDisplayProvider& display, + mg::GBMDisplayAllocator& allocator, mir::geometry::Size size) - -> std::tuple, EGLContext, EGLSurface> + -> std::tuple, EGLContext, EGLSurface> { mg::EGLExtensions::PlatformBaseEXT egl_ext; @@ -424,9 +424,9 @@ class GBMOutputSurface : public mg::gl::OutputSurface format.name()})); }(); - auto modifiers = display.modifiers_for_format(resolved_format); + auto modifiers = allocator.modifiers_for_format(resolved_format); - auto surf = display.make_surface(size, resolved_format, modifiers); + auto surf = allocator.make_surface(size, resolved_format, modifiers); auto egl_surf = egl_ext.eglCreatePlatformWindowSurface( dpy, @@ -451,14 +451,13 @@ class GBMOutputSurface : public mg::gl::OutputSurface BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } - return std::make_tuple(std::move(surf), egl_ctx, egl_surf); } GBMOutputSurface( geom::Size size, EGLDisplay dpy, - std::tuple, EGLContext, EGLSurface> renderables) + std::tuple, EGLContext, EGLSurface> renderables) : size_{size}, surface{std::move(std::get<0>(renderables))}, egl_surf{std::get<2>(renderables)}, @@ -468,7 +467,7 @@ class GBMOutputSurface : public mg::gl::OutputSurface } geom::Size const size_; - std::unique_ptr const surface; + std::unique_ptr const surface; EGLSurface const egl_surf; EGLDisplay const dpy; EGLContext const ctx; @@ -488,23 +487,20 @@ auto mgg::GLRenderingProvider::suitability_for_allocator( } auto mgg::GLRenderingProvider::suitability_for_display( - std::shared_ptr const& target) -> probe::Result + DisplayBuffer& target) -> probe::Result { if (bound_display) { - if (auto gbm_provider = target->acquire_interface()) + if (bound_display->on_this_device(target)) { - if (bound_display->gbm_device() == gbm_provider->gbm_device()) - { - /* We're rendering on the same device as display; - * it doesn't get better than this! - */ - return probe::best; - } - } + /* We're rendering on the same device as display; + * it doesn't get better than this! + */ + return probe::best; + } } - if (target->acquire_interface()) + if (target.acquire_allocator()) { // We *can* render to CPU buffers, but if anyone can do better, let them. return probe::supported; @@ -514,37 +510,37 @@ auto mgg::GLRenderingProvider::suitability_for_display( } auto mgg::GLRenderingProvider::surface_for_output( - std::shared_ptr target, + DisplayBuffer& target, geom::Size size, GLConfig const& config) -> std::unique_ptr { if (bound_display) { - if (auto gbm_provider = target->acquire_interface()) + if (auto gbm_allocator = target.acquire_allocator()) { - if (bound_display->gbm_device() == gbm_provider->gbm_device()) + if (bound_display->on_this_device(target)) { return std::make_unique( dpy, ctx, config, - *bound_display, + *gbm_allocator, DRMFormat{DRM_FORMAT_XRGB8888}, size); } - } + } } - auto cpu_provider = target->acquire_interface(); - + auto cpu_allocator = target.acquire_allocator(); + return std::make_unique( dpy, ctx, - std::move(cpu_provider), + *cpu_allocator, size); } -auto mgg::GLRenderingProvider::make_framebuffer_provider(std::shared_ptr /*target*/) +auto mgg::GLRenderingProvider::make_framebuffer_provider(DisplayBuffer& /*target*/) -> std::unique_ptr { // TODO: Make this not a null implementation, so bypass/overlays can work again diff --git a/src/platforms/gbm-kms/server/buffer_allocator.h b/src/platforms/gbm-kms/server/buffer_allocator.h index 9303e7b2c22..8c8b497c9a5 100644 --- a/src/platforms/gbm-kms/server/buffer_allocator.h +++ b/src/platforms/gbm-kms/server/buffer_allocator.h @@ -95,17 +95,17 @@ class GLRenderingProvider : public graphics::GLRenderingProvider EGLDisplay dpy, EGLContext ctx); - auto make_framebuffer_provider(std::shared_ptr target) + auto make_framebuffer_provider(DisplayBuffer& target) -> std::unique_ptr override; auto as_texture(std::shared_ptr buffer) -> std::shared_ptr override; auto suitability_for_allocator(std::shared_ptr const& target) -> probe::Result override; - auto suitability_for_display(std::shared_ptr const& target) -> probe::Result override; + auto suitability_for_display(DisplayBuffer& target) -> probe::Result override; auto surface_for_output( - std::shared_ptr framebuffer_provider, + DisplayBuffer& target, geometry::Size size, GLConfig const& config) -> std::unique_ptr override; diff --git a/src/platforms/gbm-kms/server/gbm_display_allocator.cpp b/src/platforms/gbm-kms/server/gbm_display_allocator.cpp new file mode 100644 index 00000000000..71e21624691 --- /dev/null +++ b/src/platforms/gbm-kms/server/gbm_display_allocator.cpp @@ -0,0 +1,213 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2 or 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "gbm_display_allocator.h" +#include "kms_framebuffer.h" + +#include +#include +#include + +namespace mg = mir::graphics; +namespace mgg = mir::graphics::gbm; +namespace geom = mir::geometry; + +mgg::GBMDisplayAllocator::GBMDisplayAllocator(mir::Fd drm_fd, std::shared_ptr gbm) + : fd{std::move(drm_fd)}, + gbm{std::move(gbm)} +{ +} + +auto mgg::GBMDisplayAllocator::supported_formats() const -> std::vector +{ + // TODO: Pull out of KMS plane info + return { DRMFormat{DRM_FORMAT_XRGB8888}, DRMFormat{DRM_FORMAT_ARGB8888}}; +} + +auto mgg::GBMDisplayAllocator::modifiers_for_format(DRMFormat /*format*/) const -> std::vector +{ + // TODO: Pull out off KMS plane info + return {}; +} + +namespace +{ +using LockedFrontBuffer = std::unique_ptr>; + +class GBMBoFramebuffer : public mg::FBHandle +{ +public: + static auto framebuffer_for_frontbuffer(mir::Fd const& drm_fd, LockedFrontBuffer bo) -> std::unique_ptr + { + if (auto cached_fb = static_cast*>(gbm_bo_get_user_data(bo.get()))) + { + return std::unique_ptr{new GBMBoFramebuffer{std::move(bo), *cached_fb}}; + } + + auto fb_id = new std::shared_ptr{ + new uint32_t{0}, + [drm_fd](uint32_t* fb_id) + { + if (*fb_id) + { + drmModeRmFB(drm_fd, *fb_id); + } + delete fb_id; + }}; + uint32_t handles[4] = {gbm_bo_get_handle(bo.get()).u32, 0, 0, 0}; + uint32_t strides[4] = {gbm_bo_get_stride(bo.get()), 0, 0, 0}; + uint32_t offsets[4] = {gbm_bo_get_offset(bo.get(), 0), 0, 0, 0}; + + auto format = gbm_bo_get_format(bo.get()); + + auto const width = gbm_bo_get_width(bo.get()); + auto const height = gbm_bo_get_height(bo.get()); + + /* Create a KMS FB object with the gbm_bo attached to it. */ + auto ret = drmModeAddFB2(drm_fd, width, height, format, + handles, strides, offsets, fb_id->get(), 0); + if (ret) + return nullptr; + + gbm_bo_set_user_data(bo.get(), fb_id, [](gbm_bo*, void* fb_ptr) { delete static_cast*>(fb_ptr); }); + + return std::unique_ptr{new GBMBoFramebuffer{std::move(bo), *fb_id}}; + } + + operator uint32_t() const override + { + return *fb_id; + } + + auto size() const -> geom::Size override + { + return + geom::Size{ + gbm_bo_get_width(bo.get()), + gbm_bo_get_height(bo.get())}; + } +private: + GBMBoFramebuffer(LockedFrontBuffer bo, std::shared_ptr fb) + : bo{std::move(bo)}, + fb_id{std::move(fb)} + { + } + + LockedFrontBuffer const bo; + std::shared_ptr const fb_id; +}; + +namespace +{ +auto create_gbm_surface(gbm_device* gbm, geom::Size size, mg::DRMFormat format, std::span modifiers) + -> std::shared_ptr +{ + auto const surface = + [&]() + { + if (modifiers.empty()) + { + // If we have no no modifiers don't use the with-modifiers creation path. + auto foo = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT; + return gbm_surface_create( + gbm, + size.width.as_uint32_t(), size.height.as_uint32_t(), + format, + foo); + } + else + { + return gbm_surface_create_with_modifiers2( + gbm, + size.width.as_uint32_t(), size.height.as_uint32_t(), + format, + modifiers.data(), + modifiers.size(), + GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); + } + }(); + + if (!surface) + { + BOOST_THROW_EXCEPTION(( + std::system_error{ + errno, + std::system_category(), + "Failed to create GBM surface"})); + + } + return std::shared_ptr{ + surface, + [](auto surface) { gbm_surface_destroy(surface); }}; +} +} + +class GBMSurfaceImpl : public mgg::GBMDisplayAllocator::GBMSurface +{ +public: + GBMSurfaceImpl(mir::Fd drm_fd, gbm_device* gbm, geom::Size size, mg::DRMFormat const format, std::span modifiers) + : drm_fd{std::move(drm_fd)}, + surface{create_gbm_surface(gbm, size, format, modifiers)} + { + } + + GBMSurfaceImpl(GBMSurfaceImpl const&) = delete; + auto operator=(GBMSurfaceImpl const&) -> GBMSurfaceImpl const& = delete; + + operator gbm_surface*() const override + { + return surface.get(); + } + + auto claim_framebuffer() -> std::unique_ptr override + { + if (!gbm_surface_has_free_buffers(surface.get())) + { + BOOST_THROW_EXCEPTION(( + std::system_error{ + EBUSY, + std::system_category(), + "Too many buffers consumed from GBM surface"})); + } + + LockedFrontBuffer bo{ + gbm_surface_lock_front_buffer(surface.get()), + [shared_surface = surface](gbm_bo* bo) { gbm_surface_release_buffer(shared_surface.get(), bo); }}; + + if (!bo) + { + BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to acquire GBM front buffer"})); + } + + auto fb = GBMBoFramebuffer::framebuffer_for_frontbuffer(drm_fd, std::move(bo)); + if (!fb) + { + BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to make DRM FB"})); + } + return fb; + } +private: + mir::Fd const drm_fd; + std::shared_ptr const surface; +}; +} + +auto mgg::GBMDisplayAllocator::make_surface(geom::Size size, DRMFormat format, std::span modifiers) + -> std::unique_ptr +{ + return std::make_unique(fd, gbm.get(), std::move(size), format, modifiers); +} + diff --git a/src/platforms/eglstream-kms/server/eglstream_interface_provider.h b/src/platforms/gbm-kms/server/gbm_display_allocator.h similarity index 54% rename from src/platforms/eglstream-kms/server/eglstream_interface_provider.h rename to src/platforms/gbm-kms/server/gbm_display_allocator.h index 8669fd5d268..4871ae24b20 100644 --- a/src/platforms/eglstream-kms/server/eglstream_interface_provider.h +++ b/src/platforms/gbm-kms/server/gbm_display_allocator.h @@ -14,33 +14,23 @@ * along with this program. If not, see . */ -#ifndef MIR_GRAPHICS_EGLSTREAM_INTERFACE_PROVIDER_H_ -#define MIR_GRAPHICS_EGLSTREAM_INTERFACE_PROVIDER_H_ - #include "mir/graphics/platform.h" #include "mir/fd.h" -#include - -namespace mir::graphics::eglstream +namespace mir::graphics::gbm { -class InterfaceProvider : public DisplayInterfaceProvider +class GBMDisplayAllocator : public graphics::GBMDisplayAllocator { public: - InterfaceProvider(EGLDisplay dpy, mir::Fd drm_fd); - InterfaceProvider(InterfaceProvider const& from, EGLStreamKHR with_stream); + GBMDisplayAllocator(mir::Fd drm_fd, std::shared_ptr gbm); + + auto supported_formats() const -> std::vector override; -protected: - auto maybe_create_interface(DisplayProvider::Tag const& tag) - -> std::shared_ptr override; + auto modifiers_for_format(DRMFormat format) const -> std::vector override; + auto make_surface(geometry::Size size, DRMFormat format, std::span modifier) -> std::unique_ptr override; private: - EGLDisplay dpy; - std::optional stream; - mir::Fd drm_fd; + mir::Fd const fd; + std::shared_ptr const gbm; }; - -; } - -#endif // MIR_GRAPHICS_EGLSTREAM_INTERFACE_PROVIDER_H_ diff --git a/src/platforms/gbm-kms/server/kms/display.cpp b/src/platforms/gbm-kms/server/kms/display.cpp index 12a445c3cf4..c22a355b03a 100644 --- a/src/platforms/gbm-kms/server/kms/display.cpp +++ b/src/platforms/gbm-kms/server/kms/display.cpp @@ -143,13 +143,13 @@ void log_drm_details(mir::Fd const& drm_fd) } mgg::Display::Display( - std::shared_ptr parent, mir::Fd drm_fd, + std::shared_ptr gbm, mgg::BypassOption bypass_option, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& listener) - : owner{std::move(parent)}, - drm_fd{std::move(drm_fd)}, + : drm_fd{std::move(drm_fd)}, + gbm{std::move(gbm)}, listener(listener), monitor(mir::udev::Context()), output_container{ @@ -421,8 +421,8 @@ void mgg::Display::configure_locked( else { auto db = std::make_unique( - owner, drm_fd, + gbm, bypass_option, listener, kms_outputs, @@ -467,7 +467,7 @@ auto gbm_create_device_checked(mir::Fd fd) -> std::shared_ptr gbm_device_destroy(device); } } - }; + }; } } @@ -478,6 +478,15 @@ mgg::GBMDisplayProvider::GBMDisplayProvider( { } +auto mgg::GBMDisplayProvider::on_this_device(mg::DisplayBuffer& target) const -> bool +{ + if (auto gbm_display_buffer = dynamic_cast(&target)) + { + return gbm_display_buffer->gbm_device() == gbm; + } + return false; +} + auto mgg::GBMDisplayProvider::gbm_device() const -> std::shared_ptr { return gbm; @@ -497,12 +506,12 @@ auto mgg::GBMDisplayProvider::is_same_device(mir::udev::Device const& render_dev } } }; - + std::unique_ptr primary_node{drmGetPrimaryDeviceNameFromFd(fd)}; std::unique_ptr render_node{drmGetRenderDeviceNameFromFd(fd)}; - + mir::log_debug("Checking whether %s is the same device as (%s, %s)...", render_device.devnode(), primary_node.get(), render_node.get()); - + if (primary_node) { if (strcmp(primary_node.get(), render_device.devnode()) == 0) @@ -519,13 +528,13 @@ auto mgg::GBMDisplayProvider::is_same_device(mir::udev::Device const& render_dev return true; } } - + mir::log_debug("\t...nope."); - + return false; #else drmDevicePtr us{nullptr}, them{nullptr}; - + drmGetDeviceFromDevId(render_device.devno(), 0, &them); drmGetDevice2(fd, 0, &us); @@ -533,187 +542,7 @@ auto mgg::GBMDisplayProvider::is_same_device(mir::udev::Device const& render_dev drmDeviceFree(us); drmDeviceFree(them); - + return result; #endif } - -auto mgg::GBMDisplayProvider::supported_formats() const -> std::vector -{ - // TODO: Pull out of KMS plane info - return { DRMFormat{DRM_FORMAT_XRGB8888}, DRMFormat{DRM_FORMAT_ARGB8888}}; -} - -auto mgg::GBMDisplayProvider::modifiers_for_format(DRMFormat /*format*/) const -> std::vector -{ - // TODO: Pull out off KMS plane info - return {}; -} - -namespace -{ -using LockedFrontBuffer = std::unique_ptr>; - -class GBMBoFramebuffer : public mg::FBHandle -{ -public: - static auto framebuffer_for_frontbuffer(mir::Fd const& drm_fd, LockedFrontBuffer bo) -> std::unique_ptr - { - if (auto cached_fb = static_cast*>(gbm_bo_get_user_data(bo.get()))) - { - return std::unique_ptr{new GBMBoFramebuffer{std::move(bo), *cached_fb}}; - } - - auto fb_id = new std::shared_ptr{ - new uint32_t{0}, - [drm_fd](uint32_t* fb_id) - { - if (*fb_id) - { - drmModeRmFB(drm_fd, *fb_id); - } - delete fb_id; - }}; - uint32_t handles[4] = {gbm_bo_get_handle(bo.get()).u32, 0, 0, 0}; - uint32_t strides[4] = {gbm_bo_get_stride(bo.get()), 0, 0, 0}; - uint32_t offsets[4] = {gbm_bo_get_offset(bo.get(), 0), 0, 0, 0}; - - auto format = gbm_bo_get_format(bo.get()); - - auto const width = gbm_bo_get_width(bo.get()); - auto const height = gbm_bo_get_height(bo.get()); - - /* Create a KMS FB object with the gbm_bo attached to it. */ - auto ret = drmModeAddFB2(drm_fd, width, height, format, - handles, strides, offsets, fb_id->get(), 0); - if (ret) - return nullptr; - - gbm_bo_set_user_data(bo.get(), fb_id, [](gbm_bo*, void* fb_ptr) { delete static_cast*>(fb_ptr); }); - - return std::unique_ptr{new GBMBoFramebuffer{std::move(bo), *fb_id}}; - } - - operator uint32_t() const override - { - return *fb_id; - } - - auto size() const -> geom::Size override - { - return - geom::Size{ - gbm_bo_get_width(bo.get()), - gbm_bo_get_height(bo.get())}; - } -private: - GBMBoFramebuffer(LockedFrontBuffer bo, std::shared_ptr fb) - : bo{std::move(bo)}, - fb_id{std::move(fb)} - { - } - - LockedFrontBuffer const bo; - std::shared_ptr const fb_id; -}; - -namespace -{ -auto create_gbm_surface(gbm_device* gbm, geom::Size size, mg::DRMFormat format, std::span modifiers) - -> std::shared_ptr -{ - auto const surface = - [&]() - { - if (modifiers.empty()) - { - // If we have no no modifiers don't use the with-modifiers creation path. - auto foo = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT; - return gbm_surface_create( - gbm, - size.width.as_uint32_t(), size.height.as_uint32_t(), - format, - foo); - } - else - { - return gbm_surface_create_with_modifiers2( - gbm, - size.width.as_uint32_t(), size.height.as_uint32_t(), - format, - modifiers.data(), - modifiers.size(), - GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); - } - }(); - - if (!surface) - { - BOOST_THROW_EXCEPTION(( - std::system_error{ - errno, - std::system_category(), - "Failed to create GBM surface"})); - - } - return std::shared_ptr{ - surface, - [](auto surface) { gbm_surface_destroy(surface); }}; -} -} - -class GBMSurfaceImpl : public mgg::GBMDisplayProvider::GBMSurface -{ -public: - GBMSurfaceImpl(mir::Fd drm_fd, gbm_device* gbm, geom::Size size, mg::DRMFormat const format, std::span modifiers) - : drm_fd{std::move(drm_fd)}, - surface{create_gbm_surface(gbm, size, format, modifiers)} - { - } - - GBMSurfaceImpl(GBMSurfaceImpl const&) = delete; - auto operator=(GBMSurfaceImpl const&) -> GBMSurfaceImpl const& = delete; - - operator gbm_surface*() const override - { - return surface.get(); - } - - auto claim_framebuffer() -> std::unique_ptr override - { - if (!gbm_surface_has_free_buffers(surface.get())) - { - BOOST_THROW_EXCEPTION(( - std::system_error{ - EBUSY, - std::system_category(), - "Too many buffers consumed from GBM surface"})); - } - - LockedFrontBuffer bo{ - gbm_surface_lock_front_buffer(surface.get()), - [shared_surface = surface](gbm_bo* bo) { gbm_surface_release_buffer(shared_surface.get(), bo); }}; - - if (!bo) - { - BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to acquire GBM front buffer"})); - } - - auto fb = GBMBoFramebuffer::framebuffer_for_frontbuffer(drm_fd, std::move(bo)); - if (!fb) - { - BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to make DRM FB"})); - } - return fb; - } -private: - mir::Fd const drm_fd; - std::shared_ptr const surface; -}; -} - -auto mgg::GBMDisplayProvider::make_surface(geom::Size size, DRMFormat format, std::span modifiers) - -> std::unique_ptr -{ - return std::make_unique(fd, gbm.get(), std::move(size), format, modifiers); -} diff --git a/src/platforms/gbm-kms/server/kms/display.h b/src/platforms/gbm-kms/server/kms/display.h index d1d6f184e09..f91eaf943f3 100644 --- a/src/platforms/gbm-kms/server/kms/display.h +++ b/src/platforms/gbm-kms/server/kms/display.h @@ -59,8 +59,8 @@ class Display : public graphics::Display { public: Display( - std::shared_ptr parent, mir::Fd drm_fd, + std::shared_ptr gbm, BypassOption bypass_option, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& listener); @@ -86,9 +86,9 @@ class Display : public graphics::Display private: void clear_connected_unused_outputs(); - std::shared_ptr const owner; mutable std::mutex configuration_mutex; mir::Fd const drm_fd; + std::shared_ptr const gbm; std::shared_ptr const listener; mir::udev::Monitor monitor; std::shared_ptr const output_container; @@ -107,21 +107,19 @@ class Display : public graphics::Display class GBMDisplayProvider : public graphics::GBMDisplayProvider { public: - GBMDisplayProvider(mir::Fd drm_fd); - + explicit GBMDisplayProvider(mir::Fd drm_fd); + auto is_same_device(mir::udev::Device const& render_device) const -> bool override; - + + auto on_this_device(graphics::DisplayBuffer& target) const -> bool override; + auto gbm_device() const -> std::shared_ptr override; - auto supported_formats() const -> std::vector override; - - auto modifiers_for_format(DRMFormat format) const -> std::vector override; - - auto make_surface(geometry::Size size, DRMFormat format, std::span modifier) -> std::unique_ptr override; private: mir::Fd const fd; std::shared_ptr const gbm; }; + } } } diff --git a/src/platforms/gbm-kms/server/kms/display_buffer.cpp b/src/platforms/gbm-kms/server/kms/display_buffer.cpp index 37d25faf743..d1dfbd32a8a 100644 --- a/src/platforms/gbm-kms/server/kms/display_buffer.cpp +++ b/src/platforms/gbm-kms/server/kms/display_buffer.cpp @@ -15,10 +15,13 @@ */ #include "display_buffer.h" +#include "kms_cpu_addressable_display_provider.h" #include "kms_output.h" #include "cpu_addressable_fb.h" +#include "gbm_display_allocator.h" #include "mir/fd.h" #include "mir/graphics/display_report.h" +#include "mir/graphics/platform.h" #include "mir/graphics/transformation.h" #include "bypass.h" #include "mir/fatal.h" @@ -41,18 +44,19 @@ #include #include +namespace mg = mir::graphics; namespace mgg = mir::graphics::gbm; namespace geom = mir::geometry; mgg::DisplayBuffer::DisplayBuffer( - std::shared_ptr provider, mir::Fd drm_fd, + std::shared_ptr gbm, mgg::BypassOption, std::shared_ptr const& listener, std::vector> const& outputs, geom::Rectangle const& area, glm::mat2 const& transformation) - : provider{std::move(provider)}, + : gbm{std::move(gbm)}, listener(listener), outputs(outputs), area(area), @@ -184,7 +188,7 @@ void mgg::DisplayBuffer::post() { // Hey! No one has given us a next frame yet, so we don't have to change what's onscreen. // Sweet! We can just bail. - return; + return; } /* * Otherwise, pull the next frame into the pending slot @@ -304,14 +308,14 @@ void mgg::DisplayBuffer::schedule_set_crtc() needs_set_crtc = true; } -auto mir::graphics::gbm::DisplayBuffer::display_provider() const -> std::shared_ptr +auto mgg::DisplayBuffer::drm_fd() const -> mir::Fd { - return provider; + return mir::Fd{mir::IntOwnedFd{outputs.front()->drm_fd()}}; } -auto mgg::DisplayBuffer::drm_fd() const -> mir::Fd +auto mgg::DisplayBuffer::gbm_device() const -> std::shared_ptr { - return mir::Fd{mir::IntOwnedFd{outputs.front()->drm_fd()}}; + return gbm; } void mir::graphics::gbm::DisplayBuffer::set_next_image(std::unique_ptr content) @@ -331,3 +335,25 @@ void mir::graphics::gbm::DisplayBuffer::set_next_image(std::unique_ptr DisplayAllocator* +{ + if (dynamic_cast(&type_tag)) + { + if (!kms_allocator) + { + kms_allocator = kms::CPUAddressableDisplayAllocator::create_if_supported(drm_fd()); + } + return kms_allocator.get(); + } + if (dynamic_cast(&type_tag)) + { + if (!gbm_allocator) + { + gbm_allocator = std::make_unique(drm_fd(), gbm); + } + return gbm_allocator.get(); + } + return nullptr; +} diff --git a/src/platforms/gbm-kms/server/kms/display_buffer.h b/src/platforms/gbm-kms/server/kms/display_buffer.h index 38efb4fa454..87c6fa6c621 100644 --- a/src/platforms/gbm-kms/server/kms/display_buffer.h +++ b/src/platforms/gbm-kms/server/kms/display_buffer.h @@ -21,6 +21,7 @@ #include "mir/graphics/display.h" #include "display_helpers.h" #include "egl_helper.h" +#include "mir/graphics/platform.h" #include "platform_common.h" #include "kms_framebuffer.h" @@ -41,15 +42,14 @@ namespace gbm class Platform; class KMSOutput; -class NativeBuffer; class DisplayBuffer : public graphics::DisplayBuffer, public graphics::DisplaySyncGroup { public: DisplayBuffer( - std::shared_ptr provider, mir::Fd drm_fd, + std::shared_ptr gbm, BypassOption bypass_options, std::shared_ptr const& listener, std::vector> const& outputs, @@ -76,20 +76,27 @@ class DisplayBuffer : public graphics::DisplayBuffer, void schedule_set_crtc(); void wait_for_page_flip(); - auto display_provider() const -> std::shared_ptr override; - auto drm_fd() const -> mir::Fd; + + auto gbm_device() const -> std::shared_ptr; + +protected: + auto maybe_create_allocator(DisplayAllocator::Tag const& type_tag) -> DisplayAllocator* override; + private: bool schedule_page_flip(FBHandle const& bufobj); void set_crtc(FBHandle const&); - std::shared_ptr const provider; + std::shared_ptr const gbm; bool holding_client_buffers{false}; std::shared_ptr bypass_bufobj{nullptr}; std::shared_ptr const listener; std::vector> outputs; + std::shared_ptr kms_allocator; + std::unique_ptr gbm_allocator; + // Framebuffer handling // KMS does not take a reference to submitted framebuffers; if you destroy a framebuffer while // it's in use, KMS treat that as submitting a null framebuffer and turn off the display. diff --git a/src/platforms/gbm-kms/server/kms/platform.cpp b/src/platforms/gbm-kms/server/kms/platform.cpp index 41b16d5c4a9..da6d9d348e1 100644 --- a/src/platforms/gbm-kms/server/kms/platform.cpp +++ b/src/platforms/gbm-kms/server/kms/platform.cpp @@ -62,6 +62,20 @@ auto master_fd_for_device(mir::udev::Device const& device, mir::ConsoleServices& return std::make_tuple(std::move(device_handle), std::move(drm_fd)); } + +auto maybe_make_gbm_provider(mir::Fd drm_fd) -> std::shared_ptr +{ + try + { + return std::make_shared(std::move(drm_fd)); + } + catch (std::exception const& err) + { + mir::log_info("Failed to create GBM device for direct buffer submission"); + mir::log_info("Output will use CPU buffer copies"); + return {}; + } +} } mgg::Platform::Platform( @@ -83,7 +97,7 @@ mgg::Platform::Platform( listener{listener}, device_handle{std::move(std::get<0>(drm))}, drm_fd{std::move(std::get<1>(drm))}, - provider{std::make_shared(drm_fd)}, + gbm_display_provider{maybe_make_gbm_provider(drm_fd)}, bypass_option_{bypass_option} { if (drm_fd == mir::Fd::invalid) @@ -96,7 +110,7 @@ namespace { auto gbm_device_for_udev_device( mir::udev::Device const& device, - std::vector> const& displays) + std::vector> const& displays) -> std::variant, std::shared_ptr> { /* First check to see whether our device exactly matches a display device. @@ -104,7 +118,7 @@ auto gbm_device_for_udev_device( */ for(auto const& display_device : displays) { - if (auto gbm_display = display_device->acquire_interface()) + if (auto gbm_display = display_device->acquire_provider()) { if (gbm_display->is_same_device(device)) { @@ -324,8 +338,8 @@ auto maybe_make_dmabuf_provider( mgg::RenderingPlatform::RenderingPlatform( mir::udev::Device const& device, - std::vector> const& displays) - : RenderingPlatform(gbm_device_for_udev_device(device, displays)) + std::vector> const& platforms) + : RenderingPlatform(gbm_device_for_udev_device(device, platforms)) { } @@ -365,64 +379,45 @@ auto mgg::RenderingPlatform::maybe_create_provider( return nullptr; } -class mgg::Platform::KMSDisplayInterfaceProvider : public mg::DisplayInterfaceProvider +namespace { -public: - explicit KMSDisplayInterfaceProvider(mir::Fd drm_fd) - : drm_fd{std::move(drm_fd)}, - gbm_provider{maybe_make_gbm_provider(this->drm_fd)} - { - } - -protected: - auto maybe_create_interface(mg::DisplayProvider::Tag const& type_tag) - -> std::shared_ptr - { - if (dynamic_cast(&type_tag)) - { - return gbm_provider; - } - if (dynamic_cast(&type_tag)) - { - return mg::kms::CPUAddressableDisplayProvider::create_if_supported(drm_fd); - } - return {}; - } -private: - static auto maybe_make_gbm_provider(mir::Fd drm_fd) -> std::shared_ptr +auto gbm_device_from_provider(std::shared_ptr const& provider) + -> std::shared_ptr +{ + if (provider) { - try - { - return std::make_shared(std::move(drm_fd)); - } - catch (std::exception const& err) - { - mir::log_info("Failed to create GBM device for direct buffer submission"); - mir::log_info("Output will use CPU buffer copies"); - return {}; - } + return provider->gbm_device(); } - - mir::Fd const drm_fd; - // We rely on the GBM provider being stable over probe, so we construct one at startup - // and reuse it. - std::shared_ptr const gbm_provider; -}; + return nullptr; +} +} mir::UniqueModulePtr mgg::Platform::create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const&) { return make_module_ptr( - provider, drm_fd, + gbm_device_from_provider(gbm_display_provider), bypass_option_, initial_conf_policy, listener); } -auto mgg::Platform::interface_for() -> std::shared_ptr +auto mgg::Platform::maybe_create_provider(DisplayProvider::Tag const& type_tag) + -> std::shared_ptr { - return provider; + if (dynamic_cast(&type_tag)) + { + return gbm_display_provider; + } + if (dynamic_cast(&type_tag)) + { + /* There's no implementation behind it, but we want to know during probe time + * that the DisplayBuffers will support it. + */ + return std::make_shared(); + } + return {}; } mgg::BypassOption mgg::Platform::bypass_option() const diff --git a/src/platforms/gbm-kms/server/kms/platform.h b/src/platforms/gbm-kms/server/kms/platform.h index abc7f777282..b7440c03334 100644 --- a/src/platforms/gbm-kms/server/kms/platform.h +++ b/src/platforms/gbm-kms/server/kms/platform.h @@ -64,7 +64,8 @@ class Platform : public graphics::DisplayPlatform std::shared_ptr const listener; protected: - auto interface_for() -> std::shared_ptr override; + auto maybe_create_provider(DisplayProvider::Tag const& type_tag) + -> std::shared_ptr override; public: BypassOption bypass_option() const; @@ -78,9 +79,8 @@ class Platform : public graphics::DisplayPlatform std::unique_ptr const device_handle; mir::Fd const drm_fd; - class KMSDisplayInterfaceProvider; - std::shared_ptr const provider; - + std::shared_ptr gbm_display_provider; + BypassOption const bypass_option_; }; @@ -89,7 +89,7 @@ class RenderingPlatform : public graphics::RenderingPlatform public: RenderingPlatform( udev::Device const& device, - std::vector> const& displays); + std::vector> const& platforms); ~RenderingPlatform() override; diff --git a/src/platforms/gbm-kms/server/kms/platform_symbols.cpp b/src/platforms/gbm-kms/server/kms/platform_symbols.cpp index ad5526c9328..a551b12d528 100644 --- a/src/platforms/gbm-kms/server/kms/platform_symbols.cpp +++ b/src/platforms/gbm-kms/server/kms/platform_symbols.cpp @@ -77,13 +77,13 @@ mir::UniqueModulePtr create_display_platform( auto create_rendering_platform( mg::SupportedDevice const& device, - std::vector> const& displays, + std::vector> const& platforms, mo::Option const&, mir::EmergencyCleanupRegistry&) -> mir::UniqueModulePtr { mir::assert_entry_point_signature(&create_rendering_platform); - return mir::make_module_ptr(*device.device, displays); + return mir::make_module_ptr(*device.device, platforms); } void add_graphics_platform_options(boost::program_options::options_description& config) @@ -307,7 +307,7 @@ auto probe_display_platform( } auto probe_rendering_platform( - std::span> const& displays, + std::span> const& platforms, mir::ConsoleServices&, std::shared_ptr const& udev, mir::options::ProgramOption const& options) -> std::vector @@ -316,16 +316,16 @@ auto probe_rendering_platform( mg::probe::Result maximum_suitability = mg::probe::unsupported; // First check if there are any displays we can possibly drive - for (auto const& display_provider : displays) + for (auto const& platform : platforms) { - if (display_provider->acquire_interface()) + if (platform->acquire_provider()) { // We can optimally drive a GBM-backed display mir::log_debug("GBM-capable display found"); maximum_suitability = mg::probe::best; break; } - if (display_provider->acquire_interface()) + if (platform->acquire_provider()) { /* We *can* support this output, but with slower buffer copies * If another platform supports this device better, let it. diff --git a/src/platforms/renderer-generic-egl/buffer_allocator.cpp b/src/platforms/renderer-generic-egl/buffer_allocator.cpp index cacf8e16acb..679c5e648ca 100644 --- a/src/platforms/renderer-generic-egl/buffer_allocator.cpp +++ b/src/platforms/renderer-generic-egl/buffer_allocator.cpp @@ -350,7 +350,7 @@ class EGLOutputSurface : public mg::gl::OutputSurface { public: EGLOutputSurface( - std::unique_ptr fb) + std::unique_ptr fb) : fb{std::move(fb)} { } @@ -385,7 +385,7 @@ class EGLOutputSurface : public mg::gl::OutputSurface } private: - std::unique_ptr const fb; + std::unique_ptr const fb; }; } @@ -402,9 +402,9 @@ auto mge::GLRenderingProvider::suitability_for_allocator(std::shared_ptr const& target) -> probe::Result + DisplayBuffer& target) -> probe::Result { - if (target->acquire_interface()) + if (target.acquire_allocator()) { /* We're effectively hosted on an underlying EGL platform. * @@ -414,7 +414,7 @@ auto mge::GLRenderingProvider::suitability_for_display( return probe::hosted; } - if (target->acquire_interface()) + if (target.acquire_allocator()) { /* We can *work* on a CPU-backed surface, but if anything's better * we should use something else! @@ -426,25 +426,25 @@ auto mge::GLRenderingProvider::suitability_for_display( } auto mge::GLRenderingProvider::surface_for_output( - std::shared_ptr framebuffer_provider, + DisplayBuffer& target, geometry::Size size, GLConfig const& config) -> std::unique_ptr { - if (auto egl_display = framebuffer_provider->acquire_interface()) + if (auto egl_display = target.acquire_allocator()) { return std::make_unique(egl_display->alloc_framebuffer(config, ctx)); } - auto cpu_provider = framebuffer_provider->acquire_interface(); + auto cpu_provider = target.acquire_allocator(); return std::make_unique( dpy, ctx, - std::move(cpu_provider), + *cpu_provider, size); } -auto mge::GLRenderingProvider::make_framebuffer_provider(std::shared_ptr /*target*/) +auto mge::GLRenderingProvider::make_framebuffer_provider(DisplayBuffer& /*target*/) -> std::unique_ptr { // TODO: Work out under what circumstances the EGL renderer *can* provide overlayable framebuffers diff --git a/src/platforms/renderer-generic-egl/buffer_allocator.h b/src/platforms/renderer-generic-egl/buffer_allocator.h index f29754f12cc..de060646494 100644 --- a/src/platforms/renderer-generic-egl/buffer_allocator.h +++ b/src/platforms/renderer-generic-egl/buffer_allocator.h @@ -90,17 +90,17 @@ class GLRenderingProvider : public graphics::GLRenderingProvider EGLContext ctx, std::shared_ptr dmabuf_provider); - auto make_framebuffer_provider(std::shared_ptr target) + auto make_framebuffer_provider(DisplayBuffer& target) -> std::unique_ptr override; auto as_texture(std::shared_ptr buffer) -> std::shared_ptr override; auto suitability_for_allocator(std::shared_ptr const& target) -> probe::Result override; - auto suitability_for_display(std::shared_ptr const& target) -> probe::Result override; + auto suitability_for_display(DisplayBuffer& target) -> probe::Result override; auto surface_for_output( - std::shared_ptr framebuffer_provider, + DisplayBuffer& target, geometry::Size size, GLConfig const& config) -> std::unique_ptr override; diff --git a/src/platforms/renderer-generic-egl/platform_symbols.cpp b/src/platforms/renderer-generic-egl/platform_symbols.cpp index 23744e39f0f..d42d106b687 100644 --- a/src/platforms/renderer-generic-egl/platform_symbols.cpp +++ b/src/platforms/renderer-generic-egl/platform_symbols.cpp @@ -36,7 +36,7 @@ namespace mge = mg::egl::generic; auto create_rendering_platform( mg::SupportedDevice const&, - std::vector> const& displays, + std::vector> const& displays, mo::Option const&, mir::EmergencyCleanupRegistry&) -> mir::UniqueModulePtr { @@ -51,7 +51,7 @@ void add_graphics_platform_options(boost::program_options::options_description&) } auto probe_rendering_platform( - std::span> const& displays, + std::span> const& displays, mir::ConsoleServices&, std::shared_ptr const&, mo::ProgramOption const&) -> std::vector @@ -62,12 +62,12 @@ auto probe_rendering_platform( // First check if there are any displays we can possibly drive for (auto const& display_provider : displays) { - if (display_provider->acquire_interface()) + if (display_provider->acquire_provider()) { maximum_suitability = mg::probe::hosted; break; } - if (display_provider->acquire_interface()) + if (display_provider->acquire_provider()) { // Check if the surfaceless platform is available if (mg::has_egl_client_extension("EGL_EXT_platform_base") && diff --git a/src/platforms/renderer-generic-egl/rendering_platform.cpp b/src/platforms/renderer-generic-egl/rendering_platform.cpp index 363322a3839..3e8b61e0159 100644 --- a/src/platforms/renderer-generic-egl/rendering_platform.cpp +++ b/src/platforms/renderer-generic-egl/rendering_platform.cpp @@ -47,11 +47,11 @@ auto create_default_display() -> EGLDisplay return eglGetDisplay(EGL_DEFAULT_DISPLAY); } -auto egl_display_from_platforms(std::vector> const& displays) -> std::tuple +auto egl_display_from_platforms(std::vector> const& displays) -> std::tuple { for (auto const& display : displays) { - if (auto egl_provider = display->acquire_interface()) + if (auto egl_provider = display->acquire_provider()) { return std::make_tuple(egl_provider->get_egl_display(), false); } @@ -196,7 +196,7 @@ auto maybe_make_dmabuf_provider( } } -mge::RenderingPlatform::RenderingPlatform(std::vector> const& displays) +mge::RenderingPlatform::RenderingPlatform(std::vector> const& displays) : RenderingPlatform(egl_display_from_platforms(displays)) { } diff --git a/src/platforms/renderer-generic-egl/rendering_platform.h b/src/platforms/renderer-generic-egl/rendering_platform.h index f97bdb15aed..cc33214a915 100644 --- a/src/platforms/renderer-generic-egl/rendering_platform.h +++ b/src/platforms/renderer-generic-egl/rendering_platform.h @@ -35,7 +35,7 @@ namespace graphics::egl::generic class RenderingPlatform : public graphics::RenderingPlatform { public: - explicit RenderingPlatform(std::vector> const& displays); + explicit RenderingPlatform(std::vector> const& displays); ~RenderingPlatform(); diff --git a/src/platforms/virtual/platform.cpp b/src/platforms/virtual/platform.cpp index 7f8757830e3..cbfcb364d3c 100644 --- a/src/platforms/virtual/platform.cpp +++ b/src/platforms/virtual/platform.cpp @@ -28,78 +28,10 @@ namespace geom = mir::geometry; using namespace std::literals; -class mgv::Platform::VirtualDisplayInterfaceProvider : public mg::DisplayInterfaceProvider -{ -public: - explicit VirtualDisplayInterfaceProvider() - { - } - -protected: - auto maybe_create_interface(mg::DisplayProvider::Tag const& type_tag) - -> std::shared_ptr - { - class VirtualCPUAddressableDisplayProvider: public CPUAddressableDisplayProvider - { - public: - class VirtualMappableFb: public MappableFB - { - public: - VirtualMappableFb(geom::Size const& size, DRMFormat format) - : size_{size}, format_{format} - { - } - - auto format() const -> MirPixelFormat override - { - return format_.as_mir_format().value_or(mir_pixel_format_invalid); - } - - auto stride() const -> geom::Stride override - { - return geom::Stride{}; - } - - auto size() const -> geom::Size override - { - return size_; - } - - auto map_writeable() -> std::unique_ptr> override - { - BOOST_THROW_EXCEPTION(std::logic_error("map_writeable is not implemented")); - } - - private: - geom::Size size_; - DRMFormat format_; - }; - - auto supported_formats() const -> std::vector override - { - return {mg::DRMFormat{DRM_FORMAT_XRGB8888}, mg::DRMFormat{DRM_FORMAT_ARGB8888}}; - } - - auto alloc_fb(geometry::Size pixel_size, DRMFormat format) -> std::unique_ptr override - { - return std::make_unique(pixel_size, format); - } - }; - - if (dynamic_cast(&type_tag)) - { - return std::make_shared(); - } - - return nullptr; - } -}; - mgv::Platform::Platform( std::shared_ptr const& report, std::vector outputs) : report{report}, - provider{std::make_shared()}, outputs{outputs} { } @@ -115,9 +47,13 @@ mir::UniqueModulePtr mgv::Platform::create_display( return mir::make_module_ptr(outputs); } -auto mgv::Platform::interface_for() -> std::shared_ptr +auto mgv::Platform::maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr { - return provider; + if (dynamic_cast(&type_tag)) + { + return std::make_shared(); + } + return nullptr; } auto mgv::Platform::parse_output_sizes(std::vector virtual_outputs) -> std::vector diff --git a/src/platforms/virtual/platform.h b/src/platforms/virtual/platform.h index 14cc4859843..d2b15193ef9 100644 --- a/src/platforms/virtual/platform.h +++ b/src/platforms/virtual/platform.h @@ -57,11 +57,9 @@ class Platform : public graphics::DisplayPlatform std::shared_ptr const& gl_config) override; protected: - auto interface_for() -> std::shared_ptr override; + auto maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr override; private: - class VirtualDisplayInterfaceProvider; std::shared_ptr const report; - std::shared_ptr const provider; std::vector const outputs; }; } diff --git a/src/platforms/wayland/displayclient.cpp b/src/platforms/wayland/displayclient.cpp index fde02405e18..460b2acc654 100644 --- a/src/platforms/wayland/displayclient.cpp +++ b/src/platforms/wayland/displayclient.cpp @@ -101,12 +101,12 @@ class mgw::DisplayClient::Output : auto pixel_size() const -> geometry::Size override; bool overlay(std::vector const& renderlist) override; auto transformation() const -> glm::mat2 override; - auto display_provider() const -> std::shared_ptr override; + auto maybe_create_allocator(DisplayAllocator::Tag const& type_tag) -> DisplayAllocator* override; void set_next_image(std::unique_ptr content) override; private: - std::unique_ptr next_frame; - std::shared_ptr provider; + std::unique_ptr next_frame; + std::shared_ptr provider; }; mgw::DisplayClient::Output::Output( @@ -309,7 +309,10 @@ void mgw::DisplayClient::Output::surface_configure(uint32_t serial) if (!has_initialized) { has_initialized = true; - provider = std::make_shared(*owner_->provider, surface, output_size); + provider = std::make_shared( + owner_->provider->get_egl_display(), + surface, + output_size); } else if (size_is_changed) { @@ -380,13 +383,11 @@ void mgw::DisplayClient::Output::post() frame_sync->init(); }); - // Avoid throttling compositing by blocking in eglSwapBuffers(). - // Instead we use the frame "done" notification. - // TODO: We probably don't need to do this every frame! - eglSwapInterval(provider->get_egl_display(), 0); - + // The Framebuffer ensures that this swap_buffers call doesn't block... next_frame->swap_buffers(); + // ...so we need external synchronisation to throttle rendering. + // Wait for the host compositor to tell us to render. frame_sync->wait_for_done(); } @@ -423,9 +424,20 @@ auto mgw::DisplayClient::Output::transformation() const -> glm::mat2 return glm::mat2{1}; } -auto mgw::DisplayClient::Output::display_provider() const -> std::shared_ptr +auto mgw::DisplayClient::Output::maybe_create_allocator(DisplayAllocator::Tag const& type_tag) -> DisplayAllocator* { - return provider; + if (dynamic_cast(&type_tag)) + { + if (!provider) + { + provider = std::make_unique( + owner_->provider->get_egl_display(), + surface, + pixel_size()); + } + return provider.get(); + } + return nullptr; } namespace @@ -446,7 +458,7 @@ auto unique_ptr_cast(std::unique_ptr ptr) -> std::unique_ptr void mgw::DisplayClient::Output::set_next_image(std::unique_ptr content) { - if (auto wl_content = unique_ptr_cast(std::move(content))) + if (auto wl_content = unique_ptr_cast(std::move(content))) { next_frame = std::move(wl_content); } diff --git a/src/platforms/wayland/platform.cpp b/src/platforms/wayland/platform.cpp index 6b428841e3f..46263346721 100644 --- a/src/platforms/wayland/platform.cpp +++ b/src/platforms/wayland/platform.cpp @@ -82,7 +82,11 @@ mir::UniqueModulePtr mgw::Platform::create_display( return mir::make_module_ptr(wl_display, provider, gl_config, report); } -auto mgw::Platform::interface_for() -> std::shared_ptr +auto mgw::Platform::maybe_create_provider(const DisplayProvider::Tag& type_tag) -> std::shared_ptr { - return provider; + if (dynamic_cast(&type_tag)) + { + return provider; + } + return nullptr; } diff --git a/src/platforms/wayland/platform.h b/src/platforms/wayland/platform.h index 3bbc3a3347d..44fbf6df5ef 100644 --- a/src/platforms/wayland/platform.h +++ b/src/platforms/wayland/platform.h @@ -42,7 +42,7 @@ class Platform : public graphics::DisplayPlatform std::shared_ptr const& gl_config) override; protected: - auto interface_for() -> std::shared_ptr override; + auto maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr override; private: struct wl_display* const wl_display; diff --git a/src/platforms/wayland/wl_egl_display_provider.cpp b/src/platforms/wayland/wl_egl_display_provider.cpp index ed022738214..a4803c29e70 100644 --- a/src/platforms/wayland/wl_egl_display_provider.cpp +++ b/src/platforms/wayland/wl_egl_display_provider.cpp @@ -12,7 +12,7 @@ namespace mg = mir::graphics; namespace mgw = mir::graphics::wayland; namespace geom = mir::geometry; -class mgw::WlDisplayProvider::Framebuffer::EGLState +class mgw::WlDisplayAllocator::Framebuffer::EGLState { public: EGLState(EGLDisplay dpy, EGLContext ctx, EGLSurface surf) @@ -34,23 +34,34 @@ class mgw::WlDisplayProvider::Framebuffer::EGLState EGLSurface const surf; }; -mgw::WlDisplayProvider::Framebuffer::Framebuffer(EGLDisplay dpy, EGLContext ctx, EGLSurface surf, geom::Size size) +mgw::WlDisplayAllocator::Framebuffer::Framebuffer(EGLDisplay dpy, EGLContext ctx, EGLSurface surf, geom::Size size) : Framebuffer(std::make_shared(dpy, ctx, surf), size) { + auto current_ctx = eglGetCurrentContext(); + auto current_draw_surf = eglGetCurrentSurface(EGL_DRAW); + auto current_read_surf = eglGetCurrentSurface(EGL_READ); + + make_current(); + // Don't block in eglSwapBuffers; we rely on external synchronisation to throttle rendering + eglSwapInterval(dpy, 0); + release_current(); + + // Paranoia: Restore the previous EGL context state, just in case + eglMakeCurrent(dpy, current_draw_surf, current_read_surf, current_ctx); } -mgw::WlDisplayProvider::Framebuffer::Framebuffer(std::shared_ptr state, geom::Size size) +mgw::WlDisplayAllocator::Framebuffer::Framebuffer(std::shared_ptr state, geom::Size size) : state{std::move(state)}, size_{size} { } -auto mgw::WlDisplayProvider::Framebuffer::size() const -> geom::Size +auto mgw::WlDisplayAllocator::Framebuffer::size() const -> geom::Size { return size_; } -void mgw::WlDisplayProvider::Framebuffer::make_current() +void mgw::WlDisplayAllocator::Framebuffer::make_current() { if (eglMakeCurrent(state->dpy, state->surf, state->surf, state->ctx) != EGL_TRUE) { @@ -58,7 +69,7 @@ void mgw::WlDisplayProvider::Framebuffer::make_current() } } -void mgw::WlDisplayProvider::Framebuffer::release_current() +void mgw::WlDisplayAllocator::Framebuffer::release_current() { if (eglMakeCurrent(state->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) { @@ -66,7 +77,7 @@ void mgw::WlDisplayProvider::Framebuffer::release_current() } } -void mgw::WlDisplayProvider::Framebuffer::swap_buffers() +void mgw::WlDisplayAllocator::Framebuffer::swap_buffers() { if (eglSwapBuffers(state->dpy, state->surf) != EGL_TRUE) { @@ -74,74 +85,30 @@ void mgw::WlDisplayProvider::Framebuffer::swap_buffers() } } -auto mgw::WlDisplayProvider::Framebuffer::clone_handle() -> std::unique_ptr +auto mgw::WlDisplayAllocator::Framebuffer::clone_handle() -> std::unique_ptr { - return std::unique_ptr{new Framebuffer(state, size_)}; + return std::unique_ptr{new Framebuffer(state, size_)}; } -class mgw::WlDisplayProvider::EGLDisplayProvider : public mg::GenericEGLDisplayProvider -{ -public: - EGLDisplayProvider(EGLDisplay dpy); - - EGLDisplayProvider( - EGLDisplayProvider const& from, - struct wl_surface* surface, - geometry::Size size); - - ~EGLDisplayProvider(); - - auto get_egl_display() -> EGLDisplay override; - - auto alloc_framebuffer(GLConfig const& config, EGLContext share_context) -> std::unique_ptr override; - -private: - EGLDisplay const dpy; - - struct OutputContext - { - struct wl_egl_window* wl_window; - geometry::Size size; - }; - std::optional const output; -}; - -mgw::WlDisplayProvider::EGLDisplayProvider::EGLDisplayProvider(EGLDisplay dpy) - : dpy{dpy} -{ -} - -mgw::WlDisplayProvider::EGLDisplayProvider::EGLDisplayProvider( - EGLDisplayProvider const& from, +mgw::WlDisplayAllocator::WlDisplayAllocator( + EGLDisplay dpy, struct wl_surface* surface, geometry::Size size) - : dpy{from.dpy}, - output{ - OutputContext { - wl_egl_window_create(surface, size.width.as_int(), size.height.as_int()), - size - }} + : dpy{dpy}, + wl_window{wl_egl_window_create(surface, size.width.as_int(), size.height.as_int())}, + size{size} { } -mgw::WlDisplayProvider::EGLDisplayProvider::~EGLDisplayProvider() +mgw::WlDisplayAllocator::~WlDisplayAllocator() { - if (output) - { - wl_egl_window_destroy(output->wl_window); - } + wl_egl_window_destroy(wl_window); } -auto mgw::WlDisplayProvider::EGLDisplayProvider::alloc_framebuffer( +auto mgw::WlDisplayAllocator::alloc_framebuffer( GLConfig const& config, EGLContext share_context) -> std::unique_ptr { - if (!output) - { - BOOST_THROW_EXCEPTION((std::logic_error{"Ooops"})); - } - auto const [wl_window, size] = *output; - EGLint const config_attr[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, @@ -186,35 +153,12 @@ auto mgw::WlDisplayProvider::EGLDisplayProvider::alloc_framebuffer( size); } -auto mgw::WlDisplayProvider::EGLDisplayProvider::get_egl_display() -> EGLDisplay -{ - return dpy; -} - mgw::WlDisplayProvider::WlDisplayProvider(EGLDisplay dpy) - : egl_provider{std::make_shared(dpy)} -{ -} - -mgw::WlDisplayProvider::WlDisplayProvider( - WlDisplayProvider const& from, - struct wl_surface* surface, - geometry::Size size) - : egl_provider{std::make_shared(*from.egl_provider, surface, size)} -{ -} - -auto mgw::WlDisplayProvider::get_egl_display() const -> EGLDisplay + : dpy{dpy} { - return egl_provider->get_egl_display(); } -auto mgw::WlDisplayProvider::maybe_create_interface(DisplayProvider::Tag const& type_tag) - -> std::shared_ptr +auto mgw::WlDisplayProvider::get_egl_display() -> EGLDisplay { - if (dynamic_cast(&type_tag)) - { - return egl_provider; - } - return nullptr; + return dpy; } diff --git a/src/platforms/wayland/wl_egl_display_provider.h b/src/platforms/wayland/wl_egl_display_provider.h index c0cdc0af0ce..a3c92aaddd6 100644 --- a/src/platforms/wayland/wl_egl_display_provider.h +++ b/src/platforms/wayland/wl_egl_display_provider.h @@ -21,10 +21,12 @@ #include +struct wl_egl_window; + namespace mir::graphics::wayland { -class WlDisplayProvider : public DisplayInterfaceProvider +class WlDisplayProvider : public GenericEGLDisplayProvider { public: WlDisplayProvider(EGLDisplay dpy); @@ -34,12 +36,21 @@ class WlDisplayProvider : public DisplayInterfaceProvider struct wl_surface* surface, geometry::Size size); - auto get_egl_display() const -> EGLDisplay; + auto get_egl_display() -> EGLDisplay override; +private: + EGLDisplay const dpy; +}; - auto maybe_create_interface(DisplayProvider::Tag const& type_tag) - -> std::shared_ptr override; +class WlDisplayAllocator : public GenericEGLDisplayAllocator +{ +public: + WlDisplayAllocator(EGLDisplay dpy, struct wl_surface* surface, geometry::Size size); + ~WlDisplayAllocator(); + + auto alloc_framebuffer(GLConfig const& config, EGLContext share_context) + -> std::unique_ptr override; - class Framebuffer : public GenericEGLDisplayProvider::EGLFramebuffer + class Framebuffer : public GenericEGLDisplayAllocator::EGLFramebuffer { public: /** @@ -55,7 +66,7 @@ class WlDisplayProvider : public DisplayInterfaceProvider void make_current() override; void release_current() override; - auto clone_handle() -> std::unique_ptr override; + auto clone_handle() -> std::unique_ptr override; void swap_buffers(); private: @@ -66,9 +77,9 @@ class WlDisplayProvider : public DisplayInterfaceProvider geometry::Size const size_; }; private: - class EGLDisplayProvider; - - std::shared_ptr const egl_provider; + EGLDisplay const dpy; + struct ::wl_egl_window* const wl_window; + geometry::Size const size; }; } diff --git a/src/platforms/x11/graphics/display.cpp b/src/platforms/x11/graphics/display.cpp index 372035e2a13..d070b66ebef 100644 --- a/src/platforms/x11/graphics/display.cpp +++ b/src/platforms/x11/graphics/display.cpp @@ -103,13 +103,13 @@ mgx::X11Window::operator xcb_window_t() const } mgx::Display::Display( - std::shared_ptr parent, std::shared_ptr const& x11_resources, + std::shared_ptr egl, std::string const title, std::vector const& requested_sizes, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& report) - : parent{std::move(parent)}, + : egl{std::move(egl)}, x11_resources{x11_resources}, pixel_size_mm{get_pixel_size_mm(x11_resources->conn.get())}, report{report} @@ -134,8 +134,9 @@ mgx::Display::Display( requested_size.scale, mir_orientation_normal); auto display_buffer = std::make_unique( - this->parent, + x11_resources->conn->connection(), *window, + this->egl, configuration->extents(), actual_size); top_left.x += as_delta(configuration->extents().size.width); diff --git a/src/platforms/x11/graphics/display.h b/src/platforms/x11/graphics/display.h index 502e755913b..84b7b79eb04 100644 --- a/src/platforms/x11/graphics/display.h +++ b/src/platforms/x11/graphics/display.h @@ -64,8 +64,8 @@ class Display : public graphics::Display { public: Display( - std::shared_ptr parent, std::shared_ptr const& x11_resources, + std::shared_ptr egl, std::string const title, std::vector const& requested_size, std::shared_ptr const& initial_conf_policy, @@ -108,7 +108,7 @@ class Display : public graphics::Display std::shared_ptr const config; }; - std::shared_ptr const parent; + std::shared_ptr const egl; std::shared_ptr const x11_resources; geometry::SizeF pixel_size_mm; std::shared_ptr const report; diff --git a/src/platforms/x11/graphics/display_buffer.cpp b/src/platforms/x11/graphics/display_buffer.cpp index 08eb5d976f2..0717bdd970b 100644 --- a/src/platforms/x11/graphics/display_buffer.cpp +++ b/src/platforms/x11/graphics/display_buffer.cpp @@ -20,24 +20,51 @@ #include "display_configuration.h" #include "mir/graphics/display_report.h" #include "mir/graphics/transformation.h" +#include "../x11_resources.h" #include namespace mg=mir::graphics; namespace mgx=mg::X; namespace geom=mir::geometry; -mgx::DisplayBuffer::DisplayBuffer(std::shared_ptr parent, - xcb_window_t win, - geometry::Rectangle const& view_area, - geometry::Size pixel_size) - : parent{std::move(parent)}, - area{view_area}, - in_pixels{pixel_size}, - transform(1), - x_win{win} +class mgx::DisplayBuffer::Allocator : public mg::GenericEGLDisplayAllocator +{ +public: + Allocator(std::shared_ptr egl, xcb_connection_t* connection, xcb_window_t window) + : egl{std::move(egl)}, + x11_connection{connection}, + x11_win{window} + { + } + + auto alloc_framebuffer(mg::GLConfig const& config, EGLContext share_context) + -> std::unique_ptr override + { + return egl->framebuffer_for_window(config, x11_connection, x11_win, share_context); + } +private: + std::shared_ptr const egl; + xcb_connection_t* const x11_connection; + xcb_window_t const x11_win; +}; + +mgx::DisplayBuffer::DisplayBuffer( + xcb_connection_t* connection, + xcb_window_t win, + std::shared_ptr egl, + geometry::Rectangle const& view_area, + geometry::Size pixel_size) + : area{view_area}, + in_pixels{pixel_size}, + transform(1), + egl{std::move(egl)}, + x11_connection{connection}, + x_win{win} { } +mgx::DisplayBuffer::~DisplayBuffer() = default; + geom::Rectangle mgx::DisplayBuffer::view_area() const { return area; @@ -86,11 +113,6 @@ void mgx::DisplayBuffer::set_view_area(geom::Rectangle const& a) area = a; } -auto mgx::DisplayBuffer::display_provider() const -> std::shared_ptr -{ - return parent->provider_for_window(x_win); -} - void mgx::DisplayBuffer::set_transformation(glm::mat2 const& t) { transform = t; @@ -116,4 +138,18 @@ std::chrono::milliseconds mgx::DisplayBuffer::recommended_sleep() const auto mgx::DisplayBuffer::x11_window() const -> xcb_window_t { return x_win; -} \ No newline at end of file +} + +auto mgx::DisplayBuffer::maybe_create_allocator(mg::DisplayAllocator::Tag const& type_tag) + -> DisplayAllocator* +{ + if (dynamic_cast(&type_tag)) + { + if (!egl_allocator) + { + egl_allocator = std::make_unique(egl, x11_connection, x_win); + } + return egl_allocator.get(); + } + return nullptr; +} diff --git a/src/platforms/x11/graphics/display_buffer.h b/src/platforms/x11/graphics/display_buffer.h index 4e12c1d8ea6..496d610d1cb 100644 --- a/src/platforms/x11/graphics/display_buffer.h +++ b/src/platforms/x11/graphics/display_buffer.h @@ -44,11 +44,14 @@ class DisplayBuffer : public graphics::DisplayBuffer, { public: DisplayBuffer( - std::shared_ptr parent, + xcb_connection_t* connection, xcb_window_t win, + std::shared_ptr egl, geometry::Rectangle const& view_area, geometry::Size pixel_size); + ~DisplayBuffer(); + auto view_area() const -> geometry::Rectangle override; auto pixel_size() const -> geometry::Size override; @@ -57,7 +60,10 @@ class DisplayBuffer : public graphics::DisplayBuffer, glm::mat2 transformation() const override; - auto display_provider() const -> std::shared_ptr override; +protected: + auto maybe_create_allocator(DisplayAllocator::Tag const& type_tag) -> DisplayAllocator* override; + +public: void set_view_area(geometry::Rectangle const& a); void set_transformation(glm::mat2 const& t); @@ -69,11 +75,15 @@ class DisplayBuffer : public graphics::DisplayBuffer, auto x11_window() const -> xcb_window_t; private: - std::shared_ptr const parent; + class Allocator; + std::unique_ptr egl_allocator; + std::shared_ptr next_frame; geometry::Rectangle area; geometry::Size in_pixels; glm::mat2 transform; + std::shared_ptr egl; + xcb_connection_t* const x11_connection; xcb_window_t const x_win; }; diff --git a/src/platforms/x11/graphics/egl_helper.cpp b/src/platforms/x11/graphics/egl_helper.cpp index df7536309df..3f7dc589744 100644 --- a/src/platforms/x11/graphics/egl_helper.cpp +++ b/src/platforms/x11/graphics/egl_helper.cpp @@ -88,9 +88,9 @@ void mgxh::Framebuffer::swap_buffers() } } -auto mgxh::Framebuffer::clone_handle() -> std::unique_ptr +auto mgxh::Framebuffer::clone_handle() -> std::unique_ptr { - return std::unique_ptr{new Framebuffer(state, size_)}; + return std::unique_ptr{new Framebuffer(state, size_)}; } mgxh::EGLHelper::EGLHelper(::Display* const x_dpy) diff --git a/src/platforms/x11/graphics/egl_helper.h b/src/platforms/x11/graphics/egl_helper.h index 80e5a7e1bce..1ccad6286e8 100644 --- a/src/platforms/x11/graphics/egl_helper.h +++ b/src/platforms/x11/graphics/egl_helper.h @@ -38,7 +38,7 @@ namespace X namespace helpers { -class Framebuffer : public GenericEGLDisplayProvider::EGLFramebuffer +class Framebuffer : public GenericEGLDisplayAllocator::EGLFramebuffer { public: /** @@ -54,7 +54,7 @@ class Framebuffer : public GenericEGLDisplayProvider::EGLFramebuffer void make_current() override; void release_current() override; - auto clone_handle() -> std::unique_ptr override; + auto clone_handle() -> std::unique_ptr override; void swap_buffers(); private: diff --git a/src/platforms/x11/graphics/platform.cpp b/src/platforms/x11/graphics/platform.cpp index 9174628b53e..67ee27136f1 100644 --- a/src/platforms/x11/graphics/platform.cpp +++ b/src/platforms/x11/graphics/platform.cpp @@ -55,8 +55,8 @@ mgx::Platform::Platform(std::shared_ptr const& x11_resourc std::string title, std::vector output_sizes, std::shared_ptr const& report) - : egl_provider{std::make_shared(x11_resources->xlib_dpy)}, - x11_resources{x11_resources}, + : x11_resources{x11_resources}, + egl{std::make_shared(x11_resources->xlib_dpy)}, title{std::move(title)}, report{report}, output_sizes{std::move(output_sizes)} @@ -68,85 +68,38 @@ mir::UniqueModulePtr mgx::Platform::create_display( std::shared_ptr const& /*gl_config*/) { return make_module_ptr( - std::dynamic_pointer_cast(shared_from_this()), x11_resources, + egl, title, output_sizes, initial_conf_policy, report); } -class mgx::Platform::InterfaceProvider : public mg::DisplayInterfaceProvider +namespace +{ +class EGLProvider : public mg::GenericEGLDisplayProvider { public: - InterfaceProvider(::Display* x_dpy) - : egl{std::make_shared(x_dpy)}, - connection{nullptr}, - win{std::nullopt} + explicit EGLProvider(EGLDisplay dpy) + : dpy{dpy} { } - InterfaceProvider( - InterfaceProvider const& from, - std::shared_ptr connection, - xcb_window_t win) - : egl{from.egl}, - connection{std::move(connection)}, - win{win} + auto get_egl_display() -> EGLDisplay override { + return dpy; } - - class EGLDisplayProvider : public mg::GenericEGLDisplayProvider - { - public: - EGLDisplayProvider( - std::shared_ptr egl, - std::shared_ptr connection, - std::optional x_win) - : egl{std::move(egl)}, - connection{std::move(connection)}, - x_win{std::move(x_win)} - { - } - - auto get_egl_display() -> EGLDisplay - { - return egl->display(); - } - - auto alloc_framebuffer(mg::GLConfig const& config, EGLContext share_context) - -> std::unique_ptr - { - return egl->framebuffer_for_window(config, connection->conn->connection(), x_win.value(), share_context); - } - private: - std::shared_ptr const egl; - std::shared_ptr const connection; - std::optional const x_win; - }; - - auto maybe_create_interface(mir::graphics::DisplayProvider::Tag const& type_tag) - -> std::shared_ptr - { - if (dynamic_cast(&type_tag)) - { - return std::make_shared(egl, connection, win); - } - return {}; - } - private: - std::shared_ptr const egl; - std::shared_ptr const connection; - std::optional const win; + EGLDisplay const dpy; }; - -auto mgx::Platform::interface_for() -> std::shared_ptr -{ - return egl_provider; } -auto mgx::Platform::provider_for_window(xcb_window_t x_win) -> std::shared_ptr +auto mgx::Platform::maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr { - return std::make_shared(*egl_provider, x11_resources, x_win); -} \ No newline at end of file + if (dynamic_cast(&type_tag)) + { + return std::make_shared(egl->display()); + } + return nullptr; +} diff --git a/src/platforms/x11/graphics/platform.h b/src/platforms/x11/graphics/platform.h index abbebba8206..1b8cc1fde44 100644 --- a/src/platforms/x11/graphics/platform.h +++ b/src/platforms/x11/graphics/platform.h @@ -35,6 +35,11 @@ namespace graphics { namespace X { +namespace helpers +{ +class EGLHelper; +} + struct X11OutputConfig { inline X11OutputConfig(geometry::Size const& size) @@ -73,14 +78,12 @@ class Platform : public graphics::DisplayPlatform std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) -> UniqueModulePtr override; - auto provider_for_window(xcb_window_t x_win) -> std::shared_ptr; protected: - auto interface_for() -> std::shared_ptr override; + auto maybe_create_provider(DisplayProvider::Tag const& type_tag) -> std::shared_ptr override; private: - class InterfaceProvider; - std::shared_ptr const egl_provider; std::shared_ptr const x11_resources; + std::shared_ptr const egl; std::string const title; std::shared_ptr const report; std::vector const output_sizes; diff --git a/src/server/compositor/basic_screen_shooter.cpp b/src/server/compositor/basic_screen_shooter.cpp index 8bffc25d439..2c0a7085498 100644 --- a/src/server/compositor/basic_screen_shooter.cpp +++ b/src/server/compositor/basic_screen_shooter.cpp @@ -26,6 +26,7 @@ #include "mir/graphics/platform.h" #include "mir/renderer/renderer_factory.h" #include "mir/renderer/sw/pixel_source.h" +#include "mir/graphics/display_buffer.h" namespace mc = mir::compositor; namespace mr = mir::renderer; @@ -33,12 +34,12 @@ namespace mg = mir::graphics; namespace mrs = mir::renderer::software; namespace geom = mir::geometry; -class mc::BasicScreenShooter::Self::OneShotBufferDisplayProvider : public mg::CPUAddressableDisplayProvider +class mc::BasicScreenShooter::Self::OneShotBufferDisplayProvider : public mg::CPUAddressableDisplayAllocator { public: OneShotBufferDisplayProvider() = default; - class FB : public mg::CPUAddressableDisplayProvider::MappableFB + class FB : public mg::CPUAddressableDisplayAllocator::MappableFB { public: FB(std::shared_ptr buffer) @@ -100,25 +101,54 @@ class mc::BasicScreenShooter::Self::OneShotBufferDisplayProvider : public mg::CP std::shared_ptr next_buffer; }; -class InterfaceProvider : public mg::DisplayInterfaceProvider +class OffscreenDisplayBuffer : public mg::DisplayBuffer { public: - InterfaceProvider(std::shared_ptr provider) - : provider {std::move(provider)} + OffscreenDisplayBuffer( + std::shared_ptr provider, + geom::Size size) + : provider {std::move(provider)}, + size{size} { } + + auto view_area() const -> mir::geometry::Rectangle override + { + return geom::Rectangle{{0, 0}, size}; + } + + auto pixel_size() const -> mir::geometry::Size override + { + return size; + } + + bool overlay(std::vector const& /*renderlist*/) override + { + return false; + } + + void set_next_image(std::unique_ptr) override + { + } + + auto transformation() const -> glm::mat2 override + { + return glm::mat2{}; + } + protected: - auto maybe_create_interface(mg::DisplayProvider::Tag const& type_tag) - -> std::shared_ptr override + auto maybe_create_allocator(mir::graphics::DisplayAllocator::Tag const& type_tag) + -> mg::DisplayAllocator* override { - if (dynamic_cast(&type_tag)) + if (dynamic_cast(&type_tag)) { - return provider; + return provider.get(); } return nullptr; } private: - std::shared_ptr const provider; + std::shared_ptr const provider; + geom::Size const size; }; mc::BasicScreenShooter::Self::Self( @@ -172,7 +202,7 @@ auto mc::BasicScreenShooter::Self::renderer_for_buffer(std::shared_ptrset_next_buffer(std::move(buffer)); - if (buffer_size != last_rendered_size) + if (!offscreen_db || (buffer_size != offscreen_db->pixel_size())) { // We need to build a new Renderer, at the new size class NoAuxConfig : public graphics::GLConfig @@ -187,10 +217,9 @@ auto mc::BasicScreenShooter::Self::renderer_for_buffer(std::shared_ptr(output); - auto gl_surface = render_provider->surface_for_output(interface_provider, buffer_size, NoAuxConfig{}); + offscreen_db = std::make_unique(output, buffer_size); + auto gl_surface = render_provider->surface_for_output(*offscreen_db, buffer_size, NoAuxConfig{}); current_renderer = renderer_factory->create_renderer_for(std::move(gl_surface), render_provider); - last_rendered_size = buffer_size; } return *current_renderer; } @@ -200,7 +229,7 @@ auto mc::BasicScreenShooter::select_provider( -> std::shared_ptr { auto display_provider = std::make_shared(); - auto interface_provider = std::make_shared(display_provider); + OffscreenDisplayBuffer temp_db{display_provider, geom::Size{640, 480}}; for (auto const& render_provider : providers) { @@ -210,7 +239,7 @@ auto mc::BasicScreenShooter::select_provider( * * For now, just use the first that claims to work. */ - if (render_provider->suitability_for_display(interface_provider) >= mg::probe::supported) + if (render_provider->suitability_for_display(temp_db) >= mg::probe::supported) { return render_provider; } diff --git a/src/server/compositor/basic_screen_shooter.h b/src/server/compositor/basic_screen_shooter.h index 3caeaa80779..4f4bd87c1e8 100644 --- a/src/server/compositor/basic_screen_shooter.h +++ b/src/server/compositor/basic_screen_shooter.h @@ -77,11 +77,11 @@ class BasicScreenShooter: public ScreenShooter std::shared_ptr const renderer_factory; /* The Renderer instantiation is tied to a particular output size, and - * and requires enough setup to make it worth keeping around as a consumer + * requires enough setup to make it worth keeping around as a consumer * is likely to be taking screenshots of consistent size */ std::unique_ptr current_renderer; - geometry::Size last_rendered_size; + std::unique_ptr offscreen_db; std::shared_ptr const output; }; diff --git a/src/server/compositor/default_display_buffer_compositor.cpp b/src/server/compositor/default_display_buffer_compositor.cpp index b36b70bcee2..2cc60340b26 100644 --- a/src/server/compositor/default_display_buffer_compositor.cpp +++ b/src/server/compositor/default_display_buffer_compositor.cpp @@ -37,7 +37,7 @@ mc::DefaultDisplayBufferCompositor::DefaultDisplayBufferCompositor( std::shared_ptr const& report) : display_buffer(display_buffer), renderer(renderer), - fb_adaptor{gl_provider.make_framebuffer_provider(display_buffer.display_provider())}, + fb_adaptor{gl_provider.make_framebuffer_provider(display_buffer)}, report(report) { } diff --git a/src/server/compositor/default_display_buffer_compositor_factory.cpp b/src/server/compositor/default_display_buffer_compositor_factory.cpp index 1083d6cc06a..a0bea10a333 100644 --- a/src/server/compositor/default_display_buffer_compositor_factory.cpp +++ b/src/server/compositor/default_display_buffer_compositor_factory.cpp @@ -58,15 +58,13 @@ mc::DefaultDisplayBufferCompositorFactory::create_compositor_for( * potentially-significant amount of GPU memory. */ - auto const display_provider = display_buffer.display_provider(); - /* In a heterogeneous system, different providers may be better at driving a specific * display. Select the best one. */ std::pair> best_provider = std::make_pair(mg::probe::unsupported, nullptr); for (auto const& provider : platforms) { - auto suitability = provider->suitability_for_display(display_provider); + auto suitability = provider->suitability_for_display(display_buffer); // We also need to make sure that the GLRenderingProvider can access client buffers... if (provider->suitability_for_allocator(buffer_allocator) > mg::probe::unsupported && suitability > best_provider.first) { @@ -83,7 +81,7 @@ mc::DefaultDisplayBufferCompositorFactory::create_compositor_for( auto const chosen_allocator = best_provider.second; auto output_surface = chosen_allocator->surface_for_output( - display_provider, display_buffer.pixel_size(), *gl_config); + display_buffer, display_buffer.pixel_size(), *gl_config); auto renderer = renderer_factory->create_renderer_for(std::move(output_surface), chosen_allocator); renderer->set_viewport(display_buffer.view_area()); return std::make_unique( diff --git a/src/server/graphics/default_configuration.cpp b/src/server/graphics/default_configuration.cpp index 54477a5f099..6b2f905d68a 100644 --- a/src/server/graphics/default_configuration.cpp +++ b/src/server/graphics/default_configuration.cpp @@ -276,13 +276,7 @@ auto mir::DefaultServerConfiguration::the_rendering_platforms() -> throw std::runtime_error(msg.c_str()); } - std::vector> display_interfaces; - display_interfaces.reserve(the_display_platforms().size()); - - for (auto& display : the_display_platforms()) - { - display_interfaces.push_back(mg::DisplayPlatform::interface_for(display)); - } + auto display_targets = the_display_platforms(); if (the_options()->is_set(options::platform_rendering_libs)) { @@ -293,7 +287,7 @@ auto mir::DefaultServerConfiguration::the_rendering_platforms() -> { auto supported_devices = graphics::probe_rendering_module( - display_interfaces, + display_targets, *platform, dynamic_cast(*the_options()), the_console_services()); @@ -321,7 +315,7 @@ auto mir::DefaultServerConfiguration::the_rendering_platforms() -> } else { - platform_modules = mir::graphics::rendering_modules_for_device(platforms, display_interfaces, dynamic_cast(*the_options()), the_console_services()); + platform_modules = mir::graphics::rendering_modules_for_device(platforms, display_targets, dynamic_cast(*the_options()), the_console_services()); } for (auto const& [device, platform]: platform_modules) @@ -360,7 +354,7 @@ auto mir::DefaultServerConfiguration::the_rendering_platforms() -> rendering_platform_map[description->name] = create_rendering_platform( device, - display_interfaces, + display_targets, *the_options(), *the_emergency_cleanup()); // Add this module to the list searched by the input stack later diff --git a/src/server/graphics/platform_probe.cpp b/src/server/graphics/platform_probe.cpp index 8651f1994c8..be7963594ec 100644 --- a/src/server/graphics/platform_probe.cpp +++ b/src/server/graphics/platform_probe.cpp @@ -91,18 +91,18 @@ auto mir::graphics::probe_display_module( } auto mir::graphics::probe_rendering_module( - std::span> const& displays, + std::span> const& platforms, SharedLibrary const& module, options::ProgramOption const& options, std::shared_ptr const& console) -> std::vector { return probe_module( - [&console, &options, &module, &displays]() -> std::vector + [&console, &options, &module, &platforms]() -> std::vector { auto probe = module.load_function( "probe_rendering_platform", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); - return probe(displays, *console, std::make_shared(), options); + return probe(platforms, *console, std::make_shared(), options); }, module, "rendering"); @@ -221,14 +221,14 @@ auto mir::graphics::display_modules_for_device( auto mir::graphics::rendering_modules_for_device( std::vector> const& modules, - std::span> const& displays, + std::span> const& platforms, options::ProgramOption const& options, std::shared_ptr const& console) -> std::vector>> { return modules_for_device( - [&displays, &options, &console](SharedLibrary const& module) -> std::vector + [&platforms, &options, &console](SharedLibrary const& module) -> std::vector { - return probe_rendering_module(displays, module, options, console); + return probe_rendering_module(platforms, module, options, console); }, modules); } diff --git a/src/server/graphics/platform_probe.h b/src/server/graphics/platform_probe.h index 88b177fb623..4aecf61bf8a 100644 --- a/src/server/graphics/platform_probe.h +++ b/src/server/graphics/platform_probe.h @@ -36,7 +36,7 @@ auto probe_display_module( std::shared_ptr const& console) -> std::vector; auto probe_rendering_module( - std::span> const& displays, + std::span> const& platforms, SharedLibrary const& module, options::ProgramOption const& options, std::shared_ptr const& console) -> std::vector; @@ -49,7 +49,7 @@ auto display_modules_for_device( auto rendering_modules_for_device( std::vector> const& modules, - std::span> const& displays, + std::span> const& platforms, options::ProgramOption const& options, std::shared_ptr const& console) -> std::vector>>; diff --git a/tests/include/mir/test/doubles/mock_display_buffer.h b/tests/include/mir/test/doubles/mock_display_buffer.h index aa754990976..5ccac641526 100644 --- a/tests/include/mir/test/doubles/mock_display_buffer.h +++ b/tests/include/mir/test/doubles/mock_display_buffer.h @@ -43,7 +43,7 @@ class MockDisplayBuffer : public graphics::DisplayBuffer MOCK_METHOD(bool, overlay, (std::vector const&), (override)); MOCK_METHOD(void, set_next_image, (std::unique_ptr), (override)); MOCK_METHOD(glm::mat2, transformation, (), (const override)); - MOCK_METHOD(std::shared_ptr, display_provider, (), (const override)); + MOCK_METHOD(graphics::DisplayAllocator*, maybe_create_allocator, (graphics::DisplayAllocator::Tag const&), (override)); }; } diff --git a/tests/include/mir/test/doubles/mock_gl_rendering_provider.h b/tests/include/mir/test/doubles/mock_gl_rendering_provider.h index 31a859d030b..5c7f2fa85d0 100644 --- a/tests/include/mir/test/doubles/mock_gl_rendering_provider.h +++ b/tests/include/mir/test/doubles/mock_gl_rendering_provider.h @@ -31,7 +31,7 @@ class MockGlRenderingProvider : public graphics::GLRenderingProvider MOCK_METHOD( std::unique_ptr, surface_for_output, - (std::shared_ptr, geometry::Size, graphics::GLConfig const&), + (graphics::DisplayBuffer&, geometry::Size, graphics::GLConfig const&), (override)); MOCK_METHOD( graphics::probe::Result, @@ -41,12 +41,12 @@ class MockGlRenderingProvider : public graphics::GLRenderingProvider MOCK_METHOD( graphics::probe::Result, suitability_for_display, - (std::shared_ptr const&), + (graphics::DisplayBuffer&), (override)); MOCK_METHOD( std::unique_ptr, make_framebuffer_provider, - (std::shared_ptr), + (graphics::DisplayBuffer&), (override)); }; } diff --git a/tests/include/mir/test/doubles/null_display_buffer.h b/tests/include/mir/test/doubles/null_display_buffer.h index 0fc858020b1..677ae83b545 100644 --- a/tests/include/mir/test/doubles/null_display_buffer.h +++ b/tests/include/mir/test/doubles/null_display_buffer.h @@ -34,7 +34,11 @@ class NullDisplayBuffer : public graphics::DisplayBuffer bool overlay(std::vector const&) override { return false; } void set_next_image(std::unique_ptr) override { } glm::mat2 transformation() const override { return glm::mat2(1); } - auto display_provider() const -> std::shared_ptr override { return {};} +protected: + auto maybe_create_allocator(graphics::DisplayAllocator::Tag const&) -> graphics::DisplayAllocator* + { + return nullptr; + } }; } diff --git a/tests/include/mir/test/doubles/null_platform.h b/tests/include/mir/test/doubles/null_platform.h index 919358ed1f2..7bcaf0397e5 100644 --- a/tests/include/mir/test/doubles/null_platform.h +++ b/tests/include/mir/test/doubles/null_platform.h @@ -38,8 +38,8 @@ class NullDisplayPlatform : public graphics::DisplayPlatform } protected: - auto interface_for() - -> std::shared_ptr override + auto maybe_create_provider(graphics::DisplayProvider::Tag const&) + -> std::shared_ptr override { return nullptr; } diff --git a/tests/include/mir/test/doubles/stub_gl_rendering_provider.h b/tests/include/mir/test/doubles/stub_gl_rendering_provider.h index 9950ab3803c..4f31f9a0234 100644 --- a/tests/include/mir/test/doubles/stub_gl_rendering_provider.h +++ b/tests/include/mir/test/doubles/stub_gl_rendering_provider.h @@ -51,7 +51,7 @@ class StubGlRenderingProvider : public graphics::GLRenderingProvider } auto surface_for_output( - std::shared_ptr, + graphics::DisplayBuffer&, geometry::Size, graphics::GLConfig const&) -> std::unique_ptr override { @@ -64,13 +64,13 @@ class StubGlRenderingProvider : public graphics::GLRenderingProvider return graphics::probe::supported; } - auto suitability_for_display(std::shared_ptr const& /*target*/) + auto suitability_for_display(graphics::DisplayBuffer& /*target*/) -> graphics::probe::Result override { return graphics::probe::dummy; } - auto make_framebuffer_provider(std::shared_ptr /*target*/) + auto make_framebuffer_provider(graphics::DisplayBuffer& /*target*/) -> std::unique_ptr override { class NullFramebufferProvider : public FramebufferProvider diff --git a/tests/mir_test_doubles/mock_drm.cpp b/tests/mir_test_doubles/mock_drm.cpp index a96b05d04fd..1924d214ad3 100644 --- a/tests/mir_test_doubles/mock_drm.cpp +++ b/tests/mir_test_doubles/mock_drm.cpp @@ -408,6 +408,14 @@ mtd::MockDRM::MockDRM() mmapings.erase(iter); return 0; }))); + + ON_CALL(*this, drmGetCap(_, DRM_CAP_DUMB_BUFFER, _)) + .WillByDefault( + [](auto, auto, uint64_t* value) + { + *value = 1; + return 0; + }); } mtd::MockDRM::~MockDRM() noexcept diff --git a/tests/mir_test_framework/headless_display_buffer_compositor_factory.cpp b/tests/mir_test_framework/headless_display_buffer_compositor_factory.cpp index 2bb1b42d8e4..9c8a8728893 100644 --- a/tests/mir_test_framework/headless_display_buffer_compositor_factory.cpp +++ b/tests/mir_test_framework/headless_display_buffer_compositor_factory.cpp @@ -121,6 +121,6 @@ mtf::HeadlessDisplayBufferCompositorFactory::create_compositor_for(mg::DisplayBu std::shared_ptr const tracker; }; auto output_surface = - render_platform->surface_for_output(db.display_provider(), db.pixel_size(), *gl_config); + render_platform->surface_for_output(db, db.pixel_size(), *gl_config); return std::make_unique(db, std::move(output_surface), render_platform, tracker); } diff --git a/tests/mir_test_framework/platform_graphics_dummy.cpp b/tests/mir_test_framework/platform_graphics_dummy.cpp index e376d9aa0db..f9e83101fd3 100644 --- a/tests/mir_test_framework/platform_graphics_dummy.cpp +++ b/tests/mir_test_framework/platform_graphics_dummy.cpp @@ -45,7 +45,7 @@ auto probe_display_platform( } auto probe_rendering_platform( - std::span> const&, + std::span> const&, mir::ConsoleServices&, std::shared_ptr const&, mir::options::ProgramOption const&) -> std::vector diff --git a/tests/mir_test_framework/platform_graphics_throw.cpp b/tests/mir_test_framework/platform_graphics_throw.cpp index c1af57c1d7a..779e1e5a605 100644 --- a/tests/mir_test_framework/platform_graphics_throw.cpp +++ b/tests/mir_test_framework/platform_graphics_throw.cpp @@ -62,14 +62,15 @@ class ExceptionThrowingPlatform : public mg::DisplayPlatform, public mg::Renderi protected: auto maybe_create_provider( - mir::graphics::RenderingProvider::Tag const&) -> std::shared_ptr override + mg::RenderingProvider::Tag const&) -> std::shared_ptr override { return nullptr; } - auto interface_for() -> std::shared_ptr override + auto maybe_create_provider(mg::DisplayProvider::Tag const&) + -> std::shared_ptr override { - return mg::DisplayPlatform::interface_for(stub_display_platform); + return nullptr; } public: @@ -144,7 +145,7 @@ auto probe_display_platform( } auto probe_rendering_platform( - std::span> const&, + std::span> const&, mir::ConsoleServices&, std::shared_ptr const&, mir::options::ProgramOption const&) -> std::vector @@ -181,7 +182,7 @@ void add_graphics_platform_options(boost::program_options::options_description&) mir::UniqueModulePtr create_rendering_platform( mg::SupportedDevice const&, - std::vector> const&, + std::vector> const&, mo::Option const&, mir::EmergencyCleanupRegistry&) { diff --git a/tests/mir_test_framework/stubbed_graphics_platform.cpp b/tests/mir_test_framework/stubbed_graphics_platform.cpp index fbef382dad2..a82612e5fd2 100644 --- a/tests/mir_test_framework/stubbed_graphics_platform.cpp +++ b/tests/mir_test_framework/stubbed_graphics_platform.cpp @@ -100,19 +100,10 @@ auto mtf::StubGraphicPlatform::maybe_create_provider( return nullptr; } -auto mtf::StubGraphicPlatform::interface_for() - -> std::shared_ptr +auto mtf::StubGraphicPlatform::maybe_create_provider(mg::DisplayProvider::Tag const&) + -> std::shared_ptr { - class NullInterfaceProvider : public mg::DisplayInterfaceProvider - { - protected: - auto maybe_create_interface(mg::DisplayProvider::Tag const&) - -> std::shared_ptr - { - return nullptr; - } - }; - return std::make_shared(); + return nullptr; } namespace @@ -162,7 +153,7 @@ mir::UniqueModulePtr create_display_platform( mir::UniqueModulePtr create_rendering_platform( mg::SupportedDevice const&, - std::vector> const&, + std::vector> const&, mo::Option const&, mir::EmergencyCleanupRegistry&) { diff --git a/tests/mir_test_framework/stubbed_graphics_platform.h b/tests/mir_test_framework/stubbed_graphics_platform.h index f045c176b33..bfc4ac67fef 100644 --- a/tests/mir_test_framework/stubbed_graphics_platform.h +++ b/tests/mir_test_framework/stubbed_graphics_platform.h @@ -40,8 +40,9 @@ class StubGraphicPlatform : mir::graphics::RenderingProvider::Tag const& tag) -> std::shared_ptr override; - auto interface_for() - -> std::shared_ptr override; + auto maybe_create_provider( + mir::graphics::DisplayProvider::Tag const& tag) + -> std::shared_ptr override; private: std::vector const display_rects; }; diff --git a/tests/unit-tests/compositor/test_basic_screen_shooter.cpp b/tests/unit-tests/compositor/test_basic_screen_shooter.cpp index 0a521bb313a..f6d199d86b2 100644 --- a/tests/unit-tests/compositor/test_basic_screen_shooter.cpp +++ b/tests/unit-tests/compositor/test_basic_screen_shooter.cpp @@ -16,6 +16,7 @@ #include "mir/executor.h" #include "mir/graphics/platform.h" +#include "mir/graphics/display_buffer.h" #include "mir/renderer/gl/gl_surface.h" #include "mir/test/doubles/stub_gl_rendering_provider.h" #include "src/server/compositor/basic_screen_shooter.h" @@ -79,10 +80,10 @@ struct BasicScreenShooter : Test }); ON_CALL(*gl_provider, surface_for_output(_, _, _)) .WillByDefault( - [](std::shared_ptr provider, auto size, auto const&) + [](mg::DisplayBuffer& output, auto size, auto const&) -> std::unique_ptr { - if (auto cpu_provider = provider->acquire_interface()) + if (auto cpu_provider = output.acquire_allocator()) { auto surface = std::make_unique>(); auto format = cpu_provider->supported_formats().front(); @@ -209,7 +210,7 @@ TEST_F(BasicScreenShooter, throw_in_scene_elements_for_causes_graceful_failure) TEST_F(BasicScreenShooter, throw_in_surface_for_output_handled_gracefully) { ON_CALL(*gl_provider, surface_for_output).WillByDefault( - [](auto, auto, auto&) -> std::unique_ptr + [](auto&, auto, auto&) -> std::unique_ptr { BOOST_THROW_EXCEPTION((std::runtime_error{"Throw in surface_for_output"})); }); diff --git a/tests/unit-tests/platforms/gbm-kms/kms/test_display_buffer.cpp b/tests/unit-tests/platforms/gbm-kms/kms/test_display_buffer.cpp index 7b89dd281da..6d31269a2b6 100644 --- a/tests/unit-tests/platforms/gbm-kms/kms/test_display_buffer.cpp +++ b/tests/unit-tests/platforms/gbm-kms/kms/test_display_buffer.cpp @@ -95,7 +95,7 @@ class MesaDisplayBufferTest : public Test }, bypass_framebuffer} } - , parent_platform{nullptr} + , gbm{nullptr} { ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), @@ -173,14 +173,14 @@ class MesaDisplayBufferTest : public Test StubGLConfig gl_config; std::shared_ptr const bypass_framebuffer; std::vector const bypassable_list; - std::shared_ptr const parent_platform; + std::shared_ptr const gbm; }; TEST_F(MesaDisplayBufferTest, unrotated_view_area_is_untouched) { graphics::gbm::DisplayBuffer db( - parent_platform, drm_fd, + gbm, graphics::gbm::BypassOption::allowed, null_display_report(), {mock_kms_output}, @@ -201,8 +201,8 @@ TEST_F(MesaDisplayBufferTest, frames_requiring_gl_are_not_throttled) }; graphics::gbm::DisplayBuffer db( - parent_platform, drm_fd, + gbm, graphics::gbm::BypassOption::allowed, null_display_report(), {mock_kms_output}, @@ -222,8 +222,8 @@ TEST_F(MesaDisplayBufferTest, frames_requiring_gl_are_not_throttled) TEST_F(MesaDisplayBufferTest, untransformed_with_bypassable_list_can_bypass) { graphics::gbm::DisplayBuffer db( - parent_platform, drm_fd, + gbm, graphics::gbm::BypassOption::allowed, null_display_report(), {mock_kms_output}, @@ -247,8 +247,8 @@ TEST_F(MesaDisplayBufferTest, transformation_not_implemented_internally) glm::mat2 const rotate_left = transformation(mir_orientation_left); graphics::gbm::DisplayBuffer db( - parent_platform, drm_fd, + gbm, graphics::gbm::BypassOption::allowed, null_display_report(), {mock_kms_output}, diff --git a/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp b/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp index 8817538fad7..e3d352b9a7f 100644 --- a/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp +++ b/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp @@ -161,7 +161,7 @@ class MesaDisplayMultiMonitorTest : public ::testing::Test // Caution: non-local state! // This works because standard-drm-devices contains a udev device with 226:0 and devnode /dev/dri/card0 auto device = ctx.char_device_from_devnum(makedev(226, 0)); - + return std::make_shared( *device, mir::report::null_display_report(), @@ -371,15 +371,15 @@ TEST_F(MesaDisplayMultiMonitorTest, flip_flips_all_connected_crtcs) auto platform = create_platform(); auto display = create_display_cloned(platform); - auto provider = mg::DisplayPlatform::interface_for(std::move(platform))->acquire_interface(); /* First frame: Page flips are scheduled, but not waited for */ display->for_each_display_sync_group( - [provider](mg::DisplaySyncGroup& group) + [](mg::DisplaySyncGroup& group) { group.for_each_display_buffer( - [provider](mg::DisplayBuffer& db) + [](mg::DisplayBuffer& db) { + auto provider = db.acquire_allocator(); auto fb = provider->alloc_fb(db.pixel_size(), mg::DRMFormat{DRM_FORMAT_ABGR8888}); db.set_next_image(std::move(fb)); }); @@ -389,11 +389,12 @@ TEST_F(MesaDisplayMultiMonitorTest, flip_flips_all_connected_crtcs) /* Second frame: Previous page flips finish (drmHandleEvent) and new ones are scheduled */ display->for_each_display_sync_group( - [provider](mg::DisplaySyncGroup& group) + [](mg::DisplaySyncGroup& group) { group.for_each_display_buffer( - [provider](mg::DisplayBuffer& db) + [](mg::DisplayBuffer& db) { + auto provider = db.acquire_allocator(); auto fb = provider->alloc_fb(db.pixel_size(), mg::DRMFormat{DRM_FORMAT_ARGB8888}); db.set_next_image(std::move(fb)); }); diff --git a/tests/unit-tests/platforms/virtual/test_platform.cpp b/tests/unit-tests/platforms/virtual/test_platform.cpp index d71fe4bf6c8..4cde61180ac 100644 --- a/tests/unit-tests/platforms/virtual/test_platform.cpp +++ b/tests/unit-tests/platforms/virtual/test_platform.cpp @@ -71,8 +71,7 @@ TEST_F(VirtualGraphicsPlatformTest, multiple_output_sizes_are_set_correctly_when TEST_F(VirtualGraphicsPlatformTest, can_acquire_interface_for_cpu_addressable_display_provider) { auto platform = create_platform(); - auto interface = mg::DisplayPlatform::interface_for(platform); - EXPECT_TRUE(interface->acquire_interface() != nullptr); + EXPECT_TRUE(platform->acquire_provider() != nullptr); } TEST_F(VirtualGraphicsPlatformTest, output_size_parsing_throws_on_bad_input) diff --git a/tests/unit-tests/platforms/x11/test_display.cpp b/tests/unit-tests/platforms/x11/test_display.cpp index 5f95e4232bc..9f1a4069a25 100644 --- a/tests/unit-tests/platforms/x11/test_display.cpp +++ b/tests/unit-tests/platforms/x11/test_display.cpp @@ -101,8 +101,8 @@ class X11DisplayTest : public ::testing::Test std::shared_ptr create_display() { return std::make_shared( - nullptr, mt::fake_shared(x11_resources), + nullptr, "Mir on X", sizes, mt::fake_shared(null_display_configuration_policy),