// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm

#pragma once

#include "config.hpp"
#include "frame.hpp"
#include "status.hpp"
#include <vector>

namespace VideoStitch {

/**
 * Convenience function uploading a managed pixel buffer
 * to an OpenGL texture.
 * The transfers occuring never use the Host memory, although in multiple
 * GPUs setups some might be controlled by a CPU and not by the PCI controller.
 *
 * OpenGL context management is left to the user.
 * upload(...) needs an OpenGL context to be active on the current thread.
 *
 * This function is meant to be used in an VideoWriter implementation.
 * Beware, the thread calling pushFrame(...) is not necessarily the same
 * one as the thread calling stitch(...).
 *
 * Example below for GLX:
 *
 * class GLXCallback : public Output::VideoWriter, OpenGLUpload {
 * public:
 *   GLXCallback(GLXContext& ctx, unsigned width, unsigned height)
 *   : Output::VideoWriter("display 0", width, height, 0, 0, VideoStitch::RGBA, Device) {
 *     dpy  = XOpenDisplay(nullptr);
 *     root = DefaultRootWindow(dpy);
 *     vi   = glXChooseVisual(dpy, 0, attr);
 *     glc  = glXCreateContext(dpy, vi, ctx, GL_TRUE);
 *   }
 *
 *   ~GLXCallback() {
 *     glXDestroyContext(dpy, glc);
 *   }
 *
 *   void pushFrame(int frame, const char* videoFrame, size_t nbAudioSamples, uint8_t* const* audioSamples) {
 *     glXMakeCurrent(dpy, root, glc);
 *     upload(fmt, width, height, videoFrame);
 *   }
 *
 * private:
 *   Display *dpy;
 *   Window root;
 *   GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
 *   XVisualInfo *vi;
 *   GLXContext glc;
 * };
 *
 */
class VS_EXPORT OpenGLUpload {
 public:
  class Pimpl;

  OpenGLUpload();
  virtual ~OpenGLUpload();

  /**
   * Allocates a texture in the current context if necessary and uploads the video frame
   * to it. getTexId() to retrieve and bind the associated texture.
   */
  Status upload(PixelFormat fmt, int width, int height, const char* video);

  // valid after the first call to pushFrame
  /** Texture dimension */
  int getTexWidth() const;
  /** Texture dimension */
  int getTexHeight() const;
  /** Texture identifier */
  int getTexId() const;

 protected:
  void cleanState();

 private:
  Pimpl* pimpl;
};

/**
 * Return the GPGPU-compatible devices corresponding to the current OpenGL context.
 * There can be several of them if the setup is using SLI fir example (not recommended
 * for VideoStitch).
 *
 * When using multiple GPUs, display performances will peak if using
 * the OpenGL device as a primary target for the Output::VideoWriter callbacks,
 * by diminishing the number of frame transfers between GPUs.
 *
 * Use the returned value is recommended as:
 * - the primary device for composite outputs such as the Anaglyph and
 *   TopDown / LeftRight stereo callbacks.
 * - the device for your main Stitcher, through the Controller's DeviceDefinition
 *
 * Needs an active OpenGL context for introspection, like the upload(...) function.
 */
VS_EXPORT std::vector<int> getGLDevices();
}  // namespace VideoStitch