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
:
57 bool IsCompressedFormat(BufferFormat 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
:
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
:
78 GLenum
TextureFormat(BufferFormat 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
:
92 case BufferFormat::RGBA_4444
:
93 case BufferFormat::RGBA_8888
:
95 case BufferFormat::BGRA_8888
:
97 case BufferFormat::RGBX_8888
:
98 case BufferFormat::YUV_420
:
107 GLenum
DataFormat(BufferFormat format
) {
108 return TextureFormat(format
);
111 GLenum
DataType(BufferFormat 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
:
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());
144 GLImageMemory::GLImageMemory(const Size
& size
, unsigned internalformat
)
146 internalformat_(internalformat
),
148 format_(BufferFormat::RGBA_8888
),
151 need_do_bind_tex_image_(false)
152 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
156 egl_image_(EGL_NO_IMAGE_KHR
)
161 GLImageMemory::~GLImageMemory() {
162 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
164 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
165 DCHECK_EQ(0u, egl_texture_id_
);
170 bool GLImageMemory::StrideInBytes(size_t width
,
172 size_t* stride_in_bytes
) {
173 base::CheckedNumeric
<size_t> checked_stride
= width
;
175 case BufferFormat::ATCIA
:
176 case BufferFormat::DXT5
:
177 *stride_in_bytes
= width
;
179 case BufferFormat::ATC
:
180 case BufferFormat::DXT1
:
181 case BufferFormat::ETC1
:
182 DCHECK_EQ(width
% 2, 0u);
183 *stride_in_bytes
= width
/ 2;
185 case BufferFormat::R_8
:
187 if (!checked_stride
.IsValid())
189 *stride_in_bytes
= checked_stride
.ValueOrDie() & ~0x3;
191 case BufferFormat::RGBA_4444
:
193 if (!checked_stride
.IsValid())
195 *stride_in_bytes
= checked_stride
.ValueOrDie();
197 case BufferFormat::RGBA_8888
:
198 case BufferFormat::BGRA_8888
:
200 if (!checked_stride
.IsValid())
202 *stride_in_bytes
= checked_stride
.ValueOrDie();
204 case BufferFormat::RGBX_8888
:
205 case BufferFormat::YUV_420
:
214 bool GLImageMemory::Initialize(const unsigned char* memory
,
215 BufferFormat format
) {
216 if (!ValidInternalFormat(internalformat_
)) {
217 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
221 if (!ValidFormat(format
)) {
222 LOG(ERROR
) << "Invalid format: " << static_cast<int>(format
);
228 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
229 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
235 void GLImageMemory::Destroy(bool have_context
) {
236 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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_
) {
245 glDeleteTextures(1, &egl_texture_id_
);
246 egl_texture_id_
= 0u;
252 Size
GLImageMemory::GetSize() {
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";
267 // Defer DoBindTexImage if not currently in use.
269 need_do_bind_tex_image_
= true;
273 DoBindTexImage(target
);
277 bool GLImageMemory::CopyTexSubImage(unsigned target
,
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
)
287 // Sub width is not supported.
288 if (rect
.width() != size_
.width())
291 // Height must be a multiple of 4 if compressed.
292 if (IsCompressedFormat(format_
) && rect
.height() % 4)
295 size_t stride_in_bytes
= 0;
296 bool rv
= StrideInBytes(size_
.width(), format_
, &stride_in_bytes
);
299 const unsigned char* data
= memory_
+ rect
.y() * stride_in_bytes
;
300 if (IsCompressedFormat(format_
)) {
301 glCompressedTexSubImage2D(target
,
303 offset
.x(), offset
.y(), rect
.width(),
304 rect
.height(), DataFormat(format_
),
305 SizeInBytes(rect
.size(), format_
), data
);
307 glTexSubImage2D(target
, 0, // level
308 offset
.x(), offset
.y(), rect
.width(), rect
.height(),
309 DataFormat(format_
), DataType(format_
), data
);
315 void GLImageMemory::WillUseTexImage() {
319 if (!need_do_bind_tex_image_
)
323 DoBindTexImage(target_
);
326 void GLImageMemory::DidUseTexImage() {
331 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget
,
333 OverlayTransform transform
,
334 const Rect
& bounds_rect
,
335 const RectF
& crop_rect
) {
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;
346 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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
,
362 TextureFormat(format_
), size_
.width(),
365 SizeInBytes(size_
, format_
), memory_
);
367 glTexImage2D(GL_TEXTURE_2D
,
369 TextureFormat(format_
),
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.
383 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
384 eglGetCurrentContext(),
385 EGL_GL_TEXTURE_2D_KHR
,
386 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
388 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
389 << "Error creating EGLImage: " << eglGetError();
391 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
393 if (IsCompressedFormat(format_
)) {
394 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
398 size_
.width(), size_
.height(),
400 SizeInBytes(size_
, format_
), memory_
);
402 glTexSubImage2D(GL_TEXTURE_2D
,
414 glEGLImageTargetTexture2DOES(target
, egl_image_
);
415 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
420 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
421 if (IsCompressedFormat(format_
)) {
422 glCompressedTexImage2D(target
,
424 TextureFormat(format_
), size_
.width(),
427 SizeInBytes(size_
, format_
), memory_
);
431 TextureFormat(format_
),