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

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: Rebase on master. Add gl/gfx namespace qualifiers. 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"
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
29 bool ValidInternalFormat(unsigned internalformat) { 33 bool ValidInternalFormat(unsigned internalformat) {
30 switch (internalformat) { 34 switch (internalformat) {
31 case GL_R8: 35 case GL_R8:
32 case GL_BGRA_EXT: 36 case GL_BGRA_EXT:
33 case GL_RGB: 37 case GL_RGB:
38 case GL_RGB_YCBCR_420V_CHROMIUM:
34 case GL_RGB_YCBCR_422_CHROMIUM: 39 case GL_RGB_YCBCR_422_CHROMIUM:
35 case GL_RGBA: 40 case GL_RGBA:
36 return true; 41 return true;
37 default: 42 default:
38 return false; 43 return false;
39 } 44 }
40 } 45 }
41 46
42 bool ValidFormat(BufferFormat format) { 47 bool ValidFormat(BufferFormat format) {
43 switch (format) { 48 switch (format) {
(...skipping 15 matching lines...) Expand all
59 return false; 64 return false;
60 } 65 }
61 66
62 NOTREACHED(); 67 NOTREACHED();
63 return false; 68 return false;
64 } 69 }
65 70
66 GLenum TextureFormat(BufferFormat format) { 71 GLenum TextureFormat(BufferFormat format) {
67 switch (format) { 72 switch (format) {
68 case BufferFormat::R_8: 73 case BufferFormat::R_8:
69 case BufferFormat::YUV_420_BIPLANAR:
70 return GL_RED; 74 return GL_RED;
71 case BufferFormat::BGRA_8888: 75 case BufferFormat::BGRA_8888:
72 case BufferFormat::RGBA_8888: 76 case BufferFormat::RGBA_8888:
73 return GL_RGBA; 77 return GL_RGBA;
74 case BufferFormat::UYVY_422: 78 case BufferFormat::UYVY_422:
75 return GL_RGB;
76 case BufferFormat::ATC: 79 case BufferFormat::ATC:
77 case BufferFormat::ATCIA: 80 case BufferFormat::ATCIA:
78 case BufferFormat::DXT1: 81 case BufferFormat::DXT1:
79 case BufferFormat::DXT5: 82 case BufferFormat::DXT5:
80 case BufferFormat::ETC1: 83 case BufferFormat::ETC1:
81 case BufferFormat::RGBA_4444: 84 case BufferFormat::RGBA_4444:
82 case BufferFormat::RGBX_8888: 85 case BufferFormat::RGBX_8888:
83 case BufferFormat::BGRX_8888: 86 case BufferFormat::BGRX_8888:
84 case BufferFormat::YUV_420: 87 case BufferFormat::YUV_420:
88 case BufferFormat::YUV_420_BIPLANAR:
85 NOTREACHED(); 89 NOTREACHED();
86 return 0; 90 return 0;
87 } 91 }
88 92
89 NOTREACHED(); 93 NOTREACHED();
90 return 0; 94 return 0;
91 } 95 }
92 96
93 GLenum DataFormat(BufferFormat format) { 97 GLenum DataFormat(BufferFormat format) {
94 switch (format) { 98 switch (format) {
95 case BufferFormat::R_8: 99 case BufferFormat::R_8:
96 case BufferFormat::YUV_420_BIPLANAR:
97 return GL_RED; 100 return GL_RED;
98 case BufferFormat::BGRA_8888: 101 case BufferFormat::BGRA_8888:
99 case BufferFormat::RGBA_8888: 102 case BufferFormat::RGBA_8888:
100 return GL_BGRA; 103 return GL_BGRA;
101 case BufferFormat::UYVY_422: 104 case BufferFormat::UYVY_422:
102 return GL_YCBCR_422_APPLE; 105 return GL_YCBCR_422_APPLE;
103 break;
104 case BufferFormat::ATC: 106 case BufferFormat::ATC:
105 case BufferFormat::ATCIA: 107 case BufferFormat::ATCIA:
106 case BufferFormat::DXT1: 108 case BufferFormat::DXT1:
107 case BufferFormat::DXT5: 109 case BufferFormat::DXT5:
108 case BufferFormat::ETC1: 110 case BufferFormat::ETC1:
109 case BufferFormat::RGBA_4444: 111 case BufferFormat::RGBA_4444:
110 case BufferFormat::RGBX_8888: 112 case BufferFormat::RGBX_8888:
111 case BufferFormat::BGRX_8888: 113 case BufferFormat::BGRX_8888:
112 case BufferFormat::YUV_420: 114 case BufferFormat::YUV_420:
115 case BufferFormat::YUV_420_BIPLANAR:
113 NOTREACHED(); 116 NOTREACHED();
114 return 0; 117 return 0;
115 } 118 }
116 119
117 NOTREACHED(); 120 NOTREACHED();
118 return 0; 121 return 0;
119 } 122 }
120 123
121 GLenum DataType(BufferFormat format) { 124 GLenum DataType(BufferFormat format) {
122 switch (format) { 125 switch (format) {
123 case BufferFormat::R_8: 126 case BufferFormat::R_8:
124 case BufferFormat::YUV_420_BIPLANAR:
125 return GL_UNSIGNED_BYTE; 127 return GL_UNSIGNED_BYTE;
126 case BufferFormat::BGRA_8888: 128 case BufferFormat::BGRA_8888:
127 case BufferFormat::RGBA_8888: 129 case BufferFormat::RGBA_8888:
128 return GL_UNSIGNED_INT_8_8_8_8_REV; 130 return GL_UNSIGNED_INT_8_8_8_8_REV;
129 case BufferFormat::UYVY_422: 131 case BufferFormat::UYVY_422:
130 return GL_UNSIGNED_SHORT_8_8_APPLE; 132 return GL_UNSIGNED_SHORT_8_8_APPLE;
131 break; 133 break;
132 case BufferFormat::ATC: 134 case BufferFormat::ATC:
133 case BufferFormat::ATCIA: 135 case BufferFormat::ATCIA:
134 case BufferFormat::DXT1: 136 case BufferFormat::DXT1:
135 case BufferFormat::DXT5: 137 case BufferFormat::DXT5:
136 case BufferFormat::ETC1: 138 case BufferFormat::ETC1:
137 case BufferFormat::RGBA_4444: 139 case BufferFormat::RGBA_4444:
138 case BufferFormat::RGBX_8888: 140 case BufferFormat::RGBX_8888:
139 case BufferFormat::BGRX_8888: 141 case BufferFormat::BGRX_8888:
140 case BufferFormat::YUV_420: 142 case BufferFormat::YUV_420:
143 case BufferFormat::YUV_420_BIPLANAR:
141 NOTREACHED(); 144 NOTREACHED();
142 return 0; 145 return 0;
143 } 146 }
144 147
145 NOTREACHED(); 148 NOTREACHED();
146 return 0; 149 return 0;
147 } 150 }
148 151
152 GLuint SetupVertexBuffer() {
153 GLuint vertex_buffer = 0;
154 glGenBuffersARB(1, &vertex_buffer);
155 gfx::ScopedBufferBinder sbb(GL_ARRAY_BUFFER, vertex_buffer);
reveman 2015/10/29 22:08:04 nit: s/sbb/scoped_buffer_binder/ or buffer_binder,
Daniele Castagna 2015/10/30 23:51:57 Renamed just buffer_binder, also changed the name
156
157 GLfloat data[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
158 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
159 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0);
160
161 return vertex_buffer;
162 }
163
149 } // namespace 164 } // namespace
150 165
166 // clang-format off
167 const char GLImageIOSurface::kVertexShader[] =
168 STRINGIZE(
169 attribute vec2 a_position;
170 uniform vec2 a_size;
171 varying vec2 v_texCoord;
172 void main() {
173 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
174 v_texCoord = (a_position + vec2(1,1)) * 0.5 * a_size;
175 }
176 );
177
178 const char GLImageIOSurface::kFragmentShader[] =
179 STRINGIZE(
180 uniform sampler2DRect a_y_texture;
181 uniform sampler2DRect a_uv_texture;
182 varying vec2 v_texCoord;
183 void main() {
184 vec3 yuv_adj = vec3(-0.0625, -0.5, -0.5);
185 mat3 yuv_matrix = mat3(vec3(1.164, 1.164, 1.164),
186 vec3(0.0, -.391, 2.018),
187 vec3(1.596, -.813, 0.0));
188 vec3 yuv = vec3(texture2DRect(a_y_texture, v_texCoord).r,
189 texture2DRect(a_uv_texture, v_texCoord * 0.5).rg);
190 gl_FragColor = vec4( yuv_matrix * (yuv + yuv_adj), 1.0);
191 }
192 );
193 // clang-format on
194
151 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, 195 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size,
152 unsigned internalformat) 196 unsigned internalformat)
153 : size_(size), 197 : size_(size),
154 internalformat_(internalformat), 198 internalformat_(internalformat),
155 format_(BufferFormat::RGBA_8888) {} 199 format_(BufferFormat::RGBA_8888) {}
156 200
157 GLImageIOSurface::~GLImageIOSurface() { 201 GLImageIOSurface::~GLImageIOSurface() {
158 DCHECK(thread_checker_.CalledOnValidThread()); 202 DCHECK(thread_checker_.CalledOnValidThread());
159 DCHECK(!io_surface_); 203 DCHECK(!io_surface_);
160 } 204 }
(...skipping 15 matching lines...) Expand all
176 } 220 }
177 221
178 format_ = format; 222 format_ = format;
179 io_surface_.reset(io_surface, base::scoped_policy::RETAIN); 223 io_surface_.reset(io_surface, base::scoped_policy::RETAIN);
180 io_surface_id_ = io_surface_id; 224 io_surface_id_ = io_surface_id;
181 return true; 225 return true;
182 } 226 }
183 227
184 void GLImageIOSurface::Destroy(bool have_context) { 228 void GLImageIOSurface::Destroy(bool have_context) {
185 DCHECK(thread_checker_.CalledOnValidThread()); 229 DCHECK(thread_checker_.CalledOnValidThread());
230 if (have_context) {
231 glDeleteProgram(program_);
reveman 2015/10/29 22:08:04 what if you haven't created a program?
Daniele Castagna 2015/10/30 23:51:57 In that case program_ would be 0. The documentatio
232 glDeleteShader(vertex_shader_);
233 glDeleteShader(fragment_shader_);
234 glDeleteBuffersARB(1, &vertex_buffer_);
235 glDeleteFramebuffersEXT(1, &framebuffer_);
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() { return internalformat_; }
194 245
195 bool GLImageIOSurface::BindTexImage(unsigned target) { 246 bool GLImageIOSurface::BindTexImage(unsigned target) {
196 DCHECK(thread_checker_.CalledOnValidThread()); 247 DCHECK(thread_checker_.CalledOnValidThread());
248
249 if (format_ == BufferFormat::YUV_420_BIPLANAR)
reveman 2015/10/29 22:08:04 Can you add a comment here to explain that this fo
Daniele Castagna 2015/10/30 23:51:57 Done.
250 return false;
251
197 if (target != GL_TEXTURE_RECTANGLE_ARB) { 252 if (target != GL_TEXTURE_RECTANGLE_ARB) {
198 // This might be supported in the future. For now, perform strict 253 // This might be supported in the future. For now, perform strict
199 // validation so we know what's going on. 254 // validation so we know what's going on.
200 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target"; 255 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target";
201 return false; 256 return false;
202 } 257 }
203 258
204 CGLContextObj cgl_context = 259 CGLContextObj cgl_context =
205 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); 260 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
206 261
207 DCHECK(io_surface_); 262 DCHECK(io_surface_);
208 CGLError cgl_error = 263 CGLError cgl_error =
209 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_), 264 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_),
210 size_.width(), size_.height(), DataFormat(format_), 265 size_.width(), size_.height(), DataFormat(format_),
211 DataType(format_), io_surface_.get(), 0); 266 DataType(format_), io_surface_.get(), 0);
212 if (cgl_error != kCGLNoError) { 267 if (cgl_error != kCGLNoError) {
213 LOG(ERROR) << "Error in CGLTexImageIOSurface2D"; 268 LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
214 return false; 269 return false;
215 } 270 }
216 271
217 return true; 272 return true;
218 } 273 }
219 274
220 bool GLImageIOSurface::CopyTexImage(unsigned target) { 275 bool GLImageIOSurface::CopyTexImage(unsigned target) {
221 return false; 276 DCHECK(thread_checker_.CalledOnValidThread());
277 DCHECK(io_surface_);
278 if (format_ != BufferFormat::YUV_420_BIPLANAR)
279 return false;
280
281 if (target != GL_TEXTURE_2D) {
282 LOG(ERROR) << "YUV_420_BIPLANAR requires TEXTURE_2D target";
283 return false;
284 }
285
286 if (!framebuffer_) {
287 glGenFramebuffersEXT(1, &framebuffer_);
288 vertex_buffer_ = SetupVertexBuffer();
289 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
290 fragment_shader_ =
291 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
292 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
293 gfx::ScopedUseProgram pr(program_);
294
295 size_location_ = glGetUniformLocation(program_, "a_size");
296 DCHECK_NE(-1, size_location_);
297 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture");
298 DCHECK_NE(-1, y_sampler_location);
299 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture");
300 DCHECK_NE(-1, uv_sampler_location);
301
302 glUniform1i(y_sampler_location, 0);
303 glUniform1i(uv_sampler_location, 1);
304 }
305
306 CGLContextObj cgl_context =
307 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
308
309 GLuint yuv_textures[2];
310 glGenTextures(2, yuv_textures);
311 DCHECK(yuv_textures[0] && yuv_textures[1]);
312
313 GLint service_texture = 0;
reveman 2015/10/29 22:08:04 nit: service_texture -> target_texture as there's
Daniele Castagna 2015/10/30 23:51:57 Done.
314 glGetIntegerv(GL_TEXTURE_BINDING_2D, &service_texture);
315 DCHECK(service_texture);
316
317 GLint previous_active_texture = 0;
318 glGetIntegerv(GL_ACTIVE_TEXTURE, &previous_active_texture);
319
320 CGLError cgl_error = kCGLNoError;
321 {
322 glActiveTexture(GL_TEXTURE0);
323 gfx::ScopedTextureBinder b(GL_TEXTURE_RECTANGLE_ARB, yuv_textures[0]);
324 cgl_error = CGLTexImageIOSurface2D(
325 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(),
326 size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_.get(), 0);
327 if (cgl_error != kCGLNoError) {
328 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. "
329 << cgl_error;
330 glDeleteTextures(2, yuv_textures);
reveman 2015/10/29 22:08:04 Do we need to restore the active texture here? May
Daniele Castagna 2015/10/30 23:51:57 Done.
331 return false;
332 }
333 {
334 glActiveTexture(GL_TEXTURE1);
335 gfx::ScopedTextureBinder b(GL_TEXTURE_RECTANGLE_ARB, yuv_textures[1]);
336 cgl_error = CGLTexImageIOSurface2D(
337 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2,
338 size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1);
339 if (cgl_error != kCGLNoError) {
340 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. "
341 << cgl_error;
342 glDeleteTextures(2, yuv_textures);
343 return false;
344 }
345
346 gfx::ScopedFrameBufferBinder fb(framebuffer_);
reveman 2015/10/29 22:08:04 nit: s/fb/scoped_framebuffer/
Daniele Castagna 2015/10/30 23:51:57 Changed all of them!
347 glViewport(0, 0, size_.width(), size_.height());
reveman 2015/10/29 22:08:04 do we need to restore the viewport before we exit?
Daniele Castagna 2015/10/30 23:51:57 Added another Scoped* class...
348 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
349 GL_TEXTURE_2D, service_texture, 0);
350 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
351 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
352
353 gfx::ScopedUseProgram pr(program_);
reveman 2015/10/29 22:08:04 nit: please remove "pr" abbreviation here and simi
Daniele Castagna 2015/10/30 23:51:57 Done.
354 glUniform2f(size_location_, size_.width(), size_.height());
355
356 gfx::ScopedEnableVertexAttribArray vaa(0);
357 gfx::ScopedBufferBinder bb(GL_ARRAY_BUFFER, vertex_buffer_);
358 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
359
360 // Detach the service texture from the fbo.
reveman 2015/10/29 22:08:04 target texture
Daniele Castagna 2015/10/30 23:51:57 Done.
361 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
362 GL_TEXTURE_2D, 0, 0);
363
364 } // GL_TEXTURE1
365 glActiveTexture(GL_TEXTURE0);
reveman 2015/10/29 22:08:04 previous_active_texture?
Daniele Castagna 2015/10/30 23:51:57 ack.
366 } // GL_TEXTURE0
367 return true;
222 } 368 }
223 369
224 bool GLImageIOSurface::CopyTexSubImage(unsigned target, 370 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
225 const gfx::Point& offset, 371 const gfx::Point& offset,
226 const gfx::Rect& rect) { 372 const gfx::Rect& rect) {
227 return false; 373 return false;
228 } 374 }
229 375
230 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 376 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
231 int z_order, 377 int z_order,
(...skipping 30 matching lines...) Expand all
262 // static 408 // static
263 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget, 409 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget,
264 CALayer* layer) { 410 CALayer* layer) {
265 if (layer) 411 if (layer)
266 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer)); 412 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer));
267 else 413 else
268 g_widget_to_layer_map.Pointer()->erase(widget); 414 g_widget_to_layer_map.Pointer()->erase(widget);
269 } 415 }
270 416
271 } // namespace gfx 417 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698