// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/gpu/media/va_surface.h"
#include "content/common/gpu/media/vaapi_tfp_picture.h"
#include "content/common/gpu/media/vaapi_wrapper.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image_glx.h"
#include "ui/gl/scoped_binders.h"

namespace content {

VaapiTFPPicture::VaapiTFPPicture(
    const scoped_refptr<VaapiWrapper>& vaapi_wrapper,
    const base::Callback<bool(void)> make_context_current,
    int32_t picture_buffer_id,
    uint32_t texture_id,
    const gfx::Size& size)
    : VaapiPicture(picture_buffer_id, texture_id, size),
      vaapi_wrapper_(vaapi_wrapper),
      make_context_current_(make_context_current),
      x_display_(gfx::GetXDisplay()),
      x_pixmap_(0) {}

VaapiTFPPicture::~VaapiTFPPicture() {
  if (glx_image_.get() && make_context_current_.Run()) {
    glx_image_->ReleaseTexImage(GL_TEXTURE_2D);
    glx_image_->Destroy(true);
    DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));
  }

  if (x_pixmap_)
    XFreePixmap(x_display_, x_pixmap_);
}

bool VaapiTFPPicture::Initialize() {
  if (!make_context_current_.Run())
    return false;

  XWindowAttributes win_attr;
  int screen = DefaultScreen(x_display_);
  XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
  // TODO(posciak): pass the depth required by libva, not the RootWindow's
  // depth
  x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
                            size().width(), size().height(), win_attr.depth);
  if (!x_pixmap_) {
    LOG(ERROR) << "Failed creating an X Pixmap for TFP";
    return false;
  }

  glx_image_ = new gl::GLImageGLX(size(), GL_RGB);
  if (!glx_image_->Initialize(x_pixmap_)) {
    // x_pixmap_ will be freed in the destructor.
    LOG(ERROR) << "Failed creating a GLX Pixmap for TFP";
    return false;
  }

  gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id());
  if (!glx_image_->BindTexImage(GL_TEXTURE_2D)) {
    LOG(ERROR) << "Failed to bind texture to glx image";
    return false;
  }

  return true;
}

bool VaapiTFPPicture::DownloadFromSurface(
    const scoped_refptr<VASurface>& va_surface) {
  return vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(), x_pixmap_,
                                              va_surface->size());
}

scoped_refptr<gl::GLImage> VaapiTFPPicture::GetImageToBind() {
  return nullptr;
}

}  // namespace content
