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 virtual void ReadbackYUV(const gpu::Mailbox
& mailbox
,
254 const scoped_refptr
<media::VideoFrame
>& target
,
255 const base::Callback
<void(bool)>& callback
)
258 virtual ScalerInterface
* scaler() OVERRIDE
{ return scaler_
.scaler(); }
262 CopyTextureToImpl
* copy_impl_
;
264 gfx::Rect dst_subrect_
;
265 ReadbackSwizzle swizzle_
;
266 ScalerHolder scaler_
;
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
{
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
,
292 const scoped_refptr
<media::VideoFrame
>& target
,
293 const base::Callback
<void(bool)>& callback
)
296 virtual ScalerInterface
* scaler() OVERRIDE
{ return scaler_
.scaler(); }
300 CopyTextureToImpl
* copy_impl_
;
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_
;
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
,
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
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
,
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
[];
358 gpu::ContextSupport
* context_support_
;
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.
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
,
376 return scaler_impl_
->CreateScaler(quality
,
380 vertically_flip_texture
,
384 GLuint
GLHelper::CopyTextureToImpl::ScaleTexture(
386 const gfx::Size
& src_size
,
387 const gfx::Rect
& src_subrect
,
388 const gfx::Size
& dst_size
,
389 bool vertically_flip_texture
,
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
401 if (color_type
== kRGB_565_SkColorType
) {
403 type
= GL_UNSIGNED_SHORT_5_6_5
;
406 gl_
->TexImage2D(GL_TEXTURE_2D
,
416 scoped_ptr
<ScalerInterface
> scaler(
417 helper_
->CreateScaler(quality
,
421 vertically_flip_texture
,
423 scaler
->Scale(src_texture
, dst_texture
);
427 GLuint
GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
429 const gfx::Size
& src_size
,
430 gfx::Size
* const encoded_texture_size
,
431 bool vertically_flip_texture
,
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
,
443 encoded_texture_size
->width(),
444 encoded_texture_size
->height(),
451 helper_
->InitScalerImpl();
452 scoped_ptr
<ScalerInterface
> grayscale_scaler(
453 helper_
->scaler_impl_
.get()->CreatePlanarScaler(
455 gfx::Rect(0, 0, (src_size
.width() + 3) & ~3, src_size
.height()),
456 *encoded_texture_size
,
457 vertically_flip_texture
,
459 kRGBtoGrayscaleColorWeights
));
460 grayscale_scaler
->Scale(src_texture
, dst_texture
);
464 void GLHelper::CopyTextureToImpl::ReadbackAsync(
465 const gfx::Size
& dst_size
,
467 int32 row_stride_bytes
,
471 size_t bytes_per_pixel
,
472 const base::Callback
<void(bool)>& callback
) {
473 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
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(),
487 gl_
->GenQueriesEXT(1, &request
->query
);
488 gl_
->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, request
->query
);
496 gl_
->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
497 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
498 context_support_
->SignalQuery(
500 base::Bind(&CopyTextureToImpl::ReadbackDone
, AsWeakPtr(),
501 request
, bytes_per_pixel
));
504 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
506 const gfx::Size
& src_size
,
507 const gfx::Rect
& src_subrect
,
508 const gfx::Size
& dst_size
,
510 const SkColorType out_color_type
,
511 const base::Callback
<void(bool)>& callback
,
512 GLHelper::ScalerQuality quality
) {
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
) {
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
539 bool scale_texture
= out_color_type
!= kAlpha_8_SkColorType
||
540 quality
!= GLHelper::SCALER_QUALITY_FAST
;
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
546 : supported
== GLHelperReadbackSupport::SWIZZLE
;
548 ScaleTexture(src_texture
,
554 out_color_type
== kAlpha_8_SkColorType
? kN32_SkColorType
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
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
;
570 EncodeTextureAsGrayscale(texture
,
572 &readback_texture_size
,
573 encode_as_grayscale_vertical_flip
,
574 encode_as_grayscale_swizzle
);
575 // If the scaled texture was created - delete it
577 gl_
->DeleteTextures(1, &texture
);
578 texture
= tmp_texture
;
582 // Readback the pixels of the resulting texture
583 ScopedFramebuffer
dst_framebuffer(gl_
);
584 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
586 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
587 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
588 GL_COLOR_ATTACHMENT0
,
593 int32 bytes_per_row
= out_color_type
== kAlpha_8_SkColorType
595 : dst_size
.width() * bytes_per_pixel
;
597 ReadbackAsync(readback_texture_size
,
605 gl_
->DeleteTextures(1, &texture
);
608 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
610 const gfx::Rect
& src_rect
,
612 SkColorType color_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
) {
621 ScopedFramebuffer
dst_framebuffer(gl_
);
622 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
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(),
636 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
638 const gfx::Size
& dst_size
,
640 SkColorType color_type
,
641 const base::Callback
<void(bool)>& callback
) {
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
) {
651 ScopedFramebuffer
dst_framebuffer(gl_
);
652 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
654 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
655 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
656 GL_COLOR_ATTACHMENT0
,
660 ReadbackAsync(dst_size
,
661 dst_size
.width() * bytes_per_pixel
,
662 dst_size
.width() * bytes_per_pixel
,
670 GLuint
GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
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
,
680 vertically_flip_texture
,
682 kRGBA_8888_SkColorType
, // GL_RGBA
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
) {
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
));
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
);
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
);
737 if (request
->buffer
!= 0) {
738 gl_
->DeleteBuffers(1, &request
->buffer
);
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
,
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
)
763 context_support_(context_support
),
764 readback_support_(new GLHelperReadbackSupport(gl
)) {}
766 GLHelper::~GLHelper() {}
768 void GLHelper::CropScaleReadbackAndCleanTexture(
770 const gfx::Size
& src_size
,
771 const gfx::Rect
& src_subrect
,
772 const gfx::Size
& dst_size
,
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
,
788 void GLHelper::CropScaleReadbackAndCleanMailbox(
789 const gpu::Mailbox
& src_mailbox
,
791 const gfx::Size
& src_size
,
792 const gfx::Rect
& src_subrect
,
793 const gfx::Size
& dst_size
,
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
,
807 gl_
->DeleteTextures(1, &mailbox_texture
);
810 void GLHelper::ReadbackTextureSync(GLuint texture
,
811 const gfx::Rect
& src_rect
,
813 SkColorType format
) {
814 InitCopyTextToImpl();
815 copy_texture_to_impl_
->ReadbackTextureSync(texture
, src_rect
, out
, format
);
818 void GLHelper::ReadbackTextureAsync(
820 const gfx::Size
& dst_size
,
822 SkColorType color_type
,
823 const base::Callback
<void(bool)>& callback
) {
824 InitCopyTextToImpl();
825 copy_texture_to_impl_
->ReadbackTextureAsync(texture
,
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
);
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
);
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_|
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_
,
898 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
899 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
900 GL_COLOR_ATTACHMENT0
,
904 for (SkRegion::Iterator
it(region
); !it
.done(); it
.next()) {
905 const SkIRect
& rect
= it
.rect();
906 gl_
->CopyTexSubImage2D(GL_TEXTURE_2D
,
919 GLuint
GLHelper::CreateTexture() {
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
);
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(
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
,
950 if (mailbox
.IsZero())
953 WaitSyncPoint(sync_point
);
955 gl_
->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
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
,
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
,
984 void GLHelper::CopyTextureFullImage(GLuint texture
, const gfx::Size
& size
) {
985 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
987 GL_TEXTURE_2D
, 0, GL_RGB
, 0, 0, size
.width(), size
.height(), 0);
990 void GLHelper::Flush() {
994 void GLHelper::CopyTextureToImpl::ReadbackPlane(
995 TextureFrameBufferPair
* source
,
996 const scoped_refptr
<media::VideoFrame
>& target
,
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
,
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(
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
)
1038 copy_impl_(copy_impl
),
1039 dst_size_(dst_size
),
1040 dst_subrect_(dst_subrect
),
1043 scaler_impl
->CreateScaler(quality
,
1050 scaler_impl
->CreatePlanarScaler(
1054 (dst_subrect
.width() + 3) & ~3,
1055 dst_subrect
.height()),
1056 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
1058 (swizzle
== kSwizzleBGRA
),
1059 kRGBtoYColorWeights
)),
1061 scaler_impl
->CreatePlanarScaler(
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),
1070 (swizzle
== kSwizzleBGRA
),
1071 kRGBtoUColorWeights
)),
1073 scaler_impl
->CreatePlanarScaler(
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),
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
,
1096 callback
.Run(success
);
1099 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1100 const gpu::Mailbox
& mailbox
,
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);
1123 // Read back planes, one at a time. Keep the video frame alive while doing the
1125 copy_impl_
->ReadbackPlane(y_
.texture_and_framebuffer(),
1127 media::VideoFrame::kYPlane
,
1131 base::Bind(&nullcallback
));
1132 copy_impl_
->ReadbackPlane(u_
.texture_and_framebuffer(),
1134 media::VideoFrame::kUPlane
,
1138 base::Bind(&nullcallback
));
1139 copy_impl_
->ReadbackPlane(
1140 v_
.texture_and_framebuffer(),
1142 media::VideoFrame::kVPlane
,
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(
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
)
1165 copy_impl_(copy_impl
),
1166 dst_size_(dst_size
),
1167 dst_subrect_(dst_subrect
),
1171 scaler_impl
->CreateScaler(quality
,
1177 pass1_shader_(scaler_impl
->CreateYuvMrtShader(
1179 gfx::Rect(0, 0, (dst_subrect
.width() + 3) & ~3, dst_subrect
.height()),
1180 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
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()),
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),
1193 (swizzle
== kSwizzleBGRA
),
1194 GLHelperScaling::SHADER_YUV_MRT_PASS2
)),
1195 y_(gl
, gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height())),
1198 gfx::Size((dst_subrect
.width() + 7) / 8,
1199 (dst_subrect
.height() + 1) / 2)),
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
,
1208 (dst_subrect
.width() + 3) / 4,
1209 dst_subrect
.height(),
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
,
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
);
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
;
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();
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);
1262 // Read back planes, one at a time.
1263 copy_impl_
->ReadbackPlane(&y_
,
1265 media::VideoFrame::kYPlane
,
1269 base::Bind(&nullcallback
));
1270 copy_impl_
->ReadbackPlane(&u_
,
1272 media::VideoFrame::kUPlane
,
1276 base::Bind(&nullcallback
));
1277 copy_impl_
->ReadbackPlane(
1280 media::VideoFrame::kVPlane
,
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
,
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_
,
1324 helper_
->scaler_impl_
.get(),
1333 return new ReadbackYUVImpl(gl_
,
1335 helper_
->scaler_impl_
.get(),
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
,
1353 InitCopyTextToImpl();
1354 return copy_texture_to_impl_
->CreateReadbackPipelineYUV(quality
,
1363 } // namespace content