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) || \
14 #include "ui/gl/gl_surface_egl.h"
20 bool ValidInternalFormat(unsigned internalformat
) {
21 switch (internalformat
) {
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
:
36 bool ValidFormat(BufferFormat 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
:
48 case BufferFormat::RGBX_8888
:
49 case BufferFormat::YUV_420
:
50 case BufferFormat::YUV_420_BIPLANAR
:
58 bool IsCompressedFormat(BufferFormat format
) {
60 case BufferFormat::ATC
:
61 case BufferFormat::ATCIA
:
62 case BufferFormat::DXT1
:
63 case BufferFormat::DXT5
:
64 case BufferFormat::ETC1
:
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
:
80 GLenum
TextureFormat(BufferFormat 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
:
94 case BufferFormat::RGBA_4444
:
95 case BufferFormat::RGBA_8888
:
97 case BufferFormat::BGRA_8888
:
99 case BufferFormat::RGBX_8888
:
100 case BufferFormat::YUV_420
:
101 case BufferFormat::YUV_420_BIPLANAR
:
110 GLenum
DataFormat(BufferFormat format
) {
111 return TextureFormat(format
);
114 GLenum
DataType(BufferFormat 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
:
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());
148 GLImageMemory::GLImageMemory(const Size
& size
, unsigned internalformat
)
150 internalformat_(internalformat
),
152 format_(BufferFormat::RGBA_8888
),
155 need_do_bind_tex_image_(false)
156 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
160 egl_image_(EGL_NO_IMAGE_KHR
)
165 GLImageMemory::~GLImageMemory() {
166 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
168 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
169 DCHECK_EQ(0u, egl_texture_id_
);
174 bool GLImageMemory::StrideInBytes(size_t width
,
176 size_t* stride_in_bytes
) {
177 base::CheckedNumeric
<size_t> checked_stride
= width
;
179 case BufferFormat::ATCIA
:
180 case BufferFormat::DXT5
:
181 *stride_in_bytes
= width
;
183 case BufferFormat::ATC
:
184 case BufferFormat::DXT1
:
185 case BufferFormat::ETC1
:
186 DCHECK_EQ(width
% 2, 0u);
187 *stride_in_bytes
= width
/ 2;
189 case BufferFormat::R_8
:
191 if (!checked_stride
.IsValid())
193 *stride_in_bytes
= checked_stride
.ValueOrDie() & ~0x3;
195 case BufferFormat::RGBA_4444
:
197 if (!checked_stride
.IsValid())
199 *stride_in_bytes
= checked_stride
.ValueOrDie();
201 case BufferFormat::RGBA_8888
:
202 case BufferFormat::BGRA_8888
:
204 if (!checked_stride
.IsValid())
206 *stride_in_bytes
= checked_stride
.ValueOrDie();
208 case BufferFormat::RGBX_8888
:
209 case BufferFormat::YUV_420
:
210 case BufferFormat::YUV_420_BIPLANAR
:
219 bool GLImageMemory::Initialize(const unsigned char* memory
,
220 BufferFormat format
) {
221 if (!ValidInternalFormat(internalformat_
)) {
222 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
226 if (!ValidFormat(format
)) {
227 LOG(ERROR
) << "Invalid format: " << static_cast<int>(format
);
233 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
234 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
240 void GLImageMemory::Destroy(bool have_context
) {
241 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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_
) {
250 glDeleteTextures(1, &egl_texture_id_
);
251 egl_texture_id_
= 0u;
257 Size
GLImageMemory::GetSize() {
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";
272 // Defer DoBindTexImage if not currently in use.
274 need_do_bind_tex_image_
= true;
278 DoBindTexImage(target
);
282 bool GLImageMemory::CopyTexSubImage(unsigned target
,
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
)
292 // Sub width is not supported.
293 if (rect
.width() != size_
.width())
296 // Height must be a multiple of 4 if compressed.
297 if (IsCompressedFormat(format_
) && rect
.height() % 4)
300 size_t stride_in_bytes
= 0;
301 bool rv
= StrideInBytes(size_
.width(), format_
, &stride_in_bytes
);
304 const unsigned char* data
= memory_
+ rect
.y() * stride_in_bytes
;
305 if (IsCompressedFormat(format_
)) {
306 glCompressedTexSubImage2D(target
,
308 offset
.x(), offset
.y(), rect
.width(),
309 rect
.height(), DataFormat(format_
),
310 SizeInBytes(rect
.size(), format_
), data
);
312 glTexSubImage2D(target
, 0, // level
313 offset
.x(), offset
.y(), rect
.width(), rect
.height(),
314 DataFormat(format_
), DataType(format_
), data
);
320 void GLImageMemory::WillUseTexImage() {
324 if (!need_do_bind_tex_image_
)
328 DoBindTexImage(target_
);
331 void GLImageMemory::DidUseTexImage() {
336 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget
,
338 OverlayTransform transform
,
339 const Rect
& bounds_rect
,
340 const RectF
& crop_rect
) {
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;
351 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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
,
367 TextureFormat(format_
), size_
.width(),
370 SizeInBytes(size_
, format_
), memory_
);
372 glTexImage2D(GL_TEXTURE_2D
,
374 TextureFormat(format_
),
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.
388 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
389 eglGetCurrentContext(),
390 EGL_GL_TEXTURE_2D_KHR
,
391 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
393 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
394 << "Error creating EGLImage: " << eglGetError();
396 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
398 if (IsCompressedFormat(format_
)) {
399 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
403 size_
.width(), size_
.height(),
405 SizeInBytes(size_
, format_
), memory_
);
407 glTexSubImage2D(GL_TEXTURE_2D
,
419 glEGLImageTargetTexture2DOES(target
, egl_image_
);
420 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
425 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
426 if (IsCompressedFormat(format_
)) {
427 glCompressedTexImage2D(target
,
429 TextureFormat(format_
), size_
.width(),
432 SizeInBytes(size_
, format_
), memory_
);
436 TextureFormat(format_
),