/*
    KWin - the KDE window manager
    This file is part of the KDE project.

    SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once

#include "drm_abstract_output.h"
#include "drm_object.h"
#include "drm_plane.h"
#include "utils/filedescriptor.h"

#include <QList>
#include <QObject>
#include <QPoint>
#include <QPointer>
#include <QSize>
#include <QTimer>
#include <chrono>
#include <xf86drmMode.h>

namespace KWin
{

class DrmConnector;
class DrmGpu;
class DrmPipeline;
class DumbSwapchain;
class DrmLease;
class OutputChangeSet;

class KWIN_EXPORT DrmOutput : public DrmAbstractOutput
{
    Q_OBJECT
public:
    explicit DrmOutput(const std::shared_ptr<DrmConnector> &connector, DrmPipeline *pipeline);

    DrmConnector *connector() const;
    DrmPipeline *pipeline() const;

    bool present(const std::shared_ptr<OutputFrame> &frame) override;
    DrmOutputLayer *primaryLayer() const override;
    DrmOutputLayer *cursorLayer() const override;

    bool queueChanges(const std::shared_ptr<OutputChangeSet> &properties);
    void applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &properties);
    void revertQueuedChanges();
    void updateDpmsMode(DpmsMode dpmsMode);

    bool shouldDisableCursorPlane() const;
    bool updateCursorLayer(std::optional<std::chrono::nanoseconds> allowedVrrDelay) override;

    DrmLease *lease() const;
    bool addLeaseObjects(QList<uint32_t> &objectList);
    void leased(DrmLease *lease);
    void leaseEnded();

    bool setChannelFactors(const QVector3D &rgb) override;
    void updateConnectorProperties();

    /**
     * @returns the color description / encoding that the buffers passed to the CRTC need to have, without a color pipeline to change it
     */
    const ColorDescription &scanoutColorDescription() const;
    /**
     * @returns the color description that compositing and blending need to happen in
     */
    const ColorDescription &blendingColorDescription() const;
    /**
     * @returns whether or not the renderer should apply channel factors
     */
    bool needsShadowBuffer() const;

    void removePipeline();

private:
    bool setDrmDpmsMode(DpmsMode mode);
    void setDpmsMode(DpmsMode mode) override;
    void tryKmsColorOffloading();
    ColorDescription createColorDescription(const State &next) const;
    Capabilities computeCapabilities() const;
    void updateInformation();
    void unsetBrightnessDevice() override;
    void updateBrightness(double newBrightness, double newArtificialHdrHeadroom);
    void setScanoutColorDescription(const ColorDescription &description);
    void setBlendingColorDescription(const ColorDescription &description);
    std::optional<uint32_t> decideAutomaticBpcLimit() const;

    QList<std::shared_ptr<OutputMode>> getModes() const;

    DrmGpu *const m_gpu;
    DrmPipeline *m_pipeline;
    const std::shared_ptr<DrmConnector> m_connector;

    QTimer m_turnOffTimer;
    FileDescriptor m_sleepInhibitor;
    DrmLease *m_lease = nullptr;

    QVector3D m_sRgbChannelFactors = {1, 1, 1};
    bool m_needsShadowBuffer = false;
    ColorDescription m_scanoutColorDescription = ColorDescription::sRGB;
    ColorDescription m_blendingColorDescription = ColorDescription::sRGB;
    PresentationMode m_desiredPresentationMode = PresentationMode::VSync;
};

}

Q_DECLARE_METATYPE(KWin::DrmOutput *)
