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
) {
29 bool ValidFormat(gfx::GpuMemoryBuffer::Format format
) {
31 case gfx::GpuMemoryBuffer::ATC
:
32 case gfx::GpuMemoryBuffer::ATCIA
:
33 case gfx::GpuMemoryBuffer::DXT1
:
34 case gfx::GpuMemoryBuffer::DXT5
:
35 case gfx::GpuMemoryBuffer::ETC1
:
36 case gfx::GpuMemoryBuffer::RGBA_8888
:
37 case gfx::GpuMemoryBuffer::BGRA_8888
:
39 case gfx::GpuMemoryBuffer::RGBX_8888
:
47 bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format
) {
49 case gfx::GpuMemoryBuffer::ATC
:
50 case gfx::GpuMemoryBuffer::ATCIA
:
51 case gfx::GpuMemoryBuffer::DXT1
:
52 case gfx::GpuMemoryBuffer::DXT5
:
53 case gfx::GpuMemoryBuffer::ETC1
:
55 case gfx::GpuMemoryBuffer::RGBA_8888
:
56 case gfx::GpuMemoryBuffer::BGRA_8888
:
57 case gfx::GpuMemoryBuffer::RGBX_8888
:
65 GLenum
TextureFormat(gfx::GpuMemoryBuffer::Format format
) {
67 case gfx::GpuMemoryBuffer::ATC
:
68 return GL_ATC_RGB_AMD
;
69 case gfx::GpuMemoryBuffer::ATCIA
:
70 return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD
;
71 case gfx::GpuMemoryBuffer::DXT1
:
72 return GL_COMPRESSED_RGB_S3TC_DXT1_EXT
;
73 case gfx::GpuMemoryBuffer::DXT5
:
74 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
;
75 case gfx::GpuMemoryBuffer::ETC1
:
76 return GL_ETC1_RGB8_OES
;
77 case gfx::GpuMemoryBuffer::RGBA_8888
:
79 case gfx::GpuMemoryBuffer::BGRA_8888
:
81 case gfx::GpuMemoryBuffer::RGBX_8888
:
90 GLenum
DataFormat(gfx::GpuMemoryBuffer::Format format
) {
91 return TextureFormat(format
);
94 GLenum
DataType(gfx::GpuMemoryBuffer::Format format
) {
96 case gfx::GpuMemoryBuffer::RGBA_8888
:
97 case gfx::GpuMemoryBuffer::BGRA_8888
:
98 return GL_UNSIGNED_BYTE
;
99 case gfx::GpuMemoryBuffer::ATC
:
100 case gfx::GpuMemoryBuffer::ATCIA
:
101 case gfx::GpuMemoryBuffer::DXT1
:
102 case gfx::GpuMemoryBuffer::DXT5
:
103 case gfx::GpuMemoryBuffer::ETC1
:
104 case gfx::GpuMemoryBuffer::RGBX_8888
:
113 GLsizei
SizeInBytes(const gfx::Size
& size
,
114 gfx::GpuMemoryBuffer::Format format
) {
115 size_t stride_in_bytes
= 0;
116 bool valid_stride
= GLImageMemory::StrideInBytes(
117 size
.width(), format
, &stride_in_bytes
);
118 DCHECK(valid_stride
);
119 return static_cast<GLsizei
>(stride_in_bytes
* size
.height());
124 GLImageMemory::GLImageMemory(const gfx::Size
& size
, unsigned internalformat
)
126 internalformat_(internalformat
),
128 format_(gfx::GpuMemoryBuffer::RGBA_8888
),
131 need_do_bind_tex_image_(false)
132 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
136 egl_image_(EGL_NO_IMAGE_KHR
)
141 GLImageMemory::~GLImageMemory() {
142 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
144 DCHECK_EQ(EGL_NO_IMAGE_KHR
, egl_image_
);
145 DCHECK_EQ(0u, egl_texture_id_
);
150 bool GLImageMemory::StrideInBytes(size_t width
,
151 gfx::GpuMemoryBuffer::Format format
,
152 size_t* stride_in_bytes
) {
153 base::CheckedNumeric
<size_t> s
= width
;
155 case gfx::GpuMemoryBuffer::ATCIA
:
156 case gfx::GpuMemoryBuffer::DXT5
:
157 *stride_in_bytes
= width
;
159 case gfx::GpuMemoryBuffer::ATC
:
160 case gfx::GpuMemoryBuffer::DXT1
:
161 case gfx::GpuMemoryBuffer::ETC1
:
162 DCHECK_EQ(width
% 2, 0U);
167 *stride_in_bytes
= s
.ValueOrDie();
169 case gfx::GpuMemoryBuffer::RGBA_8888
:
170 case gfx::GpuMemoryBuffer::BGRA_8888
:
175 *stride_in_bytes
= s
.ValueOrDie();
177 case gfx::GpuMemoryBuffer::RGBX_8888
:
187 bool GLImageMemory::ValidSize(const gfx::Size
& size
,
188 gfx::GpuMemoryBuffer::Format format
) {
190 case gfx::GpuMemoryBuffer::ATC
:
191 case gfx::GpuMemoryBuffer::ATCIA
:
192 case gfx::GpuMemoryBuffer::DXT1
:
193 case gfx::GpuMemoryBuffer::DXT5
:
194 case gfx::GpuMemoryBuffer::ETC1
:
195 // Compressed images must have a width and height that's evenly divisible
196 // by the block size.
197 return size
.width() % 4 == 0 && size
.height() % 4 == 0;
198 case gfx::GpuMemoryBuffer::RGBA_8888
:
199 case gfx::GpuMemoryBuffer::BGRA_8888
:
201 case gfx::GpuMemoryBuffer::RGBX_8888
:
210 bool GLImageMemory::Initialize(const unsigned char* memory
,
211 gfx::GpuMemoryBuffer::Format format
) {
212 if (!ValidInternalFormat(internalformat_
)) {
213 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
217 if (!ValidFormat(format
)) {
218 LOG(ERROR
) << "Invalid format: " << format
;
229 void GLImageMemory::Destroy(bool have_context
) {
230 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
232 if (egl_image_
!= EGL_NO_IMAGE_KHR
) {
233 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_
);
234 egl_image_
= EGL_NO_IMAGE_KHR
;
237 if (egl_texture_id_
) {
239 glDeleteTextures(1, &egl_texture_id_
);
240 egl_texture_id_
= 0u;
246 gfx::Size
GLImageMemory::GetSize() {
250 bool GLImageMemory::BindTexImage(unsigned target
) {
251 if (target_
&& target_
!= target
) {
252 LOG(ERROR
) << "GLImage can only be bound to one target";
257 // Defer DoBindTexImage if not currently in use.
259 need_do_bind_tex_image_
= true;
263 DoBindTexImage(target
);
267 bool GLImageMemory::CopyTexImage(unsigned target
) {
268 TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
270 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
271 if (target
== GL_TEXTURE_EXTERNAL_OES
)
275 if (IsCompressedFormat(format_
)) {
276 glCompressedTexSubImage2D(target
,
280 size_
.width(), size_
.height(),
281 DataFormat(format_
), SizeInBytes(size_
, format_
),
284 glTexSubImage2D(target
, 0, // level
287 size_
.width(), size_
.height(), DataFormat(format_
),
288 DataType(format_
), memory_
);
294 void GLImageMemory::WillUseTexImage() {
298 if (!need_do_bind_tex_image_
)
302 DoBindTexImage(target_
);
305 void GLImageMemory::DidUseTexImage() {
310 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
312 OverlayTransform transform
,
313 const Rect
& bounds_rect
,
314 const RectF
& crop_rect
) {
318 void GLImageMemory::DoBindTexImage(unsigned target
) {
319 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
321 DCHECK(need_do_bind_tex_image_
);
322 need_do_bind_tex_image_
= false;
325 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
327 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
328 if (egl_image_
== EGL_NO_IMAGE_KHR
) {
329 DCHECK_EQ(0u, egl_texture_id_
);
330 glGenTextures(1, &egl_texture_id_
);
333 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
335 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
336 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
337 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
338 if (IsCompressedFormat(format_
)) {
339 glCompressedTexImage2D(GL_TEXTURE_2D
,
341 TextureFormat(format_
), size_
.width(),
344 SizeInBytes(size_
, format_
), memory_
);
346 glTexImage2D(GL_TEXTURE_2D
,
348 TextureFormat(format_
),
358 EGLint attrs
[] = {EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
, EGL_NONE
};
359 // Need to pass current EGL rendering context to eglCreateImageKHR for
360 // target type EGL_GL_TEXTURE_2D_KHR.
362 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
363 eglGetCurrentContext(),
364 EGL_GL_TEXTURE_2D_KHR
,
365 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
367 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
368 << "Error creating EGLImage: " << eglGetError();
370 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
372 if (IsCompressedFormat(format_
)) {
373 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
377 size_
.width(), size_
.height(),
379 SizeInBytes(size_
, format_
),
382 glTexSubImage2D(GL_TEXTURE_2D
,
394 glEGLImageTargetTexture2DOES(target
, egl_image_
);
395 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
400 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
401 if (IsCompressedFormat(format_
)) {
402 glCompressedTexImage2D(target
,
404 TextureFormat(format_
), size_
.width(),
407 SizeInBytes(size_
, format_
), memory_
);
411 TextureFormat(format_
),