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

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: Actually enable/disable capabilities. Typo. Created 5 years 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
« no previous file with comments | « ui/gl/gl_image_io_surface.h ('k') | ui/gl/gl_image_io_surface_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/mac/foundation_util.h" 10 #include "base/mac/foundation_util.h"
11 #include "base/strings/stringize_macros.h"
11 #include "base/trace_event/memory_allocator_dump.h" 12 #include "base/trace_event/memory_allocator_dump.h"
12 #include "base/trace_event/memory_dump_manager.h" 13 #include "base/trace_event/memory_dump_manager.h"
13 #include "base/trace_event/process_memory_dump.h" 14 #include "base/trace_event/process_memory_dump.h"
14 #include "ui/gl/gl_bindings.h" 15 #include "ui/gl/gl_bindings.h"
15 #include "ui/gl/gl_context.h" 16 #include "ui/gl/gl_context.h"
17 #include "ui/gl/gl_helper.h"
18 #include "ui/gl/scoped_binders.h"
16 19
17 // Note that this must be included after gl_bindings.h to avoid conflicts. 20 // Note that this must be included after gl_bindings.h to avoid conflicts.
18 #include <OpenGL/CGLIOSurface.h> 21 #include <OpenGL/CGLIOSurface.h>
19 #include <Quartz/Quartz.h> 22 #include <Quartz/Quartz.h>
20 23
21 using gfx::BufferFormat; 24 using gfx::BufferFormat;
22 25
23 namespace gl { 26 namespace gl {
24 namespace { 27 namespace {
25 28
26 using WidgetToLayerMap = std::map<gfx::AcceleratedWidget, CALayer*>; 29 using WidgetToLayerMap = std::map<gfx::AcceleratedWidget, CALayer*>;
27 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map; 30 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map;
28 31
32 // clang-format off
33 const char kVertexShader[] =
34 STRINGIZE(
35 attribute vec2 a_position;
36 uniform vec2 a_texScale;
37 varying vec2 v_texCoord;
38 void main() {
39 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
40 v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5 * a_texScale;
41 }
42 );
43
44 const char kFragmentShader[] =
45 STRINGIZE(
46 uniform sampler2DRect a_y_texture;
47 uniform sampler2DRect a_uv_texture;
48 varying vec2 v_texCoord;
49 void main() {
50 vec3 yuv_adj = vec3(-0.0625, -0.5, -0.5);
51 mat3 yuv_matrix = mat3(vec3(1.164, 1.164, 1.164),
52 vec3(0.0, -.391, 2.018),
53 vec3(1.596, -.813, 0.0));
54 vec3 yuv = vec3(
55 texture2DRect(a_y_texture, v_texCoord).r,
56 texture2DRect(a_uv_texture, v_texCoord * 0.5).rg);
57 gl_FragColor = vec4(yuv_matrix * (yuv + yuv_adj), 1.0);
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_RED: 64 case GL_RED:
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;
109 case BufferFormat::YUV_420_BIPLANAR:
110 return GL_RGB_YCBCR_420V_CHROMIUM;
76 case BufferFormat::ATC: 111 case BufferFormat::ATC:
77 case BufferFormat::ATCIA: 112 case BufferFormat::ATCIA:
78 case BufferFormat::DXT1: 113 case BufferFormat::DXT1:
79 case BufferFormat::DXT5: 114 case BufferFormat::DXT5:
80 case BufferFormat::ETC1: 115 case BufferFormat::ETC1:
81 case BufferFormat::RGBA_4444: 116 case BufferFormat::RGBA_4444:
82 case BufferFormat::RGBX_8888: 117 case BufferFormat::RGBX_8888:
83 case BufferFormat::BGRX_8888: 118 case BufferFormat::BGRX_8888:
84 case BufferFormat::YUV_420: 119 case BufferFormat::YUV_420:
85 NOTREACHED(); 120 NOTREACHED();
86 return 0; 121 return 0;
87 } 122 }
88 123
89 NOTREACHED(); 124 NOTREACHED();
90 return 0; 125 return 0;
91 } 126 }
92 127
93 GLenum DataFormat(BufferFormat format) { 128 GLenum DataFormat(BufferFormat format) {
94 switch (format) { 129 switch (format) {
95 case BufferFormat::R_8: 130 case BufferFormat::R_8:
96 case BufferFormat::YUV_420_BIPLANAR:
97 return GL_RED; 131 return GL_RED;
98 case BufferFormat::BGRA_8888: 132 case BufferFormat::BGRA_8888:
99 case BufferFormat::RGBA_8888: 133 case BufferFormat::RGBA_8888:
100 return GL_BGRA; 134 return GL_BGRA;
101 case BufferFormat::UYVY_422: 135 case BufferFormat::UYVY_422:
102 return GL_YCBCR_422_APPLE; 136 return GL_YCBCR_422_APPLE;
103 break;
104 case BufferFormat::ATC: 137 case BufferFormat::ATC:
105 case BufferFormat::ATCIA: 138 case BufferFormat::ATCIA:
106 case BufferFormat::DXT1: 139 case BufferFormat::DXT1:
107 case BufferFormat::DXT5: 140 case BufferFormat::DXT5:
108 case BufferFormat::ETC1: 141 case BufferFormat::ETC1:
109 case BufferFormat::RGBA_4444: 142 case BufferFormat::RGBA_4444:
110 case BufferFormat::RGBX_8888: 143 case BufferFormat::RGBX_8888:
111 case BufferFormat::BGRX_8888: 144 case BufferFormat::BGRX_8888:
112 case BufferFormat::YUV_420: 145 case BufferFormat::YUV_420:
146 case BufferFormat::YUV_420_BIPLANAR:
113 NOTREACHED(); 147 NOTREACHED();
114 return 0; 148 return 0;
115 } 149 }
116 150
117 NOTREACHED(); 151 NOTREACHED();
118 return 0; 152 return 0;
119 } 153 }
120 154
121 GLenum DataType(BufferFormat format) { 155 GLenum DataType(BufferFormat format) {
122 switch (format) { 156 switch (format) {
123 case BufferFormat::R_8: 157 case BufferFormat::R_8:
124 case BufferFormat::YUV_420_BIPLANAR:
125 return GL_UNSIGNED_BYTE; 158 return GL_UNSIGNED_BYTE;
126 case BufferFormat::BGRA_8888: 159 case BufferFormat::BGRA_8888:
127 case BufferFormat::RGBA_8888: 160 case BufferFormat::RGBA_8888:
128 return GL_UNSIGNED_INT_8_8_8_8_REV; 161 return GL_UNSIGNED_INT_8_8_8_8_REV;
129 case BufferFormat::UYVY_422: 162 case BufferFormat::UYVY_422:
130 return GL_UNSIGNED_SHORT_8_8_APPLE; 163 return GL_UNSIGNED_SHORT_8_8_APPLE;
131 break; 164 break;
132 case BufferFormat::ATC: 165 case BufferFormat::ATC:
133 case BufferFormat::ATCIA: 166 case BufferFormat::ATCIA:
134 case BufferFormat::DXT1: 167 case BufferFormat::DXT1:
135 case BufferFormat::DXT5: 168 case BufferFormat::DXT5:
136 case BufferFormat::ETC1: 169 case BufferFormat::ETC1:
137 case BufferFormat::RGBA_4444: 170 case BufferFormat::RGBA_4444:
138 case BufferFormat::RGBX_8888: 171 case BufferFormat::RGBX_8888:
139 case BufferFormat::BGRX_8888: 172 case BufferFormat::BGRX_8888:
140 case BufferFormat::YUV_420: 173 case BufferFormat::YUV_420:
174 case BufferFormat::YUV_420_BIPLANAR:
141 NOTREACHED(); 175 NOTREACHED();
142 return 0; 176 return 0;
143 } 177 }
144 178
145 NOTREACHED(); 179 NOTREACHED();
146 return 0; 180 return 0;
147 } 181 }
148 182
183 GLuint SetupVertexBuffer() {
184 GLuint vertex_buffer = 0;
185 glGenBuffersARB(1, &vertex_buffer);
186 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer);
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 return vertex_buffer;
190 }
191
149 } // namespace 192 } // namespace
150 193
151 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, 194 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size,
152 unsigned internalformat) 195 unsigned internalformat)
153 : size_(size), 196 : size_(size),
154 internalformat_(internalformat), 197 internalformat_(internalformat),
155 format_(BufferFormat::RGBA_8888) {} 198 format_(BufferFormat::RGBA_8888) {}
156 199
157 GLImageIOSurface::~GLImageIOSurface() { 200 GLImageIOSurface::~GLImageIOSurface() {
158 DCHECK(thread_checker_.CalledOnValidThread()); 201 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 17 matching lines...) Expand all
176 } 219 }
177 220
178 format_ = format; 221 format_ = format;
179 io_surface_.reset(io_surface, base::scoped_policy::RETAIN); 222 io_surface_.reset(io_surface, base::scoped_policy::RETAIN);
180 io_surface_id_ = io_surface_id; 223 io_surface_id_ = io_surface_id;
181 return true; 224 return true;
182 } 225 }
183 226
184 void GLImageIOSurface::Destroy(bool have_context) { 227 void GLImageIOSurface::Destroy(bool have_context) {
185 DCHECK(thread_checker_.CalledOnValidThread()); 228 DCHECK(thread_checker_.CalledOnValidThread());
229 if (have_context && framebuffer_) {
230 glDeleteProgram(program_);
231 glDeleteShader(vertex_shader_);
232 glDeleteShader(fragment_shader_);
233 glDeleteBuffersARB(1, &vertex_buffer_);
234 glDeleteFramebuffersEXT(1, &framebuffer_);
235 glDeleteTextures(2, yuv_textures_);
236 }
186 io_surface_.reset(); 237 io_surface_.reset();
187 } 238 }
188 239
189 gfx::Size GLImageIOSurface::GetSize() { 240 gfx::Size GLImageIOSurface::GetSize() {
190 return size_; 241 return size_;
191 } 242 }
192 243
193 unsigned GLImageIOSurface::GetInternalFormat() { return internalformat_; } 244 unsigned GLImageIOSurface::GetInternalFormat() {
245 return internalformat_;
246 }
194 247
195 bool GLImageIOSurface::BindTexImage(unsigned target) { 248 bool GLImageIOSurface::BindTexImage(unsigned target) {
196 DCHECK(thread_checker_.CalledOnValidThread()); 249 DCHECK(thread_checker_.CalledOnValidThread());
250
251 // YUV_420_BIPLANAR is not supported by BindTexImage.
252 // CopyTexImage is supported by this format as that performs conversion to RGB
253 // as part of the copy operation.
254 if (format_ == BufferFormat::YUV_420_BIPLANAR)
255 return false;
256
197 if (target != GL_TEXTURE_RECTANGLE_ARB) { 257 if (target != GL_TEXTURE_RECTANGLE_ARB) {
198 // This might be supported in the future. For now, perform strict 258 // This might be supported in the future. For now, perform strict
199 // validation so we know what's going on. 259 // validation so we know what's going on.
200 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target"; 260 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target";
201 return false; 261 return false;
202 } 262 }
203 263
204 CGLContextObj cgl_context = 264 CGLContextObj cgl_context =
205 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); 265 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
206 266
207 DCHECK(io_surface_); 267 DCHECK(io_surface_);
208 CGLError cgl_error = 268 CGLError cgl_error =
209 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_), 269 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_),
210 size_.width(), size_.height(), DataFormat(format_), 270 size_.width(), size_.height(), DataFormat(format_),
211 DataType(format_), io_surface_.get(), 0); 271 DataType(format_), io_surface_.get(), 0);
212 if (cgl_error != kCGLNoError) { 272 if (cgl_error != kCGLNoError) {
213 LOG(ERROR) << "Error in CGLTexImageIOSurface2D"; 273 LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
214 return false; 274 return false;
215 } 275 }
216 276
217 return true; 277 return true;
218 } 278 }
219 279
220 bool GLImageIOSurface::CopyTexImage(unsigned target) { 280 bool GLImageIOSurface::CopyTexImage(unsigned target) {
221 return false; 281 DCHECK(thread_checker_.CalledOnValidThread());
282
283 if (format_ != BufferFormat::YUV_420_BIPLANAR)
284 return false;
285
286 if (target != GL_TEXTURE_2D) {
287 LOG(ERROR) << "YUV_420_BIPLANAR requires TEXTURE_2D target";
288 return false;
289 }
290
291 if (!framebuffer_) {
292 glGenFramebuffersEXT(1, &framebuffer_);
293 vertex_buffer_ = SetupVertexBuffer();
294 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
295 fragment_shader_ =
296 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
297 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
298 gfx::ScopedUseProgram use_program(program_);
299
300 size_location_ = glGetUniformLocation(program_, "a_texScale");
301 DCHECK_NE(-1, size_location_);
302 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture");
303 DCHECK_NE(-1, y_sampler_location);
304 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture");
305 DCHECK_NE(-1, uv_sampler_location);
306
307 glUniform1i(y_sampler_location, 0);
308 glUniform1i(uv_sampler_location, 1);
309
310 glGenTextures(2, yuv_textures_);
311 DCHECK(yuv_textures_[0]);
312 DCHECK(yuv_textures_[1]);
313 }
314
315 CGLContextObj cgl_context =
316 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
317
318 GLint target_texture = 0;
319 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
320 DCHECK(target_texture);
321 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size_.width(), size_.height(), 0,
322 GL_RGB, GL_UNSIGNED_BYTE, nullptr);
323
324 CGLError cgl_error = kCGLNoError;
325 {
326 DCHECK(io_surface_);
327
328 gfx::ScopedActiveTexture active_texture0(GL_TEXTURE0);
329 gfx::ScopedTextureBinder texture_y_binder(GL_TEXTURE_RECTANGLE_ARB,
330 yuv_textures_[0]);
331 cgl_error = CGLTexImageIOSurface2D(
332 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(),
333 size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_.get(), 0);
334 if (cgl_error != kCGLNoError) {
335 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. "
336 << cgl_error;
337 return false;
338 }
339 {
340 gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1);
341 gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB,
342 yuv_textures_[1]);
343 cgl_error = CGLTexImageIOSurface2D(
344 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2,
345 size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1);
346 if (cgl_error != kCGLNoError) {
347 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. "
348 << cgl_error;
349 return false;
350 }
351
352 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
353 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
354 glViewport(0, 0, size_.width(), size_.height());
355 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
356 GL_TEXTURE_2D, target_texture, 0);
357 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
358 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
359
360 gfx::ScopedUseProgram use_program(program_);
361 glUniform2f(size_location_, size_.width(), size_.height());
362
363 // TODO(dcastagna): Extract and share the following code to draw a quad.
364 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_);
365 gfx::ScopedVertexAttribArray vertex_attrib_array(0, 2, GL_FLOAT, GL_FALSE,
366 sizeof(GLfloat) * 2, 0);
367 gfx::ScopedCapability disable_blending(GL_BLEND, GL_FALSE);
368 gfx::ScopedCapability disable_culling(GL_CULL_FACE, GL_FALSE);
369 gfx::ScopedCapability disable_dithering(GL_DITHER, GL_FALSE);
370 gfx::ScopedCapability disable_depth_test(GL_DEPTH_TEST, GL_FALSE);
371 gfx::ScopedCapability disable_scissor_test(GL_SCISSOR_TEST, GL_FALSE);
372 gfx::ScopedColorMask color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
373
374 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
375
376 // Detach the output texture from the fbo.
377 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
378 GL_TEXTURE_2D, 0, 0);
379 }
380 }
381 return true;
222 } 382 }
223 383
224 bool GLImageIOSurface::CopyTexSubImage(unsigned target, 384 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
225 const gfx::Point& offset, 385 const gfx::Point& offset,
226 const gfx::Rect& rect) { 386 const gfx::Rect& rect) {
227 return false; 387 return false;
228 } 388 }
229 389
230 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 390 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
231 int z_order, 391 int z_order,
(...skipping 29 matching lines...) Expand all
261 421
262 // static 422 // static
263 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget, 423 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget,
264 CALayer* layer) { 424 CALayer* layer) {
265 if (layer) 425 if (layer)
266 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer)); 426 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer));
267 else 427 else
268 g_widget_to_layer_map.Pointer()->erase(widget); 428 g_widget_to_layer_map.Pointer()->erase(widget);
269 } 429 }
270 430
271 } // namespace gfx 431 // static
432 unsigned GLImageIOSurface::GetInternalFormatForTesting(
433 gfx::BufferFormat format) {
434 DCHECK(ValidFormat(format));
435 return TextureFormat(format);
436 }
437 } // namespace gl
OLDNEW
« no previous file with comments | « ui/gl/gl_image_io_surface.h ('k') | ui/gl/gl_image_io_surface_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698