Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / common / gpu / client / gl_helper.cc
blobe7f81af973fd6a36163c56120afc73a6266eb254
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.
5 #include "content/common/gpu/client/gl_helper.h"
7 #include <queue>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/string_util.h"
16 #include "base/time/time.h"
17 #include "base/trace_event/trace_event.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/geometry/point.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/size.h"
31 using gpu::gles2::GLES2Interface;
33 namespace {
35 class ScopedFlush {
36 public:
37 explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
39 ~ScopedFlush() { gl_->Flush(); }
41 private:
42 gpu::gles2::GLES2Interface* gl_;
44 DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
47 // Helper class for allocating and holding an RGBA texture of a given
48 // size and an associated framebuffer.
49 class TextureFrameBufferPair {
50 public:
51 TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
52 : texture_(gl), framebuffer_(gl), size_(size) {
53 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
54 gl->TexImage2D(GL_TEXTURE_2D,
56 GL_RGBA,
57 size.width(),
58 size.height(),
60 GL_RGBA,
61 GL_UNSIGNED_BYTE,
62 NULL);
63 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
64 gl, framebuffer_);
65 gl->FramebufferTexture2D(
66 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
69 GLuint texture() const { return texture_.id(); }
70 GLuint framebuffer() const { return framebuffer_.id(); }
71 gfx::Size size() const { return size_; }
73 private:
74 content::ScopedTexture texture_;
75 content::ScopedFramebuffer framebuffer_;
76 gfx::Size size_;
78 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
81 // Helper class for holding a scaler, a texture for the output of that
82 // scaler and an associated frame buffer. This is inteded to be used
83 // when the output of a scaler is to be sent to a readback.
84 class ScalerHolder {
85 public:
86 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
87 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
89 void Scale(GLuint src_texture) {
90 scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
93 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
94 TextureFrameBufferPair* texture_and_framebuffer() {
95 return &texture_and_framebuffer_;
97 GLuint texture() const { return texture_and_framebuffer_.texture(); }
99 private:
100 TextureFrameBufferPair texture_and_framebuffer_;
101 scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
103 DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
106 } // namespace
108 namespace content {
109 typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
111 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
112 // the data needed for it.
113 class GLHelper::CopyTextureToImpl
114 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
115 public:
116 CopyTextureToImpl(GLES2Interface* gl,
117 gpu::ContextSupport* context_support,
118 GLHelper* helper)
119 : gl_(gl),
120 context_support_(context_support),
121 helper_(helper),
122 flush_(gl),
123 max_draw_buffers_(0) {
124 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
125 if (!extensions)
126 return;
127 std::string extensions_string =
128 " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
129 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
130 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
133 ~CopyTextureToImpl() { CancelRequests(); }
135 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
136 uint32 sync_point) {
137 return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
140 void CropScaleReadbackAndCleanTexture(
141 GLuint src_texture,
142 const gfx::Size& src_size,
143 const gfx::Rect& src_subrect,
144 const gfx::Size& dst_size,
145 unsigned char* out,
146 const SkColorType out_color_type,
147 const base::Callback<void(bool)>& callback,
148 GLHelper::ScalerQuality quality);
150 void ReadbackTextureSync(GLuint texture,
151 const gfx::Rect& src_rect,
152 unsigned char* out,
153 SkColorType format);
155 void ReadbackTextureAsync(GLuint texture,
156 const gfx::Size& dst_size,
157 unsigned char* out,
158 SkColorType color_type,
159 const base::Callback<void(bool)>& callback);
161 // Reads back bytes from the currently bound frame buffer.
162 // Note that dst_size is specified in bytes, not pixels.
163 void ReadbackAsync(const gfx::Size& dst_size,
164 int32 bytes_per_row, // generally dst_size.width() * 4
165 int32 row_stride_bytes, // generally dst_size.width() * 4
166 unsigned char* out,
167 GLenum format,
168 GLenum type,
169 size_t bytes_per_pixel,
170 const base::Callback<void(bool)>& callback);
172 void ReadbackPlane(TextureFrameBufferPair* source,
173 const scoped_refptr<media::VideoFrame>& target,
174 int plane,
175 int size_shift,
176 const gfx::Rect& paste_rect,
177 ReadbackSwizzle swizzle,
178 const base::Callback<void(bool)>& callback);
180 GLuint CopyAndScaleTexture(GLuint texture,
181 const gfx::Size& src_size,
182 const gfx::Size& dst_size,
183 bool vertically_flip_texture,
184 GLHelper::ScalerQuality quality);
186 ReadbackYUVInterface* CreateReadbackPipelineYUV(
187 GLHelper::ScalerQuality quality,
188 const gfx::Size& src_size,
189 const gfx::Rect& src_subrect,
190 const gfx::Size& dst_size,
191 bool flip_vertically,
192 bool use_mrt);
194 // Returns the maximum number of draw buffers available,
195 // 0 if GL_EXT_draw_buffers is not available.
196 GLint MaxDrawBuffers() const { return max_draw_buffers_; }
198 FormatSupport GetReadbackConfig(SkColorType color_type,
199 bool can_swizzle,
200 GLenum* format,
201 GLenum* type,
202 size_t* bytes_per_pixel);
204 private:
205 // A single request to CropScaleReadbackAndCleanTexture.
206 // The main thread can cancel the request, before it's handled by the helper
207 // thread, by resetting the texture and pixels fields. Alternatively, the
208 // thread marks that it handles the request by resetting the pixels field
209 // (meaning it guarantees that the callback with be called).
210 // In either case, the callback must be called exactly once, and the texture
211 // must be deleted by the main thread gl.
212 struct Request {
213 Request(const gfx::Size& size_,
214 int32 bytes_per_row_,
215 int32 row_stride_bytes_,
216 unsigned char* pixels_,
217 const base::Callback<void(bool)>& callback_)
218 : done(false),
219 size(size_),
220 bytes_per_row(bytes_per_row_),
221 row_stride_bytes(row_stride_bytes_),
222 pixels(pixels_),
223 callback(callback_),
224 buffer(0),
225 query(0) {}
227 bool done;
228 bool result;
229 gfx::Size size;
230 int bytes_per_row;
231 int row_stride_bytes;
232 unsigned char* pixels;
233 base::Callback<void(bool)> callback;
234 GLuint buffer;
235 GLuint query;
238 // We must take care to call the callbacks last, as they may
239 // end up destroying the gl_helper and make *this invalid.
240 // We stick the finished requests in a stack object that calls
241 // the callbacks when it goes out of scope.
242 class FinishRequestHelper {
243 public:
244 FinishRequestHelper() {}
245 ~FinishRequestHelper() {
246 while (!requests_.empty()) {
247 Request* request = requests_.front();
248 requests_.pop();
249 request->callback.Run(request->result);
250 delete request;
253 void Add(Request* r) {
254 requests_.push(r);
256 private:
257 std::queue<Request*> requests_;
258 DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper);
261 // A readback pipeline that also converts the data to YUV before
262 // reading it back.
263 class ReadbackYUVImpl : public ReadbackYUVInterface {
264 public:
265 ReadbackYUVImpl(GLES2Interface* gl,
266 CopyTextureToImpl* copy_impl,
267 GLHelperScaling* scaler_impl,
268 GLHelper::ScalerQuality quality,
269 const gfx::Size& src_size,
270 const gfx::Rect& src_subrect,
271 const gfx::Size& dst_size,
272 bool flip_vertically,
273 ReadbackSwizzle swizzle);
275 void ReadbackYUV(const gpu::Mailbox& mailbox,
276 uint32 sync_point,
277 const scoped_refptr<media::VideoFrame>& target,
278 const gfx::Point& paste_location,
279 const base::Callback<void(bool)>& callback) override;
281 ScalerInterface* scaler() override { return scaler_.scaler(); }
283 private:
284 GLES2Interface* gl_;
285 CopyTextureToImpl* copy_impl_;
286 gfx::Size dst_size_;
287 ReadbackSwizzle swizzle_;
288 ScalerHolder scaler_;
289 ScalerHolder y_;
290 ScalerHolder u_;
291 ScalerHolder v_;
293 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
296 // A readback pipeline that also converts the data to YUV before
297 // reading it back. This one uses Multiple Render Targets, which
298 // may not be supported on all platforms.
299 class ReadbackYUV_MRT : public ReadbackYUVInterface {
300 public:
301 ReadbackYUV_MRT(GLES2Interface* gl,
302 CopyTextureToImpl* copy_impl,
303 GLHelperScaling* scaler_impl,
304 GLHelper::ScalerQuality quality,
305 const gfx::Size& src_size,
306 const gfx::Rect& src_subrect,
307 const gfx::Size& dst_size,
308 bool flip_vertically,
309 ReadbackSwizzle swizzle);
311 void ReadbackYUV(const gpu::Mailbox& mailbox,
312 uint32 sync_point,
313 const scoped_refptr<media::VideoFrame>& target,
314 const gfx::Point& paste_location,
315 const base::Callback<void(bool)>& callback) override;
317 ScalerInterface* scaler() override { return scaler_.scaler(); }
319 private:
320 GLES2Interface* gl_;
321 CopyTextureToImpl* copy_impl_;
322 gfx::Size dst_size_;
323 GLHelper::ScalerQuality quality_;
324 ReadbackSwizzle swizzle_;
325 ScalerHolder scaler_;
326 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
327 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
328 TextureFrameBufferPair y_;
329 ScopedTexture uv_;
330 TextureFrameBufferPair u_;
331 TextureFrameBufferPair v_;
333 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
336 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
337 // scales it to |dst_size|, writes it into a texture, and returns its ID.
338 // |src_size| is the size of |src_texture|.
339 GLuint ScaleTexture(GLuint src_texture,
340 const gfx::Size& src_size,
341 const gfx::Rect& src_subrect,
342 const gfx::Size& dst_size,
343 bool vertically_flip_texture,
344 bool swizzle,
345 SkColorType color_type,
346 GLHelper::ScalerQuality quality);
348 // Converts each four consecutive pixels of the source texture into one pixel
349 // in the result texture with each pixel channel representing the grayscale
350 // color of one of the four original pixels:
351 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
352 // The resulting texture is still an RGBA texture (which is ~4 times narrower
353 // than the original). If rendered directly, it wouldn't show anything useful,
354 // but the data in it can be used to construct a grayscale image.
355 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
356 // is equal to src_size.width()/4 rounded upwards. Some channels in the last
357 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
358 // useful data.
359 // If swizzle is set to true, the transformed pixels are reordered:
360 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
361 GLuint EncodeTextureAsGrayscale(GLuint src_texture,
362 const gfx::Size& src_size,
363 gfx::Size* const encoded_texture_size,
364 bool vertically_flip_texture,
365 bool swizzle);
367 static void nullcallback(bool success) {}
368 void ReadbackDone(Request *request, int bytes_per_pixel);
369 void FinishRequest(Request* request,
370 bool result,
371 FinishRequestHelper* helper);
372 void CancelRequests();
374 static const float kRGBtoYColorWeights[];
375 static const float kRGBtoUColorWeights[];
376 static const float kRGBtoVColorWeights[];
377 static const float kRGBtoGrayscaleColorWeights[];
379 GLES2Interface* gl_;
380 gpu::ContextSupport* context_support_;
381 GLHelper* helper_;
383 // A scoped flush that will ensure all resource deletions are flushed when
384 // this object is destroyed. Must be declared before other Scoped* fields.
385 ScopedFlush flush_;
387 std::queue<Request*> request_queue_;
388 GLint max_draw_buffers_;
391 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
392 const gfx::Size& src_size,
393 const gfx::Rect& src_subrect,
394 const gfx::Size& dst_size,
395 bool vertically_flip_texture,
396 bool swizzle) {
397 InitScalerImpl();
398 return scaler_impl_->CreateScaler(quality,
399 src_size,
400 src_subrect,
401 dst_size,
402 vertically_flip_texture,
403 swizzle);
406 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
407 GLuint src_texture,
408 const gfx::Size& src_size,
409 const gfx::Rect& src_subrect,
410 const gfx::Size& dst_size,
411 bool vertically_flip_texture,
412 bool swizzle,
413 SkColorType color_type,
414 GLHelper::ScalerQuality quality) {
415 GLuint dst_texture = 0u;
416 gl_->GenTextures(1, &dst_texture);
418 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
419 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
421 // Use GL_RGBA for destination/temporary texture unless we're working with
422 // 16-bit data
423 if (color_type == kRGB_565_SkColorType) {
424 format = GL_RGB;
425 type = GL_UNSIGNED_SHORT_5_6_5;
428 gl_->TexImage2D(GL_TEXTURE_2D,
430 format,
431 dst_size.width(),
432 dst_size.height(),
434 format,
435 type,
436 NULL);
438 scoped_ptr<ScalerInterface> scaler(
439 helper_->CreateScaler(quality,
440 src_size,
441 src_subrect,
442 dst_size,
443 vertically_flip_texture,
444 swizzle));
445 scaler->Scale(src_texture, dst_texture);
446 return dst_texture;
449 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
450 GLuint src_texture,
451 const gfx::Size& src_size,
452 gfx::Size* const encoded_texture_size,
453 bool vertically_flip_texture,
454 bool swizzle) {
455 GLuint dst_texture = 0u;
456 gl_->GenTextures(1, &dst_texture);
457 // The size of the encoded texture.
458 *encoded_texture_size =
459 gfx::Size((src_size.width() + 3) / 4, src_size.height());
461 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
462 gl_->TexImage2D(GL_TEXTURE_2D,
464 GL_RGBA,
465 encoded_texture_size->width(),
466 encoded_texture_size->height(),
468 GL_RGBA,
469 GL_UNSIGNED_BYTE,
470 NULL);
473 helper_->InitScalerImpl();
474 scoped_ptr<ScalerInterface> grayscale_scaler(
475 helper_->scaler_impl_.get()->CreatePlanarScaler(
476 src_size,
477 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()),
478 *encoded_texture_size,
479 vertically_flip_texture,
480 swizzle,
481 kRGBtoGrayscaleColorWeights));
482 grayscale_scaler->Scale(src_texture, dst_texture);
483 return dst_texture;
486 void GLHelper::CopyTextureToImpl::ReadbackAsync(
487 const gfx::Size& dst_size,
488 int32 bytes_per_row,
489 int32 row_stride_bytes,
490 unsigned char* out,
491 GLenum format,
492 GLenum type,
493 size_t bytes_per_pixel,
494 const base::Callback<void(bool)>& callback) {
495 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync");
496 Request* request =
497 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
498 request_queue_.push(request);
499 request->buffer = 0u;
501 gl_->GenBuffers(1, &request->buffer);
502 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
503 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
504 bytes_per_pixel * dst_size.GetArea(),
505 NULL,
506 GL_STREAM_READ);
508 request->query = 0u;
509 gl_->GenQueriesEXT(1, &request->query);
510 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
511 gl_->ReadPixels(0,
513 dst_size.width(),
514 dst_size.height(),
515 format,
516 type,
517 NULL);
518 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
519 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
520 context_support_->SignalQuery(
521 request->query,
522 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
523 request, bytes_per_pixel));
526 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
527 GLuint src_texture,
528 const gfx::Size& src_size,
529 const gfx::Rect& src_subrect,
530 const gfx::Size& dst_size,
531 unsigned char* out,
532 const SkColorType out_color_type,
533 const base::Callback<void(bool)>& callback,
534 GLHelper::ScalerQuality quality) {
535 GLenum format, type;
536 size_t bytes_per_pixel;
537 SkColorType readback_color_type = out_color_type;
538 // Single-component textures are not supported by all GPUs, so we implement
539 // kAlpha_8_SkColorType support here via a special encoding (see below) using
540 // a 32-bit texture to represent an 8-bit image.
541 // Thus we use generic 32-bit readback in this case.
542 if (out_color_type == kAlpha_8_SkColorType) {
543 readback_color_type = kRGBA_8888_SkColorType;
546 FormatSupport supported = GetReadbackConfig(
547 readback_color_type, true, &format, &type, &bytes_per_pixel);
549 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
550 callback.Run(false);
551 return;
554 GLuint texture = src_texture;
556 // Scale texture if needed
557 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
558 // can do just as well in EncodeTextureAsGrayscale, which we will do if
559 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
560 // in that case.
561 bool scale_texture = out_color_type != kAlpha_8_SkColorType ||
562 quality != GLHelper::SCALER_QUALITY_FAST;
563 if (scale_texture) {
564 // Don't swizzle during the scale step for kAlpha_8_SkColorType.
565 // We will swizzle in the encode step below if needed.
566 bool scale_swizzle = out_color_type == kAlpha_8_SkColorType
567 ? false
568 : supported == GLHelperReadbackSupport::SWIZZLE;
569 texture =
570 ScaleTexture(src_texture,
571 src_size,
572 src_subrect,
573 dst_size,
574 true,
575 scale_swizzle,
576 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType
577 : out_color_type,
578 quality);
579 DCHECK(texture);
582 gfx::Size readback_texture_size = dst_size;
583 // Encode texture to grayscale if needed.
584 if (out_color_type == kAlpha_8_SkColorType) {
585 // Do the vertical flip here if we haven't already done it when we scaled
586 // the texture.
587 bool encode_as_grayscale_vertical_flip = !scale_texture;
588 // EncodeTextureAsGrayscale by default creates a texture which should be
589 // read back as RGBA, so need to swizzle if the readback format is BGRA.
590 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT;
591 GLuint tmp_texture =
592 EncodeTextureAsGrayscale(texture,
593 dst_size,
594 &readback_texture_size,
595 encode_as_grayscale_vertical_flip,
596 encode_as_grayscale_swizzle);
597 // If the scaled texture was created - delete it
598 if (scale_texture)
599 gl_->DeleteTextures(1, &texture);
600 texture = tmp_texture;
601 DCHECK(texture);
604 // Readback the pixels of the resulting texture
605 ScopedFramebuffer dst_framebuffer(gl_);
606 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
607 dst_framebuffer);
608 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
609 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
610 GL_COLOR_ATTACHMENT0,
611 GL_TEXTURE_2D,
612 texture,
615 int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType
616 ? dst_size.width()
617 : dst_size.width() * bytes_per_pixel;
619 ReadbackAsync(readback_texture_size,
620 bytes_per_row,
621 bytes_per_row,
622 out,
623 format,
624 type,
625 bytes_per_pixel,
626 callback);
627 gl_->DeleteTextures(1, &texture);
630 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
631 GLuint texture,
632 const gfx::Rect& src_rect,
633 unsigned char* out,
634 SkColorType color_type) {
635 GLenum format, type;
636 size_t bytes_per_pixel;
637 FormatSupport supported =
638 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
639 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
640 return;
643 ScopedFramebuffer dst_framebuffer(gl_);
644 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
645 dst_framebuffer);
646 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
647 gl_->FramebufferTexture2D(
648 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
649 gl_->ReadPixels(src_rect.x(),
650 src_rect.y(),
651 src_rect.width(),
652 src_rect.height(),
653 format,
654 type,
655 out);
658 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
659 GLuint texture,
660 const gfx::Size& dst_size,
661 unsigned char* out,
662 SkColorType color_type,
663 const base::Callback<void(bool)>& callback) {
664 GLenum format, type;
665 size_t bytes_per_pixel;
666 FormatSupport supported =
667 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
668 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
669 callback.Run(false);
670 return;
673 ScopedFramebuffer dst_framebuffer(gl_);
674 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
675 dst_framebuffer);
676 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
677 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
678 GL_COLOR_ATTACHMENT0,
679 GL_TEXTURE_2D,
680 texture,
682 ReadbackAsync(dst_size,
683 dst_size.width() * bytes_per_pixel,
684 dst_size.width() * bytes_per_pixel,
685 out,
686 format,
687 type,
688 bytes_per_pixel,
689 callback);
692 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
693 GLuint src_texture,
694 const gfx::Size& src_size,
695 const gfx::Size& dst_size,
696 bool vertically_flip_texture,
697 GLHelper::ScalerQuality quality) {
698 return ScaleTexture(src_texture,
699 src_size,
700 gfx::Rect(src_size),
701 dst_size,
702 vertically_flip_texture,
703 false,
704 kRGBA_8888_SkColorType, // GL_RGBA
705 quality);
708 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
709 int bytes_per_pixel) {
710 TRACE_EVENT0("gpu.capture",
711 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
712 finished_request->done = true;
714 FinishRequestHelper finish_request_helper;
716 // We process transfer requests in the order they were received, regardless
717 // of the order we get the callbacks in.
718 while (!request_queue_.empty()) {
719 Request* request = request_queue_.front();
720 if (!request->done) {
721 break;
724 bool result = false;
725 if (request->buffer != 0) {
726 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
727 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
728 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
729 if (data) {
730 result = true;
731 if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
732 request->bytes_per_row == request->row_stride_bytes) {
733 memcpy(request->pixels, data,
734 request->size.GetArea() * bytes_per_pixel);
735 } else {
736 unsigned char* out = request->pixels;
737 for (int y = 0; y < request->size.height(); y++) {
738 memcpy(out, data, request->bytes_per_row);
739 out += request->row_stride_bytes;
740 data += request->size.width() * bytes_per_pixel;
743 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
745 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
747 FinishRequest(request, result, &finish_request_helper);
751 void GLHelper::CopyTextureToImpl::FinishRequest(
752 Request* request,
753 bool result,
754 FinishRequestHelper* finish_request_helper) {
755 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest");
756 DCHECK(request_queue_.front() == request);
757 request_queue_.pop();
758 request->result = result;
759 ScopedFlush flush(gl_);
760 if (request->query != 0) {
761 gl_->DeleteQueriesEXT(1, &request->query);
762 request->query = 0;
764 if (request->buffer != 0) {
765 gl_->DeleteBuffers(1, &request->buffer);
766 request->buffer = 0;
768 finish_request_helper->Add(request);
771 void GLHelper::CopyTextureToImpl::CancelRequests() {
772 FinishRequestHelper finish_request_helper;
773 while (!request_queue_.empty()) {
774 Request* request = request_queue_.front();
775 FinishRequest(request, false, &finish_request_helper);
779 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
780 SkColorType color_type,
781 bool can_swizzle,
782 GLenum* format,
783 GLenum* type,
784 size_t* bytes_per_pixel) {
785 return helper_->readback_support_->GetReadbackConfig(
786 color_type, can_swizzle, format, type, bytes_per_pixel);
789 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
790 : gl_(gl),
791 context_support_(context_support),
792 readback_support_(new GLHelperReadbackSupport(gl)) {}
794 GLHelper::~GLHelper() {}
796 void GLHelper::CropScaleReadbackAndCleanTexture(
797 GLuint src_texture,
798 const gfx::Size& src_size,
799 const gfx::Rect& src_subrect,
800 const gfx::Size& dst_size,
801 unsigned char* out,
802 const SkColorType out_color_type,
803 const base::Callback<void(bool)>& callback,
804 GLHelper::ScalerQuality quality) {
805 InitCopyTextToImpl();
806 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture,
807 src_size,
808 src_subrect,
809 dst_size,
810 out,
811 out_color_type,
812 callback,
813 quality);
816 void GLHelper::CropScaleReadbackAndCleanMailbox(
817 const gpu::Mailbox& src_mailbox,
818 uint32 sync_point,
819 const gfx::Size& src_size,
820 const gfx::Rect& src_subrect,
821 const gfx::Size& dst_size,
822 unsigned char* out,
823 const SkColorType out_color_type,
824 const base::Callback<void(bool)>& callback,
825 GLHelper::ScalerQuality quality) {
826 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
827 CropScaleReadbackAndCleanTexture(mailbox_texture,
828 src_size,
829 src_subrect,
830 dst_size,
831 out,
832 out_color_type,
833 callback,
834 quality);
835 gl_->DeleteTextures(1, &mailbox_texture);
838 void GLHelper::ReadbackTextureSync(GLuint texture,
839 const gfx::Rect& src_rect,
840 unsigned char* out,
841 SkColorType format) {
842 InitCopyTextToImpl();
843 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
846 void GLHelper::ReadbackTextureAsync(
847 GLuint texture,
848 const gfx::Size& dst_size,
849 unsigned char* out,
850 SkColorType color_type,
851 const base::Callback<void(bool)>& callback) {
852 InitCopyTextToImpl();
853 copy_texture_to_impl_->ReadbackTextureAsync(texture,
854 dst_size,
855 out,
856 color_type,
857 callback);
860 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
861 InitCopyTextToImpl();
862 return copy_texture_to_impl_->CopyAndScaleTexture(
863 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
866 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
867 const gfx::Size& src_size,
868 const gfx::Size& dst_size,
869 bool vertically_flip_texture,
870 ScalerQuality quality) {
871 InitCopyTextToImpl();
872 return copy_texture_to_impl_->CopyAndScaleTexture(
873 texture, src_size, dst_size, vertically_flip_texture, quality);
876 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
877 GLuint shader = gl_->CreateShader(type);
878 GLint length = strlen(source);
879 gl_->ShaderSource(shader, 1, &source, &length);
880 gl_->CompileShader(shader);
881 GLint compile_status = 0;
882 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
883 if (!compile_status) {
884 GLint log_length = 0;
885 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
886 if (log_length) {
887 scoped_ptr<GLchar[]> log(new GLchar[log_length]);
888 GLsizei returned_log_length = 0;
889 gl_->GetShaderInfoLog(
890 shader, log_length, &returned_log_length, log.get());
891 LOG(ERROR) << std::string(log.get(), returned_log_length);
893 gl_->DeleteShader(shader);
894 return 0;
896 return shader;
899 void GLHelper::InitCopyTextToImpl() {
900 // Lazily initialize |copy_texture_to_impl_|
901 if (!copy_texture_to_impl_)
902 copy_texture_to_impl_.reset(
903 new CopyTextureToImpl(gl_, context_support_, this));
906 void GLHelper::InitScalerImpl() {
907 // Lazily initialize |scaler_impl_|
908 if (!scaler_impl_)
909 scaler_impl_.reset(new GLHelperScaling(gl_, this));
912 GLint GLHelper::MaxDrawBuffers() {
913 InitCopyTextToImpl();
914 return copy_texture_to_impl_->MaxDrawBuffers();
917 void GLHelper::CopySubBufferDamage(GLenum target,
918 GLuint texture,
919 GLuint previous_texture,
920 const SkRegion& new_damage,
921 const SkRegion& old_damage) {
922 SkRegion region(old_damage);
923 if (region.op(new_damage, SkRegion::kDifference_Op)) {
924 ScopedFramebuffer dst_framebuffer(gl_);
925 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
926 dst_framebuffer);
927 gl_->BindTexture(target, texture);
928 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target,
929 previous_texture, 0);
930 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
931 const SkIRect& rect = it.rect();
932 gl_->CopyTexSubImage2D(target, 0, rect.x(), rect.y(), rect.x(), rect.y(),
933 rect.width(), rect.height());
935 gl_->BindTexture(target, 0);
936 gl_->Flush();
940 GLuint GLHelper::CreateTexture() {
941 GLuint texture = 0u;
942 gl_->GenTextures(1, &texture);
943 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
944 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
945 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
946 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
947 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
948 return texture;
951 void GLHelper::DeleteTexture(GLuint texture_id) {
952 gl_->DeleteTextures(1, &texture_id);
955 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
957 void GLHelper::WaitSyncPoint(uint32 sync_point) {
958 gl_->WaitSyncPointCHROMIUM(sync_point);
961 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
962 GLuint texture_id) {
963 gpu::Mailbox mailbox;
964 gl_->GenMailboxCHROMIUM(mailbox.name);
965 gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
966 return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
969 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
970 uint32 sync_point) {
971 if (mailbox.IsZero())
972 return 0;
973 if (sync_point)
974 WaitSyncPoint(sync_point);
975 GLuint texture =
976 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
977 return texture;
980 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
981 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
982 gl_->TexImage2D(GL_TEXTURE_2D,
984 GL_RGB,
985 size.width(),
986 size.height(),
988 GL_RGB,
989 GL_UNSIGNED_BYTE,
990 NULL);
993 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
994 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
995 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
997 rect.x(),
998 rect.y(),
999 rect.x(),
1000 rect.y(),
1001 rect.width(),
1002 rect.height());
1005 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
1006 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
1007 gl_->CopyTexImage2D(
1008 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
1011 void GLHelper::Flush() {
1012 gl_->Flush();
1015 void GLHelper::InsertOrderingBarrier() {
1016 gl_->OrderingBarrierCHROMIUM();
1019 void GLHelper::CopyTextureToImpl::ReadbackPlane(
1020 TextureFrameBufferPair* source,
1021 const scoped_refptr<media::VideoFrame>& target,
1022 int plane,
1023 int size_shift,
1024 const gfx::Rect& paste_rect,
1025 ReadbackSwizzle swizzle,
1026 const base::Callback<void(bool)>& callback) {
1027 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
1028 const size_t offset = target->stride(plane) * (paste_rect.y() >> size_shift) +
1029 (paste_rect.x() >> size_shift);
1030 ReadbackAsync(source->size(),
1031 paste_rect.width() >> size_shift,
1032 target->stride(plane),
1033 target->data(plane) + offset,
1034 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
1035 GL_UNSIGNED_BYTE,
1037 callback);
1040 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
1041 0.257f, 0.504f, 0.098f, 0.0625f};
1042 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
1043 -0.148f, -0.291f, 0.439f, 0.5f};
1044 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
1045 0.439f, -0.368f, -0.071f, 0.5f};
1046 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = {
1047 0.213f, 0.715f, 0.072f, 0.0f};
1049 // YUV readback constructors. Initiates the main scaler pipeline and
1050 // one planar scaler for each of the Y, U and V planes.
1051 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
1052 GLES2Interface* gl,
1053 CopyTextureToImpl* copy_impl,
1054 GLHelperScaling* scaler_impl,
1055 GLHelper::ScalerQuality quality,
1056 const gfx::Size& src_size,
1057 const gfx::Rect& src_subrect,
1058 const gfx::Size& dst_size,
1059 bool flip_vertically,
1060 ReadbackSwizzle swizzle)
1061 : gl_(gl),
1062 copy_impl_(copy_impl),
1063 dst_size_(dst_size),
1064 swizzle_(swizzle),
1065 scaler_(gl,
1066 scaler_impl->CreateScaler(quality,
1067 src_size,
1068 src_subrect,
1069 dst_size,
1070 flip_vertically,
1071 false)),
1072 y_(gl,
1073 scaler_impl->CreatePlanarScaler(
1074 dst_size,
1075 gfx::Rect(0,
1077 (dst_size.width() + 3) & ~3,
1078 dst_size.height()),
1079 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
1080 false,
1081 (swizzle == kSwizzleBGRA),
1082 kRGBtoYColorWeights)),
1083 u_(gl,
1084 scaler_impl->CreatePlanarScaler(
1085 dst_size,
1086 gfx::Rect(0,
1088 (dst_size.width() + 7) & ~7,
1089 (dst_size.height() + 1) & ~1),
1090 gfx::Size((dst_size.width() + 7) / 8,
1091 (dst_size.height() + 1) / 2),
1092 false,
1093 (swizzle == kSwizzleBGRA),
1094 kRGBtoUColorWeights)),
1095 v_(gl,
1096 scaler_impl->CreatePlanarScaler(
1097 dst_size,
1098 gfx::Rect(0,
1100 (dst_size.width() + 7) & ~7,
1101 (dst_size.height() + 1) & ~1),
1102 gfx::Size((dst_size.width() + 7) / 8,
1103 (dst_size.height() + 1) / 2),
1104 false,
1105 (swizzle == kSwizzleBGRA),
1106 kRGBtoVColorWeights)) {
1107 DCHECK(!(dst_size.width() & 1));
1108 DCHECK(!(dst_size.height() & 1));
1111 static void CallbackKeepingVideoFrameAlive(
1112 scoped_refptr<media::VideoFrame> video_frame,
1113 const base::Callback<void(bool)>& callback,
1114 bool success) {
1115 callback.Run(success);
1118 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1119 const gpu::Mailbox& mailbox,
1120 uint32 sync_point,
1121 const scoped_refptr<media::VideoFrame>& target,
1122 const gfx::Point& paste_location,
1123 const base::Callback<void(bool)>& callback) {
1124 DCHECK(!(paste_location.x() & 1));
1125 DCHECK(!(paste_location.y() & 1));
1127 GLuint mailbox_texture =
1128 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1130 // Scale texture to right size.
1131 scaler_.Scale(mailbox_texture);
1132 gl_->DeleteTextures(1, &mailbox_texture);
1134 // Convert the scaled texture in to Y, U and V planes.
1135 y_.Scale(scaler_.texture());
1136 u_.Scale(scaler_.texture());
1137 v_.Scale(scaler_.texture());
1139 const gfx::Rect paste_rect(paste_location, dst_size_);
1140 if (!target->visible_rect().Contains(paste_rect)) {
1141 LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
1142 callback.Run(false);
1143 return;
1146 // Read back planes, one at a time. Keep the video frame alive while doing the
1147 // readback.
1148 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
1149 target,
1150 media::VideoFrame::kYPlane,
1152 paste_rect,
1153 swizzle_,
1154 base::Bind(&nullcallback));
1155 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
1156 target,
1157 media::VideoFrame::kUPlane,
1159 paste_rect,
1160 swizzle_,
1161 base::Bind(&nullcallback));
1162 copy_impl_->ReadbackPlane(
1163 v_.texture_and_framebuffer(),
1164 target,
1165 media::VideoFrame::kVPlane,
1167 paste_rect,
1168 swizzle_,
1169 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1170 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1171 media::LetterboxYUV(target.get(), paste_rect);
1174 // YUV readback constructors. Initiates the main scaler pipeline and
1175 // one planar scaler for each of the Y, U and V planes.
1176 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1177 GLES2Interface* gl,
1178 CopyTextureToImpl* copy_impl,
1179 GLHelperScaling* scaler_impl,
1180 GLHelper::ScalerQuality quality,
1181 const gfx::Size& src_size,
1182 const gfx::Rect& src_subrect,
1183 const gfx::Size& dst_size,
1184 bool flip_vertically,
1185 ReadbackSwizzle swizzle)
1186 : gl_(gl),
1187 copy_impl_(copy_impl),
1188 dst_size_(dst_size),
1189 quality_(quality),
1190 swizzle_(swizzle),
1191 scaler_(gl,
1192 scaler_impl->CreateScaler(quality,
1193 src_size,
1194 src_subrect,
1195 dst_size,
1196 false,
1197 false)),
1198 pass1_shader_(scaler_impl->CreateYuvMrtShader(
1199 dst_size,
1200 gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()),
1201 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
1202 flip_vertically,
1203 (swizzle == kSwizzleBGRA),
1204 GLHelperScaling::SHADER_YUV_MRT_PASS1)),
1205 pass2_shader_(scaler_impl->CreateYuvMrtShader(
1206 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
1207 gfx::Rect(0,
1209 (dst_size.width() + 7) / 8 * 2,
1210 dst_size.height()),
1211 gfx::Size((dst_size.width() + 7) / 8,
1212 (dst_size.height() + 1) / 2),
1213 false,
1214 (swizzle == kSwizzleBGRA),
1215 GLHelperScaling::SHADER_YUV_MRT_PASS2)),
1216 y_(gl, gfx::Size((dst_size.width() + 3) / 4, dst_size.height())),
1217 uv_(gl),
1218 u_(gl,
1219 gfx::Size((dst_size.width() + 7) / 8,
1220 (dst_size.height() + 1) / 2)),
1221 v_(gl,
1222 gfx::Size((dst_size.width() + 7) / 8,
1223 (dst_size.height() + 1) / 2)) {
1224 DCHECK(!(dst_size.width() & 1));
1225 DCHECK(!(dst_size.height() & 1));
1227 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
1228 gl->TexImage2D(GL_TEXTURE_2D,
1230 GL_RGBA,
1231 (dst_size.width() + 3) / 4,
1232 dst_size.height(),
1234 GL_RGBA,
1235 GL_UNSIGNED_BYTE,
1236 NULL);
1239 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1240 const gpu::Mailbox& mailbox,
1241 uint32 sync_point,
1242 const scoped_refptr<media::VideoFrame>& target,
1243 const gfx::Point& paste_location,
1244 const base::Callback<void(bool)>& callback) {
1245 DCHECK(!(paste_location.x() & 1));
1246 DCHECK(!(paste_location.y() & 1));
1248 GLuint mailbox_texture =
1249 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1251 GLuint texture;
1252 if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
1253 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1254 // pass, which pass1_shader_ can do just as well, so let's skip
1255 // the actual scaling in that case.
1256 texture = mailbox_texture;
1257 } else {
1258 // Scale texture to right size.
1259 scaler_.Scale(mailbox_texture);
1260 texture = scaler_.texture();
1263 std::vector<GLuint> outputs(2);
1264 // Convert the scaled texture in to Y, U and V planes.
1265 outputs[0] = y_.texture();
1266 outputs[1] = uv_;
1267 pass1_shader_->Execute(texture, outputs);
1269 gl_->DeleteTextures(1, &mailbox_texture);
1271 outputs[0] = u_.texture();
1272 outputs[1] = v_.texture();
1273 pass2_shader_->Execute(uv_, outputs);
1275 const gfx::Rect paste_rect(paste_location, dst_size_);
1276 if (!target->visible_rect().Contains(paste_rect)) {
1277 LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
1278 callback.Run(false);
1279 return;
1282 // Read back planes, one at a time.
1283 copy_impl_->ReadbackPlane(&y_,
1284 target,
1285 media::VideoFrame::kYPlane,
1287 paste_rect,
1288 swizzle_,
1289 base::Bind(&nullcallback));
1290 copy_impl_->ReadbackPlane(&u_,
1291 target,
1292 media::VideoFrame::kUPlane,
1294 paste_rect,
1295 swizzle_,
1296 base::Bind(&nullcallback));
1297 copy_impl_->ReadbackPlane(
1298 &v_,
1299 target,
1300 media::VideoFrame::kVPlane,
1302 paste_rect,
1303 swizzle_,
1304 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1305 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1306 media::LetterboxYUV(target.get(), paste_rect);
1309 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
1310 DCHECK(readback_support_.get());
1311 GLenum format, type;
1312 size_t bytes_per_pixel;
1313 FormatSupport support = readback_support_->GetReadbackConfig(
1314 color_type, false, &format, &type, &bytes_per_pixel);
1316 return (support == GLHelperReadbackSupport::SUPPORTED);
1319 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1320 GLHelper::ScalerQuality quality,
1321 const gfx::Size& src_size,
1322 const gfx::Rect& src_subrect,
1323 const gfx::Size& dst_size,
1324 bool flip_vertically,
1325 bool use_mrt) {
1326 helper_->InitScalerImpl();
1327 // Just query if the best readback configuration needs a swizzle In
1328 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
1329 GLenum format, type;
1330 size_t bytes_per_pixel;
1331 FormatSupport supported = GetReadbackConfig(
1332 kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel);
1333 DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
1334 type == GL_UNSIGNED_BYTE);
1336 ReadbackSwizzle swizzle = kSwizzleNone;
1337 if (supported == GLHelperReadbackSupport::SWIZZLE)
1338 swizzle = kSwizzleBGRA;
1340 if (max_draw_buffers_ >= 2 && use_mrt) {
1341 return new ReadbackYUV_MRT(gl_,
1342 this,
1343 helper_->scaler_impl_.get(),
1344 quality,
1345 src_size,
1346 src_subrect,
1347 dst_size,
1348 flip_vertically,
1349 swizzle);
1351 return new ReadbackYUVImpl(gl_,
1352 this,
1353 helper_->scaler_impl_.get(),
1354 quality,
1355 src_size,
1356 src_subrect,
1357 dst_size,
1358 flip_vertically,
1359 swizzle);
1362 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1363 ScalerQuality quality,
1364 const gfx::Size& src_size,
1365 const gfx::Rect& src_subrect,
1366 const gfx::Size& dst_size,
1367 bool flip_vertically,
1368 bool use_mrt) {
1369 InitCopyTextToImpl();
1370 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1371 src_size,
1372 src_subrect,
1373 dst_size,
1374 flip_vertically,
1375 use_mrt);
1378 } // namespace content