Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / gl / gl_image_memory.cc
blob5ccb9d160f8c7d124a4e58e631b1ff9811778243
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(GpuMemoryBuffer::Format format) {
37 switch (format) {
38 case GpuMemoryBuffer::ATC:
39 case GpuMemoryBuffer::ATCIA:
40 case GpuMemoryBuffer::DXT1:
41 case GpuMemoryBuffer::DXT5:
42 case GpuMemoryBuffer::ETC1:
43 case GpuMemoryBuffer::R_8:
44 case GpuMemoryBuffer::RGBA_4444:
45 case GpuMemoryBuffer::RGBA_8888:
46 case GpuMemoryBuffer::BGRA_8888:
47 return true;
48 case GpuMemoryBuffer::RGBX_8888:
49 case GpuMemoryBuffer::YUV_420:
50 return false;
53 NOTREACHED();
54 return false;
57 bool IsCompressedFormat(GpuMemoryBuffer::Format format) {
58 switch (format) {
59 case GpuMemoryBuffer::ATC:
60 case GpuMemoryBuffer::ATCIA:
61 case GpuMemoryBuffer::DXT1:
62 case GpuMemoryBuffer::DXT5:
63 case GpuMemoryBuffer::ETC1:
64 case GpuMemoryBuffer::YUV_420:
65 return true;
66 case GpuMemoryBuffer::R_8:
67 case GpuMemoryBuffer::RGBA_4444:
68 case GpuMemoryBuffer::RGBA_8888:
69 case GpuMemoryBuffer::BGRA_8888:
70 case GpuMemoryBuffer::RGBX_8888:
71 return false;
74 NOTREACHED();
75 return false;
78 GLenum TextureFormat(GpuMemoryBuffer::Format format) {
79 switch (format) {
80 case GpuMemoryBuffer::ATC:
81 return GL_ATC_RGB_AMD;
82 case GpuMemoryBuffer::ATCIA:
83 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
84 case GpuMemoryBuffer::DXT1:
85 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
86 case GpuMemoryBuffer::DXT5:
87 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
88 case GpuMemoryBuffer::ETC1:
89 return GL_ETC1_RGB8_OES;
90 case GpuMemoryBuffer::R_8:
91 return GL_RED;
92 case GpuMemoryBuffer::RGBA_4444:
93 case GpuMemoryBuffer::RGBA_8888:
94 return GL_RGBA;
95 case GpuMemoryBuffer::BGRA_8888:
96 return GL_BGRA_EXT;
97 case GpuMemoryBuffer::RGBX_8888:
98 case GpuMemoryBuffer::YUV_420:
99 NOTREACHED();
100 return 0;
103 NOTREACHED();
104 return 0;
107 GLenum DataFormat(GpuMemoryBuffer::Format format) {
108 return TextureFormat(format);
111 GLenum DataType(GpuMemoryBuffer::Format format) {
112 switch (format) {
113 case GpuMemoryBuffer::RGBA_4444:
114 return GL_UNSIGNED_SHORT_4_4_4_4;
115 case GpuMemoryBuffer::RGBA_8888:
116 case GpuMemoryBuffer::BGRA_8888:
117 case GpuMemoryBuffer::R_8:
118 return GL_UNSIGNED_BYTE;
119 case GpuMemoryBuffer::ATC:
120 case GpuMemoryBuffer::ATCIA:
121 case GpuMemoryBuffer::DXT1:
122 case GpuMemoryBuffer::DXT5:
123 case GpuMemoryBuffer::ETC1:
124 case GpuMemoryBuffer::RGBX_8888:
125 case GpuMemoryBuffer::YUV_420:
126 NOTREACHED();
127 return 0;
130 NOTREACHED();
131 return 0;
134 GLsizei SizeInBytes(const Size& size,
135 GpuMemoryBuffer::Format format) {
136 size_t stride_in_bytes = 0;
137 bool valid_stride = GLImageMemory::StrideInBytes(
138 size.width(), format, &stride_in_bytes);
139 DCHECK(valid_stride);
140 return static_cast<GLsizei>(stride_in_bytes * size.height());
143 } // namespace
145 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat)
146 : size_(size),
147 internalformat_(internalformat),
148 memory_(NULL),
149 format_(GpuMemoryBuffer::RGBA_8888),
150 in_use_(false),
151 target_(0),
152 need_do_bind_tex_image_(false)
153 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
154 defined(USE_OZONE)
156 egl_texture_id_(0u),
157 egl_image_(EGL_NO_IMAGE_KHR)
158 #endif
162 GLImageMemory::~GLImageMemory() {
163 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
164 defined(USE_OZONE)
165 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
166 DCHECK_EQ(0u, egl_texture_id_);
167 #endif
170 // static
171 bool GLImageMemory::StrideInBytes(size_t width,
172 GpuMemoryBuffer::Format format,
173 size_t* stride_in_bytes) {
174 base::CheckedNumeric<size_t> checked_stride = width;
175 switch (format) {
176 case GpuMemoryBuffer::ATCIA:
177 case GpuMemoryBuffer::DXT5:
178 *stride_in_bytes = width;
179 return true;
180 case GpuMemoryBuffer::ATC:
181 case GpuMemoryBuffer::DXT1:
182 case GpuMemoryBuffer::ETC1:
183 DCHECK_EQ(width % 2, 0u);
184 *stride_in_bytes = width / 2;
185 return true;
186 case GpuMemoryBuffer::R_8:
187 checked_stride += 3;
188 if (!checked_stride.IsValid())
189 return false;
190 *stride_in_bytes = checked_stride.ValueOrDie() & ~0x3;
191 return true;
192 case GpuMemoryBuffer::RGBA_4444:
193 checked_stride *= 2;
194 if (!checked_stride.IsValid())
195 return false;
196 *stride_in_bytes = checked_stride.ValueOrDie();
197 return true;
198 case GpuMemoryBuffer::RGBA_8888:
199 case GpuMemoryBuffer::BGRA_8888:
200 checked_stride *= 4;
201 if (!checked_stride.IsValid())
202 return false;
203 *stride_in_bytes = checked_stride.ValueOrDie();
204 return true;
205 case GpuMemoryBuffer::RGBX_8888:
206 case GpuMemoryBuffer::YUV_420:
207 NOTREACHED();
208 return false;
211 NOTREACHED();
212 return false;
215 bool GLImageMemory::Initialize(const unsigned char* memory,
216 GpuMemoryBuffer::Format format) {
217 if (!ValidInternalFormat(internalformat_)) {
218 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
219 return false;
222 if (!ValidFormat(format)) {
223 LOG(ERROR) << "Invalid format: " << format;
224 return false;
227 DCHECK(memory);
228 DCHECK(!memory_);
229 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
230 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
231 memory_ = memory;
232 format_ = format;
233 return true;
236 void GLImageMemory::Destroy(bool have_context) {
237 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
238 defined(USE_OZONE)
239 if (egl_image_ != EGL_NO_IMAGE_KHR) {
240 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
241 egl_image_ = EGL_NO_IMAGE_KHR;
244 if (egl_texture_id_) {
245 if (have_context)
246 glDeleteTextures(1, &egl_texture_id_);
247 egl_texture_id_ = 0u;
249 #endif
250 memory_ = NULL;
253 Size GLImageMemory::GetSize() {
254 return size_;
257 unsigned GLImageMemory::GetInternalFormat() {
258 return internalformat_;
261 bool GLImageMemory::BindTexImage(unsigned target) {
262 if (target_ && target_ != target) {
263 LOG(ERROR) << "GLImage can only be bound to one target";
264 return false;
266 target_ = target;
268 // Defer DoBindTexImage if not currently in use.
269 if (!in_use_) {
270 need_do_bind_tex_image_ = true;
271 return true;
274 DoBindTexImage(target);
275 return true;
278 bool GLImageMemory::CopyTexSubImage(unsigned target,
279 const Point& offset,
280 const Rect& rect) {
281 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(),
282 "height", rect.height());
284 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target.
285 if (target == GL_TEXTURE_EXTERNAL_OES)
286 return false;
288 // Sub width is not supported.
289 if (rect.width() != size_.width())
290 return false;
292 // Height must be a multiple of 4 if compressed.
293 if (IsCompressedFormat(format_) && rect.height() % 4)
294 return false;
296 size_t stride_in_bytes = 0;
297 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes);
298 DCHECK(rv);
299 DCHECK(memory_);
300 const unsigned char* data = memory_ + rect.y() * stride_in_bytes;
301 if (IsCompressedFormat(format_)) {
302 glCompressedTexSubImage2D(target,
303 0, // level
304 offset.x(), offset.y(), rect.width(),
305 rect.height(), DataFormat(format_),
306 SizeInBytes(rect.size(), format_), data);
307 } else {
308 glTexSubImage2D(target, 0, // level
309 offset.x(), offset.y(), rect.width(), rect.height(),
310 DataFormat(format_), DataType(format_), data);
313 return true;
316 void GLImageMemory::WillUseTexImage() {
317 DCHECK(!in_use_);
318 in_use_ = true;
320 if (!need_do_bind_tex_image_)
321 return;
323 DCHECK(target_);
324 DoBindTexImage(target_);
327 void GLImageMemory::DidUseTexImage() {
328 DCHECK(in_use_);
329 in_use_ = false;
332 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget,
333 int z_order,
334 OverlayTransform transform,
335 const Rect& bounds_rect,
336 const RectF& crop_rect) {
337 return false;
340 void GLImageMemory::DoBindTexImage(unsigned target) {
341 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
343 DCHECK(need_do_bind_tex_image_);
344 need_do_bind_tex_image_ = false;
346 DCHECK(memory_);
347 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
348 defined(USE_OZONE)
349 if (target == GL_TEXTURE_EXTERNAL_OES) {
350 if (egl_image_ == EGL_NO_IMAGE_KHR) {
351 DCHECK_EQ(0u, egl_texture_id_);
352 glGenTextures(1, &egl_texture_id_);
355 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
360 if (IsCompressedFormat(format_)) {
361 glCompressedTexImage2D(GL_TEXTURE_2D,
362 0, // mip level
363 TextureFormat(format_), size_.width(),
364 size_.height(),
365 0, // border
366 SizeInBytes(size_, format_), memory_);
367 } else {
368 glTexImage2D(GL_TEXTURE_2D,
369 0, // mip level
370 TextureFormat(format_),
371 size_.width(),
372 size_.height(),
373 0, // border
374 DataFormat(format_),
375 DataType(format_),
376 memory_);
380 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
381 // Need to pass current EGL rendering context to eglCreateImageKHR for
382 // target type EGL_GL_TEXTURE_2D_KHR.
383 egl_image_ =
384 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
385 eglGetCurrentContext(),
386 EGL_GL_TEXTURE_2D_KHR,
387 reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
388 attrs);
389 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
390 << "Error creating EGLImage: " << eglGetError();
391 } else {
392 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
394 if (IsCompressedFormat(format_)) {
395 glCompressedTexSubImage2D(GL_TEXTURE_2D,
396 0, // mip level
397 0, // x-offset
398 0, // y-offset
399 size_.width(), size_.height(),
400 DataFormat(format_),
401 SizeInBytes(size_, format_), memory_);
402 } else {
403 glTexSubImage2D(GL_TEXTURE_2D,
404 0, // mip level
405 0, // x-offset
406 0, // y-offset
407 size_.width(),
408 size_.height(),
409 DataFormat(format_),
410 DataType(format_),
411 memory_);
415 glEGLImageTargetTexture2DOES(target, egl_image_);
416 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
417 return;
419 #endif
421 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
422 if (IsCompressedFormat(format_)) {
423 glCompressedTexImage2D(target,
424 0, // mip level
425 TextureFormat(format_), size_.width(),
426 size_.height(),
427 0, // border
428 SizeInBytes(size_, format_), memory_);
429 } else {
430 glTexImage2D(target,
431 0, // mip level
432 TextureFormat(format_),
433 size_.width(),
434 size_.height(),
435 0, // border
436 DataFormat(format_),
437 DataType(format_),
438 memory_);
442 } // namespace gfx