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

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: Address reveman's comments. 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/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_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 && framebuffer_) {
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() {
246 return internalformat_;
247 }
194 248
195 bool GLImageIOSurface::BindTexImage(unsigned target) { 249 bool GLImageIOSurface::BindTexImage(unsigned target) {
196 DCHECK(thread_checker_.CalledOnValidThread()); 250 DCHECK(thread_checker_.CalledOnValidThread());
251
252 // YUV_420_BIPLANAR is not supported by BindTexImage.
253 // CopyTexImage is supported by this format as that performs conversion to RGB
254 // as part of the copy operation.
255 if (format_ == BufferFormat::YUV_420_BIPLANAR)
256 return false;
257
197 if (target != GL_TEXTURE_RECTANGLE_ARB) { 258 if (target != GL_TEXTURE_RECTANGLE_ARB) {
198 // This might be supported in the future. For now, perform strict 259 // This might be supported in the future. For now, perform strict
199 // validation so we know what's going on. 260 // validation so we know what's going on.
200 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target"; 261 LOG(ERROR) << "IOSurface requires TEXTURE_RECTANGLE_ARB target";
201 return false; 262 return false;
202 } 263 }
203 264
204 CGLContextObj cgl_context = 265 CGLContextObj cgl_context =
205 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); 266 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
206 267
207 DCHECK(io_surface_); 268 DCHECK(io_surface_);
208 CGLError cgl_error = 269 CGLError cgl_error =
209 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_), 270 CGLTexImageIOSurface2D(cgl_context, target, TextureFormat(format_),
210 size_.width(), size_.height(), DataFormat(format_), 271 size_.width(), size_.height(), DataFormat(format_),
211 DataType(format_), io_surface_.get(), 0); 272 DataType(format_), io_surface_.get(), 0);
212 if (cgl_error != kCGLNoError) { 273 if (cgl_error != kCGLNoError) {
213 LOG(ERROR) << "Error in CGLTexImageIOSurface2D"; 274 LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
214 return false; 275 return false;
215 } 276 }
216 277
217 return true; 278 return true;
218 } 279 }
219 280
220 bool GLImageIOSurface::CopyTexImage(unsigned target) { 281 bool GLImageIOSurface::CopyTexImage(unsigned target) {
221 return false; 282 DCHECK(thread_checker_.CalledOnValidThread());
283
284 if (format_ != BufferFormat::YUV_420_BIPLANAR)
285 return false;
286
287 if (target != GL_TEXTURE_2D) {
288 LOG(ERROR) << "YUV_420_BIPLANAR requires TEXTURE_2D target";
289 return false;
290 }
291
292 if (!framebuffer_) {
293 glGenFramebuffersEXT(1, &framebuffer_);
294 vertex_buffer_ = SetupVertexBuffer();
295 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
296 fragment_shader_ =
297 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
298 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
299 gfx::ScopedUseProgram use_program(program_);
300
301 size_location_ = glGetUniformLocation(program_, "a_texScale");
302 DCHECK_NE(-1, size_location_);
303 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture");
304 DCHECK_NE(-1, y_sampler_location);
305 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture");
306 DCHECK_NE(-1, uv_sampler_location);
307
308 glUniform1i(y_sampler_location, 0);
309 glUniform1i(uv_sampler_location, 1);
310 }
311
312 CGLContextObj cgl_context =
313 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
314
315 GLuint yuv_textures[2] = {};
316 glGenTextures(2, yuv_textures);
reveman 2015/11/02 01:09:44 we seem to be leaking these when the copy operatio
Daniele Castagna 2015/11/02 19:35:51 Fixed it using ScopedClosureRunner. I'd prefer to
reveman 2015/11/02 21:13:33 This is not actually adding any more memory usage
317 DCHECK(yuv_textures[0]);
318 DCHECK(yuv_textures[1]);
319
320 GLint target_texture = 0;
321 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
322 DCHECK(target_texture);
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 glDeleteTextures(2, yuv_textures);
338 return false;
339 }
340 {
341 gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1);
342 gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB,
343 yuv_textures[1]);
344 cgl_error = CGLTexImageIOSurface2D(
345 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2,
346 size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1);
347 if (cgl_error != kCGLNoError) {
348 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. "
349 << cgl_error;
350 glDeleteTextures(2, yuv_textures);
351 return false;
352 }
353
354 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
355 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
356 glViewport(0, 0, size_.width(), size_.height());
357 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size_.width(), size_.height(), 0,
358 GL_RGB, GL_UNSIGNED_BYTE, nullptr);
359 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
360 GL_TEXTURE_2D, target_texture, 0);
361 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
362 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
363
364 gfx::ScopedUseProgram use_program(program_);
365 glUniform2f(size_location_, size_.width(), size_.height());
366
367 gfx::ScopedEnableVertexAttribArray enable_vertex_attrib_array(0);
368 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_);
369 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
370
371 // Detach the output texture from the fbo.
372 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
373 GL_TEXTURE_2D, 0, 0);
374 }
375 }
376 return true;
222 } 377 }
223 378
224 bool GLImageIOSurface::CopyTexSubImage(unsigned target, 379 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
225 const gfx::Point& offset, 380 const gfx::Point& offset,
226 const gfx::Rect& rect) { 381 const gfx::Rect& rect) {
227 return false; 382 return false;
228 } 383 }
229 384
230 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 385 bool GLImageIOSurface::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
231 int z_order, 386 int z_order,
(...skipping 29 matching lines...) Expand all
261 416
262 // static 417 // static
263 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget, 418 void GLImageIOSurface::SetLayerForWidget(gfx::AcceleratedWidget widget,
264 CALayer* layer) { 419 CALayer* layer) {
265 if (layer) 420 if (layer)
266 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer)); 421 g_widget_to_layer_map.Pointer()->insert(std::make_pair(widget, layer));
267 else 422 else
268 g_widget_to_layer_map.Pointer()->erase(widget); 423 g_widget_to_layer_map.Pointer()->erase(widget);
269 } 424 }
270 425
271 } // namespace gfx 426 } // namespace gl
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698