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"
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
;
36 explicit ScopedFlush(gpu::gles2::GLES2Interface
* gl
) : gl_(gl
) {}
38 ~ScopedFlush() { gl_
->Flush(); }
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
{
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
,
62 content::ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(
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_
; }
73 content::ScopedTexture texture_
;
74 content::ScopedFramebuffer framebuffer_
;
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.
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(); }
99 TextureFrameBufferPair texture_and_framebuffer_
;
100 scoped_ptr
<content::GLHelper::ScalerInterface
> scaler_
;
102 DISALLOW_COPY_AND_ASSIGN(ScalerHolder
);
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
> {
115 CopyTextureToImpl(GLES2Interface
* gl
,
116 gpu::ContextSupport
* context_support
,
119 context_support_(context_support
),
122 max_draw_buffers_(0) {
123 const GLubyte
* extensions
= gl_
->GetString(GL_EXTENSIONS
);
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
,
136 return helper_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
139 void CropScaleReadbackAndCleanTexture(
141 const gfx::Size
& src_size
,
142 const gfx::Rect
& src_subrect
,
143 const gfx::Size
& dst_size
,
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
,
154 void ReadbackTextureAsync(GLuint texture
,
155 const gfx::Size
& dst_size
,
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
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
,
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
,
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
,
202 size_t* bytes_per_pixel
);
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.
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_
)
220 bytes_per_row(bytes_per_row_
),
221 row_stride_bytes(row_stride_bytes_
),
230 int row_stride_bytes
;
231 unsigned char* pixels
;
232 base::Callback
<void(bool)> callback
;
237 // A readback pipeline that also converts the data to YUV before
239 class ReadbackYUVImpl
: public ReadbackYUVInterface
{
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
,
254 const scoped_refptr
<media::VideoFrame
>& target
,
255 const base::Callback
<void(bool)>& callback
) override
;
257 ScalerInterface
* scaler() override
{ return scaler_
.scaler(); }
261 CopyTextureToImpl
* copy_impl_
;
263 gfx::Rect dst_subrect_
;
264 ReadbackSwizzle swizzle_
;
265 ScalerHolder scaler_
;
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
{
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
,
291 const scoped_refptr
<media::VideoFrame
>& target
,
292 const base::Callback
<void(bool)>& callback
) override
;
294 ScalerInterface
* scaler() override
{ return scaler_
.scaler(); }
298 CopyTextureToImpl
* copy_impl_
;
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_
;
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
,
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
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
,
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
[];
356 gpu::ContextSupport
* context_support_
;
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.
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
,
374 return scaler_impl_
->CreateScaler(quality
,
378 vertically_flip_texture
,
382 GLuint
GLHelper::CopyTextureToImpl::ScaleTexture(
384 const gfx::Size
& src_size
,
385 const gfx::Rect
& src_subrect
,
386 const gfx::Size
& dst_size
,
387 bool vertically_flip_texture
,
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
399 if (color_type
== kRGB_565_SkColorType
) {
401 type
= GL_UNSIGNED_SHORT_5_6_5
;
404 gl_
->TexImage2D(GL_TEXTURE_2D
,
414 scoped_ptr
<ScalerInterface
> scaler(
415 helper_
->CreateScaler(quality
,
419 vertically_flip_texture
,
421 scaler
->Scale(src_texture
, dst_texture
);
425 GLuint
GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
427 const gfx::Size
& src_size
,
428 gfx::Size
* const encoded_texture_size
,
429 bool vertically_flip_texture
,
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
,
441 encoded_texture_size
->width(),
442 encoded_texture_size
->height(),
449 helper_
->InitScalerImpl();
450 scoped_ptr
<ScalerInterface
> grayscale_scaler(
451 helper_
->scaler_impl_
.get()->CreatePlanarScaler(
453 gfx::Rect(0, 0, (src_size
.width() + 3) & ~3, src_size
.height()),
454 *encoded_texture_size
,
455 vertically_flip_texture
,
457 kRGBtoGrayscaleColorWeights
));
458 grayscale_scaler
->Scale(src_texture
, dst_texture
);
462 void GLHelper::CopyTextureToImpl::ReadbackAsync(
463 const gfx::Size
& dst_size
,
465 int32 row_stride_bytes
,
469 size_t bytes_per_pixel
,
470 const base::Callback
<void(bool)>& callback
) {
471 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
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(),
485 gl_
->GenQueriesEXT(1, &request
->query
);
486 gl_
->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, request
->query
);
494 gl_
->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
495 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
496 context_support_
->SignalQuery(
498 base::Bind(&CopyTextureToImpl::ReadbackDone
, AsWeakPtr(),
499 request
, bytes_per_pixel
));
502 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
504 const gfx::Size
& src_size
,
505 const gfx::Rect
& src_subrect
,
506 const gfx::Size
& dst_size
,
508 const SkColorType out_color_type
,
509 const base::Callback
<void(bool)>& callback
,
510 GLHelper::ScalerQuality quality
) {
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
) {
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
537 bool scale_texture
= out_color_type
!= kAlpha_8_SkColorType
||
538 quality
!= GLHelper::SCALER_QUALITY_FAST
;
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
544 : supported
== GLHelperReadbackSupport::SWIZZLE
;
546 ScaleTexture(src_texture
,
552 out_color_type
== kAlpha_8_SkColorType
? kN32_SkColorType
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
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
;
568 EncodeTextureAsGrayscale(texture
,
570 &readback_texture_size
,
571 encode_as_grayscale_vertical_flip
,
572 encode_as_grayscale_swizzle
);
573 // If the scaled texture was created - delete it
575 gl_
->DeleteTextures(1, &texture
);
576 texture
= tmp_texture
;
580 // Readback the pixels of the resulting texture
581 ScopedFramebuffer
dst_framebuffer(gl_
);
582 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
584 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
585 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
586 GL_COLOR_ATTACHMENT0
,
591 int32 bytes_per_row
= out_color_type
== kAlpha_8_SkColorType
593 : dst_size
.width() * bytes_per_pixel
;
595 ReadbackAsync(readback_texture_size
,
603 gl_
->DeleteTextures(1, &texture
);
606 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
608 const gfx::Rect
& src_rect
,
610 SkColorType color_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
) {
619 ScopedFramebuffer
dst_framebuffer(gl_
);
620 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
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(),
634 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
636 const gfx::Size
& dst_size
,
638 SkColorType color_type
,
639 const base::Callback
<void(bool)>& callback
) {
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
) {
649 ScopedFramebuffer
dst_framebuffer(gl_
);
650 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
652 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
653 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
654 GL_COLOR_ATTACHMENT0
,
658 ReadbackAsync(dst_size
,
659 dst_size
.width() * bytes_per_pixel
,
660 dst_size
.width() * bytes_per_pixel
,
668 GLuint
GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
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
,
678 vertically_flip_texture
,
680 kRGBA_8888_SkColorType
, // GL_RGBA
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
) {
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
));
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
);
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
);
735 if (request
->buffer
!= 0) {
736 gl_
->DeleteBuffers(1, &request
->buffer
);
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
,
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
)
761 context_support_(context_support
),
762 readback_support_(new GLHelperReadbackSupport(gl
)) {}
764 GLHelper::~GLHelper() {}
766 void GLHelper::CropScaleReadbackAndCleanTexture(
768 const gfx::Size
& src_size
,
769 const gfx::Rect
& src_subrect
,
770 const gfx::Size
& dst_size
,
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
,
786 void GLHelper::CropScaleReadbackAndCleanMailbox(
787 const gpu::Mailbox
& src_mailbox
,
789 const gfx::Size
& src_size
,
790 const gfx::Rect
& src_subrect
,
791 const gfx::Size
& dst_size
,
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
,
805 gl_
->DeleteTextures(1, &mailbox_texture
);
808 void GLHelper::ReadbackTextureSync(GLuint texture
,
809 const gfx::Rect
& src_rect
,
811 SkColorType format
) {
812 InitCopyTextToImpl();
813 copy_texture_to_impl_
->ReadbackTextureSync(texture
, src_rect
, out
, format
);
816 void GLHelper::ReadbackTextureAsync(
818 const gfx::Size
& dst_size
,
820 SkColorType color_type
,
821 const base::Callback
<void(bool)>& callback
) {
822 InitCopyTextToImpl();
823 copy_texture_to_impl_
->ReadbackTextureAsync(texture
,
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
);
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
);
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_|
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_
,
896 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
897 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
898 GL_COLOR_ATTACHMENT0
,
902 for (SkRegion::Iterator
it(region
); !it
.done(); it
.next()) {
903 const SkIRect
& rect
= it
.rect();
904 gl_
->CopyTexSubImage2D(GL_TEXTURE_2D
,
917 GLuint
GLHelper::CreateTexture() {
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
);
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(
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
,
948 if (mailbox
.IsZero())
951 WaitSyncPoint(sync_point
);
953 gl_
->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
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
,
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
,
982 void GLHelper::CopyTextureFullImage(GLuint texture
, const gfx::Size
& size
) {
983 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
985 GL_TEXTURE_2D
, 0, GL_RGB
, 0, 0, size
.width(), size
.height(), 0);
988 void GLHelper::Flush() {
992 void GLHelper::CopyTextureToImpl::ReadbackPlane(
993 TextureFrameBufferPair
* source
,
994 const scoped_refptr
<media::VideoFrame
>& target
,
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
,
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(
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
)
1036 copy_impl_(copy_impl
),
1037 dst_size_(dst_size
),
1038 dst_subrect_(dst_subrect
),
1041 scaler_impl
->CreateScaler(quality
,
1048 scaler_impl
->CreatePlanarScaler(
1052 (dst_subrect
.width() + 3) & ~3,
1053 dst_subrect
.height()),
1054 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
1056 (swizzle
== kSwizzleBGRA
),
1057 kRGBtoYColorWeights
)),
1059 scaler_impl
->CreatePlanarScaler(
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),
1068 (swizzle
== kSwizzleBGRA
),
1069 kRGBtoUColorWeights
)),
1071 scaler_impl
->CreatePlanarScaler(
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),
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
,
1094 callback
.Run(success
);
1097 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1098 const gpu::Mailbox
& mailbox
,
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);
1121 // Read back planes, one at a time. Keep the video frame alive while doing the
1123 copy_impl_
->ReadbackPlane(y_
.texture_and_framebuffer(),
1125 media::VideoFrame::kYPlane
,
1129 base::Bind(&nullcallback
));
1130 copy_impl_
->ReadbackPlane(u_
.texture_and_framebuffer(),
1132 media::VideoFrame::kUPlane
,
1136 base::Bind(&nullcallback
));
1137 copy_impl_
->ReadbackPlane(
1138 v_
.texture_and_framebuffer(),
1140 media::VideoFrame::kVPlane
,
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(
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
)
1163 copy_impl_(copy_impl
),
1164 dst_size_(dst_size
),
1165 dst_subrect_(dst_subrect
),
1169 scaler_impl
->CreateScaler(quality
,
1175 pass1_shader_(scaler_impl
->CreateYuvMrtShader(
1177 gfx::Rect(0, 0, (dst_subrect
.width() + 3) & ~3, dst_subrect
.height()),
1178 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
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()),
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),
1191 (swizzle
== kSwizzleBGRA
),
1192 GLHelperScaling::SHADER_YUV_MRT_PASS2
)),
1193 y_(gl
, gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height())),
1196 gfx::Size((dst_subrect
.width() + 7) / 8,
1197 (dst_subrect
.height() + 1) / 2)),
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
,
1206 (dst_subrect
.width() + 3) / 4,
1207 dst_subrect
.height(),
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
,
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
);
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
;
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();
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);
1260 // Read back planes, one at a time.
1261 copy_impl_
->ReadbackPlane(&y_
,
1263 media::VideoFrame::kYPlane
,
1267 base::Bind(&nullcallback
));
1268 copy_impl_
->ReadbackPlane(&u_
,
1270 media::VideoFrame::kUPlane
,
1274 base::Bind(&nullcallback
));
1275 copy_impl_
->ReadbackPlane(
1278 media::VideoFrame::kVPlane
,
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
,
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_
,
1322 helper_
->scaler_impl_
.get(),
1331 return new ReadbackYUVImpl(gl_
,
1333 helper_
->scaler_impl_
.get(),
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
,
1351 InitCopyTextToImpl();
1352 return copy_texture_to_impl_
->CreateReadbackPipelineYUV(quality
,
1361 } // namespace content