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/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/string_util.h"
16 #include "base/time/time.h"
17 #include "base/trace_event/trace_event.h"
18 #include "content/common/gpu/client/gl_helper_readback_support.h"
19 #include "content/common/gpu/client/gl_helper_scaling.h"
20 #include "gpu/GLES2/gl2extchromium.h"
21 #include "gpu/command_buffer/client/context_support.h"
22 #include "gpu/command_buffer/common/mailbox.h"
23 #include "gpu/command_buffer/common/mailbox_holder.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/video_util.h"
26 #include "third_party/skia/include/core/SkRegion.h"
27 #include "ui/gfx/geometry/point.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/size.h"
31 using gpu::gles2::GLES2Interface
;
37 explicit ScopedFlush(gpu::gles2::GLES2Interface
* gl
) : gl_(gl
) {}
39 ~ScopedFlush() { gl_
->Flush(); }
42 gpu::gles2::GLES2Interface
* gl_
;
44 DISALLOW_COPY_AND_ASSIGN(ScopedFlush
);
47 // Helper class for allocating and holding an RGBA texture of a given
48 // size and an associated framebuffer.
49 class TextureFrameBufferPair
{
51 TextureFrameBufferPair(GLES2Interface
* gl
, gfx::Size size
)
52 : texture_(gl
), framebuffer_(gl
), size_(size
) {
53 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl
, texture_
);
54 gl
->TexImage2D(GL_TEXTURE_2D
,
63 content::ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(
65 gl
->FramebufferTexture2D(
66 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture_
, 0);
69 GLuint
texture() const { return texture_
.id(); }
70 GLuint
framebuffer() const { return framebuffer_
.id(); }
71 gfx::Size
size() const { return size_
; }
74 content::ScopedTexture texture_
;
75 content::ScopedFramebuffer framebuffer_
;
78 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair
);
81 // Helper class for holding a scaler, a texture for the output of that
82 // scaler and an associated frame buffer. This is inteded to be used
83 // when the output of a scaler is to be sent to a readback.
86 ScalerHolder(GLES2Interface
* gl
, content::GLHelper::ScalerInterface
* scaler
)
87 : texture_and_framebuffer_(gl
, scaler
->DstSize()), scaler_(scaler
) {}
89 void Scale(GLuint src_texture
) {
90 scaler_
->Scale(src_texture
, texture_and_framebuffer_
.texture());
93 content::GLHelper::ScalerInterface
* scaler() const { return scaler_
.get(); }
94 TextureFrameBufferPair
* texture_and_framebuffer() {
95 return &texture_and_framebuffer_
;
97 GLuint
texture() const { return texture_and_framebuffer_
.texture(); }
100 TextureFrameBufferPair texture_and_framebuffer_
;
101 scoped_ptr
<content::GLHelper::ScalerInterface
> scaler_
;
103 DISALLOW_COPY_AND_ASSIGN(ScalerHolder
);
109 typedef GLHelperReadbackSupport::FormatSupport FormatSupport
;
111 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
112 // the data needed for it.
113 class GLHelper::CopyTextureToImpl
114 : public base::SupportsWeakPtr
<GLHelper::CopyTextureToImpl
> {
116 CopyTextureToImpl(GLES2Interface
* gl
,
117 gpu::ContextSupport
* context_support
,
120 context_support_(context_support
),
123 max_draw_buffers_(0) {
124 const GLubyte
* extensions
= gl_
->GetString(GL_EXTENSIONS
);
127 std::string extensions_string
=
128 " " + std::string(reinterpret_cast<const char*>(extensions
)) + " ";
129 if (extensions_string
.find(" GL_EXT_draw_buffers ") != std::string::npos
) {
130 gl_
->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT
, &max_draw_buffers_
);
133 ~CopyTextureToImpl() { CancelRequests(); }
135 GLuint
ConsumeMailboxToTexture(const gpu::Mailbox
& mailbox
,
137 return helper_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
140 void CropScaleReadbackAndCleanTexture(
142 const gfx::Size
& src_size
,
143 const gfx::Rect
& src_subrect
,
144 const gfx::Size
& dst_size
,
146 const SkColorType out_color_type
,
147 const base::Callback
<void(bool)>& callback
,
148 GLHelper::ScalerQuality quality
);
150 void ReadbackTextureSync(GLuint texture
,
151 const gfx::Rect
& src_rect
,
155 void ReadbackTextureAsync(GLuint texture
,
156 const gfx::Size
& dst_size
,
158 SkColorType color_type
,
159 const base::Callback
<void(bool)>& callback
);
161 // Reads back bytes from the currently bound frame buffer.
162 // Note that dst_size is specified in bytes, not pixels.
163 void ReadbackAsync(const gfx::Size
& dst_size
,
164 int32 bytes_per_row
, // generally dst_size.width() * 4
165 int32 row_stride_bytes
, // generally dst_size.width() * 4
169 size_t bytes_per_pixel
,
170 const base::Callback
<void(bool)>& callback
);
172 void ReadbackPlane(TextureFrameBufferPair
* source
,
173 const scoped_refptr
<media::VideoFrame
>& target
,
176 const gfx::Rect
& paste_rect
,
177 ReadbackSwizzle swizzle
,
178 const base::Callback
<void(bool)>& callback
);
180 GLuint
CopyAndScaleTexture(GLuint texture
,
181 const gfx::Size
& src_size
,
182 const gfx::Size
& dst_size
,
183 bool vertically_flip_texture
,
184 GLHelper::ScalerQuality quality
);
186 ReadbackYUVInterface
* CreateReadbackPipelineYUV(
187 GLHelper::ScalerQuality quality
,
188 const gfx::Size
& src_size
,
189 const gfx::Rect
& src_subrect
,
190 const gfx::Size
& dst_size
,
191 bool flip_vertically
,
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_
),
231 int row_stride_bytes
;
232 unsigned char* pixels
;
233 base::Callback
<void(bool)> callback
;
238 // We must take care to call the callbacks last, as they may
239 // end up destroying the gl_helper and make *this invalid.
240 // We stick the finished requests in a stack object that calls
241 // the callbacks when it goes out of scope.
242 class FinishRequestHelper
{
244 FinishRequestHelper() {}
245 ~FinishRequestHelper() {
246 while (!requests_
.empty()) {
247 Request
* request
= requests_
.front();
249 request
->callback
.Run(request
->result
);
253 void Add(Request
* r
) {
257 std::queue
<Request
*> requests_
;
258 DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper
);
261 // A readback pipeline that also converts the data to YUV before
263 class ReadbackYUVImpl
: public ReadbackYUVInterface
{
265 ReadbackYUVImpl(GLES2Interface
* gl
,
266 CopyTextureToImpl
* copy_impl
,
267 GLHelperScaling
* scaler_impl
,
268 GLHelper::ScalerQuality quality
,
269 const gfx::Size
& src_size
,
270 const gfx::Rect
& src_subrect
,
271 const gfx::Size
& dst_size
,
272 bool flip_vertically
,
273 ReadbackSwizzle swizzle
);
275 void ReadbackYUV(const gpu::Mailbox
& mailbox
,
277 const scoped_refptr
<media::VideoFrame
>& target
,
278 const gfx::Point
& paste_location
,
279 const base::Callback
<void(bool)>& callback
) override
;
281 ScalerInterface
* scaler() override
{ return scaler_
.scaler(); }
285 CopyTextureToImpl
* copy_impl_
;
287 ReadbackSwizzle swizzle_
;
288 ScalerHolder scaler_
;
293 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl
);
296 // A readback pipeline that also converts the data to YUV before
297 // reading it back. This one uses Multiple Render Targets, which
298 // may not be supported on all platforms.
299 class ReadbackYUV_MRT
: public ReadbackYUVInterface
{
301 ReadbackYUV_MRT(GLES2Interface
* gl
,
302 CopyTextureToImpl
* copy_impl
,
303 GLHelperScaling
* scaler_impl
,
304 GLHelper::ScalerQuality quality
,
305 const gfx::Size
& src_size
,
306 const gfx::Rect
& src_subrect
,
307 const gfx::Size
& dst_size
,
308 bool flip_vertically
,
309 ReadbackSwizzle swizzle
);
311 void ReadbackYUV(const gpu::Mailbox
& mailbox
,
313 const scoped_refptr
<media::VideoFrame
>& target
,
314 const gfx::Point
& paste_location
,
315 const base::Callback
<void(bool)>& callback
) override
;
317 ScalerInterface
* scaler() override
{ return scaler_
.scaler(); }
321 CopyTextureToImpl
* copy_impl_
;
323 GLHelper::ScalerQuality quality_
;
324 ReadbackSwizzle swizzle_
;
325 ScalerHolder scaler_
;
326 scoped_ptr
<content::GLHelperScaling::ShaderInterface
> pass1_shader_
;
327 scoped_ptr
<content::GLHelperScaling::ShaderInterface
> pass2_shader_
;
328 TextureFrameBufferPair y_
;
330 TextureFrameBufferPair u_
;
331 TextureFrameBufferPair v_
;
333 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT
);
336 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
337 // scales it to |dst_size|, writes it into a texture, and returns its ID.
338 // |src_size| is the size of |src_texture|.
339 GLuint
ScaleTexture(GLuint src_texture
,
340 const gfx::Size
& src_size
,
341 const gfx::Rect
& src_subrect
,
342 const gfx::Size
& dst_size
,
343 bool vertically_flip_texture
,
345 SkColorType color_type
,
346 GLHelper::ScalerQuality quality
);
348 // Converts each four consecutive pixels of the source texture into one pixel
349 // in the result texture with each pixel channel representing the grayscale
350 // color of one of the four original pixels:
351 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
352 // The resulting texture is still an RGBA texture (which is ~4 times narrower
353 // than the original). If rendered directly, it wouldn't show anything useful,
354 // but the data in it can be used to construct a grayscale image.
355 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
356 // is equal to src_size.width()/4 rounded upwards. Some channels in the last
357 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
359 // If swizzle is set to true, the transformed pixels are reordered:
360 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
361 GLuint
EncodeTextureAsGrayscale(GLuint src_texture
,
362 const gfx::Size
& src_size
,
363 gfx::Size
* const encoded_texture_size
,
364 bool vertically_flip_texture
,
367 static void nullcallback(bool success
) {}
368 void ReadbackDone(Request
*request
, int bytes_per_pixel
);
369 void FinishRequest(Request
* request
,
371 FinishRequestHelper
* helper
);
372 void CancelRequests();
374 static const float kRGBtoYColorWeights
[];
375 static const float kRGBtoUColorWeights
[];
376 static const float kRGBtoVColorWeights
[];
377 static const float kRGBtoGrayscaleColorWeights
[];
380 gpu::ContextSupport
* context_support_
;
383 // A scoped flush that will ensure all resource deletions are flushed when
384 // this object is destroyed. Must be declared before other Scoped* fields.
387 std::queue
<Request
*> request_queue_
;
388 GLint max_draw_buffers_
;
391 GLHelper::ScalerInterface
* GLHelper::CreateScaler(ScalerQuality quality
,
392 const gfx::Size
& src_size
,
393 const gfx::Rect
& src_subrect
,
394 const gfx::Size
& dst_size
,
395 bool vertically_flip_texture
,
398 return scaler_impl_
->CreateScaler(quality
,
402 vertically_flip_texture
,
406 GLuint
GLHelper::CopyTextureToImpl::ScaleTexture(
408 const gfx::Size
& src_size
,
409 const gfx::Rect
& src_subrect
,
410 const gfx::Size
& dst_size
,
411 bool vertically_flip_texture
,
413 SkColorType color_type
,
414 GLHelper::ScalerQuality quality
) {
415 GLuint dst_texture
= 0u;
416 gl_
->GenTextures(1, &dst_texture
);
418 GLenum format
= GL_RGBA
, type
= GL_UNSIGNED_BYTE
;
419 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, dst_texture
);
421 // Use GL_RGBA for destination/temporary texture unless we're working with
423 if (color_type
== kRGB_565_SkColorType
) {
425 type
= GL_UNSIGNED_SHORT_5_6_5
;
428 gl_
->TexImage2D(GL_TEXTURE_2D
,
438 scoped_ptr
<ScalerInterface
> scaler(
439 helper_
->CreateScaler(quality
,
443 vertically_flip_texture
,
445 scaler
->Scale(src_texture
, dst_texture
);
449 GLuint
GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
451 const gfx::Size
& src_size
,
452 gfx::Size
* const encoded_texture_size
,
453 bool vertically_flip_texture
,
455 GLuint dst_texture
= 0u;
456 gl_
->GenTextures(1, &dst_texture
);
457 // The size of the encoded texture.
458 *encoded_texture_size
=
459 gfx::Size((src_size
.width() + 3) / 4, src_size
.height());
461 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, dst_texture
);
462 gl_
->TexImage2D(GL_TEXTURE_2D
,
465 encoded_texture_size
->width(),
466 encoded_texture_size
->height(),
473 helper_
->InitScalerImpl();
474 scoped_ptr
<ScalerInterface
> grayscale_scaler(
475 helper_
->scaler_impl_
.get()->CreatePlanarScaler(
477 gfx::Rect(0, 0, (src_size
.width() + 3) & ~3, src_size
.height()),
478 *encoded_texture_size
,
479 vertically_flip_texture
,
481 kRGBtoGrayscaleColorWeights
));
482 grayscale_scaler
->Scale(src_texture
, dst_texture
);
486 void GLHelper::CopyTextureToImpl::ReadbackAsync(
487 const gfx::Size
& dst_size
,
489 int32 row_stride_bytes
,
493 size_t bytes_per_pixel
,
494 const base::Callback
<void(bool)>& callback
) {
495 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync");
497 new Request(dst_size
, bytes_per_row
, row_stride_bytes
, out
, callback
);
498 request_queue_
.push(request
);
499 request
->buffer
= 0u;
501 gl_
->GenBuffers(1, &request
->buffer
);
502 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, request
->buffer
);
503 gl_
->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
504 bytes_per_pixel
* dst_size
.GetArea(),
509 gl_
->GenQueriesEXT(1, &request
->query
);
510 gl_
->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, request
->query
);
518 gl_
->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
519 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
520 context_support_
->SignalQuery(
522 base::Bind(&CopyTextureToImpl::ReadbackDone
, AsWeakPtr(),
523 request
, bytes_per_pixel
));
526 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
528 const gfx::Size
& src_size
,
529 const gfx::Rect
& src_subrect
,
530 const gfx::Size
& dst_size
,
532 const SkColorType out_color_type
,
533 const base::Callback
<void(bool)>& callback
,
534 GLHelper::ScalerQuality quality
) {
536 size_t bytes_per_pixel
;
537 SkColorType readback_color_type
= out_color_type
;
538 // Single-component textures are not supported by all GPUs, so we implement
539 // kAlpha_8_SkColorType support here via a special encoding (see below) using
540 // a 32-bit texture to represent an 8-bit image.
541 // Thus we use generic 32-bit readback in this case.
542 if (out_color_type
== kAlpha_8_SkColorType
) {
543 readback_color_type
= kRGBA_8888_SkColorType
;
546 FormatSupport supported
= GetReadbackConfig(
547 readback_color_type
, true, &format
, &type
, &bytes_per_pixel
);
549 if (supported
== GLHelperReadbackSupport::NOT_SUPPORTED
) {
554 GLuint texture
= src_texture
;
556 // Scale texture if needed
557 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
558 // can do just as well in EncodeTextureAsGrayscale, which we will do if
559 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
561 bool scale_texture
= out_color_type
!= kAlpha_8_SkColorType
||
562 quality
!= GLHelper::SCALER_QUALITY_FAST
;
564 // Don't swizzle during the scale step for kAlpha_8_SkColorType.
565 // We will swizzle in the encode step below if needed.
566 bool scale_swizzle
= out_color_type
== kAlpha_8_SkColorType
568 : supported
== GLHelperReadbackSupport::SWIZZLE
;
570 ScaleTexture(src_texture
,
576 out_color_type
== kAlpha_8_SkColorType
? kN32_SkColorType
582 gfx::Size readback_texture_size
= dst_size
;
583 // Encode texture to grayscale if needed.
584 if (out_color_type
== kAlpha_8_SkColorType
) {
585 // Do the vertical flip here if we haven't already done it when we scaled
587 bool encode_as_grayscale_vertical_flip
= !scale_texture
;
588 // EncodeTextureAsGrayscale by default creates a texture which should be
589 // read back as RGBA, so need to swizzle if the readback format is BGRA.
590 bool encode_as_grayscale_swizzle
= format
== GL_BGRA_EXT
;
592 EncodeTextureAsGrayscale(texture
,
594 &readback_texture_size
,
595 encode_as_grayscale_vertical_flip
,
596 encode_as_grayscale_swizzle
);
597 // If the scaled texture was created - delete it
599 gl_
->DeleteTextures(1, &texture
);
600 texture
= tmp_texture
;
604 // Readback the pixels of the resulting texture
605 ScopedFramebuffer
dst_framebuffer(gl_
);
606 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
608 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
609 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
610 GL_COLOR_ATTACHMENT0
,
615 int32 bytes_per_row
= out_color_type
== kAlpha_8_SkColorType
617 : dst_size
.width() * bytes_per_pixel
;
619 ReadbackAsync(readback_texture_size
,
627 gl_
->DeleteTextures(1, &texture
);
630 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
632 const gfx::Rect
& src_rect
,
634 SkColorType color_type
) {
636 size_t bytes_per_pixel
;
637 FormatSupport supported
=
638 GetReadbackConfig(color_type
, false, &format
, &type
, &bytes_per_pixel
);
639 if (supported
== GLHelperReadbackSupport::NOT_SUPPORTED
) {
643 ScopedFramebuffer
dst_framebuffer(gl_
);
644 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
646 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
647 gl_
->FramebufferTexture2D(
648 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture
, 0);
649 gl_
->ReadPixels(src_rect
.x(),
658 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
660 const gfx::Size
& dst_size
,
662 SkColorType color_type
,
663 const base::Callback
<void(bool)>& callback
) {
665 size_t bytes_per_pixel
;
666 FormatSupport supported
=
667 GetReadbackConfig(color_type
, false, &format
, &type
, &bytes_per_pixel
);
668 if (supported
== GLHelperReadbackSupport::NOT_SUPPORTED
) {
673 ScopedFramebuffer
dst_framebuffer(gl_
);
674 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
676 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
677 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
678 GL_COLOR_ATTACHMENT0
,
682 ReadbackAsync(dst_size
,
683 dst_size
.width() * bytes_per_pixel
,
684 dst_size
.width() * bytes_per_pixel
,
692 GLuint
GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
694 const gfx::Size
& src_size
,
695 const gfx::Size
& dst_size
,
696 bool vertically_flip_texture
,
697 GLHelper::ScalerQuality quality
) {
698 return ScaleTexture(src_texture
,
702 vertically_flip_texture
,
704 kRGBA_8888_SkColorType
, // GL_RGBA
708 void GLHelper::CopyTextureToImpl::ReadbackDone(Request
* finished_request
,
709 int bytes_per_pixel
) {
710 TRACE_EVENT0("gpu.capture",
711 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
712 finished_request
->done
= true;
714 FinishRequestHelper finish_request_helper
;
716 // We process transfer requests in the order they were received, regardless
717 // of the order we get the callbacks in.
718 while (!request_queue_
.empty()) {
719 Request
* request
= request_queue_
.front();
720 if (!request
->done
) {
725 if (request
->buffer
!= 0) {
726 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, request
->buffer
);
727 unsigned char* data
= static_cast<unsigned char*>(gl_
->MapBufferCHROMIUM(
728 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, GL_READ_ONLY
));
731 if (request
->bytes_per_row
== request
->size
.width() * bytes_per_pixel
&&
732 request
->bytes_per_row
== request
->row_stride_bytes
) {
733 memcpy(request
->pixels
, data
,
734 request
->size
.GetArea() * bytes_per_pixel
);
736 unsigned char* out
= request
->pixels
;
737 for (int y
= 0; y
< request
->size
.height(); y
++) {
738 memcpy(out
, data
, request
->bytes_per_row
);
739 out
+= request
->row_stride_bytes
;
740 data
+= request
->size
.width() * bytes_per_pixel
;
743 gl_
->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
);
745 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
747 FinishRequest(request
, result
, &finish_request_helper
);
751 void GLHelper::CopyTextureToImpl::FinishRequest(
754 FinishRequestHelper
* finish_request_helper
) {
755 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest");
756 DCHECK(request_queue_
.front() == request
);
757 request_queue_
.pop();
758 request
->result
= result
;
759 ScopedFlush
flush(gl_
);
760 if (request
->query
!= 0) {
761 gl_
->DeleteQueriesEXT(1, &request
->query
);
764 if (request
->buffer
!= 0) {
765 gl_
->DeleteBuffers(1, &request
->buffer
);
768 finish_request_helper
->Add(request
);
771 void GLHelper::CopyTextureToImpl::CancelRequests() {
772 FinishRequestHelper finish_request_helper
;
773 while (!request_queue_
.empty()) {
774 Request
* request
= request_queue_
.front();
775 FinishRequest(request
, false, &finish_request_helper
);
779 FormatSupport
GLHelper::CopyTextureToImpl::GetReadbackConfig(
780 SkColorType color_type
,
784 size_t* bytes_per_pixel
) {
785 return helper_
->readback_support_
->GetReadbackConfig(
786 color_type
, can_swizzle
, format
, type
, bytes_per_pixel
);
789 GLHelper::GLHelper(GLES2Interface
* gl
, gpu::ContextSupport
* context_support
)
791 context_support_(context_support
),
792 readback_support_(new GLHelperReadbackSupport(gl
)) {}
794 GLHelper::~GLHelper() {}
796 void GLHelper::CropScaleReadbackAndCleanTexture(
798 const gfx::Size
& src_size
,
799 const gfx::Rect
& src_subrect
,
800 const gfx::Size
& dst_size
,
802 const SkColorType out_color_type
,
803 const base::Callback
<void(bool)>& callback
,
804 GLHelper::ScalerQuality quality
) {
805 InitCopyTextToImpl();
806 copy_texture_to_impl_
->CropScaleReadbackAndCleanTexture(src_texture
,
816 void GLHelper::CropScaleReadbackAndCleanMailbox(
817 const gpu::Mailbox
& src_mailbox
,
819 const gfx::Size
& src_size
,
820 const gfx::Rect
& src_subrect
,
821 const gfx::Size
& dst_size
,
823 const SkColorType out_color_type
,
824 const base::Callback
<void(bool)>& callback
,
825 GLHelper::ScalerQuality quality
) {
826 GLuint mailbox_texture
= ConsumeMailboxToTexture(src_mailbox
, sync_point
);
827 CropScaleReadbackAndCleanTexture(mailbox_texture
,
835 gl_
->DeleteTextures(1, &mailbox_texture
);
838 void GLHelper::ReadbackTextureSync(GLuint texture
,
839 const gfx::Rect
& src_rect
,
841 SkColorType format
) {
842 InitCopyTextToImpl();
843 copy_texture_to_impl_
->ReadbackTextureSync(texture
, src_rect
, out
, format
);
846 void GLHelper::ReadbackTextureAsync(
848 const gfx::Size
& dst_size
,
850 SkColorType color_type
,
851 const base::Callback
<void(bool)>& callback
) {
852 InitCopyTextToImpl();
853 copy_texture_to_impl_
->ReadbackTextureAsync(texture
,
860 GLuint
GLHelper::CopyTexture(GLuint texture
, const gfx::Size
& size
) {
861 InitCopyTextToImpl();
862 return copy_texture_to_impl_
->CopyAndScaleTexture(
863 texture
, size
, size
, false, GLHelper::SCALER_QUALITY_FAST
);
866 GLuint
GLHelper::CopyAndScaleTexture(GLuint texture
,
867 const gfx::Size
& src_size
,
868 const gfx::Size
& dst_size
,
869 bool vertically_flip_texture
,
870 ScalerQuality quality
) {
871 InitCopyTextToImpl();
872 return copy_texture_to_impl_
->CopyAndScaleTexture(
873 texture
, src_size
, dst_size
, vertically_flip_texture
, quality
);
876 GLuint
GLHelper::CompileShaderFromSource(const GLchar
* source
, GLenum type
) {
877 GLuint shader
= gl_
->CreateShader(type
);
878 GLint length
= strlen(source
);
879 gl_
->ShaderSource(shader
, 1, &source
, &length
);
880 gl_
->CompileShader(shader
);
881 GLint compile_status
= 0;
882 gl_
->GetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
883 if (!compile_status
) {
884 GLint log_length
= 0;
885 gl_
->GetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &log_length
);
887 scoped_ptr
<GLchar
[]> log(new GLchar
[log_length
]);
888 GLsizei returned_log_length
= 0;
889 gl_
->GetShaderInfoLog(
890 shader
, log_length
, &returned_log_length
, log
.get());
891 LOG(ERROR
) << std::string(log
.get(), returned_log_length
);
893 gl_
->DeleteShader(shader
);
899 void GLHelper::InitCopyTextToImpl() {
900 // Lazily initialize |copy_texture_to_impl_|
901 if (!copy_texture_to_impl_
)
902 copy_texture_to_impl_
.reset(
903 new CopyTextureToImpl(gl_
, context_support_
, this));
906 void GLHelper::InitScalerImpl() {
907 // Lazily initialize |scaler_impl_|
909 scaler_impl_
.reset(new GLHelperScaling(gl_
, this));
912 GLint
GLHelper::MaxDrawBuffers() {
913 InitCopyTextToImpl();
914 return copy_texture_to_impl_
->MaxDrawBuffers();
917 void GLHelper::CopySubBufferDamage(GLenum target
,
919 GLuint previous_texture
,
920 const SkRegion
& new_damage
,
921 const SkRegion
& old_damage
) {
922 SkRegion
region(old_damage
);
923 if (region
.op(new_damage
, SkRegion::kDifference_Op
)) {
924 ScopedFramebuffer
dst_framebuffer(gl_
);
925 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
927 gl_
->BindTexture(target
, texture
);
928 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, target
,
929 previous_texture
, 0);
930 for (SkRegion::Iterator
it(region
); !it
.done(); it
.next()) {
931 const SkIRect
& rect
= it
.rect();
932 gl_
->CopyTexSubImage2D(target
, 0, rect
.x(), rect
.y(), rect
.x(), rect
.y(),
933 rect
.width(), rect
.height());
935 gl_
->BindTexture(target
, 0);
940 GLuint
GLHelper::CreateTexture() {
942 gl_
->GenTextures(1, &texture
);
943 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
944 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
945 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
946 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
947 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
951 void GLHelper::DeleteTexture(GLuint texture_id
) {
952 gl_
->DeleteTextures(1, &texture_id
);
955 uint32
GLHelper::InsertSyncPoint() { return gl_
->InsertSyncPointCHROMIUM(); }
957 void GLHelper::WaitSyncPoint(uint32 sync_point
) {
958 gl_
->WaitSyncPointCHROMIUM(sync_point
);
961 gpu::MailboxHolder
GLHelper::ProduceMailboxHolderFromTexture(
963 gpu::Mailbox mailbox
;
964 gl_
->GenMailboxCHROMIUM(mailbox
.name
);
965 gl_
->ProduceTextureDirectCHROMIUM(texture_id
, GL_TEXTURE_2D
, mailbox
.name
);
966 return gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, InsertSyncPoint());
969 GLuint
GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox
& mailbox
,
971 if (mailbox
.IsZero())
974 WaitSyncPoint(sync_point
);
976 gl_
->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
980 void GLHelper::ResizeTexture(GLuint texture
, const gfx::Size
& size
) {
981 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
982 gl_
->TexImage2D(GL_TEXTURE_2D
,
993 void GLHelper::CopyTextureSubImage(GLuint texture
, const gfx::Rect
& rect
) {
994 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
995 gl_
->CopyTexSubImage2D(GL_TEXTURE_2D
,
1005 void GLHelper::CopyTextureFullImage(GLuint texture
, const gfx::Size
& size
) {
1006 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
1007 gl_
->CopyTexImage2D(
1008 GL_TEXTURE_2D
, 0, GL_RGB
, 0, 0, size
.width(), size
.height(), 0);
1011 void GLHelper::Flush() {
1015 void GLHelper::InsertOrderingBarrier() {
1016 gl_
->OrderingBarrierCHROMIUM();
1019 void GLHelper::CopyTextureToImpl::ReadbackPlane(
1020 TextureFrameBufferPair
* source
,
1021 const scoped_refptr
<media::VideoFrame
>& target
,
1024 const gfx::Rect
& paste_rect
,
1025 ReadbackSwizzle swizzle
,
1026 const base::Callback
<void(bool)>& callback
) {
1027 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, source
->framebuffer());
1028 const size_t offset
= target
->stride(plane
) * (paste_rect
.y() >> size_shift
) +
1029 (paste_rect
.x() >> size_shift
);
1030 ReadbackAsync(source
->size(),
1031 paste_rect
.width() >> size_shift
,
1032 target
->stride(plane
),
1033 target
->data(plane
) + offset
,
1034 (swizzle
== kSwizzleBGRA
) ? GL_BGRA_EXT
: GL_RGBA
,
1040 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights
[] = {
1041 0.257f
, 0.504f
, 0.098f
, 0.0625f
};
1042 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights
[] = {
1043 -0.148f
, -0.291f
, 0.439f
, 0.5f
};
1044 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights
[] = {
1045 0.439f
, -0.368f
, -0.071f
, 0.5f
};
1046 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights
[] = {
1047 0.213f
, 0.715f
, 0.072f
, 0.0f
};
1049 // YUV readback constructors. Initiates the main scaler pipeline and
1050 // one planar scaler for each of the Y, U and V planes.
1051 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
1053 CopyTextureToImpl
* copy_impl
,
1054 GLHelperScaling
* scaler_impl
,
1055 GLHelper::ScalerQuality quality
,
1056 const gfx::Size
& src_size
,
1057 const gfx::Rect
& src_subrect
,
1058 const gfx::Size
& dst_size
,
1059 bool flip_vertically
,
1060 ReadbackSwizzle swizzle
)
1062 copy_impl_(copy_impl
),
1063 dst_size_(dst_size
),
1066 scaler_impl
->CreateScaler(quality
,
1073 scaler_impl
->CreatePlanarScaler(
1077 (dst_size
.width() + 3) & ~3,
1079 gfx::Size((dst_size
.width() + 3) / 4, dst_size
.height()),
1081 (swizzle
== kSwizzleBGRA
),
1082 kRGBtoYColorWeights
)),
1084 scaler_impl
->CreatePlanarScaler(
1088 (dst_size
.width() + 7) & ~7,
1089 (dst_size
.height() + 1) & ~1),
1090 gfx::Size((dst_size
.width() + 7) / 8,
1091 (dst_size
.height() + 1) / 2),
1093 (swizzle
== kSwizzleBGRA
),
1094 kRGBtoUColorWeights
)),
1096 scaler_impl
->CreatePlanarScaler(
1100 (dst_size
.width() + 7) & ~7,
1101 (dst_size
.height() + 1) & ~1),
1102 gfx::Size((dst_size
.width() + 7) / 8,
1103 (dst_size
.height() + 1) / 2),
1105 (swizzle
== kSwizzleBGRA
),
1106 kRGBtoVColorWeights
)) {
1107 DCHECK(!(dst_size
.width() & 1));
1108 DCHECK(!(dst_size
.height() & 1));
1111 static void CallbackKeepingVideoFrameAlive(
1112 scoped_refptr
<media::VideoFrame
> video_frame
,
1113 const base::Callback
<void(bool)>& callback
,
1115 callback
.Run(success
);
1118 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1119 const gpu::Mailbox
& mailbox
,
1121 const scoped_refptr
<media::VideoFrame
>& target
,
1122 const gfx::Point
& paste_location
,
1123 const base::Callback
<void(bool)>& callback
) {
1124 DCHECK(!(paste_location
.x() & 1));
1125 DCHECK(!(paste_location
.y() & 1));
1127 GLuint mailbox_texture
=
1128 copy_impl_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
1130 // Scale texture to right size.
1131 scaler_
.Scale(mailbox_texture
);
1132 gl_
->DeleteTextures(1, &mailbox_texture
);
1134 // Convert the scaled texture in to Y, U and V planes.
1135 y_
.Scale(scaler_
.texture());
1136 u_
.Scale(scaler_
.texture());
1137 v_
.Scale(scaler_
.texture());
1139 const gfx::Rect
paste_rect(paste_location
, dst_size_
);
1140 if (!target
->visible_rect().Contains(paste_rect
)) {
1141 LOG(DFATAL
) << "Paste rect not inside VideoFrame's visible rect!";
1142 callback
.Run(false);
1146 // Read back planes, one at a time. Keep the video frame alive while doing the
1148 copy_impl_
->ReadbackPlane(y_
.texture_and_framebuffer(),
1150 media::VideoFrame::kYPlane
,
1154 base::Bind(&nullcallback
));
1155 copy_impl_
->ReadbackPlane(u_
.texture_and_framebuffer(),
1157 media::VideoFrame::kUPlane
,
1161 base::Bind(&nullcallback
));
1162 copy_impl_
->ReadbackPlane(
1163 v_
.texture_and_framebuffer(),
1165 media::VideoFrame::kVPlane
,
1169 base::Bind(&CallbackKeepingVideoFrameAlive
, target
, callback
));
1170 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, 0);
1171 media::LetterboxYUV(target
.get(), paste_rect
);
1174 // YUV readback constructors. Initiates the main scaler pipeline and
1175 // one planar scaler for each of the Y, U and V planes.
1176 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1178 CopyTextureToImpl
* copy_impl
,
1179 GLHelperScaling
* scaler_impl
,
1180 GLHelper::ScalerQuality quality
,
1181 const gfx::Size
& src_size
,
1182 const gfx::Rect
& src_subrect
,
1183 const gfx::Size
& dst_size
,
1184 bool flip_vertically
,
1185 ReadbackSwizzle swizzle
)
1187 copy_impl_(copy_impl
),
1188 dst_size_(dst_size
),
1192 scaler_impl
->CreateScaler(quality
,
1198 pass1_shader_(scaler_impl
->CreateYuvMrtShader(
1200 gfx::Rect(0, 0, (dst_size
.width() + 3) & ~3, dst_size
.height()),
1201 gfx::Size((dst_size
.width() + 3) / 4, dst_size
.height()),
1203 (swizzle
== kSwizzleBGRA
),
1204 GLHelperScaling::SHADER_YUV_MRT_PASS1
)),
1205 pass2_shader_(scaler_impl
->CreateYuvMrtShader(
1206 gfx::Size((dst_size
.width() + 3) / 4, dst_size
.height()),
1209 (dst_size
.width() + 7) / 8 * 2,
1211 gfx::Size((dst_size
.width() + 7) / 8,
1212 (dst_size
.height() + 1) / 2),
1214 (swizzle
== kSwizzleBGRA
),
1215 GLHelperScaling::SHADER_YUV_MRT_PASS2
)),
1216 y_(gl
, gfx::Size((dst_size
.width() + 3) / 4, dst_size
.height())),
1219 gfx::Size((dst_size
.width() + 7) / 8,
1220 (dst_size
.height() + 1) / 2)),
1222 gfx::Size((dst_size
.width() + 7) / 8,
1223 (dst_size
.height() + 1) / 2)) {
1224 DCHECK(!(dst_size
.width() & 1));
1225 DCHECK(!(dst_size
.height() & 1));
1227 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl
, uv_
);
1228 gl
->TexImage2D(GL_TEXTURE_2D
,
1231 (dst_size
.width() + 3) / 4,
1239 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1240 const gpu::Mailbox
& mailbox
,
1242 const scoped_refptr
<media::VideoFrame
>& target
,
1243 const gfx::Point
& paste_location
,
1244 const base::Callback
<void(bool)>& callback
) {
1245 DCHECK(!(paste_location
.x() & 1));
1246 DCHECK(!(paste_location
.y() & 1));
1248 GLuint mailbox_texture
=
1249 copy_impl_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
1252 if (quality_
== GLHelper::SCALER_QUALITY_FAST
) {
1253 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1254 // pass, which pass1_shader_ can do just as well, so let's skip
1255 // the actual scaling in that case.
1256 texture
= mailbox_texture
;
1258 // Scale texture to right size.
1259 scaler_
.Scale(mailbox_texture
);
1260 texture
= scaler_
.texture();
1263 std::vector
<GLuint
> outputs(2);
1264 // Convert the scaled texture in to Y, U and V planes.
1265 outputs
[0] = y_
.texture();
1267 pass1_shader_
->Execute(texture
, outputs
);
1269 gl_
->DeleteTextures(1, &mailbox_texture
);
1271 outputs
[0] = u_
.texture();
1272 outputs
[1] = v_
.texture();
1273 pass2_shader_
->Execute(uv_
, outputs
);
1275 const gfx::Rect
paste_rect(paste_location
, dst_size_
);
1276 if (!target
->visible_rect().Contains(paste_rect
)) {
1277 LOG(DFATAL
) << "Paste rect not inside VideoFrame's visible rect!";
1278 callback
.Run(false);
1282 // Read back planes, one at a time.
1283 copy_impl_
->ReadbackPlane(&y_
,
1285 media::VideoFrame::kYPlane
,
1289 base::Bind(&nullcallback
));
1290 copy_impl_
->ReadbackPlane(&u_
,
1292 media::VideoFrame::kUPlane
,
1296 base::Bind(&nullcallback
));
1297 copy_impl_
->ReadbackPlane(
1300 media::VideoFrame::kVPlane
,
1304 base::Bind(&CallbackKeepingVideoFrameAlive
, target
, callback
));
1305 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, 0);
1306 media::LetterboxYUV(target
.get(), paste_rect
);
1309 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type
) {
1310 DCHECK(readback_support_
.get());
1311 GLenum format
, type
;
1312 size_t bytes_per_pixel
;
1313 FormatSupport support
= readback_support_
->GetReadbackConfig(
1314 color_type
, false, &format
, &type
, &bytes_per_pixel
);
1316 return (support
== GLHelperReadbackSupport::SUPPORTED
);
1319 ReadbackYUVInterface
* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1320 GLHelper::ScalerQuality quality
,
1321 const gfx::Size
& src_size
,
1322 const gfx::Rect
& src_subrect
,
1323 const gfx::Size
& dst_size
,
1324 bool flip_vertically
,
1326 helper_
->InitScalerImpl();
1327 // Just query if the best readback configuration needs a swizzle In
1328 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
1329 GLenum format
, type
;
1330 size_t bytes_per_pixel
;
1331 FormatSupport supported
= GetReadbackConfig(
1332 kRGBA_8888_SkColorType
, true, &format
, &type
, &bytes_per_pixel
);
1333 DCHECK((format
== GL_RGBA
|| format
== GL_BGRA_EXT
) &&
1334 type
== GL_UNSIGNED_BYTE
);
1336 ReadbackSwizzle swizzle
= kSwizzleNone
;
1337 if (supported
== GLHelperReadbackSupport::SWIZZLE
)
1338 swizzle
= kSwizzleBGRA
;
1340 if (max_draw_buffers_
>= 2 && use_mrt
) {
1341 return new ReadbackYUV_MRT(gl_
,
1343 helper_
->scaler_impl_
.get(),
1351 return new ReadbackYUVImpl(gl_
,
1353 helper_
->scaler_impl_
.get(),
1362 ReadbackYUVInterface
* GLHelper::CreateReadbackPipelineYUV(
1363 ScalerQuality quality
,
1364 const gfx::Size
& src_size
,
1365 const gfx::Rect
& src_subrect
,
1366 const gfx::Size
& dst_size
,
1367 bool flip_vertically
,
1369 InitCopyTextToImpl();
1370 return copy_texture_to_impl_
->CreateReadbackPipelineYUV(quality
,
1378 } // namespace content