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 <stdint.h> | 5 #include <stdint.h> |
6 | 6 |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "base/memory/aligned_memory.h" | 8 #include "base/memory/aligned_memory.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 10 #include "gpu/GLES2/gl2extchromium.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 return 0; | 43 return 0; |
44 if (!canvas->readPixels(&bitmap, x, y)) | 44 if (!canvas->readPixels(&bitmap, x, y)) |
45 return 0; | 45 return 0; |
46 return bitmap.getColor(0, 0); | 46 return bitmap.getColor(0, 0); |
47 } | 47 } |
48 | 48 |
49 SkColor GetColor(SkCanvas* canvas) { | 49 SkColor GetColor(SkCanvas* canvas) { |
50 return GetColorAt(canvas, 0, 0); | 50 return GetColorAt(canvas, 0, 0); |
51 } | 51 } |
52 | 52 |
| 53 // Generate frame pixels to provided |external_memory| and wrap it as frame. |
| 54 scoped_refptr<VideoFrame> CreateTestY16Frame(const gfx::Size& coded_size, |
| 55 const gfx::Rect& visible_rect, |
| 56 void* external_memory, |
| 57 base::TimeDelta timestamp) { |
| 58 const int offset_x = visible_rect.x(); |
| 59 const int offset_y = visible_rect.y(); |
| 60 const int stride = coded_size.width(); |
| 61 const size_t byte_size = stride * coded_size.height() * 2; |
| 62 |
| 63 // In the visible rect, fill upper byte with [0-255] and lower with [255-0]. |
| 64 uint16_t* data = static_cast<uint16_t*>(external_memory); |
| 65 for (int j = 0; j < visible_rect.height(); j++) { |
| 66 for (int i = 0; i < visible_rect.width(); i++) { |
| 67 const int value = i + j * visible_rect.width(); |
| 68 data[(stride * (j + offset_y)) + i + offset_x] = |
| 69 ((value & 0xFF) << 8) | (~value & 0xFF); |
| 70 } |
| 71 } |
| 72 |
| 73 return media::VideoFrame::WrapExternalData( |
| 74 media::PIXEL_FORMAT_Y16, coded_size, visible_rect, visible_rect.size(), |
| 75 static_cast<uint8_t*>(external_memory), byte_size, timestamp); |
| 76 } |
| 77 |
53 class SkCanvasVideoRendererTest : public testing::Test { | 78 class SkCanvasVideoRendererTest : public testing::Test { |
54 public: | 79 public: |
55 enum Color { | 80 enum Color { |
56 kNone, | 81 kNone, |
57 kRed, | 82 kRed, |
58 kGreen, | 83 kGreen, |
59 kBlue, | 84 kBlue, |
60 }; | 85 }; |
61 | 86 |
62 SkCanvasVideoRendererTest(); | 87 SkCanvasVideoRendererTest(); |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 bitmap.allocPixels(SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType)); | 543 bitmap.allocPixels(SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType)); |
519 | 544 |
520 // |offset_x| and |offset_y| define visible rect's offset to coded rect. | 545 // |offset_x| and |offset_y| define visible rect's offset to coded rect. |
521 const int offset_x = 3; | 546 const int offset_x = 3; |
522 const int offset_y = 5; | 547 const int offset_y = 5; |
523 const int stride = bitmap.width() + offset_x; | 548 const int stride = bitmap.width() + offset_x; |
524 const size_t byte_size = stride * (bitmap.height() + offset_y) * 2; | 549 const size_t byte_size = stride * (bitmap.height() + offset_y) * 2; |
525 std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( | 550 std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( |
526 static_cast<unsigned char*>(base::AlignedAlloc( | 551 static_cast<unsigned char*>(base::AlignedAlloc( |
527 byte_size, media::VideoFrame::kFrameAddressAlignment))); | 552 byte_size, media::VideoFrame::kFrameAddressAlignment))); |
528 | |
529 // In the visible rect, fill upper byte with [0-255] and lower with [255-0]. | |
530 uint16_t* data = reinterpret_cast<uint16_t*>(memory.get()); | |
531 for (int j = 0; j < bitmap.height(); j++) { | |
532 for (int i = 0; i < bitmap.width(); i++) { | |
533 const int value = i + j * bitmap.width(); | |
534 data[(stride * (j + offset_y)) + i + offset_x] = | |
535 ((value & 0xFF) << 8) | (~value & 0xFF); | |
536 } | |
537 } | |
538 const gfx::Rect rect(offset_x, offset_y, bitmap.width(), bitmap.height()); | 553 const gfx::Rect rect(offset_x, offset_y, bitmap.width(), bitmap.height()); |
539 scoped_refptr<media::VideoFrame> video_frame = | 554 scoped_refptr<media::VideoFrame> video_frame = |
540 media::VideoFrame::WrapExternalData( | 555 CreateTestY16Frame(gfx::Size(stride, offset_y + bitmap.height()), rect, |
541 media::PIXEL_FORMAT_Y16, | 556 memory.get(), cropped_frame()->timestamp()); |
542 gfx::Size(stride, offset_y + bitmap.height()), rect, rect.size(), | |
543 memory.get(), byte_size, cropped_frame()->timestamp()); | |
544 | 557 |
545 SkCanvas canvas(bitmap); | 558 SkCanvas canvas(bitmap); |
546 SkPaint paint; | 559 SkPaint paint; |
547 paint.setFilterQuality(kNone_SkFilterQuality); | 560 paint.setFilterQuality(kNone_SkFilterQuality); |
548 renderer_.Paint(video_frame, &canvas, | 561 renderer_.Paint(video_frame, &canvas, |
549 gfx::RectF(bitmap.width(), bitmap.height()), paint, | 562 gfx::RectF(bitmap.width(), bitmap.height()), paint, |
550 VIDEO_ROTATION_0, Context3D()); | 563 VIDEO_ROTATION_0, Context3D()); |
551 SkAutoLockPixels lock(bitmap); | 564 SkAutoLockPixels lock(bitmap); |
552 for (int j = 0; j < bitmap.height(); j++) { | 565 for (int j = 0; j < bitmap.height(); j++) { |
553 for (int i = 0; i < bitmap.width(); i++) { | 566 for (int i = 0; i < bitmap.width(); i++) { |
554 const int value = i + j * bitmap.width(); | 567 const int value = i + j * bitmap.width(); |
555 EXPECT_EQ(SkColorSetRGB(value, value, value), bitmap.getColor(i, j)); | 568 EXPECT_EQ(SkColorSetRGB(value, value, value), bitmap.getColor(i, j)); |
556 } | 569 } |
557 } | 570 } |
558 } | 571 } |
559 | 572 |
560 namespace { | 573 namespace { |
561 class TestGLES2Interface : public gpu::gles2::GLES2InterfaceStub { | 574 class TestGLES2Interface : public gpu::gles2::GLES2InterfaceStub { |
562 public: | 575 public: |
563 void GenTextures(GLsizei n, GLuint* textures) override { | 576 void GenTextures(GLsizei n, GLuint* textures) override { |
564 DCHECK_EQ(1, n); | 577 DCHECK_EQ(1, n); |
565 *textures = 1; | 578 *textures = 1; |
566 } | 579 } |
| 580 |
| 581 void TexImage2D(GLenum target, |
| 582 GLint level, |
| 583 GLint internalformat, |
| 584 GLsizei width, |
| 585 GLsizei height, |
| 586 GLint border, |
| 587 GLenum format, |
| 588 GLenum type, |
| 589 const void* pixels) override { |
| 590 if (!teximage2d_callback_.is_null()) { |
| 591 teximage2d_callback_.Run(target, level, internalformat, width, height, |
| 592 border, format, type, pixels); |
| 593 } |
| 594 } |
| 595 |
| 596 base::Callback<void(GLenum target, |
| 597 GLint level, |
| 598 GLint internalformat, |
| 599 GLsizei width, |
| 600 GLsizei height, |
| 601 GLint border, |
| 602 GLenum format, |
| 603 GLenum type, |
| 604 const void* pixels)> |
| 605 teximage2d_callback_; |
567 }; | 606 }; |
568 void MailboxHoldersReleased(const gpu::SyncToken& sync_token) {} | 607 void MailboxHoldersReleased(const gpu::SyncToken& sync_token) {} |
569 } // namespace | 608 } // namespace |
570 | 609 |
571 // Test that SkCanvasVideoRendererTest::Paint doesn't crash when GrContext is | 610 // Test that SkCanvasVideoRendererTest::Paint doesn't crash when GrContext is |
572 // abandoned. | 611 // abandoned. |
573 TEST_F(SkCanvasVideoRendererTest, ContextLost) { | 612 TEST_F(SkCanvasVideoRendererTest, ContextLost) { |
574 sk_sp<const GrGLInterface> null_interface(GrGLCreateNullInterface()); | 613 sk_sp<const GrGLInterface> null_interface(GrGLCreateNullInterface()); |
575 sk_sp<GrContext> gr_context(GrContext::Create( | 614 sk_sp<GrContext> gr_context(GrContext::Create( |
576 kOpenGL_GrBackend, | 615 kOpenGL_GrBackend, |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 | 667 |
629 gfx::RectF visible_rect(visible_size.width(), visible_size.height()); | 668 gfx::RectF visible_rect(visible_size.width(), visible_size.height()); |
630 SkPaint paint; | 669 SkPaint paint; |
631 renderer_.Paint(video_frame, canvas, visible_rect, paint, VIDEO_ROTATION_0, | 670 renderer_.Paint(video_frame, canvas, visible_rect, paint, VIDEO_ROTATION_0, |
632 context_3d); | 671 context_3d); |
633 | 672 |
634 EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().width()); | 673 EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().width()); |
635 EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().height()); | 674 EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().height()); |
636 } | 675 } |
637 | 676 |
| 677 TEST_F(SkCanvasVideoRendererTest, TexImageImplY16) { |
| 678 // Create test frame. |
| 679 // |offset_x| and |offset_y| define visible rect's offset to coded rect. |
| 680 const int offset_x = 3; |
| 681 const int offset_y = 5; |
| 682 const int width = 16; |
| 683 const int height = 16; |
| 684 const int stride = width + offset_x; |
| 685 const size_t byte_size = stride * (height + offset_y) * 2; |
| 686 std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( |
| 687 static_cast<unsigned char*>(base::AlignedAlloc( |
| 688 byte_size, media::VideoFrame::kFrameAddressAlignment))); |
| 689 const gfx::Rect rect(offset_x, offset_y, width, height); |
| 690 scoped_refptr<media::VideoFrame> video_frame = |
| 691 CreateTestY16Frame(gfx::Size(stride, offset_y + height), rect, |
| 692 memory.get(), cropped_frame()->timestamp()); |
| 693 |
| 694 // Create GL context. |
| 695 sk_sp<const GrGLInterface> null_interface(GrGLCreateNullInterface()); |
| 696 sk_sp<GrContext> gr_context(GrContext::Create( |
| 697 kOpenGL_GrBackend, |
| 698 reinterpret_cast<GrBackendContext>(null_interface.get()))); |
| 699 TestGLES2Interface gles2; |
| 700 Context3D context_3d(&gles2, gr_context.get()); |
| 701 |
| 702 // Bind the texImage2D callback to verify the uint16 to float32 conversion. |
| 703 gles2.teximage2d_callback_ = |
| 704 base::Bind([](GLenum target, GLint level, GLint internalformat, |
| 705 GLsizei width, GLsizei height, GLint border, GLenum format, |
| 706 GLenum type, const void* pixels) { |
| 707 EXPECT_EQ(static_cast<unsigned>(GL_FLOAT), type); |
| 708 EXPECT_EQ(static_cast<unsigned>(GL_RGBA), format); |
| 709 EXPECT_EQ(GL_RGBA, internalformat); |
| 710 EXPECT_EQ(0, border); |
| 711 EXPECT_EQ(16, width); |
| 712 EXPECT_EQ(16, height); |
| 713 EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); |
| 714 const float* data = static_cast<const float*>(pixels); |
| 715 for (int j = 0; j < height; j++) { |
| 716 for (int i = 0; i < width; i++) { |
| 717 const int value = i + (height - j - 1) * width; // flip_y is true. |
| 718 float expected_value = |
| 719 (((value & 0xFF) << 8) | (~value & 0xFF)) / 65535.f; |
| 720 EXPECT_EQ(expected_value, data[(i + j * width) * 4]); |
| 721 EXPECT_EQ(expected_value, data[(i + j * width) * 4 + 1]); |
| 722 EXPECT_EQ(expected_value, data[(i + j * width) * 4 + 2]); |
| 723 EXPECT_EQ(1.0f, data[(i + j * width) * 4 + 3]); |
| 724 } |
| 725 } |
| 726 }); |
| 727 SkCanvasVideoRenderer::TexImage2D(GL_TEXTURE_2D, &gles2, video_frame.get(), 0, |
| 728 GL_RGBA, GL_RGBA, GL_FLOAT, true /*flip_y*/, |
| 729 true); |
| 730 } |
| 731 |
638 } // namespace media | 732 } // namespace media |
OLD | NEW |