// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_
#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_
#include <stddef.h>
#include <stdint.h>
#include <xf86drmMode.h>
#include <cstdint>
#include <map>
#include <memory>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#include "ui/display/types/display_color_management.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
#include "ui/ozone/platform/drm/gpu/crtc_commit_request.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/public/hardware_capabilities.h"
namespace gfx {
class Rect;
struct GpuFenceHandle;
} // namespace gfx
namespace ui {
class CrtcController;
class HardwareDisplayPlane;
// This contains the list of planes controlled by one HDC on a given DRM fd.
// It is owned by the HDC and filled by the CrtcController.
struct HardwareDisplayPlaneList {
HardwareDisplayPlaneList();
~HardwareDisplayPlaneList();
// This is the list of planes to be committed this time.
// This field is not vector<raw_ptr<...>> due to interaction with third_party
// api.
RAW_PTR_EXCLUSION std::vector<HardwareDisplayPlane*> plane_list;
// This is the list of planes that was committed last time.
// This field is not vector<raw_ptr<...>> due to interaction with third_party
// api.
RAW_PTR_EXCLUSION std::vector<HardwareDisplayPlane*> old_plane_list;
struct PageFlipInfo {
PageFlipInfo(uint32_t crtc_id, uint32_t framebuffer);
PageFlipInfo(const PageFlipInfo& other);
~PageFlipInfo();
uint32_t crtc_id;
uint32_t framebuffer;
};
// In the case of non-atomic operation, this info will be used for
// pageflipping.
std::vector<PageFlipInfo> legacy_page_flips;
// Adds trace records to |context|.
void WriteIntoTrace(perfetto::TracedValue context) const;
};
class HardwareDisplayPlaneManager {
public:
struct CrtcProperties {
CrtcProperties();
CrtcProperties(const CrtcProperties& other);
~CrtcProperties();
// Unique identifier for the CRTC. This must be greater than 0 to be valid.
uint32_t id;
// Keeps track of the CRTC state. If a surface has been bound, then the
// value is set to true. Otherwise it is false.
DrmWrapper::Property active;
DrmWrapper::Property mode_id;
// Optional properties.
DrmWrapper::Property ctm;
DrmWrapper::Property gamma_lut;
DrmWrapper::Property gamma_lut_size;
DrmWrapper::Property degamma_lut;
DrmWrapper::Property degamma_lut_size;
DrmWrapper::Property out_fence_ptr;
DrmWrapper::Property background_color;
DrmWrapper::Property vrr_enabled;
};
struct CrtcState {
CrtcState();
~CrtcState();
CrtcState(const CrtcState&) = delete;
CrtcState& operator=(const CrtcState&) = delete;
CrtcState(CrtcState&&);
drmModeModeInfo mode = {};
std::vector<scoped_refptr<DrmFramebuffer>> modeset_framebuffers;
CrtcProperties properties = {};
// The parameters most recently set from the browser. These are used to
// compute the CTM, GAMMA, and DEGAMMA blobs.
display::ColorTemperatureAdjustment color_temperature_adjustment;
display::ColorCalibration color_calibration;
display::GammaAdjustment gamma_adjustment;
// The color space of all input planes. This assumes that all planes have
// the same color space, because all existing devices only support one
// color management configuration for all planes.
SkColorSpacePrimaries planes_primaries = SkNamedPrimariesExt::kSRGB;
// The color space of the output. All planes must be transformed to this
// space, using the hardware color management parameters (DEGAMMA, CTM,
// and GAMMA, where available).
SkColorSpacePrimaries output_primaries = SkNamedPrimariesExt::kSRGB;
// Cached blobs for the properties to commit in CommitCrtcProperties.
// * If a property is `std::nullopt`, then it should be left unchanged.
// * If a property is `nullptr` then it should be set to 0.
// * If a property is a blob, then it should be set to that blob.
std::optional<ScopedDrmPropertyBlob> pending_ctm_blob;
std::optional<ScopedDrmPropertyBlob> pending_gamma_lut_blob;
std::optional<ScopedDrmPropertyBlob> pending_degamma_lut_blob;
};
explicit HardwareDisplayPlaneManager(DrmDevice* drm);
HardwareDisplayPlaneManager(const HardwareDisplayPlaneManager&) = delete;
HardwareDisplayPlaneManager& operator=(const HardwareDisplayPlaneManager&) =
delete;
virtual ~HardwareDisplayPlaneManager();
// This parses information from the drm driver, adding any new planes
// or crtcs found.
bool Initialize();
// |commit_request| contains all the necessary information to build the
// atomic/legacy request. It acts as a thin wrapper that looks like the atomic
// request. It then gets converted into an atomic request for DRM atomic and
// has all the parameters for a legacy request.
// TODO(markyacoub): Consolidate this Commit() with the overloaded page flip
// Commit() down below.
virtual bool Commit(CommitRequest commit_request, uint32_t flags) = 0;
// Probe the mode for the CRTC to |mode| based on the current configuration
// of display hardware.
virtual bool TestSeamlessMode(int32_t crtc_id,
const drmModeModeInfo& mode) = 0;
// Clears old frame state out. Must be called before any AssignOverlayPlanes
// calls.
void BeginFrame(HardwareDisplayPlaneList* plane_list);
// Sets the input color space for all planes. This assumes that all planes on
// a CRTC have the same color space.
void SetColorSpaceForAllPlanes(uint32_t crtc_id,
const SkColorSpacePrimaries& primaries);
// Sets the output color space for the given CRTC.
void SetOutputColorSpace(uint32_t crtc_id,
const SkColorSpacePrimaries& primaries);
// Sets the color temperature adjustment for a given CRTC.
void SetColorTemperatureAdjustment(
uint32_t crtc_id,
const display::ColorTemperatureAdjustment& cta);
// Sets the color calibration information for a given CRTC.
void SetColorCalibration(uint32_t crtc_id,
const display::ColorCalibration& calibration);
// Sets the gamma adjustment for a given CRTC.
void SetGammaAdjustment(uint32_t crtc_id,
const display::GammaAdjustment& adjustment);
// Sets the background color on the CRTC object with ID |crtc_id|.
void SetBackgroundColor(uint32_t crtc_id, const uint64_t background_color);
// Assign hardware planes from the |planes_| list to |overlay_list| entries,
// recording the plane IDs in the |plane_list|. Only planes compatible with
// |crtc_id| will be used. |overlay_list| must be sorted bottom-to-top.
virtual bool AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
const DrmOverlayPlaneList& overlay_list,
uint32_t crtc_id);
// Commit the plane states in |plane_list|.
// If |page_flip_request| is null, this tests the plane configuration without
// submitting it.
// The fence returned in |out_fence| will signal when the currently scanned
// out buffers are replaced, and not when the buffers are scheduled with
// |page_flip_request|. Note that the returned fence may be a nullptr
// if the system doesn't support out fences.
virtual bool Commit(HardwareDisplayPlaneList* plane_list,
scoped_refptr<PageFlipRequest> page_flip_request,
gfx::GpuFenceHandle* release_fence) = 0;
// Disable all the overlay planes previously submitted and now stored in
// plane_list->old_plane_list.
virtual bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) = 0;
// Check that the primary plane is valid for this
// PlaneManager. Specifically, legacy can't support primary planes
// that don't have the same size as the current mode of the crtc.
virtual bool ValidatePrimarySize(const DrmOverlayPlane& primary,
const drmModeModeInfo& mode) = 0;
// Get the set of CRTC IDs from a plane's possible CRTCs bitmap
base::flat_set<uint32_t> CrtcMaskToCrtcIds(uint32_t crtc_mask) const;
const std::vector<std::unique_ptr<HardwareDisplayPlane>>& planes() const {
return planes_;
}
// Request a callback to be called when the planes are ready to be displayed.
// The callback will be invoked in the caller's execution context (same
// sequence or thread).
virtual void RequestPlanesReadyCallback(
DrmOverlayPlaneList planes,
base::OnceCallback<void(DrmOverlayPlaneList planes)> callback) = 0;
// Returns all formats which can be scanned out by this PlaneManager.
const std::vector<uint32_t>& GetSupportedFormats() const;
std::vector<uint64_t> GetFormatModifiers(uint32_t crtc_id,
uint32_t format) const;
// Cache the most updated connectors found in DRM resources. This needs to be
// called whenever a DRM hotplug event is received via UDEV.
// Return a list of the valid Connector IDs that we got.
base::flat_set<uint32_t> ResetConnectorsCacheAndGetValidIds(
const ScopedDrmResourcesPtr& resources);
// Get Immutable CRTC State.
const CrtcState& GetCrtcStateForCrtcId(uint32_t crtc_id);
// TODO(markyacoub): this seems hacky, this could be cleaned up a bit. Clarify
// which resources needed to be tracked internally in
// HardwareDisplayPlaneManager and which should be taken care of by the
// caller.
void ResetModesetStateForCrtc(uint32_t crtc_id);
// Gets `HardwareCapabilities` based on planes available to the specified
// CRTC. num_overlay_capable_planes counts both `DRM_PLANE_TYPE_PRIMARY` and
// `DRM_PLANE_TYPE_OVERLAY` planes.
HardwareCapabilities GetHardwareCapabilities(uint32_t crtc_id);
// Get a bitmask of possible CRTCs for the connector with |connector_id|.
// Returns 0 for invalid |connector_id|.
uint32_t GetPossibleCrtcsBitmaskForConnector(uint32_t connector_id) const;
protected:
struct ConnectorProperties {
uint32_t id;
drmModeConnection connection;
int count_modes;
DrmWrapper::Property crtc_id;
DrmWrapper::Property link_status;
uint64_t possible_crtcs_bitmask;
};
bool InitializeCrtcState();
void UpdateCrtcAndPlaneStatesAfterModeset(
const CommitRequest& commit_request);
// As the CRTC is being initialized, all connectors connected to it should
// be disabled. This is a workaround for a bug on Hatch where Puff enables
// a connector in dev mode before Chrome even starts. The kernel maps the HW
// state at initial modeset (with a dangling connector attached to a CRTC).
// When an Atomic Modeset is performed, it fails to modeset as the CRTC is
// already attached to another dead connector. (Analysis: crbug/1067121#c5)
// TODO(b/168154314): Remove this call when the bug is fixed.
void DisableConnectedConnectorsToCrtcs(
const ScopedDrmResourcesPtr& resources);
virtual bool InitializePlanes() = 0;
virtual bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
HardwareDisplayPlane* hw_plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_id,
const gfx::Rect& src_rect) = 0;
virtual std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id);
// Convert |crtc/connector_id| into an index, returning empty if the ID
// couldn't be found.
std::optional<int> LookupCrtcIndex(uint32_t crtc_id) const;
std::optional<int> LookupConnectorIndex(uint32_t connector_id) const;
// Get Mutable CRTC State.
CrtcState& CrtcStateForCrtcId(uint32_t crtc_id);
// Returns true if |plane| can support |overlay| and compatible with
// |crtc_id|.
virtual bool IsCompatible(HardwareDisplayPlane* plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_id) const;
// Resets |plane_list| setting all planes to unused.
// Frees any temporary data structure in |plane_list| used for pageflipping.
void ResetCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
// Restores |plane_list| planes |in_use| flag to what it was before
// BeginFrame was called.
// Frees any temporary data structure in |plane_list| used for pageflipping.
void RestoreCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
// Populates scanout formats supported by all planes.
void PopulateSupportedFormats();
void UpdatePendingCrtcState(CrtcState& state);
virtual bool CommitPendingCrtcState(CrtcState& state) = 0;
// Object containing the connection to the graphics device and wraps the API
// calls to control it. Not owned.
const raw_ptr<DrmDevice> drm_;
bool has_universal_planes_ = false;
bool ctm_negative_values_broken_ = false;
std::vector<std::unique_ptr<HardwareDisplayPlane>> planes_;
std::vector<CrtcState> crtc_state_;
std::vector<ConnectorProperties> connectors_props_;
std::vector<uint32_t> supported_formats_;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_H_