OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/client/gl_helper.h" | 5 #include "content/common/gpu/client/gl_helper.h" |
6 | 6 |
7 #include <queue> | 7 #include <queue> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 uint32 sync_point) { | 135 uint32 sync_point) { |
136 return helper_->ConsumeMailboxToTexture(mailbox, sync_point); | 136 return helper_->ConsumeMailboxToTexture(mailbox, sync_point); |
137 } | 137 } |
138 | 138 |
139 void CropScaleReadbackAndCleanTexture( | 139 void CropScaleReadbackAndCleanTexture( |
140 GLuint src_texture, | 140 GLuint src_texture, |
141 const gfx::Size& src_size, | 141 const gfx::Size& src_size, |
142 const gfx::Rect& src_subrect, | 142 const gfx::Rect& src_subrect, |
143 const gfx::Size& dst_size, | 143 const gfx::Size& dst_size, |
144 unsigned char* out, | 144 unsigned char* out, |
145 const SkColorType color_type, | 145 const SkColorType out_color_type, |
146 const base::Callback<void(bool)>& callback, | 146 const base::Callback<void(bool)>& callback, |
147 GLHelper::ScalerQuality quality); | 147 GLHelper::ScalerQuality quality); |
148 | 148 |
149 void ReadbackTextureSync(GLuint texture, | 149 void ReadbackTextureSync(GLuint texture, |
150 const gfx::Rect& src_rect, | 150 const gfx::Rect& src_rect, |
151 unsigned char* out, | 151 unsigned char* out, |
152 SkColorType format); | 152 SkColorType format); |
153 | 153 |
154 void ReadbackTextureAsync(GLuint texture, | 154 void ReadbackTextureAsync(GLuint texture, |
155 const gfx::Size& dst_size, | 155 const gfx::Size& dst_size, |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 // |src_size| is the size of |src_texture|. | 318 // |src_size| is the size of |src_texture|. |
319 GLuint ScaleTexture(GLuint src_texture, | 319 GLuint ScaleTexture(GLuint src_texture, |
320 const gfx::Size& src_size, | 320 const gfx::Size& src_size, |
321 const gfx::Rect& src_subrect, | 321 const gfx::Rect& src_subrect, |
322 const gfx::Size& dst_size, | 322 const gfx::Size& dst_size, |
323 bool vertically_flip_texture, | 323 bool vertically_flip_texture, |
324 bool swizzle, | 324 bool swizzle, |
325 SkColorType color_type, | 325 SkColorType color_type, |
326 GLHelper::ScalerQuality quality); | 326 GLHelper::ScalerQuality quality); |
327 | 327 |
328 // Converts each four consecutive pixels of the source texture into one pixel | |
329 // in the result texture with each pixel channel representing the grayscale | |
330 // color of one of the four original pixels: | |
331 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4 | |
332 // The resulting texture is still an RGBA texture (which is ~4 times narrower | |
333 // than the original). If rendered directly, it wouldn't show anything useful, | |
334 // but the data in it can be used to construct a grayscale image. | |
335 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It | |
336 // is equal to src_size.width()/4 rounded upwards. Some channels in the last | |
337 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain | |
338 // useful data. | |
339 // If swizzle is set to true, the transformed pixels are reordered: | |
340 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4. | |
341 GLuint EncodeTextureAsGrayscale(GLuint src_texture, | |
342 const gfx::Size& src_size, | |
343 gfx::Size* const encoded_texture_size, | |
344 bool vertically_flip_texture, | |
345 bool swizzle); | |
346 | |
328 static void nullcallback(bool success) {} | 347 static void nullcallback(bool success) {} |
329 void ReadbackDone(Request *request, int bytes_per_pixel); | 348 void ReadbackDone(Request *request, int bytes_per_pixel); |
330 void FinishRequest(Request* request, bool result); | 349 void FinishRequest(Request* request, bool result); |
331 void CancelRequests(); | 350 void CancelRequests(); |
332 | 351 |
333 static const float kRGBtoYColorWeights[]; | 352 static const float kRGBtoYColorWeights[]; |
334 static const float kRGBtoUColorWeights[]; | 353 static const float kRGBtoUColorWeights[]; |
335 static const float kRGBtoVColorWeights[]; | 354 static const float kRGBtoVColorWeights[]; |
355 static const float kRGBtoGrayscaleColorWeights[]; | |
336 | 356 |
337 GLES2Interface* gl_; | 357 GLES2Interface* gl_; |
338 gpu::ContextSupport* context_support_; | 358 gpu::ContextSupport* context_support_; |
339 GLHelper* helper_; | 359 GLHelper* helper_; |
340 | 360 |
341 // A scoped flush that will ensure all resource deletions are flushed when | 361 // A scoped flush that will ensure all resource deletions are flushed when |
342 // this object is destroyed. Must be declared before other Scoped* fields. | 362 // this object is destroyed. Must be declared before other Scoped* fields. |
343 ScopedFlush flush_; | 363 ScopedFlush flush_; |
344 | 364 |
345 std::queue<Request*> request_queue_; | 365 std::queue<Request*> request_queue_; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 helper_->CreateScaler(quality, | 417 helper_->CreateScaler(quality, |
398 src_size, | 418 src_size, |
399 src_subrect, | 419 src_subrect, |
400 dst_size, | 420 dst_size, |
401 vertically_flip_texture, | 421 vertically_flip_texture, |
402 swizzle)); | 422 swizzle)); |
403 scaler->Scale(src_texture, dst_texture); | 423 scaler->Scale(src_texture, dst_texture); |
404 return dst_texture; | 424 return dst_texture; |
405 } | 425 } |
406 | 426 |
427 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale( | |
428 GLuint src_texture, | |
429 const gfx::Size& src_size, | |
430 gfx::Size* const encoded_texture_size, | |
431 bool vertically_flip_texture, | |
432 bool swizzle) { | |
433 GLuint dst_texture = 0u; | |
434 gl_->GenTextures(1, &dst_texture); | |
435 // The size of the encoded texture. | |
436 *encoded_texture_size = | |
437 gfx::Size((src_size.width() + 3) / 4, src_size.height()); | |
438 { | |
439 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); | |
440 gl_->TexImage2D(GL_TEXTURE_2D, | |
441 0, | |
442 GL_RGBA, | |
443 encoded_texture_size->width(), | |
444 encoded_texture_size->height(), | |
445 0, | |
446 GL_RGBA, | |
447 GL_UNSIGNED_BYTE, | |
448 NULL); | |
449 } | |
450 | |
451 helper_->InitScalerImpl(); | |
452 scoped_ptr<ScalerInterface> grayscale_scaler( | |
453 helper_->scaler_impl_.get()->CreatePlanarScaler( | |
454 src_size, | |
455 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()), | |
456 *encoded_texture_size, | |
457 vertically_flip_texture, | |
458 swizzle, | |
459 kRGBtoGrayscaleColorWeights)); | |
460 grayscale_scaler->Scale(src_texture, dst_texture); | |
461 return dst_texture; | |
462 } | |
463 | |
407 void GLHelper::CopyTextureToImpl::ReadbackAsync( | 464 void GLHelper::CopyTextureToImpl::ReadbackAsync( |
408 const gfx::Size& dst_size, | 465 const gfx::Size& dst_size, |
409 int32 bytes_per_row, | 466 int32 bytes_per_row, |
410 int32 row_stride_bytes, | 467 int32 row_stride_bytes, |
411 unsigned char* out, | 468 unsigned char* out, |
412 GLenum format, | 469 GLenum format, |
413 GLenum type, | 470 GLenum type, |
414 size_t bytes_per_pixel, | 471 size_t bytes_per_pixel, |
415 const base::Callback<void(bool)>& callback) { | 472 const base::Callback<void(bool)>& callback) { |
416 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync"); | 473 TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync"); |
(...skipping 19 matching lines...) Expand all Loading... | |
436 format, | 493 format, |
437 type, | 494 type, |
438 NULL); | 495 NULL); |
439 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM); | 496 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM); |
440 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); | 497 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); |
441 context_support_->SignalQuery( | 498 context_support_->SignalQuery( |
442 request->query, | 499 request->query, |
443 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), | 500 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), |
444 request, bytes_per_pixel)); | 501 request, bytes_per_pixel)); |
445 } | 502 } |
503 | |
446 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( | 504 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( |
447 GLuint src_texture, | 505 GLuint src_texture, |
448 const gfx::Size& src_size, | 506 const gfx::Size& src_size, |
449 const gfx::Rect& src_subrect, | 507 const gfx::Rect& src_subrect, |
450 const gfx::Size& dst_size, | 508 const gfx::Size& dst_size, |
451 unsigned char* out, | 509 unsigned char* out, |
452 const SkColorType color_type, | 510 const SkColorType out_color_type, |
453 const base::Callback<void(bool)>& callback, | 511 const base::Callback<void(bool)>& callback, |
454 GLHelper::ScalerQuality quality) { | 512 GLHelper::ScalerQuality quality) { |
455 GLenum format, type; | 513 GLenum format, type; |
456 size_t bytes_per_pixel; | 514 size_t bytes_per_pixel; |
457 FormatSupport supported = | 515 SkColorType readback_color_type = out_color_type; |
458 GetReadbackConfig(color_type, true, &format, &type, &bytes_per_pixel); | 516 // Single-component textures are not supported by all GPUs, so we implement |
517 // kAlpha_8_SkColorType support here via a special encoding (see below) using | |
518 // a 32-bit texture to represent an 8-bit image. | |
519 // Thus we use generic 32-bit readback in this case. | |
520 if (out_color_type == kAlpha_8_SkColorType) { | |
521 readback_color_type = kN32_SkColorType; | |
no sievers
2014/08/20 20:29:51
I don't think it makes sense to check for readback
mfomitchev
2014/08/22 18:01:33
GetReadbackConfig() returns the readback format.
no sievers
2014/08/22 18:44:13
I kow this is really confusing :/
GetReadbackForm
hubbe
2014/08/22 19:19:20
The reason reading back as BGRA is faster than RGB
no sievers
2014/08/22 20:54:48
Thanks hubbe+piman, that makes sense.
In that cas
| |
522 } | |
523 | |
524 FormatSupport supported = GetReadbackConfig(readback_color_type, | |
525 true, | |
526 &format, | |
527 &type, | |
528 &bytes_per_pixel); | |
529 | |
459 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { | 530 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { |
460 callback.Run(false); | 531 callback.Run(false); |
461 return; | 532 return; |
462 } | 533 } |
463 | 534 |
464 GLuint texture = ScaleTexture(src_texture, | 535 GLuint texture = src_texture; |
465 src_size, | 536 |
466 src_subrect, | 537 // Scale texture if needed |
467 dst_size, | 538 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we |
468 true, | 539 // can do just as well in EncodeTextureAsGrayscale, which we will do if |
469 (supported == GLHelperReadbackSupport::SWIZZLE), | 540 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step |
470 color_type, | 541 // in that case. |
471 quality); | 542 bool scale_texture = out_color_type != kAlpha_8_SkColorType || |
472 DCHECK(texture); | 543 quality != GLHelper::SCALER_QUALITY_FAST; |
544 if (scale_texture) { | |
545 // Don't swizzle during the scale step for kAlpha_8_SkColorType. | |
546 // We will swizzle in the encode step below if needed. | |
547 bool scale_swizzle = | |
548 out_color_type == kAlpha_8_SkColorType ? | |
549 false : supported == GLHelperReadbackSupport::SWIZZLE; | |
550 texture = | |
551 ScaleTexture(src_texture, | |
552 src_size, | |
553 src_subrect, | |
554 dst_size, | |
555 true, | |
556 scale_swizzle, | |
557 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType | |
558 : out_color_type, | |
559 quality); | |
560 DCHECK(texture); | |
561 } | |
562 | |
563 gfx::Size readback_texture_size = dst_size; | |
564 // Encode texture to grayscale if needed. | |
565 if (out_color_type == kAlpha_8_SkColorType) { | |
566 // Do the vertical flip here if we haven't already done it when we scaled | |
567 // the texture. | |
568 bool encode_as_grayscale_vertical_flip = !scale_texture; | |
569 // EncodeTextureAsGrayscale by default creates a texture which should be | |
570 // read back as RGBA, so need to swizzle if the readback format is BGRA. | |
no sievers
2014/08/20 20:29:51
...and this check is still correct then, I think.
| |
571 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT; | |
572 texture = EncodeTextureAsGrayscale( | |
no sievers
2014/08/20 20:29:51
Do we leak |texture| here if we scaled above, as i
mfomitchev
2014/08/22 18:01:33
Done.
| |
573 texture, | |
574 dst_size, | |
575 &readback_texture_size, | |
576 encode_as_grayscale_vertical_flip, | |
577 encode_as_grayscale_swizzle); | |
578 DCHECK(texture); | |
579 } | |
580 | |
581 // Readback the pixels of the resulting texture | |
473 ScopedFramebuffer dst_framebuffer(gl_); | 582 ScopedFramebuffer dst_framebuffer(gl_); |
474 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, | 583 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, |
475 dst_framebuffer); | 584 dst_framebuffer); |
476 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | 585 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); |
477 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, | 586 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, |
478 GL_COLOR_ATTACHMENT0, | 587 GL_COLOR_ATTACHMENT0, |
479 GL_TEXTURE_2D, | 588 GL_TEXTURE_2D, |
480 texture, | 589 texture, |
481 0); | 590 0); |
482 ReadbackAsync(dst_size, | 591 |
483 dst_size.width() * bytes_per_pixel, | 592 int32 bytes_per_row = |
484 dst_size.width() * bytes_per_pixel, | 593 out_color_type == kAlpha_8_SkColorType ? |
594 dst_size.width() : dst_size.width() * bytes_per_pixel; | |
595 | |
596 ReadbackAsync(readback_texture_size, | |
597 bytes_per_row, | |
598 bytes_per_row, | |
485 out, | 599 out, |
486 format, | 600 format, |
487 type, | 601 type, |
488 bytes_per_pixel, | 602 bytes_per_pixel, |
489 callback); | 603 callback); |
490 gl_->DeleteTextures(1, &texture); | 604 gl_->DeleteTextures(1, &texture); |
491 } | 605 } |
492 | 606 |
493 void GLHelper::CopyTextureToImpl::ReadbackTextureSync( | 607 void GLHelper::CopyTextureToImpl::ReadbackTextureSync( |
494 GLuint texture, | 608 GLuint texture, |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
649 readback_support_(new GLHelperReadbackSupport(gl)) {} | 763 readback_support_(new GLHelperReadbackSupport(gl)) {} |
650 | 764 |
651 GLHelper::~GLHelper() {} | 765 GLHelper::~GLHelper() {} |
652 | 766 |
653 void GLHelper::CropScaleReadbackAndCleanTexture( | 767 void GLHelper::CropScaleReadbackAndCleanTexture( |
654 GLuint src_texture, | 768 GLuint src_texture, |
655 const gfx::Size& src_size, | 769 const gfx::Size& src_size, |
656 const gfx::Rect& src_subrect, | 770 const gfx::Rect& src_subrect, |
657 const gfx::Size& dst_size, | 771 const gfx::Size& dst_size, |
658 unsigned char* out, | 772 unsigned char* out, |
659 const SkColorType color_type, | 773 const SkColorType out_color_type, |
660 const base::Callback<void(bool)>& callback, | 774 const base::Callback<void(bool)>& callback, |
661 GLHelper::ScalerQuality quality) { | 775 GLHelper::ScalerQuality quality) { |
662 InitCopyTextToImpl(); | 776 InitCopyTextToImpl(); |
663 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture( | 777 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture, |
664 src_texture, | 778 src_size, |
665 src_size, | 779 src_subrect, |
666 src_subrect, | 780 dst_size, |
667 dst_size, | 781 out, |
668 out, | 782 out_color_type, |
669 color_type, | 783 callback, |
670 callback, | 784 quality); |
671 quality); | |
672 } | 785 } |
673 | 786 |
674 void GLHelper::CropScaleReadbackAndCleanMailbox( | 787 void GLHelper::CropScaleReadbackAndCleanMailbox( |
675 const gpu::Mailbox& src_mailbox, | 788 const gpu::Mailbox& src_mailbox, |
676 uint32 sync_point, | 789 uint32 sync_point, |
677 const gfx::Size& src_size, | 790 const gfx::Size& src_size, |
678 const gfx::Rect& src_subrect, | 791 const gfx::Rect& src_subrect, |
679 const gfx::Size& dst_size, | 792 const gfx::Size& dst_size, |
680 unsigned char* out, | 793 unsigned char* out, |
681 const SkColorType color_type, | 794 const SkColorType out_color_type, |
682 const base::Callback<void(bool)>& callback, | 795 const base::Callback<void(bool)>& callback, |
683 GLHelper::ScalerQuality quality) { | 796 GLHelper::ScalerQuality quality) { |
684 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point); | 797 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point); |
685 CropScaleReadbackAndCleanTexture( | 798 CropScaleReadbackAndCleanTexture(mailbox_texture, |
686 mailbox_texture, src_size, src_subrect, dst_size, out, | 799 src_size, |
687 color_type, | 800 src_subrect, |
688 callback, | 801 dst_size, |
689 quality); | 802 out, |
803 out_color_type, | |
804 callback, | |
805 quality); | |
690 gl_->DeleteTextures(1, &mailbox_texture); | 806 gl_->DeleteTextures(1, &mailbox_texture); |
691 } | 807 } |
692 | 808 |
693 void GLHelper::ReadbackTextureSync(GLuint texture, | 809 void GLHelper::ReadbackTextureSync(GLuint texture, |
694 const gfx::Rect& src_rect, | 810 const gfx::Rect& src_rect, |
695 unsigned char* out, | 811 unsigned char* out, |
696 SkColorType format) { | 812 SkColorType format) { |
697 InitCopyTextToImpl(); | 813 InitCopyTextToImpl(); |
698 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format); | 814 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format); |
699 } | 815 } |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
894 4, | 1010 4, |
895 callback); | 1011 callback); |
896 } | 1012 } |
897 | 1013 |
898 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { | 1014 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { |
899 0.257f, 0.504f, 0.098f, 0.0625f}; | 1015 0.257f, 0.504f, 0.098f, 0.0625f}; |
900 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { | 1016 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { |
901 -0.148f, -0.291f, 0.439f, 0.5f}; | 1017 -0.148f, -0.291f, 0.439f, 0.5f}; |
902 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { | 1018 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { |
903 0.439f, -0.368f, -0.071f, 0.5f}; | 1019 0.439f, -0.368f, -0.071f, 0.5f}; |
1020 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = { | |
1021 0.213f, 0.715f, 0.072f, 0.0f}; | |
904 | 1022 |
905 // YUV readback constructors. Initiates the main scaler pipeline and | 1023 // YUV readback constructors. Initiates the main scaler pipeline and |
906 // one planar scaler for each of the Y, U and V planes. | 1024 // one planar scaler for each of the Y, U and V planes. |
907 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( | 1025 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( |
908 GLES2Interface* gl, | 1026 GLES2Interface* gl, |
909 CopyTextureToImpl* copy_impl, | 1027 CopyTextureToImpl* copy_impl, |
910 GLHelperScaling* scaler_impl, | 1028 GLHelperScaling* scaler_impl, |
911 GLHelper::ScalerQuality quality, | 1029 GLHelper::ScalerQuality quality, |
912 const gfx::Size& src_size, | 1030 const gfx::Size& src_size, |
913 const gfx::Rect& src_subrect, | 1031 const gfx::Rect& src_subrect, |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1235 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality, | 1353 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality, |
1236 src_size, | 1354 src_size, |
1237 src_subrect, | 1355 src_subrect, |
1238 dst_size, | 1356 dst_size, |
1239 dst_subrect, | 1357 dst_subrect, |
1240 flip_vertically, | 1358 flip_vertically, |
1241 use_mrt); | 1359 use_mrt); |
1242 } | 1360 } |
1243 | 1361 |
1244 } // namespace content | 1362 } // namespace content |
OLD | NEW |