1 // Copyright (c) 2012 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.
4
5 #include "content/common/gpu/client/gl_helper.h"
6
7 #include <queue>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/debug/trace_event.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/strings/string_util.h"
17 #include "base/time/time.h"
18 #include "content/common/gpu/client/gl_helper_readback_support.h"
19 #include "content/common/gpu/client/gl_helper_scaling.h"
20 #include "gpu/GLES2/gl2extchromium.h"
21 #include "gpu/command_buffer/client/context_support.h"
22 #include "gpu/command_buffer/common/mailbox.h"
23 #include "gpu/command_buffer/common/mailbox_holder.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/video_util.h"
26 #include "third_party/skia/include/core/SkRegion.h"
27 #include "ui/gfx/rect.h"
28 #include "ui/gfx/size.h"
29
30 using gpu::gles2::GLES2Interface;
31
32 namespace {
33
34 class ScopedFlush {
35 public:
ScopedFlush(gpu::gles2::GLES2Interface * gl)36 explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
37
~ScopedFlush()38 ~ScopedFlush() { gl_->Flush(); }
39
40 private:
41 gpu::gles2::GLES2Interface* gl_;
42
43 DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
44 };
45
46 // Helper class for allocating and holding an RGBA texture of a given
47 // size and an associated framebuffer.
48 class TextureFrameBufferPair {
49 public:
TextureFrameBufferPair(GLES2Interface * gl,gfx::Size size)50 TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
51 : texture_(gl), framebuffer_(gl), size_(size) {
52 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
53 gl->TexImage2D(GL_TEXTURE_2D,
54 0,
55 GL_RGBA,
56 size.width(),
57 size.height(),
58 0,
59 GL_RGBA,
60 GL_UNSIGNED_BYTE,
61 NULL);
62 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
63 gl, framebuffer_);
64 gl->FramebufferTexture2D(
65 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
66 }
67
texture() const68 GLuint texture() const { return texture_.id(); }
framebuffer() const69 GLuint framebuffer() const { return framebuffer_.id(); }
size() const70 gfx::Size size() const { return size_; }
71
72 private:
73 content::ScopedTexture texture_;
74 content::ScopedFramebuffer framebuffer_;
75 gfx::Size size_;
76
77 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
78 };
79
80 // Helper class for holding a scaler, a texture for the output of that
81 // scaler and an associated frame buffer. This is inteded to be used
82 // when the output of a scaler is to be sent to a readback.
83 class ScalerHolder {
84 public:
ScalerHolder(GLES2Interface * gl,content::GLHelper::ScalerInterface * scaler)85 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
86 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
87
Scale(GLuint src_texture)88 void Scale(GLuint src_texture) {
89 scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
90 }
91
scaler() const92 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
texture_and_framebuffer()93 TextureFrameBufferPair* texture_and_framebuffer() {
94 return &texture_and_framebuffer_;
95 }
texture() const96 GLuint texture() const { return texture_and_framebuffer_.texture(); }
97
98 private:
99 TextureFrameBufferPair texture_and_framebuffer_;
100 scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
101
102 DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
103 };
104
105 } // namespace
106
107 namespace content {
108
109 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
110 // the data needed for it.
111 class GLHelper::CopyTextureToImpl
112 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
113 public:
CopyTextureToImpl(GLES2Interface * gl,gpu::ContextSupport * context_support,GLHelper * helper)114 CopyTextureToImpl(GLES2Interface* gl,
115 gpu::ContextSupport* context_support,
116 GLHelper* helper)
117 : gl_(gl),
118 context_support_(context_support),
119 helper_(helper),
120 flush_(gl),
121 max_draw_buffers_(0) {
122 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
123 if (!extensions)
124 return;
125 std::string extensions_string =
126 " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
127 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
128 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
129 }
130 }
~CopyTextureToImpl()131 ~CopyTextureToImpl() { CancelRequests(); }
132
ConsumeMailboxToTexture(const gpu::Mailbox & mailbox,uint32 sync_point)133 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
134 uint32 sync_point) {
135 return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
136 }
137
138 void CropScaleReadbackAndCleanTexture(
139 GLuint src_texture,
140 const gfx::Size& src_size,
141 const gfx::Rect& src_subrect,
142 const gfx::Size& dst_size,
143 unsigned char* out,
144 const SkBitmap::Config config,
145 const base::Callback<void(bool)>& callback,
146 GLHelper::ScalerQuality quality);
147
148 void ReadbackTextureSync(GLuint texture,
149 const gfx::Rect& src_rect,
150 unsigned char* out,
151 SkBitmap::Config format);
152
153 void ReadbackTextureAsync(GLuint texture,
154 const gfx::Size& dst_size,
155 unsigned char* out,
156 SkBitmap::Config config,
157 const base::Callback<void(bool)>& callback);
158
159 // Reads back bytes from the currently bound frame buffer.
160 // Note that dst_size is specified in bytes, not pixels.
161 void ReadbackAsync(const gfx::Size& dst_size,
162 int32 bytes_per_row, // generally dst_size.width() * 4
163 int32 row_stride_bytes, // generally dst_size.width() * 4
164 unsigned char* out,
165 const SkBitmap::Config config,
166 ReadbackSwizzle swizzle,
167 const base::Callback<void(bool)>& callback);
168
169 void ReadbackPlane(TextureFrameBufferPair* source,
170 const scoped_refptr<media::VideoFrame>& target,
171 int plane,
172 int size_shift,
173 const gfx::Rect& dst_subrect,
174 ReadbackSwizzle swizzle,
175 const base::Callback<void(bool)>& callback);
176
177 GLuint CopyAndScaleTexture(GLuint texture,
178 const gfx::Size& src_size,
179 const gfx::Size& dst_size,
180 bool vertically_flip_texture,
181 GLHelper::ScalerQuality quality);
182
183 ReadbackYUVInterface* CreateReadbackPipelineYUV(
184 GLHelper::ScalerQuality quality,
185 const gfx::Size& src_size,
186 const gfx::Rect& src_subrect,
187 const gfx::Size& dst_size,
188 const gfx::Rect& dst_subrect,
189 bool flip_vertically,
190 bool use_mrt);
191
192 // Returns the maximum number of draw buffers available,
193 // 0 if GL_EXT_draw_buffers is not available.
MaxDrawBuffers() const194 GLint MaxDrawBuffers() const { return max_draw_buffers_; }
195
196 bool IsReadbackConfigSupported(SkBitmap::Config bitmap_config);
197
198 private:
199 // A single request to CropScaleReadbackAndCleanTexture.
200 // The main thread can cancel the request, before it's handled by the helper
201 // thread, by resetting the texture and pixels fields. Alternatively, the
202 // thread marks that it handles the request by resetting the pixels field
203 // (meaning it guarantees that the callback with be called).
204 // In either case, the callback must be called exactly once, and the texture
205 // must be deleted by the main thread gl.
206 struct Request {
Requestcontent::GLHelper::CopyTextureToImpl::Request207 Request(const gfx::Size& size_,
208 int32 bytes_per_row_,
209 int32 row_stride_bytes_,
210 unsigned char* pixels_,
211 const base::Callback<void(bool)>& callback_)
212 : done(false),
213 size(size_),
214 bytes_per_row(bytes_per_row_),
215 row_stride_bytes(row_stride_bytes_),
216 pixels(pixels_),
217 callback(callback_),
218 buffer(0),
219 query(0) {}
220
221 bool done;
222 gfx::Size size;
223 int bytes_per_row;
224 int row_stride_bytes;
225 unsigned char* pixels;
226 base::Callback<void(bool)> callback;
227 GLuint buffer;
228 GLuint query;
229 };
230
231 // A readback pipeline that also converts the data to YUV before
232 // reading it back.
233 class ReadbackYUVImpl : public ReadbackYUVInterface {
234 public:
235 ReadbackYUVImpl(GLES2Interface* gl,
236 CopyTextureToImpl* copy_impl,
237 GLHelperScaling* scaler_impl,
238 GLHelper::ScalerQuality quality,
239 const gfx::Size& src_size,
240 const gfx::Rect& src_subrect,
241 const gfx::Size& dst_size,
242 const gfx::Rect& dst_subrect,
243 bool flip_vertically,
244 ReadbackSwizzle swizzle);
245
246 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
247 uint32 sync_point,
248 const scoped_refptr<media::VideoFrame>& target,
249 const base::Callback<void(bool)>& callback)
250 OVERRIDE;
251
scaler()252 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
253
254 private:
255 GLES2Interface* gl_;
256 CopyTextureToImpl* copy_impl_;
257 gfx::Size dst_size_;
258 gfx::Rect dst_subrect_;
259 ReadbackSwizzle swizzle_;
260 ScalerHolder scaler_;
261 ScalerHolder y_;
262 ScalerHolder u_;
263 ScalerHolder v_;
264
265 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
266 };
267
268 // A readback pipeline that also converts the data to YUV before
269 // reading it back. This one uses Multiple Render Targets, which
270 // may not be supported on all platforms.
271 class ReadbackYUV_MRT : public ReadbackYUVInterface {
272 public:
273 ReadbackYUV_MRT(GLES2Interface* gl,
274 CopyTextureToImpl* copy_impl,
275 GLHelperScaling* scaler_impl,
276 GLHelper::ScalerQuality quality,
277 const gfx::Size& src_size,
278 const gfx::Rect& src_subrect,
279 const gfx::Size& dst_size,
280 const gfx::Rect& dst_subrect,
281 bool flip_vertically,
282 ReadbackSwizzle swizzle);
283
284 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
285 uint32 sync_point,
286 const scoped_refptr<media::VideoFrame>& target,
287 const base::Callback<void(bool)>& callback)
288 OVERRIDE;
289
scaler()290 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
291
292 private:
293 GLES2Interface* gl_;
294 CopyTextureToImpl* copy_impl_;
295 gfx::Size dst_size_;
296 gfx::Rect dst_subrect_;
297 GLHelper::ScalerQuality quality_;
298 ReadbackSwizzle swizzle_;
299 ScalerHolder scaler_;
300 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
301 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
302 TextureFrameBufferPair y_;
303 ScopedTexture uv_;
304 TextureFrameBufferPair u_;
305 TextureFrameBufferPair v_;
306
307 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
308 };
309
310 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
311 // scales it to |dst_size|, writes it into a texture, and returns its ID.
312 // |src_size| is the size of |src_texture|.
313 GLuint ScaleTexture(GLuint src_texture,
314 const gfx::Size& src_size,
315 const gfx::Rect& src_subrect,
316 const gfx::Size& dst_size,
317 bool vertically_flip_texture,
318 bool swizzle,
319 SkBitmap::Config config,
320 GLHelper::ScalerQuality quality);
321
nullcallback(bool success)322 static void nullcallback(bool success) {}
323 void ReadbackDone(Request *request, int bytes_per_pixel);
324 void FinishRequest(Request* request, bool result);
325 void CancelRequests();
326
327 static const float kRGBtoYColorWeights[];
328 static const float kRGBtoUColorWeights[];
329 static const float kRGBtoVColorWeights[];
330
331 GLES2Interface* gl_;
332 gpu::ContextSupport* context_support_;
333 GLHelper* helper_;
334
335 // A scoped flush that will ensure all resource deletions are flushed when
336 // this object is destroyed. Must be declared before other Scoped* fields.
337 ScopedFlush flush_;
338
339 std::queue<Request*> request_queue_;
340 GLint max_draw_buffers_;
341 };
342
CreateScaler(ScalerQuality quality,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,bool vertically_flip_texture,bool swizzle)343 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
344 const gfx::Size& src_size,
345 const gfx::Rect& src_subrect,
346 const gfx::Size& dst_size,
347 bool vertically_flip_texture,
348 bool swizzle) {
349 InitScalerImpl();
350 return scaler_impl_->CreateScaler(quality,
351 src_size,
352 src_subrect,
353 dst_size,
354 vertically_flip_texture,
355 swizzle);
356 }
357
ScaleTexture(GLuint src_texture,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,bool vertically_flip_texture,bool swizzle,SkBitmap::Config bitmap_config,GLHelper::ScalerQuality quality)358 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
359 GLuint src_texture,
360 const gfx::Size& src_size,
361 const gfx::Rect& src_subrect,
362 const gfx::Size& dst_size,
363 bool vertically_flip_texture,
364 bool swizzle,
365 SkBitmap::Config bitmap_config,
366 GLHelper::ScalerQuality quality) {
367 if (!IsReadbackConfigSupported(bitmap_config))
368 return 0;
369
370 scoped_ptr<ScalerInterface> scaler(
371 helper_->CreateScaler(quality,
372 src_size,
373 src_subrect,
374 dst_size,
375 vertically_flip_texture,
376 swizzle));
377 GLuint dst_texture = 0u;
378 // Start with ARGB8888 params as any other format which is not
379 // supported is already asserted above.
380 GLenum format = GL_RGBA , type = GL_UNSIGNED_BYTE;
381 gl_->GenTextures(1, &dst_texture);
382 {
383 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
384 switch (bitmap_config) {
385 case SkBitmap::kARGB_8888_Config:
386 // Do nothing params already set.
387 break;
388 case SkBitmap::kRGB_565_Config:
389 format = GL_RGB;
390 type = GL_UNSIGNED_SHORT_5_6_5;
391 break;
392 default:
393 NOTREACHED();
394 break;
395 }
396 gl_->TexImage2D(GL_TEXTURE_2D,
397 0,
398 format,
399 dst_size.width(),
400 dst_size.height(),
401 0,
402 format,
403 type,
404 NULL);
405 }
406 scaler->Scale(src_texture, dst_texture);
407 return dst_texture;
408 }
409
ReadbackAsync(const gfx::Size & dst_size,int32 bytes_per_row,int32 row_stride_bytes,unsigned char * out,const SkBitmap::Config bitmap_config,ReadbackSwizzle swizzle,const base::Callback<void (bool)> & callback)410 void GLHelper::CopyTextureToImpl::ReadbackAsync(
411 const gfx::Size& dst_size,
412 int32 bytes_per_row,
413 int32 row_stride_bytes,
414 unsigned char* out,
415 const SkBitmap::Config bitmap_config,
416 ReadbackSwizzle swizzle,
417 const base::Callback<void(bool)>& callback) {
418 if (!IsReadbackConfigSupported(bitmap_config)) {
419 callback.Run(false);
420 return;
421 }
422 Request* request =
423 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
424 request_queue_.push(request);
425 request->buffer = 0u;
426 // Start with ARGB8888 params as any other format which is not
427 // supported is already asserted above.
428 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
429 int bytes_per_pixel = 4;
430
431 switch (bitmap_config) {
432 case SkBitmap::kARGB_8888_Config:
433 if (swizzle == kSwizzleBGRA)
434 format = GL_BGRA_EXT;
435 break;
436 case SkBitmap::kRGB_565_Config:
437 format = GL_RGB;
438 type = GL_UNSIGNED_SHORT_5_6_5;
439 bytes_per_pixel = 2;
440 break;
441 default:
442 NOTREACHED();
443 break;
444 }
445 gl_->GenBuffers(1, &request->buffer);
446 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
447 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
448 bytes_per_pixel * dst_size.GetArea(),
449 NULL,
450 GL_STREAM_READ);
451
452 request->query = 0u;
453 gl_->GenQueriesEXT(1, &request->query);
454 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
455 gl_->ReadPixels(0,
456 0,
457 dst_size.width(),
458 dst_size.height(),
459 format,
460 type,
461 NULL);
462 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
463 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
464 context_support_->SignalQuery(
465 request->query,
466 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
467 request, bytes_per_pixel));
468 }
CropScaleReadbackAndCleanTexture(GLuint src_texture,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,unsigned char * out,const SkBitmap::Config bitmap_config,const base::Callback<void (bool)> & callback,GLHelper::ScalerQuality quality)469 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
470 GLuint src_texture,
471 const gfx::Size& src_size,
472 const gfx::Rect& src_subrect,
473 const gfx::Size& dst_size,
474 unsigned char* out,
475 const SkBitmap::Config bitmap_config,
476 const base::Callback<void(bool)>& callback,
477 GLHelper::ScalerQuality quality) {
478 if (!IsReadbackConfigSupported(bitmap_config)) {
479 callback.Run(false);
480 return;
481 }
482 GLuint texture = ScaleTexture(src_texture,
483 src_size,
484 src_subrect,
485 dst_size,
486 true,
487 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
488 true,
489 #else
490 false,
491 #endif
492 bitmap_config,
493 quality);
494 DCHECK(texture);
495 ScopedFramebuffer dst_framebuffer(gl_);
496 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
497 dst_framebuffer);
498 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
499 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
500 GL_COLOR_ATTACHMENT0,
501 GL_TEXTURE_2D,
502 texture,
503 0);
504 int bytes_per_pixel = 4;
505 switch (bitmap_config) {
506 case SkBitmap::kARGB_8888_Config:
507 // Do nothing params already set.
508 break;
509 case SkBitmap::kRGB_565_Config:
510 bytes_per_pixel = 2;
511 break;
512 default:
513 NOTREACHED();
514 break;
515 }
516 ReadbackAsync(dst_size,
517 dst_size.width() * bytes_per_pixel,
518 dst_size.width() * bytes_per_pixel,
519 out,
520 bitmap_config,
521 kSwizzleNone,
522 callback);
523 gl_->DeleteTextures(1, &texture);
524 }
525
ReadbackTextureSync(GLuint texture,const gfx::Rect & src_rect,unsigned char * out,SkBitmap::Config bitmap_config)526 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
527 GLuint texture,
528 const gfx::Rect& src_rect,
529 unsigned char* out,
530 SkBitmap::Config bitmap_config) {
531 if (!IsReadbackConfigSupported(bitmap_config))
532 return;
533
534 ScopedFramebuffer dst_framebuffer(gl_);
535 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
536 dst_framebuffer);
537 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
538 gl_->FramebufferTexture2D(
539 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
540 GLenum format =
541 (bitmap_config == SkBitmap::kRGB_565_Config) ? GL_RGB : GL_RGBA;
542 GLenum type = (bitmap_config == SkBitmap::kRGB_565_Config)
543 ? GL_UNSIGNED_SHORT_5_6_5
544 : GL_UNSIGNED_BYTE;
545 gl_->ReadPixels(src_rect.x(),
546 src_rect.y(),
547 src_rect.width(),
548 src_rect.height(),
549 format,
550 type,
551 out);
552 }
553
ReadbackTextureAsync(GLuint texture,const gfx::Size & dst_size,unsigned char * out,SkBitmap::Config bitmap_config,const base::Callback<void (bool)> & callback)554 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
555 GLuint texture,
556 const gfx::Size& dst_size,
557 unsigned char* out,
558 SkBitmap::Config bitmap_config,
559 const base::Callback<void(bool)>& callback) {
560 if (!IsReadbackConfigSupported(bitmap_config))
561 return;
562
563 ScopedFramebuffer dst_framebuffer(gl_);
564 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
565 dst_framebuffer);
566 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
567 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
568 GL_COLOR_ATTACHMENT0,
569 GL_TEXTURE_2D,
570 texture,
571 0);
572 int bytes_per_pixel = (bitmap_config == SkBitmap::kRGB_565_Config) ? 2 : 4;
573 ReadbackAsync(dst_size,
574 dst_size.width() * bytes_per_pixel,
575 dst_size.width() * bytes_per_pixel,
576 out,
577 bitmap_config,
578 kSwizzleNone,
579 callback);
580 }
581
CopyAndScaleTexture(GLuint src_texture,const gfx::Size & src_size,const gfx::Size & dst_size,bool vertically_flip_texture,GLHelper::ScalerQuality quality)582 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
583 GLuint src_texture,
584 const gfx::Size& src_size,
585 const gfx::Size& dst_size,
586 bool vertically_flip_texture,
587 GLHelper::ScalerQuality quality) {
588 return ScaleTexture(src_texture,
589 src_size,
590 gfx::Rect(src_size),
591 dst_size,
592 vertically_flip_texture,
593 false,
594 SkBitmap::kARGB_8888_Config,
595 quality);
596 }
597
IsReadbackConfigSupported(SkBitmap::Config bitmap_config)598 bool GLHelper::CopyTextureToImpl::IsReadbackConfigSupported(
599 SkBitmap::Config bitmap_config) {
600 if (!helper_) {
601 DCHECK(helper_);
602 return false;
603 }
604 return helper_->IsReadbackConfigSupported(bitmap_config);
605 }
606
ReadbackDone(Request * finished_request,int bytes_per_pixel)607 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
608 int bytes_per_pixel) {
609 TRACE_EVENT0("mirror",
610 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
611 finished_request->done = true;
612
613 // We process transfer requests in the order they were received, regardless
614 // of the order we get the callbacks in.
615 while (!request_queue_.empty()) {
616 Request* request = request_queue_.front();
617 if (!request->done) {
618 break;
619 }
620
621 bool result = false;
622 if (request->buffer != 0) {
623 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
624 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
625 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
626 if (data) {
627 result = true;
628 if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
629 request->bytes_per_row == request->row_stride_bytes) {
630 memcpy(request->pixels, data,
631 request->size.GetArea() * bytes_per_pixel);
632 } else {
633 unsigned char* out = request->pixels;
634 for (int y = 0; y < request->size.height(); y++) {
635 memcpy(out, data, request->bytes_per_row);
636 out += request->row_stride_bytes;
637 data += request->size.width() * bytes_per_pixel;
638 }
639 }
640 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
641 }
642 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
643 }
644 FinishRequest(request, result);
645 }
646 }
647
FinishRequest(Request * request,bool result)648 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
649 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
650 DCHECK(request_queue_.front() == request);
651 request_queue_.pop();
652 request->callback.Run(result);
653 ScopedFlush flush(gl_);
654 if (request->query != 0) {
655 gl_->DeleteQueriesEXT(1, &request->query);
656 request->query = 0;
657 }
658 if (request->buffer != 0) {
659 gl_->DeleteBuffers(1, &request->buffer);
660 request->buffer = 0;
661 }
662 delete request;
663 }
664
CancelRequests()665 void GLHelper::CopyTextureToImpl::CancelRequests() {
666 while (!request_queue_.empty()) {
667 Request* request = request_queue_.front();
668 FinishRequest(request, false);
669 }
670 }
671
GLHelper(GLES2Interface * gl,gpu::ContextSupport * context_support)672 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
673 : gl_(gl),
674 context_support_(context_support),
675 readback_support_(new GLHelperReadbackSupport(gl)) {}
676
~GLHelper()677 GLHelper::~GLHelper() {}
678
CropScaleReadbackAndCleanTexture(GLuint src_texture,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,unsigned char * out,const SkBitmap::Config config,const base::Callback<void (bool)> & callback,GLHelper::ScalerQuality quality)679 void GLHelper::CropScaleReadbackAndCleanTexture(
680 GLuint src_texture,
681 const gfx::Size& src_size,
682 const gfx::Rect& src_subrect,
683 const gfx::Size& dst_size,
684 unsigned char* out,
685 const SkBitmap::Config config,
686 const base::Callback<void(bool)>& callback,
687 GLHelper::ScalerQuality quality) {
688 InitCopyTextToImpl();
689 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(
690 src_texture,
691 src_size,
692 src_subrect,
693 dst_size,
694 out,
695 config,
696 callback,
697 quality);
698 }
699
CropScaleReadbackAndCleanMailbox(const gpu::Mailbox & src_mailbox,uint32 sync_point,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,unsigned char * out,const SkBitmap::Config bitmap_config,const base::Callback<void (bool)> & callback,GLHelper::ScalerQuality quality)700 void GLHelper::CropScaleReadbackAndCleanMailbox(
701 const gpu::Mailbox& src_mailbox,
702 uint32 sync_point,
703 const gfx::Size& src_size,
704 const gfx::Rect& src_subrect,
705 const gfx::Size& dst_size,
706 unsigned char* out,
707 const SkBitmap::Config bitmap_config,
708 const base::Callback<void(bool)>& callback,
709 GLHelper::ScalerQuality quality) {
710 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
711 CropScaleReadbackAndCleanTexture(
712 mailbox_texture, src_size, src_subrect, dst_size, out,
713 bitmap_config,
714 callback,
715 quality);
716 gl_->DeleteTextures(1, &mailbox_texture);
717 }
718
ReadbackTextureSync(GLuint texture,const gfx::Rect & src_rect,unsigned char * out,SkBitmap::Config format)719 void GLHelper::ReadbackTextureSync(GLuint texture,
720 const gfx::Rect& src_rect,
721 unsigned char* out,
722 SkBitmap::Config format) {
723 InitCopyTextToImpl();
724 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
725 }
726
ReadbackTextureAsync(GLuint texture,const gfx::Size & dst_size,unsigned char * out,SkBitmap::Config config,const base::Callback<void (bool)> & callback)727 void GLHelper::ReadbackTextureAsync(
728 GLuint texture,
729 const gfx::Size& dst_size,
730 unsigned char* out,
731 SkBitmap::Config config,
732 const base::Callback<void(bool)>& callback) {
733 InitCopyTextToImpl();
734 copy_texture_to_impl_->ReadbackTextureAsync(texture,
735 dst_size,
736 out,
737 config,
738 callback);
739 }
740
CopyTexture(GLuint texture,const gfx::Size & size)741 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
742 InitCopyTextToImpl();
743 return copy_texture_to_impl_->CopyAndScaleTexture(
744 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
745 }
746
CopyAndScaleTexture(GLuint texture,const gfx::Size & src_size,const gfx::Size & dst_size,bool vertically_flip_texture,ScalerQuality quality)747 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
748 const gfx::Size& src_size,
749 const gfx::Size& dst_size,
750 bool vertically_flip_texture,
751 ScalerQuality quality) {
752 InitCopyTextToImpl();
753 return copy_texture_to_impl_->CopyAndScaleTexture(
754 texture, src_size, dst_size, vertically_flip_texture, quality);
755 }
756
CompileShaderFromSource(const GLchar * source,GLenum type)757 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
758 GLuint shader = gl_->CreateShader(type);
759 GLint length = strlen(source);
760 gl_->ShaderSource(shader, 1, &source, &length);
761 gl_->CompileShader(shader);
762 GLint compile_status = 0;
763 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
764 if (!compile_status) {
765 GLint log_length = 0;
766 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
767 if (log_length) {
768 scoped_ptr<GLchar[]> log(new GLchar[log_length]);
769 GLsizei returned_log_length = 0;
770 gl_->GetShaderInfoLog(
771 shader, log_length, &returned_log_length, log.get());
772 LOG(ERROR) << std::string(log.get(), returned_log_length);
773 }
774 gl_->DeleteShader(shader);
775 return 0;
776 }
777 return shader;
778 }
779
InitCopyTextToImpl()780 void GLHelper::InitCopyTextToImpl() {
781 // Lazily initialize |copy_texture_to_impl_|
782 if (!copy_texture_to_impl_)
783 copy_texture_to_impl_.reset(
784 new CopyTextureToImpl(gl_, context_support_, this));
785 }
786
InitScalerImpl()787 void GLHelper::InitScalerImpl() {
788 // Lazily initialize |scaler_impl_|
789 if (!scaler_impl_)
790 scaler_impl_.reset(new GLHelperScaling(gl_, this));
791 }
792
MaxDrawBuffers()793 GLint GLHelper::MaxDrawBuffers() {
794 InitCopyTextToImpl();
795 return copy_texture_to_impl_->MaxDrawBuffers();
796 }
797
CopySubBufferDamage(GLuint texture,GLuint previous_texture,const SkRegion & new_damage,const SkRegion & old_damage)798 void GLHelper::CopySubBufferDamage(GLuint texture,
799 GLuint previous_texture,
800 const SkRegion& new_damage,
801 const SkRegion& old_damage) {
802 SkRegion region(old_damage);
803 if (region.op(new_damage, SkRegion::kDifference_Op)) {
804 ScopedFramebuffer dst_framebuffer(gl_);
805 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
806 dst_framebuffer);
807 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
808 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
809 GL_COLOR_ATTACHMENT0,
810 GL_TEXTURE_2D,
811 previous_texture,
812 0);
813 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
814 const SkIRect& rect = it.rect();
815 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
816 0,
817 rect.x(),
818 rect.y(),
819 rect.x(),
820 rect.y(),
821 rect.width(),
822 rect.height());
823 }
824 gl_->Flush();
825 }
826 }
827
CreateTexture()828 GLuint GLHelper::CreateTexture() {
829 GLuint texture = 0u;
830 gl_->GenTextures(1, &texture);
831 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
832 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
833 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
834 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
835 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
836 return texture;
837 }
838
DeleteTexture(GLuint texture_id)839 void GLHelper::DeleteTexture(GLuint texture_id) {
840 gl_->DeleteTextures(1, &texture_id);
841 }
842
InsertSyncPoint()843 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
844
WaitSyncPoint(uint32 sync_point)845 void GLHelper::WaitSyncPoint(uint32 sync_point) {
846 gl_->WaitSyncPointCHROMIUM(sync_point);
847 }
848
ProduceMailboxHolderFromTexture(GLuint texture_id)849 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
850 GLuint texture_id) {
851 gpu::Mailbox mailbox;
852 gl_->GenMailboxCHROMIUM(mailbox.name);
853 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture_id);
854 gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
855 return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
856 }
857
ConsumeMailboxToTexture(const gpu::Mailbox & mailbox,uint32 sync_point)858 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
859 uint32 sync_point) {
860 if (mailbox.IsZero())
861 return 0;
862 if (sync_point)
863 WaitSyncPoint(sync_point);
864 GLuint texture = CreateTexture();
865 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
866 gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
867 return texture;
868 }
869
ResizeTexture(GLuint texture,const gfx::Size & size)870 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
871 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
872 gl_->TexImage2D(GL_TEXTURE_2D,
873 0,
874 GL_RGB,
875 size.width(),
876 size.height(),
877 0,
878 GL_RGB,
879 GL_UNSIGNED_BYTE,
880 NULL);
881 }
882
CopyTextureSubImage(GLuint texture,const gfx::Rect & rect)883 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
884 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
885 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
886 0,
887 rect.x(),
888 rect.y(),
889 rect.x(),
890 rect.y(),
891 rect.width(),
892 rect.height());
893 }
894
CopyTextureFullImage(GLuint texture,const gfx::Size & size)895 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
896 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
897 gl_->CopyTexImage2D(
898 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
899 }
900
Flush()901 void GLHelper::Flush() {
902 gl_->Flush();
903 }
904
ReadbackPlane(TextureFrameBufferPair * source,const scoped_refptr<media::VideoFrame> & target,int plane,int size_shift,const gfx::Rect & dst_subrect,ReadbackSwizzle swizzle,const base::Callback<void (bool)> & callback)905 void GLHelper::CopyTextureToImpl::ReadbackPlane(
906 TextureFrameBufferPair* source,
907 const scoped_refptr<media::VideoFrame>& target,
908 int plane,
909 int size_shift,
910 const gfx::Rect& dst_subrect,
911 ReadbackSwizzle swizzle,
912 const base::Callback<void(bool)>& callback) {
913 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
914 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
915 (dst_subrect.x() >> size_shift);
916 ReadbackAsync(source->size(),
917 dst_subrect.width() >> size_shift,
918 target->stride(plane),
919 target->data(plane) + offset,
920 SkBitmap::kARGB_8888_Config,
921 swizzle,
922 callback);
923 }
924
925 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
926 0.257f, 0.504f, 0.098f, 0.0625f};
927 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
928 -0.148f, -0.291f, 0.439f, 0.5f};
929 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
930 0.439f, -0.368f, -0.071f, 0.5f};
931
932 // YUV readback constructors. Initiates the main scaler pipeline and
933 // one planar scaler for each of the Y, U and V planes.
ReadbackYUVImpl(GLES2Interface * gl,CopyTextureToImpl * copy_impl,GLHelperScaling * scaler_impl,GLHelper::ScalerQuality quality,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,const gfx::Rect & dst_subrect,bool flip_vertically,ReadbackSwizzle swizzle)934 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
935 GLES2Interface* gl,
936 CopyTextureToImpl* copy_impl,
937 GLHelperScaling* scaler_impl,
938 GLHelper::ScalerQuality quality,
939 const gfx::Size& src_size,
940 const gfx::Rect& src_subrect,
941 const gfx::Size& dst_size,
942 const gfx::Rect& dst_subrect,
943 bool flip_vertically,
944 ReadbackSwizzle swizzle)
945 : gl_(gl),
946 copy_impl_(copy_impl),
947 dst_size_(dst_size),
948 dst_subrect_(dst_subrect),
949 swizzle_(swizzle),
950 scaler_(gl,
951 scaler_impl->CreateScaler(quality,
952 src_size,
953 src_subrect,
954 dst_subrect.size(),
955 flip_vertically,
956 false)),
957 y_(gl,
958 scaler_impl->CreatePlanarScaler(
959 dst_subrect.size(),
960 gfx::Rect(0,
961 0,
962 (dst_subrect.width() + 3) & ~3,
963 dst_subrect.height()),
964 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
965 false,
966 (swizzle == kSwizzleBGRA),
967 kRGBtoYColorWeights)),
968 u_(gl,
969 scaler_impl->CreatePlanarScaler(
970 dst_subrect.size(),
971 gfx::Rect(0,
972 0,
973 (dst_subrect.width() + 7) & ~7,
974 (dst_subrect.height() + 1) & ~1),
975 gfx::Size((dst_subrect.width() + 7) / 8,
976 (dst_subrect.height() + 1) / 2),
977 false,
978 (swizzle == kSwizzleBGRA),
979 kRGBtoUColorWeights)),
980 v_(gl,
981 scaler_impl->CreatePlanarScaler(
982 dst_subrect.size(),
983 gfx::Rect(0,
984 0,
985 (dst_subrect.width() + 7) & ~7,
986 (dst_subrect.height() + 1) & ~1),
987 gfx::Size((dst_subrect.width() + 7) / 8,
988 (dst_subrect.height() + 1) / 2),
989 false,
990 (swizzle == kSwizzleBGRA),
991 kRGBtoVColorWeights)) {
992 DCHECK(!(dst_size.width() & 1));
993 DCHECK(!(dst_size.height() & 1));
994 DCHECK(!(dst_subrect.width() & 1));
995 DCHECK(!(dst_subrect.height() & 1));
996 DCHECK(!(dst_subrect.x() & 1));
997 DCHECK(!(dst_subrect.y() & 1));
998 }
999
CallbackKeepingVideoFrameAlive(scoped_refptr<media::VideoFrame> video_frame,const base::Callback<void (bool)> & callback,bool success)1000 static void CallbackKeepingVideoFrameAlive(
1001 scoped_refptr<media::VideoFrame> video_frame,
1002 const base::Callback<void(bool)>& callback,
1003 bool success) {
1004 callback.Run(success);
1005 }
1006
ReadbackYUV(const gpu::Mailbox & mailbox,uint32 sync_point,const scoped_refptr<media::VideoFrame> & target,const base::Callback<void (bool)> & callback)1007 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1008 const gpu::Mailbox& mailbox,
1009 uint32 sync_point,
1010 const scoped_refptr<media::VideoFrame>& target,
1011 const base::Callback<void(bool)>& callback) {
1012 GLuint mailbox_texture =
1013 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1014
1015 // Scale texture to right size.
1016 scaler_.Scale(mailbox_texture);
1017 gl_->DeleteTextures(1, &mailbox_texture);
1018
1019 // Convert the scaled texture in to Y, U and V planes.
1020 y_.Scale(scaler_.texture());
1021 u_.Scale(scaler_.texture());
1022 v_.Scale(scaler_.texture());
1023
1024 if (target->coded_size() != dst_size_) {
1025 DCHECK(target->coded_size() == dst_size_);
1026 LOG(ERROR) << "ReadbackYUV size error!";
1027 callback.Run(false);
1028 return;
1029 }
1030
1031 // Read back planes, one at a time. Keep the video frame alive while doing the
1032 // readback.
1033 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
1034 target,
1035 media::VideoFrame::kYPlane,
1036 0,
1037 dst_subrect_,
1038 swizzle_,
1039 base::Bind(&nullcallback));
1040 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
1041 target,
1042 media::VideoFrame::kUPlane,
1043 1,
1044 dst_subrect_,
1045 swizzle_,
1046 base::Bind(&nullcallback));
1047 copy_impl_->ReadbackPlane(
1048 v_.texture_and_framebuffer(),
1049 target,
1050 media::VideoFrame::kVPlane,
1051 1,
1052 dst_subrect_,
1053 swizzle_,
1054 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1055 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1056 media::LetterboxYUV(target, dst_subrect_);
1057 }
1058
1059 // YUV readback constructors. Initiates the main scaler pipeline and
1060 // one planar scaler for each of the Y, U and V planes.
ReadbackYUV_MRT(GLES2Interface * gl,CopyTextureToImpl * copy_impl,GLHelperScaling * scaler_impl,GLHelper::ScalerQuality quality,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,const gfx::Rect & dst_subrect,bool flip_vertically,ReadbackSwizzle swizzle)1061 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1062 GLES2Interface* gl,
1063 CopyTextureToImpl* copy_impl,
1064 GLHelperScaling* scaler_impl,
1065 GLHelper::ScalerQuality quality,
1066 const gfx::Size& src_size,
1067 const gfx::Rect& src_subrect,
1068 const gfx::Size& dst_size,
1069 const gfx::Rect& dst_subrect,
1070 bool flip_vertically,
1071 ReadbackSwizzle swizzle)
1072 : gl_(gl),
1073 copy_impl_(copy_impl),
1074 dst_size_(dst_size),
1075 dst_subrect_(dst_subrect),
1076 quality_(quality),
1077 swizzle_(swizzle),
1078 scaler_(gl,
1079 scaler_impl->CreateScaler(quality,
1080 src_size,
1081 src_subrect,
1082 dst_subrect.size(),
1083 false,
1084 false)),
1085 pass1_shader_(scaler_impl->CreateYuvMrtShader(
1086 dst_subrect.size(),
1087 gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
1088 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1089 flip_vertically,
1090 (swizzle == kSwizzleBGRA),
1091 GLHelperScaling::SHADER_YUV_MRT_PASS1)),
1092 pass2_shader_(scaler_impl->CreateYuvMrtShader(
1093 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1094 gfx::Rect(0,
1095 0,
1096 (dst_subrect.width() + 7) / 8 * 2,
1097 dst_subrect.height()),
1098 gfx::Size((dst_subrect.width() + 7) / 8,
1099 (dst_subrect.height() + 1) / 2),
1100 false,
1101 (swizzle == kSwizzleBGRA),
1102 GLHelperScaling::SHADER_YUV_MRT_PASS2)),
1103 y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
1104 uv_(gl),
1105 u_(gl,
1106 gfx::Size((dst_subrect.width() + 7) / 8,
1107 (dst_subrect.height() + 1) / 2)),
1108 v_(gl,
1109 gfx::Size((dst_subrect.width() + 7) / 8,
1110 (dst_subrect.height() + 1) / 2)) {
1111
1112 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
1113 gl->TexImage2D(GL_TEXTURE_2D,
1114 0,
1115 GL_RGBA,
1116 (dst_subrect.width() + 3) / 4,
1117 dst_subrect.height(),
1118 0,
1119 GL_RGBA,
1120 GL_UNSIGNED_BYTE,
1121 NULL);
1122
1123 DCHECK(!(dst_size.width() & 1));
1124 DCHECK(!(dst_size.height() & 1));
1125 DCHECK(!(dst_subrect.width() & 1));
1126 DCHECK(!(dst_subrect.height() & 1));
1127 DCHECK(!(dst_subrect.x() & 1));
1128 DCHECK(!(dst_subrect.y() & 1));
1129 }
1130
ReadbackYUV(const gpu::Mailbox & mailbox,uint32 sync_point,const scoped_refptr<media::VideoFrame> & target,const base::Callback<void (bool)> & callback)1131 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1132 const gpu::Mailbox& mailbox,
1133 uint32 sync_point,
1134 const scoped_refptr<media::VideoFrame>& target,
1135 const base::Callback<void(bool)>& callback) {
1136 GLuint mailbox_texture =
1137 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1138
1139 GLuint texture;
1140 if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
1141 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1142 // pass, which pass1_shader_ can do just as well, so let's skip
1143 // the actual scaling in that case.
1144 texture = mailbox_texture;
1145 } else {
1146 // Scale texture to right size.
1147 scaler_.Scale(mailbox_texture);
1148 texture = scaler_.texture();
1149 }
1150
1151 std::vector<GLuint> outputs(2);
1152 // Convert the scaled texture in to Y, U and V planes.
1153 outputs[0] = y_.texture();
1154 outputs[1] = uv_;
1155 pass1_shader_->Execute(texture, outputs);
1156
1157 gl_->DeleteTextures(1, &mailbox_texture);
1158
1159 outputs[0] = u_.texture();
1160 outputs[1] = v_.texture();
1161 pass2_shader_->Execute(uv_, outputs);
1162
1163 if (target->coded_size() != dst_size_) {
1164 DCHECK(target->coded_size() == dst_size_);
1165 LOG(ERROR) << "ReadbackYUV size error!";
1166 callback.Run(false);
1167 return;
1168 }
1169
1170 // Read back planes, one at a time.
1171 copy_impl_->ReadbackPlane(&y_,
1172 target,
1173 media::VideoFrame::kYPlane,
1174 0,
1175 dst_subrect_,
1176 swizzle_,
1177 base::Bind(&nullcallback));
1178 copy_impl_->ReadbackPlane(&u_,
1179 target,
1180 media::VideoFrame::kUPlane,
1181 1,
1182 dst_subrect_,
1183 swizzle_,
1184 base::Bind(&nullcallback));
1185 copy_impl_->ReadbackPlane(
1186 &v_,
1187 target,
1188 media::VideoFrame::kVPlane,
1189 1,
1190 dst_subrect_,
1191 swizzle_,
1192 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1193 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1194 media::LetterboxYUV(target, dst_subrect_);
1195 }
1196
IsReadbackConfigSupported(SkBitmap::Config texture_format)1197 bool GLHelper::IsReadbackConfigSupported(SkBitmap::Config texture_format) {
1198 DCHECK(readback_support_.get());
1199 return readback_support_.get()->IsReadbackConfigSupported(texture_format);
1200 }
1201
CreateReadbackPipelineYUV(GLHelper::ScalerQuality quality,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,const gfx::Rect & dst_subrect,bool flip_vertically,bool use_mrt)1202 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1203 GLHelper::ScalerQuality quality,
1204 const gfx::Size& src_size,
1205 const gfx::Rect& src_subrect,
1206 const gfx::Size& dst_size,
1207 const gfx::Rect& dst_subrect,
1208 bool flip_vertically,
1209 bool use_mrt) {
1210 helper_->InitScalerImpl();
1211 // Query preferred format for glReadPixels, if is is GL_BGRA then use that
1212 // and trigger the appropriate swizzle in the YUV shaders.
1213 GLint format = 0, type = 0;
1214 ReadbackSwizzle swizzle = kSwizzleNone;
1215 helper_->readback_support_.get()->GetAdditionalFormat(GL_RGBA,
1216 GL_UNSIGNED_BYTE,
1217 &format, &type);
1218 if (format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
1219 swizzle = kSwizzleBGRA;
1220 if (max_draw_buffers_ >= 2 && use_mrt) {
1221 return new ReadbackYUV_MRT(gl_,
1222 this,
1223 helper_->scaler_impl_.get(),
1224 quality,
1225 src_size,
1226 src_subrect,
1227 dst_size,
1228 dst_subrect,
1229 flip_vertically,
1230 swizzle);
1231 }
1232 return new ReadbackYUVImpl(gl_,
1233 this,
1234 helper_->scaler_impl_.get(),
1235 quality,
1236 src_size,
1237 src_subrect,
1238 dst_size,
1239 dst_subrect,
1240 flip_vertically,
1241 swizzle);
1242 }
1243
CreateReadbackPipelineYUV(ScalerQuality quality,const gfx::Size & src_size,const gfx::Rect & src_subrect,const gfx::Size & dst_size,const gfx::Rect & dst_subrect,bool flip_vertically,bool use_mrt)1244 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1245 ScalerQuality quality,
1246 const gfx::Size& src_size,
1247 const gfx::Rect& src_subrect,
1248 const gfx::Size& dst_size,
1249 const gfx::Rect& dst_subrect,
1250 bool flip_vertically,
1251 bool use_mrt) {
1252 InitCopyTextToImpl();
1253 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1254 src_size,
1255 src_subrect,
1256 dst_size,
1257 dst_subrect,
1258 flip_vertically,
1259 use_mrt);
1260 }
1261
1262 } // namespace content
1263