Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / common / gpu / client / gl_helper.cc
blob0ba9193c8742eea0999b0de5e5433d424d911963
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/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"
30 using gpu::gles2::GLES2Interface;
32 namespace {
34 class ScopedFlush {
35 public:
36 explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
38 ~ScopedFlush() { gl_->Flush(); }
40 private:
41 gpu::gles2::GLES2Interface* gl_;
43 DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
46 // Helper class for allocating and holding an RGBA texture of a given
47 // size and an associated framebuffer.
48 class TextureFrameBufferPair {
49 public:
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,
55 GL_RGBA,
56 size.width(),
57 size.height(),
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);
68 GLuint texture() const { return texture_.id(); }
69 GLuint framebuffer() const { return framebuffer_.id(); }
70 gfx::Size size() const { return size_; }
72 private:
73 content::ScopedTexture texture_;
74 content::ScopedFramebuffer framebuffer_;
75 gfx::Size size_;
77 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
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:
85 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
86 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
88 void Scale(GLuint src_texture) {
89 scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
92 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
93 TextureFrameBufferPair* texture_and_framebuffer() {
94 return &texture_and_framebuffer_;
96 GLuint texture() const { return texture_and_framebuffer_.texture(); }
98 private:
99 TextureFrameBufferPair texture_and_framebuffer_;
100 scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
102 DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
105 } // namespace
107 namespace content {
108 typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
110 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
111 // the data needed for it.
112 class GLHelper::CopyTextureToImpl
113 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
114 public:
115 CopyTextureToImpl(GLES2Interface* gl,
116 gpu::ContextSupport* context_support,
117 GLHelper* helper)
118 : gl_(gl),
119 context_support_(context_support),
120 helper_(helper),
121 flush_(gl),
122 max_draw_buffers_(0) {
123 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
124 if (!extensions)
125 return;
126 std::string extensions_string =
127 " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
128 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
129 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
132 ~CopyTextureToImpl() { CancelRequests(); }
134 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
135 uint32 sync_point) {
136 return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
139 void CropScaleReadbackAndCleanTexture(
140 GLuint src_texture,
141 const gfx::Size& src_size,
142 const gfx::Rect& src_subrect,
143 const gfx::Size& dst_size,
144 unsigned char* out,
145 const SkColorType out_color_type,
146 const base::Callback<void(bool)>& callback,
147 GLHelper::ScalerQuality quality);
149 void ReadbackTextureSync(GLuint texture,
150 const gfx::Rect& src_rect,
151 unsigned char* out,
152 SkColorType format);
154 void ReadbackTextureAsync(GLuint texture,
155 const gfx::Size& dst_size,
156 unsigned char* out,
157 SkColorType color_type,
158 const base::Callback<void(bool)>& callback);
160 // Reads back bytes from the currently bound frame buffer.
161 // Note that dst_size is specified in bytes, not pixels.
162 void ReadbackAsync(const gfx::Size& dst_size,
163 int32 bytes_per_row, // generally dst_size.width() * 4
164 int32 row_stride_bytes, // generally dst_size.width() * 4
165 unsigned char* out,
166 GLenum format,
167 GLenum type,
168 size_t bytes_per_pixel,
169 const base::Callback<void(bool)>& callback);
171 void ReadbackPlane(TextureFrameBufferPair* source,
172 const scoped_refptr<media::VideoFrame>& target,
173 int plane,
174 int size_shift,
175 const gfx::Rect& dst_subrect,
176 ReadbackSwizzle swizzle,
177 const base::Callback<void(bool)>& callback);
179 GLuint CopyAndScaleTexture(GLuint texture,
180 const gfx::Size& src_size,
181 const gfx::Size& dst_size,
182 bool vertically_flip_texture,
183 GLHelper::ScalerQuality quality);
185 ReadbackYUVInterface* CreateReadbackPipelineYUV(
186 GLHelper::ScalerQuality quality,
187 const gfx::Size& src_size,
188 const gfx::Rect& src_subrect,
189 const gfx::Size& dst_size,
190 const gfx::Rect& dst_subrect,
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 gfx::Size size;
229 int bytes_per_row;
230 int row_stride_bytes;
231 unsigned char* pixels;
232 base::Callback<void(bool)> callback;
233 GLuint buffer;
234 GLuint query;
237 // A readback pipeline that also converts the data to YUV before
238 // reading it back.
239 class ReadbackYUVImpl : public ReadbackYUVInterface {
240 public:
241 ReadbackYUVImpl(GLES2Interface* gl,
242 CopyTextureToImpl* copy_impl,
243 GLHelperScaling* scaler_impl,
244 GLHelper::ScalerQuality quality,
245 const gfx::Size& src_size,
246 const gfx::Rect& src_subrect,
247 const gfx::Size& dst_size,
248 const gfx::Rect& dst_subrect,
249 bool flip_vertically,
250 ReadbackSwizzle swizzle);
252 void ReadbackYUV(const gpu::Mailbox& mailbox,
253 uint32 sync_point,
254 const scoped_refptr<media::VideoFrame>& target,
255 const base::Callback<void(bool)>& callback) override;
257 ScalerInterface* scaler() override { return scaler_.scaler(); }
259 private:
260 GLES2Interface* gl_;
261 CopyTextureToImpl* copy_impl_;
262 gfx::Size dst_size_;
263 gfx::Rect dst_subrect_;
264 ReadbackSwizzle swizzle_;
265 ScalerHolder scaler_;
266 ScalerHolder y_;
267 ScalerHolder u_;
268 ScalerHolder v_;
270 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
273 // A readback pipeline that also converts the data to YUV before
274 // reading it back. This one uses Multiple Render Targets, which
275 // may not be supported on all platforms.
276 class ReadbackYUV_MRT : public ReadbackYUVInterface {
277 public:
278 ReadbackYUV_MRT(GLES2Interface* gl,
279 CopyTextureToImpl* copy_impl,
280 GLHelperScaling* scaler_impl,
281 GLHelper::ScalerQuality quality,
282 const gfx::Size& src_size,
283 const gfx::Rect& src_subrect,
284 const gfx::Size& dst_size,
285 const gfx::Rect& dst_subrect,
286 bool flip_vertically,
287 ReadbackSwizzle swizzle);
289 void ReadbackYUV(const gpu::Mailbox& mailbox,
290 uint32 sync_point,
291 const scoped_refptr<media::VideoFrame>& target,
292 const base::Callback<void(bool)>& callback) override;
294 ScalerInterface* scaler() override { return scaler_.scaler(); }
296 private:
297 GLES2Interface* gl_;
298 CopyTextureToImpl* copy_impl_;
299 gfx::Size dst_size_;
300 gfx::Rect dst_subrect_;
301 GLHelper::ScalerQuality quality_;
302 ReadbackSwizzle swizzle_;
303 ScalerHolder scaler_;
304 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
305 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
306 TextureFrameBufferPair y_;
307 ScopedTexture uv_;
308 TextureFrameBufferPair u_;
309 TextureFrameBufferPair v_;
311 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
314 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
315 // scales it to |dst_size|, writes it into a texture, and returns its ID.
316 // |src_size| is the size of |src_texture|.
317 GLuint ScaleTexture(GLuint src_texture,
318 const gfx::Size& src_size,
319 const gfx::Rect& src_subrect,
320 const gfx::Size& dst_size,
321 bool vertically_flip_texture,
322 bool swizzle,
323 SkColorType color_type,
324 GLHelper::ScalerQuality quality);
326 // Converts each four consecutive pixels of the source texture into one pixel
327 // in the result texture with each pixel channel representing the grayscale
328 // color of one of the four original pixels:
329 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
330 // The resulting texture is still an RGBA texture (which is ~4 times narrower
331 // than the original). If rendered directly, it wouldn't show anything useful,
332 // but the data in it can be used to construct a grayscale image.
333 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
334 // is equal to src_size.width()/4 rounded upwards. Some channels in the last
335 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
336 // useful data.
337 // If swizzle is set to true, the transformed pixels are reordered:
338 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
339 GLuint EncodeTextureAsGrayscale(GLuint src_texture,
340 const gfx::Size& src_size,
341 gfx::Size* const encoded_texture_size,
342 bool vertically_flip_texture,
343 bool swizzle);
345 static void nullcallback(bool success) {}
346 void ReadbackDone(Request *request, int bytes_per_pixel);
347 void FinishRequest(Request* request, bool result);
348 void CancelRequests();
350 static const float kRGBtoYColorWeights[];
351 static const float kRGBtoUColorWeights[];
352 static const float kRGBtoVColorWeights[];
353 static const float kRGBtoGrayscaleColorWeights[];
355 GLES2Interface* gl_;
356 gpu::ContextSupport* context_support_;
357 GLHelper* helper_;
359 // A scoped flush that will ensure all resource deletions are flushed when
360 // this object is destroyed. Must be declared before other Scoped* fields.
361 ScopedFlush flush_;
363 std::queue<Request*> request_queue_;
364 GLint max_draw_buffers_;
367 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
368 const gfx::Size& src_size,
369 const gfx::Rect& src_subrect,
370 const gfx::Size& dst_size,
371 bool vertically_flip_texture,
372 bool swizzle) {
373 InitScalerImpl();
374 return scaler_impl_->CreateScaler(quality,
375 src_size,
376 src_subrect,
377 dst_size,
378 vertically_flip_texture,
379 swizzle);
382 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
383 GLuint src_texture,
384 const gfx::Size& src_size,
385 const gfx::Rect& src_subrect,
386 const gfx::Size& dst_size,
387 bool vertically_flip_texture,
388 bool swizzle,
389 SkColorType color_type,
390 GLHelper::ScalerQuality quality) {
391 GLuint dst_texture = 0u;
392 gl_->GenTextures(1, &dst_texture);
394 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
395 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
397 // Use GL_RGBA for destination/temporary texture unless we're working with
398 // 16-bit data
399 if (color_type == kRGB_565_SkColorType) {
400 format = GL_RGB;
401 type = GL_UNSIGNED_SHORT_5_6_5;
404 gl_->TexImage2D(GL_TEXTURE_2D,
406 format,
407 dst_size.width(),
408 dst_size.height(),
410 format,
411 type,
412 NULL);
414 scoped_ptr<ScalerInterface> scaler(
415 helper_->CreateScaler(quality,
416 src_size,
417 src_subrect,
418 dst_size,
419 vertically_flip_texture,
420 swizzle));
421 scaler->Scale(src_texture, dst_texture);
422 return dst_texture;
425 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
426 GLuint src_texture,
427 const gfx::Size& src_size,
428 gfx::Size* const encoded_texture_size,
429 bool vertically_flip_texture,
430 bool swizzle) {
431 GLuint dst_texture = 0u;
432 gl_->GenTextures(1, &dst_texture);
433 // The size of the encoded texture.
434 *encoded_texture_size =
435 gfx::Size((src_size.width() + 3) / 4, src_size.height());
437 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
438 gl_->TexImage2D(GL_TEXTURE_2D,
440 GL_RGBA,
441 encoded_texture_size->width(),
442 encoded_texture_size->height(),
444 GL_RGBA,
445 GL_UNSIGNED_BYTE,
446 NULL);
449 helper_->InitScalerImpl();
450 scoped_ptr<ScalerInterface> grayscale_scaler(
451 helper_->scaler_impl_.get()->CreatePlanarScaler(
452 src_size,
453 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()),
454 *encoded_texture_size,
455 vertically_flip_texture,
456 swizzle,
457 kRGBtoGrayscaleColorWeights));
458 grayscale_scaler->Scale(src_texture, dst_texture);
459 return dst_texture;
462 void GLHelper::CopyTextureToImpl::ReadbackAsync(
463 const gfx::Size& dst_size,
464 int32 bytes_per_row,
465 int32 row_stride_bytes,
466 unsigned char* out,
467 GLenum format,
468 GLenum type,
469 size_t bytes_per_pixel,
470 const base::Callback<void(bool)>& callback) {
471 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
472 Request* request =
473 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
474 request_queue_.push(request);
475 request->buffer = 0u;
477 gl_->GenBuffers(1, &request->buffer);
478 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
479 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
480 bytes_per_pixel * dst_size.GetArea(),
481 NULL,
482 GL_STREAM_READ);
484 request->query = 0u;
485 gl_->GenQueriesEXT(1, &request->query);
486 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
487 gl_->ReadPixels(0,
489 dst_size.width(),
490 dst_size.height(),
491 format,
492 type,
493 NULL);
494 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
495 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
496 context_support_->SignalQuery(
497 request->query,
498 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
499 request, bytes_per_pixel));
502 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
503 GLuint src_texture,
504 const gfx::Size& src_size,
505 const gfx::Rect& src_subrect,
506 const gfx::Size& dst_size,
507 unsigned char* out,
508 const SkColorType out_color_type,
509 const base::Callback<void(bool)>& callback,
510 GLHelper::ScalerQuality quality) {
511 GLenum format, type;
512 size_t bytes_per_pixel;
513 SkColorType readback_color_type = out_color_type;
514 // Single-component textures are not supported by all GPUs, so we implement
515 // kAlpha_8_SkColorType support here via a special encoding (see below) using
516 // a 32-bit texture to represent an 8-bit image.
517 // Thus we use generic 32-bit readback in this case.
518 if (out_color_type == kAlpha_8_SkColorType) {
519 readback_color_type = kRGBA_8888_SkColorType;
522 FormatSupport supported = GetReadbackConfig(
523 readback_color_type, true, &format, &type, &bytes_per_pixel);
525 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
526 callback.Run(false);
527 return;
530 GLuint texture = src_texture;
532 // Scale texture if needed
533 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
534 // can do just as well in EncodeTextureAsGrayscale, which we will do if
535 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
536 // in that case.
537 bool scale_texture = out_color_type != kAlpha_8_SkColorType ||
538 quality != GLHelper::SCALER_QUALITY_FAST;
539 if (scale_texture) {
540 // Don't swizzle during the scale step for kAlpha_8_SkColorType.
541 // We will swizzle in the encode step below if needed.
542 bool scale_swizzle = out_color_type == kAlpha_8_SkColorType
543 ? false
544 : supported == GLHelperReadbackSupport::SWIZZLE;
545 texture =
546 ScaleTexture(src_texture,
547 src_size,
548 src_subrect,
549 dst_size,
550 true,
551 scale_swizzle,
552 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType
553 : out_color_type,
554 quality);
555 DCHECK(texture);
558 gfx::Size readback_texture_size = dst_size;
559 // Encode texture to grayscale if needed.
560 if (out_color_type == kAlpha_8_SkColorType) {
561 // Do the vertical flip here if we haven't already done it when we scaled
562 // the texture.
563 bool encode_as_grayscale_vertical_flip = !scale_texture;
564 // EncodeTextureAsGrayscale by default creates a texture which should be
565 // read back as RGBA, so need to swizzle if the readback format is BGRA.
566 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT;
567 GLuint tmp_texture =
568 EncodeTextureAsGrayscale(texture,
569 dst_size,
570 &readback_texture_size,
571 encode_as_grayscale_vertical_flip,
572 encode_as_grayscale_swizzle);
573 // If the scaled texture was created - delete it
574 if (scale_texture)
575 gl_->DeleteTextures(1, &texture);
576 texture = tmp_texture;
577 DCHECK(texture);
580 // Readback the pixels of the resulting texture
581 ScopedFramebuffer dst_framebuffer(gl_);
582 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
583 dst_framebuffer);
584 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
585 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
586 GL_COLOR_ATTACHMENT0,
587 GL_TEXTURE_2D,
588 texture,
591 int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType
592 ? dst_size.width()
593 : dst_size.width() * bytes_per_pixel;
595 ReadbackAsync(readback_texture_size,
596 bytes_per_row,
597 bytes_per_row,
598 out,
599 format,
600 type,
601 bytes_per_pixel,
602 callback);
603 gl_->DeleteTextures(1, &texture);
606 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
607 GLuint texture,
608 const gfx::Rect& src_rect,
609 unsigned char* out,
610 SkColorType color_type) {
611 GLenum format, type;
612 size_t bytes_per_pixel;
613 FormatSupport supported =
614 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
615 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
616 return;
619 ScopedFramebuffer dst_framebuffer(gl_);
620 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
621 dst_framebuffer);
622 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
623 gl_->FramebufferTexture2D(
624 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
625 gl_->ReadPixels(src_rect.x(),
626 src_rect.y(),
627 src_rect.width(),
628 src_rect.height(),
629 format,
630 type,
631 out);
634 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
635 GLuint texture,
636 const gfx::Size& dst_size,
637 unsigned char* out,
638 SkColorType color_type,
639 const base::Callback<void(bool)>& callback) {
640 GLenum format, type;
641 size_t bytes_per_pixel;
642 FormatSupport supported =
643 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
644 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
645 callback.Run(false);
646 return;
649 ScopedFramebuffer dst_framebuffer(gl_);
650 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
651 dst_framebuffer);
652 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
653 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
654 GL_COLOR_ATTACHMENT0,
655 GL_TEXTURE_2D,
656 texture,
658 ReadbackAsync(dst_size,
659 dst_size.width() * bytes_per_pixel,
660 dst_size.width() * bytes_per_pixel,
661 out,
662 format,
663 type,
664 bytes_per_pixel,
665 callback);
668 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
669 GLuint src_texture,
670 const gfx::Size& src_size,
671 const gfx::Size& dst_size,
672 bool vertically_flip_texture,
673 GLHelper::ScalerQuality quality) {
674 return ScaleTexture(src_texture,
675 src_size,
676 gfx::Rect(src_size),
677 dst_size,
678 vertically_flip_texture,
679 false,
680 kRGBA_8888_SkColorType, // GL_RGBA
681 quality);
684 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
685 int bytes_per_pixel) {
686 TRACE_EVENT0("mirror",
687 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
688 finished_request->done = true;
690 // We process transfer requests in the order they were received, regardless
691 // of the order we get the callbacks in.
692 while (!request_queue_.empty()) {
693 Request* request = request_queue_.front();
694 if (!request->done) {
695 break;
698 bool result = false;
699 if (request->buffer != 0) {
700 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
701 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
702 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
703 if (data) {
704 result = true;
705 if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
706 request->bytes_per_row == request->row_stride_bytes) {
707 memcpy(request->pixels, data,
708 request->size.GetArea() * bytes_per_pixel);
709 } else {
710 unsigned char* out = request->pixels;
711 for (int y = 0; y < request->size.height(); y++) {
712 memcpy(out, data, request->bytes_per_row);
713 out += request->row_stride_bytes;
714 data += request->size.width() * bytes_per_pixel;
717 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
719 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
721 FinishRequest(request, result);
725 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
726 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
727 DCHECK(request_queue_.front() == request);
728 request_queue_.pop();
729 request->callback.Run(result);
730 ScopedFlush flush(gl_);
731 if (request->query != 0) {
732 gl_->DeleteQueriesEXT(1, &request->query);
733 request->query = 0;
735 if (request->buffer != 0) {
736 gl_->DeleteBuffers(1, &request->buffer);
737 request->buffer = 0;
739 delete request;
742 void GLHelper::CopyTextureToImpl::CancelRequests() {
743 while (!request_queue_.empty()) {
744 Request* request = request_queue_.front();
745 FinishRequest(request, false);
749 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
750 SkColorType color_type,
751 bool can_swizzle,
752 GLenum* format,
753 GLenum* type,
754 size_t* bytes_per_pixel) {
755 return helper_->readback_support_->GetReadbackConfig(
756 color_type, can_swizzle, format, type, bytes_per_pixel);
759 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
760 : gl_(gl),
761 context_support_(context_support),
762 readback_support_(new GLHelperReadbackSupport(gl)) {}
764 GLHelper::~GLHelper() {}
766 void GLHelper::CropScaleReadbackAndCleanTexture(
767 GLuint src_texture,
768 const gfx::Size& src_size,
769 const gfx::Rect& src_subrect,
770 const gfx::Size& dst_size,
771 unsigned char* out,
772 const SkColorType out_color_type,
773 const base::Callback<void(bool)>& callback,
774 GLHelper::ScalerQuality quality) {
775 InitCopyTextToImpl();
776 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture,
777 src_size,
778 src_subrect,
779 dst_size,
780 out,
781 out_color_type,
782 callback,
783 quality);
786 void GLHelper::CropScaleReadbackAndCleanMailbox(
787 const gpu::Mailbox& src_mailbox,
788 uint32 sync_point,
789 const gfx::Size& src_size,
790 const gfx::Rect& src_subrect,
791 const gfx::Size& dst_size,
792 unsigned char* out,
793 const SkColorType out_color_type,
794 const base::Callback<void(bool)>& callback,
795 GLHelper::ScalerQuality quality) {
796 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
797 CropScaleReadbackAndCleanTexture(mailbox_texture,
798 src_size,
799 src_subrect,
800 dst_size,
801 out,
802 out_color_type,
803 callback,
804 quality);
805 gl_->DeleteTextures(1, &mailbox_texture);
808 void GLHelper::ReadbackTextureSync(GLuint texture,
809 const gfx::Rect& src_rect,
810 unsigned char* out,
811 SkColorType format) {
812 InitCopyTextToImpl();
813 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
816 void GLHelper::ReadbackTextureAsync(
817 GLuint texture,
818 const gfx::Size& dst_size,
819 unsigned char* out,
820 SkColorType color_type,
821 const base::Callback<void(bool)>& callback) {
822 InitCopyTextToImpl();
823 copy_texture_to_impl_->ReadbackTextureAsync(texture,
824 dst_size,
825 out,
826 color_type,
827 callback);
830 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
831 InitCopyTextToImpl();
832 return copy_texture_to_impl_->CopyAndScaleTexture(
833 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
836 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
837 const gfx::Size& src_size,
838 const gfx::Size& dst_size,
839 bool vertically_flip_texture,
840 ScalerQuality quality) {
841 InitCopyTextToImpl();
842 return copy_texture_to_impl_->CopyAndScaleTexture(
843 texture, src_size, dst_size, vertically_flip_texture, quality);
846 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
847 GLuint shader = gl_->CreateShader(type);
848 GLint length = strlen(source);
849 gl_->ShaderSource(shader, 1, &source, &length);
850 gl_->CompileShader(shader);
851 GLint compile_status = 0;
852 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
853 if (!compile_status) {
854 GLint log_length = 0;
855 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
856 if (log_length) {
857 scoped_ptr<GLchar[]> log(new GLchar[log_length]);
858 GLsizei returned_log_length = 0;
859 gl_->GetShaderInfoLog(
860 shader, log_length, &returned_log_length, log.get());
861 LOG(ERROR) << std::string(log.get(), returned_log_length);
863 gl_->DeleteShader(shader);
864 return 0;
866 return shader;
869 void GLHelper::InitCopyTextToImpl() {
870 // Lazily initialize |copy_texture_to_impl_|
871 if (!copy_texture_to_impl_)
872 copy_texture_to_impl_.reset(
873 new CopyTextureToImpl(gl_, context_support_, this));
876 void GLHelper::InitScalerImpl() {
877 // Lazily initialize |scaler_impl_|
878 if (!scaler_impl_)
879 scaler_impl_.reset(new GLHelperScaling(gl_, this));
882 GLint GLHelper::MaxDrawBuffers() {
883 InitCopyTextToImpl();
884 return copy_texture_to_impl_->MaxDrawBuffers();
887 void GLHelper::CopySubBufferDamage(GLuint texture,
888 GLuint previous_texture,
889 const SkRegion& new_damage,
890 const SkRegion& old_damage) {
891 SkRegion region(old_damage);
892 if (region.op(new_damage, SkRegion::kDifference_Op)) {
893 ScopedFramebuffer dst_framebuffer(gl_);
894 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
895 dst_framebuffer);
896 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
897 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
898 GL_COLOR_ATTACHMENT0,
899 GL_TEXTURE_2D,
900 previous_texture,
902 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
903 const SkIRect& rect = it.rect();
904 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
906 rect.x(),
907 rect.y(),
908 rect.x(),
909 rect.y(),
910 rect.width(),
911 rect.height());
913 gl_->Flush();
917 GLuint GLHelper::CreateTexture() {
918 GLuint texture = 0u;
919 gl_->GenTextures(1, &texture);
920 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
921 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
922 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
923 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
924 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
925 return texture;
928 void GLHelper::DeleteTexture(GLuint texture_id) {
929 gl_->DeleteTextures(1, &texture_id);
932 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
934 void GLHelper::WaitSyncPoint(uint32 sync_point) {
935 gl_->WaitSyncPointCHROMIUM(sync_point);
938 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
939 GLuint texture_id) {
940 gpu::Mailbox mailbox;
941 gl_->GenMailboxCHROMIUM(mailbox.name);
942 gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
943 return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
946 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
947 uint32 sync_point) {
948 if (mailbox.IsZero())
949 return 0;
950 if (sync_point)
951 WaitSyncPoint(sync_point);
952 GLuint texture =
953 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
954 return texture;
957 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
958 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
959 gl_->TexImage2D(GL_TEXTURE_2D,
961 GL_RGB,
962 size.width(),
963 size.height(),
965 GL_RGB,
966 GL_UNSIGNED_BYTE,
967 NULL);
970 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
971 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
972 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
974 rect.x(),
975 rect.y(),
976 rect.x(),
977 rect.y(),
978 rect.width(),
979 rect.height());
982 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
983 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
984 gl_->CopyTexImage2D(
985 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
988 void GLHelper::Flush() {
989 gl_->Flush();
992 void GLHelper::CopyTextureToImpl::ReadbackPlane(
993 TextureFrameBufferPair* source,
994 const scoped_refptr<media::VideoFrame>& target,
995 int plane,
996 int size_shift,
997 const gfx::Rect& dst_subrect,
998 ReadbackSwizzle swizzle,
999 const base::Callback<void(bool)>& callback) {
1000 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
1001 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
1002 (dst_subrect.x() >> size_shift);
1003 ReadbackAsync(source->size(),
1004 dst_subrect.width() >> size_shift,
1005 target->stride(plane),
1006 target->data(plane) + offset,
1007 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
1008 GL_UNSIGNED_BYTE,
1010 callback);
1013 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
1014 0.257f, 0.504f, 0.098f, 0.0625f};
1015 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
1016 -0.148f, -0.291f, 0.439f, 0.5f};
1017 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
1018 0.439f, -0.368f, -0.071f, 0.5f};
1019 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = {
1020 0.213f, 0.715f, 0.072f, 0.0f};
1022 // YUV readback constructors. Initiates the main scaler pipeline and
1023 // one planar scaler for each of the Y, U and V planes.
1024 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
1025 GLES2Interface* gl,
1026 CopyTextureToImpl* copy_impl,
1027 GLHelperScaling* scaler_impl,
1028 GLHelper::ScalerQuality quality,
1029 const gfx::Size& src_size,
1030 const gfx::Rect& src_subrect,
1031 const gfx::Size& dst_size,
1032 const gfx::Rect& dst_subrect,
1033 bool flip_vertically,
1034 ReadbackSwizzle swizzle)
1035 : gl_(gl),
1036 copy_impl_(copy_impl),
1037 dst_size_(dst_size),
1038 dst_subrect_(dst_subrect),
1039 swizzle_(swizzle),
1040 scaler_(gl,
1041 scaler_impl->CreateScaler(quality,
1042 src_size,
1043 src_subrect,
1044 dst_subrect.size(),
1045 flip_vertically,
1046 false)),
1047 y_(gl,
1048 scaler_impl->CreatePlanarScaler(
1049 dst_subrect.size(),
1050 gfx::Rect(0,
1052 (dst_subrect.width() + 3) & ~3,
1053 dst_subrect.height()),
1054 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1055 false,
1056 (swizzle == kSwizzleBGRA),
1057 kRGBtoYColorWeights)),
1058 u_(gl,
1059 scaler_impl->CreatePlanarScaler(
1060 dst_subrect.size(),
1061 gfx::Rect(0,
1063 (dst_subrect.width() + 7) & ~7,
1064 (dst_subrect.height() + 1) & ~1),
1065 gfx::Size((dst_subrect.width() + 7) / 8,
1066 (dst_subrect.height() + 1) / 2),
1067 false,
1068 (swizzle == kSwizzleBGRA),
1069 kRGBtoUColorWeights)),
1070 v_(gl,
1071 scaler_impl->CreatePlanarScaler(
1072 dst_subrect.size(),
1073 gfx::Rect(0,
1075 (dst_subrect.width() + 7) & ~7,
1076 (dst_subrect.height() + 1) & ~1),
1077 gfx::Size((dst_subrect.width() + 7) / 8,
1078 (dst_subrect.height() + 1) / 2),
1079 false,
1080 (swizzle == kSwizzleBGRA),
1081 kRGBtoVColorWeights)) {
1082 DCHECK(!(dst_size.width() & 1));
1083 DCHECK(!(dst_size.height() & 1));
1084 DCHECK(!(dst_subrect.width() & 1));
1085 DCHECK(!(dst_subrect.height() & 1));
1086 DCHECK(!(dst_subrect.x() & 1));
1087 DCHECK(!(dst_subrect.y() & 1));
1090 static void CallbackKeepingVideoFrameAlive(
1091 scoped_refptr<media::VideoFrame> video_frame,
1092 const base::Callback<void(bool)>& callback,
1093 bool success) {
1094 callback.Run(success);
1097 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1098 const gpu::Mailbox& mailbox,
1099 uint32 sync_point,
1100 const scoped_refptr<media::VideoFrame>& target,
1101 const base::Callback<void(bool)>& callback) {
1102 GLuint mailbox_texture =
1103 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1105 // Scale texture to right size.
1106 scaler_.Scale(mailbox_texture);
1107 gl_->DeleteTextures(1, &mailbox_texture);
1109 // Convert the scaled texture in to Y, U and V planes.
1110 y_.Scale(scaler_.texture());
1111 u_.Scale(scaler_.texture());
1112 v_.Scale(scaler_.texture());
1114 if (target->coded_size() != dst_size_) {
1115 DCHECK(target->coded_size() == dst_size_);
1116 LOG(ERROR) << "ReadbackYUV size error!";
1117 callback.Run(false);
1118 return;
1121 // Read back planes, one at a time. Keep the video frame alive while doing the
1122 // readback.
1123 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
1124 target,
1125 media::VideoFrame::kYPlane,
1127 dst_subrect_,
1128 swizzle_,
1129 base::Bind(&nullcallback));
1130 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
1131 target,
1132 media::VideoFrame::kUPlane,
1134 dst_subrect_,
1135 swizzle_,
1136 base::Bind(&nullcallback));
1137 copy_impl_->ReadbackPlane(
1138 v_.texture_and_framebuffer(),
1139 target,
1140 media::VideoFrame::kVPlane,
1142 dst_subrect_,
1143 swizzle_,
1144 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1145 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1146 media::LetterboxYUV(target.get(), dst_subrect_);
1149 // YUV readback constructors. Initiates the main scaler pipeline and
1150 // one planar scaler for each of the Y, U and V planes.
1151 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1152 GLES2Interface* gl,
1153 CopyTextureToImpl* copy_impl,
1154 GLHelperScaling* scaler_impl,
1155 GLHelper::ScalerQuality quality,
1156 const gfx::Size& src_size,
1157 const gfx::Rect& src_subrect,
1158 const gfx::Size& dst_size,
1159 const gfx::Rect& dst_subrect,
1160 bool flip_vertically,
1161 ReadbackSwizzle swizzle)
1162 : gl_(gl),
1163 copy_impl_(copy_impl),
1164 dst_size_(dst_size),
1165 dst_subrect_(dst_subrect),
1166 quality_(quality),
1167 swizzle_(swizzle),
1168 scaler_(gl,
1169 scaler_impl->CreateScaler(quality,
1170 src_size,
1171 src_subrect,
1172 dst_subrect.size(),
1173 false,
1174 false)),
1175 pass1_shader_(scaler_impl->CreateYuvMrtShader(
1176 dst_subrect.size(),
1177 gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
1178 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1179 flip_vertically,
1180 (swizzle == kSwizzleBGRA),
1181 GLHelperScaling::SHADER_YUV_MRT_PASS1)),
1182 pass2_shader_(scaler_impl->CreateYuvMrtShader(
1183 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1184 gfx::Rect(0,
1186 (dst_subrect.width() + 7) / 8 * 2,
1187 dst_subrect.height()),
1188 gfx::Size((dst_subrect.width() + 7) / 8,
1189 (dst_subrect.height() + 1) / 2),
1190 false,
1191 (swizzle == kSwizzleBGRA),
1192 GLHelperScaling::SHADER_YUV_MRT_PASS2)),
1193 y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
1194 uv_(gl),
1195 u_(gl,
1196 gfx::Size((dst_subrect.width() + 7) / 8,
1197 (dst_subrect.height() + 1) / 2)),
1198 v_(gl,
1199 gfx::Size((dst_subrect.width() + 7) / 8,
1200 (dst_subrect.height() + 1) / 2)) {
1202 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
1203 gl->TexImage2D(GL_TEXTURE_2D,
1205 GL_RGBA,
1206 (dst_subrect.width() + 3) / 4,
1207 dst_subrect.height(),
1209 GL_RGBA,
1210 GL_UNSIGNED_BYTE,
1211 NULL);
1213 DCHECK(!(dst_size.width() & 1));
1214 DCHECK(!(dst_size.height() & 1));
1215 DCHECK(!(dst_subrect.width() & 1));
1216 DCHECK(!(dst_subrect.height() & 1));
1217 DCHECK(!(dst_subrect.x() & 1));
1218 DCHECK(!(dst_subrect.y() & 1));
1221 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1222 const gpu::Mailbox& mailbox,
1223 uint32 sync_point,
1224 const scoped_refptr<media::VideoFrame>& target,
1225 const base::Callback<void(bool)>& callback) {
1226 GLuint mailbox_texture =
1227 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1229 GLuint texture;
1230 if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
1231 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1232 // pass, which pass1_shader_ can do just as well, so let's skip
1233 // the actual scaling in that case.
1234 texture = mailbox_texture;
1235 } else {
1236 // Scale texture to right size.
1237 scaler_.Scale(mailbox_texture);
1238 texture = scaler_.texture();
1241 std::vector<GLuint> outputs(2);
1242 // Convert the scaled texture in to Y, U and V planes.
1243 outputs[0] = y_.texture();
1244 outputs[1] = uv_;
1245 pass1_shader_->Execute(texture, outputs);
1247 gl_->DeleteTextures(1, &mailbox_texture);
1249 outputs[0] = u_.texture();
1250 outputs[1] = v_.texture();
1251 pass2_shader_->Execute(uv_, outputs);
1253 if (target->coded_size() != dst_size_) {
1254 DCHECK(target->coded_size() == dst_size_);
1255 LOG(ERROR) << "ReadbackYUV size error!";
1256 callback.Run(false);
1257 return;
1260 // Read back planes, one at a time.
1261 copy_impl_->ReadbackPlane(&y_,
1262 target,
1263 media::VideoFrame::kYPlane,
1265 dst_subrect_,
1266 swizzle_,
1267 base::Bind(&nullcallback));
1268 copy_impl_->ReadbackPlane(&u_,
1269 target,
1270 media::VideoFrame::kUPlane,
1272 dst_subrect_,
1273 swizzle_,
1274 base::Bind(&nullcallback));
1275 copy_impl_->ReadbackPlane(
1276 &v_,
1277 target,
1278 media::VideoFrame::kVPlane,
1280 dst_subrect_,
1281 swizzle_,
1282 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1283 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1284 media::LetterboxYUV(target.get(), dst_subrect_);
1287 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
1288 DCHECK(readback_support_.get());
1289 GLenum format, type;
1290 size_t bytes_per_pixel;
1291 FormatSupport support = readback_support_->GetReadbackConfig(
1292 color_type, false, &format, &type, &bytes_per_pixel);
1294 return (support == GLHelperReadbackSupport::SUPPORTED);
1297 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1298 GLHelper::ScalerQuality quality,
1299 const gfx::Size& src_size,
1300 const gfx::Rect& src_subrect,
1301 const gfx::Size& dst_size,
1302 const gfx::Rect& dst_subrect,
1303 bool flip_vertically,
1304 bool use_mrt) {
1305 helper_->InitScalerImpl();
1306 // Just query if the best readback configuration needs a swizzle In
1307 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
1308 GLenum format, type;
1309 size_t bytes_per_pixel;
1310 FormatSupport supported = GetReadbackConfig(
1311 kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel);
1312 DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
1313 type == GL_UNSIGNED_BYTE);
1315 ReadbackSwizzle swizzle = kSwizzleNone;
1316 if (supported == GLHelperReadbackSupport::SWIZZLE)
1317 swizzle = kSwizzleBGRA;
1319 if (max_draw_buffers_ >= 2 && use_mrt) {
1320 return new ReadbackYUV_MRT(gl_,
1321 this,
1322 helper_->scaler_impl_.get(),
1323 quality,
1324 src_size,
1325 src_subrect,
1326 dst_size,
1327 dst_subrect,
1328 flip_vertically,
1329 swizzle);
1331 return new ReadbackYUVImpl(gl_,
1332 this,
1333 helper_->scaler_impl_.get(),
1334 quality,
1335 src_size,
1336 src_subrect,
1337 dst_size,
1338 dst_subrect,
1339 flip_vertically,
1340 swizzle);
1343 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1344 ScalerQuality quality,
1345 const gfx::Size& src_size,
1346 const gfx::Rect& src_subrect,
1347 const gfx::Size& dst_size,
1348 const gfx::Rect& dst_subrect,
1349 bool flip_vertically,
1350 bool use_mrt) {
1351 InitCopyTextToImpl();
1352 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1353 src_size,
1354 src_subrect,
1355 dst_size,
1356 dst_subrect,
1357 flip_vertically,
1358 use_mrt);
1361 } // namespace content