//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// Stream.h: Defines the egl::Stream class, representing the stream
// where frames are streamed in. Implements EGLStreanKHR.

#ifndef LIBANGLE_STREAM_H_
#define LIBANGLE_STREAM_H_

#include <array>

#include <EGL/egl.h>
#include <EGL/eglext.h>

#include "common/angleutils.h"
#include "libANGLE/AttributeMap.h"
#include "libANGLE/Debug.h"

namespace rx
{
class StreamProducerImpl;
}

namespace gl
{
class Context;
class Texture;
}

namespace egl
{
class Display;
class Error;
class Thread;

class Stream final : public LabeledObject, angle::NonCopyable
{
  public:
    Stream(Display *display, const AttributeMap &attribs);
    ~Stream();

    void setLabel(EGLLabelKHR label) override;
    EGLLabelKHR getLabel() const override;

    enum class ConsumerType
    {
        NoConsumer,
        GLTextureRGB,
        GLTextureYUV,
    };

    enum class ProducerType
    {
        NoProducer,
        D3D11Texture,
    };

    // A GL texture interpretation of a part of a producer frame. For use with GL texture consumers
    struct GLTextureDescription
    {
        unsigned int width;
        unsigned int height;
        unsigned int internalFormat;
        unsigned int mipLevels;
    };

    EGLenum getState() const;

    void setConsumerLatency(EGLint latency);
    EGLint getConsumerLatency() const;

    EGLuint64KHR getProducerFrame() const;
    EGLuint64KHR getConsumerFrame() const;

    void setConsumerAcquireTimeout(EGLint timeout);
    EGLint getConsumerAcquireTimeout() const;

    ConsumerType getConsumerType() const;
    ProducerType getProducerType() const;

    EGLint getPlaneCount() const;

    rx::StreamProducerImpl *getImplementation();

    // Consumer creation methods
    Error createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context);

    // Producer creation methods
    Error createProducerD3D11Texture(const AttributeMap &attributes);

    // Consumer methods
    Error consumerAcquire(const gl::Context *context);
    Error consumerRelease(const gl::Context *context);

    // Some consumers are bound to GL contexts. This validates that a given context is bound to the
    // stream's consumer
    bool isConsumerBoundToContext(const gl::Context *context) const;

    // Producer methods
    Error validateD3D11Texture(void *texture, const AttributeMap &attributes) const;
    Error postD3D11Texture(void *texture, const AttributeMap &attributes);

  private:
    EGLLabelKHR mLabel;

    // Associated display
    Display *mDisplay;

    // Producer Implementation
    rx::StreamProducerImpl *mProducerImplementation;

    // Associated GL context. Note that this is a weak pointer used for validation purposes only,
    // and should never be arbitrarily dereferenced without knowing the context still exists as it
    // can become dangling at any time.
    gl::Context *mContext;

    // EGL defined attributes
    EGLint mState;
    EGLuint64KHR mProducerFrame;
    EGLuint64KHR mConsumerFrame;
    EGLint mConsumerLatency;

    // EGL gltexture consumer attributes
    EGLint mConsumerAcquireTimeout;

    // EGL gltexture yuv consumer attributes
    EGLint mPlaneCount;
    struct PlaneTexture
    {
        EGLint textureUnit;
        gl::Texture *texture;
    };
    // Texture units and textures for all the planes
    std::array<PlaneTexture, 3> mPlanes;

    // Consumer and producer types
    ConsumerType mConsumerType;
    ProducerType mProducerType;

    // ANGLE-only method, used internally
    friend class gl::Texture;
    void releaseTextures();
};
}  // namespace egl

#endif  // LIBANGLE_STREAM_H_
