Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: ui/gl/gl_image_io_surface.mm

Issue 1419733005: gpu: Add YCbCr 420v extension. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Set origin to crrev.com/1408753003. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gl/gl_image_io_surface.h" 5 #include "ui/gl/gl_image_io_surface.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/callback_helpers.h"
reveman 2015/11/01 14:19:04 is this used?
Daniele Castagna 2015/11/01 21:55:31 Not anymore. Removed.
9 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
10 #include "base/mac/foundation_util.h" 11 #include "base/mac/foundation_util.h"
12 #include "base/strings/stringize_macros.h"
11 #include "base/trace_event/memory_allocator_dump.h" 13 #include "base/trace_event/memory_allocator_dump.h"
12 #include "base/trace_event/memory_dump_manager.h" 14 #include "base/trace_event/memory_dump_manager.h"
13 #include "base/trace_event/process_memory_dump.h" 15 #include "base/trace_event/process_memory_dump.h"
14 #include "ui/gl/gl_bindings.h" 16 #include "ui/gl/gl_bindings.h"
15 #include "ui/gl/gl_context.h" 17 #include "ui/gl/gl_context.h"
18 #include "ui/gl/gl_helper.h"
19 #include "ui/gl/scoped_binders.h"
16 20
17 // Note that this must be included after gl_bindings.h to avoid conflicts. 21 // Note that this must be included after gl_bindings.h to avoid conflicts.
18 #include <OpenGL/CGLIOSurface.h> 22 #include <OpenGL/CGLIOSurface.h>
19 #include <Quartz/Quartz.h> 23 #include <Quartz/Quartz.h>
20 24
21 using gfx::BufferFormat; 25 using gfx::BufferFormat;
22 26
23 namespace gl { 27 namespace gl {
24 namespace { 28 namespace {
25 29
26 using WidgetToLayerMap = std::map<gfx::AcceleratedWidget, CALayer*>; 30 using WidgetToLayerMap = std::map<gfx::AcceleratedWidget, CALayer*>;
27 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map; 31 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map;
28 32
33 // clang-format off
34 const char kVertexShader[] =
35 STRINGIZE(
36 attribute vec2 a_position;
37 uniform vec2 a_size;
38 varying vec2 v_texCoord;
39 void main() {
40 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
41 v_texCoord = (a_position + vec2(1,1)) * 0.5 * a_size;
reveman 2015/11/01 14:19:05 s/vec2(1,1)/vec2(1, 1)/ maybe vec2(1.0, 1.0)? als
Daniele Castagna 2015/11/01 21:55:31 Done.
42 }
43 );
44
45 const char kFragmentShader[] =
46 STRINGIZE(
47 uniform sampler2DRect a_y_texture;
48 uniform sampler2DRect a_uv_texture;
49 varying vec2 v_texCoord;
50 void main() {
51 vec3 yuv_adj = vec3(-0.0625, -0.5, -0.5);
52 mat3 yuv_matrix = mat3(vec3(1.164, 1.164, 1.164),
53 vec3(0.0, -.391, 2.018),
54 vec3(1.596, -.813, 0.0));
55 vec3 yuv = vec3(texture2DRect(a_y_texture, v_texCoord).r,
56 texture2DRect(a_uv_texture, v_texCoord * 0.5).rg);
reveman 2015/11/01 14:19:04 nit: Horizontally align texture2DRect to have cons
Daniele Castagna 2015/11/01 21:55:31 Done.
57 gl_FragColor = vec4( yuv_matrix * (yuv + yuv_adj), 1.0);
reveman 2015/11/01 14:19:04 nit: s/vec4( yuv_mat.../vec4(yuv_mat.../
Daniele Castagna 2015/11/01 21:55:31 Done.
58 }
59 );
60 // clang-format on
61
29 bool ValidInternalFormat(unsigned internalformat) { 62 bool ValidInternalFormat(unsigned internalformat) {
30 switch (internalformat) { 63 switch (internalformat) {
31 case GL_R8: 64 case GL_R8:
32 case GL_BGRA_EXT: 65 case GL_BGRA_EXT:
33 case GL_RGB: 66 case GL_RGB:
67 case GL_RGB_YCBCR_420V_CHROMIUM:
34 case GL_RGB_YCBCR_422_CHROMIUM: 68 case GL_RGB_YCBCR_422_CHROMIUM:
35 case GL_RGBA: 69 case GL_RGBA:
36 return true; 70 return true;
37 default: 71 default:
38 return false; 72 return false;
39 } 73 }
40 } 74 }
41 75
42 bool ValidFormat(BufferFormat format) { 76 bool ValidFormat(BufferFormat format) {
43 switch (format) { 77 switch (format) {
(...skipping 15 matching lines...) Expand all
59 return false; 93 return false;
60 } 94 }
61 95
62 NOTREACHED(); 96 NOTREACHED();
63 return false; 97 return false;
64 } 98 }
65 99
66 GLenum TextureFormat(BufferFormat format) { 100 GLenum TextureFormat(BufferFormat format) {
67 switch (format) { 101 switch (format) {
68 case BufferFormat::R_8: 102 case BufferFormat::R_8:
69 case BufferFormat::YUV_420_BIPLANAR:
70 return GL_RED; 103 return GL_RED;
71 case BufferFormat::BGRA_8888: 104 case BufferFormat::BGRA_8888:
72 case BufferFormat::RGBA_8888: 105 case BufferFormat::RGBA_8888:
73 return GL_RGBA; 106 return GL_RGBA;
74 case BufferFormat::UYVY_422: 107 case BufferFormat::UYVY_422:
75 return GL_RGB; 108 return GL_RGB;
76 case BufferFormat::ATC: 109 case BufferFormat::ATC:
77 case BufferFormat::ATCIA: 110 case BufferFormat::ATCIA:
78 case BufferFormat::DXT1: 111 case BufferFormat::DXT1:
79 case BufferFormat::DXT5: 112 case BufferFormat::DXT5:
80 case BufferFormat::ETC1: 113 case BufferFormat::ETC1:
81 case BufferFormat::RGBA_4444: 114 case BufferFormat::RGBA_4444:
82 case BufferFormat::RGBX_8888: 115 case BufferFormat::RGBX_8888:
83 case BufferFormat::BGRX_8888: 116 case BufferFormat::BGRX_8888:
84 case BufferFormat::YUV_420: 117 case BufferFormat::YUV_420:
118 case BufferFormat::YUV_420_BIPLANAR:
85 NOTREACHED(); 119 NOTREACHED();
86 return 0; 120 return 0;
87 } 121 }
88 122
89 NOTREACHED(); 123 NOTREACHED();
90 return 0; 124 return 0;
91 } 125 }
92 126
93 GLenum DataFormat(BufferFormat format) { 127 GLenum DataFormat(BufferFormat format) {
94 switch (format) { 128 switch (format) {
95 case BufferFormat::R_8: 129 case BufferFormat::R_8:
96 case BufferFormat::YUV_420_BIPLANAR:
97 return GL_RED; 130 return GL_RED;
98 case BufferFormat::BGRA_8888: 131 case BufferFormat::BGRA_8888:
99 case BufferFormat::RGBA_8888: 132 case BufferFormat::RGBA_8888:
100 return GL_BGRA; 133 return GL_BGRA;
101 case BufferFormat::UYVY_422: 134 case BufferFormat::UYVY_422:
102 return GL_YCBCR_422_APPLE; 135 return GL_YCBCR_422_APPLE;
103 break;
104 case BufferFormat::ATC: 136 case BufferFormat::ATC:
105 case BufferFormat::ATCIA: 137 case BufferFormat::ATCIA:
106 case BufferFormat::DXT1: 138 case BufferFormat::DXT1:
107 case BufferFormat::DXT5: 139 case BufferFormat::DXT5:
108 case BufferFormat::ETC1: 140 case BufferFormat::ETC1:
109 case BufferFormat::RGBA_4444: 141 case BufferFormat::RGBA_4444:
110 case BufferFormat::RGBX_8888: 142 case BufferFormat::RGBX_8888:
111 case BufferFormat::BGRX_8888: 143 case BufferFormat::BGRX_8888:
112 case BufferFormat::YUV_420: 144 case BufferFormat::YUV_420:
145 case BufferFormat::YUV_420_BIPLANAR:
113 NOTREACHED(); 146 NOTREACHED();
114 return 0; 147 return 0;
115 } 148 }
116 149
117 NOTREACHED(); 150 NOTREACHED();
118 return 0; 151 return 0;
119 } 152 }
120 153
121 GLenum DataType(BufferFormat format) { 154 GLenum DataType(BufferFormat format) {
122 switch (format) { 155 switch (format) {
123 case BufferFormat::R_8: 156 case BufferFormat::R_8:
124 case BufferFormat::YUV_420_BIPLANAR:
125 return GL_UNSIGNED_BYTE; 157 return GL_UNSIGNED_BYTE;
126 case BufferFormat::BGRA_8888: 158 case BufferFormat::BGRA_8888:
127 case BufferFormat::RGBA_8888: 159 case BufferFormat::RGBA_8888:
128 return GL_UNSIGNED_INT_8_8_8_8_REV; 160 return GL_UNSIGNED_INT_8_8_8_8_REV;
129 case BufferFormat::UYVY_422: 161 case BufferFormat::UYVY_422:
130 return GL_UNSIGNED_SHORT_8_8_APPLE; 162 return GL_UNSIGNED_SHORT_8_8_APPLE;
131 break; 163 break;
132 case BufferFormat::ATC: 164 case BufferFormat::ATC:
133 case BufferFormat::ATCIA: 165 case BufferFormat::ATCIA:
134 case BufferFormat::DXT1: 166 case BufferFormat::DXT1:
135 case BufferFormat::DXT5: 167 case BufferFormat::DXT5:
136 case BufferFormat::ETC1: 168 case BufferFormat::ETC1:
137 case BufferFormat::RGBA_4444: 169 case BufferFormat::RGBA_4444:
138 case BufferFormat::RGBX_8888: 170 case BufferFormat::RGBX_8888:
139 case BufferFormat::BGRX_8888: 171 case BufferFormat::BGRX_8888:
140 case BufferFormat::YUV_420: 172 case BufferFormat::YUV_420:
173 case BufferFormat::YUV_420_BIPLANAR:
141 NOTREACHED(); 174 NOTREACHED();
142 return 0; 175 return 0;
143 } 176 }
144 177
145 NOTREACHED(); 178 NOTREACHED();
146 return 0; 179 return 0;
147 } 180 }
148 181
182 GLuint SetupVertexBuffer() {
183 GLuint vertex_buffer = 0;
184 glGenBuffersARB(1, &vertex_buffer);
185 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer);
186
187 GLfloat data[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
188 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
189 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0);
190
191 return vertex_buffer;
192 }
193
149 } // namespace 194 } // namespace
150 195
151 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, 196 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size,
152 unsigned internalformat) 197 unsigned internalformat)
153 : size_(size), 198 : size_(size),
154 internalformat_(internalformat), 199 internalformat_(internalformat),
155 format_(BufferFormat::RGBA_8888) {} 200 format_(BufferFormat::RGBA_8888) {}
156 201
157 GLImageIOSurface::~GLImageIOSurface() { 202 GLImageIOSurface::~GLImageIOSurface() {
158 DCHECK(thread_checker_.CalledOnValidThread()); 203 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 17 matching lines...) Expand all
176 } 221 }
177 222
178 format_ = format; 223 format_ = format;
179 io_surface_.reset(io_surface, base::scoped_policy::RETAIN); 224 io_surface_.reset(io_surface, base::scoped_policy::RETAIN);
180 io_surface_id_ = io_surface_id; 225 io_surface_id_ = io_surface_id;
181 return true; 226 return true;
182 } 227 }
183 228
184 void GLImageIOSurface::Destroy(bool have_context) { 229 void GLImageIOSurface::Destroy(bool have_context) {
185 DCHECK(thread_checker_.CalledOnValidThread()); 230 DCHECK(thread_checker_.CalledOnValidThread());
231 if (have_context) {
reveman 2015/11/01 14:19:04 Can you add framebuffer_ to this 'if' clause? I kn
Daniele Castagna 2015/11/01 21:55:30 Done.
232 glDeleteProgram(program_);
233 glDeleteShader(vertex_shader_);
234 glDeleteShader(fragment_shader_);
235 glDeleteBuffersARB(1, &vertex_buffer_);
236 glDeleteFramebuffersEXT(1, &framebuffer_);
237 }
186 io_surface_.reset(); 238 io_surface_.reset();
187 } 239 }
188 240
189 gfx::Size GLImageIOSurface::GetSize() { 241 gfx::Size GLImageIOSurface::GetSize() {
190 return size_; 242 return size_;
191 } 243 }
192 244
193 unsigned GLImageIOSurface::GetInternalFormat() { return internalformat_; } 245 unsigned GLImageIOSurface::GetInternalFormat() { return internalformat_; }
194 246
195 bool GLImageIOSurface::BindTexImage(unsigned target) { 247 bool GLImageIOSurface::BindTexImage(unsigned target) {
196 DCHECK(thread_checker_.CalledOnValidThread()); 248 DCHECK(thread_checker_.CalledOnValidThread());
249 // YUV_420_BIPLANAR is not supported by BindTexImage.
reveman 2015/11/01 14:19:04 nit: can you add a blinkline after the DCHECK as o
Daniele Castagna 2015/11/01 21:55:31 Done.
250 // Returning false here will result in conversion to RGB in CopyTexImage.
reveman 2015/11/01 14:19:04 nit: maybe something like "CopyTexImage is support
Daniele Castagna 2015/11/01 21:55:30 Done.
251 if (format_ == BufferFormat::YUV_420_BIPLANAR)
252 return false;
253
197 if (target != GL_TEXTURE_RECTANGLE_ARB) { 254 if (target != GL_TEXTURE_RECTANGLE_ARB) {
198 // This might be supported in the future. For now, perform strict 255 // This might be supported in the future. For now, perform strict
199 // validation so we know what's going on. 256 // validation so we know what's going on.
200 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target"; 257 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target";
201 return false; 258 return false;
202 } 259 }
203 260
204 CGLContextObj cgl_context = 261 CGLContextObj cgl_context =
205 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); 262 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
206 263
207 DCHECK(io_surface_); 264 DCHECK(io_surface_);
208 CGLError cgl_error = 265 CGLError cgl_error =
209 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_), 266 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_),
210 size_.width(), size_.height(), DataFormat(format_), 267 size_.width(), size_.height(), DataFormat(format_),
211 DataType(format_), io_surface_.get(), 0); 268 DataType(format_), io_surface_.get(), 0);
212 if (cgl_error != kCGLNoError) { 269 if (cgl_error != kCGLNoError) {
213 LOG(ERROR) << "Error in CGLTexImageIOSurface2D"; 270 LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
214 return false; 271 return false;
215 } 272 }
216 273
217 return true; 274 return true;
218 } 275 }
219 276
220 bool GLImageIOSurface::CopyTexImage(unsigned target) { 277 bool GLImageIOSurface::CopyTexImage(unsigned target) {
221 return false; 278 DCHECK(thread_checker_.CalledOnValidThread());
279 DCHECK(io_surface_);
280 if (format_ != BufferFormat::YUV_420_BIPLANAR)
reveman 2015/11/01 14:19:05 nit: blankline after DCHECKs and maybe move the io
Daniele Castagna 2015/11/01 21:55:31 Done.
281 return false;
282
283 if (target != GL_TEXTURE_2D) {
284 LOG(ERROR) << "YUV_420_BIPLANAR requires TEXTURE_2D target";
285 return false;
286 }
287
288 if (!framebuffer_) {
289 glGenFramebuffersEXT(1, &framebuffer_);
290 vertex_buffer_ = SetupVertexBuffer();
291 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
292 fragment_shader_ =
293 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
294 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
295 gfx::ScopedUseProgram use_program(program_);
296
297 size_location_ = glGetUniformLocation(program_, "a_size");
298 DCHECK_NE(-1, size_location_);
299 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture");
300 DCHECK_NE(-1, y_sampler_location);
301 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture");
302 DCHECK_NE(-1, uv_sampler_location);
303
304 glUniform1i(y_sampler_location, 0);
305 glUniform1i(uv_sampler_location, 1);
306 }
307
308 CGLContextObj cgl_context =
309 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
310
311 GLuint yuv_textures[2];
reveman 2015/11/01 14:19:04 nit: ..textures[2] = {};
Daniele Castagna 2015/11/01 21:55:30 Done.
312 glGenTextures(2, yuv_textures);
313 DCHECK(yuv_textures[0] && yuv_textures[1]);
reveman 2015/11/01 14:19:04 nit: one DCHECK for each texture is preferred
Daniele Castagna 2015/11/01 21:55:30 Done.
314
315 GLint target_texture = 0;
316 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
317 DCHECK(target_texture);
318
319 GLint previous_active_texture = 0;
320 glGetIntegerv(GL_ACTIVE_TEXTURE, &previous_active_texture);
reveman 2015/11/01 14:19:04 is this still used?
Daniele Castagna 2015/11/01 21:55:30 Nop. Gone.
321
322 CGLError cgl_error = kCGLNoError;
323 {
324 gfx::ScopedActiveTexture active_texture0(GL_TEXTURE0);
325 gfx::ScopedTextureBinder texture_y_binder(GL_TEXTURE_RECTANGLE_ARB,
326 yuv_textures[0]);
327 cgl_error = CGLTexImageIOSurface2D(
328 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(),
329 size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_.get(), 0);
330 if (cgl_error != kCGLNoError) {
331 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. "
332 << cgl_error;
333 glDeleteTextures(2, yuv_textures);
334 return false;
335 }
336 {
337 gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1);
338 gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB,
339 yuv_textures[1]);
340 cgl_error = CGLTexImageIOSurface2D(
341 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2,
342 size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1);
343 if (cgl_error != kCGLNoError) {
344 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. "
345 << cgl_error;
346 glDeleteTextures(2, yuv_textures);
347 return false;
348 }
349
350 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
351 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
352 glViewport(0, 0, size_.width(), size_.height());
353 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
354 GL_TEXTURE_2D, target_texture, 0);
reveman 2015/11/01 14:19:04 Do we need a glTexImage2D call for the target text
Daniele Castagna 2015/11/01 21:55:31 We do need it. Added it.
355 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
356 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
357
358 gfx::ScopedUseProgram use_program(program_);
359 glUniform2f(size_location_, size_.width(), size_.height());
360
361 gfx::ScopedEnableVertexAttribArray enable_vertex_attrib_array(0);
362 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_);
363 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
364
365 // Detach the output texture from the fbo.
366 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
367 GL_TEXTURE_2D, 0, 0);
368 }
369 }
370 return true;
222 } 371 }
223 372
224 bool GLImageIOSurface::CopyTexSubImage(unsigned target, 373 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
225 const gfx::Point& offset, 374 const gfx::Point& offset,
226 const gfx::Rect& rect) { 375 const gfx::Rect& rect) {
227 return false; 376 return false;
228 } 377 }
229 378
230 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 379 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
231 int z_order, 380 int z_order,
(...skipping 30 matching lines...) Expand all
262 // static 411 // static
263 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget, 412 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget,
264 CALayer* layer) { 413 CALayer* layer) {
265 if (layer) 414 if (layer)
266 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer)); 415 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer));
267 else 416 else
268 g_widget_to_layer_map.Pointer()->erase(widget); 417 g_widget_to_layer_map.Pointer()->erase(widget);
269 } 418 }
270 419
271 } // namespace gfx 420 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698