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
:
186 bool GLImageMemory::Initialize(const unsigned char* memory
,
187 gfx::GpuMemoryBuffer::Format format
) {
188 if (!ValidInternalFormat(internalformat_
)) {
189 LOG(ERROR
) << "Invalid internalformat: " << internalformat_
;
193 if (!ValidFormat(format
)) {
194 LOG(ERROR
) << "Invalid format: " << format
;
200 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.width() % 4 == 0);
201 DCHECK_IMPLIES(IsCompressedFormat(format
), size_
.height() % 4 == 0);
207 void GLImageMemory::Destroy(bool have_context
) {
208 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
210 if (egl_image_
!= EGL_NO_IMAGE_KHR
) {
211 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_
);
212 egl_image_
= EGL_NO_IMAGE_KHR
;
215 if (egl_texture_id_
) {
217 glDeleteTextures(1, &egl_texture_id_
);
218 egl_texture_id_
= 0u;
224 gfx::Size
GLImageMemory::GetSize() {
228 bool GLImageMemory::BindTexImage(unsigned target
) {
229 if (target_
&& target_
!= target
) {
230 LOG(ERROR
) << "GLImage can only be bound to one target";
235 // Defer DoBindTexImage if not currently in use.
237 need_do_bind_tex_image_
= true;
241 DoBindTexImage(target
);
245 bool GLImageMemory::CopyTexImage(unsigned target
) {
246 TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
248 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
249 if (target
== GL_TEXTURE_EXTERNAL_OES
)
253 if (IsCompressedFormat(format_
)) {
254 glCompressedTexSubImage2D(target
,
258 size_
.width(), size_
.height(),
259 DataFormat(format_
), SizeInBytes(size_
, format_
),
262 glTexSubImage2D(target
, 0, // level
265 size_
.width(), size_
.height(), DataFormat(format_
),
266 DataType(format_
), memory_
);
272 void GLImageMemory::WillUseTexImage() {
276 if (!need_do_bind_tex_image_
)
280 DoBindTexImage(target_
);
283 void GLImageMemory::DidUseTexImage() {
288 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
290 OverlayTransform transform
,
291 const Rect
& bounds_rect
,
292 const RectF
& crop_rect
) {
296 void GLImageMemory::DoBindTexImage(unsigned target
) {
297 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
299 DCHECK(need_do_bind_tex_image_
);
300 need_do_bind_tex_image_
= false;
303 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
305 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
306 if (egl_image_
== EGL_NO_IMAGE_KHR
) {
307 DCHECK_EQ(0u, egl_texture_id_
);
308 glGenTextures(1, &egl_texture_id_
);
311 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
313 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
314 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
315 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
316 if (IsCompressedFormat(format_
)) {
317 glCompressedTexImage2D(GL_TEXTURE_2D
,
319 TextureFormat(format_
), size_
.width(),
322 SizeInBytes(size_
, format_
), memory_
);
324 glTexImage2D(GL_TEXTURE_2D
,
326 TextureFormat(format_
),
336 EGLint attrs
[] = {EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
, EGL_NONE
};
337 // Need to pass current EGL rendering context to eglCreateImageKHR for
338 // target type EGL_GL_TEXTURE_2D_KHR.
340 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
341 eglGetCurrentContext(),
342 EGL_GL_TEXTURE_2D_KHR
,
343 reinterpret_cast<EGLClientBuffer
>(egl_texture_id_
),
345 DCHECK_NE(EGL_NO_IMAGE_KHR
, egl_image_
)
346 << "Error creating EGLImage: " << eglGetError();
348 ScopedTextureBinder
texture_binder(GL_TEXTURE_2D
, egl_texture_id_
);
350 if (IsCompressedFormat(format_
)) {
351 glCompressedTexSubImage2D(GL_TEXTURE_2D
,
355 size_
.width(), size_
.height(),
357 SizeInBytes(size_
, format_
),
360 glTexSubImage2D(GL_TEXTURE_2D
,
372 glEGLImageTargetTexture2DOES(target
, egl_image_
);
373 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
378 DCHECK_NE(static_cast<GLenum
>(GL_TEXTURE_EXTERNAL_OES
), target
);
379 if (IsCompressedFormat(format_
)) {
380 glCompressedTexImage2D(target
,
382 TextureFormat(format_
), size_
.width(),
385 SizeInBytes(size_
, format_
), memory_
);
389 TextureFormat(format_
),