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
) {
30 bool ValidFormat(gfx::GpuMemoryBuffer::Format format
) {
32 case gfx::GpuMemoryBuffer::ATC
:
33 case gfx::GpuMemoryBuffer::ATCIA
:
34 case gfx::GpuMemoryBuffer::DXT1
:
35 case gfx::GpuMemoryBuffer::DXT5
:
36 case gfx::GpuMemoryBuffer::ETC1
:
37 case gfx::GpuMemoryBuffer::RGBA_8888
:
38 case gfx::GpuMemoryBuffer::BGRA_8888
:
40 case gfx::GpuMemoryBuffer::RGBX_8888
:
48 bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format
) {
50 case gfx::GpuMemoryBuffer::ATC
:
51 case gfx::GpuMemoryBuffer::ATCIA
:
52 case gfx::GpuMemoryBuffer::DXT1
:
53 case gfx::GpuMemoryBuffer::DXT5
:
54 case gfx::GpuMemoryBuffer::ETC1
:
56 case gfx::GpuMemoryBuffer::RGBA_8888
:
57 case gfx::GpuMemoryBuffer::BGRA_8888
:
58 case gfx::GpuMemoryBuffer::RGBX_8888
:
66 GLenum
TextureFormat(gfx::GpuMemoryBuffer::Format format
) {
68 case gfx::GpuMemoryBuffer::ATC
:
69 return GL_ATC_RGB_AMD
;
70 case gfx::GpuMemoryBuffer::ATCIA
:
71 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD
;
72 case gfx::GpuMemoryBuffer::DXT1
:
73 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
74 case gfx::GpuMemoryBuffer::DXT5
:
75 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
;
76 case gfx::GpuMemoryBuffer::ETC1
:
77 return GL_ETC1_RGB8_OES
;
78 case gfx::GpuMemoryBuffer::RGBA_8888
:
80 case gfx::GpuMemoryBuffer::BGRA_8888
:
82 case gfx::GpuMemoryBuffer::RGBX_8888
:
91 GLenum
DataFormat(gfx::GpuMemoryBuffer::Format format
) {
92 return TextureFormat(format
);
95 GLenum
DataType(gfx::GpuMemoryBuffer::Format format
) {
97 case gfx::GpuMemoryBuffer::RGBA_8888
:
98 case gfx::GpuMemoryBuffer::BGRA_8888
:
99 return GL_UNSIGNED_BYTE
;
100 case gfx::GpuMemoryBuffer::ATC
:
101 case gfx::GpuMemoryBuffer::ATCIA
:
102 case gfx::GpuMemoryBuffer::DXT1
:
103 case gfx::GpuMemoryBuffer::DXT5
:
104 case gfx::GpuMemoryBuffer::ETC1
:
105 case gfx::GpuMemoryBuffer::RGBX_8888
:
114 GLsizei
SizeInBytes(const gfx::Size
& size
,
115 gfx::GpuMemoryBuffer::Format format
) {
116 size_t stride_in_bytes
= 0;
117 bool valid_stride
= GLImageMemory::StrideInBytes(
118 size
.width(), format
, &stride_in_bytes
);
119 DCHECK(valid_stride
);
120 return static_cast<GLsizei
>(stride_in_bytes
* size
.height());
125 GLImageMemory::GLImageMemory(const gfx::Size
& size
, unsigned internalformat
)
127 internalformat_(internalformat
),
129 format_(gfx::GpuMemoryBuffer::RGBA_8888
),
132 need_do_bind_tex_image_(false)
133 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
137 egl_image_(EGL_NO_IMAGE_KHR
)
142 GLImageMemory::~GLImageMemory() {
143 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
145 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
146 DCHECK_EQ(0u, egl_texture_id_
);
151 bool GLImageMemory::StrideInBytes(size_t width
,
152 gfx::GpuMemoryBuffer::Format format
,
153 size_t* stride_in_bytes
) {
154 base::CheckedNumeric
<size_t> s
= width
;
156 case gfx::GpuMemoryBuffer::ATCIA
:
157 case gfx::GpuMemoryBuffer::DXT5
:
158 *stride_in_bytes
= width
;
160 case gfx::GpuMemoryBuffer::ATC
:
161 case gfx::GpuMemoryBuffer::DXT1
:
162 case gfx::GpuMemoryBuffer::ETC1
:
163 DCHECK_EQ(width
% 2, 0U);
168 *stride_in_bytes
= s
.ValueOrDie();
170 case gfx::GpuMemoryBuffer::RGBA_8888
:
171 case gfx::GpuMemoryBuffer::BGRA_8888
:
176 *stride_in_bytes
= s
.ValueOrDie();
178 case gfx::GpuMemoryBuffer::RGBX_8888
:
187 bool GLImageMemory::Initialize(const unsigned char* memory
,
188 gfx::GpuMemoryBuffer::Format format
) {
189 if (!ValidInternalFormat(internalformat_
)) {
190 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
194 if (!ValidFormat(format
)) {
195 LOG(ERROR
) << "Invalid format: " << format
;
201 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
202 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
208 void GLImageMemory::Destroy(bool have_context
) {
209 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
211 if (egl_image_
!= EGL_NO_IMAGE_KHR
) {
212 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_
);
213 egl_image_
= EGL_NO_IMAGE_KHR
;
216 if (egl_texture_id_
) {
218 glDeleteTextures(1, &egl_texture_id_
);
219 egl_texture_id_
= 0u;
225 gfx::Size
GLImageMemory::GetSize() {
229 bool GLImageMemory::BindTexImage(unsigned target
) {
230 if (target_
&& target_
!= target
) {
231 LOG(ERROR
) << "GLImage can only be bound to one target";
236 // Defer DoBindTexImage if not currently in use.
238 need_do_bind_tex_image_
= true;
242 DoBindTexImage(target
);
246 bool GLImageMemory::CopyTexImage(unsigned target
) {
247 TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
249 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
250 if (target
== GL_TEXTURE_EXTERNAL_OES
)
254 if (IsCompressedFormat(format_
)) {
255 glCompressedTexSubImage2D(target
,
259 size_
.width(), size_
.height(),
260 DataFormat(format_
), SizeInBytes(size_
, format_
),
263 glTexSubImage2D(target
, 0, // level
266 size_
.width(), size_
.height(), DataFormat(format_
),
267 DataType(format_
), memory_
);
273 void GLImageMemory::WillUseTexImage() {
277 if (!need_do_bind_tex_image_
)
281 DoBindTexImage(target_
);
284 void GLImageMemory::DidUseTexImage() {
289 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
291 OverlayTransform transform
,
292 const Rect
& bounds_rect
,
293 const RectF
& crop_rect
) {
297 void GLImageMemory::DoBindTexImage(unsigned target
) {
298 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
300 DCHECK(need_do_bind_tex_image_
);
301 need_do_bind_tex_image_
= false;
304 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
306 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
307 if (egl_image_
== EGL_NO_IMAGE_KHR
) {
308 DCHECK_EQ(0u, egl_texture_id_
);
309 glGenTextures(1, &egl_texture_id_
);
312 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
314 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
315 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
316 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
317 if (IsCompressedFormat(format_
)) {
318 glCompressedTexImage2D(GL_TEXTURE_2D
,
320 TextureFormat(format_
), size_
.width(),
323 SizeInBytes(size_
, format_
), memory_
);
325 glTexImage2D(GL_TEXTURE_2D
,
327 TextureFormat(format_
),
337 EGLint attrs
[] = {EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
, EGL_NONE
};
338 // Need to pass current EGL rendering context to eglCreateImageKHR for
339 // target type EGL_GL_TEXTURE_2D_KHR.
341 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
342 eglGetCurrentContext(),
343 EGL_GL_TEXTURE_2D_KHR
,
344 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
346 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
347 << "Error creating EGLImage: " << eglGetError();
349 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
351 if (IsCompressedFormat(format_
)) {
352 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
356 size_
.width(), size_
.height(),
358 SizeInBytes(size_
, format_
),
361 glTexSubImage2D(GL_TEXTURE_2D
,
373 glEGLImageTargetTexture2DOES(target
, egl_image_
);
374 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
379 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
380 if (IsCompressedFormat(format_
)) {
381 glCompressedTexImage2D(target
,
383 TextureFormat(format_
), size_
.width(),
386 SizeInBytes(size_
, format_
), memory_
);
390 TextureFormat(format_
),