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 "cc/resources/sync_point_helper.h" 19 #include "content/common/gpu/client/gl_helper_scaling.h" 20 #include "gpu/command_buffer/common/mailbox.h" 21 #include "media/base/video_frame.h" 22 #include "media/base/video_util.h" 23 #include "third_party/WebKit/public/platform/WebCString.h" 24 #include "third_party/skia/include/core/SkRegion.h" 25 #include "ui/gfx/rect.h" 26 #include "ui/gfx/size.h" 27 #include "ui/gl/gl_bindings.h" 28 29 using WebKit::WebGLId; 30 using WebKit::WebGraphicsContext3D; 31 32 namespace { 33 34 // Helper class for allocating and holding an RGBA texture of a given 35 // size and an associated framebuffer. 36 class TextureFrameBufferPair { 37 public: 38 TextureFrameBufferPair(WebGraphicsContext3D* context, 39 gfx::Size size) 40 : texture_(context, context->createTexture()), 41 framebuffer_(context, context->createFramebuffer()), 42 size_(size) { 43 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context, 44 texture_); 45 context->texImage2D(GL_TEXTURE_2D, 46 0, 47 GL_RGBA, 48 size.width(), 49 size.height(), 50 0, 51 GL_RGBA, 52 GL_UNSIGNED_BYTE, 53 NULL); 54 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( 55 context, 56 framebuffer_); 57 context->framebufferTexture2D(GL_FRAMEBUFFER, 58 GL_COLOR_ATTACHMENT0, 59 GL_TEXTURE_2D, 60 texture_, 61 0); 62 } 63 64 WebGLId texture() const { return texture_.id(); } 65 WebGLId framebuffer() const { return framebuffer_.id(); } 66 gfx::Size size() const { return size_; } 67 68 private: 69 content::ScopedTexture texture_; 70 content::ScopedFramebuffer framebuffer_; 71 gfx::Size size_; 72 73 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair); 74 }; 75 76 // Helper class for holding a scaler, a texture for the output of that 77 // scaler and an associated frame buffer. This is inteded to be used 78 // when the output of a scaler is to be sent to a readback. 79 class ScalerHolder { 80 public: 81 ScalerHolder(WebGraphicsContext3D* context, 82 content::GLHelper::ScalerInterface *scaler) 83 : texture_and_framebuffer_(context, scaler->DstSize()), 84 scaler_(scaler) { 85 } 86 87 void Scale(WebKit::WebGLId src_texture) { 88 scaler_->Scale(src_texture, texture_and_framebuffer_.texture()); 89 } 90 91 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); } 92 TextureFrameBufferPair *texture_and_framebuffer() { 93 return &texture_and_framebuffer_; 94 } 95 WebGLId texture() const { return texture_and_framebuffer_.texture(); } 96 97 private: 98 TextureFrameBufferPair texture_and_framebuffer_; 99 scoped_ptr<content::GLHelper::ScalerInterface> scaler_; 100 101 DISALLOW_COPY_AND_ASSIGN(ScalerHolder); 102 }; 103 104 } // namespace 105 106 namespace content { 107 108 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates 109 // the data needed for it. 110 class GLHelper::CopyTextureToImpl : 111 public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> { 112 public: 113 CopyTextureToImpl(WebGraphicsContext3D* context, 114 GLHelper* helper) 115 : context_(context), 116 helper_(helper), 117 flush_(context), 118 max_draw_buffers_(0) { 119 std::string extensions_string = " " + 120 UTF16ToASCII(context_->getString(GL_EXTENSIONS)) + " "; 121 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) { 122 context_->getIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers_); 123 } 124 } 125 ~CopyTextureToImpl() { 126 CancelRequests(); 127 } 128 129 WebGLId ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, 130 uint32 sync_point) { 131 return helper_->ConsumeMailboxToTexture(mailbox, sync_point); 132 } 133 134 void CropScaleReadbackAndCleanTexture( 135 WebGLId src_texture, 136 const gfx::Size& src_size, 137 const gfx::Rect& src_subrect, 138 const gfx::Size& dst_size, 139 unsigned char* out, 140 const base::Callback<void(bool)>& callback, 141 GLHelper::ScalerQuality quality); 142 143 void ReadbackTextureSync(WebGLId texture, 144 const gfx::Rect& src_rect, 145 unsigned char* out); 146 147 // Reads back bytes from the currently bound frame buffer. 148 // Note that dst_size is specified in bytes, not pixels. 149 void ReadbackAsync( 150 const gfx::Size& dst_size, 151 int32 bytes_per_row, // generally dst_size.width() * 4 152 int32 row_stride_bytes, // generally dst_size.width() * 4 153 unsigned char* out, 154 const base::Callback<void(bool)>& callback); 155 156 void ReadbackPlane(TextureFrameBufferPair* source, 157 const scoped_refptr<media::VideoFrame>& target, 158 int plane, 159 int size_shift, 160 const gfx::Rect& dst_subrect, 161 const base::Callback<void(bool)>& callback); 162 163 WebKit::WebGLId CopyAndScaleTexture(WebGLId texture, 164 const gfx::Size& src_size, 165 const gfx::Size& dst_size, 166 bool vertically_flip_texture, 167 GLHelper::ScalerQuality quality); 168 169 ReadbackYUVInterface* CreateReadbackPipelineYUV( 170 GLHelper::ScalerQuality quality, 171 const gfx::Size& src_size, 172 const gfx::Rect& src_subrect, 173 const gfx::Size& dst_size, 174 const gfx::Rect& dst_subrect, 175 bool flip_vertically, 176 bool use_mrt); 177 178 // Returns the maximum number of draw buffers available, 179 // 0 if GL_EXT_draw_buffers is not available. 180 WebKit::WGC3Dint MaxDrawBuffers() const { 181 return max_draw_buffers_; 182 } 183 184 private: 185 // A single request to CropScaleReadbackAndCleanTexture. 186 // The main thread can cancel the request, before it's handled by the helper 187 // thread, by resetting the texture and pixels fields. Alternatively, the 188 // thread marks that it handles the request by resetting the pixels field 189 // (meaning it guarantees that the callback with be called). 190 // In either case, the callback must be called exactly once, and the texture 191 // must be deleted by the main thread context. 192 struct Request { 193 Request(const gfx::Size& size_, 194 int32 bytes_per_row_, 195 int32 row_stride_bytes_, 196 unsigned char* pixels_, 197 const base::Callback<void(bool)>& callback_) 198 : done(false), 199 size(size_), 200 bytes_per_row(bytes_per_row_), 201 row_stride_bytes(row_stride_bytes_), 202 pixels(pixels_), 203 callback(callback_), 204 buffer(0), 205 query(0) { 206 } 207 208 bool done; 209 gfx::Size size; 210 int bytes_per_row; 211 int row_stride_bytes; 212 unsigned char* pixels; 213 base::Callback<void(bool)> callback; 214 GLuint buffer; 215 WebKit::WebGLId query; 216 }; 217 218 // A readback pipeline that also converts the data to YUV before 219 // reading it back. 220 class ReadbackYUVImpl : public ReadbackYUVInterface { 221 public: 222 ReadbackYUVImpl(WebGraphicsContext3D* context, 223 CopyTextureToImpl* copy_impl, 224 GLHelperScaling* scaler_impl, 225 GLHelper::ScalerQuality quality, 226 const gfx::Size& src_size, 227 const gfx::Rect& src_subrect, 228 const gfx::Size& dst_size, 229 const gfx::Rect& dst_subrect, 230 bool flip_vertically); 231 232 virtual void ReadbackYUV( 233 const gpu::Mailbox& mailbox, 234 uint32 sync_point, 235 const scoped_refptr<media::VideoFrame>& target, 236 const base::Callback<void(bool)>& callback) OVERRIDE; 237 238 virtual ScalerInterface* scaler() OVERRIDE { 239 return scaler_.scaler(); 240 } 241 242 private: 243 WebGraphicsContext3D* context_; 244 CopyTextureToImpl* copy_impl_; 245 gfx::Size dst_size_; 246 gfx::Rect dst_subrect_; 247 ScalerHolder scaler_; 248 ScalerHolder y_; 249 ScalerHolder u_; 250 ScalerHolder v_; 251 252 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl); 253 }; 254 255 // A readback pipeline that also converts the data to YUV before 256 // reading it back. This one uses Multiple Render Targets, which 257 // may not be supported on all platforms. 258 class ReadbackYUV_MRT : public ReadbackYUVInterface { 259 public: 260 ReadbackYUV_MRT(WebGraphicsContext3D* context, 261 CopyTextureToImpl* copy_impl, 262 GLHelperScaling* scaler_impl, 263 GLHelper::ScalerQuality quality, 264 const gfx::Size& src_size, 265 const gfx::Rect& src_subrect, 266 const gfx::Size& dst_size, 267 const gfx::Rect& dst_subrect, 268 bool flip_vertically); 269 270 virtual void ReadbackYUV( 271 const gpu::Mailbox& mailbox, 272 uint32 sync_point, 273 const scoped_refptr<media::VideoFrame>& target, 274 const base::Callback<void(bool)>& callback) OVERRIDE; 275 276 virtual ScalerInterface* scaler() OVERRIDE { 277 return scaler_.scaler(); 278 } 279 280 private: 281 WebGraphicsContext3D* context_; 282 CopyTextureToImpl* copy_impl_; 283 gfx::Size dst_size_; 284 gfx::Rect dst_subrect_; 285 ScalerHolder scaler_; 286 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_; 287 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_; 288 TextureFrameBufferPair y_; 289 ScopedTexture uv_; 290 TextureFrameBufferPair u_; 291 TextureFrameBufferPair v_; 292 293 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT); 294 }; 295 296 // Copies the block of pixels specified with |src_subrect| from |src_texture|, 297 // scales it to |dst_size|, writes it into a texture, and returns its ID. 298 // |src_size| is the size of |src_texture|. 299 WebGLId ScaleTexture(WebGLId src_texture, 300 const gfx::Size& src_size, 301 const gfx::Rect& src_subrect, 302 const gfx::Size& dst_size, 303 bool vertically_flip_texture, 304 bool swizzle, 305 GLHelper::ScalerQuality quality); 306 307 static void nullcallback(bool success) {} 308 void ReadbackDone(Request *request); 309 void FinishRequest(Request* request, bool result); 310 void CancelRequests(); 311 312 static const float kRGBtoYColorWeights[]; 313 static const float kRGBtoUColorWeights[]; 314 static const float kRGBtoVColorWeights[]; 315 316 WebGraphicsContext3D* context_; 317 GLHelper* helper_; 318 319 // A scoped flush that will ensure all resource deletions are flushed when 320 // this object is destroyed. Must be declared before other Scoped* fields. 321 ScopedFlush flush_; 322 323 std::queue<Request*> request_queue_; 324 WebKit::WGC3Dint max_draw_buffers_; 325 }; 326 327 GLHelper::ScalerInterface* GLHelper::CreateScaler( 328 ScalerQuality quality, 329 const gfx::Size& src_size, 330 const gfx::Rect& src_subrect, 331 const gfx::Size& dst_size, 332 bool vertically_flip_texture, 333 bool swizzle) { 334 InitScalerImpl(); 335 return scaler_impl_->CreateScaler(quality, 336 src_size, 337 src_subrect, 338 dst_size, 339 vertically_flip_texture, 340 swizzle); 341 } 342 343 WebGLId GLHelper::CopyTextureToImpl::ScaleTexture( 344 WebGLId src_texture, 345 const gfx::Size& src_size, 346 const gfx::Rect& src_subrect, 347 const gfx::Size& dst_size, 348 bool vertically_flip_texture, 349 bool swizzle, 350 GLHelper::ScalerQuality quality) { 351 scoped_ptr<ScalerInterface> scaler( 352 helper_->CreateScaler(quality, 353 src_size, 354 src_subrect, 355 dst_size, 356 vertically_flip_texture, 357 swizzle)); 358 359 WebGLId dst_texture = context_->createTexture(); 360 { 361 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, dst_texture); 362 context_->texImage2D(GL_TEXTURE_2D, 363 0, 364 GL_RGBA, 365 dst_size.width(), 366 dst_size.height(), 367 0, 368 GL_RGBA, 369 GL_UNSIGNED_BYTE, 370 NULL); 371 } 372 scaler->Scale(src_texture, dst_texture); 373 return dst_texture; 374 } 375 376 void GLHelper::CopyTextureToImpl::ReadbackAsync( 377 const gfx::Size& dst_size, 378 int32 bytes_per_row, 379 int32 row_stride_bytes, 380 unsigned char* out, 381 const base::Callback<void(bool)>& callback) { 382 Request* request = new Request(dst_size, 383 bytes_per_row, 384 row_stride_bytes, 385 out, 386 callback); 387 request_queue_.push(request); 388 request->buffer = context_->createBuffer(); 389 context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 390 request->buffer); 391 context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 392 4 * dst_size.GetArea(), 393 NULL, 394 GL_STREAM_READ); 395 396 request->query = context_->createQueryEXT(); 397 context_->beginQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM, 398 request->query); 399 context_->readPixels(0, 0, dst_size.width(), dst_size.height(), 400 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 401 context_->endQueryEXT(GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM); 402 context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); 403 cc::SyncPointHelper::SignalQuery( 404 context_, 405 request->query, 406 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request)); 407 } 408 409 410 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( 411 WebGLId src_texture, 412 const gfx::Size& src_size, 413 const gfx::Rect& src_subrect, 414 const gfx::Size& dst_size, 415 unsigned char* out, 416 const base::Callback<void(bool)>& callback, 417 GLHelper::ScalerQuality quality) { 418 WebGLId texture = ScaleTexture(src_texture, 419 src_size, 420 src_subrect, 421 dst_size, 422 true, 423 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT 424 true, 425 #else 426 false, 427 #endif 428 quality); 429 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); 430 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, 431 dst_framebuffer); 432 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 433 context_->framebufferTexture2D(GL_FRAMEBUFFER, 434 GL_COLOR_ATTACHMENT0, 435 GL_TEXTURE_2D, 436 texture, 437 0); 438 ReadbackAsync(dst_size, 439 dst_size.width() * 4, 440 dst_size.width() * 4, 441 out, 442 callback); 443 context_->deleteTexture(texture); 444 } 445 446 void GLHelper::CopyTextureToImpl::ReadbackTextureSync( 447 WebGLId texture, 448 const gfx::Rect& src_rect, 449 unsigned char* out) { 450 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); 451 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, 452 dst_framebuffer); 453 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 454 context_->framebufferTexture2D(GL_FRAMEBUFFER, 455 GL_COLOR_ATTACHMENT0, 456 GL_TEXTURE_2D, 457 texture, 458 0); 459 context_->readPixels(src_rect.x(), 460 src_rect.y(), 461 src_rect.width(), 462 src_rect.height(), 463 GL_RGBA, 464 GL_UNSIGNED_BYTE, 465 out); 466 } 467 468 WebKit::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture( 469 WebGLId src_texture, 470 const gfx::Size& src_size, 471 const gfx::Size& dst_size, 472 bool vertically_flip_texture, 473 GLHelper::ScalerQuality quality) { 474 return ScaleTexture(src_texture, 475 src_size, 476 gfx::Rect(src_size), 477 dst_size, 478 vertically_flip_texture, 479 false, 480 quality); 481 } 482 483 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request) { 484 TRACE_EVENT0("mirror", 485 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete"); 486 finished_request->done = true; 487 488 // We process transfer requests in the order they were received, regardless 489 // of the order we get the callbacks in. 490 while (!request_queue_.empty()) { 491 Request* request = request_queue_.front(); 492 if (!request->done) { 493 break; 494 } 495 496 bool result = false; 497 if (request->buffer != 0) { 498 context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 499 request->buffer); 500 unsigned char* data = static_cast<unsigned char *>( 501 context_->mapBufferCHROMIUM( 502 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); 503 if (data) { 504 result = true; 505 if (request->bytes_per_row == request->size.width() * 4 && 506 request->bytes_per_row == request->row_stride_bytes) { 507 memcpy(request->pixels, data, request->size.GetArea() * 4); 508 } else { 509 unsigned char* out = request->pixels; 510 for (int y = 0; y < request->size.height(); y++) { 511 memcpy(out, data, request->bytes_per_row); 512 out += request->row_stride_bytes; 513 data += request->size.width() * 4; 514 } 515 } 516 context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); 517 } 518 context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); 519 } 520 521 FinishRequest(request, result); 522 } 523 } 524 525 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, 526 bool result) { 527 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest"); 528 DCHECK(request_queue_.front() == request); 529 request_queue_.pop(); 530 request->callback.Run(result); 531 ScopedFlush flush(context_); 532 if (request->query != 0) { 533 context_->deleteQueryEXT(request->query); 534 request->query = 0; 535 } 536 if (request->buffer != 0) { 537 context_->deleteBuffer(request->buffer); 538 request->buffer = 0; 539 } 540 delete request; 541 } 542 543 void GLHelper::CopyTextureToImpl::CancelRequests() { 544 while (!request_queue_.empty()) { 545 Request* request = request_queue_.front(); 546 FinishRequest(request, false); 547 } 548 } 549 550 GLHelper::GLHelper(WebKit::WebGraphicsContext3D* context) 551 : context_(context) { 552 } 553 554 GLHelper::~GLHelper() { 555 } 556 557 void GLHelper::CropScaleReadbackAndCleanTexture( 558 WebGLId src_texture, 559 const gfx::Size& src_size, 560 const gfx::Rect& src_subrect, 561 const gfx::Size& dst_size, 562 unsigned char* out, 563 const base::Callback<void(bool)>& callback) { 564 InitCopyTextToImpl(); 565 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture( 566 src_texture, 567 src_size, 568 src_subrect, 569 dst_size, 570 out, 571 callback, 572 GLHelper::SCALER_QUALITY_FAST); 573 } 574 575 void GLHelper::CropScaleReadbackAndCleanMailbox( 576 const gpu::Mailbox& src_mailbox, 577 uint32 sync_point, 578 const gfx::Size& src_size, 579 const gfx::Rect& src_subrect, 580 const gfx::Size& dst_size, 581 unsigned char* out, 582 const base::Callback<void(bool)>& callback) { 583 WebGLId mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point); 584 CropScaleReadbackAndCleanTexture( 585 mailbox_texture, src_size, src_subrect, dst_size, out, callback); 586 context_->deleteTexture(mailbox_texture); 587 } 588 589 void GLHelper::ReadbackTextureSync(WebKit::WebGLId texture, 590 const gfx::Rect& src_rect, 591 unsigned char* out) { 592 InitCopyTextToImpl(); 593 copy_texture_to_impl_->ReadbackTextureSync(texture, 594 src_rect, 595 out); 596 } 597 598 WebKit::WebGLId GLHelper::CopyTexture(WebKit::WebGLId texture, 599 const gfx::Size& size) { 600 InitCopyTextToImpl(); 601 return copy_texture_to_impl_->CopyAndScaleTexture( 602 texture, 603 size, 604 size, 605 false, 606 GLHelper::SCALER_QUALITY_FAST); 607 } 608 609 WebKit::WebGLId GLHelper::CopyAndScaleTexture( 610 WebKit::WebGLId texture, 611 const gfx::Size& src_size, 612 const gfx::Size& dst_size, 613 bool vertically_flip_texture, 614 ScalerQuality quality) { 615 InitCopyTextToImpl(); 616 return copy_texture_to_impl_->CopyAndScaleTexture(texture, 617 src_size, 618 dst_size, 619 vertically_flip_texture, 620 quality); 621 } 622 623 WebGLId GLHelper::CompileShaderFromSource( 624 const WebKit::WGC3Dchar* source, 625 WebKit::WGC3Denum type) { 626 ScopedShader shader(context_, context_->createShader(type)); 627 context_->shaderSource(shader, source); 628 context_->compileShader(shader); 629 WebKit::WGC3Dint compile_status = 0; 630 context_->getShaderiv(shader, GL_COMPILE_STATUS, &compile_status); 631 if (!compile_status) { 632 LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8()); 633 return 0; 634 } 635 return shader.Detach(); 636 } 637 638 void GLHelper::InitCopyTextToImpl() { 639 // Lazily initialize |copy_texture_to_impl_| 640 if (!copy_texture_to_impl_) 641 copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, this)); 642 } 643 644 void GLHelper::InitScalerImpl() { 645 // Lazily initialize |scaler_impl_| 646 if (!scaler_impl_) 647 scaler_impl_.reset(new GLHelperScaling(context_, this)); 648 } 649 650 WebKit::WGC3Dint GLHelper::MaxDrawBuffers() { 651 InitCopyTextToImpl(); 652 return copy_texture_to_impl_->MaxDrawBuffers(); 653 } 654 655 void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture, 656 WebKit::WebGLId previous_texture, 657 const SkRegion& new_damage, 658 const SkRegion& old_damage) { 659 SkRegion region(old_damage); 660 if (region.op(new_damage, SkRegion::kDifference_Op)) { 661 ScopedFramebuffer dst_framebuffer(context_, 662 context_->createFramebuffer()); 663 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, 664 dst_framebuffer); 665 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 666 context_->framebufferTexture2D(GL_FRAMEBUFFER, 667 GL_COLOR_ATTACHMENT0, 668 GL_TEXTURE_2D, 669 previous_texture, 670 0); 671 for (SkRegion::Iterator it(region); !it.done(); it.next()) { 672 const SkIRect& rect = it.rect(); 673 context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, 674 rect.x(), rect.y(), 675 rect.x(), rect.y(), 676 rect.width(), rect.height()); 677 } 678 context_->flush(); 679 } 680 } 681 682 WebKit::WebGLId GLHelper::CreateTexture() { 683 WebKit::WebGLId texture = context_->createTexture(); 684 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, 685 texture); 686 context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 687 context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 688 context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 689 context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 690 return texture; 691 } 692 693 WebKit::WebGLId GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, 694 uint32 sync_point) { 695 if (mailbox.IsZero()) 696 return 0; 697 if (sync_point) 698 context_->waitSyncPoint(sync_point); 699 WebKit::WebGLId texture = CreateTexture(); 700 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, 701 texture); 702 context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 703 return texture; 704 } 705 706 void GLHelper::ResizeTexture(WebKit::WebGLId texture, const gfx::Size& size) { 707 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 708 context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 709 size.width(), size.height(), 0, 710 GL_RGB, GL_UNSIGNED_BYTE, NULL); 711 } 712 713 void GLHelper::CopyTextureSubImage(WebKit::WebGLId texture, 714 const gfx::Rect& rect) { 715 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 716 context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, 717 rect.x(), rect.y(), 718 rect.x(), rect.y(), rect.width(), rect.height()); 719 } 720 721 void GLHelper::CopyTextureFullImage(WebKit::WebGLId texture, 722 const gfx::Size& size) { 723 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); 724 context_->copyTexImage2D(GL_TEXTURE_2D, 0, 725 GL_RGB, 726 0, 0, 727 size.width(), size.height(), 0); 728 } 729 730 void GLHelper::CopyTextureToImpl::ReadbackPlane( 731 TextureFrameBufferPair* source, 732 const scoped_refptr<media::VideoFrame>& target, 733 int plane, 734 int size_shift, 735 const gfx::Rect& dst_subrect, 736 const base::Callback<void(bool)>& callback) { 737 context_->bindFramebuffer(GL_FRAMEBUFFER, source->framebuffer()); 738 size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) + 739 (dst_subrect.x() >> size_shift); 740 ReadbackAsync( 741 source->size(), 742 dst_subrect.width() >> size_shift, 743 target->stride(plane), 744 target->data(plane) + offset, 745 callback); 746 } 747 748 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { 749 0.257f, 0.504f, 0.098f, 0.0625f 750 }; 751 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { 752 -0.148f, -0.291f, 0.439f, 0.5f 753 }; 754 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { 755 0.439f, -0.368f, -0.071f, 0.5f 756 }; 757 758 // YUV readback constructors. Initiates the main scaler pipeline and 759 // one planar scaler for each of the Y, U and V planes. 760 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( 761 WebGraphicsContext3D* context, 762 CopyTextureToImpl* copy_impl, 763 GLHelperScaling* scaler_impl, 764 GLHelper::ScalerQuality quality, 765 const gfx::Size& src_size, 766 const gfx::Rect& src_subrect, 767 const gfx::Size& dst_size, 768 const gfx::Rect& dst_subrect, 769 bool flip_vertically) 770 : context_(context), 771 copy_impl_(copy_impl), 772 dst_size_(dst_size), 773 dst_subrect_(dst_subrect), 774 scaler_(context, scaler_impl->CreateScaler( 775 quality, 776 src_size, 777 src_subrect, 778 dst_subrect.size(), 779 flip_vertically, 780 false)), 781 y_(context, scaler_impl->CreatePlanarScaler( 782 dst_subrect.size(), 783 gfx::Rect(0, 0, 784 (dst_subrect.width() + 3) & ~3, 785 dst_subrect.height()), 786 gfx::Size((dst_subrect.width() + 3) / 4, 787 dst_subrect.height()), 788 false, 789 kRGBtoYColorWeights)), 790 u_(context, scaler_impl->CreatePlanarScaler( 791 dst_subrect.size(), 792 gfx::Rect(0, 0, 793 (dst_subrect.width() + 7) & ~7, 794 (dst_subrect.height() + 1) & ~1), 795 gfx::Size((dst_subrect.width() + 7) / 8, 796 (dst_subrect.height() + 1) / 2), 797 false, 798 kRGBtoUColorWeights)), 799 v_(context, scaler_impl->CreatePlanarScaler( 800 dst_subrect.size(), 801 gfx::Rect(0, 0, 802 (dst_subrect.width() + 7) & ~7, 803 (dst_subrect.height() + 1) & ~1), 804 gfx::Size((dst_subrect.width() + 7) / 8, 805 (dst_subrect.height() + 1) / 2), 806 false, 807 kRGBtoVColorWeights)) { 808 DCHECK(!(dst_size.width() & 1)); 809 DCHECK(!(dst_size.height() & 1)); 810 DCHECK(!(dst_subrect.width() & 1)); 811 DCHECK(!(dst_subrect.height() & 1)); 812 DCHECK(!(dst_subrect.x() & 1)); 813 DCHECK(!(dst_subrect.y() & 1)); 814 } 815 816 static void CallbackKeepingVideoFrameAlive( 817 scoped_refptr<media::VideoFrame> video_frame, 818 const base::Callback<void(bool)>& callback, 819 bool success) { 820 callback.Run(success); 821 } 822 823 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV( 824 const gpu::Mailbox& mailbox, 825 uint32 sync_point, 826 const scoped_refptr<media::VideoFrame>& target, 827 const base::Callback<void(bool)>& callback) { 828 WebGLId mailbox_texture = 829 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point); 830 831 // Scale texture to right size. 832 scaler_.Scale(mailbox_texture); 833 context_->deleteTexture(mailbox_texture); 834 835 // Convert the scaled texture in to Y, U and V planes. 836 y_.Scale(scaler_.texture()); 837 u_.Scale(scaler_.texture()); 838 v_.Scale(scaler_.texture()); 839 840 if (target->coded_size() != dst_size_) { 841 DCHECK(target->coded_size() == dst_size_); 842 LOG(ERROR) << "ReadbackYUV size error!"; 843 callback.Run(false); 844 return; 845 } 846 847 // Read back planes, one at a time. Keep the video frame alive while doing the 848 // readback. 849 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), 850 target, 851 media::VideoFrame::kYPlane, 852 0, 853 dst_subrect_, 854 base::Bind(&nullcallback)); 855 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), 856 target, 857 media::VideoFrame::kUPlane, 858 1, 859 dst_subrect_, 860 base::Bind(&nullcallback)); 861 copy_impl_->ReadbackPlane(v_.texture_and_framebuffer(), 862 target, 863 media::VideoFrame::kVPlane, 864 1, 865 dst_subrect_, 866 base::Bind(&CallbackKeepingVideoFrameAlive, 867 target, 868 callback)); 869 context_->bindFramebuffer(GL_FRAMEBUFFER, 0); 870 media::LetterboxYUV(target, dst_subrect_); 871 } 872 873 // YUV readback constructors. Initiates the main scaler pipeline and 874 // one planar scaler for each of the Y, U and V planes. 875 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT( 876 WebGraphicsContext3D* context, 877 CopyTextureToImpl* copy_impl, 878 GLHelperScaling* scaler_impl, 879 GLHelper::ScalerQuality quality, 880 const gfx::Size& src_size, 881 const gfx::Rect& src_subrect, 882 const gfx::Size& dst_size, 883 const gfx::Rect& dst_subrect, 884 bool flip_vertically) 885 : context_(context), 886 copy_impl_(copy_impl), 887 dst_size_(dst_size), 888 dst_subrect_(dst_subrect), 889 scaler_(context, scaler_impl->CreateScaler( 890 quality, 891 src_size, 892 src_subrect, 893 dst_subrect.size(), 894 flip_vertically, 895 false)), 896 pass1_shader_(scaler_impl->CreateYuvMrtShader( 897 dst_subrect.size(), 898 gfx::Rect(0, 0, 899 (dst_subrect.width() + 3) & ~3, 900 dst_subrect.height()), 901 gfx::Size((dst_subrect.width() + 3) / 4, 902 dst_subrect.height()), 903 false, 904 GLHelperScaling::SHADER_YUV_MRT_PASS1)), 905 pass2_shader_(scaler_impl->CreateYuvMrtShader( 906 gfx::Size((dst_subrect.width() + 3) / 4, 907 dst_subrect.height()), 908 gfx::Rect(0, 0, 909 (dst_subrect.width() + 7) / 8 * 2, 910 dst_subrect.height()), 911 gfx::Size((dst_subrect.width() + 7) / 8, 912 (dst_subrect.height() + 1) / 2), 913 false, 914 GLHelperScaling::SHADER_YUV_MRT_PASS2)), 915 y_(context, gfx::Size((dst_subrect.width() + 3) / 4, 916 dst_subrect.height())), 917 uv_(context, context->createTexture()), 918 u_(context, gfx::Size((dst_subrect.width() + 7) / 8, 919 (dst_subrect.height() + 1) / 2)), 920 v_(context, gfx::Size((dst_subrect.width() + 7) / 8, 921 (dst_subrect.height() + 1) / 2)) { 922 923 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context, uv_); 924 context->texImage2D(GL_TEXTURE_2D, 925 0, 926 GL_RGBA, 927 (dst_subrect.width() + 3) / 4, 928 dst_subrect.height(), 929 0, 930 GL_RGBA, 931 GL_UNSIGNED_BYTE, 932 NULL); 933 934 DCHECK(!(dst_size.width() & 1)); 935 DCHECK(!(dst_size.height() & 1)); 936 DCHECK(!(dst_subrect.width() & 1)); 937 DCHECK(!(dst_subrect.height() & 1)); 938 DCHECK(!(dst_subrect.x() & 1)); 939 DCHECK(!(dst_subrect.y() & 1)); 940 } 941 942 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV( 943 const gpu::Mailbox& mailbox, 944 uint32 sync_point, 945 const scoped_refptr<media::VideoFrame>& target, 946 const base::Callback<void(bool)>& callback) { 947 WebGLId mailbox_texture = 948 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point); 949 950 // Scale texture to right size. 951 scaler_.Scale(mailbox_texture); 952 context_->deleteTexture(mailbox_texture); 953 954 std::vector<WebKit::WebGLId> outputs(2); 955 // Convert the scaled texture in to Y, U and V planes. 956 outputs[0] = y_.texture(); 957 outputs[1] = uv_; 958 pass1_shader_->Execute(scaler_.texture(), outputs); 959 outputs[0] = u_.texture(); 960 outputs[1] = v_.texture(); 961 pass2_shader_->Execute(uv_, outputs); 962 963 if (target->coded_size() != dst_size_) { 964 DCHECK(target->coded_size() == dst_size_); 965 LOG(ERROR) << "ReadbackYUV size error!"; 966 callback.Run(false); 967 return; 968 } 969 970 // Read back planes, one at a time. 971 copy_impl_->ReadbackPlane(&y_, 972 target, 973 media::VideoFrame::kYPlane, 974 0, 975 dst_subrect_, 976 base::Bind(&nullcallback)); 977 copy_impl_->ReadbackPlane(&u_, 978 target, 979 media::VideoFrame::kUPlane, 980 1, 981 dst_subrect_, 982 base::Bind(&nullcallback)); 983 copy_impl_->ReadbackPlane(&v_, 984 target, 985 media::VideoFrame::kVPlane, 986 1, 987 dst_subrect_, 988 base::Bind(&CallbackKeepingVideoFrameAlive, 989 target, 990 callback)); 991 context_->bindFramebuffer(GL_FRAMEBUFFER, 0); 992 media::LetterboxYUV(target, dst_subrect_); 993 } 994 995 ReadbackYUVInterface* 996 GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV( 997 GLHelper::ScalerQuality quality, 998 const gfx::Size& src_size, 999 const gfx::Rect& src_subrect, 1000 const gfx::Size& dst_size, 1001 const gfx::Rect& dst_subrect, 1002 bool flip_vertically, 1003 bool use_mrt) { 1004 helper_->InitScalerImpl(); 1005 if (max_draw_buffers_ >= 2 && use_mrt) { 1006 return new ReadbackYUV_MRT( 1007 context_, 1008 this, 1009 helper_->scaler_impl_.get(), 1010 quality, 1011 src_size, 1012 src_subrect, 1013 dst_size, 1014 dst_subrect, 1015 flip_vertically); 1016 } 1017 return new ReadbackYUVImpl( 1018 context_, 1019 this, 1020 helper_->scaler_impl_.get(), 1021 quality, 1022 src_size, 1023 src_subrect, 1024 dst_size, 1025 dst_subrect, 1026 flip_vertically); 1027 } 1028 1029 ReadbackYUVInterface* 1030 GLHelper::CreateReadbackPipelineYUV( 1031 ScalerQuality quality, 1032 const gfx::Size& src_size, 1033 const gfx::Rect& src_subrect, 1034 const gfx::Size& dst_size, 1035 const gfx::Rect& dst_subrect, 1036 bool flip_vertically, 1037 bool use_mrt) { 1038 InitCopyTextToImpl(); 1039 return copy_texture_to_impl_->CreateReadbackPipelineYUV( 1040 quality, 1041 src_size, 1042 src_subrect, 1043 dst_size, 1044 dst_subrect, 1045 flip_vertically, 1046 use_mrt); 1047 } 1048 1049 } // namespace content 1050