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
);
109 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
110 // the data needed for it.
111 class GLHelper::CopyTextureToImpl
112 : public base::SupportsWeakPtr
<GLHelper::CopyTextureToImpl
> {
114 CopyTextureToImpl(GLES2Interface
* gl
,
115 gpu::ContextSupport
* context_support
,
118 context_support_(context_support
),
121 max_draw_buffers_(0) {
122 const GLubyte
* extensions
= gl_
->GetString(GL_EXTENSIONS
);
125 std::string extensions_string
=
126 " " + std::string(reinterpret_cast<const char*>(extensions
)) + " ";
127 if (extensions_string
.find(" GL_EXT_draw_buffers ") != std::string::npos
) {
128 gl_
->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT
, &max_draw_buffers_
);
131 ~CopyTextureToImpl() { CancelRequests(); }
133 GLuint
ConsumeMailboxToTexture(const gpu::Mailbox
& mailbox
,
135 return helper_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
138 void CropScaleReadbackAndCleanTexture(
140 const gfx::Size
& src_size
,
141 const gfx::Rect
& src_subrect
,
142 const gfx::Size
& dst_size
,
144 const SkColorType color_type
,
145 const base::Callback
<void(bool)>& callback
,
146 GLHelper::ScalerQuality quality
);
148 void ReadbackTextureSync(GLuint texture
,
149 const gfx::Rect
& src_rect
,
153 void ReadbackTextureAsync(GLuint texture
,
154 const gfx::Size
& dst_size
,
156 SkColorType color_type
,
157 const base::Callback
<void(bool)>& callback
);
159 // Reads back bytes from the currently bound frame buffer.
160 // Note that dst_size is specified in bytes, not pixels.
161 void ReadbackAsync(const gfx::Size
& dst_size
,
162 int32 bytes_per_row
, // generally dst_size.width() * 4
163 int32 row_stride_bytes
, // generally dst_size.width() * 4
165 const SkColorType color_type
,
166 ReadbackSwizzle swizzle
,
167 const base::Callback
<void(bool)>& callback
);
169 void ReadbackPlane(TextureFrameBufferPair
* source
,
170 const scoped_refptr
<media::VideoFrame
>& target
,
173 const gfx::Rect
& dst_subrect
,
174 ReadbackSwizzle swizzle
,
175 const base::Callback
<void(bool)>& callback
);
177 GLuint
CopyAndScaleTexture(GLuint texture
,
178 const gfx::Size
& src_size
,
179 const gfx::Size
& dst_size
,
180 bool vertically_flip_texture
,
181 GLHelper::ScalerQuality quality
);
183 ReadbackYUVInterface
* CreateReadbackPipelineYUV(
184 GLHelper::ScalerQuality quality
,
185 const gfx::Size
& src_size
,
186 const gfx::Rect
& src_subrect
,
187 const gfx::Size
& dst_size
,
188 const gfx::Rect
& dst_subrect
,
189 bool flip_vertically
,
192 // Returns the maximum number of draw buffers available,
193 // 0 if GL_EXT_draw_buffers is not available.
194 GLint
MaxDrawBuffers() const { return max_draw_buffers_
; }
196 bool IsReadbackConfigSupported(SkColorType color_type
);
199 // A single request to CropScaleReadbackAndCleanTexture.
200 // The main thread can cancel the request, before it's handled by the helper
201 // thread, by resetting the texture and pixels fields. Alternatively, the
202 // thread marks that it handles the request by resetting the pixels field
203 // (meaning it guarantees that the callback with be called).
204 // In either case, the callback must be called exactly once, and the texture
205 // must be deleted by the main thread gl.
207 Request(const gfx::Size
& size_
,
208 int32 bytes_per_row_
,
209 int32 row_stride_bytes_
,
210 unsigned char* pixels_
,
211 const base::Callback
<void(bool)>& callback_
)
214 bytes_per_row(bytes_per_row_
),
215 row_stride_bytes(row_stride_bytes_
),
224 int row_stride_bytes
;
225 unsigned char* pixels
;
226 base::Callback
<void(bool)> callback
;
231 // A readback pipeline that also converts the data to YUV before
233 class ReadbackYUVImpl
: public ReadbackYUVInterface
{
235 ReadbackYUVImpl(GLES2Interface
* gl
,
236 CopyTextureToImpl
* copy_impl
,
237 GLHelperScaling
* scaler_impl
,
238 GLHelper::ScalerQuality quality
,
239 const gfx::Size
& src_size
,
240 const gfx::Rect
& src_subrect
,
241 const gfx::Size
& dst_size
,
242 const gfx::Rect
& dst_subrect
,
243 bool flip_vertically
,
244 ReadbackSwizzle swizzle
);
246 virtual void ReadbackYUV(const gpu::Mailbox
& mailbox
,
248 const scoped_refptr
<media::VideoFrame
>& target
,
249 const base::Callback
<void(bool)>& callback
)
252 virtual ScalerInterface
* scaler() OVERRIDE
{ return scaler_
.scaler(); }
256 CopyTextureToImpl
* copy_impl_
;
258 gfx::Rect dst_subrect_
;
259 ReadbackSwizzle swizzle_
;
260 ScalerHolder scaler_
;
265 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl
);
268 // A readback pipeline that also converts the data to YUV before
269 // reading it back. This one uses Multiple Render Targets, which
270 // may not be supported on all platforms.
271 class ReadbackYUV_MRT
: public ReadbackYUVInterface
{
273 ReadbackYUV_MRT(GLES2Interface
* gl
,
274 CopyTextureToImpl
* copy_impl
,
275 GLHelperScaling
* scaler_impl
,
276 GLHelper::ScalerQuality quality
,
277 const gfx::Size
& src_size
,
278 const gfx::Rect
& src_subrect
,
279 const gfx::Size
& dst_size
,
280 const gfx::Rect
& dst_subrect
,
281 bool flip_vertically
,
282 ReadbackSwizzle swizzle
);
284 virtual void ReadbackYUV(const gpu::Mailbox
& mailbox
,
286 const scoped_refptr
<media::VideoFrame
>& target
,
287 const base::Callback
<void(bool)>& callback
)
290 virtual ScalerInterface
* scaler() OVERRIDE
{ return scaler_
.scaler(); }
294 CopyTextureToImpl
* copy_impl_
;
296 gfx::Rect dst_subrect_
;
297 GLHelper::ScalerQuality quality_
;
298 ReadbackSwizzle swizzle_
;
299 ScalerHolder scaler_
;
300 scoped_ptr
<content::GLHelperScaling::ShaderInterface
> pass1_shader_
;
301 scoped_ptr
<content::GLHelperScaling::ShaderInterface
> pass2_shader_
;
302 TextureFrameBufferPair y_
;
304 TextureFrameBufferPair u_
;
305 TextureFrameBufferPair v_
;
307 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT
);
310 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
311 // scales it to |dst_size|, writes it into a texture, and returns its ID.
312 // |src_size| is the size of |src_texture|.
313 GLuint
ScaleTexture(GLuint src_texture
,
314 const gfx::Size
& src_size
,
315 const gfx::Rect
& src_subrect
,
316 const gfx::Size
& dst_size
,
317 bool vertically_flip_texture
,
319 SkColorType color_type
,
320 GLHelper::ScalerQuality quality
);
322 static void nullcallback(bool success
) {}
323 void ReadbackDone(Request
*request
, int bytes_per_pixel
);
324 void FinishRequest(Request
* request
, bool result
);
325 void CancelRequests();
327 static const float kRGBtoYColorWeights
[];
328 static const float kRGBtoUColorWeights
[];
329 static const float kRGBtoVColorWeights
[];
332 gpu::ContextSupport
* context_support_
;
335 // A scoped flush that will ensure all resource deletions are flushed when
336 // this object is destroyed. Must be declared before other Scoped* fields.
339 std::queue
<Request
*> request_queue_
;
340 GLint max_draw_buffers_
;
343 GLHelper::ScalerInterface
* GLHelper::CreateScaler(ScalerQuality quality
,
344 const gfx::Size
& src_size
,
345 const gfx::Rect
& src_subrect
,
346 const gfx::Size
& dst_size
,
347 bool vertically_flip_texture
,
350 return scaler_impl_
->CreateScaler(quality
,
354 vertically_flip_texture
,
358 GLuint
GLHelper::CopyTextureToImpl::ScaleTexture(
360 const gfx::Size
& src_size
,
361 const gfx::Rect
& src_subrect
,
362 const gfx::Size
& dst_size
,
363 bool vertically_flip_texture
,
365 SkColorType color_type
,
366 GLHelper::ScalerQuality quality
) {
367 if (!IsReadbackConfigSupported(color_type
))
370 scoped_ptr
<ScalerInterface
> scaler(
371 helper_
->CreateScaler(quality
,
375 vertically_flip_texture
,
377 GLuint dst_texture
= 0u;
378 // Start with ARGB8888 params as any other format which is not
379 // supported is already asserted above.
380 GLenum format
= GL_RGBA
, type
= GL_UNSIGNED_BYTE
;
381 gl_
->GenTextures(1, &dst_texture
);
383 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, dst_texture
);
384 switch (color_type
) {
385 case kN32_SkColorType
:
386 // Do nothing params already set.
388 case kRGB_565_SkColorType
:
390 type
= GL_UNSIGNED_SHORT_5_6_5
;
396 gl_
->TexImage2D(GL_TEXTURE_2D
,
406 scaler
->Scale(src_texture
, dst_texture
);
410 void GLHelper::CopyTextureToImpl::ReadbackAsync(
411 const gfx::Size
& dst_size
,
413 int32 row_stride_bytes
,
415 const SkColorType color_type
,
416 ReadbackSwizzle swizzle
,
417 const base::Callback
<void(bool)>& callback
) {
418 if (!IsReadbackConfigSupported(color_type
)) {
423 new Request(dst_size
, bytes_per_row
, row_stride_bytes
, out
, callback
);
424 request_queue_
.push(request
);
425 request
->buffer
= 0u;
426 // Start with ARGB8888 params as any other format which is not
427 // supported is already asserted above.
428 GLenum format
= GL_RGBA
, type
= GL_UNSIGNED_BYTE
;
429 int bytes_per_pixel
= 4;
431 switch (color_type
) {
432 case kN32_SkColorType
:
433 if (swizzle
== kSwizzleBGRA
)
434 format
= GL_BGRA_EXT
;
436 case kRGB_565_SkColorType
:
438 type
= GL_UNSIGNED_SHORT_5_6_5
;
445 gl_
->GenBuffers(1, &request
->buffer
);
446 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, request
->buffer
);
447 gl_
->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
448 bytes_per_pixel
* dst_size
.GetArea(),
453 gl_
->GenQueriesEXT(1, &request
->query
);
454 gl_
->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, request
->query
);
462 gl_
->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
463 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
464 context_support_
->SignalQuery(
466 base::Bind(&CopyTextureToImpl::ReadbackDone
, AsWeakPtr(),
467 request
, bytes_per_pixel
));
469 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
471 const gfx::Size
& src_size
,
472 const gfx::Rect
& src_subrect
,
473 const gfx::Size
& dst_size
,
475 const SkColorType color_type
,
476 const base::Callback
<void(bool)>& callback
,
477 GLHelper::ScalerQuality quality
) {
478 if (!IsReadbackConfigSupported(color_type
)) {
482 GLuint texture
= ScaleTexture(src_texture
,
487 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
495 ScopedFramebuffer
dst_framebuffer(gl_
);
496 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
498 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
499 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
500 GL_COLOR_ATTACHMENT0
,
504 int bytes_per_pixel
= 4;
505 switch (color_type
) {
506 case kN32_SkColorType
:
507 // Do nothing params already set.
509 case kRGB_565_SkColorType
:
516 ReadbackAsync(dst_size
,
517 dst_size
.width() * bytes_per_pixel
,
518 dst_size
.width() * bytes_per_pixel
,
523 gl_
->DeleteTextures(1, &texture
);
526 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
528 const gfx::Rect
& src_rect
,
530 SkColorType color_type
) {
531 if (!IsReadbackConfigSupported(color_type
))
534 ScopedFramebuffer
dst_framebuffer(gl_
);
535 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
537 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
538 gl_
->FramebufferTexture2D(
539 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture
, 0);
541 (color_type
== kRGB_565_SkColorType
) ? GL_RGB
: GL_RGBA
;
542 GLenum type
= (color_type
== kRGB_565_SkColorType
)
543 ? GL_UNSIGNED_SHORT_5_6_5
545 gl_
->ReadPixels(src_rect
.x(),
554 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
556 const gfx::Size
& dst_size
,
558 SkColorType color_type
,
559 const base::Callback
<void(bool)>& callback
) {
560 if (!IsReadbackConfigSupported(color_type
))
563 ScopedFramebuffer
dst_framebuffer(gl_
);
564 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
566 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
567 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
568 GL_COLOR_ATTACHMENT0
,
572 int bytes_per_pixel
= (color_type
== kRGB_565_SkColorType
) ? 2 : 4;
573 ReadbackAsync(dst_size
,
574 dst_size
.width() * bytes_per_pixel
,
575 dst_size
.width() * bytes_per_pixel
,
582 GLuint
GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
584 const gfx::Size
& src_size
,
585 const gfx::Size
& dst_size
,
586 bool vertically_flip_texture
,
587 GLHelper::ScalerQuality quality
) {
588 return ScaleTexture(src_texture
,
592 vertically_flip_texture
,
598 bool GLHelper::CopyTextureToImpl::IsReadbackConfigSupported(
599 SkColorType color_type
) {
604 return helper_
->IsReadbackConfigSupported(color_type
);
607 void GLHelper::CopyTextureToImpl::ReadbackDone(Request
* finished_request
,
608 int bytes_per_pixel
) {
609 TRACE_EVENT0("mirror",
610 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
611 finished_request
->done
= true;
613 // We process transfer requests in the order they were received, regardless
614 // of the order we get the callbacks in.
615 while (!request_queue_
.empty()) {
616 Request
* request
= request_queue_
.front();
617 if (!request
->done
) {
622 if (request
->buffer
!= 0) {
623 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, request
->buffer
);
624 unsigned char* data
= static_cast<unsigned char*>(gl_
->MapBufferCHROMIUM(
625 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, GL_READ_ONLY
));
628 if (request
->bytes_per_row
== request
->size
.width() * bytes_per_pixel
&&
629 request
->bytes_per_row
== request
->row_stride_bytes
) {
630 memcpy(request
->pixels
, data
,
631 request
->size
.GetArea() * bytes_per_pixel
);
633 unsigned char* out
= request
->pixels
;
634 for (int y
= 0; y
< request
->size
.height(); y
++) {
635 memcpy(out
, data
, request
->bytes_per_row
);
636 out
+= request
->row_stride_bytes
;
637 data
+= request
->size
.width() * bytes_per_pixel
;
640 gl_
->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
);
642 gl_
->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
644 FinishRequest(request
, result
);
648 void GLHelper::CopyTextureToImpl::FinishRequest(Request
* request
, bool result
) {
649 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
650 DCHECK(request_queue_
.front() == request
);
651 request_queue_
.pop();
652 request
->callback
.Run(result
);
653 ScopedFlush
flush(gl_
);
654 if (request
->query
!= 0) {
655 gl_
->DeleteQueriesEXT(1, &request
->query
);
658 if (request
->buffer
!= 0) {
659 gl_
->DeleteBuffers(1, &request
->buffer
);
665 void GLHelper::CopyTextureToImpl::CancelRequests() {
666 while (!request_queue_
.empty()) {
667 Request
* request
= request_queue_
.front();
668 FinishRequest(request
, false);
672 GLHelper::GLHelper(GLES2Interface
* gl
, gpu::ContextSupport
* context_support
)
674 context_support_(context_support
),
675 readback_support_(new GLHelperReadbackSupport(gl
)) {}
677 GLHelper::~GLHelper() {}
679 void GLHelper::CropScaleReadbackAndCleanTexture(
681 const gfx::Size
& src_size
,
682 const gfx::Rect
& src_subrect
,
683 const gfx::Size
& dst_size
,
685 const SkColorType color_type
,
686 const base::Callback
<void(bool)>& callback
,
687 GLHelper::ScalerQuality quality
) {
688 InitCopyTextToImpl();
689 copy_texture_to_impl_
->CropScaleReadbackAndCleanTexture(
700 void GLHelper::CropScaleReadbackAndCleanMailbox(
701 const gpu::Mailbox
& src_mailbox
,
703 const gfx::Size
& src_size
,
704 const gfx::Rect
& src_subrect
,
705 const gfx::Size
& dst_size
,
707 const SkColorType color_type
,
708 const base::Callback
<void(bool)>& callback
,
709 GLHelper::ScalerQuality quality
) {
710 GLuint mailbox_texture
= ConsumeMailboxToTexture(src_mailbox
, sync_point
);
711 CropScaleReadbackAndCleanTexture(
712 mailbox_texture
, src_size
, src_subrect
, dst_size
, out
,
716 gl_
->DeleteTextures(1, &mailbox_texture
);
719 void GLHelper::ReadbackTextureSync(GLuint texture
,
720 const gfx::Rect
& src_rect
,
722 SkColorType format
) {
723 InitCopyTextToImpl();
724 copy_texture_to_impl_
->ReadbackTextureSync(texture
, src_rect
, out
, format
);
727 void GLHelper::ReadbackTextureAsync(
729 const gfx::Size
& dst_size
,
731 SkColorType color_type
,
732 const base::Callback
<void(bool)>& callback
) {
733 InitCopyTextToImpl();
734 copy_texture_to_impl_
->ReadbackTextureAsync(texture
,
741 GLuint
GLHelper::CopyTexture(GLuint texture
, const gfx::Size
& size
) {
742 InitCopyTextToImpl();
743 return copy_texture_to_impl_
->CopyAndScaleTexture(
744 texture
, size
, size
, false, GLHelper::SCALER_QUALITY_FAST
);
747 GLuint
GLHelper::CopyAndScaleTexture(GLuint texture
,
748 const gfx::Size
& src_size
,
749 const gfx::Size
& dst_size
,
750 bool vertically_flip_texture
,
751 ScalerQuality quality
) {
752 InitCopyTextToImpl();
753 return copy_texture_to_impl_
->CopyAndScaleTexture(
754 texture
, src_size
, dst_size
, vertically_flip_texture
, quality
);
757 GLuint
GLHelper::CompileShaderFromSource(const GLchar
* source
, GLenum type
) {
758 GLuint shader
= gl_
->CreateShader(type
);
759 GLint length
= strlen(source
);
760 gl_
->ShaderSource(shader
, 1, &source
, &length
);
761 gl_
->CompileShader(shader
);
762 GLint compile_status
= 0;
763 gl_
->GetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
764 if (!compile_status
) {
765 GLint log_length
= 0;
766 gl_
->GetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &log_length
);
768 scoped_ptr
<GLchar
[]> log(new GLchar
[log_length
]);
769 GLsizei returned_log_length
= 0;
770 gl_
->GetShaderInfoLog(
771 shader
, log_length
, &returned_log_length
, log
.get());
772 LOG(ERROR
) << std::string(log
.get(), returned_log_length
);
774 gl_
->DeleteShader(shader
);
780 void GLHelper::InitCopyTextToImpl() {
781 // Lazily initialize |copy_texture_to_impl_|
782 if (!copy_texture_to_impl_
)
783 copy_texture_to_impl_
.reset(
784 new CopyTextureToImpl(gl_
, context_support_
, this));
787 void GLHelper::InitScalerImpl() {
788 // Lazily initialize |scaler_impl_|
790 scaler_impl_
.reset(new GLHelperScaling(gl_
, this));
793 GLint
GLHelper::MaxDrawBuffers() {
794 InitCopyTextToImpl();
795 return copy_texture_to_impl_
->MaxDrawBuffers();
798 void GLHelper::CopySubBufferDamage(GLuint texture
,
799 GLuint previous_texture
,
800 const SkRegion
& new_damage
,
801 const SkRegion
& old_damage
) {
802 SkRegion
region(old_damage
);
803 if (region
.op(new_damage
, SkRegion::kDifference_Op
)) {
804 ScopedFramebuffer
dst_framebuffer(gl_
);
805 ScopedFramebufferBinder
<GL_FRAMEBUFFER
> framebuffer_binder(gl_
,
807 ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
808 gl_
->FramebufferTexture2D(GL_FRAMEBUFFER
,
809 GL_COLOR_ATTACHMENT0
,
813 for (SkRegion::Iterator
it(region
); !it
.done(); it
.next()) {
814 const SkIRect
& rect
= it
.rect();
815 gl_
->CopyTexSubImage2D(GL_TEXTURE_2D
,
828 GLuint
GLHelper::CreateTexture() {
830 gl_
->GenTextures(1, &texture
);
831 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
832 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
833 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
834 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
835 gl_
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
839 void GLHelper::DeleteTexture(GLuint texture_id
) {
840 gl_
->DeleteTextures(1, &texture_id
);
843 uint32
GLHelper::InsertSyncPoint() { return gl_
->InsertSyncPointCHROMIUM(); }
845 void GLHelper::WaitSyncPoint(uint32 sync_point
) {
846 gl_
->WaitSyncPointCHROMIUM(sync_point
);
849 gpu::MailboxHolder
GLHelper::ProduceMailboxHolderFromTexture(
851 gpu::Mailbox mailbox
;
852 gl_
->GenMailboxCHROMIUM(mailbox
.name
);
853 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture_id
);
854 gl_
->ProduceTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
855 return gpu::MailboxHolder(mailbox
, GL_TEXTURE_2D
, InsertSyncPoint());
858 GLuint
GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox
& mailbox
,
860 if (mailbox
.IsZero())
863 WaitSyncPoint(sync_point
);
864 GLuint texture
= CreateTexture();
865 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
866 gl_
->ConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
.name
);
870 void GLHelper::ResizeTexture(GLuint texture
, const gfx::Size
& size
) {
871 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
872 gl_
->TexImage2D(GL_TEXTURE_2D
,
883 void GLHelper::CopyTextureSubImage(GLuint texture
, const gfx::Rect
& rect
) {
884 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
885 gl_
->CopyTexSubImage2D(GL_TEXTURE_2D
,
895 void GLHelper::CopyTextureFullImage(GLuint texture
, const gfx::Size
& size
) {
896 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl_
, texture
);
898 GL_TEXTURE_2D
, 0, GL_RGB
, 0, 0, size
.width(), size
.height(), 0);
901 void GLHelper::Flush() {
905 void GLHelper::CopyTextureToImpl::ReadbackPlane(
906 TextureFrameBufferPair
* source
,
907 const scoped_refptr
<media::VideoFrame
>& target
,
910 const gfx::Rect
& dst_subrect
,
911 ReadbackSwizzle swizzle
,
912 const base::Callback
<void(bool)>& callback
) {
913 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, source
->framebuffer());
914 size_t offset
= target
->stride(plane
) * (dst_subrect
.y() >> size_shift
) +
915 (dst_subrect
.x() >> size_shift
);
916 ReadbackAsync(source
->size(),
917 dst_subrect
.width() >> size_shift
,
918 target
->stride(plane
),
919 target
->data(plane
) + offset
,
925 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights
[] = {
926 0.257f
, 0.504f
, 0.098f
, 0.0625f
};
927 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights
[] = {
928 -0.148f
, -0.291f
, 0.439f
, 0.5f
};
929 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights
[] = {
930 0.439f
, -0.368f
, -0.071f
, 0.5f
};
932 // YUV readback constructors. Initiates the main scaler pipeline and
933 // one planar scaler for each of the Y, U and V planes.
934 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
936 CopyTextureToImpl
* copy_impl
,
937 GLHelperScaling
* scaler_impl
,
938 GLHelper::ScalerQuality quality
,
939 const gfx::Size
& src_size
,
940 const gfx::Rect
& src_subrect
,
941 const gfx::Size
& dst_size
,
942 const gfx::Rect
& dst_subrect
,
943 bool flip_vertically
,
944 ReadbackSwizzle swizzle
)
946 copy_impl_(copy_impl
),
948 dst_subrect_(dst_subrect
),
951 scaler_impl
->CreateScaler(quality
,
958 scaler_impl
->CreatePlanarScaler(
962 (dst_subrect
.width() + 3) & ~3,
963 dst_subrect
.height()),
964 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
966 (swizzle
== kSwizzleBGRA
),
967 kRGBtoYColorWeights
)),
969 scaler_impl
->CreatePlanarScaler(
973 (dst_subrect
.width() + 7) & ~7,
974 (dst_subrect
.height() + 1) & ~1),
975 gfx::Size((dst_subrect
.width() + 7) / 8,
976 (dst_subrect
.height() + 1) / 2),
978 (swizzle
== kSwizzleBGRA
),
979 kRGBtoUColorWeights
)),
981 scaler_impl
->CreatePlanarScaler(
985 (dst_subrect
.width() + 7) & ~7,
986 (dst_subrect
.height() + 1) & ~1),
987 gfx::Size((dst_subrect
.width() + 7) / 8,
988 (dst_subrect
.height() + 1) / 2),
990 (swizzle
== kSwizzleBGRA
),
991 kRGBtoVColorWeights
)) {
992 DCHECK(!(dst_size
.width() & 1));
993 DCHECK(!(dst_size
.height() & 1));
994 DCHECK(!(dst_subrect
.width() & 1));
995 DCHECK(!(dst_subrect
.height() & 1));
996 DCHECK(!(dst_subrect
.x() & 1));
997 DCHECK(!(dst_subrect
.y() & 1));
1000 static void CallbackKeepingVideoFrameAlive(
1001 scoped_refptr
<media::VideoFrame
> video_frame
,
1002 const base::Callback
<void(bool)>& callback
,
1004 callback
.Run(success
);
1007 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1008 const gpu::Mailbox
& mailbox
,
1010 const scoped_refptr
<media::VideoFrame
>& target
,
1011 const base::Callback
<void(bool)>& callback
) {
1012 GLuint mailbox_texture
=
1013 copy_impl_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
1015 // Scale texture to right size.
1016 scaler_
.Scale(mailbox_texture
);
1017 gl_
->DeleteTextures(1, &mailbox_texture
);
1019 // Convert the scaled texture in to Y, U and V planes.
1020 y_
.Scale(scaler_
.texture());
1021 u_
.Scale(scaler_
.texture());
1022 v_
.Scale(scaler_
.texture());
1024 if (target
->coded_size() != dst_size_
) {
1025 DCHECK(target
->coded_size() == dst_size_
);
1026 LOG(ERROR
) << "ReadbackYUV size error!";
1027 callback
.Run(false);
1031 // Read back planes, one at a time. Keep the video frame alive while doing the
1033 copy_impl_
->ReadbackPlane(y_
.texture_and_framebuffer(),
1035 media::VideoFrame::kYPlane
,
1039 base::Bind(&nullcallback
));
1040 copy_impl_
->ReadbackPlane(u_
.texture_and_framebuffer(),
1042 media::VideoFrame::kUPlane
,
1046 base::Bind(&nullcallback
));
1047 copy_impl_
->ReadbackPlane(
1048 v_
.texture_and_framebuffer(),
1050 media::VideoFrame::kVPlane
,
1054 base::Bind(&CallbackKeepingVideoFrameAlive
, target
, callback
));
1055 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, 0);
1056 media::LetterboxYUV(target
, dst_subrect_
);
1059 // YUV readback constructors. Initiates the main scaler pipeline and
1060 // one planar scaler for each of the Y, U and V planes.
1061 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1063 CopyTextureToImpl
* copy_impl
,
1064 GLHelperScaling
* scaler_impl
,
1065 GLHelper::ScalerQuality quality
,
1066 const gfx::Size
& src_size
,
1067 const gfx::Rect
& src_subrect
,
1068 const gfx::Size
& dst_size
,
1069 const gfx::Rect
& dst_subrect
,
1070 bool flip_vertically
,
1071 ReadbackSwizzle swizzle
)
1073 copy_impl_(copy_impl
),
1074 dst_size_(dst_size
),
1075 dst_subrect_(dst_subrect
),
1079 scaler_impl
->CreateScaler(quality
,
1085 pass1_shader_(scaler_impl
->CreateYuvMrtShader(
1087 gfx::Rect(0, 0, (dst_subrect
.width() + 3) & ~3, dst_subrect
.height()),
1088 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
1090 (swizzle
== kSwizzleBGRA
),
1091 GLHelperScaling::SHADER_YUV_MRT_PASS1
)),
1092 pass2_shader_(scaler_impl
->CreateYuvMrtShader(
1093 gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height()),
1096 (dst_subrect
.width() + 7) / 8 * 2,
1097 dst_subrect
.height()),
1098 gfx::Size((dst_subrect
.width() + 7) / 8,
1099 (dst_subrect
.height() + 1) / 2),
1101 (swizzle
== kSwizzleBGRA
),
1102 GLHelperScaling::SHADER_YUV_MRT_PASS2
)),
1103 y_(gl
, gfx::Size((dst_subrect
.width() + 3) / 4, dst_subrect
.height())),
1106 gfx::Size((dst_subrect
.width() + 7) / 8,
1107 (dst_subrect
.height() + 1) / 2)),
1109 gfx::Size((dst_subrect
.width() + 7) / 8,
1110 (dst_subrect
.height() + 1) / 2)) {
1112 content::ScopedTextureBinder
<GL_TEXTURE_2D
> texture_binder(gl
, uv_
);
1113 gl
->TexImage2D(GL_TEXTURE_2D
,
1116 (dst_subrect
.width() + 3) / 4,
1117 dst_subrect
.height(),
1123 DCHECK(!(dst_size
.width() & 1));
1124 DCHECK(!(dst_size
.height() & 1));
1125 DCHECK(!(dst_subrect
.width() & 1));
1126 DCHECK(!(dst_subrect
.height() & 1));
1127 DCHECK(!(dst_subrect
.x() & 1));
1128 DCHECK(!(dst_subrect
.y() & 1));
1131 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1132 const gpu::Mailbox
& mailbox
,
1134 const scoped_refptr
<media::VideoFrame
>& target
,
1135 const base::Callback
<void(bool)>& callback
) {
1136 GLuint mailbox_texture
=
1137 copy_impl_
->ConsumeMailboxToTexture(mailbox
, sync_point
);
1140 if (quality_
== GLHelper::SCALER_QUALITY_FAST
) {
1141 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1142 // pass, which pass1_shader_ can do just as well, so let's skip
1143 // the actual scaling in that case.
1144 texture
= mailbox_texture
;
1146 // Scale texture to right size.
1147 scaler_
.Scale(mailbox_texture
);
1148 texture
= scaler_
.texture();
1151 std::vector
<GLuint
> outputs(2);
1152 // Convert the scaled texture in to Y, U and V planes.
1153 outputs
[0] = y_
.texture();
1155 pass1_shader_
->Execute(texture
, outputs
);
1157 gl_
->DeleteTextures(1, &mailbox_texture
);
1159 outputs
[0] = u_
.texture();
1160 outputs
[1] = v_
.texture();
1161 pass2_shader_
->Execute(uv_
, outputs
);
1163 if (target
->coded_size() != dst_size_
) {
1164 DCHECK(target
->coded_size() == dst_size_
);
1165 LOG(ERROR
) << "ReadbackYUV size error!";
1166 callback
.Run(false);
1170 // Read back planes, one at a time.
1171 copy_impl_
->ReadbackPlane(&y_
,
1173 media::VideoFrame::kYPlane
,
1177 base::Bind(&nullcallback
));
1178 copy_impl_
->ReadbackPlane(&u_
,
1180 media::VideoFrame::kUPlane
,
1184 base::Bind(&nullcallback
));
1185 copy_impl_
->ReadbackPlane(
1188 media::VideoFrame::kVPlane
,
1192 base::Bind(&CallbackKeepingVideoFrameAlive
, target
, callback
));
1193 gl_
->BindFramebuffer(GL_FRAMEBUFFER
, 0);
1194 media::LetterboxYUV(target
, dst_subrect_
);
1197 bool GLHelper::IsReadbackConfigSupported(SkColorType texture_format
) {
1198 DCHECK(readback_support_
.get());
1199 return readback_support_
.get()->IsReadbackConfigSupported(texture_format
);
1202 ReadbackYUVInterface
* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1203 GLHelper::ScalerQuality quality
,
1204 const gfx::Size
& src_size
,
1205 const gfx::Rect
& src_subrect
,
1206 const gfx::Size
& dst_size
,
1207 const gfx::Rect
& dst_subrect
,
1208 bool flip_vertically
,
1210 helper_
->InitScalerImpl();
1211 // Query preferred format for glReadPixels, if is is GL_BGRA then use that
1212 // and trigger the appropriate swizzle in the YUV shaders.
1213 GLint format
= 0, type
= 0;
1214 ReadbackSwizzle swizzle
= kSwizzleNone
;
1215 helper_
->readback_support_
.get()->GetAdditionalFormat(GL_RGBA
,
1218 if (format
== GL_BGRA_EXT
&& type
== GL_UNSIGNED_BYTE
)
1219 swizzle
= kSwizzleBGRA
;
1220 if (max_draw_buffers_
>= 2 && use_mrt
) {
1221 return new ReadbackYUV_MRT(gl_
,
1223 helper_
->scaler_impl_
.get(),
1232 return new ReadbackYUVImpl(gl_
,
1234 helper_
->scaler_impl_
.get(),
1244 ReadbackYUVInterface
* GLHelper::CreateReadbackPipelineYUV(
1245 ScalerQuality quality
,
1246 const gfx::Size
& src_size
,
1247 const gfx::Rect
& src_subrect
,
1248 const gfx::Size
& dst_size
,
1249 const gfx::Rect
& dst_subrect
,
1250 bool flip_vertically
,
1252 InitCopyTextToImpl();
1253 return copy_texture_to_impl_
->CreateReadbackPipelineYUV(quality
,
1262 } // namespace content