summaryrefslogtreecommitdiffstats
path: root/ui/gl/gl_image_android_native_buffer.cc
blob: 6d11497b2a31ccd36bef9b7231917b194b89438d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// 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 "ui/gl/gl_image_android_native_buffer.h"

#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/scoped_binders.h"

namespace gfx {

GLImageAndroidNativeBuffer::GLImageAndroidNativeBuffer(gfx::Size size)
    : GLImageEGL(size),
      release_after_use_(false),
      in_use_(false),
      target_(0),
      egl_image_for_unbind_(EGL_NO_IMAGE_KHR),
      texture_id_for_unbind_(0) {}

GLImageAndroidNativeBuffer::~GLImageAndroidNativeBuffer() { Destroy(); }

bool GLImageAndroidNativeBuffer::Initialize(gfx::GpuMemoryBufferHandle buffer) {
  DCHECK(buffer.native_buffer);

  EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
  return GLImageEGL::Initialize(
      EGL_NATIVE_BUFFER_ANDROID, buffer.native_buffer, attrs);
}

void GLImageAndroidNativeBuffer::Destroy() {
  if (egl_image_for_unbind_ != EGL_NO_IMAGE_KHR) {
    eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
                       egl_image_for_unbind_);
    egl_image_for_unbind_ = EGL_NO_IMAGE_KHR;
  }
  if (texture_id_for_unbind_) {
    glDeleteTextures(1, &texture_id_for_unbind_);
    texture_id_for_unbind_ = 0;
  }

  GLImageEGL::Destroy();
}

bool GLImageAndroidNativeBuffer::BindTexImage(unsigned target) {
  DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);

  if (target == GL_TEXTURE_RECTANGLE_ARB) {
    LOG(ERROR) << "EGLImage cannot be bound to TEXTURE_RECTANGLE_ARB target";
    return false;
  }

  if (target_ && target_ != target) {
    LOG(ERROR) << "EGLImage can only be bound to one target";
    return false;
  }
  target_ = target;

  // Defer ImageTargetTexture2D if not currently in use.
  if (!in_use_)
    return true;

  glEGLImageTargetTexture2DOES(target_, egl_image_);
  DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  return true;
}

void GLImageAndroidNativeBuffer::WillUseTexImage() {
  DCHECK(egl_image_);
  DCHECK(!in_use_);
  in_use_ = true;
  glEGLImageTargetTexture2DOES(target_, egl_image_);
  DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
}

void GLImageAndroidNativeBuffer::DidUseTexImage() {
  DCHECK(in_use_);
  in_use_ = false;

  if (!release_after_use_)
    return;

  if (egl_image_for_unbind_ == EGL_NO_IMAGE_KHR) {
    DCHECK_EQ(0u, texture_id_for_unbind_);
    glGenTextures(1, &texture_id_for_unbind_);

    {
      ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_for_unbind_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

      char zero[4] = {0, };
      glTexImage2D(
          GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
    }

    EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
    // Need to pass current EGL rendering context to eglCreateImageKHR for
    // target type EGL_GL_TEXTURE_2D_KHR.
    egl_image_for_unbind_ = eglCreateImageKHR(
        GLSurfaceEGL::GetHardwareDisplay(),
        eglGetCurrentContext(),
        EGL_GL_TEXTURE_2D_KHR,
        reinterpret_cast<EGLClientBuffer>(texture_id_for_unbind_),
        attrs);
    DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_for_unbind_)
        << "Error creating EGLImage: " << eglGetError();
  }

  glEGLImageTargetTexture2DOES(target_, egl_image_for_unbind_);
  DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
}

void GLImageAndroidNativeBuffer::SetReleaseAfterUse() {
  release_after_use_ = true;
}

}  // namespace gfx