Add ICU message format support
[chromium-blink-merge.git] / ui / gl / gl_image_memory.cc
blobf34611851c042ab8a3fdb92ae4df2ce69c882744
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 return false;
53 NOTREACHED();
54 return false;
57 bool IsCompressedFormat(BufferFormat format) {
58 switch (format) {
59 case BufferFormat::ATC:
60 case BufferFormat::ATCIA:
61 case BufferFormat::DXT1:
62 case BufferFormat::DXT5:
63 case BufferFormat::ETC1:
64 case BufferFormat::YUV_420:
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 return false;
74 NOTREACHED();
75 return false;
78 GLenum TextureFormat(BufferFormat format) {
79 switch (format) {
80 case BufferFormat::ATC:
81 return GL_ATC_RGB_AMD;
82 case BufferFormat::ATCIA:
83 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
84 case BufferFormat::DXT1:
85 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
86 case BufferFormat::DXT5:
87 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
88 case BufferFormat::ETC1:
89 return GL_ETC1_RGB8_OES;
90 case BufferFormat::R_8:
91 return GL_RED;
92 case BufferFormat::RGBA_4444:
93 case BufferFormat::RGBA_8888:
94 return GL_RGBA;
95 case BufferFormat::BGRA_8888:
96 return GL_BGRA_EXT;
97 case BufferFormat::RGBX_8888:
98 case BufferFormat::YUV_420:
99 NOTREACHED();
100 return 0;
103 NOTREACHED();
104 return 0;
107 GLenum DataFormat(BufferFormat format) {
108 return TextureFormat(format);
111 GLenum DataType(BufferFormat format) {
112 switch (format) {
113 case BufferFormat::RGBA_4444:
114 return GL_UNSIGNED_SHORT_4_4_4_4;
115 case BufferFormat::RGBA_8888:
116 case BufferFormat::BGRA_8888:
117 case BufferFormat::R_8:
118 return GL_UNSIGNED_BYTE;
119 case BufferFormat::ATC:
120 case BufferFormat::ATCIA:
121 case BufferFormat::DXT1:
122 case BufferFormat::DXT5:
123 case BufferFormat::ETC1:
124 case BufferFormat::RGBX_8888:
125 case BufferFormat::YUV_420:
126 NOTREACHED();
127 return 0;
130 NOTREACHED();
131 return 0;
134 GLsizei SizeInBytes(const Size& size, BufferFormat format) {
135 size_t stride_in_bytes = 0;
136 bool valid_stride = GLImageMemory::StrideInBytes(
137 size.width(), format, &stride_in_bytes);
138 DCHECK(valid_stride);
139 return static_cast<GLsizei>(stride_in_bytes * size.height());
142 } // namespace
144 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat)
145 : size_(size),
146 internalformat_(internalformat),
147 memory_(NULL),
148 format_(BufferFormat::RGBA_8888),
149 in_use_(false),
150 target_(0),
151 need_do_bind_tex_image_(false)
152 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
153 defined(USE_OZONE)
155 egl_texture_id_(0u),
156 egl_image_(EGL_NO_IMAGE_KHR)
157 #endif
161 GLImageMemory::~GLImageMemory() {
162 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
163 defined(USE_OZONE)
164 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
165 DCHECK_EQ(0u, egl_texture_id_);
166 #endif
169 // static
170 bool GLImageMemory::StrideInBytes(size_t width,
171 BufferFormat format,
172 size_t* stride_in_bytes) {
173 base::CheckedNumeric<size_t> checked_stride = width;
174 switch (format) {
175 case BufferFormat::ATCIA:
176 case BufferFormat::DXT5:
177 *stride_in_bytes = width;
178 return true;
179 case BufferFormat::ATC:
180 case BufferFormat::DXT1:
181 case BufferFormat::ETC1:
182 DCHECK_EQ(width % 2, 0u);
183 *stride_in_bytes = width / 2;
184 return true;
185 case BufferFormat::R_8:
186 checked_stride += 3;
187 if (!checked_stride.IsValid())
188 return false;
189 *stride_in_bytes = checked_stride.ValueOrDie() & ~0x3;
190 return true;
191 case BufferFormat::RGBA_4444:
192 checked_stride *= 2;
193 if (!checked_stride.IsValid())
194 return false;
195 *stride_in_bytes = checked_stride.ValueOrDie();
196 return true;
197 case BufferFormat::RGBA_8888:
198 case BufferFormat::BGRA_8888:
199 checked_stride *= 4;
200 if (!checked_stride.IsValid())
201 return false;
202 *stride_in_bytes = checked_stride.ValueOrDie();
203 return true;
204 case BufferFormat::RGBX_8888:
205 case BufferFormat::YUV_420:
206 NOTREACHED();
207 return false;
210 NOTREACHED();
211 return false;
214 bool GLImageMemory::Initialize(const unsigned char* memory,
215 BufferFormat format) {
216 if (!ValidInternalFormat(internalformat_)) {
217 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
218 return false;
221 if (!ValidFormat(format)) {
222 LOG(ERROR) << "Invalid format: " << static_cast<int>(format);
223 return false;
226 DCHECK(memory);
227 DCHECK(!memory_);
228 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0);
229 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0);
230 memory_ = memory;
231 format_ = format;
232 return true;
235 void GLImageMemory::Destroy(bool have_context) {
236 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
237 defined(USE_OZONE)
238 if (egl_image_ != EGL_NO_IMAGE_KHR) {
239 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
240 egl_image_ = EGL_NO_IMAGE_KHR;
243 if (egl_texture_id_) {
244 if (have_context)
245 glDeleteTextures(1, &egl_texture_id_);
246 egl_texture_id_ = 0u;
248 #endif
249 memory_ = NULL;
252 Size GLImageMemory::GetSize() {
253 return size_;
256 unsigned GLImageMemory::GetInternalFormat() {
257 return internalformat_;
260 bool GLImageMemory::BindTexImage(unsigned target) {
261 if (target_ && target_ != target) {
262 LOG(ERROR) << "GLImage can only be bound to one target";
263 return false;
265 target_ = target;
267 // Defer DoBindTexImage if not currently in use.
268 if (!in_use_) {
269 need_do_bind_tex_image_ = true;
270 return true;
273 DoBindTexImage(target);
274 return true;
277 bool GLImageMemory::CopyTexSubImage(unsigned target,
278 const Point& offset,
279 const Rect& rect) {
280 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(),
281 "height", rect.height());
283 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target.
284 if (target == GL_TEXTURE_EXTERNAL_OES)
285 return false;
287 // Sub width is not supported.
288 if (rect.width() != size_.width())
289 return false;
291 // Height must be a multiple of 4 if compressed.
292 if (IsCompressedFormat(format_) && rect.height() % 4)
293 return false;
295 size_t stride_in_bytes = 0;
296 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes);
297 DCHECK(rv);
298 DCHECK(memory_);
299 const unsigned char* data = memory_ + rect.y() * stride_in_bytes;
300 if (IsCompressedFormat(format_)) {
301 glCompressedTexSubImage2D(target,
302 0, // level
303 offset.x(), offset.y(), rect.width(),
304 rect.height(), DataFormat(format_),
305 SizeInBytes(rect.size(), format_), data);
306 } else {
307 glTexSubImage2D(target, 0, // level
308 offset.x(), offset.y(), rect.width(), rect.height(),
309 DataFormat(format_), DataType(format_), data);
312 return true;
315 void GLImageMemory::WillUseTexImage() {
316 DCHECK(!in_use_);
317 in_use_ = true;
319 if (!need_do_bind_tex_image_)
320 return;
322 DCHECK(target_);
323 DoBindTexImage(target_);
326 void GLImageMemory::DidUseTexImage() {
327 DCHECK(in_use_);
328 in_use_ = false;
331 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget,
332 int z_order,
333 OverlayTransform transform,
334 const Rect& bounds_rect,
335 const RectF& crop_rect) {
336 return false;
339 void GLImageMemory::DoBindTexImage(unsigned target) {
340 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
342 DCHECK(need_do_bind_tex_image_);
343 need_do_bind_tex_image_ = false;
345 DCHECK(memory_);
346 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
347 defined(USE_OZONE)
348 if (target == GL_TEXTURE_EXTERNAL_OES) {
349 if (egl_image_ == EGL_NO_IMAGE_KHR) {
350 DCHECK_EQ(0u, egl_texture_id_);
351 glGenTextures(1, &egl_texture_id_);
354 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
359 if (IsCompressedFormat(format_)) {
360 glCompressedTexImage2D(GL_TEXTURE_2D,
361 0, // mip level
362 TextureFormat(format_), size_.width(),
363 size_.height(),
364 0, // border
365 SizeInBytes(size_, format_), memory_);
366 } else {
367 glTexImage2D(GL_TEXTURE_2D,
368 0, // mip level
369 TextureFormat(format_),
370 size_.width(),
371 size_.height(),
372 0, // border
373 DataFormat(format_),
374 DataType(format_),
375 memory_);
379 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
380 // Need to pass current EGL rendering context to eglCreateImageKHR for
381 // target type EGL_GL_TEXTURE_2D_KHR.
382 egl_image_ =
383 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
384 eglGetCurrentContext(),
385 EGL_GL_TEXTURE_2D_KHR,
386 reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
387 attrs);
388 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
389 << "Error creating EGLImage: " << eglGetError();
390 } else {
391 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
393 if (IsCompressedFormat(format_)) {
394 glCompressedTexSubImage2D(GL_TEXTURE_2D,
395 0, // mip level
396 0, // x-offset
397 0, // y-offset
398 size_.width(), size_.height(),
399 DataFormat(format_),
400 SizeInBytes(size_, format_), memory_);
401 } else {
402 glTexSubImage2D(GL_TEXTURE_2D,
403 0, // mip level
404 0, // x-offset
405 0, // y-offset
406 size_.width(),
407 size_.height(),
408 DataFormat(format_),
409 DataType(format_),
410 memory_);
414 glEGLImageTargetTexture2DOES(target, egl_image_);
415 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
416 return;
418 #endif
420 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
421 if (IsCompressedFormat(format_)) {
422 glCompressedTexImage2D(target,
423 0, // mip level
424 TextureFormat(format_), size_.width(),
425 size_.height(),
426 0, // border
427 SizeInBytes(size_, format_), memory_);
428 } else {
429 glTexImage2D(target,
430 0, // mip level
431 TextureFormat(format_),
432 size_.width(),
433 size_.height(),
434 0, // border
435 DataFormat(format_),
436 DataType(format_),
437 memory_);
441 } // namespace gfx