Fix WindowAndroid leak in Android WebView
[chromium-blink-merge.git] / ui / gl / gl_image_memory.cc
blobca106b7cb2941bdb202e00c0632b40a1cb128a5e
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gl/gl_image_memory.h"
7 #include "base/logging.h"
8 #include "base/trace_event/trace_event.h"
9 #include "ui/gl/gl_bindings.h"
10 #include "ui/gl/scoped_binders.h"
12 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
13 defined(USE_OZONE)
14 #include "ui/gl/gl_surface_egl.h"
15 #endif
17 namespace gfx {
18 namespace {
20 bool ValidInternalFormat(unsigned internalformat) {
21 switch (internalformat) {
22 case GL_RGBA:
23 return true;
24 default:
25 return false;
29 bool ValidFormat(gfx::GpuMemoryBuffer::Format format) {
30 switch (format) {
31 case gfx::GpuMemoryBuffer::ATC:
32 case gfx::GpuMemoryBuffer::ATCIA:
33 case gfx::GpuMemoryBuffer::DXT1:
34 case gfx::GpuMemoryBuffer::DXT5:
35 case gfx::GpuMemoryBuffer::ETC1:
36 case gfx::GpuMemoryBuffer::RGBA_8888:
37 case gfx::GpuMemoryBuffer::BGRA_8888:
38 return true;
39 case gfx::GpuMemoryBuffer::RGBX_8888:
40 return false;
43 NOTREACHED();
44 return false;
47 bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format) {
48 switch (format) {
49 case gfx::GpuMemoryBuffer::ATC:
50 case gfx::GpuMemoryBuffer::ATCIA:
51 case gfx::GpuMemoryBuffer::DXT1:
52 case gfx::GpuMemoryBuffer::DXT5:
53 case gfx::GpuMemoryBuffer::ETC1:
54 return true;
55 case gfx::GpuMemoryBuffer::RGBA_8888:
56 case gfx::GpuMemoryBuffer::BGRA_8888:
57 case gfx::GpuMemoryBuffer::RGBX_8888:
58 return false;
61 NOTREACHED();
62 return false;
65 GLenum TextureFormat(gfx::GpuMemoryBuffer::Format format) {
66 switch (format) {
67 case gfx::GpuMemoryBuffer::ATC:
68 return GL_ATC_RGB_AMD;
69 case gfx::GpuMemoryBuffer::ATCIA:
70 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
71 case gfx::GpuMemoryBuffer::DXT1:
72 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
73 case gfx::GpuMemoryBuffer::DXT5:
74 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
75 case gfx::GpuMemoryBuffer::ETC1:
76 return GL_ETC1_RGB8_OES;
77 case gfx::GpuMemoryBuffer::RGBA_8888:
78 return GL_RGBA;
79 case gfx::GpuMemoryBuffer::BGRA_8888:
80 return GL_BGRA_EXT;
81 case gfx::GpuMemoryBuffer::RGBX_8888:
82 NOTREACHED();
83 return 0;
86 NOTREACHED();
87 return 0;
90 GLenum DataFormat(gfx::GpuMemoryBuffer::Format format) {
91 return TextureFormat(format);
94 GLenum DataType(gfx::GpuMemoryBuffer::Format format) {
95 switch (format) {
96 case gfx::GpuMemoryBuffer::RGBA_8888:
97 case gfx::GpuMemoryBuffer::BGRA_8888:
98 return GL_UNSIGNED_BYTE;
99 case gfx::GpuMemoryBuffer::ATC:
100 case gfx::GpuMemoryBuffer::ATCIA:
101 case gfx::GpuMemoryBuffer::DXT1:
102 case gfx::GpuMemoryBuffer::DXT5:
103 case gfx::GpuMemoryBuffer::ETC1:
104 case gfx::GpuMemoryBuffer::RGBX_8888:
105 NOTREACHED();
106 return 0;
109 NOTREACHED();
110 return 0;
113 GLsizei SizeInBytes(const gfx::Size& size,
114 gfx::GpuMemoryBuffer::Format format) {
115 size_t stride_in_bytes = 0;
116 bool valid_stride = GLImageMemory::StrideInBytes(
117 size.width(), format, &stride_in_bytes);
118 DCHECK(valid_stride);
119 return static_cast<GLsizei>(stride_in_bytes * size.height());
122 } // namespace
124 GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat)
125 : size_(size),
126 internalformat_(internalformat),
127 memory_(NULL),
128 format_(gfx::GpuMemoryBuffer::RGBA_8888),
129 in_use_(false),
130 target_(0),
131 need_do_bind_tex_image_(false)
132 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
133 defined(USE_OZONE)
135 egl_texture_id_(0u),
136 egl_image_(EGL_NO_IMAGE_KHR)
137 #endif
141 GLImageMemory::~GLImageMemory() {
142 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
143 defined(USE_OZONE)
144 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
145 DCHECK_EQ(0u, egl_texture_id_);
146 #endif
149 // static
150 bool GLImageMemory::StrideInBytes(size_t width,
151 gfx::GpuMemoryBuffer::Format format,
152 size_t* stride_in_bytes) {
153 base::CheckedNumeric<size_t> s = width;
154 switch (format) {
155 case gfx::GpuMemoryBuffer::ATCIA:
156 case gfx::GpuMemoryBuffer::DXT5:
157 *stride_in_bytes = width;
158 return true;
159 case gfx::GpuMemoryBuffer::ATC:
160 case gfx::GpuMemoryBuffer::DXT1:
161 case gfx::GpuMemoryBuffer::ETC1:
162 DCHECK_EQ(width % 2, 0U);
163 s /= 2;
164 if (!s.IsValid())
165 return false;
167 *stride_in_bytes = s.ValueOrDie();
168 return true;
169 case gfx::GpuMemoryBuffer::RGBA_8888:
170 case gfx::GpuMemoryBuffer::BGRA_8888:
171 s *= 4;
172 if (!s.IsValid())
173 return false;
175 *stride_in_bytes = s.ValueOrDie();
176 return true;
177 case gfx::GpuMemoryBuffer::RGBX_8888:
178 NOTREACHED();
179 return false;
182 NOTREACHED();
183 return false;
186 bool GLImageMemory::Initialize(const unsigned char* memory,
187 gfx::GpuMemoryBuffer::Format format) {
188 if (!ValidInternalFormat(internalformat_)) {
189 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
190 return false;
193 if (!ValidFormat(format)) {
194 LOG(ERROR) << "Invalid format: " << format;
195 return false;
198 DCHECK(memory);
199 DCHECK(!memory_);
200 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
201 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
202 memory_ = memory;
203 format_ = format;
204 return true;
207 void GLImageMemory::Destroy(bool have_context) {
208 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
209 defined(USE_OZONE)
210 if (egl_image_ != EGL_NO_IMAGE_KHR) {
211 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
212 egl_image_ = EGL_NO_IMAGE_KHR;
215 if (egl_texture_id_) {
216 if (have_context)
217 glDeleteTextures(1, &egl_texture_id_);
218 egl_texture_id_ = 0u;
220 #endif
221 memory_ = NULL;
224 gfx::Size GLImageMemory::GetSize() {
225 return size_;
228 bool GLImageMemory::BindTexImage(unsigned target) {
229 if (target_ && target_ != target) {
230 LOG(ERROR) << "GLImage can only be bound to one target";
231 return false;
233 target_ = target;
235 // Defer DoBindTexImage if not currently in use.
236 if (!in_use_) {
237 need_do_bind_tex_image_ = true;
238 return true;
241 DoBindTexImage(target);
242 return true;
245 bool GLImageMemory::CopyTexImage(unsigned target) {
246 TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
248 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
249 if (target == GL_TEXTURE_EXTERNAL_OES)
250 return false;
252 DCHECK(memory_);
253 if (IsCompressedFormat(format_)) {
254 glCompressedTexSubImage2D(target,
255 0, // level
256 0, // x-offset
257 0, // y-offset
258 size_.width(), size_.height(),
259 DataFormat(format_), SizeInBytes(size_, format_),
260 memory_);
261 } else {
262 glTexSubImage2D(target, 0, // level
263 0, // x
264 0, // y
265 size_.width(), size_.height(), DataFormat(format_),
266 DataType(format_), memory_);
269 return true;
272 void GLImageMemory::WillUseTexImage() {
273 DCHECK(!in_use_);
274 in_use_ = true;
276 if (!need_do_bind_tex_image_)
277 return;
279 DCHECK(target_);
280 DoBindTexImage(target_);
283 void GLImageMemory::DidUseTexImage() {
284 DCHECK(in_use_);
285 in_use_ = false;
288 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
289 int z_order,
290 OverlayTransform transform,
291 const Rect& bounds_rect,
292 const RectF& crop_rect) {
293 return false;
296 void GLImageMemory::DoBindTexImage(unsigned target) {
297 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
299 DCHECK(need_do_bind_tex_image_);
300 need_do_bind_tex_image_ = false;
302 DCHECK(memory_);
303 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
304 defined(USE_OZONE)
305 if (target == GL_TEXTURE_EXTERNAL_OES) {
306 if (egl_image_ == EGL_NO_IMAGE_KHR) {
307 DCHECK_EQ(0u, egl_texture_id_);
308 glGenTextures(1, &egl_texture_id_);
311 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
316 if (IsCompressedFormat(format_)) {
317 glCompressedTexImage2D(GL_TEXTURE_2D,
318 0, // mip level
319 TextureFormat(format_), size_.width(),
320 size_.height(),
321 0, // border
322 SizeInBytes(size_, format_), memory_);
323 } else {
324 glTexImage2D(GL_TEXTURE_2D,
325 0, // mip level
326 TextureFormat(format_),
327 size_.width(),
328 size_.height(),
329 0, // border
330 DataFormat(format_),
331 DataType(format_),
332 memory_);
336 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
337 // Need to pass current EGL rendering context to eglCreateImageKHR for
338 // target type EGL_GL_TEXTURE_2D_KHR.
339 egl_image_ =
340 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
341 eglGetCurrentContext(),
342 EGL_GL_TEXTURE_2D_KHR,
343 reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
344 attrs);
345 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
346 << "Error creating EGLImage: " << eglGetError();
347 } else {
348 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
350 if (IsCompressedFormat(format_)) {
351 glCompressedTexSubImage2D(GL_TEXTURE_2D,
352 0, // mip level
353 0, // x-offset
354 0, // y-offset
355 size_.width(), size_.height(),
356 DataFormat(format_),
357 SizeInBytes(size_, format_),
358 memory_);
359 } else {
360 glTexSubImage2D(GL_TEXTURE_2D,
361 0, // mip level
362 0, // x-offset
363 0, // y-offset
364 size_.width(),
365 size_.height(),
366 DataFormat(format_),
367 DataType(format_),
368 memory_);
372 glEGLImageTargetTexture2DOES(target, egl_image_);
373 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
374 return;
376 #endif
378 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
379 if (IsCompressedFormat(format_)) {
380 glCompressedTexImage2D(target,
381 0, // mip level
382 TextureFormat(format_), size_.width(),
383 size_.height(),
384 0, // border
385 SizeInBytes(size_, format_), memory_);
386 } else {
387 glTexImage2D(target,
388 0, // mip level
389 TextureFormat(format_),
390 size_.width(),
391 size_.height(),
392 0, // border
393 DataFormat(format_),
394 DataType(format_),
395 memory_);
399 } // namespace gfx