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
) {
31 bool ValidFormat(gfx::GpuMemoryBuffer::Format format
) {
33 case gfx::GpuMemoryBuffer::ATC
:
34 case gfx::GpuMemoryBuffer::ATCIA
:
35 case gfx::GpuMemoryBuffer::DXT1
:
36 case gfx::GpuMemoryBuffer::DXT5
:
37 case gfx::GpuMemoryBuffer::ETC1
:
38 case gfx::GpuMemoryBuffer::R_8
:
39 case gfx::GpuMemoryBuffer::RGBA_8888
:
40 case gfx::GpuMemoryBuffer::BGRA_8888
:
42 case gfx::GpuMemoryBuffer::RGBX_8888
:
43 case gfx::GpuMemoryBuffer::YUV_420
:
51 bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format
) {
53 case gfx::GpuMemoryBuffer::ATC
:
54 case gfx::GpuMemoryBuffer::ATCIA
:
55 case gfx::GpuMemoryBuffer::DXT1
:
56 case gfx::GpuMemoryBuffer::DXT5
:
57 case gfx::GpuMemoryBuffer::ETC1
:
58 case gfx::GpuMemoryBuffer::YUV_420
:
60 case gfx::GpuMemoryBuffer::R_8
:
61 case gfx::GpuMemoryBuffer::RGBA_8888
:
62 case gfx::GpuMemoryBuffer::BGRA_8888
:
63 case gfx::GpuMemoryBuffer::RGBX_8888
:
71 GLenum
TextureFormat(gfx::GpuMemoryBuffer::Format format
) {
73 case gfx::GpuMemoryBuffer::ATC
:
74 return GL_ATC_RGB_AMD
;
75 case gfx::GpuMemoryBuffer::ATCIA
:
76 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD
;
77 case gfx::GpuMemoryBuffer::DXT1
:
78 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
79 case gfx::GpuMemoryBuffer::DXT5
:
80 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
;
81 case gfx::GpuMemoryBuffer::ETC1
:
82 return GL_ETC1_RGB8_OES
;
83 case gfx::GpuMemoryBuffer::R_8
:
85 case gfx::GpuMemoryBuffer::RGBA_8888
:
87 case gfx::GpuMemoryBuffer::BGRA_8888
:
89 case gfx::GpuMemoryBuffer::RGBX_8888
:
90 case gfx::GpuMemoryBuffer::YUV_420
:
99 GLenum
DataFormat(gfx::GpuMemoryBuffer::Format format
) {
100 return TextureFormat(format
);
103 GLenum
DataType(gfx::GpuMemoryBuffer::Format format
) {
105 case gfx::GpuMemoryBuffer::RGBA_8888
:
106 case gfx::GpuMemoryBuffer::BGRA_8888
:
107 case gfx::GpuMemoryBuffer::R_8
:
108 return GL_UNSIGNED_BYTE
;
109 case gfx::GpuMemoryBuffer::ATC
:
110 case gfx::GpuMemoryBuffer::ATCIA
:
111 case gfx::GpuMemoryBuffer::DXT1
:
112 case gfx::GpuMemoryBuffer::DXT5
:
113 case gfx::GpuMemoryBuffer::ETC1
:
114 case gfx::GpuMemoryBuffer::RGBX_8888
:
115 case gfx::GpuMemoryBuffer::YUV_420
:
124 GLsizei
SizeInBytes(const gfx::Size
& size
,
125 gfx::GpuMemoryBuffer::Format format
) {
126 size_t stride_in_bytes
= 0;
127 bool valid_stride
= GLImageMemory::StrideInBytes(
128 size
.width(), format
, &stride_in_bytes
);
129 DCHECK(valid_stride
);
130 return static_cast<GLsizei
>(stride_in_bytes
* size
.height());
135 GLImageMemory::GLImageMemory(const gfx::Size
& size
, unsigned internalformat
)
137 internalformat_(internalformat
),
139 format_(gfx::GpuMemoryBuffer::RGBA_8888
),
142 need_do_bind_tex_image_(false)
143 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
147 egl_image_(EGL_NO_IMAGE_KHR
)
152 GLImageMemory::~GLImageMemory() {
153 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
155 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
156 DCHECK_EQ(0u, egl_texture_id_
);
161 bool GLImageMemory::StrideInBytes(size_t width
,
162 gfx::GpuMemoryBuffer::Format format
,
163 size_t* stride_in_bytes
) {
164 base::CheckedNumeric
<size_t> checked_stride
= width
;
166 case gfx::GpuMemoryBuffer::ATCIA
:
167 case gfx::GpuMemoryBuffer::DXT5
:
168 *stride_in_bytes
= width
;
170 case gfx::GpuMemoryBuffer::ATC
:
171 case gfx::GpuMemoryBuffer::DXT1
:
172 case gfx::GpuMemoryBuffer::ETC1
:
173 DCHECK_EQ(width
% 2, 0u);
174 *stride_in_bytes
= width
/ 2;
176 case gfx::GpuMemoryBuffer::R_8
:
178 if (!checked_stride
.IsValid())
180 *stride_in_bytes
= checked_stride
.ValueOrDie() & ~0x3;
182 case gfx::GpuMemoryBuffer::RGBA_8888
:
183 case gfx::GpuMemoryBuffer::BGRA_8888
:
185 if (!checked_stride
.IsValid())
187 *stride_in_bytes
= checked_stride
.ValueOrDie();
189 case gfx::GpuMemoryBuffer::RGBX_8888
:
190 case gfx::GpuMemoryBuffer::YUV_420
:
199 bool GLImageMemory::Initialize(const unsigned char* memory
,
200 gfx::GpuMemoryBuffer::Format format
) {
201 if (!ValidInternalFormat(internalformat_
)) {
202 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
206 if (!ValidFormat(format
)) {
207 LOG(ERROR
) << "Invalid format: " << format
;
213 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
214 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
220 void GLImageMemory::Destroy(bool have_context
) {
221 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
223 if (egl_image_
!= EGL_NO_IMAGE_KHR
) {
224 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_
);
225 egl_image_
= EGL_NO_IMAGE_KHR
;
228 if (egl_texture_id_
) {
230 glDeleteTextures(1, &egl_texture_id_
);
231 egl_texture_id_
= 0u;
237 gfx::Size
GLImageMemory::GetSize() {
241 bool GLImageMemory::BindTexImage(unsigned target
) {
242 if (target_
&& target_
!= target
) {
243 LOG(ERROR
) << "GLImage can only be bound to one target";
248 // Defer DoBindTexImage if not currently in use.
250 need_do_bind_tex_image_
= true;
254 DoBindTexImage(target
);
258 bool GLImageMemory::CopyTexImage(unsigned target
) {
259 TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
261 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
262 if (target
== GL_TEXTURE_EXTERNAL_OES
)
266 if (IsCompressedFormat(format_
)) {
267 glCompressedTexSubImage2D(target
,
271 size_
.width(), size_
.height(),
272 DataFormat(format_
), SizeInBytes(size_
, format_
),
275 glTexSubImage2D(target
, 0, // level
278 size_
.width(), size_
.height(), DataFormat(format_
),
279 DataType(format_
), memory_
);
285 void GLImageMemory::WillUseTexImage() {
289 if (!need_do_bind_tex_image_
)
293 DoBindTexImage(target_
);
296 void GLImageMemory::DidUseTexImage() {
301 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
303 OverlayTransform transform
,
304 const Rect
& bounds_rect
,
305 const RectF
& crop_rect
) {
309 void GLImageMemory::DoBindTexImage(unsigned target
) {
310 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
312 DCHECK(need_do_bind_tex_image_
);
313 need_do_bind_tex_image_
= false;
316 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
318 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
319 if (egl_image_
== EGL_NO_IMAGE_KHR
) {
320 DCHECK_EQ(0u, egl_texture_id_
);
321 glGenTextures(1, &egl_texture_id_
);
324 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
326 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
327 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
328 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
329 if (IsCompressedFormat(format_
)) {
330 glCompressedTexImage2D(GL_TEXTURE_2D
,
332 TextureFormat(format_
), size_
.width(),
335 SizeInBytes(size_
, format_
), memory_
);
337 glTexImage2D(GL_TEXTURE_2D
,
339 TextureFormat(format_
),
349 EGLint attrs
[] = {EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
, EGL_NONE
};
350 // Need to pass current EGL rendering context to eglCreateImageKHR for
351 // target type EGL_GL_TEXTURE_2D_KHR.
353 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
354 eglGetCurrentContext(),
355 EGL_GL_TEXTURE_2D_KHR
,
356 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
358 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
359 << "Error creating EGLImage: " << eglGetError();
361 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
363 if (IsCompressedFormat(format_
)) {
364 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
368 size_
.width(), size_
.height(),
370 SizeInBytes(size_
, format_
), memory_
);
372 glTexSubImage2D(GL_TEXTURE_2D
,
384 glEGLImageTargetTexture2DOES(target
, egl_image_
);
385 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
390 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
391 if (IsCompressedFormat(format_
)) {
392 glCompressedTexImage2D(target
,
394 TextureFormat(format_
), size_
.width(),
397 SizeInBytes(size_
, format_
), memory_
);
401 TextureFormat(format_
),