diff options
Diffstat (limited to 'chromium/ui/ozone/platform/drm/gpu')
39 files changed, 1387 insertions, 481 deletions
diff --git a/chromium/ui/ozone/platform/drm/gpu/DEPS b/chromium/ui/ozone/platform/drm/gpu/DEPS index 3fb5fa6f6a3..a4e9f0a5006 100644 --- a/chromium/ui/ozone/platform/drm/gpu/DEPS +++ b/chromium/ui/ozone/platform/drm/gpu/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+media/media_buildflags.h", "-ui/ozone/platform/drm", "+ui/ozone/platform/drm/common", "+ui/ozone/platform/drm/gpu", diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc index 8127e1633f2..6f4c17b6fa9 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc @@ -9,6 +9,7 @@ namespace ui { CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id, uint32_t connector_id, drmModeModeInfo mode, + gfx::Point origin, HardwareDisplayPlaneList* plane_list, DrmOverlayPlaneList overlays, bool should_enable) @@ -16,8 +17,11 @@ CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id, crtc_id_(crtc_id), connector_id_(connector_id), mode_(mode), + origin_(origin), plane_list_(plane_list), overlays_(std::move(overlays)) { + // Verify that at least one overlay plane is a primary plane if we're enabling + // a CRTC. DCHECK(!should_enable || DrmOverlayPlane::GetPrimaryPlane(overlays_)); } @@ -28,6 +32,7 @@ CrtcCommitRequest::CrtcCommitRequest(const CrtcCommitRequest& other) crtc_id_(other.crtc_id_), connector_id_(other.connector_id_), mode_(other.mode_), + origin_(other.origin_), plane_list_(other.plane_list_), overlays_(DrmOverlayPlane::Clone(other.overlays_)) {} @@ -36,11 +41,12 @@ CrtcCommitRequest CrtcCommitRequest::EnableCrtcRequest( uint32_t crtc_id, uint32_t connector_id, drmModeModeInfo mode, + gfx::Point origin, HardwareDisplayPlaneList* plane_list, DrmOverlayPlaneList overlays) { DCHECK(plane_list && !overlays.empty()); - return CrtcCommitRequest(crtc_id, connector_id, mode, plane_list, + return CrtcCommitRequest(crtc_id, connector_id, mode, origin, plane_list, std::move(overlays), /*should_enable=*/true); } @@ -49,7 +55,7 @@ CrtcCommitRequest CrtcCommitRequest::DisableCrtcRequest( uint32_t crtc_id, uint32_t connector_id, HardwareDisplayPlaneList* plane_list) { - return CrtcCommitRequest(crtc_id, connector_id, {}, plane_list, + return CrtcCommitRequest(crtc_id, connector_id, {}, gfx::Point(), plane_list, DrmOverlayPlaneList(), /*should_enable=*/false); } diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h index ad8eab84e7f..f3597f3bb31 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h @@ -9,6 +9,7 @@ #include <stdint.h> #include <xf86drmMode.h> +#include "ui/gfx/geometry/point.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h" @@ -31,6 +32,7 @@ class CrtcCommitRequest { uint32_t crtc_id, uint32_t connector_id, drmModeModeInfo mode, + gfx::Point origin, HardwareDisplayPlaneList* plane_list, DrmOverlayPlaneList overlays); @@ -43,6 +45,7 @@ class CrtcCommitRequest { uint32_t crtc_id() const { return crtc_id_; } uint32_t connector_id() const { return connector_id_; } const drmModeModeInfo& mode() const { return mode_; } + const gfx::Point& origin() const { return origin_; } HardwareDisplayPlaneList* plane_list() const { return plane_list_; } const DrmOverlayPlaneList& overlays() const { return overlays_; } @@ -50,6 +53,7 @@ class CrtcCommitRequest { CrtcCommitRequest(uint32_t crtc_id, uint32_t connector_id, drmModeModeInfo mode, + gfx::Point origin, HardwareDisplayPlaneList* plane_list, DrmOverlayPlaneList overlays, bool should_enable); @@ -58,6 +62,7 @@ class CrtcCommitRequest { const uint32_t crtc_id_ = 0; const uint32_t connector_id_ = 0; const drmModeModeInfo mode_ = {}; + const gfx::Point origin_; HardwareDisplayPlaneList* plane_list_ = nullptr; const DrmOverlayPlaneList overlays_; }; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc index cc5e8c5f213..6e262e27bbb 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc @@ -308,9 +308,15 @@ bool DrmDevice::SetCrtc(uint32_t crtc_id, TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size", gfx::Size(mode.hdisplay, mode.vdisplay).ToString()); - return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, - connectors.data(), connectors.size(), - const_cast<drmModeModeInfo*>(&mode)); + + if (!drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, + connectors.data(), connectors.size(), + const_cast<drmModeModeInfo*>(&mode))) { + ++modeset_sequence_id_; + return true; + } + + return false; } bool DrmDevice::DisableCrtc(uint32_t crtc_id) { @@ -540,14 +546,45 @@ bool DrmDevice::CommitProperties( uint32_t flags, uint32_t crtc_count, scoped_refptr<PageFlipRequest> page_flip_request) { + bool success = CommitPropertiesInternal(properties, flags, crtc_count, + page_flip_request); + + if (success && flags == DRM_MODE_ATOMIC_ALLOW_MODESET) + ++modeset_sequence_id_; + + return success; +} + +bool DrmDevice::CommitPropertiesInternal( + drmModeAtomicReq* properties, + uint32_t flags, + uint32_t crtc_count, + scoped_refptr<PageFlipRequest> page_flip_request) { uint64_t id = 0; + if (page_flip_request) { flags |= DRM_MODE_PAGE_FLIP_EVENT; id = page_flip_manager_->GetNextId(); } - if (!drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags, - reinterpret_cast<void*>(id))) { + int result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags, + reinterpret_cast<void*>(id)); + if (result && errno == EBUSY && (flags & DRM_MODE_ATOMIC_NONBLOCK)) { + VLOG(1) << "Nonblocking atomic commit failed with EBUSY, retry without " + "nonblock"; + // There have been cases where we get back EBUSY when attempting a + // non-blocking atomic commit. If we return false from here, that will cause + // the GPU process to CHECK itself. These are likely due to kernel bugs, + // which should be fixed, but rather than crashing we should retry the + // commit without the non-blocking flag and then it should work. This will + // cause a slight delay, but that should be imperceptible and better than + // crashing. We still do want the underlying driver bugs fixed, but this + // provide a better user experience. + flags &= ~DRM_MODE_ATOMIC_NONBLOCK; + result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags, + reinterpret_cast<void*>(id)); + } + if (!result) { if (page_flip_request) { page_flip_manager_->RegisterCallback(id, crtc_count, page_flip_request->AddPageFlip()); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.h b/chromium/ui/ozone/platform/drm/gpu/drm_device.h index fdc7f2d0a38..400c9a80e66 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_device.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.h @@ -215,11 +215,10 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { // On success, true is returned and |page_flip_request| will receive a // callback signalling completion of the flip, if provided. - virtual bool CommitProperties( - drmModeAtomicReq* properties, - uint32_t flags, - uint32_t crtc_count, - scoped_refptr<PageFlipRequest> page_flip_request); + bool CommitProperties(drmModeAtomicReq* properties, + uint32_t flags, + uint32_t crtc_count, + scoped_refptr<PageFlipRequest> page_flip_request); virtual bool SetCapability(uint64_t capability, uint64_t value); @@ -230,6 +229,8 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { virtual bool SetMaster(); virtual bool DropMaster(); + int modeset_sequence_id() const { return modeset_sequence_id_; } + int get_fd() const { return file_.GetPlatformFile(); } base::FilePath device_path() const { return device_path_; } @@ -244,8 +245,19 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { virtual ~DrmDevice(); + virtual bool CommitPropertiesInternal( + drmModeAtomicReq* properties, + uint32_t flags, + uint32_t crtc_count, + scoped_refptr<PageFlipRequest> page_flip_request); + std::unique_ptr<HardwareDisplayPlaneManager> plane_manager_; + // Sequence ID incremented at each modeset. + // Currently used by DRM Framebuffer to indicate when was the fb initialized + // wrt the preceding modeset. + int modeset_sequence_id_ = 0; + private: class IOWatcher; class PageFlipManager; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc index 4f84ef488cf..b1ccd606e67 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/stl_util.h" #include "base/trace_event/trace_event.h" +#include "build/chromeos_buildflags.h" #include "ui/display/display_features.h" #include "ui/display/types/display_snapshot.h" #include "ui/display/types/gamma_ramp_rgb_entry.h" @@ -156,7 +157,7 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update( modes_ = GetDrmModeVector(info->connector()); is_hdr_capable_ = params->bits_per_channel() > 8 && params->color_space().IsHDR(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) is_hdr_capable_ = is_hdr_capable_ && base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc index bdf7db0ec19..4eb71a4d0f7 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc @@ -113,7 +113,8 @@ DrmFramebuffer::DrmFramebuffer(scoped_refptr<DrmDevice> drm_device, opaque_framebuffer_pixel_format_(opaque_framebuffer_pixel_format), format_modifier_(format_modifier), preferred_modifiers_(modifiers), - size_(size) {} + size_(size), + modeset_sequence_id_at_allocation_(drm_device_->modeset_sequence_id()) {} DrmFramebuffer::~DrmFramebuffer() { if (!drm_device_->RemoveFramebuffer(framebuffer_id_)) diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h index 079297ac1a7..8dbfe7f2bd4 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h @@ -92,6 +92,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> { // Device on which the buffer was created. const scoped_refptr<DrmDevice>& drm_device() const { return drm_device_; } + int modeset_sequence_id_at_allocation() const { + return modeset_sequence_id_at_allocation_; + } + private: ~DrmFramebuffer(); @@ -110,6 +114,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> { const std::vector<uint64_t> preferred_modifiers_; const gfx::Size size_; + // The latest modeset sequence ID that was retrieved from DrmDevice when the + // buffer is initialized. + const int modeset_sequence_id_at_allocation_ = 0; + friend class base::RefCountedThreadSafe<DrmFramebuffer>; }; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc index 8fdb11aba63..bd67bd3d60a 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc @@ -166,9 +166,8 @@ void DrmGpuDisplayManager::RelinquishDisplayControl() { drm->DropMaster(); } -base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays( +bool DrmGpuDisplayManager::ConfigureDisplays( const std::vector<display::DisplayConfigurationParams>& config_requests) { - base::flat_map<int64_t, bool> statuses; ScreenManager::ControllerConfigsList controllers_to_configure; for (const auto& config : config_requests) { @@ -176,8 +175,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays( DrmDisplay* display = FindDisplay(display_id); if (!display) { LOG(ERROR) << "There is no display with ID " << display_id; - statuses.insert(std::make_pair(display_id, false)); - continue; + return false; } std::unique_ptr<drmModeModeInfo> mode_ptr = @@ -185,8 +183,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays( if (config.mode) { if (!FindModeForDisplay(mode_ptr.get(), *config.mode.value(), display->modes(), displays_)) { - statuses.insert(std::make_pair(display_id, false)); - continue; + return false; } } @@ -205,41 +202,30 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays( controllers_to_configure.push_back(std::move(params)); } - if (controllers_to_configure.empty()) - return statuses; - if (clear_overlay_cache_callback_) clear_overlay_cache_callback_.Run(); - auto config_statuses = + bool config_success = screen_manager_->ConfigureDisplayControllers(controllers_to_configure); - for (const auto& status : config_statuses) { - int64_t display_id = status.first; - bool success = status.second; - DrmDisplay* display = FindDisplay(display_id); - auto config = std::find_if( - config_requests.begin(), config_requests.end(), - [display_id](const auto& request) { return request.id == display_id; }); - if (success) { - display->SetOrigin(config->origin); + for (const auto& controller : controllers_to_configure) { + if (config_success) { + FindDisplay(controller.display_id)->SetOrigin(controller.origin); } else { - if (config->mode) { + if (controller.mode) { VLOG(1) << "Failed to enable device=" - << display->drm()->device_path().value() - << " crtc=" << display->crtc() - << " connector=" << display->connector(); + << controller.drm->device_path().value() + << " crtc=" << controller.crtc + << " connector=" << controller.connector; } else { VLOG(1) << "Failed to disable device=" - << display->drm()->device_path().value() - << " crtc=" << display->crtc(); + << controller.drm->device_path().value() + << " crtc=" << controller.crtc; } } - - statuses.insert(std::make_pair(display_id, success)); } - return statuses; + return config_success; } bool DrmGpuDisplayManager::GetHDCPState( diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h index 2dbe2ba68a4..5bbdc84144e 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h @@ -52,7 +52,7 @@ class DrmGpuDisplayManager { bool TakeDisplayControl(); void RelinquishDisplayControl(); - base::flat_map<int64_t, bool> ConfigureDisplays( + bool ConfigureDisplays( const std::vector<display::DisplayConfigurationParams>& config_requests); bool GetHDCPState(int64_t display_id, display::HDCPState* state, diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc index 231d1728494..928ad048588 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc @@ -40,7 +40,10 @@ std::vector<OverlaySurfaceCandidate> ToCacheKey( } // namespace -DrmOverlayManager::DrmOverlayManager() { +DrmOverlayManager::DrmOverlayManager( + bool allow_sync_and_real_buffer_page_flip_testing) { + allow_sync_and_real_buffer_page_flip_testing_ = + allow_sync_and_real_buffer_page_flip_testing; DETACH_FROM_THREAD(thread_checker_); } @@ -79,7 +82,8 @@ void DrmOverlayManager::CheckOverlaySupport( result_candidates.back().overlay_handled = can_handle; } - if (features::IsSynchronousPageFlipTestingEnabled()) { + if (allow_sync_and_real_buffer_page_flip_testing_ && + features::IsSynchronousPageFlipTestingEnabled()) { std::vector<OverlayStatus> status = SendOverlayValidationRequestSync(result_candidates, widget); size_t size = candidates->size(); @@ -145,6 +149,11 @@ bool DrmOverlayManager::CanHandleCandidate( if (candidate.transform == gfx::OVERLAY_TRANSFORM_INVALID) return false; + // The remaining checks are for ensuring consistency between GL compositing + // and overlays. If we must use an overlay, then skip the remaining checks. + if (candidate.requires_overlay) + return true; + // Reject candidates that don't fall on a pixel boundary. if (!gfx::IsNearestRectWithinDistance(candidate.display_rect, 0.01f)) return false; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h index 87173fa824a..56112a3f508 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h @@ -23,7 +23,8 @@ class OverlaySurfaceCandidate; // of recent configurations. class DrmOverlayManager : public OverlayManagerOzone { public: - DrmOverlayManager(); + explicit DrmOverlayManager( + bool allow_sync_and_real_buffer_page_flip_testing = true); ~DrmOverlayManager() override; // OverlayManagerOzone: diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc index 2137523fbd8..89c86a5f80e 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc @@ -8,13 +8,17 @@ #include "base/bind.h" #include "base/trace_event/trace_event.h" +#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h" #include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h" #include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { -DrmOverlayManagerGpu::DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy) - : drm_thread_proxy_(drm_thread_proxy) {} +DrmOverlayManagerGpu::DrmOverlayManagerGpu( + DrmThreadProxy* drm_thread_proxy, + bool allow_sync_and_real_buffer_page_flip_testing) + : DrmOverlayManager(allow_sync_and_real_buffer_page_flip_testing), + drm_thread_proxy_(drm_thread_proxy) {} DrmOverlayManagerGpu::~DrmOverlayManagerGpu() = default; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h index 3931e02dac5..cb759538344 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h @@ -18,7 +18,9 @@ class DrmThreadProxy; // overlay validations requests to the DRM thread. class DrmOverlayManagerGpu : public DrmOverlayManager { public: - explicit DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy); + explicit DrmOverlayManagerGpu( + DrmThreadProxy* drm_thread_proxy, + bool allow_sync_and_real_buffer_page_flip_testing); ~DrmOverlayManagerGpu() override; private: diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc index 4c496547411..348cba77ec8 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc @@ -46,7 +46,7 @@ scoped_refptr<DrmFramebuffer> GetBufferForPageFlipTest( // flip commits. std::vector<uint64_t> modifiers = is_0th_plane - ? drm_window->GetController()->GetFormatModifiers(fourcc_format) + ? drm_window->GetController()->GetSupportedModifiers(fourcc_format) : std::vector<uint64_t>(); // Check if we can re-use existing buffers. diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc index 76577c6e485..f5938777c47 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc @@ -81,15 +81,16 @@ class DrmOverlayValidatorTest : public testing::Test { bool ModesetController(ui::HardwareDisplayController* controller) { ui::CommitRequest commit_request; - ui::DrmOverlayPlane plane(CreateBuffer(), nullptr); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); - controller->GetModesetProps(&commit_request, plane, kDefaultMode); + controller->GetModesetProps(&commit_request, modeset_planes, kDefaultMode); ui::CommitRequest request_for_update = commit_request; bool status = drm_->plane_manager()->Commit(std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET); - controller->UpdateState( - /*enable_requested=*/true, - ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays())); + + for (const ui::CrtcCommitRequest& crtc_request : commit_request) + controller->UpdateState(crtc_request); return status; } diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc index d77131c3dfc..115231c7d02 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc @@ -142,7 +142,7 @@ void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget, std::vector<uint64_t> modifiers; if (window && window->GetController() && !(flags & GBM_BO_USE_LINEAR) && !(client_flags & GbmPixmap::kFlagNoModifiers)) { - modifiers = window->GetController()->GetFormatModifiers(fourcc_format); + modifiers = window->GetController()->GetSupportedModifiers(fourcc_format); } CreateBufferWithGbmFlags(drm, fourcc_format, size, framebuffer_size, flags, @@ -328,13 +328,11 @@ void DrmThread::RefreshNativeDisplays( void DrmThread::ConfigureNativeDisplays( const std::vector<display::DisplayConfigurationParams>& config_requests, - base::OnceCallback<void(const base::flat_map<int64_t, bool>&)> callback) { + base::OnceCallback<void(bool)> callback) { TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplays"); - base::flat_map<int64_t, bool> statuses = - display_manager_->ConfigureDisplays(config_requests); - - std::move(callback).Run(statuses); + bool config_success = display_manager_->ConfigureDisplays(config_requests); + std::move(callback).Run(config_success); } void DrmThread::TakeDisplayControl(base::OnceCallback<void(bool)> callback) { diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc index fa04ef64c35..f2774c1e4aa 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/bind.h" +#include "base/threading/thread_restrictions.h" #include "base/trace_event/trace_event.h" #include "ui/gfx/linux/gbm_wrapper.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc index ec3aa6b951d..d83a4f53d8b 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc @@ -31,11 +31,9 @@ DrmWindow::DrmWindow(gfx::AcceleratedWidget widget, ScreenManager* screen_manager) : widget_(widget), device_manager_(device_manager), - screen_manager_(screen_manager) { -} + screen_manager_(screen_manager) {} -DrmWindow::~DrmWindow() { -} +DrmWindow::~DrmWindow() {} void DrmWindow::Initialize() { TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_); @@ -133,10 +131,6 @@ OverlayStatusList DrmWindow::TestPageFlip( last_submitted_planes_); } -const DrmOverlayPlane* DrmWindow::GetLastModesetBuffer() const { - return DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes_); -} - void DrmWindow::UpdateCursorImage() { if (!controller_) return; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.h b/chromium/ui/ozone/platform/drm/gpu/drm_window.h index ea2a2721408..ea1ef54b324 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_window.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.h @@ -84,8 +84,9 @@ class DrmWindow { OverlayStatusList TestPageFlip( const OverlaySurfaceCandidateList& overlay_params); - // Returns the last buffer associated with this window. - const DrmOverlayPlane* GetLastModesetBuffer() const; + const DrmOverlayPlaneList& last_submitted_planes() const { + return last_submitted_planes_; + } private: // Draw next frame in an animated cursor. diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc index 163a89f699c..2fdc72f9a49 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc @@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/strings/stringprintf.h" +#include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "third_party/khronos/EGL/egl.h" #include "ui/gfx/buffer_format_util.h" @@ -20,6 +21,7 @@ #include "ui/gfx/linux/gbm_defines.h" #include "ui/gfx/linux/scoped_gbm_device.h" #include "ui/gfx/native_pixmap.h" +#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_egl.h" #include "ui/ozone/common/egl_util.h" #include "ui/ozone/common/gl_ozone_egl.h" @@ -275,8 +277,11 @@ GLOzone* GbmSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) { #if BUILDFLAG(ENABLE_VULKAN) std::unique_ptr<gpu::VulkanImplementation> -GbmSurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory, +GbmSurfaceFactory::CreateVulkanImplementation(bool use_swiftshader, + bool allow_protected_memory, bool enforce_protected_memory) { + DCHECK(!use_swiftshader) + << "Vulkan Swiftshader is not supported on this platform."; return std::make_unique<ui::VulkanImplementationGbm>(); } diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h index 4ac05739713..4aa40139d7d 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h @@ -39,6 +39,7 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone { #if BUILDFLAG(ENABLE_VULKAN) std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation( + bool use_swiftshader, bool allow_protected_memory, bool enforce_protected_memory) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmapForVulkan( diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 664381d52a2..67cb75493b6 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc @@ -15,12 +15,17 @@ #include "base/trace_event/trace_event.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/presentation_feedback.h" +#include "ui/gl/gl_bindings.h" #include "ui/ozone/common/egl_util.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h" #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h" #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h" +#if BUILDFLAG(USE_OPENGL_APITRACE) +#include "ui/gl/gl_implementation.h" +#endif + namespace ui { namespace { @@ -133,6 +138,10 @@ void GbmSurfaceless::SwapBuffersAsync( glFlush(); } +#if BUILDFLAG(USE_OPENGL_APITRACE) + gl::TerminateFrame(); // Notify end of frame at buffer swap request. +#endif + unsubmitted_frames_.back()->Flush(); PendingFrame* frame = unsubmitted_frames_.back().get(); diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc index 47a684e7d22..ed387cbc7dc 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc @@ -16,9 +16,11 @@ #include "base/trace_event/trace_event.h" #include "third_party/libdrm/src/include/drm/drm_fourcc.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkImage.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_fence.h" +#include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/native_pixmap.h" #include "ui/gfx/presentation_feedback.h" #include "ui/gfx/swap_result.h" @@ -58,7 +60,7 @@ void DrawCursor(DrmDumbBuffer* cursor, const SkBitmap& image) { // Clear to transparent in case |image| is smaller than the canvas. SkCanvas* canvas = cursor->GetCanvas(); canvas->clear(SK_ColorTRANSPARENT); - canvas->drawBitmapRect(image, damage, nullptr); + canvas->drawImageRect(image.asImage(), damage, SkSamplingOptions()); } } // namespace @@ -73,26 +75,26 @@ HardwareDisplayController::HardwareDisplayController( HardwareDisplayController::~HardwareDisplayController() = default; -void HardwareDisplayController::GetModesetProps(CommitRequest* commit_request, - const DrmOverlayPlane& primary, - const drmModeModeInfo& mode) { - TRACE_EVENT0("drm", "HDC::GetModesetProps"); - GetModesetPropsForCrtcs(commit_request, primary, +void HardwareDisplayController::GetModesetProps( + CommitRequest* commit_request, + const DrmOverlayPlaneList& modeset_planes, + const drmModeModeInfo& mode) { + GetModesetPropsForCrtcs(commit_request, modeset_planes, /*use_current_crtc_mode=*/false, mode); } -void HardwareDisplayController::GetEnableProps(CommitRequest* commit_request, - const DrmOverlayPlane& primary) { - TRACE_EVENT0("drm", "HDC::GetEnableProps"); +void HardwareDisplayController::GetEnableProps( + CommitRequest* commit_request, + const DrmOverlayPlaneList& modeset_planes) { // TODO(markyacoub): Simplify and remove the use of empty_mode. drmModeModeInfo empty_mode = {}; - GetModesetPropsForCrtcs(commit_request, primary, + GetModesetPropsForCrtcs(commit_request, modeset_planes, /*use_current_crtc_mode=*/true, empty_mode); } void HardwareDisplayController::GetModesetPropsForCrtcs( CommitRequest* commit_request, - const DrmOverlayPlane& primary, + const DrmOverlayPlaneList& modeset_planes, bool use_current_crtc_mode, const drmModeModeInfo& mode) { DCHECK(commit_request); @@ -103,19 +105,16 @@ void HardwareDisplayController::GetModesetPropsForCrtcs( drmModeModeInfo modeset_mode = use_current_crtc_mode ? controller->mode() : mode; - DrmOverlayPlaneList overlays; - overlays.push_back(primary.Clone()); + DrmOverlayPlaneList overlays = DrmOverlayPlane::Clone(modeset_planes); CrtcCommitRequest request = CrtcCommitRequest::EnableCrtcRequest( - controller->crtc(), controller->connector(), modeset_mode, + controller->crtc(), controller->connector(), modeset_mode, origin_, &owned_hardware_planes_, std::move(overlays)); commit_request->push_back(std::move(request)); } } void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) { - TRACE_EVENT0("drm", "HDC::GetDisableProps"); - for (const auto& controller : crtc_controllers_) { CrtcCommitRequest request = CrtcCommitRequest::DisableCrtcRequest( controller->crtc(), controller->connector(), &owned_hardware_planes_); @@ -124,14 +123,13 @@ void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) { } void HardwareDisplayController::UpdateState( - bool enable_requested, - const DrmOverlayPlane* primary_plane) { + const CrtcCommitRequest& crtc_request) { // Verify that the current state matches the requested state. - if (enable_requested && IsEnabled()) { - DCHECK(primary_plane); + if (crtc_request.should_enable() && IsEnabled()) { + DCHECK(!crtc_request.overlays().empty()); // TODO(markyacoub): This should be absorbed in the commit request. ResetCursor(); - OnModesetComplete(*primary_plane); + OnModesetComplete(crtc_request.overlays()); } } @@ -146,6 +144,24 @@ void HardwareDisplayController::SchedulePageFlip( bool status = ScheduleOrTestPageFlip(plane_list, page_flip_request, &out_fence); + if (!status) { + for (const auto& plane : plane_list) { + // If the page flip failed and we see that the buffer has been allocated + // before the latest modeset, it could mean it was an in-flight buffer + // carrying an obsolete configuration. + // Request a buffer reallocation to reflect the new change. + if (plane.buffer && + plane.buffer->modeset_sequence_id_at_allocation() < + plane.buffer->drm_device()->modeset_sequence_id()) { + std::move(submission_callback) + .Run(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, nullptr); + std::move(presentation_callback) + .Run(gfx::PresentationFeedback::Failure()); + return; + } + } + } + CHECK(status) << "SchedulePageFlip failed"; if (page_flip_request->page_flip_count() == 0) { @@ -204,17 +220,16 @@ bool HardwareDisplayController::ScheduleOrTestPageFlip( } std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers( - uint32_t format) const { - std::vector<uint64_t> modifiers; - + uint32_t fourcc_format) const { if (crtc_controllers_.empty()) - return modifiers; + return std::vector<uint64_t>(); - modifiers = crtc_controllers_[0]->GetFormatModifiers(format); + std::vector<uint64_t> modifiers = + crtc_controllers_[0]->GetFormatModifiers(fourcc_format); for (size_t i = 1; i < crtc_controllers_.size(); ++i) { std::vector<uint64_t> other = - crtc_controllers_[i]->GetFormatModifiers(format); + crtc_controllers_[i]->GetFormatModifiers(fourcc_format); std::vector<uint64_t> intersection; std::set_intersection(modifiers.begin(), modifiers.end(), other.begin(), @@ -225,11 +240,26 @@ std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers( return modifiers; } -std::vector<uint64_t> -HardwareDisplayController::GetFormatModifiersForModesetting( +std::vector<uint64_t> HardwareDisplayController::GetSupportedModifiers( uint32_t fourcc_format) const { - const auto& modifiers = GetFormatModifiers(fourcc_format); + if (preferred_format_modifier_.empty()) + return std::vector<uint64_t>(); + + auto it = preferred_format_modifier_.find(fourcc_format); + if (it != preferred_format_modifier_.end()) + return std::vector<uint64_t>{it->second}; + + return GetFormatModifiers(fourcc_format); +} + +std::vector<uint64_t> +HardwareDisplayController::GetFormatModifiersForTestModeset( + uint32_t fourcc_format) { + // If we're about to test, clear the current preferred modifier. + preferred_format_modifier_.clear(); + std::vector<uint64_t> filtered_modifiers; + const auto& modifiers = GetFormatModifiers(fourcc_format); for (auto modifier : modifiers) { // AFBC for modeset buffers doesn't work correctly, as we can't fill it with // a valid AFBC buffer. For now, don't use AFBC for modeset buffers. @@ -242,6 +272,18 @@ HardwareDisplayController::GetFormatModifiersForModesetting( return filtered_modifiers; } +void HardwareDisplayController::UpdatePreferredModiferForFormat( + gfx::BufferFormat buffer_format, + uint64_t modifier) { + uint32_t fourcc_format = GetFourCCFormatFromBufferFormat(buffer_format); + base::InsertOrAssign(preferred_format_modifier_, fourcc_format, modifier); + + uint32_t opaque_fourcc_format = + GetFourCCFormatForOpaqueFramebuffer(buffer_format); + base::InsertOrAssign(preferred_format_modifier_, opaque_fourcc_format, + modifier); +} + void HardwareDisplayController::MoveCursor(const gfx::Point& location) { cursor_location_ = location; UpdateCursorLocation(); @@ -368,22 +410,21 @@ void HardwareDisplayController::OnPageFlipComplete( time_of_last_flip_ = presentation_feedback.timestamp; current_planes_ = std::move(pending_planes); for (const auto& controller : crtc_controllers_) { - GetDrmDevice()->plane_manager()->ResetModesetBufferOfCrtc( + GetDrmDevice()->plane_manager()->ResetModesetStateForCrtc( controller->crtc()); } page_flip_request_ = nullptr; } void HardwareDisplayController::OnModesetComplete( - const DrmOverlayPlane& primary) { - // drmModeSetCrtc has an immediate effect, so we can assume that the current - // planes have been updated. However if a page flip is still pending, set the - // pending planes to the same values so that the callback keeps the correct - // state. + const DrmOverlayPlaneList& modeset_planes) { + // Modesetting is blocking so it has an immediate effect. We can assume that + // the current planes have been updated. However, if a page flip is still + // pending, set the pending planes to the same values so that the callback + // keeps the correct state. page_flip_request_ = nullptr; owned_hardware_planes_.legacy_page_flips.clear(); - current_planes_.clear(); - current_planes_.push_back(primary.Clone()); + current_planes_ = DrmOverlayPlane::Clone(modeset_planes); time_of_last_flip_ = base::TimeTicks::Now(); } diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h index 17a917183ae..27e4dd4bcbf 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h @@ -14,9 +14,11 @@ #include <vector> #include "base/callback.h" +#include "base/containers/flat_map.h" #include "base/macros.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/buffer_types.h" #include "ui/gfx/swap_result.h" #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h" @@ -96,15 +98,15 @@ class HardwareDisplayController { // Gets the props required to modeset a CRTC with a |mode| onto // |commit_request|. void GetModesetProps(CommitRequest* commit_request, - const DrmOverlayPlane& primary, + const DrmOverlayPlaneList& modeset_planes, const drmModeModeInfo& mode); // Gets the props required to enable/disable a CRTC onto |commit_request|. void GetEnableProps(CommitRequest* commit_request, - const DrmOverlayPlane& primary); + const DrmOverlayPlaneList& modeset_planes); void GetDisableProps(CommitRequest* commit_request); // Updates state of the controller after modeset/enable/disable is performed. - void UpdateState(bool enable_requested, const DrmOverlayPlane* primary_plane); + void UpdateState(const CrtcCommitRequest& crtc_request); // Schedules the |overlays|' framebuffers to be displayed on the next vsync // event. The event will be posted on the graphics card file descriptor |fd_| @@ -128,17 +130,19 @@ class HardwareDisplayController { // doesn't change any state. bool TestPageFlip(const DrmOverlayPlaneList& plane_list); - // Return the supported modifiers for |fourcc_format| for this - // controller. - std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const; + // Return the supported modifiers for |fourcc_format| for this controller. + std::vector<uint64_t> GetSupportedModifiers(uint32_t fourcc_format) const; // Return the supported modifiers for |fourcc_format| for this // controller to be used for modeset buffers. Currently, this only exists // because we can't provide valid AFBC buffers during modeset. // See https://crbug.com/852675 // TODO: Remove this. - std::vector<uint64_t> GetFormatModifiersForModesetting( - uint32_t fourcc_format) const; + std::vector<uint64_t> GetFormatModifiersForTestModeset( + uint32_t fourcc_format); + + void UpdatePreferredModiferForFormat(gfx::BufferFormat buffer_format, + uint64_t modifier); // Moves the hardware cursor to |location|. void MoveCursor(const gfx::Point& location); @@ -175,10 +179,10 @@ class HardwareDisplayController { // Loops over |crtc_controllers_| and save their props into |commit_request| // to be enabled/modeset. void GetModesetPropsForCrtcs(CommitRequest* commit_request, - const DrmOverlayPlane& primary, + const DrmOverlayPlaneList& modeset_planes, bool use_current_crtc_mode, const drmModeModeInfo& mode); - void OnModesetComplete(const DrmOverlayPlane& primary); + void OnModesetComplete(const DrmOverlayPlaneList& modeset_planes); bool ScheduleOrTestPageFlip(const DrmOverlayPlaneList& plane_list, scoped_refptr<PageFlipRequest> page_flip_request, std::unique_ptr<gfx::GpuFence>* out_fence); @@ -189,6 +193,8 @@ class HardwareDisplayController { void ResetCursor(); void DisableCursor(); + std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const; + HardwareDisplayPlaneList owned_hardware_planes_; // Stores the CRTC configuration. This is used to identify monitors and @@ -207,6 +213,11 @@ class HardwareDisplayController { int cursor_frontbuffer_ = 0; DrmDumbBuffer* current_cursor_ = nullptr; + // Maps each fourcc_format to its preferred modifier which was generated + // through modeset-test and updated in UpdatePreferredModifierForFormat(). + base::flat_map<uint32_t /*fourcc_format*/, uint64_t /*preferred_modifier*/> + preferred_format_modifier_; + base::WeakPtrFactory<HardwareDisplayController> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController); diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc index 739c8dd5d62..7cc0dddf155 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc @@ -9,6 +9,7 @@ #include <utility> #include "base/bind.h" +#include "base/containers/contains.h" #include "base/files/file_util.h" #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -123,7 +124,7 @@ class HardwareDisplayControllerTest : public testing::Test { } protected: - bool ModesetWithPlane(const ui::DrmOverlayPlane& plane); + bool ModesetWithPlanes(const ui::DrmOverlayPlaneList& modeset_planes); bool DisableController(); std::unique_ptr<ui::HardwareDisplayController> controller_; @@ -242,16 +243,15 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) { gfx::Point()); } -bool HardwareDisplayControllerTest::ModesetWithPlane( - const ui::DrmOverlayPlane& plane) { +bool HardwareDisplayControllerTest::ModesetWithPlanes( + const ui::DrmOverlayPlaneList& modeset_planes) { ui::CommitRequest commit_request; - controller_->GetModesetProps(&commit_request, plane, kDefaultMode); + controller_->GetModesetProps(&commit_request, modeset_planes, kDefaultMode); ui::CommitRequest request_for_update = commit_request; bool status = drm_->plane_manager()->Commit(std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET); - controller_->UpdateState( - /*enable_requested=*/true, - ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays())); + for (const ui::CrtcCommitRequest& crtc_request : commit_request) + controller_->UpdateState(crtc_request); return status; } @@ -262,7 +262,8 @@ bool HardwareDisplayControllerTest::DisableController() { ui::CommitRequest request_for_update = commit_request; bool status = drm_->plane_manager()->Commit(std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET); - controller_->UpdateState(/*enable_requested=*/false, nullptr); + for (const ui::CrtcCommitRequest& crtc_request : commit_request) + controller_->UpdateState(crtc_request); return status; } @@ -301,15 +302,18 @@ uint64_t HardwareDisplayControllerTest::GetPlanePropertyValue( } TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) { - ui::DrmOverlayPlane plane(CreateBuffer(), nullptr); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane)); - EXPECT_FALSE(plane.buffer->HasOneRef()); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); + EXPECT_FALSE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes) + ->buffer->HasOneRef()); } TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); ui::ScopedDrmObjectPropertyPtr crtc_props = drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC); @@ -328,8 +332,9 @@ TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) { } TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); ui::ScopedDrmObjectPropertyPtr connector_props = drm_->GetObjectProperties(kConnectorIdBase, DRM_MODE_OBJECT_CONNECTOR); @@ -343,11 +348,15 @@ TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) { TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) { const FakeFenceFD fake_fence_fd; - ui::DrmOverlayPlane plane1(CreateBuffer(), fake_fence_fd.GetGpuFence()); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), fake_fence_fd.GetGpuFence()); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); ui::ScopedDrmObjectPropertyPtr plane_props = drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE); + const ui::DrmOverlayPlane* primary_plane = + ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes); + { ui::DrmDevice::Property prop = {}; ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_ID", &prop); @@ -358,13 +367,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) { ui::DrmDevice::Property prop = {}; ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_X", &prop); EXPECT_EQ(kCrtcX, prop.id); - EXPECT_EQ(plane1.display_bounds.x(), static_cast<int>(prop.value)); + EXPECT_EQ(primary_plane->display_bounds.x(), static_cast<int>(prop.value)); } { ui::DrmDevice::Property prop = {}; ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_Y", &prop); EXPECT_EQ(kCrtcY, prop.id); - EXPECT_EQ(plane1.display_bounds.y(), static_cast<int>(prop.value)); + EXPECT_EQ(primary_plane->display_bounds.y(), static_cast<int>(prop.value)); } { ui::DrmDevice::Property prop = {}; @@ -382,13 +391,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) { ui::DrmDevice::Property prop = {}; ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "FB_ID", &prop); EXPECT_EQ(kPlaneFbId, prop.id); - EXPECT_EQ(plane1.buffer->opaque_framebuffer_id(), + EXPECT_EQ(primary_plane->buffer->opaque_framebuffer_id(), static_cast<uint32_t>(prop.value)); } - gfx::RectF crop_rectf = plane1.crop_rect; - crop_rectf.Scale(plane1.buffer->size().width(), - plane1.buffer->size().height()); + gfx::RectF crop_rectf = primary_plane->crop_rect; + crop_rectf.Scale(primary_plane->buffer->size().width(), + primary_plane->buffer->size().height()); gfx::Rect crop_rect = gfx::ToNearestRect(crop_rectf); gfx::Rect fixed_point_rect = gfx::Rect(crop_rect.x() << 16, crop_rect.y() << 16, @@ -427,8 +436,10 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) { } TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + ui::DrmOverlayPlane plane(CreateBuffer(), nullptr); + modeset_planes.push_back(plane.Clone()); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); // Test invalid fence fd { @@ -443,9 +454,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) { } const FakeFenceFD fake_fence_fd; - plane1.gpu_fence = fake_fence_fd.GetGpuFence(); + plane.gpu_fence = fake_fence_fd.GetGpuFence(); std::vector<ui::DrmOverlayPlane> planes = {}; - planes.push_back(plane1.Clone()); + planes.push_back(plane.Clone()); SchedulePageFlip(std::move(planes)); // Verify fence FD after a GPU Fence is added to the plane. @@ -460,8 +471,10 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) { static_cast<int>(fence_fd_prop.value)); } - plane1.gpu_fence = nullptr; - EXPECT_TRUE(ModesetWithPlane(plane1)); + plane.gpu_fence = nullptr; + modeset_planes.clear(); + modeset_planes.push_back(plane.Clone()); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); // Test an invalid FD again after the fence is removed. { @@ -477,9 +490,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) { } TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); // Test props values after disabling. DisableController(); @@ -581,20 +594,21 @@ TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) { } TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); EXPECT_EQ(1, drm_->get_commit_count()); - ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane2.Clone()); + ui::DrmOverlayPlane page_flip_plane(CreateBuffer(), nullptr); + std::vector<ui::DrmOverlayPlane> page_flip_planes; + page_flip_planes.push_back(page_flip_plane.Clone()); - SchedulePageFlip(std::move(planes)); + SchedulePageFlip(std::move(page_flip_planes)); drm_->RunCallbacks(); - EXPECT_TRUE(plane1.buffer->HasOneRef()); - EXPECT_FALSE(plane2.buffer->HasOneRef()); + EXPECT_TRUE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes) + ->buffer->HasOneRef()); + EXPECT_FALSE(page_flip_plane.buffer->HasOneRef()); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); EXPECT_EQ(1, page_flips_); @@ -608,24 +622,21 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) { InitializeDrmDevice(/* use_atomic */ false); drm_->set_set_crtc_expectation(false); - ui::DrmOverlayPlane plane(CreateBuffer(), nullptr); - - EXPECT_FALSE(ModesetWithPlane(plane)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_FALSE(ModesetWithPlanes(modeset_planes)); } TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - ui::DrmOverlayPlane plane2( - CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, - gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, + gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), + true, nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + EXPECT_TRUE(ModesetWithPlanes(planes)); EXPECT_EQ(1, drm_->get_commit_count()); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - planes.push_back(plane2.Clone()); - SchedulePageFlip(std::move(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -637,18 +648,15 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) { } TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - ui::DrmOverlayPlane plane2( - CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, - gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, + gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), + true, nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + EXPECT_TRUE(ModesetWithPlanes(planes)); EXPECT_EQ(1, drm_->get_commit_count()); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - planes.push_back(plane2.Clone()); - SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes)); EXPECT_EQ(2, drm_->get_commit_count()); // Verify both planes on the primary display have a valid framebuffer. @@ -674,16 +682,13 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) { } TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - ui::DrmOverlayPlane plane2(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE, - gfx::Rect(kDefaultModeSize), - gfx::RectF(kDefaultModeSizeF), true, nullptr); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + planes.emplace_back(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE, + gfx::Rect(kDefaultModeSize), + gfx::RectF(kDefaultModeSizeF), true, nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - planes.push_back(plane2.Clone()); + EXPECT_TRUE(ModesetWithPlanes(planes)); SchedulePageFlip(std::move(planes)); drm_->RunCallbacks(); @@ -695,13 +700,12 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) { controller_->AddCrtc(std::make_unique<ui::CrtcController>( drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)); - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + + EXPECT_TRUE(ModesetWithPlanes(planes)); EXPECT_EQ(1, drm_->get_commit_count()); - ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane2.Clone()); SchedulePageFlip(std::move(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -720,10 +724,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) { controller_->AddCrtc(std::make_unique<ui::CrtcController>( drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)); - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -762,10 +766,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) { } TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + SchedulePageFlip(std::move(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -790,10 +794,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) { controller_->AddCrtc(std::make_unique<ui::CrtcController>( drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1)); - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -835,39 +839,52 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) { } TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - SchedulePageFlip(std::move(planes)); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); - EXPECT_TRUE(ModesetWithPlane(plane1)); + SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes)); + + EXPECT_TRUE(ModesetWithPlanes(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); EXPECT_EQ(1, page_flips_); } TEST_F(HardwareDisplayControllerTest, FailPageFlipping) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + ASSERT_TRUE(ModesetWithPlanes(modeset_planes)); + + std::vector<ui::DrmOverlayPlane> page_flip_planes; + page_flip_planes.emplace_back(CreateBuffer(), nullptr); drm_->set_commit_expectation(false); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)), + EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(page_flip_planes)), "SchedulePageFlip failed"); } -TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) { - ui::DrmOverlayPlane modeset_primary_plane(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(modeset_primary_plane)); - - ui::DrmOverlayPlane plane1(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, - gfx::Rect(kDefaultModeSize), - gfx::RectF(0, 0, 1, 1), true, nullptr); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); +TEST_F(HardwareDisplayControllerTest, + RecreateBuffersOnOldPlanesPageFlipFailure) { + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + ASSERT_TRUE(ModesetWithPlanes(planes)); + + drm_->set_commit_expectation(false); SchedulePageFlip(std::move(planes)); + EXPECT_EQ(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, last_swap_result_); +} + +TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) { + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(modeset_planes)); + + std::vector<ui::DrmOverlayPlane> page_flip_planes; + page_flip_planes.emplace_back(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, + gfx::Rect(kDefaultModeSize), + gfx::RectF(0, 0, 1, 1), true, nullptr); + SchedulePageFlip(std::move(page_flip_planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -875,10 +892,10 @@ TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) { } TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + SchedulePageFlip(std::move(planes)); controller_->AddCrtc(std::make_unique<ui::CrtcController>( @@ -890,10 +907,10 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) { } TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) { - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + SchedulePageFlip(std::move(planes)); controller_->RemoveCrtc(drm_, kPrimaryCrtc); @@ -907,16 +924,13 @@ TEST_F(HardwareDisplayControllerTest, Disable) { // Page flipping overlays is only supported on atomic configurations. InitializeDrmDevice(/* use_atomic= */ true); - ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr); - EXPECT_TRUE(ModesetWithPlane(plane1)); - - ui::DrmOverlayPlane plane2( - CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, - gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr); - std::vector<ui::DrmOverlayPlane> planes; - planes.push_back(plane1.Clone()); - planes.push_back(plane2.Clone()); + ui::DrmOverlayPlaneList planes; + planes.emplace_back(CreateBuffer(), nullptr); + EXPECT_TRUE(ModesetWithPlanes(planes)); + planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE, + gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), + true, nullptr); SchedulePageFlip(std::move(planes)); drm_->RunCallbacks(); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); @@ -931,3 +945,20 @@ TEST_F(HardwareDisplayControllerTest, Disable) { // No plane should be in use. ASSERT_EQ(0, planes_in_use); } + +TEST_F(HardwareDisplayControllerTest, MultiplePlanesModeset) { + ui::DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(CreateBuffer(), nullptr); + modeset_planes.emplace_back(CreateBuffer(), nullptr); + ASSERT_TRUE(ModesetWithPlanes(modeset_planes)); + EXPECT_EQ(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers.size(), + 2UL); + for (const auto& plane : modeset_planes) { + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + plane.buffer)); + } +} diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc index acff6ed2116..a24b5b83e70 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc @@ -4,7 +4,10 @@ #include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h" +#include <drm_fourcc.h> + #include "base/logging.h" +#include "media/media_buildflags.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h" @@ -20,12 +23,15 @@ uint32_t OverlayTransformToDrmRotationPropertyValue( return DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_0; case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: return DRM_MODE_REFLECT_Y | DRM_MODE_ROTATE_0; + // Driver code swaps 90 and 270 to be compliant with how xrandr uses these + // values, so we need to invert them here as well to get them back to the + // proper value. case gfx::OVERLAY_TRANSFORM_ROTATE_90: - return DRM_MODE_ROTATE_90; + return DRM_MODE_ROTATE_270; case gfx::OVERLAY_TRANSFORM_ROTATE_180: return DRM_MODE_ROTATE_180; case gfx::OVERLAY_TRANSFORM_ROTATE_270: - return DRM_MODE_ROTATE_270; + return DRM_MODE_ROTATE_90; default: NOTREACHED(); } @@ -35,8 +41,22 @@ uint32_t OverlayTransformToDrmRotationPropertyValue( // Rotations are dependent on modifiers. Tiled formats can be rotated, // linear formats cannot. Atomic tests currently ignore modifiers, so there // isn't a way of determining if the rotation is supported. -// TODO(https://crbug/880464): Remove this. -bool IsRotationTransformSupported(gfx::OverlayTransform transform) { +// TODO(https://b/172210707): Atomic tests should work if we are using +// kUseRealBuffersForPageFlipTest, so this should be revisited and tested more +// broadly with a condition on that. +// NOTE: This is enabled for TGL+ and NV12/P010 formats for 90/270 rotation +// currently since we always allocate those formats as Y-tiled and 90/270 +// rotation is supported by the HW in that case. This is needed for protected +// content that requires overlays. +bool IsRotationTransformSupported(gfx::OverlayTransform transform, + uint32_t format_fourcc) { +#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) + if ((format_fourcc == DRM_FORMAT_NV12 || format_fourcc == DRM_FORMAT_P010) && + (transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 || + transform == gfx::OVERLAY_TRANSFORM_ROTATE_270)) { + return true; + } +#endif if ((transform == gfx::OVERLAY_TRANSFORM_ROTATE_90) || (transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) || (transform == gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL)) { @@ -80,11 +100,12 @@ bool HardwareDisplayPlaneAtomic::AssignPlaneProps( const gfx::Rect& crtc_rect, const gfx::Rect& src_rect, const gfx::OverlayTransform transform, - int in_fence_fd) { + int in_fence_fd, + uint32_t format_fourcc) { if (transform != gfx::OVERLAY_TRANSFORM_NONE && !properties_.rotation.id) return false; - if (!IsRotationTransformSupported(transform)) + if (!IsRotationTransformSupported(transform, format_fourcc)) return false; // Make a copy of properties to get the props IDs for the new intermediate diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h index 5043b987468..ae8d07997ec 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h @@ -31,7 +31,8 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane { const gfx::Rect& crtc_rect, const gfx::Rect& src_rect, const gfx::OverlayTransform transform, - int in_fence_fd); + int in_fence_fd, + uint32_t format_fourcc); // Sets the props on |property_set| for commit. bool SetPlaneProps(drmModeAtomicReq* property_set); diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc index 634fb042481..448cfa9a14b 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc @@ -459,8 +459,10 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset( if (is_enabled) { crtc_state.mode = crtc_request.mode(); - crtc_state.modeset_framebuffer = - DrmOverlayPlane::GetPrimaryPlane(crtc_request.overlays())->buffer; + crtc_state.modeset_framebuffers.clear(); + for (const auto& overlay : crtc_request.overlays()) + crtc_state.modeset_framebuffers.push_back(overlay.buffer); + } else { if (crtc_request.plane_list()) disable_planes_lists.insert(crtc_request.plane_list()); @@ -483,9 +485,9 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset( } } -void HardwareDisplayPlaneManager::ResetModesetBufferOfCrtc(uint32_t crtc_id) { +void HardwareDisplayPlaneManager::ResetModesetStateForCrtc(uint32_t crtc_id) { CrtcState& crtc_state = CrtcStateForCrtcId(crtc_id); - crtc_state.modeset_framebuffer = nullptr; + crtc_state.modeset_framebuffers.clear(); } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h index a4593292e8d..0cd18997ce8 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h @@ -82,7 +82,7 @@ class HardwareDisplayPlaneManager { CrtcState(CrtcState&&); drmModeModeInfo mode = {}; - scoped_refptr<DrmFramebuffer> modeset_framebuffer; + std::vector<scoped_refptr<DrmFramebuffer>> modeset_framebuffers; CrtcProperties properties = {}; @@ -187,7 +187,7 @@ class HardwareDisplayPlaneManager { // which resources needed to be tracked internally in // HardwareDisplayPlaneManager and which should be taken care of by the // caller. - void ResetModesetBufferOfCrtc(uint32_t crtc_id); + void ResetModesetStateForCrtc(uint32_t crtc_id); protected: struct ConnectorProperties { diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc index db7e3cad473..2fae9fcc8ff 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc @@ -11,10 +11,10 @@ #include <utility> #include "base/bind.h" +#include "base/containers/contains.h" #include "base/containers/flat_set.h" #include "base/files/platform_file.h" #include "base/logging.h" -#include "base/stl_util.h" #include "base/threading/sequenced_task_runner_handle.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/gpu_fence_handle.h" @@ -142,8 +142,11 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(CommitRequest commit_request, if (crtc_request.should_enable()) { DCHECK(crtc_request.plane_list()); - status &= AssignOverlayPlanes(crtc_request.plane_list(), - crtc_request.overlays(), crtc_id); + if (!AssignOverlayPlanes(crtc_request.plane_list(), + crtc_request.overlays(), crtc_id)) { + LOG_IF(ERROR, !is_testing) << "Failed to Assign Overlay Planes"; + status = false; + } enable_planes_lists.insert(crtc_request.plane_list()); } } @@ -204,9 +207,9 @@ void HardwareDisplayPlaneManagerAtomic::SetAtomicPropsForCommit( plane->set_in_use(false); HardwareDisplayPlaneAtomic* atomic_plane = static_cast<HardwareDisplayPlaneAtomic*>(plane); - atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(), - gfx::OVERLAY_TRANSFORM_NONE, - base::kInvalidPlatformFile); + atomic_plane->AssignPlaneProps( + 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE, + base::kInvalidPlatformFile, DRM_FORMAT_INVALID); atomic_plane->SetPlaneProps(atomic_request); } } @@ -307,9 +310,9 @@ bool HardwareDisplayPlaneManagerAtomic::DisableOverlayPlanes( HardwareDisplayPlaneAtomic* atomic_plane = static_cast<HardwareDisplayPlaneAtomic*>(plane); - atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(), - gfx::OVERLAY_TRANSFORM_NONE, - base::kInvalidPlatformFile); + atomic_plane->AssignPlaneProps( + 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE, + base::kInvalidPlatformFile, DRM_FORMAT_INVALID); atomic_plane->SetPlaneProps(plane_list->atomic_property_set.get()); } ret = drm_->CommitProperties(plane_list->atomic_property_set.get(), @@ -365,7 +368,7 @@ void HardwareDisplayPlaneManagerAtomic::RequestPlanesReadyCallback( } bool HardwareDisplayPlaneManagerAtomic::SetPlaneData( - HardwareDisplayPlaneList* plane_list, + HardwareDisplayPlaneList*, HardwareDisplayPlane* hw_plane, const DrmOverlayPlane& overlay, uint32_t crtc_id, @@ -382,9 +385,10 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData( fence_fd = gpu_fence_handle.owned_fd.get(); } - if (!atomic_plane->AssignPlaneProps(crtc_id, framebuffer_id, - overlay.display_bounds, src_rect, - overlay.plane_transform, fence_fd)) { + if (!atomic_plane->AssignPlaneProps( + crtc_id, framebuffer_id, overlay.display_bounds, src_rect, + overlay.plane_transform, fence_fd, + overlay.buffer->framebuffer_pixel_format())) { return false; } return true; diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc index 6f73d1747a0..1f23be53932 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc @@ -288,7 +288,7 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) { ui::CrtcCommitRequest request = ui::CrtcCommitRequest::EnableCrtcRequest( crtc_properties_[i].id, connector_properties[i].id, kDefaultMode, - &state, std::move(overlays)); + gfx::Point(), &state, std::move(overlays)); commit_request.push_back(std::move(request)); } @@ -309,22 +309,22 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) { ui::DrmOverlayPlaneList overlays; overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, gfx::Point(), + &state, std::move(overlays))); } { ui::DrmOverlayPlaneList overlays; overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode, + gfx::Point(), &state, std::move(overlays))); } { ui::DrmOverlayPlaneList overlays; overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode, + gfx::Point(), &state, std::move(overlays))); } EXPECT_TRUE(fake_drm_->plane_manager()->Commit( @@ -332,6 +332,47 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) { } } +TEST_P(HardwareDisplayPlaneManagerTest, SequenceIncrementOnModesetOnly) { + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, + /*use_atomic=*/true); + + // Modeset Test + { + int pre_test_sequence_id = fake_drm_->modeset_sequence_id(); + ASSERT_TRUE(fake_drm_->plane_manager()->Commit( + ui::CommitRequest(), + DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)); + EXPECT_EQ(pre_test_sequence_id, fake_drm_->modeset_sequence_id()); + } + + // Successful Modeset + { + int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id(); + ASSERT_TRUE(fake_drm_->plane_manager()->Commit( + ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET)); + EXPECT_EQ(pre_modeset_sequence_id + 1, fake_drm_->modeset_sequence_id()); + } + + // Failed Modeset + { + int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id(); + fake_drm_->set_set_crtc_expectation(false); + ASSERT_FALSE(fake_drm_->plane_manager()->Commit( + ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET)); + fake_drm_->set_set_crtc_expectation(true); + EXPECT_EQ(pre_modeset_sequence_id, fake_drm_->modeset_sequence_id()); + } + + // Page Flip + { + int pre_flip_sequence_id = fake_drm_->modeset_sequence_id(); + ASSERT_TRUE(fake_drm_->plane_manager()->Commit(ui::CommitRequest(), + DRM_MODE_ATOMIC_NONBLOCK)); + EXPECT_EQ(pre_flip_sequence_id, fake_drm_->modeset_sequence_id()); + } +} + TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) { InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1); fake_drm_->InitializeState(crtc_properties_, connector_properties_, @@ -346,8 +387,8 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) { ui::DrmOverlayPlaneList overlays; overlays.push_back(plane.Clone()); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, + gfx::Point(), &state, std::move(overlays))); EXPECT_FALSE(fake_drm_->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET)); @@ -495,8 +536,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, Modeset) { overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, + gfx::Point(), &state, std::move(overlays))); EXPECT_TRUE(fake_drm_->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET)); @@ -530,8 +571,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterModeset) { ui::DrmOverlayPlaneList overlays; overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( - crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state, - std::move(overlays))); + crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, + gfx::Point(), &state, std::move(overlays))); EXPECT_TRUE(fake_drm_->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET)); @@ -570,7 +611,7 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterDisable) { overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr)); commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest( crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, - &state, std::move(overlays))); + gfx::Point(), &state, std::move(overlays))); EXPECT_TRUE(fake_drm_->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET)); } @@ -1379,7 +1420,8 @@ class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic { const gfx::Rect& crtc_rect, const gfx::Rect& src_rect, const gfx::OverlayTransform transform, - int in_fence_fd) override { + int in_fence_fd, + uint32_t format_fourcc) override { framebuffer_ = framebuffer; return true; } diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc index bf00ae93cfe..1ef0fe9f11f 100644 --- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc +++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc @@ -9,7 +9,9 @@ #include <utility> #include "base/check.h" -#include "base/stl_util.h" +#include "base/containers/contains.h" +#include "base/containers/flat_map.h" +#include "base/logging.h" #include "skia/ext/legacy_display_globals.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -70,6 +72,13 @@ Type* FindObjectById(uint32_t id, std::vector<Type>& properties) { return it != properties.end() ? &(*it) : nullptr; } +// TODO(dnicoara): Generate all IDs internal to MockDrmDevice. +// For now generate something with a high enough ID to be unique in tests. +uint32_t GetUniqueNumber() { + static uint32_t value_generator = 0xff000000; + return ++value_generator; +} + } // namespace MockDrmDevice::CrtcProperties::CrtcProperties() = default; @@ -173,6 +182,34 @@ void MockDrmDevice::UpdateState( connector_properties_ = connector_properties; plane_properties_ = plane_properties; property_names_ = property_names; + + // Props IDs shouldn't change throughout a DRM state. Grab it once at + // UpdateState. + plane_crtc_id_prop_id_ = 0; + for (const PlaneProperties& plane_props : plane_properties) { + const std::vector<DrmDevice::Property>& props = plane_props.properties; + auto it = std::find_if( + props.begin(), props.end(), + [&names = property_names_](const DrmDevice::Property& prop) { + return names.at(prop.id) == "CRTC_ID"; + }); + if (it != props.end()) { + plane_crtc_id_prop_id_ = it->id; + // all planes should have the same prop ID for the name. Break right after + // the first one is found. + break; + } + } +} + +void MockDrmDevice::SetModifiersOverhead( + base::flat_map<uint64_t /*modifier*/, int /*overhead*/> + modifiers_overhead) { + modifiers_overhead_ = modifiers_overhead; +} + +void MockDrmDevice::SetSystemLimitOfModifiers(uint64_t limit) { + system_watermark_limitations_ = limit; } ScopedDrmResourcesPtr MockDrmDevice::GetResources() { @@ -258,8 +295,9 @@ bool MockDrmDevice::AddFramebuffer2(uint32_t width, uint32_t* framebuffer, uint32_t flags) { add_framebuffer_call_count_++; - *framebuffer = add_framebuffer_call_count_; + *framebuffer = GetUniqueNumber(); framebuffer_ids_.insert(*framebuffer); + fb_props_[*framebuffer] = {width, height, modifiers[0]}; return add_framebuffer_expectation_; } @@ -269,6 +307,11 @@ bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) { CHECK(it != framebuffer_ids_.end()); framebuffer_ids_.erase(it); } + { + auto it = fb_props_.find(framebuffer); + CHECK(it != fb_props_.end()); + fb_props_.erase(it); + } remove_framebuffer_call_count_++; std::vector<uint32_t> crtcs_to_clear; for (auto crtc_fb : crtc_fb_) { @@ -330,7 +373,7 @@ bool MockDrmDevice::SetProperty(uint32_t connector_id, ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(const void* blob, size_t size) { - uint32_t id = ++property_id_generator_; + uint32_t id = GetUniqueNumber(); allocated_property_blobs_.insert(id); return std::make_unique<DrmPropertyBlobMetadata>(this, id); } @@ -427,25 +470,46 @@ bool MockDrmDevice::CloseBufferHandle(uint32_t handle) { return true; } -bool MockDrmDevice::CommitProperties( +bool MockDrmDevice::CommitPropertiesInternal( drmModeAtomicReq* request, uint32_t flags, uint32_t crtc_count, scoped_refptr<PageFlipRequest> page_flip_request) { + commit_count_++; if (flags == kTestModesetFlags) ++test_modeset_count_; else if (flags == kCommitModesetFlags) ++commit_modeset_count_; - commit_count_++; - if (!commit_expectation_) + if ((flags & kCommitModesetFlags && !set_crtc_expectation_) || + (flags & DRM_MODE_ATOMIC_NONBLOCK && !commit_expectation_)) { return false; + } + + uint64_t requested_resources = 0; + base::flat_map<uint64_t, int> crtc_planes_counter; for (uint32_t i = 0; i < request->cursor; ++i) { - bool res = ValidatePropertyValue(request->items[i].property_id, - request->items[i].value); - if (!res) + const drmModeAtomicReqItem& item = request->items[i]; + if (!ValidatePropertyValue(item.property_id, item.value)) return false; + + if (fb_props_.find(item.value) != fb_props_.end()) { + const FramebufferProps& props = fb_props_[item.value]; + requested_resources += modifiers_overhead_[props.modifier]; + } + + if (item.property_id == plane_crtc_id_prop_id_) { + if (++crtc_planes_counter[item.value] > 1 && + !modeset_with_overlays_expectation_) + return false; + } + } + + if (requested_resources > system_watermark_limitations_) { + LOG(ERROR) << "Requested display configuration exceeds system watermark " + "limitations"; + return false; } if (page_flip_request) @@ -463,6 +527,12 @@ bool MockDrmDevice::CommitProperties( return false; } + // Count all committed planes at the end just before returning true to reflect + // the number of planes that have successfully been committed. + last_planes_committed_count_ = 0; + for (const auto& planes_counter : crtc_planes_counter) + last_planes_committed_count_ += planes_counter.second; + return true; } diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h index 922d402147c..0c2d823f12a 100644 --- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h +++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h @@ -8,11 +8,13 @@ #include <drm_mode.h> #include <stddef.h> #include <stdint.h> +#include <limits> #include <map> #include <memory> #include <set> #include <vector> +#include "base/containers/flat_map.h" #include "base/containers/queue.h" #include "base/macros.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -90,11 +92,18 @@ class MockDrmDevice : public DrmDevice { legacy_gamma_ramp_expectation_ = state; } void set_commit_expectation(bool state) { commit_expectation_ = state; } + void set_overlay_modeset_expecation(bool state) { + modeset_with_overlays_expectation_ = state; + } uint32_t current_framebuffer() const { return current_framebuffer_; } const std::vector<sk_sp<SkSurface>> buffers() const { return buffers_; } + int last_planes_committed_count() const { + return last_planes_committed_count_; + } + uint32_t get_cursor_handle_for_crtc(uint32_t crtc) const { const auto it = crtc_cursor_map_.find(crtc); return it != crtc_cursor_map_.end() ? it->second : 0; @@ -122,6 +131,9 @@ class MockDrmDevice : public DrmDevice { void SetPropertyBlob(ScopedDrmPropertyBlobPtr blob); + void SetModifiersOverhead(base::flat_map<uint64_t, int> modifiers_overhead); + void SetSystemLimitOfModifiers(uint64_t limit); + // DrmDevice: ScopedDrmResourcesPtr GetResources() override; ScopedDrmPlaneResPtr GetPlaneResources() override; @@ -177,10 +189,6 @@ class MockDrmDevice : public DrmDevice { bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels) override; bool UnmapDumbBuffer(void* pixels, size_t size) override; bool CloseBufferHandle(uint32_t handle) override; - bool CommitProperties(drmModeAtomicReq* request, - uint32_t flags, - uint32_t crtc_count, - scoped_refptr<PageFlipRequest> callback) override; bool SetGammaRamp( uint32_t crtc_id, const std::vector<display::GammaRampRGBEntry>& lut) override; @@ -188,8 +196,21 @@ class MockDrmDevice : public DrmDevice { uint32_t GetFramebufferForCrtc(uint32_t crtc_id) const; private: + // Properties of the plane associated with a fb. + struct FramebufferProps { + uint32_t width = 0; + uint32_t height = 0; + uint64_t modifier = 0; + }; + ~MockDrmDevice() override; + bool CommitPropertiesInternal( + drmModeAtomicReq* request, + uint32_t flags, + uint32_t crtc_count, + scoped_refptr<PageFlipRequest> callback) override; + bool UpdateProperty(uint32_t id, uint64_t value, std::vector<DrmDevice::Property>* properties); @@ -210,6 +231,7 @@ class MockDrmDevice : public DrmDevice { int commit_count_ = 0; int set_object_property_count_ = 0; int set_gamma_ramp_count_ = 0; + int last_planes_committed_count_ = 0; bool set_crtc_expectation_; bool add_framebuffer_expectation_; @@ -217,8 +239,10 @@ class MockDrmDevice : public DrmDevice { bool create_dumb_buffer_expectation_; bool legacy_gamma_ramp_expectation_ = false; bool commit_expectation_ = true; + bool modeset_with_overlays_expectation_ = true; uint32_t current_framebuffer_; + uint32_t plane_crtc_id_prop_id_ = 0; std::vector<sk_sp<SkSurface>> buffers_; @@ -237,12 +261,14 @@ class MockDrmDevice : public DrmDevice { std::map<uint32_t, std::string> property_names_; - // TODO(dnicoara): Generate all IDs internal to MockDrmDevice. - // For now generate something with a high enough ID to be unique in tests. - uint32_t property_id_generator_ = 0xff000000; - std::set<uint32_t> allocated_property_blobs_; + // Props of the plane associated with the generated fb_id. + base::flat_map<uint32_t /*fb_id*/, FramebufferProps> fb_props_; + + uint64_t system_watermark_limitations_ = std::numeric_limits<uint64_t>::max(); + base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_; + DISALLOW_COPY_AND_ASSIGN(MockDrmDevice); }; diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc index c65c5f6825c..af364e9c0e4 100644 --- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc +++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc @@ -6,6 +6,8 @@ #include <utility> +#include "base/bind.h" + namespace ui { void PostSyncTask( diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h index d5be9bd74e3..c488aea5a1d 100644 --- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h +++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h @@ -7,7 +7,7 @@ #include <utility> -#include "base/bind.h" +#include "base/bind_post_task.h" #include "base/location.h" #include "base/memory/ref_counted.h" #include "base/synchronization/waitable_event.h" @@ -15,19 +15,6 @@ namespace ui { -namespace internal { - -template <typename... Args> -void PostAsyncTask( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - base::OnceCallback<void(Args...)> callback, - Args... args) { - auto closure = base::BindOnce(std::move(callback), std::move(args)...); - task_runner->PostTask(FROM_HERE, std::move(closure)); -} - -} // namespace internal - // Posts a task to a different thread and blocks waiting for the task to finish // executing. void PostSyncTask( @@ -40,10 +27,10 @@ void PostSyncTask( // thread). template <typename... Args> base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback( - base::RepeatingCallback<void(Args...)> callback) { - return base::BindRepeating(&internal::PostAsyncTask<Args...>, - base::ThreadTaskRunnerHandle::Get(), - std::move(callback)); + base::RepeatingCallback<void(Args...)> callback, + const base::Location& location = FROM_HERE) { + return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(), + std::move(callback), location); } // Creates a OnceCallback that will run |callback| on the calling thread. Useful @@ -51,10 +38,10 @@ base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback( // task finished (and the callback needs to run on the original thread). template <typename... Args> base::OnceCallback<void(Args...)> CreateSafeOnceCallback( - base::OnceCallback<void(Args...)> callback) { - return base::BindOnce(&internal::PostAsyncTask<Args...>, - base::ThreadTaskRunnerHandle::Get(), - std::move(callback)); + base::OnceCallback<void(Args...)> callback, + const base::Location& location = FROM_HERE) { + return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(), + std::move(callback), location); } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc index 5a8319fe9cd..127f4d87257 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc @@ -10,6 +10,7 @@ #include "base/files/platform_file.h" #include "base/logging.h" +#include "base/trace_event/trace_event.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/display/types/display_snapshot.h" @@ -36,7 +37,7 @@ namespace { bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm, HardwareDisplayController* controller, SkSurface* surface, - uint32_t fourcc_format) { + const std::vector<uint64_t>& modifiers) { DCHECK(!controller->crtc_controllers().empty()); CrtcController* first_crtc = controller->crtc_controllers()[0].get(); ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(first_crtc->crtc())); @@ -45,7 +46,6 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm, return false; } - const auto& modifiers = controller->GetFormatModifiers(fourcc_format); for (const uint64_t modifier : modifiers) { // A value of 0 means DRM_FORMAT_MOD_NONE. If the CRTC has any other // modifier (tiling, compression, etc.) we can't read the fb and assume it's @@ -77,7 +77,7 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm, // Copy the source buffer. Do not perform any blending. paint.setBlendMode(SkBlendMode::kSrc); surface->getCanvas()->drawImage(saved_buffer.surface()->makeImageSnapshot(), - 0, 0, &paint); + 0, 0, SkSamplingOptions(), &paint); return true; } @@ -93,19 +93,6 @@ CrtcController* GetCrtcController(HardwareDisplayController* controller, return nullptr; } -std::vector<uint64_t> GetModifiersForPrimaryFormat( - HardwareDisplayController* controller) { - gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat(); - uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format); - return controller->GetFormatModifiersForModesetting(fourcc_format); -} - -bool AreAllStatusesTrue(base::flat_map<int64_t, bool>& display_statuses) { - auto it = find_if(display_statuses.begin(), display_statuses.end(), - [](const auto status) { return status.second == false; }); - return (it == display_statuses.end()); -} - } // namespace ScreenManager::ScreenManager() = default; @@ -175,6 +162,9 @@ void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm, void ScreenManager::RemoveDisplayControllers( const CrtcsWithDrmList& controllers_to_remove) { + TRACE_EVENT1("drm", "ScreenManager::RemoveDisplayControllers", + "display_count", controllers_to_remove.size()); + // Split them to different lists unique to each DRM Device. base::flat_map<scoped_refptr<DrmDevice>, CrtcsWithDrmList> controllers_for_drm_devices; @@ -223,8 +213,10 @@ void ScreenManager::RemoveDisplayControllers( UpdateControllerToWindowMapping(); } -base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers( +bool ScreenManager::ConfigureDisplayControllers( const ControllerConfigsList& controllers_params) { + TRACE_EVENT0("drm", "ScreenManager::ConfigureDisplayControllers"); + // Split them to different lists unique to each DRM Device. base::flat_map<scoped_refptr<DrmDevice>, ControllerConfigsList> displays_for_drm_devices; @@ -238,33 +230,81 @@ base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers( displays_for_drm_devices[params.drm].emplace_back(params); } - base::flat_map<int64_t, bool> statuses; + bool config_success = true; // Perform display configurations together for the same DRM only. for (const auto& configs_on_drm : displays_for_drm_devices) { - auto display_statuses = TestAndModeset(configs_on_drm.second); - statuses.insert(display_statuses.begin(), display_statuses.end()); + const ControllerConfigsList& controllers_params = configs_on_drm.second; + bool test_modeset = TestAndSetPreferredModifiers(controllers_params) || + TestAndSetLinearModifier(controllers_params); + config_success &= test_modeset; + if (!test_modeset) + continue; + bool can_modeset_with_overlays = + TestModesetWithOverlays(controllers_params); + config_success &= Modeset(controllers_params, can_modeset_with_overlays); } - if (AreAllStatusesTrue(statuses)) + if (config_success) UpdateControllerToWindowMapping(); - return statuses; + return config_success; } -base::flat_map<int64_t, bool> ScreenManager::TestAndModeset( +bool ScreenManager::TestAndSetPreferredModifiers( const ControllerConfigsList& controllers_params) { - if (!TestModeset(controllers_params)) { - base::flat_map<int64_t, bool> statuses; - for (const auto& params : controllers_params) - statuses.insert(std::make_pair(params.display_id, false)); - return statuses; + TRACE_EVENT1("drm", "ScreenManager::TestAndSetPreferredModifiers", + "display_count", controllers_params.size()); + + CrtcPreferredModifierMap crtcs_preferred_modifier; + CommitRequest commit_request; + auto drm = controllers_params[0].drm; + + for (const auto& params : controllers_params) { + auto it = FindDisplayController(params.drm, params.crtc); + DCHECK(controllers_.end() != it); + HardwareDisplayController* controller = it->get(); + + if (params.mode) { + uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + std::vector<uint64_t> modifiers = + controller->GetFormatModifiersForTestModeset(fourcc_format); + // Test with no overlays to go for a lower bandwidth usage. + DrmOverlayPlaneList modeset_planes = GetModesetPlanes( + controller, gfx::Rect(params.origin, ModeSize(*params.mode)), + modifiers, /*include_overlays=*/false, /*is_testing=*/true); + if (modeset_planes.empty()) + return false; + + uint64_t primary_modifier = + DrmOverlayPlane::GetPrimaryPlane(modeset_planes) + ->buffer->format_modifier(); + crtcs_preferred_modifier[params.crtc] = + std::make_pair(modifiers.empty(), primary_modifier); + + GetModesetControllerProps(&commit_request, controller, params.origin, + *params.mode, modeset_planes); + } else { + controller->GetDisableProps(&commit_request); + } + } + + if (!drm->plane_manager()->Commit( + std::move(commit_request), + DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) { + return false; } - return Modeset(controllers_params); + SetPreferredModifiers(controllers_params, crtcs_preferred_modifier); + return true; } -bool ScreenManager::TestModeset( +bool ScreenManager::TestAndSetLinearModifier( const ControllerConfigsList& controllers_params) { + TRACE_EVENT1("drm", "ScreenManager::TestAndSetLinearModifier", + "display_count", controllers_params.size()); + + CrtcPreferredModifierMap crtcs_preferred_modifier; CommitRequest commit_request; auto drm = controllers_params[0].drm; @@ -273,65 +313,151 @@ bool ScreenManager::TestModeset( DCHECK(controllers_.end() != it); HardwareDisplayController* controller = it->get(); + uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + std::vector<uint64_t> modifiers = + controller->GetFormatModifiersForTestModeset(fourcc_format); + // Test with an empty list if no preferred modifiers are advertised. + // Platforms might not support gbm_bo_create_with_modifiers(). If the + // platform doesn't expose modifiers, do not attempt to explicitly request + // LINEAR otherwise we might CHECK() when trying to allocate buffers. + if (!modifiers.empty()) + modifiers = std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}; + crtcs_preferred_modifier[params.crtc] = + std::make_pair(modifiers.empty(), DRM_FORMAT_MOD_LINEAR); + if (params.mode) { - DrmOverlayPlane primary_plane = GetModesetBuffer( + // Test with no overlays to go for a lower bandwidth usage. + DrmOverlayPlaneList modeset_planes = GetModesetPlanes( controller, gfx::Rect(params.origin, ModeSize(*params.mode)), - GetModifiersForPrimaryFormat(controller)); - if (!primary_plane.buffer) + modifiers, /*include_overlays=*/false, /*is_testing=*/true); + if (modeset_planes.empty()) return false; GetModesetControllerProps(&commit_request, controller, params.origin, - *params.mode, primary_plane); + *params.mode, modeset_planes); + } else { + controller->GetDisableProps(&commit_request); + } + } + + if (!drm->plane_manager()->Commit( + std::move(commit_request), + DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) { + return false; + } + + SetPreferredModifiers(controllers_params, crtcs_preferred_modifier); + return true; +} + +void ScreenManager::SetPreferredModifiers( + const ControllerConfigsList& controllers_params, + const CrtcPreferredModifierMap& crtcs_preferred_modifier) { + for (const auto& params : controllers_params) { + if (params.mode) { + bool was_modifiers_list_empty = + crtcs_preferred_modifier.at(params.crtc).first; + // No preferred modifiers should be saved as some platforms might not have + // bo_create_with_modifiers implemented, this will send the preferred + // modifiers list as an empty list. + if (!was_modifiers_list_empty) { + uint64_t picked_modifier = + crtcs_preferred_modifier.at(params.crtc).second; + auto it = FindDisplayController(params.drm, params.crtc); + DCHECK(*it); + it->get()->UpdatePreferredModiferForFormat( + display::DisplaySnapshot::PrimaryFormat(), picked_modifier); + } + } + } +} + +bool ScreenManager::TestModesetWithOverlays( + const ControllerConfigsList& controllers_params) { + TRACE_EVENT1("drm", "ScreenManager::TestModesetWithOverlays", "display_count", + controllers_params.size()); + + bool does_an_overlay_exist = false; + + CommitRequest commit_request; + auto drm = controllers_params[0].drm; + for (const auto& params : controllers_params) { + auto it = FindDisplayController(params.drm, params.crtc); + DCHECK(controllers_.end() != it); + HardwareDisplayController* controller = it->get(); + + if (params.mode) { + uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + std::vector<uint64_t> modifiers = + controller->GetSupportedModifiers(fourcc_format); + + DrmOverlayPlaneList modeset_planes = GetModesetPlanes( + controller, gfx::Rect(params.origin, ModeSize(*params.mode)), + modifiers, /*include_overlays=*/true, /*is_testing=*/true); + DCHECK(!modeset_planes.empty()); + does_an_overlay_exist |= modeset_planes.size() > 1; + + GetModesetControllerProps(&commit_request, controller, params.origin, + *params.mode, modeset_planes); } else { controller->GetDisableProps(&commit_request); } } + // If we have no overlays, report not modesetting with overlays as we haven't + // tested with overlays. + if (!does_an_overlay_exist) + return false; return drm->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET); } -base::flat_map<int64_t, bool> ScreenManager::Modeset( - const ControllerConfigsList& controllers_params) { - base::flat_map<int64_t, bool> statuses; +bool ScreenManager::Modeset(const ControllerConfigsList& controllers_params, + bool can_modeset_with_overlays) { + TRACE_EVENT2("drm", "ScreenManager::Modeset", "display_count", + controllers_params.size(), "modeset_with_overlays", + can_modeset_with_overlays); + + CommitRequest commit_request; + auto drm = controllers_params[0].drm; for (const auto& params : controllers_params) { - // Commit one controller at a time. - CommitRequest commit_request; - bool status = true; if (params.mode) { auto it = FindDisplayController(params.drm, params.crtc); DCHECK(controllers_.end() != it); HardwareDisplayController* controller = it->get(); - DrmOverlayPlane primary_plane = GetModesetBuffer( - controller, gfx::Rect(params.origin, ModeSize(*params.mode)), - GetModifiersForPrimaryFormat(controller)); - if (primary_plane.buffer) { - SetDisplayControllerForEnableAndGetProps( - &commit_request, params.drm, params.crtc, params.connector, - params.origin, *params.mode, primary_plane); - } else { - status = false; - } + uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + std::vector<uint64_t> modifiers = + controller->GetSupportedModifiers(fourcc_format); + + gfx::Rect bounds = gfx::Rect(params.origin, ModeSize(*params.mode)); + DrmOverlayPlaneList modeset_planes = + GetModesetPlanes(controller, bounds, modifiers, + can_modeset_with_overlays, /*is_testing=*/false); + + SetDisplayControllerForEnableAndGetProps( + &commit_request, params.drm, params.crtc, params.connector, + params.origin, *params.mode, modeset_planes); } else { - status = SetDisableDisplayControllerForDisableAndGetProps( + bool disable_set = SetDisableDisplayControllerForDisableAndGetProps( &commit_request, params.drm, params.crtc); + if (!disable_set) + return false; } + } - CommitRequest request_for_update = commit_request; - if (status) { - status &= params.drm->plane_manager()->Commit( - std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET); - UpdateControllerStateAfterModeset(params, request_for_update, status); - } + bool commit_status = drm->plane_manager()->Commit( + commit_request, DRM_MODE_ATOMIC_ALLOW_MODESET); - statuses.insert(std::make_pair(params.display_id, status)); - } + UpdateControllerStateAfterModeset(drm, commit_request, commit_status); - return statuses; + return commit_status; } void ScreenManager::SetDisplayControllerForEnableAndGetProps( @@ -341,7 +467,7 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps( uint32_t connector, const gfx::Point& origin, const drmModeModeInfo& mode, - const DrmOverlayPlane& primary) { + const DrmOverlayPlaneList& modeset_planes) { HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc); DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc << ") doesn't exist."; @@ -358,10 +484,10 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps( // Otherwise it could apply a mode with the same resolution and refresh // rate but with different timings to the other CRTC. GetModesetControllerProps(commit_request, controller, - controller->origin(), mode, primary); + controller->origin(), mode, modeset_planes); } else { // Just get props to re-enable the controller re-using the current state. - GetEnableControllerProps(commit_request, controller, primary); + GetEnableControllerProps(commit_request, controller, modeset_planes); } return; } @@ -377,7 +503,8 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps( controller = it->get(); } - GetModesetControllerProps(commit_request, controller, origin, mode, primary); + GetModesetControllerProps(commit_request, controller, origin, mode, + modeset_planes); } bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps( @@ -402,31 +529,32 @@ bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps( } void ScreenManager::UpdateControllerStateAfterModeset( - const ControllerConfigParams& config, + const scoped_refptr<DrmDevice>& drm, const CommitRequest& commit_request, bool did_succeed) { - for (auto& crtc_request : commit_request) { + for (const CrtcCommitRequest& crtc_request : commit_request) { bool was_enabled = (crtc_request.should_enable()); HardwareDisplayControllers::iterator it = - FindDisplayController(config.drm, crtc_request.crtc_id()); + FindDisplayController(drm, crtc_request.crtc_id()); if (it != controllers_.end()) { - it->get()->UpdateState(was_enabled, DrmOverlayPlane::GetPrimaryPlane( - crtc_request.overlays())); + it->get()->UpdateState(crtc_request); // If the CRTC is mirrored, move it to the mirror controller. if (did_succeed && was_enabled) - HandleMirrorIfExists(config, it); + HandleMirrorIfExists(drm, crtc_request, it); } } } void ScreenManager::HandleMirrorIfExists( - const ControllerConfigParams& config, + const scoped_refptr<DrmDevice>& drm, + const CrtcCommitRequest& crtc_request, const HardwareDisplayControllers::iterator& controller) { - gfx::Rect modeset_bounds(config.origin, ModeSize(*config.mode)); + gfx::Rect modeset_bounds(crtc_request.origin(), + ModeSize(crtc_request.mode())); HardwareDisplayControllers::iterator mirror = - FindActiveDisplayControllerByLocation(config.drm, modeset_bounds); + FindActiveDisplayControllerByLocation(drm, modeset_bounds); // TODO(dnicoara): This is hacky, instead the DrmDisplay and // CrtcController should be merged and picking the mode should be done // properly within HardwareDisplayController. @@ -434,7 +562,7 @@ void ScreenManager::HandleMirrorIfExists( // TODO(markyacoub): RemoveCrtc makes a blocking commit to // DisableOverlayPlanes. This should be redesigned and included as part of // the Modeset commit. - (*mirror)->AddCrtc((*controller)->RemoveCrtc(config.drm, config.crtc)); + (*mirror)->AddCrtc((*controller)->RemoveCrtc(drm, crtc_request.crtc_id())); controllers_.erase(controller); } } @@ -541,24 +669,30 @@ void ScreenManager::UpdateControllerToWindowMapping() { // otherwise the controller may be waiting for a page flip while the window // tries to schedule another buffer. if (should_enable) { - DrmOverlayPlane primary_plane = GetModesetBuffer( + uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + std::vector<uint64_t> modifiers = + controller->GetSupportedModifiers(fourcc_format); + DrmOverlayPlaneList modeset_planes = GetModesetPlanes( controller, - gfx::Rect(controller->origin(), controller->GetModeSize()), - GetModifiersForPrimaryFormat(controller)); - DCHECK(primary_plane.buffer); + gfx::Rect(controller->origin(), controller->GetModeSize()), modifiers, + /*include_overlays=*/true, /*is_testing=*/false); + DCHECK(!modeset_planes.empty()); CommitRequest commit_request; - GetEnableControllerProps(&commit_request, controller, primary_plane); + GetEnableControllerProps(&commit_request, controller, modeset_planes); controller->GetDrmDevice()->plane_manager()->Commit( std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET); } } } -DrmOverlayPlane ScreenManager::GetModesetBuffer( +DrmOverlayPlaneList ScreenManager::GetModesetPlanes( HardwareDisplayController* controller, const gfx::Rect& bounds, - const std::vector<uint64_t>& modifiers) { + const std::vector<uint64_t>& modifiers, + bool include_overlays, + bool is_testing) { scoped_refptr<DrmDevice> drm = controller->GetDrmDevice(); uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer( display::DisplaySnapshot::PrimaryFormat()); @@ -569,19 +703,27 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers); if (!buffer) { LOG(ERROR) << "Failed to create scanout buffer"; - return DrmOverlayPlane::Error(); + return DrmOverlayPlaneList(); } // If the current primary plane matches what we need for the next page flip, - // we can clone it. + // clone all last_submitted_planes (matching primary + overlays). DrmWindow* window = FindWindowAt(bounds); if (window) { - const DrmOverlayPlane* primary = window->GetLastModesetBuffer(); - const DrmDevice* drm = controller->GetDrmDevice().get(); + const DrmOverlayPlaneList& last_submitted_planes = + window->last_submitted_planes(); + const DrmOverlayPlane* primary = + DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes); if (primary && primary->buffer->size() == bounds.size() && - primary->buffer->drm_device() == drm) { - if (primary->buffer->format_modifier() == buffer->GetFormatModifier()) - return primary->Clone(); + primary->buffer->drm_device() == controller->GetDrmDevice().get() && + primary->buffer->format_modifier() == buffer->GetFormatModifier()) { + if (include_overlays) { + return DrmOverlayPlane::Clone(last_submitted_planes); + } else { + DrmOverlayPlaneList modeset_plane; + modeset_plane.push_back(primary->Clone()); + return modeset_plane; + } } } @@ -589,28 +731,32 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( drm, buffer.get(), buffer->GetSize(), modifiers); if (!framebuffer) { LOG(ERROR) << "Failed to add framebuffer for scanout buffer"; - return DrmOverlayPlane::Error(); + return DrmOverlayPlaneList(); } - sk_sp<SkSurface> surface = buffer->GetSurface(); - if (!surface) { - VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer."; - } else if (!FillModesetBuffer(drm, controller, surface.get(), - buffer->GetFormat())) { - // If we fail to fill the modeset buffer, clear it black to avoid displaying - // an uninitialized framebuffer. - surface->getCanvas()->clear(SK_ColorBLACK); + if (!is_testing) { + sk_sp<SkSurface> surface = buffer->GetSurface(); + if (!surface) { + VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer."; + } else if (!FillModesetBuffer(drm, controller, surface.get(), modifiers)) { + // If we fail to fill the modeset buffer, clear it black to avoid + // displaying an uninitialized framebuffer. + surface->getCanvas()->clear(SK_ColorBLACK); + } } - return DrmOverlayPlane(framebuffer, nullptr); + + DrmOverlayPlaneList modeset_planes; + modeset_planes.emplace_back(framebuffer, nullptr); + return modeset_planes; } void ScreenManager::GetEnableControllerProps( CommitRequest* commit_request, HardwareDisplayController* controller, - const DrmOverlayPlane& primary) { + const DrmOverlayPlaneList& modeset_planes) { DCHECK(!controller->crtc_controllers().empty()); - controller->GetEnableProps(commit_request, primary); + controller->GetEnableProps(commit_request, modeset_planes); } void ScreenManager::GetModesetControllerProps( @@ -618,11 +764,11 @@ void ScreenManager::GetModesetControllerProps( HardwareDisplayController* controller, const gfx::Point& origin, const drmModeModeInfo& mode, - const DrmOverlayPlane& primary) { + const DrmOverlayPlaneList& modeset_planes) { DCHECK(!controller->crtc_controllers().empty()); controller->set_origin(origin); - controller->GetModesetProps(commit_request, primary, mode); + controller->GetModesetProps(commit_request, modeset_planes, mode); } DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const { diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h index d7ac2810b53..c102c52525d 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h @@ -68,7 +68,7 @@ class ScreenManager { void RemoveDisplayControllers(const CrtcsWithDrmList& controllers_to_remove); // Enables/Disables the display controller based on if a mode exists. - base::flat_map<int64_t, bool> ConfigureDisplayControllers( + bool ConfigureDisplayControllers( const ControllerConfigsList& controllers_params); // Returns a reference to the display controller configured to display within @@ -98,6 +98,9 @@ class ScreenManager { std::vector<std::unique_ptr<HardwareDisplayController>>; using WidgetToWindowMap = std::unordered_map<gfx::AcceleratedWidget, std::unique_ptr<DrmWindow>>; + using CrtcPreferredModifierMap = base::flat_map< + uint32_t /*crtc_is*/, + std::pair<bool /*modifiers_list.empty()*/, uint64_t /*picked_modifier*/>>; // Returns an iterator into |controllers_| for the controller identified by // (|crtc|, |connector|). @@ -105,13 +108,21 @@ class ScreenManager { const scoped_refptr<DrmDevice>& drm, uint32_t crtc); - base::flat_map<int64_t, bool> TestAndModeset( + bool TestAndSetPreferredModifiers( const ControllerConfigsList& controllers_params); - - bool TestModeset(const ControllerConfigsList& controllers_params); - - base::flat_map<int64_t, bool> Modeset( + bool TestAndSetLinearModifier( const ControllerConfigsList& controllers_params); + // Setting the Preferred modifiers that passed from one of the Modeset Test + // functions. The preferred modifiers are used in Modeset. + void SetPreferredModifiers( + const ControllerConfigsList& controllers_params, + const CrtcPreferredModifierMap& crtcs_preferred_modifier); + // The planes used for modesetting can have overlays beside the primary, test + // if we can modeset with them. If not, return false to indicate that we must + // only use the primary plane. + bool TestModesetWithOverlays(const ControllerConfigsList& controllers_params); + bool Modeset(const ControllerConfigsList& controllers_params, + bool can_modeset_with_overlays); // Configures a display controller to be enabled. The display controller is // identified by (|crtc|, |connector|) and the controller is to be modeset @@ -123,7 +134,7 @@ class ScreenManager { uint32_t connector, const gfx::Point& origin, const drmModeModeInfo& mode, - const DrmOverlayPlane& primary); + const DrmOverlayPlaneList& modeset_planes); // Configures a display controller to be disabled. The display controller is // identified by |crtc|. Controller modeset props are added into @@ -135,12 +146,13 @@ class ScreenManager { const scoped_refptr<DrmDevice>& drm, uint32_t crtc); - void UpdateControllerStateAfterModeset(const ControllerConfigParams& config, + void UpdateControllerStateAfterModeset(const scoped_refptr<DrmDevice>& drm, const CommitRequest& commit_request, bool did_succeed); void HandleMirrorIfExists( - const ControllerConfigParams& config, + const scoped_refptr<DrmDevice>& drm, + const CrtcCommitRequest& crtc_request, const HardwareDisplayControllers::iterator& controller); // Returns an iterator into |controllers_| for the controller located at @@ -154,19 +166,21 @@ class ScreenManager { const scoped_refptr<DrmDevice>& drm, const gfx::Rect& bounds); - DrmOverlayPlane GetModesetBuffer(HardwareDisplayController* controller, - const gfx::Rect& bounds, - const std::vector<uint64_t>& modifiers); + DrmOverlayPlaneList GetModesetPlanes(HardwareDisplayController* controller, + const gfx::Rect& bounds, + const std::vector<uint64_t>& modifiers, + bool include_overlays, + bool is_testing); // Gets props for modesetting the |controller| using |origin| and |mode|. void GetModesetControllerProps(CommitRequest* commit_request, HardwareDisplayController* controller, const gfx::Point& origin, const drmModeModeInfo& mode, - const DrmOverlayPlane& primary); + const DrmOverlayPlaneList& modeset_planes); void GetEnableControllerProps(CommitRequest* commit_request, HardwareDisplayController* controller, - const DrmOverlayPlane& primary); + const DrmOverlayPlaneList& modeset_planes); DrmWindow* FindWindowAt(const gfx::Rect& bounds) const; diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc index d4a1a691a1e..a98d358da52 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc @@ -47,6 +47,7 @@ constexpr uint32_t kSecondaryConnector = kConnectorIdBase + 1; constexpr uint32_t kPlaneIdBase = 300; constexpr uint32_t kInFormatsBlobPropIdBase = 400; +constexpr uint32_t kFbIdPropId = 3005; constexpr uint32_t kTypePropId = 3010; constexpr uint32_t kInFormatsPropId = 3011; @@ -81,7 +82,8 @@ class ScreenManagerTest : public testing::Test { void InitializeDrmState(ui::MockDrmDevice* drm, const std::vector<CrtcState>& crtc_states, - bool is_atomic = true) { + bool is_atomic, + bool use_modifiers_list = false) { std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties( crtc_states.size()); std::map<uint32_t, std::string> crtc_property_names = { @@ -109,7 +111,7 @@ class ScreenManagerTest : public testing::Test { {3002, "CRTC_Y"}, {3003, "CRTC_W"}, {3004, "CRTC_H"}, - {3005, "FB_ID"}, + {kFbIdPropId, "FB_ID"}, {3006, "SRC_X"}, {3007, "SRC_Y"}, {3008, "SRC_W"}, @@ -143,9 +145,17 @@ class ScreenManagerTest : public testing::Test { : DRM_PLANE_TYPE_OVERLAY; } else if (pair.first == kInFormatsPropId) { value = property_id++; + std::vector<drm_format_modifier> drm_format_modifiers; + if (use_modifiers_list) { + for (const auto modifier : supported_modifiers_) { + drm_format_modifiers.push_back( + {/*formats=*/1, /*offset=*/0, /*pad=*/0, modifier}); + } + } + drm->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob( value, crtc_states[crtc_idx].planes[plane_idx].formats, - std::vector<drm_format_modifier>())); + std::move(drm_format_modifiers))); } crtc_plane_properties[plane_idx].properties.push_back( @@ -165,12 +175,15 @@ class ScreenManagerTest : public testing::Test { connector_property_names.end()); property_names.insert(plane_property_names.begin(), plane_property_names.end()); + + drm->SetModifiersOverhead(modifiers_overhead_); drm->InitializeState(crtc_properties, connector_properties, plane_properties, property_names, is_atomic); } void InitializeDrmStateWithDefault(ui::MockDrmDevice* drm, - bool is_atomic = true) { + bool is_atomic, + bool use_modifiers_list = false) { // A Sample of CRTC states. std::vector<CrtcState> crtc_states = { {/* .planes = */ @@ -182,11 +195,12 @@ class ScreenManagerTest : public testing::Test { {/* .formats = */ {DRM_FORMAT_XRGB8888}}, }}, }; - InitializeDrmState(drm, crtc_states, is_atomic); + InitializeDrmState(drm, crtc_states, is_atomic, use_modifiers_list); } void SetUp() override { auto gbm = std::make_unique<ui::MockGbmDevice>(); + supported_modifiers_ = gbm->GetSupportedModifiers(); drm_ = new ui::MockDrmDevice(std::move(gbm)); device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr); screen_manager_ = std::make_unique<ui::ScreenManager>(); @@ -218,6 +232,10 @@ class ScreenManagerTest : public testing::Test { scoped_refptr<ui::MockDrmDevice> drm_; std::unique_ptr<ui::DrmDeviceManager> device_manager_; std::unique_ptr<ui::ScreenManager> screen_manager_; + std::vector<uint64_t> supported_modifiers_; + base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_{ + {DRM_FORMAT_MOD_LINEAR, 1}, + {I915_FORMAT_MOD_Yf_TILED_CCS, 100}}; private: DISALLOW_COPY_AND_ASSIGN(ScreenManagerTest); @@ -231,7 +249,7 @@ TEST_F(ScreenManagerTest, CheckWithNoControllers) { } TEST_F(ScreenManagerTest, CheckWithValidController) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); @@ -252,7 +270,7 @@ TEST_F(ScreenManagerTest, CheckWithValidController) { } TEST_F(ScreenManagerTest, CheckWithInvalidBounds) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); @@ -268,7 +286,7 @@ TEST_F(ScreenManagerTest, CheckWithInvalidBounds) { } TEST_F(ScreenManagerTest, CheckForSecondValidController) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -287,14 +305,104 @@ TEST_F(ScreenManagerTest, CheckForSecondValidController) { screen_manager_->ConfigureDisplayControllers(controllers_to_enable); EXPECT_EQ(drm_->get_test_modeset_count(), 1); - EXPECT_EQ(drm_->get_commit_modeset_count(), 2); + EXPECT_EQ(drm_->get_commit_modeset_count(), 1); EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds())); EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds())); } +TEST_F(ScreenManagerTest, CheckMultipleDisplaysWithinModifiersLimit) { + int max_supported_displays_with_modifier = 2; + drm_->SetSystemLimitOfModifiers( + modifiers_overhead_[I915_FORMAT_MOD_Yf_TILED_CCS] * + max_supported_displays_with_modifier); + + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true, + /*use_modifiers_list=*/true); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, + kSecondaryConnector); + + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + drmModeModeInfo secondary_mode = kDefaultMode; + controllers_to_enable.emplace_back( + kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector, + GetSecondaryBounds().origin(), + std::make_unique<drmModeModeInfo>(secondary_mode)); + EXPECT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_EQ(drm_->get_test_modeset_count(), 1); + EXPECT_EQ(drm_->get_commit_modeset_count(), 1); +} + +TEST_F(ScreenManagerTest, CheckMultipleDisplaysOutsideModifiersLimit) { + int max_supported_displays_with_modifier = 2; + drm_->SetSystemLimitOfModifiers(modifiers_overhead_[DRM_FORMAT_MOD_LINEAR] * + max_supported_displays_with_modifier); + + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true, + /*use_modifiers_list=*/true); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, + kSecondaryConnector); + + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + drmModeModeInfo secondary_mode = kDefaultMode; + controllers_to_enable.emplace_back( + kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector, + GetSecondaryBounds().origin(), + std::make_unique<drmModeModeInfo>(secondary_mode)); + EXPECT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + // Testing for a failed test-modeset with modifiers + a fallback to Linear + // Modifier and a modeset commit. + EXPECT_EQ(drm_->get_test_modeset_count(), 2); + EXPECT_EQ(drm_->get_commit_modeset_count(), 1); +} + +TEST_F(ScreenManagerTest, CheckDisplaysWith0Limit) { + drm_->SetSystemLimitOfModifiers(0); + + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true, + /*use_modifiers_list=*/true); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, + kSecondaryConnector); + + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + drmModeModeInfo secondary_mode = kDefaultMode; + controllers_to_enable.emplace_back( + kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector, + GetSecondaryBounds().origin(), + std::make_unique<drmModeModeInfo>(secondary_mode)); + EXPECT_FALSE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + // Testing for a failed test-modeset with modifiers + failed test-modeset with + // Linear Modifier and no modeset due to failed tests. + EXPECT_EQ(drm_->get_test_modeset_count(), 2); + EXPECT_EQ(drm_->get_commit_modeset_count(), 0); +} + TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); @@ -314,7 +422,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) { } TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); // Enable @@ -344,7 +452,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) { } TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -375,7 +483,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) { } TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); @@ -407,7 +515,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) { EXPECT_EQ(drm_->get_test_modeset_count(), test_modeset_count_before_disable + 1); EXPECT_EQ(drm_->get_commit_modeset_count(), - commit_modeset_count_before_disable + 2); + commit_modeset_count_before_disable + 1); EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds())); EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds())); @@ -442,7 +550,7 @@ TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) { } TEST_F(ScreenManagerTest, CheckChangingMode) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); @@ -478,7 +586,7 @@ TEST_F(ScreenManagerTest, CheckChangingMode) { } TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -517,7 +625,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) { }, }, }; - InitializeDrmState(drm_.get(), crtc_states); + InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -574,7 +682,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) { // Make sure we're using each display's mode when doing mirror mode otherwise // the timings may be off. TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -609,7 +717,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) { } TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -641,23 +749,29 @@ TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) { } TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, kSecondaryConnector); - ScreenManager::ControllerConfigsList controllers_to_enable; - controllers_to_enable.emplace_back( - kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, - GetPrimaryBounds().origin(), - std::make_unique<drmModeModeInfo>(kDefaultMode)); - drmModeModeInfo secondary_mode = kDefaultMode; - controllers_to_enable.emplace_back( - kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector, - GetPrimaryBounds().origin(), - std::make_unique<drmModeModeInfo>(secondary_mode)); + // Enable in Mirror Mode. + { + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + drmModeModeInfo secondary_mode = kDefaultMode; + controllers_to_enable.emplace_back( + kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(secondary_mode)); + screen_manager_->ConfigureDisplayControllers(controllers_to_enable); + } + // Disable display Controller. + ScreenManager::ControllerConfigsList controllers_to_enable; controllers_to_enable.emplace_back(0, drm_, kSecondaryCrtc, 0, gfx::Point(), nullptr); screen_manager_->ConfigureDisplayControllers(controllers_to_enable); @@ -672,7 +786,7 @@ TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) { } TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -741,7 +855,7 @@ TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) { } TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kSecondaryCrtc, @@ -839,8 +953,8 @@ TEST_F(ScreenManagerTest, scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice(std::move(gbm_device)); - InitializeDrmStateWithDefault(drm_.get()); - InitializeDrmStateWithDefault(drm2.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); + InitializeDrmStateWithDefault(drm2.get(), /*is_atomic=*/true); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector); @@ -868,7 +982,7 @@ TEST_F(ScreenManagerTest, } TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); std::unique_ptr<ui::DrmWindow> window( new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); @@ -891,7 +1005,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) { } TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); std::unique_ptr<ui::DrmWindow> window( new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); @@ -917,7 +1031,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) { TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithOverlappingWindows) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); const size_t kWindowCount = 2; for (size_t i = 1; i < kWindowCount + 1; ++i) { @@ -948,7 +1062,7 @@ TEST_F(ScreenManagerTest, } TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) { - InitializeDrmStateWithDefault(drm_.get()); + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); gfx::AcceleratedWidget window_id = 1; std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow( @@ -1105,12 +1219,12 @@ TEST_F(ScreenManagerTest, ShouldNotHardwareMirrorDifferentDrmDevices) { auto gbm_device1 = std::make_unique<MockGbmDevice>(); auto drm_device1 = base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device1)); - InitializeDrmStateWithDefault(drm_device1.get()); + InitializeDrmStateWithDefault(drm_device1.get(), /*is_atomic=*/true); auto gbm_device2 = std::make_unique<MockGbmDevice>(); auto drm_device2 = base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device2)); - InitializeDrmStateWithDefault(drm_device2.get()); + InitializeDrmStateWithDefault(drm_device2.get(), /*is_atomic=*/true); DrmDeviceManager drm_device_manager(nullptr); ScreenManager screen_manager; @@ -1310,4 +1424,315 @@ TEST_F(ScreenManagerTest, ShouldNotUnbindFramebufferOnJoiningMirror) { screen_manager.RemoveWindow(1)->Shutdown(); } +TEST_F(ScreenManagerTest, DrmFramebufferSequenceIdIncrementingAtModeset) { + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); + + scoped_refptr<DrmFramebuffer> pre_modeset_buffer = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0); + + // Successful modeset + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + { + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + } + + scoped_refptr<DrmFramebuffer> first_post_modeset_buffer = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1); + CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0); + + // Unsuccessful modeset + { + drm_->set_set_crtc_expectation(false); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetSecondaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_FALSE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + } + + scoped_refptr<DrmFramebuffer> second_post_modeset_buffer = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + CHECK_EQ(second_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1); + CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1); + CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0); +} + +TEST_F(ScreenManagerTest, CloningPlanesOnModeset) { + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); + + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + scoped_refptr<DrmFramebuffer> buffer = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(buffer, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + buffer)); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + +TEST_F(ScreenManagerTest, CloningMultiplePlanesOnModeset) { + std::vector<CrtcState> crtc_states = {{ + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }}; + InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true); + + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + scoped_refptr<DrmFramebuffer> primary = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + scoped_refptr<DrmFramebuffer> overlay = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(primary, nullptr)); + planes.push_back(ui::DrmOverlayPlane(overlay, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + primary)); + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + overlay)); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + +TEST_F(ScreenManagerTest, ModesetWithClonedPlanesNoOverlays) { + InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true); + + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + scoped_refptr<DrmFramebuffer> buffer = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(buffer, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + ASSERT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + buffer)); + + EXPECT_EQ(drm_->get_test_modeset_count(), 1); + EXPECT_EQ(drm_->last_planes_committed_count(), 1); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + +TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlaySucceeding) { + std::vector<CrtcState> crtc_states = {{ + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }}; + InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true); + + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + scoped_refptr<DrmFramebuffer> primary = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + scoped_refptr<DrmFramebuffer> overlay = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(primary, nullptr)); + planes.push_back(ui::DrmOverlayPlane(overlay, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + primary)); + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + overlay)); + + EXPECT_EQ(drm_->get_test_modeset_count(), 2); + EXPECT_EQ(drm_->last_planes_committed_count(), 2); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + +TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlayFailing) { + std::vector<CrtcState> crtc_states = {{ + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }}; + InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true); + + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + scoped_refptr<DrmFramebuffer> primary = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + scoped_refptr<DrmFramebuffer> overlay = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(primary, nullptr)); + planes.push_back(ui::DrmOverlayPlane(overlay, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + drm_->set_overlay_modeset_expecation(false); + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + EXPECT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_TRUE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + primary)); + EXPECT_FALSE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + overlay)); + + EXPECT_EQ(drm_->get_test_modeset_count(), 2); + EXPECT_EQ(drm_->last_planes_committed_count(), 1); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + +TEST_F(ScreenManagerTest, ModesetWithNewBuffersOnModifiersChange) { + std::vector<CrtcState> crtc_states = {{ + /* .planes = */ + { + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + {/* .formats = */ {DRM_FORMAT_XRGB8888}}, + }, + }}; + InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true, + /*use_modifiers_list=*/true); + std::unique_ptr<ui::DrmWindow> window( + new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); + window->Initialize(); + window->SetBounds(GetPrimaryBounds()); + + scoped_refptr<DrmFramebuffer> primary = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + scoped_refptr<DrmFramebuffer> overlay = + CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size()); + ui::DrmOverlayPlaneList planes; + planes.push_back(ui::DrmOverlayPlane(primary, nullptr)); + planes.push_back(ui::DrmOverlayPlane(overlay, nullptr)); + window->SchedulePageFlip(std::move(planes), base::DoNothing(), + base::DoNothing()); + screen_manager_->AddWindow(1, std::move(window)); + + screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); + ScreenManager::ControllerConfigsList controllers_to_enable; + controllers_to_enable.emplace_back( + kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector, + GetPrimaryBounds().origin(), + std::make_unique<drmModeModeInfo>(kDefaultMode)); + ASSERT_TRUE( + screen_manager_->ConfigureDisplayControllers(controllers_to_enable)); + + EXPECT_FALSE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + primary)); + EXPECT_FALSE(base::Contains(drm_->plane_manager() + ->GetCrtcStateForCrtcId(kPrimaryCrtc) + .modeset_framebuffers, + overlay)); + + // Testing test modifiers only, no linear or overlays test. + EXPECT_EQ(drm_->get_test_modeset_count(), 1); + EXPECT_EQ(drm_->last_planes_committed_count(), 1); + + window = screen_manager_->RemoveWindow(1); + window->Shutdown(); +} + } // namespace ui |