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(GpuMemoryBuffer::Format 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
:
48 case GpuMemoryBuffer::RGBX_8888
:
49 case GpuMemoryBuffer::YUV_420
:
57 bool IsCompressedFormat(GpuMemoryBuffer::Format 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
:
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
:
78 GLenum
TextureFormat(GpuMemoryBuffer::Format 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
:
92 case GpuMemoryBuffer::RGBA_4444
:
93 case GpuMemoryBuffer::RGBA_8888
:
95 case GpuMemoryBuffer::BGRA_8888
:
97 case GpuMemoryBuffer::RGBX_8888
:
98 case GpuMemoryBuffer::YUV_420
:
107 GLenum
DataFormat(GpuMemoryBuffer::Format format
) {
108 return TextureFormat(format
);
111 GLenum
DataType(GpuMemoryBuffer::Format 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
:
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());
145 GLImageMemory::GLImageMemory(const Size
& size
, unsigned internalformat
)
147 internalformat_(internalformat
),
149 format_(GpuMemoryBuffer::RGBA_8888
),
152 need_do_bind_tex_image_(false)
153 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
157 egl_image_(EGL_NO_IMAGE_KHR
)
162 GLImageMemory::~GLImageMemory() {
163 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
165 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
166 DCHECK_EQ(0u, egl_texture_id_
);
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
;
176 case GpuMemoryBuffer::ATCIA
:
177 case GpuMemoryBuffer::DXT5
:
178 *stride_in_bytes
= width
;
180 case GpuMemoryBuffer::ATC
:
181 case GpuMemoryBuffer::DXT1
:
182 case GpuMemoryBuffer::ETC1
:
183 DCHECK_EQ(width
% 2, 0u);
184 *stride_in_bytes
= width
/ 2;
186 case GpuMemoryBuffer::R_8
:
188 if (!checked_stride
.IsValid())
190 *stride_in_bytes
= checked_stride
.ValueOrDie() & ~0x3;
192 case GpuMemoryBuffer::RGBA_4444
:
194 if (!checked_stride
.IsValid())
196 *stride_in_bytes
= checked_stride
.ValueOrDie();
198 case GpuMemoryBuffer::RGBA_8888
:
199 case GpuMemoryBuffer::BGRA_8888
:
201 if (!checked_stride
.IsValid())
203 *stride_in_bytes
= checked_stride
.ValueOrDie();
205 case GpuMemoryBuffer::RGBX_8888
:
206 case GpuMemoryBuffer::YUV_420
:
215 bool GLImageMemory::Initialize(const unsigned char* memory
,
216 GpuMemoryBuffer::Format format
) {
217 if (!ValidInternalFormat(internalformat_
)) {
218 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
222 if (!ValidFormat(format
)) {
223 LOG(ERROR
) << "Invalid format: " << format
;
229 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
230 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
236 void GLImageMemory::Destroy(bool have_context
) {
237 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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_
) {
246 glDeleteTextures(1, &egl_texture_id_
);
247 egl_texture_id_
= 0u;
253 Size
GLImageMemory::GetSize() {
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";
268 // Defer DoBindTexImage if not currently in use.
270 need_do_bind_tex_image_
= true;
274 DoBindTexImage(target
);
278 bool GLImageMemory::CopyTexSubImage(unsigned target
,
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
)
288 // Sub width is not supported.
289 if (rect
.width() != size_
.width())
292 // Height must be a multiple of 4 if compressed.
293 if (IsCompressedFormat(format_
) && rect
.height() % 4)
296 size_t stride_in_bytes
= 0;
297 bool rv
= StrideInBytes(size_
.width(), format_
, &stride_in_bytes
);
300 const unsigned char* data
= memory_
+ rect
.y() * stride_in_bytes
;
301 if (IsCompressedFormat(format_
)) {
302 glCompressedTexSubImage2D(target
,
304 offset
.x(), offset
.y(), rect
.width(),
305 rect
.height(), DataFormat(format_
),
306 SizeInBytes(rect
.size(), format_
), data
);
308 glTexSubImage2D(target
, 0, // level
309 offset
.x(), offset
.y(), rect
.width(), rect
.height(),
310 DataFormat(format_
), DataType(format_
), data
);
316 void GLImageMemory::WillUseTexImage() {
320 if (!need_do_bind_tex_image_
)
324 DoBindTexImage(target_
);
327 void GLImageMemory::DidUseTexImage() {
332 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget
,
334 OverlayTransform transform
,
335 const Rect
& bounds_rect
,
336 const RectF
& crop_rect
) {
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;
347 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
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
,
363 TextureFormat(format_
), size_
.width(),
366 SizeInBytes(size_
, format_
), memory_
);
368 glTexImage2D(GL_TEXTURE_2D
,
370 TextureFormat(format_
),
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.
384 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
385 eglGetCurrentContext(),
386 EGL_GL_TEXTURE_2D_KHR
,
387 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
389 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
390 << "Error creating EGLImage: " << eglGetError();
392 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
394 if (IsCompressedFormat(format_
)) {
395 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
399 size_
.width(), size_
.height(),
401 SizeInBytes(size_
, format_
), memory_
);
403 glTexSubImage2D(GL_TEXTURE_2D
,
415 glEGLImageTargetTexture2DOES(target
, egl_image_
);
416 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
421 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
422 if (IsCompressedFormat(format_
)) {
423 glCompressedTexImage2D(target
,
425 TextureFormat(format_
), size_
.width(),
428 SizeInBytes(size_
, format_
), memory_
);
432 TextureFormat(format_
),