cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / ui / gl / gl_image_memory.cc
blobc91ad5635f9ccad1e124e926a436b49fcc442146
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::BGRX_8888:
49 case BufferFormat::YUV_420:
50 case BufferFormat::YUV_420_BIPLANAR:
51 case BufferFormat::UYVY_422:
52 return false;
55 NOTREACHED();
56 return false;
59 bool IsCompressedFormat(BufferFormat format) {
60 switch (format) {
61 case BufferFormat::ATC:
62 case BufferFormat::ATCIA:
63 case BufferFormat::DXT1:
64 case BufferFormat::DXT5:
65 case BufferFormat::ETC1:
66 return true;
67 case BufferFormat::R_8:
68 case BufferFormat::RGBA_4444:
69 case BufferFormat::RGBA_8888:
70 case BufferFormat::BGRA_8888:
71 case BufferFormat::BGRX_8888:
72 case BufferFormat::YUV_420:
73 case BufferFormat::YUV_420_BIPLANAR:
74 case BufferFormat::UYVY_422:
75 return false;
78 NOTREACHED();
79 return false;
82 GLenum TextureFormat(BufferFormat format) {
83 switch (format) {
84 case BufferFormat::ATC:
85 return GL_ATC_RGB_AMD;
86 case BufferFormat::ATCIA:
87 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
88 case BufferFormat::DXT1:
89 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
90 case BufferFormat::DXT5:
91 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
92 case BufferFormat::ETC1:
93 return GL_ETC1_RGB8_OES;
94 case BufferFormat::R_8:
95 return GL_RED;
96 case BufferFormat::RGBA_4444:
97 case BufferFormat::RGBA_8888:
98 return GL_RGBA;
99 case BufferFormat::BGRA_8888:
100 return GL_BGRA_EXT;
101 case BufferFormat::BGRX_8888:
102 case BufferFormat::YUV_420:
103 case BufferFormat::YUV_420_BIPLANAR:
104 case BufferFormat::UYVY_422:
105 NOTREACHED();
106 return 0;
109 NOTREACHED();
110 return 0;
113 GLenum DataFormat(BufferFormat format) {
114 return TextureFormat(format);
117 GLenum DataType(BufferFormat format) {
118 switch (format) {
119 case BufferFormat::RGBA_4444:
120 return GL_UNSIGNED_SHORT_4_4_4_4;
121 case BufferFormat::RGBA_8888:
122 case BufferFormat::BGRA_8888:
123 case BufferFormat::R_8:
124 return GL_UNSIGNED_BYTE;
125 case BufferFormat::ATC:
126 case BufferFormat::ATCIA:
127 case BufferFormat::DXT1:
128 case BufferFormat::DXT5:
129 case BufferFormat::ETC1:
130 case BufferFormat::BGRX_8888:
131 case BufferFormat::YUV_420:
132 case BufferFormat::YUV_420_BIPLANAR:
133 case BufferFormat::UYVY_422:
134 NOTREACHED();
135 return 0;
138 NOTREACHED();
139 return 0;
142 GLsizei SizeInBytes(const Size& size, BufferFormat format) {
143 size_t stride_in_bytes = 0;
144 bool valid_stride = GLImageMemory::StrideInBytes(
145 size.width(), format, &stride_in_bytes);
146 DCHECK(valid_stride);
147 return static_cast<GLsizei>(stride_in_bytes * size.height());
150 } // namespace
152 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat)
153 : size_(size),
154 internalformat_(internalformat),
155 memory_(NULL),
156 format_(BufferFormat::RGBA_8888),
157 in_use_(false),
158 target_(0),
159 need_do_bind_tex_image_(false)
160 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
161 defined(USE_OZONE)
163 egl_texture_id_(0u),
164 egl_image_(EGL_NO_IMAGE_KHR)
165 #endif
169 GLImageMemory::~GLImageMemory() {
170 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
171 defined(USE_OZONE)
172 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
173 DCHECK_EQ(0u, egl_texture_id_);
174 #endif
177 // static
178 bool GLImageMemory::StrideInBytes(size_t width,
179 BufferFormat format,
180 size_t* stride_in_bytes) {
181 base::CheckedNumeric<size_t> checked_stride = width;
182 switch (format) {
183 case BufferFormat::ATCIA:
184 case BufferFormat::DXT5:
185 *stride_in_bytes = width;
186 return true;
187 case BufferFormat::ATC:
188 case BufferFormat::DXT1:
189 case BufferFormat::ETC1:
190 DCHECK_EQ(width % 2, 0u);
191 *stride_in_bytes = width / 2;
192 return true;
193 case BufferFormat::R_8:
194 checked_stride += 3;
195 if (!checked_stride.IsValid())
196 return false;
197 *stride_in_bytes = checked_stride.ValueOrDie() & ~0x3;
198 return true;
199 case BufferFormat::RGBA_4444:
200 checked_stride *= 2;
201 if (!checked_stride.IsValid())
202 return false;
203 *stride_in_bytes = checked_stride.ValueOrDie();
204 return true;
205 case BufferFormat::RGBA_8888:
206 case BufferFormat::BGRA_8888:
207 checked_stride *= 4;
208 if (!checked_stride.IsValid())
209 return false;
210 *stride_in_bytes = checked_stride.ValueOrDie();
211 return true;
212 case BufferFormat::BGRX_8888:
213 case BufferFormat::YUV_420:
214 case BufferFormat::YUV_420_BIPLANAR:
215 case BufferFormat::UYVY_422:
216 NOTREACHED();
217 return false;
220 NOTREACHED();
221 return false;
224 bool GLImageMemory::Initialize(const unsigned char* memory,
225 BufferFormat format) {
226 if (!ValidInternalFormat(internalformat_)) {
227 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
228 return false;
231 if (!ValidFormat(format)) {
232 LOG(ERROR) << "Invalid format: " << static_cast<int>(format);
233 return false;
236 DCHECK(memory);
237 DCHECK(!memory_);
238 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
239 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
240 memory_ = memory;
241 format_ = format;
242 return true;
245 void GLImageMemory::Destroy(bool have_context) {
246 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
247 defined(USE_OZONE)
248 if (egl_image_ != EGL_NO_IMAGE_KHR) {
249 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
250 egl_image_ = EGL_NO_IMAGE_KHR;
253 if (egl_texture_id_) {
254 if (have_context)
255 glDeleteTextures(1, &egl_texture_id_);
256 egl_texture_id_ = 0u;
258 #endif
259 memory_ = NULL;
262 Size GLImageMemory::GetSize() {
263 return size_;
266 unsigned GLImageMemory::GetInternalFormat() {
267 return internalformat_;
270 bool GLImageMemory::BindTexImage(unsigned target) {
271 if (target_ && target_ != target) {
272 LOG(ERROR) << "GLImage can only be bound to one target";
273 return false;
275 target_ = target;
277 // Defer DoBindTexImage if not currently in use.
278 if (!in_use_) {
279 need_do_bind_tex_image_ = true;
280 return true;
283 DoBindTexImage(target);
284 return true;
287 bool GLImageMemory::CopyTexSubImage(unsigned target,
288 const Point& offset,
289 const Rect& rect) {
290 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(),
291 "height", rect.height());
293 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target.
294 if (target == GL_TEXTURE_EXTERNAL_OES)
295 return false;
297 // Sub width is not supported.
298 if (rect.width() != size_.width())
299 return false;
301 // Height must be a multiple of 4 if compressed.
302 if (IsCompressedFormat(format_) && rect.height() % 4)
303 return false;
305 size_t stride_in_bytes = 0;
306 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes);
307 DCHECK(rv);
308 DCHECK(memory_);
309 const unsigned char* data = memory_ + rect.y() * stride_in_bytes;
310 if (IsCompressedFormat(format_)) {
311 glCompressedTexSubImage2D(target,
312 0, // level
313 offset.x(), offset.y(), rect.width(),
314 rect.height(), DataFormat(format_),
315 SizeInBytes(rect.size(), format_), data);
316 } else {
317 glTexSubImage2D(target, 0, // level
318 offset.x(), offset.y(), rect.width(), rect.height(),
319 DataFormat(format_), DataType(format_), data);
322 return true;
325 void GLImageMemory::WillUseTexImage() {
326 DCHECK(!in_use_);
327 in_use_ = true;
329 if (!need_do_bind_tex_image_)
330 return;
332 DCHECK(target_);
333 DoBindTexImage(target_);
336 void GLImageMemory::DidUseTexImage() {
337 DCHECK(in_use_);
338 in_use_ = false;
341 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget,
342 int z_order,
343 OverlayTransform transform,
344 const Rect& bounds_rect,
345 const RectF& crop_rect) {
346 return false;
349 void GLImageMemory::DoBindTexImage(unsigned target) {
350 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
352 DCHECK(need_do_bind_tex_image_);
353 need_do_bind_tex_image_ = false;
355 DCHECK(memory_);
356 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
357 defined(USE_OZONE)
358 if (target == GL_TEXTURE_EXTERNAL_OES) {
359 if (egl_image_ == EGL_NO_IMAGE_KHR) {
360 DCHECK_EQ(0u, egl_texture_id_);
361 glGenTextures(1, &egl_texture_id_);
364 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
369 if (IsCompressedFormat(format_)) {
370 glCompressedTexImage2D(GL_TEXTURE_2D,
371 0, // mip level
372 TextureFormat(format_), size_.width(),
373 size_.height(),
374 0, // border
375 SizeInBytes(size_, format_), memory_);
376 } else {
377 glTexImage2D(GL_TEXTURE_2D,
378 0, // mip level
379 TextureFormat(format_),
380 size_.width(),
381 size_.height(),
382 0, // border
383 DataFormat(format_),
384 DataType(format_),
385 memory_);
389 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
390 // Need to pass current EGL rendering context to eglCreateImageKHR for
391 // target type EGL_GL_TEXTURE_2D_KHR.
392 egl_image_ =
393 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
394 eglGetCurrentContext(),
395 EGL_GL_TEXTURE_2D_KHR,
396 reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
397 attrs);
398 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
399 << "Error creating EGLImage: " << eglGetError();
400 } else {
401 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
403 if (IsCompressedFormat(format_)) {
404 glCompressedTexSubImage2D(GL_TEXTURE_2D,
405 0, // mip level
406 0, // x-offset
407 0, // y-offset
408 size_.width(), size_.height(),
409 DataFormat(format_),
410 SizeInBytes(size_, format_), memory_);
411 } else {
412 glTexSubImage2D(GL_TEXTURE_2D,
413 0, // mip level
414 0, // x-offset
415 0, // y-offset
416 size_.width(),
417 size_.height(),
418 DataFormat(format_),
419 DataType(format_),
420 memory_);
424 glEGLImageTargetTexture2DOES(target, egl_image_);
425 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
426 return;
428 #endif
430 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
431 if (IsCompressedFormat(format_)) {
432 glCompressedTexImage2D(target,
433 0, // mip level
434 TextureFormat(format_), size_.width(),
435 size_.height(),
436 0, // border
437 SizeInBytes(size_, format_), memory_);
438 } else {
439 glTexImage2D(target,
440 0, // mip level
441 TextureFormat(format_),
442 size_.width(),
443 size_.height(),
444 0, // border
445 DataFormat(format_),
446 DataType(format_),
447 memory_);
451 void GLImageMemory::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
452 uint64_t process_tracing_id,
453 const std::string& dump_name) {
454 // Note that the following calculation does not consider whether this GLImage
455 // has been un-bound from a texture. It also relies on this GLImage only ever
456 // being bound to a single texture. We could check these conditions more
457 // thoroughly, but at the cost of extra GL queries.
458 bool is_bound_to_texture = target_ && !need_do_bind_tex_image_;
460 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
461 defined(USE_OZONE)
462 is_bound_to_texture |= !!egl_texture_id_;
463 #endif
465 size_t size_in_bytes = is_bound_to_texture ? SizeInBytes(size_, format_) : 0;
467 base::trace_event::MemoryAllocatorDump* dump =
468 pmd->CreateAllocatorDump(dump_name + "/texture_memory");
469 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
470 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
471 static_cast<uint64_t>(size_in_bytes));
473 // No need for a global shared edge here. This object in the GPU process is
474 // the sole owner of this texture id.
477 } // namespace gfx