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