OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <stdio.h> | 5 #include <stdio.h> |
6 #include <cmath> | 6 #include <cmath> |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include <GLES2/gl2.h> | 10 #include <GLES2/gl2.h> |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 float x3 = x2 * x; | 132 float x3 = x2 * x; |
133 if (x <= 1) { | 133 if (x <= 1) { |
134 return (a + 2) * x3 - (a + 3) * x2 + 1; | 134 return (a + 2) * x3 - (a + 3) * x2 + 1; |
135 } else if (x < 2) { | 135 } else if (x < 2) { |
136 return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; | 136 return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; |
137 } else { | 137 } else { |
138 return 0.0f; | 138 return 0.0f; |
139 } | 139 } |
140 } | 140 } |
141 | 141 |
142 // Look up a single R/G/B/A value. | 142 // Look up a single channel value. Works for 4-channel and single channel |
143 // Clamp x/y. | 143 // bitmaps. Clamp x/y. |
144 int Channel(SkBitmap* pixels, int x, int y, int c) { | 144 int Channel(SkBitmap* pixels, int x, int y, int c) { |
145 uint32* data = | 145 if (pixels->bytesPerPixel() == 4) { |
146 pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), | 146 uint32* data = |
147 std::max(0, std::min(y, pixels->height() - 1))); | 147 pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), |
148 return (*data) >> (c * 8) & 0xff; | 148 std::max(0, std::min(y, pixels->height() - 1))); |
149 return (*data) >> (c * 8) & 0xff; | |
150 } else { | |
151 DCHECK_EQ(pixels->bytesPerPixel(), 1); | |
152 DCHECK_EQ(c, 0); | |
153 return *pixels->getAddr8(std::max(0, std::min(x, pixels->width() - 1)), | |
154 std::max(0, std::min(y, pixels->height() - 1))); | |
155 } | |
149 } | 156 } |
150 | 157 |
151 // Set a single R/G/B/A value. | 158 // Set a single channel value. Works for 4-channel and single channel |
159 // bitmaps. Clamp x/y. | |
152 void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { | 160 void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { |
153 DCHECK_GE(x, 0); | 161 DCHECK_GE(x, 0); |
154 DCHECK_GE(y, 0); | 162 DCHECK_GE(y, 0); |
155 DCHECK_LT(x, pixels->width()); | 163 DCHECK_LT(x, pixels->width()); |
156 DCHECK_LT(y, pixels->height()); | 164 DCHECK_LT(y, pixels->height()); |
157 uint32* data = pixels->getAddr32(x, y); | 165 if (pixels->bytesPerPixel() == 4) { |
158 v = std::max(0, std::min(v, 255)); | 166 uint32* data = pixels->getAddr32(x, y); |
159 *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); | 167 v = std::max(0, std::min(v, 255)); |
168 *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); | |
169 } else { | |
170 DCHECK_EQ(pixels->bytesPerPixel(), 1); | |
171 DCHECK_EQ(c, 0); | |
172 uint8* data = pixels->getAddr8(x, y); | |
173 v = std::max(0, std::min(v, 255)); | |
174 *data = v; | |
175 } | |
160 } | 176 } |
161 | 177 |
162 // Print all the R, G, B or A values from an SkBitmap in a | 178 // Print all the R, G, B or A values from an SkBitmap in a |
163 // human-readable format. | 179 // human-readable format. |
164 void PrintChannel(SkBitmap* pixels, int c) { | 180 void PrintChannel(SkBitmap* pixels, int c) { |
165 for (int y = 0; y < pixels->height(); y++) { | 181 for (int y = 0; y < pixels->height(); y++) { |
166 std::string formatted; | 182 std::string formatted; |
167 for (int x = 0; x < pixels->width(); x++) { | 183 for (int x = 0; x < pixels->width(); x++) { |
168 formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); | 184 formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); |
169 } | 185 } |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 // is no more than |maxdiff| apart. If they are not similar enough, | 398 // is no more than |maxdiff| apart. If they are not similar enough, |
383 // prints out |truth|, |other|, |source|, |scaler_stages| and |message|. | 399 // prints out |truth|, |other|, |source|, |scaler_stages| and |message|. |
384 void Compare(SkBitmap* truth, | 400 void Compare(SkBitmap* truth, |
385 SkBitmap* other, | 401 SkBitmap* other, |
386 int maxdiff, | 402 int maxdiff, |
387 SkBitmap* source, | 403 SkBitmap* source, |
388 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, | 404 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, |
389 std::string message) { | 405 std::string message) { |
390 EXPECT_EQ(truth->width(), other->width()); | 406 EXPECT_EQ(truth->width(), other->width()); |
391 EXPECT_EQ(truth->height(), other->height()); | 407 EXPECT_EQ(truth->height(), other->height()); |
408 EXPECT_EQ(truth->bytesPerPixel(), other->bytesPerPixel()); | |
409 int bpp = truth->bytesPerPixel(); | |
392 for (int x = 0; x < truth->width(); x++) { | 410 for (int x = 0; x < truth->width(); x++) { |
393 for (int y = 0; y < truth->height(); y++) { | 411 for (int y = 0; y < truth->height(); y++) { |
394 for (int c = 0; c < 4; c++) { | 412 for (int c = 0; c < bpp; c++) { |
395 int a = Channel(truth, x, y, c); | 413 int a = Channel(truth, x, y, c); |
396 int b = Channel(other, x, y, c); | 414 int b = Channel(other, x, y, c); |
397 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c | 415 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c |
398 << " " << message; | 416 << " " << message; |
399 if (std::abs(a - b) > maxdiff) { | 417 if (std::abs(a - b) > maxdiff) { |
400 LOG(ERROR) << "-------expected--------"; | 418 LOG(ERROR) << "-------expected--------"; |
401 PrintChannel(truth, c); | 419 for (int i = 0; i < bpp; i++) { |
420 LOG(ERROR) << "Channel " << i << ":"; | |
421 PrintChannel(truth, i); | |
422 } | |
402 LOG(ERROR) << "-------actual--------"; | 423 LOG(ERROR) << "-------actual--------"; |
403 PrintChannel(other, c); | 424 for (int i = 0; i < bpp; i++) { |
425 LOG(ERROR) << "Channel " << i << ":"; | |
426 PrintChannel(other, i); | |
427 } | |
404 if (source) { | 428 if (source) { |
405 LOG(ERROR) << "-------before scaling--------"; | 429 LOG(ERROR) << "-------original--------"; |
no sievers
2014/08/20 20:29:52
nit: indent
mfomitchev
2014/08/22 18:01:33
Done.
| |
406 PrintChannel(source, c); | 430 for (int i = 0; i < source->bytesPerPixel(); i++) { |
431 LOG(ERROR) << "Channel " << i << ":"; | |
432 PrintChannel(source, i); | |
433 } | |
407 } | 434 } |
408 LOG(ERROR) << "-----Scaler stages------"; | 435 LOG(ERROR) << "-----Scaler stages------"; |
409 LOG(ERROR) << PrintStages(scaler_stages); | 436 LOG(ERROR) << PrintStages(scaler_stages); |
410 return; | 437 return; |
411 } | 438 } |
412 } | 439 } |
413 } | 440 } |
414 } | 441 } |
415 } | 442 } |
416 | 443 |
417 // Get a single R, G, B or A value as a float. | 444 // Get a single R, G, B or A value as a float. |
418 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { | 445 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { |
419 return Channel(pixels, x, y, c) / 255.0; | 446 return Channel(pixels, x, y, c) / 255.0; |
420 } | 447 } |
421 | 448 |
422 // Works like a GL_LINEAR lookup on an SkBitmap. | 449 // Works like a GL_LINEAR lookup on an SkBitmap. |
423 float Bilinear(SkBitmap* pixels, float x, float y, int c) { | 450 float Bilinear(SkBitmap* pixels, float x, float y, int c) { |
424 x -= 0.5; | 451 x -= 0.5; |
425 y -= 0.5; | 452 y -= 0.5; |
426 int base_x = static_cast<int>(floorf(x)); | 453 int base_x = static_cast<int>(floorf(x)); |
427 int base_y = static_cast<int>(floorf(y)); | 454 int base_y = static_cast<int>(floorf(y)); |
428 x -= base_x; | 455 x -= base_x; |
429 y -= base_y; | 456 y -= base_y; |
430 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + | 457 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + |
431 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + | 458 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + |
432 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + | 459 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + |
433 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); | 460 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); |
434 } | 461 } |
435 | 462 |
463 // Encodes an RGBA bitmap to grayscale. | |
464 // Reference implementation for | |
465 // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale. | |
466 void EncodeToGrayscaleSlow(SkBitmap* input, | |
467 SkBitmap* output) { | |
468 const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f}; | |
no sievers
2014/08/20 20:29:52
Should these constants be shared?
mfomitchev
2014/08/22 18:01:33
It wouldn't be terribly straightforward. This arra
no sievers
2014/08/22 18:44:13
If you expose them in gl_helper.h somehow, can the
mfomitchev
2014/08/25 19:21:53
Yes, I could construct the 3-element array in gl_h
| |
469 CHECK_EQ(kAlpha_8_SkColorType, output->colorType()); | |
470 CHECK_EQ(input->width(), output->width()); | |
471 CHECK_EQ(input->height(), output->height()); | |
472 CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType); | |
473 | |
474 for (int dst_y = 0; dst_y < output->height(); dst_y++) { | |
475 for (int dst_x = 0; dst_x < output->width(); dst_x++) { | |
476 float c0 = ChannelAsFloat(input, dst_x, dst_y, 0); | |
477 float c1 = ChannelAsFloat(input, dst_x, dst_y, 1); | |
478 float c2 = ChannelAsFloat(input, dst_x, dst_y, 2); | |
479 float value = c0 * kRGBtoGrayscaleColorWeights[0] + | |
480 c1 * kRGBtoGrayscaleColorWeights[1] + | |
481 c2 * kRGBtoGrayscaleColorWeights[2]; | |
482 SetChannel(output, | |
483 dst_x, | |
484 dst_y, | |
485 0, | |
486 static_cast<int>(value * 255.0f + 0.5f)); | |
no sievers
2014/08/20 20:29:52
hmm why +0.5?
mfomitchev
2014/08/22 18:01:33
So that it rounds to the closest int rather than r
| |
487 } | |
488 } | |
489 } | |
490 | |
436 // Very slow bicubic / bilinear scaler for reference. | 491 // Very slow bicubic / bilinear scaler for reference. |
437 void ScaleSlow(SkBitmap* input, | 492 void ScaleSlow(SkBitmap* input, |
438 SkBitmap* output, | 493 SkBitmap* output, |
439 content::GLHelper::ScalerQuality quality) { | 494 content::GLHelper::ScalerQuality quality) { |
440 float xscale = static_cast<float>(input->width()) / output->width(); | 495 float xscale = static_cast<float>(input->width()) / output->width(); |
441 float yscale = static_cast<float>(input->height()) / output->height(); | 496 float yscale = static_cast<float>(input->height()) / output->height(); |
442 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; | 497 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; |
443 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; | 498 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; |
444 for (int dst_y = 0; dst_y < output->height(); dst_y++) { | 499 for (int dst_y = 0; dst_y < output->height(); dst_y++) { |
445 for (int dst_x = 0; dst_x < output->width(); dst_x++) { | 500 for (int dst_x = 0; dst_x < output->width(); dst_x++) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 dst_x, | 563 dst_x, |
509 dst_y, | 564 dst_y, |
510 channel, | 565 channel, |
511 static_cast<int>(value * 255.0f + 0.5f)); | 566 static_cast<int>(value * 255.0f + 0.5f)); |
512 } | 567 } |
513 } | 568 } |
514 } | 569 } |
515 } | 570 } |
516 | 571 |
517 void FlipSKBitmap(SkBitmap* bitmap) { | 572 void FlipSKBitmap(SkBitmap* bitmap) { |
573 int bpp = bitmap->bytesPerPixel(); | |
574 DCHECK(bpp == 4 || bpp == 1); | |
518 int top_line = 0; | 575 int top_line = 0; |
519 int bottom_line = bitmap->height() - 1; | 576 int bottom_line = bitmap->height() - 1; |
520 while (top_line < bottom_line) { | 577 while (top_line < bottom_line) { |
521 for (int x = 0; x < bitmap->width(); x++) { | 578 for (int x = 0; x < bitmap->width(); x++) { |
522 std::swap(*bitmap->getAddr32(x, top_line), | 579 bpp == 4 ? |
523 *bitmap->getAddr32(x, bottom_line)); | 580 std::swap(*bitmap->getAddr32(x, top_line), |
581 *bitmap->getAddr32(x, bottom_line)) | |
582 : std::swap(*bitmap->getAddr8(x, top_line), | |
583 *bitmap->getAddr8(x, bottom_line)); | |
524 } | 584 } |
525 top_line++; | 585 top_line++; |
526 bottom_line--; | 586 bottom_line--; |
527 } | 587 } |
528 } | 588 } |
529 | 589 |
590 // Swaps red and blue channels in each pixel in a 32-bit bitmap. | |
591 void SwizzleSKBitmap(SkBitmap* bitmap) { | |
592 int bpp = bitmap->bytesPerPixel(); | |
593 DCHECK(bpp == 4); | |
594 for (int y = 0; y < bitmap->height(); y++) { | |
595 for (int x = 0; x < bitmap->width(); x++) { | |
596 // Swap channels 0 and 2 (red and blue) | |
597 int c0 = Channel(bitmap, x, y, 0); | |
598 int c2 = Channel(bitmap, x, y, 2); | |
599 SetChannel(bitmap, x, y, 2, c0); | |
600 SetChannel(bitmap, x, y, 0, c2); | |
601 } | |
602 } | |
603 } | |
604 | |
530 // gl_helper scales recursively, so we'll need to do that | 605 // gl_helper scales recursively, so we'll need to do that |
531 // in the reference implementation too. | 606 // in the reference implementation too. |
532 void ScaleSlowRecursive(SkBitmap* input, | 607 void ScaleSlowRecursive(SkBitmap* input, |
533 SkBitmap* output, | 608 SkBitmap* output, |
534 content::GLHelper::ScalerQuality quality) { | 609 content::GLHelper::ScalerQuality quality) { |
535 if (quality == content::GLHelper::SCALER_QUALITY_FAST || | 610 if (quality == content::GLHelper::SCALER_QUALITY_FAST || |
536 quality == content::GLHelper::SCALER_QUALITY_GOOD) { | 611 quality == content::GLHelper::SCALER_QUALITY_GOOD) { |
537 ScaleSlow(input, output, quality); | 612 ScaleSlow(input, output, quality); |
538 return; | 613 return; |
539 } | 614 } |
(...skipping 28 matching lines...) Expand all Loading... | |
568 } | 643 } |
569 } | 644 } |
570 | 645 |
571 SkBitmap tmp; | 646 SkBitmap tmp; |
572 tmp.allocN32Pixels(xtmp, ytmp); | 647 tmp.allocN32Pixels(xtmp, ytmp); |
573 | 648 |
574 ScaleSlowRecursive(input, &tmp, quality); | 649 ScaleSlowRecursive(input, &tmp, quality); |
575 ScaleSlowRecursive(&tmp, output, quality); | 650 ScaleSlowRecursive(&tmp, output, quality); |
576 } | 651 } |
577 | 652 |
653 // Creates an RGBA SkBitmap | |
654 scoped_ptr<SkBitmap> CreateTestBitmap(int width, | |
655 int height, | |
656 int test_pattern) { | |
657 scoped_ptr<SkBitmap> bitmap(new SkBitmap); | |
658 bitmap->allocPixels(SkImageInfo::Make( | |
659 width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | |
660 | |
661 for (int x = 0; x < width; ++x) { | |
662 for (int y = 0; y < height; ++y) { | |
663 switch (test_pattern) { | |
664 case 0: // Smooth test pattern | |
665 SetChannel(bitmap.get(), x, y, 0, x * 10); | |
666 SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10); | |
667 SetChannel(bitmap.get(), x, y, 1, y * 10); | |
668 SetChannel(bitmap.get(), x, y, 2, (x + y) * 10); | |
669 SetChannel(bitmap.get(), x, y, 3, 255); | |
670 break; | |
671 case 1: // Small blocks | |
672 SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0); | |
673 SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0); | |
674 SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0); | |
675 SetChannel(bitmap.get(), x, y, 3, 255); | |
676 break; | |
677 case 2: // Medium blocks | |
678 SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50); | |
679 SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50); | |
680 SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5); | |
681 SetChannel(bitmap.get(), x, y, 3, 255); | |
682 break; | |
683 } | |
684 } | |
685 } | |
686 return bitmap.Pass(); | |
687 } | |
688 | |
689 // Binds texture and framebuffer and loads the bitmap pixels into the texture. | |
690 void BindTextureAndFrameBuffer(WebGLId texture, | |
691 WebGLId framebuffer, | |
692 SkBitmap* bitmap, | |
693 int width, | |
694 int height) { | |
695 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); | |
696 context_->bindTexture(GL_TEXTURE_2D, texture); | |
697 context_->texImage2D(GL_TEXTURE_2D, | |
698 0, | |
699 GL_RGBA, | |
700 width, | |
701 height, | |
702 0, | |
703 GL_RGBA, | |
704 GL_UNSIGNED_BYTE, | |
705 bitmap->getPixels()); | |
706 } | |
707 | |
708 // Create a test image, transform it using | |
709 // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation | |
710 // and compare the results. | |
711 void TestCropScaleReadbackAndCleanTexture(int xsize, | |
712 int ysize, | |
713 int scaled_xsize, | |
714 int scaled_ysize, | |
715 int test_pattern, | |
716 SkColorType out_color_type, | |
717 bool swizzle, | |
718 size_t quality) { | |
no sievers
2014/08/20 20:29:52
nit: maybe less error-prone to just pass the Scale
mfomitchev
2014/08/22 18:01:33
Yeah, this is modeled after TestScale() below, but
no sievers
2014/08/22 18:44:13
I see, maybe just keep it as is then if it matches
| |
719 DCHECK(out_color_type == kAlpha_8_SkColorType || | |
720 out_color_type == kRGBA_8888_SkColorType || | |
721 out_color_type == kBGRA_8888_SkColorType); | |
722 WebGLId src_texture = context_->createTexture(); | |
723 WebGLId framebuffer = context_->createFramebuffer(); | |
724 scoped_ptr<SkBitmap> input_pixels = | |
725 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); | |
726 BindTextureAndFrameBuffer( | |
727 src_texture, framebuffer, input_pixels.get(), xsize, ysize); | |
728 | |
729 std::string message = base::StringPrintf( | |
730 "input size: %dx%d " | |
731 "output size: %dx%d " | |
732 "pattern: %d , quality: %s, " | |
733 "out_color_type: %d", | |
734 xsize, | |
735 ysize, | |
736 scaled_xsize, | |
737 scaled_ysize, | |
738 test_pattern, | |
739 kQualityNames[quality], | |
740 out_color_type); | |
741 | |
742 // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture. | |
743 SkBitmap output_pixels; | |
744 output_pixels.allocPixels(SkImageInfo::Make( | |
745 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); | |
746 base::RunLoop run_loop; | |
747 gfx::Size encoded_texture_size; | |
748 helper_->CropScaleReadbackAndCleanTexture( | |
749 src_texture, | |
750 gfx::Size(xsize, ysize), | |
751 gfx::Rect(xsize, ysize), | |
752 gfx::Size(scaled_xsize, scaled_ysize), | |
753 static_cast<unsigned char*>(output_pixels.getPixels()), | |
754 out_color_type, | |
755 base::Bind(&callcallback, run_loop.QuitClosure()), | |
756 kQualities[quality]); | |
757 run_loop.Run(); | |
758 // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back. | |
759 FlipSKBitmap(&output_pixels); | |
no sievers
2014/08/20 20:29:52
Why do we end up with an upside down image? That s
mfomitchev
2014/08/22 18:01:34
The old version of CropScaleReadbackAndCleanTextur
no sievers
2014/08/22 18:44:13
This is intriguing, as I believe we use this path
| |
760 | |
761 // Now transofrm the bitmap using the reference implementation. | |
no sievers
2014/08/20 20:29:52
nit, typo: 'transform'
mfomitchev
2014/08/22 18:01:33
Done.
| |
762 SkBitmap scaled_pixels; | |
763 scaled_pixels.allocPixels(SkImageInfo::Make( | |
764 scaled_xsize, | |
765 scaled_ysize, | |
766 kRGBA_8888_SkColorType, | |
767 kPremul_SkAlphaType)); | |
768 SkBitmap truth_pixels; | |
769 // Step 1: Scale | |
770 ScaleSlowRecursive(input_pixels.get(), &scaled_pixels, kQualities[quality]); | |
771 // Step 2: Convert to the specified output format, encoding to grayscale if | |
772 // needed. | |
773 switch (out_color_type) { | |
774 case kRGBA_8888_SkColorType: | |
775 truth_pixels = scaled_pixels; | |
776 break; | |
777 case kBGRA_8888_SkColorType: | |
no sievers
2014/08/20 20:29:52
nit: indent here and below
mfomitchev
2014/08/22 18:01:33
Done.
| |
778 // Swizzle pixels of the scaled bitmap if the output needs to be BGRA | |
no sievers
2014/08/20 20:29:52
or could Compare() just learn to handle the format
mfomitchev
2014/08/22 18:01:33
Problem is, scale tests here use Compare() to do a
no sievers
2014/08/22 18:44:13
hmm maybe put a TODO then?
mfomitchev
2014/08/25 19:21:53
Ok, I've just updated TestScale to consistently us
| |
779 truth_pixels.installPixels( | |
780 SkImageInfo::Make(scaled_xsize, | |
781 scaled_ysize, | |
782 out_color_type, | |
783 kPremul_SkAlphaType), | |
784 scaled_pixels.getPixels(), | |
785 scaled_pixels.width() * 4); | |
786 SwizzleSKBitmap(&truth_pixels); | |
787 break; | |
788 case kAlpha_8_SkColorType: | |
789 truth_pixels.allocPixels(SkImageInfo::Make( | |
790 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); | |
791 EncodeToGrayscaleSlow(&scaled_pixels, &truth_pixels); | |
792 break; | |
793 default: | |
794 NOTREACHED(); | |
795 } | |
796 | |
797 // Now compare the results. | |
798 SkAutoLockPixels lock_input(truth_pixels); | |
799 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; | |
800 Compare(&truth_pixels, | |
801 &output_pixels, | |
802 2, | |
no sievers
2014/08/20 20:29:52
Just wondering, why 2? Maybe hubbe knows. I did no
mfomitchev
2014/08/22 18:01:33
It does fail on my machine for 16x16 -> 3x6 best-q
| |
803 input_pixels.get(), | |
804 dummy_stages, | |
805 message + " comparing against transformed/scaled"); | |
806 | |
807 context_->deleteTexture(src_texture); | |
808 context_->deleteFramebuffer(framebuffer); | |
809 } | |
810 | |
578 // Scaling test: Create a test image, scale it using GLHelperScaling | 811 // Scaling test: Create a test image, scale it using GLHelperScaling |
579 // and a reference implementation and compare the results. | 812 // and a reference implementation and compare the results. |
580 void TestScale(int xsize, | 813 void TestScale(int xsize, |
581 int ysize, | 814 int ysize, |
582 int scaled_xsize, | 815 int scaled_xsize, |
583 int scaled_ysize, | 816 int scaled_ysize, |
584 int test_pattern, | 817 int test_pattern, |
585 size_t quality, | 818 size_t quality, |
586 bool flip) { | 819 bool flip) { |
587 WebGLId src_texture = context_->createTexture(); | 820 WebGLId src_texture = context_->createTexture(); |
588 WebGLId framebuffer = context_->createFramebuffer(); | 821 WebGLId framebuffer = context_->createFramebuffer(); |
589 SkBitmap input_pixels; | 822 scoped_ptr<SkBitmap> input_pixels = |
590 input_pixels.allocN32Pixels(xsize, ysize); | 823 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); |
591 | 824 BindTextureAndFrameBuffer( |
592 for (int x = 0; x < xsize; ++x) { | 825 src_texture, framebuffer, input_pixels.get(), xsize, ysize); |
593 for (int y = 0; y < ysize; ++y) { | |
594 switch (test_pattern) { | |
595 case 0: // Smooth test pattern | |
596 SetChannel(&input_pixels, x, y, 0, x * 10); | |
597 SetChannel(&input_pixels, x, y, 1, y * 10); | |
598 SetChannel(&input_pixels, x, y, 2, (x + y) * 10); | |
599 SetChannel(&input_pixels, x, y, 3, 255); | |
600 break; | |
601 case 1: // Small blocks | |
602 SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0); | |
603 SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0); | |
604 SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0); | |
605 SetChannel(&input_pixels, x, y, 3, 255); | |
606 break; | |
607 case 2: // Medium blocks | |
608 SetChannel(&input_pixels, x, y, 0, 10 + x / 2 * 50); | |
609 SetChannel(&input_pixels, x, y, 1, 10 + y / 3 * 50); | |
610 SetChannel(&input_pixels, x, y, 2, (x + y) / 5 * 50 + 5); | |
611 SetChannel(&input_pixels, x, y, 3, 255); | |
612 break; | |
613 } | |
614 } | |
615 } | |
616 | |
617 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); | |
618 context_->bindTexture(GL_TEXTURE_2D, src_texture); | |
619 context_->texImage2D(GL_TEXTURE_2D, | |
620 0, | |
621 GL_RGBA, | |
622 xsize, | |
623 ysize, | |
624 0, | |
625 GL_RGBA, | |
626 GL_UNSIGNED_BYTE, | |
627 input_pixels.getPixels()); | |
628 | 826 |
629 std::string message = base::StringPrintf( | 827 std::string message = base::StringPrintf( |
630 "input size: %dx%d " | 828 "input size: %dx%d " |
631 "output size: %dx%d " | 829 "output size: %dx%d " |
632 "pattern: %d quality: %s", | 830 "pattern: %d quality: %s", |
633 xsize, | 831 xsize, |
634 ysize, | 832 ysize, |
635 scaled_xsize, | 833 scaled_xsize, |
636 scaled_ysize, | 834 scaled_ysize, |
637 test_pattern, | 835 test_pattern, |
(...skipping 25 matching lines...) Expand all Loading... | |
663 helper_->ReadbackTextureSync( | 861 helper_->ReadbackTextureSync( |
664 dst_texture, | 862 dst_texture, |
665 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), | 863 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), |
666 static_cast<unsigned char*>(output_pixels.getPixels()), | 864 static_cast<unsigned char*>(output_pixels.getPixels()), |
667 kRGBA_8888_SkColorType); | 865 kRGBA_8888_SkColorType); |
668 if (flip) { | 866 if (flip) { |
669 // Flip the pixels back. | 867 // Flip the pixels back. |
670 FlipSKBitmap(&output_pixels); | 868 FlipSKBitmap(&output_pixels); |
671 } | 869 } |
672 if (xsize == scaled_xsize && ysize == scaled_ysize) { | 870 if (xsize == scaled_xsize && ysize == scaled_ysize) { |
673 Compare(&input_pixels, | 871 Compare(input_pixels.get(), |
674 &output_pixels, | 872 &output_pixels, |
675 2, | 873 2, |
676 NULL, | 874 NULL, |
677 stages, | 875 stages, |
678 message + " comparing against input"); | 876 message + " comparing against input"); |
679 } | 877 } |
680 SkBitmap truth_pixels; | 878 SkBitmap truth_pixels; |
681 truth_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); | 879 truth_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); |
682 | 880 |
683 ScaleSlowRecursive(&input_pixels, &truth_pixels, kQualities[quality]); | 881 ScaleSlowRecursive(input_pixels.get(), &truth_pixels, kQualities[quality]); |
684 Compare(&truth_pixels, | 882 Compare(&truth_pixels, |
685 &output_pixels, | 883 &output_pixels, |
686 2, | 884 2, |
687 &input_pixels, | 885 input_pixels.get(), |
688 stages, | 886 stages, |
689 message + " comparing against scaled"); | 887 message + " comparing against scaled"); |
690 | 888 |
691 context_->deleteTexture(src_texture); | 889 context_->deleteTexture(src_texture); |
692 context_->deleteTexture(dst_texture); | 890 context_->deleteTexture(dst_texture); |
693 context_->deleteFramebuffer(framebuffer); | 891 context_->deleteFramebuffer(framebuffer); |
694 } | 892 } |
695 | 893 |
696 // Create a scaling pipeline and check that it is made up of | 894 // Create a scaling pipeline and check that it is made up of |
697 // valid scaling operations. | 895 // valid scaling operations. |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1006 base::Bind(&callcallback, | 1204 base::Bind(&callcallback, |
1007 run_loop.QuitClosure())); | 1205 run_loop.QuitClosure())); |
1008 run_loop.Run(); | 1206 run_loop.Run(); |
1009 } else { | 1207 } else { |
1010 helper_->ReadbackTextureSync(src_texture, | 1208 helper_->ReadbackTextureSync(src_texture, |
1011 gfx::Rect(src_size), | 1209 gfx::Rect(src_size), |
1012 pixels, | 1210 pixels, |
1013 color_type); | 1211 color_type); |
1014 } | 1212 } |
1015 } | 1213 } |
1016 | |
1017 // Test basic format readback. | 1214 // Test basic format readback. |
1018 bool TestTextureFormatReadback(const gfx::Size& src_size, | 1215 bool TestTextureFormatReadback(const gfx::Size& src_size, |
1019 SkColorType color_type, | 1216 SkColorType color_type, |
1020 bool async) { | 1217 bool async) { |
1021 SkImageInfo info = | 1218 SkImageInfo info = |
1022 SkImageInfo::Make(src_size.width(), | 1219 SkImageInfo::Make(src_size.width(), |
1023 src_size.height(), | 1220 src_size.height(), |
1024 color_type, | 1221 color_type, |
1025 kPremul_SkAlphaType); | 1222 kPremul_SkAlphaType); |
1026 if (!helper_->IsReadbackConfigSupported(color_type)) { | 1223 if (!helper_->IsReadbackConfigSupported(color_type)) { |
(...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1618 } | 1815 } |
1619 } | 1816 } |
1620 } | 1817 } |
1621 } | 1818 } |
1622 } | 1819 } |
1623 } | 1820 } |
1624 } | 1821 } |
1625 } | 1822 } |
1626 } | 1823 } |
1627 | 1824 |
1825 // Per pixel tests, all sizes are small so that we can print | |
1826 // out the generated bitmaps. | |
1827 TEST_F(GLHelperPixelTest, CropScaleReadbackAndCleanTextureTest) { | |
1828 int sizes[] = {3, 6, 16}; | |
1829 SkColorType color_types[] = | |
no sievers
2014/08/20 20:29:52
nit:
const int kSizes[] = ...
const SkColorType k
mfomitchev
2014/08/22 18:01:33
Done.
| |
1830 {kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}; | |
1831 // Test BEST and FAST qualities, skip GOOD | |
1832 for (size_t q = 0; q < arraysize(kQualities); q += 2) { | |
no sievers
2014/08/20 20:29:52
why q+=2 and not q++?
mfomitchev
2014/08/22 18:01:33
FAST uses a different code path in CropScaleReadba
no sievers
2014/08/22 18:44:13
Ok, maybe it's more straightforward to define your
mfomitchev
2014/08/25 19:21:53
The index is also used to fetch the name from kQua
| |
1833 for (int color_type = 0; color_type < 3; color_type++) { | |
no sievers
2014/08/20 20:29:52
color_type < arraysize(kColorTypes)
mfomitchev
2014/08/22 18:01:33
Done.
| |
1834 for (int x = 0; x < 3; x++) { | |
1835 for (int y = 0; y < 3; y++) { | |
1836 for (int dst_x = 0; dst_x < 3; dst_x++) { | |
1837 for (int dst_y = 0; dst_y < 3; dst_y++) { | |
1838 for (int pattern = 0; pattern < 3; pattern++) { | |
1839 TestCropScaleReadbackAndCleanTexture(sizes[x], | |
1840 sizes[y], | |
1841 sizes[dst_x], | |
1842 sizes[dst_y], | |
1843 pattern, | |
1844 color_types[color_type], | |
1845 false, | |
1846 q); | |
1847 if (HasFailure()) | |
1848 return; | |
1849 } | |
1850 } | |
1851 } | |
1852 } | |
1853 } | |
1854 } | |
1855 } | |
1856 } | |
1857 | |
1628 // Validate that all scaling generates valid pipelines. | 1858 // Validate that all scaling generates valid pipelines. |
1629 TEST_F(GLHelperTest, ValidateScalerPipelines) { | 1859 TEST_F(GLHelperTest, ValidateScalerPipelines) { |
1630 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; | 1860 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; |
1631 for (size_t q = 0; q < arraysize(kQualities); q++) { | 1861 for (size_t q = 0; q < arraysize(kQualities); q++) { |
1632 for (size_t x = 0; x < arraysize(sizes); x++) { | 1862 for (size_t x = 0; x < arraysize(sizes); x++) { |
1633 for (size_t y = 0; y < arraysize(sizes); y++) { | 1863 for (size_t y = 0; y < arraysize(sizes); y++) { |
1634 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { | 1864 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { |
1635 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { | 1865 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { |
1636 TestScalerPipeline( | 1866 TestScalerPipeline( |
1637 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); | 1867 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1701 base::CommandLine::Init(argc, argv); | 1931 base::CommandLine::Init(argc, argv); |
1702 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); | 1932 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); |
1703 #if defined(OS_MACOSX) | 1933 #if defined(OS_MACOSX) |
1704 base::mac::ScopedNSAutoreleasePool pool; | 1934 base::mac::ScopedNSAutoreleasePool pool; |
1705 #endif | 1935 #endif |
1706 | 1936 |
1707 content::UnitTestTestSuite runner(suite); | 1937 content::UnitTestTestSuite runner(suite); |
1708 base::MessageLoop message_loop; | 1938 base::MessageLoop message_loop; |
1709 return runner.Run(); | 1939 return runner.Run(); |
1710 } | 1940 } |
OLD | NEW |