1 // Copyright 2013 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_io_surface.h"
9 #include "base/lazy_instance.h"
10 #include "base/mac/foundation_util.h"
11 #include "ui/gl/gl_bindings.h"
12 #include "ui/gl/gl_context.h"
14 // Note that this must be included after gl_bindings.h to avoid conflicts.
15 #include <OpenGL/CGLIOSurface.h>
16 #include <Quartz/Quartz.h>
21 typedef std::map<gfx::AcceleratedWidget,CALayer*> WidgetToLayerMap;
22 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map;
24 bool ValidInternalFormat(unsigned internalformat) {
25 switch (internalformat) {
34 bool ValidFormat(GpuMemoryBuffer::Format format) {
36 case GpuMemoryBuffer::R_8:
37 case GpuMemoryBuffer::BGRA_8888:
39 case GpuMemoryBuffer::ATC:
40 case GpuMemoryBuffer::ATCIA:
41 case GpuMemoryBuffer::DXT1:
42 case GpuMemoryBuffer::DXT5:
43 case GpuMemoryBuffer::ETC1:
44 case GpuMemoryBuffer::RGBA_4444:
45 case GpuMemoryBuffer::RGBA_8888:
46 case GpuMemoryBuffer::RGBX_8888:
47 case GpuMemoryBuffer::YUV_420:
55 GLenum TextureFormat(GpuMemoryBuffer::Format format) {
57 case GpuMemoryBuffer::R_8:
59 case GpuMemoryBuffer::BGRA_8888:
61 case GpuMemoryBuffer::ATC:
62 case GpuMemoryBuffer::ATCIA:
63 case GpuMemoryBuffer::DXT1:
64 case GpuMemoryBuffer::DXT5:
65 case GpuMemoryBuffer::ETC1:
66 case GpuMemoryBuffer::RGBA_4444:
67 case GpuMemoryBuffer::RGBA_8888:
68 case GpuMemoryBuffer::RGBX_8888:
69 case GpuMemoryBuffer::YUV_420:
78 GLenum DataFormat(GpuMemoryBuffer::Format format) {
80 case GpuMemoryBuffer::R_8:
82 case GpuMemoryBuffer::BGRA_8888:
84 case GpuMemoryBuffer::ATC:
85 case GpuMemoryBuffer::ATCIA:
86 case GpuMemoryBuffer::DXT1:
87 case GpuMemoryBuffer::DXT5:
88 case GpuMemoryBuffer::ETC1:
89 case GpuMemoryBuffer::RGBA_4444:
90 case GpuMemoryBuffer::RGBA_8888:
91 case GpuMemoryBuffer::RGBX_8888:
92 case GpuMemoryBuffer::YUV_420:
101 GLenum DataType(GpuMemoryBuffer::Format format) {
103 case GpuMemoryBuffer::R_8:
104 return GL_UNSIGNED_BYTE;
105 case GpuMemoryBuffer::BGRA_8888:
106 return GL_UNSIGNED_INT_8_8_8_8_REV;
107 case GpuMemoryBuffer::ATC:
108 case GpuMemoryBuffer::ATCIA:
109 case GpuMemoryBuffer::DXT1:
110 case GpuMemoryBuffer::DXT5:
111 case GpuMemoryBuffer::ETC1:
112 case GpuMemoryBuffer::RGBA_4444:
113 case GpuMemoryBuffer::RGBA_8888:
114 case GpuMemoryBuffer::RGBX_8888:
115 case GpuMemoryBuffer::YUV_420:
126 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size,
127 unsigned internalformat)
129 internalformat_(internalformat),
130 format_(GpuMemoryBuffer::RGBA_8888) {
133 GLImageIOSurface::~GLImageIOSurface() {
134 DCHECK(thread_checker_.CalledOnValidThread());
135 DCHECK(!io_surface_);
138 bool GLImageIOSurface::Initialize(IOSurfaceRef io_surface,
139 GpuMemoryBuffer::Format format) {
140 DCHECK(thread_checker_.CalledOnValidThread());
141 DCHECK(!io_surface_);
143 if (!ValidInternalFormat(internalformat_)) {
144 LOG(ERROR) << "Invalid internalformat: " << internalformat_;
148 if (!ValidFormat(format)) {
149 LOG(ERROR) << "Invalid format: " << format;
154 io_surface_.reset(io_surface, base::scoped_policy::RETAIN);
158 void GLImageIOSurface::Destroy(bool have_context) {
159 DCHECK(thread_checker_.CalledOnValidThread());
163 gfx::Size GLImageIOSurface::GetSize() { return size_; }
165 unsigned GLImageIOSurface::GetInternalFormat() { return internalformat_; }
167 bool GLImageIOSurface::BindTexImage(unsigned target) {
168 DCHECK(thread_checker_.CalledOnValidThread());
169 if (target != GL_TEXTURE_RECTANGLE_ARB) {
170 // This might be supported in the future. For now, perform strict
171 // validation so we know what's going on.
172 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target";
176 CGLContextObj cgl_context =
177 static_cast<CGLContextObj>(GLContext::GetCurrent()->GetHandle());
181 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_),
182 size_.width(), size_.height(), DataFormat(format_),
183 DataType(format_), io_surface_.get(), 0);
184 if (cgl_error != kCGLNoError) {
185 LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
192 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
198 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
200 OverlayTransform transform,
201 const Rect& bounds_rect,
202 const RectF& crop_rect) {
203 // Only simple overlay planes are currently supported.
204 DCHECK_EQ(0, z_order);
205 DCHECK_EQ(gfx::RectF(0, 0, 1, 1).ToString(), crop_rect.ToString());
206 DCHECK_EQ(gfx::OVERLAY_TRANSFORM_NONE, transform);
208 // Convert the phony widget to the appropriate CALayer.
209 auto found = g_widget_to_layer_map.Pointer()->find(widget);
210 if (found == g_widget_to_layer_map.Pointer()->end())
212 CALayer* layer = found->second;
214 // Also note that transactions are not disabled. The caller must ensure that
215 // all changes to the CALayer tree happen atomically.
216 [layer setContents:static_cast<id>(io_surface_.get())];
217 [layer setFrame:bounds_rect.ToCGRect()];
222 void GLImageIOSurface::SetLayerForWidget(
223 gfx::AcceleratedWidget widget, CALayer* layer) {
225 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer));
227 g_widget_to_layer_map.Pointer()->erase(widget);