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