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_scaling.h"
19 #include "gpu/GLES2/gl2extchromium.h"
20 #include "gpu/command_buffer/client/context_support.h"
21 #include "gpu/command_buffer/common/mailbox.h"
22 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h"
24 #include "third_party/skia/include/core/SkRegion.h"
25 #include "ui/gfx/rect.h"
26 #include "ui/gfx/size.h"
28 using gpu::gles2::GLES2Interface;
32 // Helper class for allocating and holding an RGBA texture of a given
33 // size and an associated framebuffer.
34 class TextureFrameBufferPair {
36 TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
37 : texture_(gl), framebuffer_(gl), size_(size) {
38 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
39 gl->TexImage2D(GL_TEXTURE_2D,
48 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
50 gl->FramebufferTexture2D(
51 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
54 GLuint texture() const { return texture_.id(); }
55 GLuint framebuffer() const { return framebuffer_.id(); }
56 gfx::Size size() const { return size_; }
59 content::ScopedTexture texture_;
60 content::ScopedFramebuffer framebuffer_;
63 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
66 // Helper class for holding a scaler, a texture for the output of that
67 // scaler and an associated frame buffer. This is inteded to be used
68 // when the output of a scaler is to be sent to a readback.
71 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
72 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
74 void Scale(GLuint src_texture) {
75 scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
78 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
79 TextureFrameBufferPair* texture_and_framebuffer() {
80 return &texture_and_framebuffer_;
82 GLuint texture() const { return texture_and_framebuffer_.texture(); }
85 TextureFrameBufferPair texture_and_framebuffer_;
86 scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
88 DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
95 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
96 // the data needed for it.
97 class GLHelper::CopyTextureToImpl
98 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
100 CopyTextureToImpl(GLES2Interface* gl,
101 gpu::ContextSupport* context_support,
104 context_support_(context_support),
107 max_draw_buffers_(0) {
108 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
111 std::string extensions_string =
112 " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
113 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
114 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
117 ~CopyTextureToImpl() { CancelRequests(); }
119 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
121 return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
124 void CropScaleReadbackAndCleanTexture(
126 const gfx::Size& src_size,
127 const gfx::Rect& src_subrect,
128 const gfx::Size& dst_size,
130 const SkBitmap::Config config,
131 const base::Callback<void(bool)>& callback,
132 GLHelper::ScalerQuality quality);
134 void ReadbackTextureSync(GLuint texture,
135 const gfx::Rect& src_rect,
137 SkBitmap::Config format);
139 void ReadbackTextureAsync(GLuint texture,
140 const gfx::Size& dst_size,
142 SkBitmap::Config config,
143 const base::Callback<void(bool)>& callback);
145 // Reads back bytes from the currently bound frame buffer.
146 // Note that dst_size is specified in bytes, not pixels.
147 void ReadbackAsync(const gfx::Size& dst_size,
148 int32 bytes_per_row, // generally dst_size.width() * 4
149 int32 row_stride_bytes, // generally dst_size.width() * 4
151 const SkBitmap::Config config,
152 const base::Callback<void(bool)>& callback);
154 void ReadbackPlane(TextureFrameBufferPair* source,
155 const scoped_refptr<media::VideoFrame>& target,
158 const gfx::Rect& dst_subrect,
159 const base::Callback<void(bool)>& callback);
161 GLuint CopyAndScaleTexture(GLuint texture,
162 const gfx::Size& src_size,
163 const gfx::Size& dst_size,
164 bool vertically_flip_texture,
165 GLHelper::ScalerQuality quality);
167 ReadbackYUVInterface* CreateReadbackPipelineYUV(
168 GLHelper::ScalerQuality quality,
169 const gfx::Size& src_size,
170 const gfx::Rect& src_subrect,
171 const gfx::Size& dst_size,
172 const gfx::Rect& dst_subrect,
173 bool flip_vertically,
176 // Returns the maximum number of draw buffers available,
177 // 0 if GL_EXT_draw_buffers is not available.
178 GLint MaxDrawBuffers() const { return max_draw_buffers_; }
181 // A single request to CropScaleReadbackAndCleanTexture.
182 // The main thread can cancel the request, before it's handled by the helper
183 // thread, by resetting the texture and pixels fields. Alternatively, the
184 // thread marks that it handles the request by resetting the pixels field
185 // (meaning it guarantees that the callback with be called).
186 // In either case, the callback must be called exactly once, and the texture
187 // must be deleted by the main thread gl.
189 Request(const gfx::Size& size_,
190 int32 bytes_per_row_,
191 int32 row_stride_bytes_,
192 unsigned char* pixels_,
193 const base::Callback<void(bool)>& callback_)
196 bytes_per_row(bytes_per_row_),
197 row_stride_bytes(row_stride_bytes_),
206 int row_stride_bytes;
207 unsigned char* pixels;
208 base::Callback<void(bool)> callback;
213 // A readback pipeline that also converts the data to YUV before
215 class ReadbackYUVImpl : public ReadbackYUVInterface {
217 ReadbackYUVImpl(GLES2Interface* gl,
218 CopyTextureToImpl* copy_impl,
219 GLHelperScaling* scaler_impl,
220 GLHelper::ScalerQuality quality,
221 const gfx::Size& src_size,
222 const gfx::Rect& src_subrect,
223 const gfx::Size& dst_size,
224 const gfx::Rect& dst_subrect,
225 bool flip_vertically);
227 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
229 const scoped_refptr<media::VideoFrame>& target,
230 const base::Callback<void(bool)>& callback)
233 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
237 CopyTextureToImpl* copy_impl_;
239 gfx::Rect dst_subrect_;
240 ScalerHolder scaler_;
245 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
248 // A readback pipeline that also converts the data to YUV before
249 // reading it back. This one uses Multiple Render Targets, which
250 // may not be supported on all platforms.
251 class ReadbackYUV_MRT : public ReadbackYUVInterface {
253 ReadbackYUV_MRT(GLES2Interface* gl,
254 CopyTextureToImpl* copy_impl,
255 GLHelperScaling* scaler_impl,
256 GLHelper::ScalerQuality quality,
257 const gfx::Size& src_size,
258 const gfx::Rect& src_subrect,
259 const gfx::Size& dst_size,
260 const gfx::Rect& dst_subrect,
261 bool flip_vertically);
263 virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
265 const scoped_refptr<media::VideoFrame>& target,
266 const base::Callback<void(bool)>& callback)
269 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
273 CopyTextureToImpl* copy_impl_;
275 gfx::Rect dst_subrect_;
276 GLHelper::ScalerQuality quality_;
277 ScalerHolder scaler_;
278 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
279 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
280 TextureFrameBufferPair y_;
282 TextureFrameBufferPair u_;
283 TextureFrameBufferPair v_;
285 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
288 // Copies the block of pixels specified with |src_subrect| from |src_texture|,
289 // scales it to |dst_size|, writes it into a texture, and returns its ID.
290 // |src_size| is the size of |src_texture|.
291 GLuint ScaleTexture(GLuint src_texture,
292 const gfx::Size& src_size,
293 const gfx::Rect& src_subrect,
294 const gfx::Size& dst_size,
295 bool vertically_flip_texture,
297 SkBitmap::Config config,
298 GLHelper::ScalerQuality quality);
300 static void nullcallback(bool success) {}
301 void ReadbackDone(Request *request, int bytes_per_pixel);
302 void FinishRequest(Request* request, bool result);
303 void CancelRequests();
305 static const float kRGBtoYColorWeights[];
306 static const float kRGBtoUColorWeights[];
307 static const float kRGBtoVColorWeights[];
310 gpu::ContextSupport* context_support_;
313 // A scoped flush that will ensure all resource deletions are flushed when
314 // this object is destroyed. Must be declared before other Scoped* fields.
317 std::queue<Request*> request_queue_;
318 GLint max_draw_buffers_;
321 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
322 const gfx::Size& src_size,
323 const gfx::Rect& src_subrect,
324 const gfx::Size& dst_size,
325 bool vertically_flip_texture,
328 return scaler_impl_->CreateScaler(quality,
332 vertically_flip_texture,
336 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
338 const gfx::Size& src_size,
339 const gfx::Rect& src_subrect,
340 const gfx::Size& dst_size,
341 bool vertically_flip_texture,
343 SkBitmap::Config config,
344 GLHelper::ScalerQuality quality) {
346 bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
347 (config == SkBitmap::kARGB_8888_Config));
348 if (!format_support) {
349 DCHECK(format_support);
352 scoped_ptr<ScalerInterface> scaler(
353 helper_->CreateScaler(quality,
357 vertically_flip_texture,
359 GLuint dst_texture = 0u;
360 // Start with ARGB8888 params as any other format which is not
361 // supported is already asserted above.
362 GLenum format = GL_RGBA , type = GL_UNSIGNED_BYTE;
363 gl_->GenTextures(1, &dst_texture);
365 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
367 case SkBitmap::kARGB_8888_Config:
368 // Do nothing params already set.
370 case SkBitmap::kRGB_565_Config:
372 type = GL_UNSIGNED_SHORT_5_6_5;
378 gl_->TexImage2D(GL_TEXTURE_2D,
388 scaler->Scale(src_texture, dst_texture);
392 void GLHelper::CopyTextureToImpl::ReadbackAsync(
393 const gfx::Size& dst_size,
395 int32 row_stride_bytes,
397 const SkBitmap::Config config,
398 const base::Callback<void(bool)>& callback) {
399 bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
400 (config == SkBitmap::kARGB_8888_Config));
401 if (!format_support) {
402 DCHECK(format_support);
407 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
408 request_queue_.push(request);
409 request->buffer = 0u;
410 // Start with ARGB8888 params as any other format which is not
411 // supported is already asserted above.
412 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
413 int bytes_per_pixel = 4;
416 case SkBitmap::kARGB_8888_Config:
417 // Do nothing params already set.
419 case SkBitmap::kRGB_565_Config:
421 type = GL_UNSIGNED_SHORT_5_6_5;
428 gl_->GenBuffers(1, &request->buffer);
429 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
430 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
431 bytes_per_pixel * dst_size.GetArea(),
436 gl_->GenQueriesEXT(1, &request->query);
437 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
445 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
446 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
447 context_support_->SignalQuery(
449 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
450 request, bytes_per_pixel));
452 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
454 const gfx::Size& src_size,
455 const gfx::Rect& src_subrect,
456 const gfx::Size& dst_size,
458 const SkBitmap::Config bitmap_config,
459 const base::Callback<void(bool)>& callback,
460 GLHelper::ScalerQuality quality) {
461 bool format_support = ((bitmap_config == SkBitmap::kRGB_565_Config) ||
462 (bitmap_config == SkBitmap::kARGB_8888_Config));
463 if (!format_support) {
464 DCHECK(format_support);
468 GLuint texture = ScaleTexture(src_texture,
473 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
481 ScopedFramebuffer dst_framebuffer(gl_);
482 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
484 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
485 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
486 GL_COLOR_ATTACHMENT0,
490 int bytes_per_pixel = 4;
491 switch (bitmap_config) {
492 case SkBitmap::kARGB_8888_Config:
493 // Do nothing params already set.
495 case SkBitmap::kRGB_565_Config:
502 ReadbackAsync(dst_size,
503 dst_size.width() * bytes_per_pixel,
504 dst_size.width() * bytes_per_pixel,
508 gl_->DeleteTextures(1, &texture);
511 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(GLuint texture,
512 const gfx::Rect& src_rect,
514 SkBitmap::Config config) {
515 DCHECK((config == SkBitmap::kRGB_565_Config) ||
516 (config == SkBitmap::kARGB_8888_Config));
517 ScopedFramebuffer dst_framebuffer(gl_);
518 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
520 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
521 gl_->FramebufferTexture2D(
522 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
523 GLenum format = (config == SkBitmap::kRGB_565_Config) ?
526 GLenum type = (config == SkBitmap::kRGB_565_Config) ?
527 GL_UNSIGNED_SHORT_5_6_5 :
529 gl_->ReadPixels(src_rect.x(),
538 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
540 const gfx::Size& dst_size,
542 SkBitmap::Config config,
543 const base::Callback<void(bool)>& callback) {
544 // Only ARGB888 and RGB565 supported as of now.
545 bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
546 (config == SkBitmap::kARGB_8888_Config));
547 if (!format_support) {
548 DCHECK(format_support);
551 ScopedFramebuffer dst_framebuffer(gl_);
552 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
554 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
555 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
556 GL_COLOR_ATTACHMENT0,
560 int bytes_per_pixel = (config == SkBitmap::kRGB_565_Config) ? 2 : 4;
561 ReadbackAsync(dst_size,
562 dst_size.width() * bytes_per_pixel,
563 dst_size.width() * bytes_per_pixel,
569 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
571 const gfx::Size& src_size,
572 const gfx::Size& dst_size,
573 bool vertically_flip_texture,
574 GLHelper::ScalerQuality quality) {
575 return ScaleTexture(src_texture,
579 vertically_flip_texture,
581 SkBitmap::kARGB_8888_Config,
585 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
586 int bytes_per_pixel) {
587 TRACE_EVENT0("mirror",
588 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
589 finished_request->done = true;
591 // We process transfer requests in the order they were received, regardless
592 // of the order we get the callbacks in.
593 while (!request_queue_.empty()) {
594 Request* request = request_queue_.front();
595 if (!request->done) {
600 if (request->buffer != 0) {
601 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
602 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
603 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
606 if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
607 request->bytes_per_row == request->row_stride_bytes) {
608 memcpy(request->pixels, data,
609 request->size.GetArea() * bytes_per_pixel);
611 unsigned char* out = request->pixels;
612 for (int y = 0; y < request->size.height(); y++) {
613 memcpy(out, data, request->bytes_per_row);
614 out += request->row_stride_bytes;
615 data += request->size.width() * bytes_per_pixel;
618 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
620 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
622 FinishRequest(request, result);
626 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
627 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
628 DCHECK(request_queue_.front() == request);
629 request_queue_.pop();
630 request->callback.Run(result);
631 ScopedFlush flush(gl_);
632 if (request->query != 0) {
633 gl_->DeleteQueriesEXT(1, &request->query);
636 if (request->buffer != 0) {
637 gl_->DeleteBuffers(1, &request->buffer);
643 void GLHelper::CopyTextureToImpl::CancelRequests() {
644 while (!request_queue_.empty()) {
645 Request* request = request_queue_.front();
646 FinishRequest(request, false);
650 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
652 context_support_(context_support),
653 initialized_565_format_check_(false),
654 support_565_format_(false) {}
656 GLHelper::~GLHelper() {}
658 void GLHelper::CropScaleReadbackAndCleanTexture(
660 const gfx::Size& src_size,
661 const gfx::Rect& src_subrect,
662 const gfx::Size& dst_size,
664 const SkBitmap::Config config,
665 const base::Callback<void(bool)>& callback) {
666 InitCopyTextToImpl();
667 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(
675 GLHelper::SCALER_QUALITY_FAST);
678 void GLHelper::CropScaleReadbackAndCleanMailbox(
679 const gpu::Mailbox& src_mailbox,
681 const gfx::Size& src_size,
682 const gfx::Rect& src_subrect,
683 const gfx::Size& dst_size,
685 const SkBitmap::Config bitmap_config,
686 const base::Callback<void(bool)>& callback) {
687 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
688 CropScaleReadbackAndCleanTexture(
689 mailbox_texture, src_size, src_subrect, dst_size, out,
692 gl_->DeleteTextures(1, &mailbox_texture);
695 void GLHelper::ReadbackTextureSync(GLuint texture,
696 const gfx::Rect& src_rect,
698 SkBitmap::Config format) {
699 InitCopyTextToImpl();
700 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
703 void GLHelper::ReadbackTextureAsync(
705 const gfx::Size& dst_size,
707 SkBitmap::Config config,
708 const base::Callback<void(bool)>& callback) {
709 InitCopyTextToImpl();
710 copy_texture_to_impl_->ReadbackTextureAsync(texture,
717 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
718 InitCopyTextToImpl();
719 return copy_texture_to_impl_->CopyAndScaleTexture(
720 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
723 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
724 const gfx::Size& src_size,
725 const gfx::Size& dst_size,
726 bool vertically_flip_texture,
727 ScalerQuality quality) {
728 InitCopyTextToImpl();
729 return copy_texture_to_impl_->CopyAndScaleTexture(
730 texture, src_size, dst_size, vertically_flip_texture, quality);
733 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
734 GLuint shader = gl_->CreateShader(type);
735 GLint length = strlen(source);
736 gl_->ShaderSource(shader, 1, &source, &length);
737 gl_->CompileShader(shader);
738 GLint compile_status = 0;
739 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
740 if (!compile_status) {
741 GLint log_length = 0;
742 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
744 scoped_ptr<GLchar[]> log(new GLchar[log_length]);
745 GLsizei returned_log_length = 0;
746 gl_->GetShaderInfoLog(
747 shader, log_length, &returned_log_length, log.get());
748 LOG(ERROR) << std::string(log.get(), returned_log_length);
750 gl_->DeleteShader(shader);
756 void GLHelper::InitCopyTextToImpl() {
757 // Lazily initialize |copy_texture_to_impl_|
758 if (!copy_texture_to_impl_)
759 copy_texture_to_impl_.reset(
760 new CopyTextureToImpl(gl_, context_support_, this));
763 void GLHelper::InitScalerImpl() {
764 // Lazily initialize |scaler_impl_|
766 scaler_impl_.reset(new GLHelperScaling(gl_, this));
769 GLint GLHelper::MaxDrawBuffers() {
770 InitCopyTextToImpl();
771 return copy_texture_to_impl_->MaxDrawBuffers();
774 void GLHelper::CopySubBufferDamage(GLuint texture,
775 GLuint previous_texture,
776 const SkRegion& new_damage,
777 const SkRegion& old_damage) {
778 SkRegion region(old_damage);
779 if (region.op(new_damage, SkRegion::kDifference_Op)) {
780 ScopedFramebuffer dst_framebuffer(gl_);
781 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
783 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
784 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
785 GL_COLOR_ATTACHMENT0,
789 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
790 const SkIRect& rect = it.rect();
791 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
804 GLuint GLHelper::CreateTexture() {
806 gl_->GenTextures(1, &texture);
807 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
808 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
809 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
810 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
811 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
815 void GLHelper::DeleteTexture(GLuint texture_id) {
816 gl_->DeleteTextures(1, &texture_id);
819 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
821 void GLHelper::WaitSyncPoint(uint32 sync_point) {
822 gl_->WaitSyncPointCHROMIUM(sync_point);
825 gpu::Mailbox GLHelper::ProduceMailboxFromTexture(GLuint texture_id,
826 uint32* sync_point) {
827 gpu::Mailbox mailbox;
828 gl_->GenMailboxCHROMIUM(mailbox.name);
829 if (mailbox.IsZero()) {
833 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture_id);
834 gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
835 *sync_point = InsertSyncPoint();
839 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
841 if (mailbox.IsZero())
844 WaitSyncPoint(sync_point);
845 GLuint texture = CreateTexture();
846 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
847 gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
851 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
852 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
853 gl_->TexImage2D(GL_TEXTURE_2D,
864 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
865 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
866 gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
876 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
877 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
879 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
882 bool GLHelper::CanUseRgb565Readback() {
883 if(initialized_565_format_check_){
884 return support_565_format_;
886 const int kTestSize = 64;
887 GLuint dst_texture = 0u;
888 gl_->GenTextures(1, &dst_texture);
889 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
890 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
891 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
892 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
893 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
894 gl_->TexImage2D(GL_TEXTURE_2D,
901 GL_UNSIGNED_SHORT_5_6_5,
903 ScopedFramebuffer dst_framebuffer(gl_);
904 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
906 gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
907 GL_COLOR_ATTACHMENT0,
911 GLint ext_format = 0, ext_type = 0;
912 gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &ext_format);
913 gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &ext_type);
914 gl_->DeleteTextures(1, &dst_texture);
915 if ((ext_format == GL_RGB) && (ext_type == GL_UNSIGNED_SHORT_5_6_5)) {
916 support_565_format_ = true;
918 initialized_565_format_check_ = true;
919 return support_565_format_;
922 void GLHelper::CopyTextureToImpl::ReadbackPlane(
923 TextureFrameBufferPair* source,
924 const scoped_refptr<media::VideoFrame>& target,
927 const gfx::Rect& dst_subrect,
928 const base::Callback<void(bool)>& callback) {
929 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
930 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
931 (dst_subrect.x() >> size_shift);
932 ReadbackAsync(source->size(),
933 dst_subrect.width() >> size_shift,
934 target->stride(plane),
935 target->data(plane) + offset,
936 SkBitmap::kARGB_8888_Config,
940 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
941 0.257f, 0.504f, 0.098f, 0.0625f};
942 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
943 -0.148f, -0.291f, 0.439f, 0.5f};
944 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
945 0.439f, -0.368f, -0.071f, 0.5f};
947 // YUV readback constructors. Initiates the main scaler pipeline and
948 // one planar scaler for each of the Y, U and V planes.
949 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
951 CopyTextureToImpl* copy_impl,
952 GLHelperScaling* scaler_impl,
953 GLHelper::ScalerQuality quality,
954 const gfx::Size& src_size,
955 const gfx::Rect& src_subrect,
956 const gfx::Size& dst_size,
957 const gfx::Rect& dst_subrect,
958 bool flip_vertically)
960 copy_impl_(copy_impl),
962 dst_subrect_(dst_subrect),
964 scaler_impl->CreateScaler(quality,
971 scaler_impl->CreatePlanarScaler(
975 (dst_subrect.width() + 3) & ~3,
976 dst_subrect.height()),
977 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
979 kRGBtoYColorWeights)),
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 kRGBtoUColorWeights)),
992 scaler_impl->CreatePlanarScaler(
996 (dst_subrect.width() + 7) & ~7,
997 (dst_subrect.height() + 1) & ~1),
998 gfx::Size((dst_subrect.width() + 7) / 8,
999 (dst_subrect.height() + 1) / 2),
1001 kRGBtoVColorWeights)) {
1002 DCHECK(!(dst_size.width() & 1));
1003 DCHECK(!(dst_size.height() & 1));
1004 DCHECK(!(dst_subrect.width() & 1));
1005 DCHECK(!(dst_subrect.height() & 1));
1006 DCHECK(!(dst_subrect.x() & 1));
1007 DCHECK(!(dst_subrect.y() & 1));
1010 static void CallbackKeepingVideoFrameAlive(
1011 scoped_refptr<media::VideoFrame> video_frame,
1012 const base::Callback<void(bool)>& callback,
1014 callback.Run(success);
1017 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
1018 const gpu::Mailbox& mailbox,
1020 const scoped_refptr<media::VideoFrame>& target,
1021 const base::Callback<void(bool)>& callback) {
1022 GLuint mailbox_texture =
1023 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1025 // Scale texture to right size.
1026 scaler_.Scale(mailbox_texture);
1027 gl_->DeleteTextures(1, &mailbox_texture);
1029 // Convert the scaled texture in to Y, U and V planes.
1030 y_.Scale(scaler_.texture());
1031 u_.Scale(scaler_.texture());
1032 v_.Scale(scaler_.texture());
1034 if (target->coded_size() != dst_size_) {
1035 DCHECK(target->coded_size() == dst_size_);
1036 LOG(ERROR) << "ReadbackYUV size error!";
1037 callback.Run(false);
1041 // Read back planes, one at a time. Keep the video frame alive while doing the
1043 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
1045 media::VideoFrame::kYPlane,
1048 base::Bind(&nullcallback));
1049 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
1051 media::VideoFrame::kUPlane,
1054 base::Bind(&nullcallback));
1055 copy_impl_->ReadbackPlane(
1056 v_.texture_and_framebuffer(),
1058 media::VideoFrame::kVPlane,
1061 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1062 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1063 media::LetterboxYUV(target, dst_subrect_);
1066 // YUV readback constructors. Initiates the main scaler pipeline and
1067 // one planar scaler for each of the Y, U and V planes.
1068 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
1070 CopyTextureToImpl* copy_impl,
1071 GLHelperScaling* scaler_impl,
1072 GLHelper::ScalerQuality quality,
1073 const gfx::Size& src_size,
1074 const gfx::Rect& src_subrect,
1075 const gfx::Size& dst_size,
1076 const gfx::Rect& dst_subrect,
1077 bool flip_vertically)
1079 copy_impl_(copy_impl),
1080 dst_size_(dst_size),
1081 dst_subrect_(dst_subrect),
1084 scaler_impl->CreateScaler(quality,
1090 pass1_shader_(scaler_impl->CreateYuvMrtShader(
1092 gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
1093 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1095 GLHelperScaling::SHADER_YUV_MRT_PASS1)),
1096 pass2_shader_(scaler_impl->CreateYuvMrtShader(
1097 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
1100 (dst_subrect.width() + 7) / 8 * 2,
1101 dst_subrect.height()),
1102 gfx::Size((dst_subrect.width() + 7) / 8,
1103 (dst_subrect.height() + 1) / 2),
1105 GLHelperScaling::SHADER_YUV_MRT_PASS2)),
1106 y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
1109 gfx::Size((dst_subrect.width() + 7) / 8,
1110 (dst_subrect.height() + 1) / 2)),
1112 gfx::Size((dst_subrect.width() + 7) / 8,
1113 (dst_subrect.height() + 1) / 2)) {
1115 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
1116 gl->TexImage2D(GL_TEXTURE_2D,
1119 (dst_subrect.width() + 3) / 4,
1120 dst_subrect.height(),
1126 DCHECK(!(dst_size.width() & 1));
1127 DCHECK(!(dst_size.height() & 1));
1128 DCHECK(!(dst_subrect.width() & 1));
1129 DCHECK(!(dst_subrect.height() & 1));
1130 DCHECK(!(dst_subrect.x() & 1));
1131 DCHECK(!(dst_subrect.y() & 1));
1134 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
1135 const gpu::Mailbox& mailbox,
1137 const scoped_refptr<media::VideoFrame>& target,
1138 const base::Callback<void(bool)>& callback) {
1139 GLuint mailbox_texture =
1140 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
1143 if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
1144 // Optimization: SCALER_QUALITY_FAST is just a single bilinear
1145 // pass, which pass1_shader_ can do just as well, so let's skip
1146 // the actual scaling in that case.
1147 texture = mailbox_texture;
1149 // Scale texture to right size.
1150 scaler_.Scale(mailbox_texture);
1151 texture = scaler_.texture();
1154 std::vector<GLuint> outputs(2);
1155 // Convert the scaled texture in to Y, U and V planes.
1156 outputs[0] = y_.texture();
1158 pass1_shader_->Execute(texture, outputs);
1160 gl_->DeleteTextures(1, &mailbox_texture);
1162 outputs[0] = u_.texture();
1163 outputs[1] = v_.texture();
1164 pass2_shader_->Execute(uv_, outputs);
1166 if (target->coded_size() != dst_size_) {
1167 DCHECK(target->coded_size() == dst_size_);
1168 LOG(ERROR) << "ReadbackYUV size error!";
1169 callback.Run(false);
1173 // Read back planes, one at a time.
1174 copy_impl_->ReadbackPlane(&y_,
1176 media::VideoFrame::kYPlane,
1179 base::Bind(&nullcallback));
1180 copy_impl_->ReadbackPlane(&u_,
1182 media::VideoFrame::kUPlane,
1185 base::Bind(&nullcallback));
1186 copy_impl_->ReadbackPlane(
1189 media::VideoFrame::kVPlane,
1192 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
1193 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
1194 media::LetterboxYUV(target, dst_subrect_);
1197 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
1198 GLHelper::ScalerQuality quality,
1199 const gfx::Size& src_size,
1200 const gfx::Rect& src_subrect,
1201 const gfx::Size& dst_size,
1202 const gfx::Rect& dst_subrect,
1203 bool flip_vertically,
1205 helper_->InitScalerImpl();
1206 if (max_draw_buffers_ >= 2 && use_mrt) {
1207 return new ReadbackYUV_MRT(gl_,
1209 helper_->scaler_impl_.get(),
1217 return new ReadbackYUVImpl(gl_,
1219 helper_->scaler_impl_.get(),
1228 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1229 ScalerQuality quality,
1230 const gfx::Size& src_size,
1231 const gfx::Rect& src_subrect,
1232 const gfx::Size& dst_size,
1233 const gfx::Rect& dst_subrect,
1234 bool flip_vertically,
1236 InitCopyTextToImpl();
1237 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1246 } // namespace content