/*
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_SF_COMPOSER_HAL_H
#define ANDROID_SF_COMPOSER_HAL_H

#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <utils/StrongPointer.h>
#include <IComposerCommandBuffer.h>

namespace android {

namespace Hwc2 {

using android::frameworks::vr::composer::V1_0::IVrComposerClient;

using android::hardware::graphics::common::V1_0::ColorMode;
using android::hardware::graphics::common::V1_0::ColorTransform;
using android::hardware::graphics::common::V1_0::Dataspace;
using android::hardware::graphics::common::V1_0::Hdr;
using android::hardware::graphics::common::V1_0::PixelFormat;
using android::hardware::graphics::common::V1_0::Transform;

using android::hardware::graphics::composer::V2_1::IComposer;
using android::hardware::graphics::composer::V2_1::IComposerCallback;
using android::hardware::graphics::composer::V2_1::IComposerClient;
using android::hardware::graphics::composer::V2_1::Error;
using android::hardware::graphics::composer::V2_1::Display;
using android::hardware::graphics::composer::V2_1::Layer;
using android::hardware::graphics::composer::V2_1::Config;

using android::hardware::graphics::composer::V2_1::CommandWriterBase;
using android::hardware::graphics::composer::V2_1::CommandReaderBase;

using android::hardware::kSynchronizedReadWrite;
using android::hardware::MessageQueue;
using android::hardware::MQDescriptorSync;
using android::hardware::hidl_vec;
using android::hardware::hidl_handle;

class CommandReader : public CommandReaderBase {
public:
    ~CommandReader();

    // Parse and execute commands from the command queue.  The commands are
    // actually return values from the server and will be saved in ReturnData.
    Error parse();

    // Get and clear saved errors.
    struct CommandError {
        uint32_t location;
        Error error;
    };
    std::vector<CommandError> takeErrors();

    bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
            uint32_t* outNumLayerRequestMasks) const;

    // Get and clear saved changed composition types.
    void takeChangedCompositionTypes(Display display,
            std::vector<Layer>* outLayers,
            std::vector<IComposerClient::Composition>* outTypes);

    // Get and clear saved display requests.
    void takeDisplayRequests(Display display,
        uint32_t* outDisplayRequestMask, std::vector<Layer>* outLayers,
        std::vector<uint32_t>* outLayerRequestMasks);

    // Get and clear saved release fences.
    void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
            std::vector<int>* outReleaseFences);

    // Get and clear saved present fence.
    void takePresentFence(Display display, int* outPresentFence);

private:
    void resetData();

    bool parseSelectDisplay(uint16_t length);
    bool parseSetError(uint16_t length);
    bool parseSetChangedCompositionTypes(uint16_t length);
    bool parseSetDisplayRequests(uint16_t length);
    bool parseSetPresentFence(uint16_t length);
    bool parseSetReleaseFences(uint16_t length);

    struct ReturnData {
        uint32_t displayRequests = 0;

        std::vector<Layer> changedLayers;
        std::vector<IComposerClient::Composition> compositionTypes;

        std::vector<Layer> requestedLayers;
        std::vector<uint32_t> requestMasks;

        int presentFence = -1;

        std::vector<Layer> releasedLayers;
        std::vector<int> releaseFences;
    };

    std::vector<CommandError> mErrors;
    std::unordered_map<Display, ReturnData> mReturnData;

    // When SELECT_DISPLAY is parsed, this is updated to point to the
    // display's return data in mReturnData.  We use it to avoid repeated
    // map lookups.
    ReturnData* mCurrentReturnData;
};

// Composer is a wrapper to IComposer, a proxy to server-side composer.
class Composer {
public:
    Composer(bool useVrComposer);

    std::vector<IComposer::Capability> getCapabilities();
    std::string dumpDebugInfo();

    void registerCallback(const sp<IComposerCallback>& callback);

    // Reset all pending commands in the command buffer. Useful if you want to
    // skip a frame but have already queued some commands.
    void resetCommands();

    uint32_t getMaxVirtualDisplayCount();
    bool isUsingVrComposer() const { return mIsUsingVrComposer; }
    Error createVirtualDisplay(uint32_t width, uint32_t height,
            PixelFormat* format, Display* outDisplay);
    Error destroyVirtualDisplay(Display display);

    Error acceptDisplayChanges(Display display);

    Error createLayer(Display display, Layer* outLayer);
    Error destroyLayer(Display display, Layer layer);

    Error getActiveConfig(Display display, Config* outConfig);
    Error getChangedCompositionTypes(Display display,
            std::vector<Layer>* outLayers,
            std::vector<IComposerClient::Composition>* outTypes);
    Error getColorModes(Display display, std::vector<ColorMode>* outModes);
    Error getDisplayAttribute(Display display, Config config,
            IComposerClient::Attribute attribute, int32_t* outValue);
    Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
    Error getDisplayName(Display display, std::string* outName);

    Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
            std::vector<Layer>* outLayers,
            std::vector<uint32_t>* outLayerRequestMasks);

    Error getDisplayType(Display display,
            IComposerClient::DisplayType* outType);
    Error getDozeSupport(Display display, bool* outSupport);
    Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
            float* outMaxLuminance, float* outMaxAverageLuminance,
            float* outMinLuminance);

    Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
            std::vector<int>* outReleaseFences);

    Error presentDisplay(Display display, int* outPresentFence);

    Error setActiveConfig(Display display, Config config);

    /*
     * The composer caches client targets internally.  When target is nullptr,
     * the composer uses slot to look up the client target from its cache.
     * When target is not nullptr, the cache is updated with the new target.
     */
    Error setClientTarget(Display display, uint32_t slot,
            const sp<GraphicBuffer>& target,
            int acquireFence, Dataspace dataspace,
            const std::vector<IComposerClient::Rect>& damage);
    Error setColorMode(Display display, ColorMode mode);
    Error setColorTransform(Display display, const float* matrix,
            ColorTransform hint);
    Error setOutputBuffer(Display display, const native_handle_t* buffer,
            int releaseFence);
    Error setPowerMode(Display display, IComposerClient::PowerMode mode);
    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled);

    Error setClientTargetSlotCount(Display display);

    Error validateDisplay(Display display, uint32_t* outNumTypes,
            uint32_t* outNumRequests);

    Error setCursorPosition(Display display, Layer layer,
            int32_t x, int32_t y);
    /* see setClientTarget for the purpose of slot */
    Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
            const sp<GraphicBuffer>& buffer, int acquireFence);
    Error setLayerSurfaceDamage(Display display, Layer layer,
            const std::vector<IComposerClient::Rect>& damage);
    Error setLayerBlendMode(Display display, Layer layer,
            IComposerClient::BlendMode mode);
    Error setLayerColor(Display display, Layer layer,
            const IComposerClient::Color& color);
    Error setLayerCompositionType(Display display, Layer layer,
            IComposerClient::Composition type);
    Error setLayerDataspace(Display display, Layer layer,
            Dataspace dataspace);
    Error setLayerDisplayFrame(Display display, Layer layer,
            const IComposerClient::Rect& frame);
    Error setLayerPlaneAlpha(Display display, Layer layer,
            float alpha);
    Error setLayerSidebandStream(Display display, Layer layer,
            const native_handle_t* stream);
    Error setLayerSourceCrop(Display display, Layer layer,
            const IComposerClient::FRect& crop);
    Error setLayerTransform(Display display, Layer layer,
            Transform transform);
    Error setLayerVisibleRegion(Display display, Layer layer,
            const std::vector<IComposerClient::Rect>& visible);
    Error setLayerZOrder(Display display, Layer layer, uint32_t z);
    Error setLayerInfo(Display display, Layer layer, uint32_t type,
                       uint32_t appId);
private:
    class CommandWriter : public CommandWriterBase {
    public:
        CommandWriter(uint32_t initialMaxSize);
        ~CommandWriter() override;

        void setLayerInfo(uint32_t type, uint32_t appId);
        void setClientTargetMetadata(
                const IVrComposerClient::BufferMetadata& metadata);
        void setLayerBufferMetadata(
                const IVrComposerClient::BufferMetadata& metadata);

    private:
        void writeBufferMetadata(
                const IVrComposerClient::BufferMetadata& metadata);
    };

    // Many public functions above simply write a command into the command
    // queue to batch the calls.  validateDisplay and presentDisplay will call
    // this function to execute the command queue.
    Error execute();

    sp<IComposer> mComposer;
    sp<IComposerClient> mClient;

    // 64KiB minus a small space for metadata such as read/write pointers
    static constexpr size_t kWriterInitialSize =
        64 * 1024 / sizeof(uint32_t) - 16;
    CommandWriter mWriter;
    CommandReader mReader;

    // When true, the we attach to the vr_hwcomposer service instead of the
    // hwcomposer. This allows us to redirect surfaces to 3d surfaces in vr.
    const bool mIsUsingVrComposer;
};

} // namespace Hwc2

} // namespace android

#endif // ANDROID_SF_COMPOSER_HAL_H
