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. 4 5 #include "content/common/gpu/client/gl_helper.h" 6 7 #include <queue> 8 #include <string> 9 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" 29 30 using gpu::gles2::GLES2Interface; 31 32 namespace { 33 34 class ScopedFlush { 35 public: 36 explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} 37 38 ~ScopedFlush() { gl_->Flush(); } 39 40 private: 41 gpu::gles2::GLES2Interface* gl_; 42 43 DISALLOW_COPY_AND_ASSIGN(ScopedFlush); 44 }; 45 46 // Helper class for allocating and holding an RGBA texture of a given 47 // size and an associated framebuffer. 48 class TextureFrameBufferPair { 49 public: 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, 54 0, 55 GL_RGBA, 56 size.width(), 57 size.height(), 58 0, 59 GL_RGBA, 60 GL_UNSIGNED_BYTE, 61 NULL); 62 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( 63 gl, framebuffer_); 64 gl->FramebufferTexture2D( 65 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); 66 } 67 68 GLuint texture() const { return texture_.id(); } 69 GLuint framebuffer() const { return framebuffer_.id(); } 70 gfx::Size size() const { return size_; } 71 72 private: 73 content::ScopedTexture texture_; 74 content::ScopedFramebuffer framebuffer_; 75 gfx::Size size_; 76 77 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair); 78 }; 79 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. 83 class ScalerHolder { 84 public: 85 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler) 86 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {} 87 88 void Scale(GLuint src_texture) { 89 scaler_->Scale(src_texture, texture_and_framebuffer_.texture()); 90 } 91 92 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); } 93 TextureFrameBufferPair* texture_and_framebuffer() { 94 return &texture_and_framebuffer_; 95 } 96 GLuint texture() const { return texture_and_framebuffer_.texture(); } 97 98 private: 99 TextureFrameBufferPair texture_and_framebuffer_; 100 scoped_ptr<content::GLHelper::ScalerInterface> scaler_; 101 102 DISALLOW_COPY_AND_ASSIGN(ScalerHolder); 103 }; 104 105 } // namespace 106 107 namespace content { 108 typedef GLHelperReadbackSupport::FormatSupport FormatSupport; 109 110 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates 111 // the data needed for it. 112 class GLHelper::CopyTextureToImpl 113 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> { 114 public: 115 CopyTextureToImpl(GLES2Interface* gl, 116 gpu::ContextSupport* context_support, 117 GLHelper* helper) 118 : gl_(gl), 119 context_support_(context_support), 120 helper_(helper), 121 flush_(gl), 122 max_draw_buffers_(0) { 123 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS); 124 if (!extensions) 125 return; 126 std::string extensions_string = 127 " " + std::string(reinterpret_cast<const char*>(extensions)) + " "; 128 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) { 129 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_); 130 } 131 } 132 ~CopyTextureToImpl() { CancelRequests(); } 133 134 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, 135 uint32 sync_point) { 136 return helper_->ConsumeMailboxToTexture(mailbox, sync_point); 137 } 138 139 void CropScaleReadbackAndCleanTexture( 140 GLuint src_texture, 141 const gfx::Size& src_size, 142 const gfx::Rect& src_subrect, 143 const gfx::Size& dst_size, 144 unsigned char* out, 145 const SkColorType out_color_type, 146 const base::Callback<void(bool)>& callback, 147 GLHelper::ScalerQuality quality); 148 149 void ReadbackTextureSync(GLuint texture, 150 const gfx::Rect& src_rect, 151 unsigned char* out, 152 SkColorType format); 153 154 void ReadbackTextureAsync(GLuint texture, 155 const gfx::Size& dst_size, 156 unsigned char* out, 157 SkColorType color_type, 158 const base::Callback<void(bool)>& callback); 159 160 // Reads back bytes from the currently bound frame buffer. 161 // Note that dst_size is specified in bytes, not pixels. 162 void ReadbackAsync(const gfx::Size& dst_size, 163 int32 bytes_per_row, // generally dst_size.width() * 4 164 int32 row_stride_bytes, // generally dst_size.width() * 4 165 unsigned char* out, 166 GLenum format, 167 GLenum type, 168 size_t bytes_per_pixel, 169 const base::Callback<void(bool)>& callback); 170 171 void ReadbackPlane(TextureFrameBufferPair* source, 172 const scoped_refptr<media::VideoFrame>& target, 173 int plane, 174 int size_shift, 175 const gfx::Rect& dst_subrect, 176 ReadbackSwizzle swizzle, 177 const base::Callback<void(bool)>& callback); 178 179 GLuint CopyAndScaleTexture(GLuint texture, 180 const gfx::Size& src_size, 181 const gfx::Size& dst_size, 182 bool vertically_flip_texture, 183 GLHelper::ScalerQuality quality); 184 185 ReadbackYUVInterface* CreateReadbackPipelineYUV( 186 GLHelper::ScalerQuality quality, 187 const gfx::Size& src_size, 188 const gfx::Rect& src_subrect, 189 const gfx::Size& dst_size, 190 const gfx::Rect& dst_subrect, 191 bool flip_vertically, 192 bool use_mrt); 193 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_; } 197 198 FormatSupport GetReadbackConfig(SkColorType color_type, 199 bool can_swizzle, 200 GLenum* format, 201 GLenum* type, 202 size_t* bytes_per_pixel); 203 204 private: 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. 212 struct Request { 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_) 218 : done(false), 219 size(size_), 220 bytes_per_row(bytes_per_row_), 221 row_stride_bytes(row_stride_bytes_), 222 pixels(pixels_), 223 callback(callback_), 224 buffer(0), 225 query(0) {} 226 227 bool done; 228 gfx::Size size; 229 int bytes_per_row; 230 int row_stride_bytes; 231 unsigned char* pixels; 232 base::Callback<void(bool)> callback; 233 GLuint buffer; 234 GLuint query; 235 }; 236 237 // A readback pipeline that also converts the data to YUV before 238 // reading it back. 239 class ReadbackYUVImpl : public ReadbackYUVInterface { 240 public: 241 ReadbackYUVImpl(GLES2Interface* gl, 242 CopyTextureToImpl* copy_impl, 243 GLHelperScaling* scaler_impl, 244 GLHelper::ScalerQuality quality, 245 const gfx::Size& src_size, 246 const gfx::Rect& src_subrect, 247 const gfx::Size& dst_size, 248 const gfx::Rect& dst_subrect, 249 bool flip_vertically, 250 ReadbackSwizzle swizzle); 251 252 virtual void ReadbackYUV(const gpu::Mailbox& mailbox, 253 uint32 sync_point, 254 const scoped_refptr<media::VideoFrame>& target, 255 const base::Callback<void(bool)>& callback) 256 OVERRIDE; 257 258 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); } 259 260 private: 261 GLES2Interface* gl_; 262 CopyTextureToImpl* copy_impl_; 263 gfx::Size dst_size_; 264 gfx::Rect dst_subrect_; 265 ReadbackSwizzle swizzle_; 266 ScalerHolder scaler_; 267 ScalerHolder y_; 268 ScalerHolder u_; 269 ScalerHolder v_; 270 271 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl); 272 }; 273 274 // A readback pipeline that also converts the data to YUV before 275 // reading it back. This one uses Multiple Render Targets, which 276 // may not be supported on all platforms. 277 class ReadbackYUV_MRT : public ReadbackYUVInterface { 278 public: 279 ReadbackYUV_MRT(GLES2Interface* gl, 280 CopyTextureToImpl* copy_impl, 281 GLHelperScaling* scaler_impl, 282 GLHelper::ScalerQuality quality, 283 const gfx::Size& src_size, 284 const gfx::Rect& src_subrect, 285 const gfx::Size& dst_size, 286 const gfx::Rect& dst_subrect, 287 bool flip_vertically, 288 ReadbackSwizzle swizzle); 289 290 virtual void ReadbackYUV(const gpu::Mailbox& mailbox, 291 uint32 sync_point, 292 const scoped_refptr<media::VideoFrame>& target, 293 const base::Callback<void(bool)>& callback) 294 OVERRIDE; 295 296 virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); } 297 298 private: 299 GLES2Interface* gl_; 300 CopyTextureToImpl* copy_impl_; 301 gfx::Size dst_size_; 302 gfx::Rect dst_subrect_; 303 GLHelper::ScalerQuality quality_; 304 ReadbackSwizzle swizzle_; 305 ScalerHolder scaler_; 306 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_; 307 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_; 308 TextureFrameBufferPair y_; 309 ScopedTexture uv_; 310 TextureFrameBufferPair u_; 311 TextureFrameBufferPair v_; 312 313 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT); 314 }; 315 316 // Copies the block of pixels specified with |src_subrect| from |src_texture|, 317 // scales it to |dst_size|, writes it into a texture, and returns its ID. 318 // |src_size| is the size of |src_texture|. 319 GLuint ScaleTexture(GLuint src_texture, 320 const gfx::Size& src_size, 321 const gfx::Rect& src_subrect, 322 const gfx::Size& dst_size, 323 bool vertically_flip_texture, 324 bool swizzle, 325 SkColorType color_type, 326 GLHelper::ScalerQuality quality); 327 328 // Converts each four consecutive pixels of the source texture into one pixel 329 // in the result texture with each pixel channel representing the grayscale 330 // color of one of the four original pixels: 331 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4 332 // The resulting texture is still an RGBA texture (which is ~4 times narrower 333 // than the original). If rendered directly, it wouldn't show anything useful, 334 // but the data in it can be used to construct a grayscale image. 335 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It 336 // is equal to src_size.width()/4 rounded upwards. Some channels in the last 337 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain 338 // useful data. 339 // If swizzle is set to true, the transformed pixels are reordered: 340 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4. 341 GLuint EncodeTextureAsGrayscale(GLuint src_texture, 342 const gfx::Size& src_size, 343 gfx::Size* const encoded_texture_size, 344 bool vertically_flip_texture, 345 bool swizzle); 346 347 static void nullcallback(bool success) {} 348 void ReadbackDone(Request *request, int bytes_per_pixel); 349 void FinishRequest(Request* request, bool result); 350 void CancelRequests(); 351 352 static const float kRGBtoYColorWeights[]; 353 static const float kRGBtoUColorWeights[]; 354 static const float kRGBtoVColorWeights[]; 355 static const float kRGBtoGrayscaleColorWeights[]; 356 357 GLES2Interface* gl_; 358 gpu::ContextSupport* context_support_; 359 GLHelper* helper_; 360 361 // A scoped flush that will ensure all resource deletions are flushed when 362 // this object is destroyed. Must be declared before other Scoped* fields. 363 ScopedFlush flush_; 364 365 std::queue<Request*> request_queue_; 366 GLint max_draw_buffers_; 367 }; 368 369 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality, 370 const gfx::Size& src_size, 371 const gfx::Rect& src_subrect, 372 const gfx::Size& dst_size, 373 bool vertically_flip_texture, 374 bool swizzle) { 375 InitScalerImpl(); 376 return scaler_impl_->CreateScaler(quality, 377 src_size, 378 src_subrect, 379 dst_size, 380 vertically_flip_texture, 381 swizzle); 382 } 383 384 GLuint GLHelper::CopyTextureToImpl::ScaleTexture( 385 GLuint src_texture, 386 const gfx::Size& src_size, 387 const gfx::Rect& src_subrect, 388 const gfx::Size& dst_size, 389 bool vertically_flip_texture, 390 bool swizzle, 391 SkColorType color_type, 392 GLHelper::ScalerQuality quality) { 393 GLuint dst_texture = 0u; 394 gl_->GenTextures(1, &dst_texture); 395 { 396 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE; 397 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); 398 399 // Use GL_RGBA for destination/temporary texture unless we're working with 400 // 16-bit data 401 if (color_type == kRGB_565_SkColorType) { 402 format = GL_RGB; 403 type = GL_UNSIGNED_SHORT_5_6_5; 404 } 405 406 gl_->TexImage2D(GL_TEXTURE_2D, 407 0, 408 format, 409 dst_size.width(), 410 dst_size.height(), 411 0, 412 format, 413 type, 414 NULL); 415 } 416 scoped_ptr<ScalerInterface> scaler( 417 helper_->CreateScaler(quality, 418 src_size, 419 src_subrect, 420 dst_size, 421 vertically_flip_texture, 422 swizzle)); 423 scaler->Scale(src_texture, dst_texture); 424 return dst_texture; 425 } 426 427 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale( 428 GLuint src_texture, 429 const gfx::Size& src_size, 430 gfx::Size* const encoded_texture_size, 431 bool vertically_flip_texture, 432 bool swizzle) { 433 GLuint dst_texture = 0u; 434 gl_->GenTextures(1, &dst_texture); 435 // The size of the encoded texture. 436 *encoded_texture_size = 437 gfx::Size((src_size.width() + 3) / 4, src_size.height()); 438 { 439 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); 440 gl_->TexImage2D(GL_TEXTURE_2D, 441 0, 442 GL_RGBA, 443 encoded_texture_size->width(), 444 encoded_texture_size->height(), 445 0, 446 GL_RGBA, 447 GL_UNSIGNED_BYTE, 448 NULL); 449 } 450 451 helper_->InitScalerImpl(); 452 scoped_ptr<ScalerInterface> grayscale_scaler( 453 helper_->scaler_impl_.get()->CreatePlanarScaler( 454 src_size, 455 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()), 456 *encoded_texture_size, 457 vertically_flip_texture, 458 swizzle, 459 kRGBtoGrayscaleColorWeights)); 460 grayscale_scaler->Scale(src_texture, dst_texture); 461 return dst_texture; 462 } 463 464 void GLHelper::CopyTextureToImpl::ReadbackAsync( 465 const gfx::Size& dst_size, 466 int32 bytes_per_row, 467 int32 row_stride_bytes, 468 unsigned char* out, 469 GLenum format, 470 GLenum type, 471 size_t bytes_per_pixel, 472 const base::Callback<void(bool)>& callback) { 473 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync"); 474 Request* request = 475 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback); 476 request_queue_.push(request); 477 request->buffer = 0u; 478 479 gl_->GenBuffers(1, &request->buffer); 480 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); 481 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 482 bytes_per_pixel * dst_size.GetArea(), 483 NULL, 484 GL_STREAM_READ); 485 486 request->query = 0u; 487 gl_->GenQueriesEXT(1, &request->query); 488 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query); 489 gl_->ReadPixels(0, 490 0, 491 dst_size.width(), 492 dst_size.height(), 493 format, 494 type, 495 NULL); 496 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM); 497 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); 498 context_support_->SignalQuery( 499 request->query, 500 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), 501 request, bytes_per_pixel)); 502 } 503 504 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( 505 GLuint src_texture, 506 const gfx::Size& src_size, 507 const gfx::Rect& src_subrect, 508 const gfx::Size& dst_size, 509 unsigned char* out, 510 const SkColorType out_color_type, 511 const base::Callback<void(bool)>& callback, 512 GLHelper::ScalerQuality quality) { 513 GLenum format, type; 514 size_t bytes_per_pixel; 515 SkColorType readback_color_type = out_color_type; 516 // Single-component textures are not supported by all GPUs, so we implement 517 // kAlpha_8_SkColorType support here via a special encoding (see below) using 518 // a 32-bit texture to represent an 8-bit image. 519 // Thus we use generic 32-bit readback in this case. 520 if (out_color_type == kAlpha_8_SkColorType) { 521 readback_color_type = kRGBA_8888_SkColorType; 522 } 523 524 FormatSupport supported = GetReadbackConfig( 525 readback_color_type, true, &format, &type, &bytes_per_pixel); 526 527 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { 528 callback.Run(false); 529 return; 530 } 531 532 GLuint texture = src_texture; 533 534 // Scale texture if needed 535 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we 536 // can do just as well in EncodeTextureAsGrayscale, which we will do if 537 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step 538 // in that case. 539 bool scale_texture = out_color_type != kAlpha_8_SkColorType || 540 quality != GLHelper::SCALER_QUALITY_FAST; 541 if (scale_texture) { 542 // Don't swizzle during the scale step for kAlpha_8_SkColorType. 543 // We will swizzle in the encode step below if needed. 544 bool scale_swizzle = out_color_type == kAlpha_8_SkColorType 545 ? false 546 : supported == GLHelperReadbackSupport::SWIZZLE; 547 texture = 548 ScaleTexture(src_texture, 549 src_size, 550 src_subrect, 551 dst_size, 552 true, 553 scale_swizzle, 554 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType 555 : out_color_type, 556 quality); 557 DCHECK(texture); 558 } 559 560 gfx::Size readback_texture_size = dst_size; 561 // Encode texture to grayscale if needed. 562 if (out_color_type == kAlpha_8_SkColorType) { 563 // Do the vertical flip here if we haven't already done it when we scaled 564 // the texture. 565 bool encode_as_grayscale_vertical_flip = !scale_texture; 566 // EncodeTextureAsGrayscale by default creates a texture which should be 567 // read back as RGBA, so need to swizzle if the readback format is BGRA. 568 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT; 569 GLuint tmp_texture = 570 EncodeTextureAsGrayscale(texture, 571 dst_size, 572 &readback_texture_size, 573 encode_as_grayscale_vertical_flip, 574 encode_as_grayscale_swizzle); 575 // If the scaled texture was created - delete it 576 if (scale_texture) 577 gl_->DeleteTextures(1, &texture); 578 texture = tmp_texture; 579 DCHECK(texture); 580 } 581 582 // Readback the pixels of the resulting texture 583 ScopedFramebuffer dst_framebuffer(gl_); 584 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, 585 dst_framebuffer); 586 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 587 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, 588 GL_COLOR_ATTACHMENT0, 589 GL_TEXTURE_2D, 590 texture, 591 0); 592 593 int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType 594 ? dst_size.width() 595 : dst_size.width() * bytes_per_pixel; 596 597 ReadbackAsync(readback_texture_size, 598 bytes_per_row, 599 bytes_per_row, 600 out, 601 format, 602 type, 603 bytes_per_pixel, 604 callback); 605 gl_->DeleteTextures(1, &texture); 606 } 607 608 void GLHelper::CopyTextureToImpl::ReadbackTextureSync( 609 GLuint texture, 610 const gfx::Rect& src_rect, 611 unsigned char* out, 612 SkColorType color_type) { 613 GLenum format, type; 614 size_t bytes_per_pixel; 615 FormatSupport supported = 616 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); 617 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { 618 return; 619 } 620 621 ScopedFramebuffer dst_framebuffer(gl_); 622 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, 623 dst_framebuffer); 624 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 625 gl_->FramebufferTexture2D( 626 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 627 gl_->ReadPixels(src_rect.x(), 628 src_rect.y(), 629 src_rect.width(), 630 src_rect.height(), 631 format, 632 type, 633 out); 634 } 635 636 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync( 637 GLuint texture, 638 const gfx::Size& dst_size, 639 unsigned char* out, 640 SkColorType color_type, 641 const base::Callback<void(bool)>& callback) { 642 GLenum format, type; 643 size_t bytes_per_pixel; 644 FormatSupport supported = 645 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); 646 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { 647 callback.Run(false); 648 return; 649 } 650 651 ScopedFramebuffer dst_framebuffer(gl_); 652 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, 653 dst_framebuffer); 654 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 655 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, 656 GL_COLOR_ATTACHMENT0, 657 GL_TEXTURE_2D, 658 texture, 659 0); 660 ReadbackAsync(dst_size, 661 dst_size.width() * bytes_per_pixel, 662 dst_size.width() * bytes_per_pixel, 663 out, 664 format, 665 type, 666 bytes_per_pixel, 667 callback); 668 } 669 670 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture( 671 GLuint src_texture, 672 const gfx::Size& src_size, 673 const gfx::Size& dst_size, 674 bool vertically_flip_texture, 675 GLHelper::ScalerQuality quality) { 676 return ScaleTexture(src_texture, 677 src_size, 678 gfx::Rect(src_size), 679 dst_size, 680 vertically_flip_texture, 681 false, 682 kRGBA_8888_SkColorType, // GL_RGBA 683 quality); 684 } 685 686 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request, 687 int bytes_per_pixel) { 688 TRACE_EVENT0("mirror", 689 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete"); 690 finished_request->done = true; 691 692 // We process transfer requests in the order they were received, regardless 693 // of the order we get the callbacks in. 694 while (!request_queue_.empty()) { 695 Request* request = request_queue_.front(); 696 if (!request->done) { 697 break; 698 } 699 700 bool result = false; 701 if (request->buffer != 0) { 702 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); 703 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM( 704 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); 705 if (data) { 706 result = true; 707 if (request->bytes_per_row == request->size.width() * bytes_per_pixel && 708 request->bytes_per_row == request->row_stride_bytes) { 709 memcpy(request->pixels, data, 710 request->size.GetArea() * bytes_per_pixel); 711 } else { 712 unsigned char* out = request->pixels; 713 for (int y = 0; y < request->size.height(); y++) { 714 memcpy(out, data, request->bytes_per_row); 715 out += request->row_stride_bytes; 716 data += request->size.width() * bytes_per_pixel; 717 } 718 } 719 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); 720 } 721 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); 722 } 723 FinishRequest(request, result); 724 } 725 } 726 727 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) { 728 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest"); 729 DCHECK(request_queue_.front() == request); 730 request_queue_.pop(); 731 request->callback.Run(result); 732 ScopedFlush flush(gl_); 733 if (request->query != 0) { 734 gl_->DeleteQueriesEXT(1, &request->query); 735 request->query = 0; 736 } 737 if (request->buffer != 0) { 738 gl_->DeleteBuffers(1, &request->buffer); 739 request->buffer = 0; 740 } 741 delete request; 742 } 743 744 void GLHelper::CopyTextureToImpl::CancelRequests() { 745 while (!request_queue_.empty()) { 746 Request* request = request_queue_.front(); 747 FinishRequest(request, false); 748 } 749 } 750 751 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig( 752 SkColorType color_type, 753 bool can_swizzle, 754 GLenum* format, 755 GLenum* type, 756 size_t* bytes_per_pixel) { 757 return helper_->readback_support_->GetReadbackConfig( 758 color_type, can_swizzle, format, type, bytes_per_pixel); 759 } 760 761 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support) 762 : gl_(gl), 763 context_support_(context_support), 764 readback_support_(new GLHelperReadbackSupport(gl)) {} 765 766 GLHelper::~GLHelper() {} 767 768 void GLHelper::CropScaleReadbackAndCleanTexture( 769 GLuint src_texture, 770 const gfx::Size& src_size, 771 const gfx::Rect& src_subrect, 772 const gfx::Size& dst_size, 773 unsigned char* out, 774 const SkColorType out_color_type, 775 const base::Callback<void(bool)>& callback, 776 GLHelper::ScalerQuality quality) { 777 InitCopyTextToImpl(); 778 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture, 779 src_size, 780 src_subrect, 781 dst_size, 782 out, 783 out_color_type, 784 callback, 785 quality); 786 } 787 788 void GLHelper::CropScaleReadbackAndCleanMailbox( 789 const gpu::Mailbox& src_mailbox, 790 uint32 sync_point, 791 const gfx::Size& src_size, 792 const gfx::Rect& src_subrect, 793 const gfx::Size& dst_size, 794 unsigned char* out, 795 const SkColorType out_color_type, 796 const base::Callback<void(bool)>& callback, 797 GLHelper::ScalerQuality quality) { 798 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point); 799 CropScaleReadbackAndCleanTexture(mailbox_texture, 800 src_size, 801 src_subrect, 802 dst_size, 803 out, 804 out_color_type, 805 callback, 806 quality); 807 gl_->DeleteTextures(1, &mailbox_texture); 808 } 809 810 void GLHelper::ReadbackTextureSync(GLuint texture, 811 const gfx::Rect& src_rect, 812 unsigned char* out, 813 SkColorType format) { 814 InitCopyTextToImpl(); 815 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format); 816 } 817 818 void GLHelper::ReadbackTextureAsync( 819 GLuint texture, 820 const gfx::Size& dst_size, 821 unsigned char* out, 822 SkColorType color_type, 823 const base::Callback<void(bool)>& callback) { 824 InitCopyTextToImpl(); 825 copy_texture_to_impl_->ReadbackTextureAsync(texture, 826 dst_size, 827 out, 828 color_type, 829 callback); 830 } 831 832 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) { 833 InitCopyTextToImpl(); 834 return copy_texture_to_impl_->CopyAndScaleTexture( 835 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST); 836 } 837 838 GLuint GLHelper::CopyAndScaleTexture(GLuint texture, 839 const gfx::Size& src_size, 840 const gfx::Size& dst_size, 841 bool vertically_flip_texture, 842 ScalerQuality quality) { 843 InitCopyTextToImpl(); 844 return copy_texture_to_impl_->CopyAndScaleTexture( 845 texture, src_size, dst_size, vertically_flip_texture, quality); 846 } 847 848 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) { 849 GLuint shader = gl_->CreateShader(type); 850 GLint length = strlen(source); 851 gl_->ShaderSource(shader, 1, &source, &length); 852 gl_->CompileShader(shader); 853 GLint compile_status = 0; 854 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); 855 if (!compile_status) { 856 GLint log_length = 0; 857 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); 858 if (log_length) { 859 scoped_ptr<GLchar[]> log(new GLchar[log_length]); 860 GLsizei returned_log_length = 0; 861 gl_->GetShaderInfoLog( 862 shader, log_length, &returned_log_length, log.get()); 863 LOG(ERROR) << std::string(log.get(), returned_log_length); 864 } 865 gl_->DeleteShader(shader); 866 return 0; 867 } 868 return shader; 869 } 870 871 void GLHelper::InitCopyTextToImpl() { 872 // Lazily initialize |copy_texture_to_impl_| 873 if (!copy_texture_to_impl_) 874 copy_texture_to_impl_.reset( 875 new CopyTextureToImpl(gl_, context_support_, this)); 876 } 877 878 void GLHelper::InitScalerImpl() { 879 // Lazily initialize |scaler_impl_| 880 if (!scaler_impl_) 881 scaler_impl_.reset(new GLHelperScaling(gl_, this)); 882 } 883 884 GLint GLHelper::MaxDrawBuffers() { 885 InitCopyTextToImpl(); 886 return copy_texture_to_impl_->MaxDrawBuffers(); 887 } 888 889 void GLHelper::CopySubBufferDamage(GLuint texture, 890 GLuint previous_texture, 891 const SkRegion& new_damage, 892 const SkRegion& old_damage) { 893 SkRegion region(old_damage); 894 if (region.op(new_damage, SkRegion::kDifference_Op)) { 895 ScopedFramebuffer dst_framebuffer(gl_); 896 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, 897 dst_framebuffer); 898 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 899 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, 900 GL_COLOR_ATTACHMENT0, 901 GL_TEXTURE_2D, 902 previous_texture, 903 0); 904 for (SkRegion::Iterator it(region); !it.done(); it.next()) { 905 const SkIRect& rect = it.rect(); 906 gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 907 0, 908 rect.x(), 909 rect.y(), 910 rect.x(), 911 rect.y(), 912 rect.width(), 913 rect.height()); 914 } 915 gl_->Flush(); 916 } 917 } 918 919 GLuint GLHelper::CreateTexture() { 920 GLuint texture = 0u; 921 gl_->GenTextures(1, &texture); 922 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 923 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 924 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 925 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 926 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 927 return texture; 928 } 929 930 void GLHelper::DeleteTexture(GLuint texture_id) { 931 gl_->DeleteTextures(1, &texture_id); 932 } 933 934 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); } 935 936 void GLHelper::WaitSyncPoint(uint32 sync_point) { 937 gl_->WaitSyncPointCHROMIUM(sync_point); 938 } 939 940 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture( 941 GLuint texture_id) { 942 gpu::Mailbox mailbox; 943 gl_->GenMailboxCHROMIUM(mailbox.name); 944 gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name); 945 return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint()); 946 } 947 948 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, 949 uint32 sync_point) { 950 if (mailbox.IsZero()) 951 return 0; 952 if (sync_point) 953 WaitSyncPoint(sync_point); 954 GLuint texture = 955 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 956 return texture; 957 } 958 959 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) { 960 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 961 gl_->TexImage2D(GL_TEXTURE_2D, 962 0, 963 GL_RGB, 964 size.width(), 965 size.height(), 966 0, 967 GL_RGB, 968 GL_UNSIGNED_BYTE, 969 NULL); 970 } 971 972 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) { 973 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 974 gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 975 0, 976 rect.x(), 977 rect.y(), 978 rect.x(), 979 rect.y(), 980 rect.width(), 981 rect.height()); 982 } 983 984 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) { 985 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); 986 gl_->CopyTexImage2D( 987 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0); 988 } 989 990 void GLHelper::Flush() { 991 gl_->Flush(); 992 } 993 994 void GLHelper::CopyTextureToImpl::ReadbackPlane( 995 TextureFrameBufferPair* source, 996 const scoped_refptr<media::VideoFrame>& target, 997 int plane, 998 int size_shift, 999 const gfx::Rect& dst_subrect, 1000 ReadbackSwizzle swizzle, 1001 const base::Callback<void(bool)>& callback) { 1002 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer()); 1003 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) + 1004 (dst_subrect.x() >> size_shift); 1005 ReadbackAsync(source->size(), 1006 dst_subrect.width() >> size_shift, 1007 target->stride(plane), 1008 target->data(plane) + offset, 1009 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA, 1010 GL_UNSIGNED_BYTE, 1011 4, 1012 callback); 1013 } 1014 1015 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { 1016 0.257f, 0.504f, 0.098f, 0.0625f}; 1017 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { 1018 -0.148f, -0.291f, 0.439f, 0.5f}; 1019 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { 1020 0.439f, -0.368f, -0.071f, 0.5f}; 1021 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = { 1022 0.213f, 0.715f, 0.072f, 0.0f}; 1023 1024 // YUV readback constructors. Initiates the main scaler pipeline and 1025 // one planar scaler for each of the Y, U and V planes. 1026 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( 1027 GLES2Interface* gl, 1028 CopyTextureToImpl* copy_impl, 1029 GLHelperScaling* scaler_impl, 1030 GLHelper::ScalerQuality quality, 1031 const gfx::Size& src_size, 1032 const gfx::Rect& src_subrect, 1033 const gfx::Size& dst_size, 1034 const gfx::Rect& dst_subrect, 1035 bool flip_vertically, 1036 ReadbackSwizzle swizzle) 1037 : gl_(gl), 1038 copy_impl_(copy_impl), 1039 dst_size_(dst_size), 1040 dst_subrect_(dst_subrect), 1041 swizzle_(swizzle), 1042 scaler_(gl, 1043 scaler_impl->CreateScaler(quality, 1044 src_size, 1045 src_subrect, 1046 dst_subrect.size(), 1047 flip_vertically, 1048 false)), 1049 y_(gl, 1050 scaler_impl->CreatePlanarScaler( 1051 dst_subrect.size(), 1052 gfx::Rect(0, 1053 0, 1054 (dst_subrect.width() + 3) & ~3, 1055 dst_subrect.height()), 1056 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()), 1057 false, 1058 (swizzle == kSwizzleBGRA), 1059 kRGBtoYColorWeights)), 1060 u_(gl, 1061 scaler_impl->CreatePlanarScaler( 1062 dst_subrect.size(), 1063 gfx::Rect(0, 1064 0, 1065 (dst_subrect.width() + 7) & ~7, 1066 (dst_subrect.height() + 1) & ~1), 1067 gfx::Size((dst_subrect.width() + 7) / 8, 1068 (dst_subrect.height() + 1) / 2), 1069 false, 1070 (swizzle == kSwizzleBGRA), 1071 kRGBtoUColorWeights)), 1072 v_(gl, 1073 scaler_impl->CreatePlanarScaler( 1074 dst_subrect.size(), 1075 gfx::Rect(0, 1076 0, 1077 (dst_subrect.width() + 7) & ~7, 1078 (dst_subrect.height() + 1) & ~1), 1079 gfx::Size((dst_subrect.width() + 7) / 8, 1080 (dst_subrect.height() + 1) / 2), 1081 false, 1082 (swizzle == kSwizzleBGRA), 1083 kRGBtoVColorWeights)) { 1084 DCHECK(!(dst_size.width() & 1)); 1085 DCHECK(!(dst_size.height() & 1)); 1086 DCHECK(!(dst_subrect.width() & 1)); 1087 DCHECK(!(dst_subrect.height() & 1)); 1088 DCHECK(!(dst_subrect.x() & 1)); 1089 DCHECK(!(dst_subrect.y() & 1)); 1090 } 1091 1092 static void CallbackKeepingVideoFrameAlive( 1093 scoped_refptr<media::VideoFrame> video_frame, 1094 const base::Callback<void(bool)>& callback, 1095 bool success) { 1096 callback.Run(success); 1097 } 1098 1099 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV( 1100 const gpu::Mailbox& mailbox, 1101 uint32 sync_point, 1102 const scoped_refptr<media::VideoFrame>& target, 1103 const base::Callback<void(bool)>& callback) { 1104 GLuint mailbox_texture = 1105 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point); 1106 1107 // Scale texture to right size. 1108 scaler_.Scale(mailbox_texture); 1109 gl_->DeleteTextures(1, &mailbox_texture); 1110 1111 // Convert the scaled texture in to Y, U and V planes. 1112 y_.Scale(scaler_.texture()); 1113 u_.Scale(scaler_.texture()); 1114 v_.Scale(scaler_.texture()); 1115 1116 if (target->coded_size() != dst_size_) { 1117 DCHECK(target->coded_size() == dst_size_); 1118 LOG(ERROR) << "ReadbackYUV size error!"; 1119 callback.Run(false); 1120 return; 1121 } 1122 1123 // Read back planes, one at a time. Keep the video frame alive while doing the 1124 // readback. 1125 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), 1126 target, 1127 media::VideoFrame::kYPlane, 1128 0, 1129 dst_subrect_, 1130 swizzle_, 1131 base::Bind(&nullcallback)); 1132 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), 1133 target, 1134 media::VideoFrame::kUPlane, 1135 1, 1136 dst_subrect_, 1137 swizzle_, 1138 base::Bind(&nullcallback)); 1139 copy_impl_->ReadbackPlane( 1140 v_.texture_and_framebuffer(), 1141 target, 1142 media::VideoFrame::kVPlane, 1143 1, 1144 dst_subrect_, 1145 swizzle_, 1146 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); 1147 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); 1148 media::LetterboxYUV(target.get(), dst_subrect_); 1149 } 1150 1151 // YUV readback constructors. Initiates the main scaler pipeline and 1152 // one planar scaler for each of the Y, U and V planes. 1153 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT( 1154 GLES2Interface* gl, 1155 CopyTextureToImpl* copy_impl, 1156 GLHelperScaling* scaler_impl, 1157 GLHelper::ScalerQuality quality, 1158 const gfx::Size& src_size, 1159 const gfx::Rect& src_subrect, 1160 const gfx::Size& dst_size, 1161 const gfx::Rect& dst_subrect, 1162 bool flip_vertically, 1163 ReadbackSwizzle swizzle) 1164 : gl_(gl), 1165 copy_impl_(copy_impl), 1166 dst_size_(dst_size), 1167 dst_subrect_(dst_subrect), 1168 quality_(quality), 1169 swizzle_(swizzle), 1170 scaler_(gl, 1171 scaler_impl->CreateScaler(quality, 1172 src_size, 1173 src_subrect, 1174 dst_subrect.size(), 1175 false, 1176 false)), 1177 pass1_shader_(scaler_impl->CreateYuvMrtShader( 1178 dst_subrect.size(), 1179 gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()), 1180 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()), 1181 flip_vertically, 1182 (swizzle == kSwizzleBGRA), 1183 GLHelperScaling::SHADER_YUV_MRT_PASS1)), 1184 pass2_shader_(scaler_impl->CreateYuvMrtShader( 1185 gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()), 1186 gfx::Rect(0, 1187 0, 1188 (dst_subrect.width() + 7) / 8 * 2, 1189 dst_subrect.height()), 1190 gfx::Size((dst_subrect.width() + 7) / 8, 1191 (dst_subrect.height() + 1) / 2), 1192 false, 1193 (swizzle == kSwizzleBGRA), 1194 GLHelperScaling::SHADER_YUV_MRT_PASS2)), 1195 y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())), 1196 uv_(gl), 1197 u_(gl, 1198 gfx::Size((dst_subrect.width() + 7) / 8, 1199 (dst_subrect.height() + 1) / 2)), 1200 v_(gl, 1201 gfx::Size((dst_subrect.width() + 7) / 8, 1202 (dst_subrect.height() + 1) / 2)) { 1203 1204 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_); 1205 gl->TexImage2D(GL_TEXTURE_2D, 1206 0, 1207 GL_RGBA, 1208 (dst_subrect.width() + 3) / 4, 1209 dst_subrect.height(), 1210 0, 1211 GL_RGBA, 1212 GL_UNSIGNED_BYTE, 1213 NULL); 1214 1215 DCHECK(!(dst_size.width() & 1)); 1216 DCHECK(!(dst_size.height() & 1)); 1217 DCHECK(!(dst_subrect.width() & 1)); 1218 DCHECK(!(dst_subrect.height() & 1)); 1219 DCHECK(!(dst_subrect.x() & 1)); 1220 DCHECK(!(dst_subrect.y() & 1)); 1221 } 1222 1223 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV( 1224 const gpu::Mailbox& mailbox, 1225 uint32 sync_point, 1226 const scoped_refptr<media::VideoFrame>& target, 1227 const base::Callback<void(bool)>& callback) { 1228 GLuint mailbox_texture = 1229 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point); 1230 1231 GLuint texture; 1232 if (quality_ == GLHelper::SCALER_QUALITY_FAST) { 1233 // Optimization: SCALER_QUALITY_FAST is just a single bilinear 1234 // pass, which pass1_shader_ can do just as well, so let's skip 1235 // the actual scaling in that case. 1236 texture = mailbox_texture; 1237 } else { 1238 // Scale texture to right size. 1239 scaler_.Scale(mailbox_texture); 1240 texture = scaler_.texture(); 1241 } 1242 1243 std::vector<GLuint> outputs(2); 1244 // Convert the scaled texture in to Y, U and V planes. 1245 outputs[0] = y_.texture(); 1246 outputs[1] = uv_; 1247 pass1_shader_->Execute(texture, outputs); 1248 1249 gl_->DeleteTextures(1, &mailbox_texture); 1250 1251 outputs[0] = u_.texture(); 1252 outputs[1] = v_.texture(); 1253 pass2_shader_->Execute(uv_, outputs); 1254 1255 if (target->coded_size() != dst_size_) { 1256 DCHECK(target->coded_size() == dst_size_); 1257 LOG(ERROR) << "ReadbackYUV size error!"; 1258 callback.Run(false); 1259 return; 1260 } 1261 1262 // Read back planes, one at a time. 1263 copy_impl_->ReadbackPlane(&y_, 1264 target, 1265 media::VideoFrame::kYPlane, 1266 0, 1267 dst_subrect_, 1268 swizzle_, 1269 base::Bind(&nullcallback)); 1270 copy_impl_->ReadbackPlane(&u_, 1271 target, 1272 media::VideoFrame::kUPlane, 1273 1, 1274 dst_subrect_, 1275 swizzle_, 1276 base::Bind(&nullcallback)); 1277 copy_impl_->ReadbackPlane( 1278 &v_, 1279 target, 1280 media::VideoFrame::kVPlane, 1281 1, 1282 dst_subrect_, 1283 swizzle_, 1284 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); 1285 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); 1286 media::LetterboxYUV(target.get(), dst_subrect_); 1287 } 1288 1289 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) { 1290 DCHECK(readback_support_.get()); 1291 GLenum format, type; 1292 size_t bytes_per_pixel; 1293 FormatSupport support = readback_support_->GetReadbackConfig( 1294 color_type, false, &format, &type, &bytes_per_pixel); 1295 1296 return (support == GLHelperReadbackSupport::SUPPORTED); 1297 } 1298 1299 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV( 1300 GLHelper::ScalerQuality quality, 1301 const gfx::Size& src_size, 1302 const gfx::Rect& src_subrect, 1303 const gfx::Size& dst_size, 1304 const gfx::Rect& dst_subrect, 1305 bool flip_vertically, 1306 bool use_mrt) { 1307 helper_->InitScalerImpl(); 1308 // Just query if the best readback configuration needs a swizzle In 1309 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle 1310 GLenum format, type; 1311 size_t bytes_per_pixel; 1312 FormatSupport supported = GetReadbackConfig( 1313 kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel); 1314 DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) && 1315 type == GL_UNSIGNED_BYTE); 1316 1317 ReadbackSwizzle swizzle = kSwizzleNone; 1318 if (supported == GLHelperReadbackSupport::SWIZZLE) 1319 swizzle = kSwizzleBGRA; 1320 1321 if (max_draw_buffers_ >= 2 && use_mrt) { 1322 return new ReadbackYUV_MRT(gl_, 1323 this, 1324 helper_->scaler_impl_.get(), 1325 quality, 1326 src_size, 1327 src_subrect, 1328 dst_size, 1329 dst_subrect, 1330 flip_vertically, 1331 swizzle); 1332 } 1333 return new ReadbackYUVImpl(gl_, 1334 this, 1335 helper_->scaler_impl_.get(), 1336 quality, 1337 src_size, 1338 src_subrect, 1339 dst_size, 1340 dst_subrect, 1341 flip_vertically, 1342 swizzle); 1343 } 1344 1345 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV( 1346 ScalerQuality quality, 1347 const gfx::Size& src_size, 1348 const gfx::Rect& src_subrect, 1349 const gfx::Size& dst_size, 1350 const gfx::Rect& dst_subrect, 1351 bool flip_vertically, 1352 bool use_mrt) { 1353 InitCopyTextToImpl(); 1354 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality, 1355 src_size, 1356 src_subrect, 1357 dst_size, 1358 dst_subrect, 1359 flip_vertically, 1360 use_mrt); 1361 } 1362 1363 } // namespace content 1364