Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / common / gpu / client / gl_helper.cc
blob8c4a260f842c64cf65532650eae6290e38bf658b
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 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
253 uint32 sync_point,
254 const scoped_refptr<media::VideoFrame>& target,
255 const base::Callback<void(bool)>& callback)
256 OVERRIDE;
258 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
260 private:
261 GLES2Interface* gl_;
262 CopyTextureToImpl* copy_impl_;
263 gfx::Size dst_size_;
264 gfx::Rect dst_subrect_;
265 ReadbackSwizzle swizzle_;
266 ScalerHolder scaler_;
267 ScalerHolder y_;
268 ScalerHolder u_;
269 ScalerHolder v_;
271 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
274 // A readback pipeline that also converts the data to YUV before
275 // reading it back. This one uses Multiple Render Targets, which
276 // may not be supported on all platforms.
277 class ReadbackYUV_MRT : public ReadbackYUVInterface {
278 public:
279 ReadbackYUV_MRT(GLES2Interface* gl,
280 CopyTextureToImpl* copy_impl,
281 GLHelperScaling* scaler_impl,
282 GLHelper::ScalerQuality quality,
283 const gfx::Size& src_size,
284 const gfx::Rect& src_subrect,
285 const gfx::Size& dst_size,
286 const gfx::Rect& dst_subrect,
287 bool flip_vertically,
288 ReadbackSwizzle swizzle);
290 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
291 uint32 sync_point,
292 const scoped_refptr<media::VideoFrame>& target,
293 const base::Callback<void(bool)>& callback)
294 OVERRIDE;
296 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
298 private:
299 GLES2Interface* gl_;
300 CopyTextureToImpl* copy_impl_;
301 gfx::Size dst_size_;
302 gfx::Rect dst_subrect_;
303 GLHelper::ScalerQuality quality_;
304 ReadbackSwizzle swizzle_;
305 ScalerHolder scaler_;
306 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
307 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
308 TextureFrameBufferPair y_;
309 ScopedTexture uv_;
310 TextureFrameBufferPair u_;
311 TextureFrameBufferPair v_;
313 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
316 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
317 // scales it to |dst_size|, writes it into a texture, and returns its ID.
318 // |src_size| is the size of |src_texture|.
319 GLuint ScaleTexture(GLuint src_texture,
320 const gfx::Size& src_size,
321 const gfx::Rect& src_subrect,
322 const gfx::Size& dst_size,
323 bool vertically_flip_texture,
324 bool swizzle,
325 SkColorType color_type,
326 GLHelper::ScalerQuality quality);
328 // Converts each four consecutive pixels of the source texture into one pixel
329 // in the result texture with each pixel channel representing the grayscale
330 // color of one of the four original pixels:
331 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
332 // The resulting texture is still an RGBA texture (which is ~4 times narrower
333 // than the original). If rendered directly, it wouldn't show anything useful,
334 // but the data in it can be used to construct a grayscale image.
335 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
336 // is equal to src_size.width()/4 rounded upwards. Some channels in the last
337 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
338 // useful data.
339 // If swizzle is set to true, the transformed pixels are reordered:
340 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
341 GLuint EncodeTextureAsGrayscale(GLuint src_texture,
342 const gfx::Size& src_size,
343 gfx::Size* const encoded_texture_size,
344 bool vertically_flip_texture,
345 bool swizzle);
347 static void nullcallback(bool success) {}
348 void ReadbackDone(Request *request, int bytes_per_pixel);
349 void FinishRequest(Request* request, bool result);
350 void CancelRequests();
352 static const float kRGBtoYColorWeights[];
353 static const float kRGBtoUColorWeights[];
354 static const float kRGBtoVColorWeights[];
355 static const float kRGBtoGrayscaleColorWeights[];
357 GLES2Interface* gl_;
358 gpu::ContextSupport* context_support_;
359 GLHelper* helper_;
361 // A scoped flush that will ensure all resource deletions are flushed when
362 // this object is destroyed. Must be declared before other Scoped* fields.
363 ScopedFlush flush_;
365 std::queue<Request*> request_queue_;
366 GLint max_draw_buffers_;
369 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
370 const gfx::Size& src_size,
371 const gfx::Rect& src_subrect,
372 const gfx::Size& dst_size,
373 bool vertically_flip_texture,
374 bool swizzle) {
375 InitScalerImpl();
376 return scaler_impl_->CreateScaler(quality,
377 src_size,
378 src_subrect,
379 dst_size,
380 vertically_flip_texture,
381 swizzle);
384 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
385 GLuint src_texture,
386 const gfx::Size& src_size,
387 const gfx::Rect& src_subrect,
388 const gfx::Size& dst_size,
389 bool vertically_flip_texture,
390 bool swizzle,
391 SkColorType color_type,
392 GLHelper::ScalerQuality quality) {
393 GLuint dst_texture = 0u;
394 gl_->GenTextures(1, &dst_texture);
396 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
397 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
399 // Use GL_RGBA for destination/temporary texture unless we're working with
400 // 16-bit data
401 if (color_type == kRGB_565_SkColorType) {
402 format = GL_RGB;
403 type = GL_UNSIGNED_SHORT_5_6_5;
406 gl_->TexImage2D(GL_TEXTURE_2D,
408 format,
409 dst_size.width(),
410 dst_size.height(),
412 format,
413 type,
414 NULL);
416 scoped_ptr<ScalerInterface> scaler(
417 helper_->CreateScaler(quality,
418 src_size,
419 src_subrect,
420 dst_size,
421 vertically_flip_texture,
422 swizzle));
423 scaler->Scale(src_texture, dst_texture);
424 return dst_texture;
427 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
428 GLuint src_texture,
429 const gfx::Size& src_size,
430 gfx::Size* const encoded_texture_size,
431 bool vertically_flip_texture,
432 bool swizzle) {
433 GLuint dst_texture = 0u;
434 gl_->GenTextures(1, &dst_texture);
435 // The size of the encoded texture.
436 *encoded_texture_size =
437 gfx::Size((src_size.width() + 3) / 4, src_size.height());
439 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
440 gl_->TexImage2D(GL_TEXTURE_2D,
442 GL_RGBA,
443 encoded_texture_size->width(),
444 encoded_texture_size->height(),
446 GL_RGBA,
447 GL_UNSIGNED_BYTE,
448 NULL);
451 helper_->InitScalerImpl();
452 scoped_ptr<ScalerInterface> grayscale_scaler(
453 helper_->scaler_impl_.get()->CreatePlanarScaler(
454 src_size,
455 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()),
456 *encoded_texture_size,
457 vertically_flip_texture,
458 swizzle,
459 kRGBtoGrayscaleColorWeights));
460 grayscale_scaler->Scale(src_texture, dst_texture);
461 return dst_texture;
464 void GLHelper::CopyTextureToImpl::ReadbackAsync(
465 const gfx::Size& dst_size,
466 int32 bytes_per_row,
467 int32 row_stride_bytes,
468 unsigned char* out,
469 GLenum format,
470 GLenum type,
471 size_t bytes_per_pixel,
472 const base::Callback<void(bool)>& callback) {
473 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
474 Request* request =
475 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
476 request_queue_.push(request);
477 request->buffer = 0u;
479 gl_->GenBuffers(1, &request->buffer);
480 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
481 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
482 bytes_per_pixel * dst_size.GetArea(),
483 NULL,
484 GL_STREAM_READ);
486 request->query = 0u;
487 gl_->GenQueriesEXT(1, &request->query);
488 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
489 gl_->ReadPixels(0,
491 dst_size.width(),
492 dst_size.height(),
493 format,
494 type,
495 NULL);
496 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
497 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
498 context_support_->SignalQuery(
499 request->query,
500 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
501 request, bytes_per_pixel));
504 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
505 GLuint src_texture,
506 const gfx::Size& src_size,
507 const gfx::Rect& src_subrect,
508 const gfx::Size& dst_size,
509 unsigned char* out,
510 const SkColorType out_color_type,
511 const base::Callback<void(bool)>& callback,
512 GLHelper::ScalerQuality quality) {
513 GLenum format, type;
514 size_t bytes_per_pixel;
515 SkColorType readback_color_type = out_color_type;
516 // Single-component textures are not supported by all GPUs, so we implement
517 // kAlpha_8_SkColorType support here via a special encoding (see below) using
518 // a 32-bit texture to represent an 8-bit image.
519 // Thus we use generic 32-bit readback in this case.
520 if (out_color_type == kAlpha_8_SkColorType) {
521 readback_color_type = kRGBA_8888_SkColorType;
524 FormatSupport supported = GetReadbackConfig(
525 readback_color_type, true, &format, &type, &bytes_per_pixel);
527 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
528 callback.Run(false);
529 return;
532 GLuint texture = src_texture;
534 // Scale texture if needed
535 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
536 // can do just as well in EncodeTextureAsGrayscale, which we will do if
537 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
538 // in that case.
539 bool scale_texture = out_color_type != kAlpha_8_SkColorType ||
540 quality != GLHelper::SCALER_QUALITY_FAST;
541 if (scale_texture) {
542 // Don't swizzle during the scale step for kAlpha_8_SkColorType.
543 // We will swizzle in the encode step below if needed.
544 bool scale_swizzle = out_color_type == kAlpha_8_SkColorType
545 ? false
546 : supported == GLHelperReadbackSupport::SWIZZLE;
547 texture =
548 ScaleTexture(src_texture,
549 src_size,
550 src_subrect,
551 dst_size,
552 true,
553 scale_swizzle,
554 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType
555 : out_color_type,
556 quality);
557 DCHECK(texture);
560 gfx::Size readback_texture_size = dst_size;
561 // Encode texture to grayscale if needed.
562 if (out_color_type == kAlpha_8_SkColorType) {
563 // Do the vertical flip here if we haven't already done it when we scaled
564 // the texture.
565 bool encode_as_grayscale_vertical_flip = !scale_texture;
566 // EncodeTextureAsGrayscale by default creates a texture which should be
567 // read back as RGBA, so need to swizzle if the readback format is BGRA.
568 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT;
569 GLuint tmp_texture =
570 EncodeTextureAsGrayscale(texture,
571 dst_size,
572 &readback_texture_size,
573 encode_as_grayscale_vertical_flip,
574 encode_as_grayscale_swizzle);
575 // If the scaled texture was created - delete it
576 if (scale_texture)
577 gl_->DeleteTextures(1, &texture);
578 texture = tmp_texture;
579 DCHECK(texture);
582 // Readback the pixels of the resulting texture
583 ScopedFramebuffer dst_framebuffer(gl_);
584 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
585 dst_framebuffer);
586 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
587 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
588 GL_COLOR_ATTACHMENT0,
589 GL_TEXTURE_2D,
590 texture,
593 int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType
594 ? dst_size.width()
595 : dst_size.width() * bytes_per_pixel;
597 ReadbackAsync(readback_texture_size,
598 bytes_per_row,
599 bytes_per_row,
600 out,
601 format,
602 type,
603 bytes_per_pixel,
604 callback);
605 gl_->DeleteTextures(1, &texture);
608 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
609 GLuint texture,
610 const gfx::Rect& src_rect,
611 unsigned char* out,
612 SkColorType color_type) {
613 GLenum format, type;
614 size_t bytes_per_pixel;
615 FormatSupport supported =
616 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
617 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
618 return;
621 ScopedFramebuffer dst_framebuffer(gl_);
622 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
623 dst_framebuffer);
624 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
625 gl_->FramebufferTexture2D(
626 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
627 gl_->ReadPixels(src_rect.x(),
628 src_rect.y(),
629 src_rect.width(),
630 src_rect.height(),
631 format,
632 type,
633 out);
636 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
637 GLuint texture,
638 const gfx::Size& dst_size,
639 unsigned char* out,
640 SkColorType color_type,
641 const base::Callback<void(bool)>& callback) {
642 GLenum format, type;
643 size_t bytes_per_pixel;
644 FormatSupport supported =
645 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
646 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
647 callback.Run(false);
648 return;
651 ScopedFramebuffer dst_framebuffer(gl_);
652 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
653 dst_framebuffer);
654 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
655 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
656 GL_COLOR_ATTACHMENT0,
657 GL_TEXTURE_2D,
658 texture,
660 ReadbackAsync(dst_size,
661 dst_size.width() * bytes_per_pixel,
662 dst_size.width() * bytes_per_pixel,
663 out,
664 format,
665 type,
666 bytes_per_pixel,
667 callback);
670 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
671 GLuint src_texture,
672 const gfx::Size& src_size,
673 const gfx::Size& dst_size,
674 bool vertically_flip_texture,
675 GLHelper::ScalerQuality quality) {
676 return ScaleTexture(src_texture,
677 src_size,
678 gfx::Rect(src_size),
679 dst_size,
680 vertically_flip_texture,
681 false,
682 kRGBA_8888_SkColorType, // GL_RGBA
683 quality);
686 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
687 int bytes_per_pixel) {
688 TRACE_EVENT0("mirror",
689 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
690 finished_request->done = true;
692 // We process transfer requests in the order they were received, regardless
693 // of the order we get the callbacks in.
694 while (!request_queue_.empty()) {
695 Request* request = request_queue_.front();
696 if (!request->done) {
697 break;
700 bool result = false;
701 if (request->buffer != 0) {
702 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
703 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
704 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
705 if (data) {
706 result = true;
707 if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
708 request->bytes_per_row == request->row_stride_bytes) {
709 memcpy(request->pixels, data,
710 request->size.GetArea() * bytes_per_pixel);
711 } else {
712 unsigned char* out = request->pixels;
713 for (int y = 0; y < request->size.height(); y++) {
714 memcpy(out, data, request->bytes_per_row);
715 out += request->row_stride_bytes;
716 data += request->size.width() * bytes_per_pixel;
719 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
721 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
723 FinishRequest(request, result);
727 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
728 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
729 DCHECK(request_queue_.front() == request);
730 request_queue_.pop();
731 request->callback.Run(result);
732 ScopedFlush flush(gl_);
733 if (request->query != 0) {
734 gl_->DeleteQueriesEXT(1, &request->query);
735 request->query = 0;
737 if (request->buffer != 0) {
738 gl_->DeleteBuffers(1, &request->buffer);
739 request->buffer = 0;
741 delete request;
744 void GLHelper::CopyTextureToImpl::CancelRequests() {
745 while (!request_queue_.empty()) {
746 Request* request = request_queue_.front();
747 FinishRequest(request, false);
751 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
752 SkColorType color_type,
753 bool can_swizzle,
754 GLenum* format,
755 GLenum* type,
756 size_t* bytes_per_pixel) {
757 return helper_->readback_support_->GetReadbackConfig(
758 color_type, can_swizzle, format, type, bytes_per_pixel);
761 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
762 : gl_(gl),
763 context_support_(context_support),
764 readback_support_(new GLHelperReadbackSupport(gl)) {}
766 GLHelper::~GLHelper() {}
768 void GLHelper::CropScaleReadbackAndCleanTexture(
769 GLuint src_texture,
770 const gfx::Size& src_size,
771 const gfx::Rect& src_subrect,
772 const gfx::Size& dst_size,
773 unsigned char* out,
774 const SkColorType out_color_type,
775 const base::Callback<void(bool)>& callback,
776 GLHelper::ScalerQuality quality) {
777 InitCopyTextToImpl();
778 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture,
779 src_size,
780 src_subrect,
781 dst_size,
782 out,
783 out_color_type,
784 callback,
785 quality);
788 void GLHelper::CropScaleReadbackAndCleanMailbox(
789 const gpu::Mailbox& src_mailbox,
790 uint32 sync_point,
791 const gfx::Size& src_size,
792 const gfx::Rect& src_subrect,
793 const gfx::Size& dst_size,
794 unsigned char* out,
795 const SkColorType out_color_type,
796 const base::Callback<void(bool)>& callback,
797 GLHelper::ScalerQuality quality) {
798 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
799 CropScaleReadbackAndCleanTexture(mailbox_texture,
800 src_size,
801 src_subrect,
802 dst_size,
803 out,
804 out_color_type,
805 callback,
806 quality);
807 gl_->DeleteTextures(1, &mailbox_texture);
810 void GLHelper::ReadbackTextureSync(GLuint texture,
811 const gfx::Rect& src_rect,
812 unsigned char* out,
813 SkColorType format) {
814 InitCopyTextToImpl();
815 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
818 void GLHelper::ReadbackTextureAsync(
819 GLuint texture,
820 const gfx::Size& dst_size,
821 unsigned char* out,
822 SkColorType color_type,
823 const base::Callback<void(bool)>& callback) {
824 InitCopyTextToImpl();
825 copy_texture_to_impl_->ReadbackTextureAsync(texture,
826 dst_size,
827 out,
828 color_type,
829 callback);
832 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
833 InitCopyTextToImpl();
834 return copy_texture_to_impl_->CopyAndScaleTexture(
835 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
838 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
839 const gfx::Size& src_size,
840 const gfx::Size& dst_size,
841 bool vertically_flip_texture,
842 ScalerQuality quality) {
843 InitCopyTextToImpl();
844 return copy_texture_to_impl_->CopyAndScaleTexture(
845 texture, src_size, dst_size, vertically_flip_texture, quality);
848 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
849 GLuint shader = gl_->CreateShader(type);
850 GLint length = strlen(source);
851 gl_->ShaderSource(shader, 1, &source, &length);
852 gl_->CompileShader(shader);
853 GLint compile_status = 0;
854 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
855 if (!compile_status) {
856 GLint log_length = 0;
857 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
858 if (log_length) {
859 scoped_ptr<GLchar[]> log(new GLchar[log_length]);
860 GLsizei returned_log_length = 0;
861 gl_->GetShaderInfoLog(
862 shader, log_length, &returned_log_length, log.get());
863 LOG(ERROR) << std::string(log.get(), returned_log_length);
865 gl_->DeleteShader(shader);
866 return 0;
868 return shader;
871 void GLHelper::InitCopyTextToImpl() {
872 // Lazily initialize |copy_texture_to_impl_|
873 if (!copy_texture_to_impl_)
874 copy_texture_to_impl_.reset(
875 new CopyTextureToImpl(gl_, context_support_, this));
878 void GLHelper::InitScalerImpl() {
879 // Lazily initialize |scaler_impl_|
880 if (!scaler_impl_)
881 scaler_impl_.reset(new GLHelperScaling(gl_, this));
884 GLint GLHelper::MaxDrawBuffers() {
885 InitCopyTextToImpl();
886 return copy_texture_to_impl_->MaxDrawBuffers();
889 void GLHelper::CopySubBufferDamage(GLuint texture,
890 GLuint previous_texture,
891 const SkRegion& new_damage,
892 const SkRegion& old_damage) {
893 SkRegion region(old_damage);
894 if (region.op(new_damage, SkRegion::kDifference_Op)) {
895 ScopedFramebuffer dst_framebuffer(gl_);
896 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
897 dst_framebuffer);
898 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
899 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
900 GL_COLOR_ATTACHMENT0,
901 GL_TEXTURE_2D,
902 previous_texture,
904 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
905 const SkIRect& rect = it.rect();
906 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
908 rect.x(),
909 rect.y(),
910 rect.x(),
911 rect.y(),
912 rect.width(),
913 rect.height());
915 gl_->Flush();
919 GLuint GLHelper::CreateTexture() {
920 GLuint texture = 0u;
921 gl_->GenTextures(1, &texture);
922 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
923 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
924 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
925 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
926 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
927 return texture;
930 void GLHelper::DeleteTexture(GLuint texture_id) {
931 gl_->DeleteTextures(1, &texture_id);
934 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
936 void GLHelper::WaitSyncPoint(uint32 sync_point) {
937 gl_->WaitSyncPointCHROMIUM(sync_point);
940 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
941 GLuint texture_id) {
942 gpu::Mailbox mailbox;
943 gl_->GenMailboxCHROMIUM(mailbox.name);
944 gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
945 return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
948 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
949 uint32 sync_point) {
950 if (mailbox.IsZero())
951 return 0;
952 if (sync_point)
953 WaitSyncPoint(sync_point);
954 GLuint texture =
955 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
956 return texture;
959 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
960 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
961 gl_->TexImage2D(GL_TEXTURE_2D,
963 GL_RGB,
964 size.width(),
965 size.height(),
967 GL_RGB,
968 GL_UNSIGNED_BYTE,
969 NULL);
972 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
973 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
974 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
976 rect.x(),
977 rect.y(),
978 rect.x(),
979 rect.y(),
980 rect.width(),
981 rect.height());
984 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
985 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
986 gl_->CopyTexImage2D(
987 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
990 void GLHelper::Flush() {
991 gl_->Flush();
994 void GLHelper::CopyTextureToImpl::ReadbackPlane(
995 TextureFrameBufferPair* source,
996 const scoped_refptr<media::VideoFrame>& target,
997 int plane,
998 int size_shift,
999 const gfx::Rect& dst_subrect,
1000 ReadbackSwizzle swizzle,
1001 const base::Callback<void(bool)>& callback) {
1002 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
1003 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
1004 (dst_subrect.x() >> size_shift);
1005 ReadbackAsync(source->size(),
1006 dst_subrect.width() >> size_shift,
1007 target->stride(plane),
1008 target->data(plane) + offset,
1009 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
1010 GL_UNSIGNED_BYTE,
1012 callback);
1015 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
1016 0.257f, 0.504f, 0.098f, 0.0625f};
1017 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
1018 -0.148f, -0.291f, 0.439f, 0.5f};
1019 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
1020 0.439f, -0.368f, -0.071f, 0.5f};
1021 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = {
1022 0.213f, 0.715f, 0.072f, 0.0f};
1024 // YUV readback constructors. Initiates the main scaler pipeline and
1025 // one planar scaler for each of the Y, U and V planes.
1026 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
1027 GLES2Interface* gl,
1028 CopyTextureToImpl* copy_impl,
1029 GLHelperScaling* scaler_impl,
1030 GLHelper::ScalerQuality quality,
1031 const gfx::Size& src_size,
1032 const gfx::Rect& src_subrect,
1033 const gfx::Size& dst_size,
1034 const gfx::Rect& dst_subrect,
1035 bool flip_vertically,
1036 ReadbackSwizzle swizzle)
1037 : gl_(gl),
1038 copy_impl_(copy_impl),
1039 dst_size_(dst_size),
1040 dst_subrect_(dst_subrect),
1041 swizzle_(swizzle),
1042 scaler_(gl,
1043 scaler_impl->CreateScaler(quality,
1044 src_size,
1045 src_subrect,
1046 dst_subrect.size(),
1047 flip_vertically,
1048 false)),
1049 y_(gl,
1050 scaler_impl->CreatePlanarScaler(
1051 dst_subrect.size(),
1052 gfx::Rect(0,
1054 (dst_subrect.width() + 3) & ~3,
1055 dst_subrect.height()),
1056 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1057 false,
1058 (swizzle == kSwizzleBGRA),
1059 kRGBtoYColorWeights)),
1060 u_(gl,
1061 scaler_impl->CreatePlanarScaler(
1062 dst_subrect.size(),
1063 gfx::Rect(0,
1065 (dst_subrect.width() + 7) & ~7,
1066 (dst_subrect.height() + 1) & ~1),
1067 gfx::Size((dst_subrect.width() + 7) / 8,
1068 (dst_subrect.height() + 1) / 2),
1069 false,
1070 (swizzle == kSwizzleBGRA),
1071 kRGBtoUColorWeights)),
1072 v_(gl,
1073 scaler_impl->CreatePlanarScaler(
1074 dst_subrect.size(),
1075 gfx::Rect(0,
1077 (dst_subrect.width() + 7) & ~7,
1078 (dst_subrect.height() + 1) & ~1),
1079 gfx::Size((dst_subrect.width() + 7) / 8,
1080 (dst_subrect.height() + 1) / 2),
1081 false,
1082 (swizzle == kSwizzleBGRA),
1083 kRGBtoVColorWeights)) {
1084 DCHECK(!(dst_size.width() & 1));
1085 DCHECK(!(dst_size.height() & 1));
1086 DCHECK(!(dst_subrect.width() & 1));
1087 DCHECK(!(dst_subrect.height() & 1));
1088 DCHECK(!(dst_subrect.x() & 1));
1089 DCHECK(!(dst_subrect.y() & 1));
1092 static void CallbackKeepingVideoFrameAlive(
1093 scoped_refptr<media::VideoFrame> video_frame,
1094 const base::Callback<void(bool)>& callback,
1095 bool success) {
1096 callback.Run(success);
1099 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1100 const gpu::Mailbox& mailbox,
1101 uint32 sync_point,
1102 const scoped_refptr<media::VideoFrame>& target,
1103 const base::Callback<void(bool)>& callback) {
1104 GLuint mailbox_texture =
1105 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1107 // Scale texture to right size.
1108 scaler_.Scale(mailbox_texture);
1109 gl_->DeleteTextures(1, &mailbox_texture);
1111 // Convert the scaled texture in to Y, U and V planes.
1112 y_.Scale(scaler_.texture());
1113 u_.Scale(scaler_.texture());
1114 v_.Scale(scaler_.texture());
1116 if (target->coded_size() != dst_size_) {
1117 DCHECK(target->coded_size() == dst_size_);
1118 LOG(ERROR) << "ReadbackYUV size error!";
1119 callback.Run(false);
1120 return;
1123 // Read back planes, one at a time. Keep the video frame alive while doing the
1124 // readback.
1125 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
1126 target,
1127 media::VideoFrame::kYPlane,
1129 dst_subrect_,
1130 swizzle_,
1131 base::Bind(&nullcallback));
1132 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
1133 target,
1134 media::VideoFrame::kUPlane,
1136 dst_subrect_,
1137 swizzle_,
1138 base::Bind(&nullcallback));
1139 copy_impl_->ReadbackPlane(
1140 v_.texture_and_framebuffer(),
1141 target,
1142 media::VideoFrame::kVPlane,
1144 dst_subrect_,
1145 swizzle_,
1146 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1147 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1148 media::LetterboxYUV(target.get(), dst_subrect_);
1151 // YUV readback constructors. Initiates the main scaler pipeline and
1152 // one planar scaler for each of the Y, U and V planes.
1153 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1154 GLES2Interface* gl,
1155 CopyTextureToImpl* copy_impl,
1156 GLHelperScaling* scaler_impl,
1157 GLHelper::ScalerQuality quality,
1158 const gfx::Size& src_size,
1159 const gfx::Rect& src_subrect,
1160 const gfx::Size& dst_size,
1161 const gfx::Rect& dst_subrect,
1162 bool flip_vertically,
1163 ReadbackSwizzle swizzle)
1164 : gl_(gl),
1165 copy_impl_(copy_impl),
1166 dst_size_(dst_size),
1167 dst_subrect_(dst_subrect),
1168 quality_(quality),
1169 swizzle_(swizzle),
1170 scaler_(gl,
1171 scaler_impl->CreateScaler(quality,
1172 src_size,
1173 src_subrect,
1174 dst_subrect.size(),
1175 false,
1176 false)),
1177 pass1_shader_(scaler_impl->CreateYuvMrtShader(
1178 dst_subrect.size(),
1179 gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
1180 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1181 flip_vertically,
1182 (swizzle == kSwizzleBGRA),
1183 GLHelperScaling::SHADER_YUV_MRT_PASS1)),
1184 pass2_shader_(scaler_impl->CreateYuvMrtShader(
1185 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1186 gfx::Rect(0,
1188 (dst_subrect.width() + 7) / 8 * 2,
1189 dst_subrect.height()),
1190 gfx::Size((dst_subrect.width() + 7) / 8,
1191 (dst_subrect.height() + 1) / 2),
1192 false,
1193 (swizzle == kSwizzleBGRA),
1194 GLHelperScaling::SHADER_YUV_MRT_PASS2)),
1195 y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
1196 uv_(gl),
1197 u_(gl,
1198 gfx::Size((dst_subrect.width() + 7) / 8,
1199 (dst_subrect.height() + 1) / 2)),
1200 v_(gl,
1201 gfx::Size((dst_subrect.width() + 7) / 8,
1202 (dst_subrect.height() + 1) / 2)) {
1204 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
1205 gl->TexImage2D(GL_TEXTURE_2D,
1207 GL_RGBA,
1208 (dst_subrect.width() + 3) / 4,
1209 dst_subrect.height(),
1211 GL_RGBA,
1212 GL_UNSIGNED_BYTE,
1213 NULL);
1215 DCHECK(!(dst_size.width() & 1));
1216 DCHECK(!(dst_size.height() & 1));
1217 DCHECK(!(dst_subrect.width() & 1));
1218 DCHECK(!(dst_subrect.height() & 1));
1219 DCHECK(!(dst_subrect.x() & 1));
1220 DCHECK(!(dst_subrect.y() & 1));
1223 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1224 const gpu::Mailbox& mailbox,
1225 uint32 sync_point,
1226 const scoped_refptr<media::VideoFrame>& target,
1227 const base::Callback<void(bool)>& callback) {
1228 GLuint mailbox_texture =
1229 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1231 GLuint texture;
1232 if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
1233 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1234 // pass, which pass1_shader_ can do just as well, so let's skip
1235 // the actual scaling in that case.
1236 texture = mailbox_texture;
1237 } else {
1238 // Scale texture to right size.
1239 scaler_.Scale(mailbox_texture);
1240 texture = scaler_.texture();
1243 std::vector<GLuint> outputs(2);
1244 // Convert the scaled texture in to Y, U and V planes.
1245 outputs[0] = y_.texture();
1246 outputs[1] = uv_;
1247 pass1_shader_->Execute(texture, outputs);
1249 gl_->DeleteTextures(1, &mailbox_texture);
1251 outputs[0] = u_.texture();
1252 outputs[1] = v_.texture();
1253 pass2_shader_->Execute(uv_, outputs);
1255 if (target->coded_size() != dst_size_) {
1256 DCHECK(target->coded_size() == dst_size_);
1257 LOG(ERROR) << "ReadbackYUV size error!";
1258 callback.Run(false);
1259 return;
1262 // Read back planes, one at a time.
1263 copy_impl_->ReadbackPlane(&y_,
1264 target,
1265 media::VideoFrame::kYPlane,
1267 dst_subrect_,
1268 swizzle_,
1269 base::Bind(&nullcallback));
1270 copy_impl_->ReadbackPlane(&u_,
1271 target,
1272 media::VideoFrame::kUPlane,
1274 dst_subrect_,
1275 swizzle_,
1276 base::Bind(&nullcallback));
1277 copy_impl_->ReadbackPlane(
1278 &v_,
1279 target,
1280 media::VideoFrame::kVPlane,
1282 dst_subrect_,
1283 swizzle_,
1284 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1285 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1286 media::LetterboxYUV(target.get(), dst_subrect_);
1289 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
1290 DCHECK(readback_support_.get());
1291 GLenum format, type;
1292 size_t bytes_per_pixel;
1293 FormatSupport support = readback_support_->GetReadbackConfig(
1294 color_type, false, &format, &type, &bytes_per_pixel);
1296 return (support == GLHelperReadbackSupport::SUPPORTED);
1299 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1300 GLHelper::ScalerQuality quality,
1301 const gfx::Size& src_size,
1302 const gfx::Rect& src_subrect,
1303 const gfx::Size& dst_size,
1304 const gfx::Rect& dst_subrect,
1305 bool flip_vertically,
1306 bool use_mrt) {
1307 helper_->InitScalerImpl();
1308 // Just query if the best readback configuration needs a swizzle In
1309 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
1310 GLenum format, type;
1311 size_t bytes_per_pixel;
1312 FormatSupport supported = GetReadbackConfig(
1313 kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel);
1314 DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
1315 type == GL_UNSIGNED_BYTE);
1317 ReadbackSwizzle swizzle = kSwizzleNone;
1318 if (supported == GLHelperReadbackSupport::SWIZZLE)
1319 swizzle = kSwizzleBGRA;
1321 if (max_draw_buffers_ >= 2 && use_mrt) {
1322 return new ReadbackYUV_MRT(gl_,
1323 this,
1324 helper_->scaler_impl_.get(),
1325 quality,
1326 src_size,
1327 src_subrect,
1328 dst_size,
1329 dst_subrect,
1330 flip_vertically,
1331 swizzle);
1333 return new ReadbackYUVImpl(gl_,
1334 this,
1335 helper_->scaler_impl_.get(),
1336 quality,
1337 src_size,
1338 src_subrect,
1339 dst_size,
1340 dst_subrect,
1341 flip_vertically,
1342 swizzle);
1345 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1346 ScalerQuality quality,
1347 const gfx::Size& src_size,
1348 const gfx::Rect& src_subrect,
1349 const gfx::Size& dst_size,
1350 const gfx::Rect& dst_subrect,
1351 bool flip_vertically,
1352 bool use_mrt) {
1353 InitCopyTextToImpl();
1354 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1355 src_size,
1356 src_subrect,
1357 dst_size,
1358 dst_subrect,
1359 flip_vertically,
1360 use_mrt);
1363 } // namespace content