Roll src/third_party/WebKit 37b70da:e3be828 (svn 200645:200646)
[chromium-blink-merge.git] / ui / gl / gl_image_memory.cc
blobaa308be59d6656e57a256534ded3fa7d2d8d73e3
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_ATC_RGB_AMD:
23 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
24 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
25 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
26 case GL_ETC1_RGB8_OES:
27 case GL_R8:
28 case GL_RGBA:
29 case GL_BGRA_EXT:
30 return true;
31 default:
32 return false;
36 bool ValidFormat(BufferFormat format) {
37 switch (format) {
38 case BufferFormat::ATC:
39 case BufferFormat::ATCIA:
40 case BufferFormat::DXT1:
41 case BufferFormat::DXT5:
42 case BufferFormat::ETC1:
43 case BufferFormat::R_8:
44 case BufferFormat::RGBA_4444:
45 case BufferFormat::RGBA_8888:
46 case BufferFormat::BGRA_8888:
47 return true;
48 case BufferFormat::RGBX_8888:
49 case BufferFormat::YUV_420:
50 case BufferFormat::YUV_420_BIPLANAR:
51 return false;
54 NOTREACHED();
55 return false;
58 bool IsCompressedFormat(BufferFormat format) {
59 switch (format) {
60 case BufferFormat::ATC:
61 case BufferFormat::ATCIA:
62 case BufferFormat::DXT1:
63 case BufferFormat::DXT5:
64 case BufferFormat::ETC1:
65 return true;
66 case BufferFormat::R_8:
67 case BufferFormat::RGBA_4444:
68 case BufferFormat::RGBA_8888:
69 case BufferFormat::BGRA_8888:
70 case BufferFormat::RGBX_8888:
71 case BufferFormat::YUV_420:
72 case BufferFormat::YUV_420_BIPLANAR:
73 return false;
76 NOTREACHED();
77 return false;
80 GLenum TextureFormat(BufferFormat format) {
81 switch (format) {
82 case BufferFormat::ATC:
83 return GL_ATC_RGB_AMD;
84 case BufferFormat::ATCIA:
85 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
86 case BufferFormat::DXT1:
87 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
88 case BufferFormat::DXT5:
89 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
90 case BufferFormat::ETC1:
91 return GL_ETC1_RGB8_OES;
92 case BufferFormat::R_8:
93 return GL_RED;
94 case BufferFormat::RGBA_4444:
95 case BufferFormat::RGBA_8888:
96 return GL_RGBA;
97 case BufferFormat::BGRA_8888:
98 return GL_BGRA_EXT;
99 case BufferFormat::RGBX_8888:
100 case BufferFormat::YUV_420:
101 case BufferFormat::YUV_420_BIPLANAR:
102 NOTREACHED();
103 return 0;
106 NOTREACHED();
107 return 0;
110 GLenum DataFormat(BufferFormat format) {
111 return TextureFormat(format);
114 GLenum DataType(BufferFormat format) {
115 switch (format) {
116 case BufferFormat::RGBA_4444:
117 return GL_UNSIGNED_SHORT_4_4_4_4;
118 case BufferFormat::RGBA_8888:
119 case BufferFormat::BGRA_8888:
120 case BufferFormat::R_8:
121 return GL_UNSIGNED_BYTE;
122 case BufferFormat::ATC:
123 case BufferFormat::ATCIA:
124 case BufferFormat::DXT1:
125 case BufferFormat::DXT5:
126 case BufferFormat::ETC1:
127 case BufferFormat::RGBX_8888:
128 case BufferFormat::YUV_420:
129 case BufferFormat::YUV_420_BIPLANAR:
130 NOTREACHED();
131 return 0;
134 NOTREACHED();
135 return 0;
138 GLsizei SizeInBytes(const Size& size, BufferFormat format) {
139 size_t stride_in_bytes = 0;
140 bool valid_stride = GLImageMemory::StrideInBytes(
141 size.width(), format, &stride_in_bytes);
142 DCHECK(valid_stride);
143 return static_cast<GLsizei>(stride_in_bytes * size.height());
146 } // namespace
148 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat)
149 : size_(size),
150 internalformat_(internalformat),
151 memory_(NULL),
152 format_(BufferFormat::RGBA_8888),
153 in_use_(false),
154 target_(0),
155 need_do_bind_tex_image_(false)
156 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
157 defined(USE_OZONE)
159 egl_texture_id_(0u),
160 egl_image_(EGL_NO_IMAGE_KHR)
161 #endif
165 GLImageMemory::~GLImageMemory() {
166 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
167 defined(USE_OZONE)
168 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
169 DCHECK_EQ(0u, egl_texture_id_);
170 #endif
173 // static
174 bool GLImageMemory::StrideInBytes(size_t width,
175 BufferFormat format,
176 size_t* stride_in_bytes) {
177 base::CheckedNumeric<size_t> checked_stride = width;
178 switch (format) {
179 case BufferFormat::ATCIA:
180 case BufferFormat::DXT5:
181 *stride_in_bytes = width;
182 return true;
183 case BufferFormat::ATC:
184 case BufferFormat::DXT1:
185 case BufferFormat::ETC1:
186 DCHECK_EQ(width % 2, 0u);
187 *stride_in_bytes = width / 2;
188 return true;
189 case BufferFormat::R_8:
190 checked_stride += 3;
191 if (!checked_stride.IsValid())
192 return false;
193 *stride_in_bytes = checked_stride.ValueOrDie() & ~0x3;
194 return true;
195 case BufferFormat::RGBA_4444:
196 checked_stride *= 2;
197 if (!checked_stride.IsValid())
198 return false;
199 *stride_in_bytes = checked_stride.ValueOrDie();
200 return true;
201 case BufferFormat::RGBA_8888:
202 case BufferFormat::BGRA_8888:
203 checked_stride *= 4;
204 if (!checked_stride.IsValid())
205 return false;
206 *stride_in_bytes = checked_stride.ValueOrDie();
207 return true;
208 case BufferFormat::RGBX_8888:
209 case BufferFormat::YUV_420:
210 case BufferFormat::YUV_420_BIPLANAR:
211 NOTREACHED();
212 return false;
215 NOTREACHED();
216 return false;
219 bool GLImageMemory::Initialize(const unsigned char* memory,
220 BufferFormat format) {
221 if (!ValidInternalFormat(internalformat_)) {
222 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
223 return false;
226 if (!ValidFormat(format)) {
227 LOG(ERROR) << "Invalid format: " << static_cast<int>(format);
228 return false;
231 DCHECK(memory);
232 DCHECK(!memory_);
233 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
234 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
235 memory_ = memory;
236 format_ = format;
237 return true;
240 void GLImageMemory::Destroy(bool have_context) {
241 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
242 defined(USE_OZONE)
243 if (egl_image_ != EGL_NO_IMAGE_KHR) {
244 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
245 egl_image_ = EGL_NO_IMAGE_KHR;
248 if (egl_texture_id_) {
249 if (have_context)
250 glDeleteTextures(1, &egl_texture_id_);
251 egl_texture_id_ = 0u;
253 #endif
254 memory_ = NULL;
257 Size GLImageMemory::GetSize() {
258 return size_;
261 unsigned GLImageMemory::GetInternalFormat() {
262 return internalformat_;
265 bool GLImageMemory::BindTexImage(unsigned target) {
266 if (target_ && target_ != target) {
267 LOG(ERROR) << "GLImage can only be bound to one target";
268 return false;
270 target_ = target;
272 // Defer DoBindTexImage if not currently in use.
273 if (!in_use_) {
274 need_do_bind_tex_image_ = true;
275 return true;
278 DoBindTexImage(target);
279 return true;
282 bool GLImageMemory::CopyTexSubImage(unsigned target,
283 const Point& offset,
284 const Rect& rect) {
285 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(),
286 "height", rect.height());
288 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target.
289 if (target == GL_TEXTURE_EXTERNAL_OES)
290 return false;
292 // Sub width is not supported.
293 if (rect.width() != size_.width())
294 return false;
296 // Height must be a multiple of 4 if compressed.
297 if (IsCompressedFormat(format_) && rect.height() % 4)
298 return false;
300 size_t stride_in_bytes = 0;
301 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes);
302 DCHECK(rv);
303 DCHECK(memory_);
304 const unsigned char* data = memory_ + rect.y() * stride_in_bytes;
305 if (IsCompressedFormat(format_)) {
306 glCompressedTexSubImage2D(target,
307 0, // level
308 offset.x(), offset.y(), rect.width(),
309 rect.height(), DataFormat(format_),
310 SizeInBytes(rect.size(), format_), data);
311 } else {
312 glTexSubImage2D(target, 0, // level
313 offset.x(), offset.y(), rect.width(), rect.height(),
314 DataFormat(format_), DataType(format_), data);
317 return true;
320 void GLImageMemory::WillUseTexImage() {
321 DCHECK(!in_use_);
322 in_use_ = true;
324 if (!need_do_bind_tex_image_)
325 return;
327 DCHECK(target_);
328 DoBindTexImage(target_);
331 void GLImageMemory::DidUseTexImage() {
332 DCHECK(in_use_);
333 in_use_ = false;
336 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget,
337 int z_order,
338 OverlayTransform transform,
339 const Rect& bounds_rect,
340 const RectF& crop_rect) {
341 return false;
344 void GLImageMemory::DoBindTexImage(unsigned target) {
345 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
347 DCHECK(need_do_bind_tex_image_);
348 need_do_bind_tex_image_ = false;
350 DCHECK(memory_);
351 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
352 defined(USE_OZONE)
353 if (target == GL_TEXTURE_EXTERNAL_OES) {
354 if (egl_image_ == EGL_NO_IMAGE_KHR) {
355 DCHECK_EQ(0u, egl_texture_id_);
356 glGenTextures(1, &egl_texture_id_);
359 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
364 if (IsCompressedFormat(format_)) {
365 glCompressedTexImage2D(GL_TEXTURE_2D,
366 0, // mip level
367 TextureFormat(format_), size_.width(),
368 size_.height(),
369 0, // border
370 SizeInBytes(size_, format_), memory_);
371 } else {
372 glTexImage2D(GL_TEXTURE_2D,
373 0, // mip level
374 TextureFormat(format_),
375 size_.width(),
376 size_.height(),
377 0, // border
378 DataFormat(format_),
379 DataType(format_),
380 memory_);
384 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
385 // Need to pass current EGL rendering context to eglCreateImageKHR for
386 // target type EGL_GL_TEXTURE_2D_KHR.
387 egl_image_ =
388 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
389 eglGetCurrentContext(),
390 EGL_GL_TEXTURE_2D_KHR,
391 reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
392 attrs);
393 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
394 << "Error creating EGLImage: " << eglGetError();
395 } else {
396 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
398 if (IsCompressedFormat(format_)) {
399 glCompressedTexSubImage2D(GL_TEXTURE_2D,
400 0, // mip level
401 0, // x-offset
402 0, // y-offset
403 size_.width(), size_.height(),
404 DataFormat(format_),
405 SizeInBytes(size_, format_), memory_);
406 } else {
407 glTexSubImage2D(GL_TEXTURE_2D,
408 0, // mip level
409 0, // x-offset
410 0, // y-offset
411 size_.width(),
412 size_.height(),
413 DataFormat(format_),
414 DataType(format_),
415 memory_);
419 glEGLImageTargetTexture2DOES(target, egl_image_);
420 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
421 return;
423 #endif
425 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
426 if (IsCompressedFormat(format_)) {
427 glCompressedTexImage2D(target,
428 0, // mip level
429 TextureFormat(format_), size_.width(),
430 size_.height(),
431 0, // border
432 SizeInBytes(size_, format_), memory_);
433 } else {
434 glTexImage2D(target,
435 0, // mip level
436 TextureFormat(format_),
437 size_.width(),
438 size_.height(),
439 0, // border
440 DataFormat(format_),
441 DataType(format_),
442 memory_);
446 } // namespace gfx