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 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 } | 387 } |
372 } | 388 } |
373 | 389 |
374 if (HasFailure() && !previous_error) { | 390 if (HasFailure() && !previous_error) { |
375 LOG(ERROR) << "Invalid scaler stages: " << message; | 391 LOG(ERROR) << "Invalid scaler stages: " << message; |
376 LOG(ERROR) << "Scaler stages:"; | 392 LOG(ERROR) << "Scaler stages:"; |
377 LOG(ERROR) << PrintStages(scaler_stages); | 393 LOG(ERROR) << PrintStages(scaler_stages); |
378 } | 394 } |
379 } | 395 } |
380 | 396 |
381 // Compare two bitmaps, make sure that each component of each pixel | 397 // Compares two bitmaps taking color types into account. Checks whether each |
382 // is no more than |maxdiff| apart. If they are not similar enough, | 398 // component of each pixel is no more than |maxdiff| apart. If bitmaps are not |
383 // prints out |truth|, |other|, |source|, |scaler_stages| and |message|. | 399 // similar enough, prints out |truth|, |other|, |source|, |scaler_stages| |
400 // and |message|. | |
384 void Compare(SkBitmap* truth, | 401 void Compare(SkBitmap* truth, |
385 SkBitmap* other, | 402 SkBitmap* other, |
386 int maxdiff, | 403 int maxdiff, |
387 SkBitmap* source, | 404 SkBitmap* source, |
388 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, | 405 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, |
389 std::string message) { | 406 std::string message) { |
390 EXPECT_EQ(truth->width(), other->width()); | 407 EXPECT_EQ(truth->width(), other->width()); |
391 EXPECT_EQ(truth->height(), other->height()); | 408 EXPECT_EQ(truth->height(), other->height()); |
409 bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType && | |
410 other->colorType() == kBGRA_8888_SkColorType) || | |
411 (truth->colorType() == kBGRA_8888_SkColorType && | |
412 other->colorType() == kRGBA_8888_SkColorType); | |
413 EXPECT_TRUE(swizzle || truth->colorType() == other->colorType()); | |
414 int bpp = truth->bytesPerPixel(); | |
392 for (int x = 0; x < truth->width(); x++) { | 415 for (int x = 0; x < truth->width(); x++) { |
393 for (int y = 0; y < truth->height(); y++) { | 416 for (int y = 0; y < truth->height(); y++) { |
394 for (int c = 0; c < 4; c++) { | 417 for (int c = 0; c < bpp; c++) { |
395 int a = Channel(truth, x, y, c); | 418 int a = Channel(truth, x, y, c); |
396 int b = Channel(other, x, y, c); | 419 // swizzle when comparing if needed |
420 int b = swizzle && (c == 0 || c == 2) | |
421 ? Channel(other, x, y, (c + 2) & 2) | |
422 : Channel(other, x, y, c); | |
397 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c | 423 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c |
398 << " " << message; | 424 << " " << message; |
399 if (std::abs(a - b) > maxdiff) { | 425 if (std::abs(a - b) > maxdiff) { |
400 LOG(ERROR) << "-------expected--------"; | 426 LOG(ERROR) << "-------expected--------"; |
401 PrintChannel(truth, c); | 427 for (int i = 0; i < bpp; i++) { |
428 LOG(ERROR) << "Channel " << i << ":"; | |
429 PrintChannel(truth, i); | |
430 } | |
402 LOG(ERROR) << "-------actual--------"; | 431 LOG(ERROR) << "-------actual--------"; |
403 PrintChannel(other, c); | 432 for (int i = 0; i < bpp; i++) { |
433 LOG(ERROR) << "Channel " << i << ":"; | |
434 PrintChannel(other, i); | |
435 } | |
404 if (source) { | 436 if (source) { |
405 LOG(ERROR) << "-------before scaling--------"; | 437 LOG(ERROR) << "-------original--------"; |
406 PrintChannel(source, c); | 438 for (int i = 0; i < source->bytesPerPixel(); i++) { |
439 LOG(ERROR) << "Channel " << i << ":"; | |
440 PrintChannel(source, i); | |
441 } | |
407 } | 442 } |
408 LOG(ERROR) << "-----Scaler stages------"; | 443 LOG(ERROR) << "-----Scaler stages------"; |
409 LOG(ERROR) << PrintStages(scaler_stages); | 444 LOG(ERROR) << PrintStages(scaler_stages); |
410 return; | 445 return; |
411 } | 446 } |
412 } | 447 } |
413 } | 448 } |
414 } | 449 } |
415 } | 450 } |
416 | 451 |
417 // Get a single R, G, B or A value as a float. | 452 // Get a single R, G, B or A value as a float. |
418 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { | 453 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { |
419 return Channel(pixels, x, y, c) / 255.0; | 454 return Channel(pixels, x, y, c) / 255.0; |
420 } | 455 } |
421 | 456 |
422 // Works like a GL_LINEAR lookup on an SkBitmap. | 457 // Works like a GL_LINEAR lookup on an SkBitmap. |
423 float Bilinear(SkBitmap* pixels, float x, float y, int c) { | 458 float Bilinear(SkBitmap* pixels, float x, float y, int c) { |
424 x -= 0.5; | 459 x -= 0.5; |
425 y -= 0.5; | 460 y -= 0.5; |
426 int base_x = static_cast<int>(floorf(x)); | 461 int base_x = static_cast<int>(floorf(x)); |
427 int base_y = static_cast<int>(floorf(y)); | 462 int base_y = static_cast<int>(floorf(y)); |
428 x -= base_x; | 463 x -= base_x; |
429 y -= base_y; | 464 y -= base_y; |
430 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + | 465 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + |
431 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + | 466 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + |
432 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + | 467 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + |
433 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); | 468 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); |
434 } | 469 } |
435 | 470 |
471 // Encodes an RGBA bitmap to grayscale. | |
472 // Reference implementation for | |
473 // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale. | |
474 void EncodeToGrayscaleSlow(SkBitmap* input, SkBitmap* output) { | |
475 const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f}; | |
476 CHECK_EQ(kAlpha_8_SkColorType, output->colorType()); | |
477 CHECK_EQ(input->width(), output->width()); | |
478 CHECK_EQ(input->height(), output->height()); | |
479 CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType); | |
480 | |
481 for (int dst_y = 0; dst_y < output->height(); dst_y++) { | |
482 for (int dst_x = 0; dst_x < output->width(); dst_x++) { | |
483 float c0 = ChannelAsFloat(input, dst_x, dst_y, 0); | |
484 float c1 = ChannelAsFloat(input, dst_x, dst_y, 1); | |
485 float c2 = ChannelAsFloat(input, dst_x, dst_y, 2); | |
486 float value = c0 * kRGBtoGrayscaleColorWeights[0] + | |
487 c1 * kRGBtoGrayscaleColorWeights[1] + | |
488 c2 * kRGBtoGrayscaleColorWeights[2]; | |
489 SetChannel( | |
490 output, dst_x, dst_y, 0, static_cast<int>(value * 255.0f + 0.5f)); | |
491 } | |
492 } | |
493 } | |
494 | |
436 // Very slow bicubic / bilinear scaler for reference. | 495 // Very slow bicubic / bilinear scaler for reference. |
437 void ScaleSlow(SkBitmap* input, | 496 void ScaleSlow(SkBitmap* input, |
438 SkBitmap* output, | 497 SkBitmap* output, |
439 content::GLHelper::ScalerQuality quality) { | 498 content::GLHelper::ScalerQuality quality) { |
440 float xscale = static_cast<float>(input->width()) / output->width(); | 499 float xscale = static_cast<float>(input->width()) / output->width(); |
441 float yscale = static_cast<float>(input->height()) / output->height(); | 500 float yscale = static_cast<float>(input->height()) / output->height(); |
442 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; | 501 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; |
443 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; | 502 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; |
444 for (int dst_y = 0; dst_y < output->height(); dst_y++) { | 503 for (int dst_y = 0; dst_y < output->height(); dst_y++) { |
445 for (int dst_x = 0; dst_x < output->width(); dst_x++) { | 504 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, | 567 dst_x, |
509 dst_y, | 568 dst_y, |
510 channel, | 569 channel, |
511 static_cast<int>(value * 255.0f + 0.5f)); | 570 static_cast<int>(value * 255.0f + 0.5f)); |
512 } | 571 } |
513 } | 572 } |
514 } | 573 } |
515 } | 574 } |
516 | 575 |
517 void FlipSKBitmap(SkBitmap* bitmap) { | 576 void FlipSKBitmap(SkBitmap* bitmap) { |
577 int bpp = bitmap->bytesPerPixel(); | |
578 DCHECK(bpp == 4 || bpp == 1); | |
518 int top_line = 0; | 579 int top_line = 0; |
519 int bottom_line = bitmap->height() - 1; | 580 int bottom_line = bitmap->height() - 1; |
520 while (top_line < bottom_line) { | 581 while (top_line < bottom_line) { |
521 for (int x = 0; x < bitmap->width(); x++) { | 582 for (int x = 0; x < bitmap->width(); x++) { |
522 std::swap(*bitmap->getAddr32(x, top_line), | 583 bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line), |
523 *bitmap->getAddr32(x, bottom_line)); | 584 *bitmap->getAddr32(x, bottom_line)) |
585 : std::swap(*bitmap->getAddr8(x, top_line), | |
586 *bitmap->getAddr8(x, bottom_line)); | |
524 } | 587 } |
525 top_line++; | 588 top_line++; |
526 bottom_line--; | 589 bottom_line--; |
527 } | 590 } |
528 } | 591 } |
529 | 592 |
593 // Swaps red and blue channels in each pixel in a 32-bit bitmap. | |
594 void SwizzleSKBitmap(SkBitmap* bitmap) { | |
595 int bpp = bitmap->bytesPerPixel(); | |
596 DCHECK(bpp == 4); | |
597 for (int y = 0; y < bitmap->height(); y++) { | |
598 for (int x = 0; x < bitmap->width(); x++) { | |
599 // Swap channels 0 and 2 (red and blue) | |
600 int c0 = Channel(bitmap, x, y, 0); | |
601 int c2 = Channel(bitmap, x, y, 2); | |
602 SetChannel(bitmap, x, y, 2, c0); | |
603 SetChannel(bitmap, x, y, 0, c2); | |
604 } | |
605 } | |
606 } | |
607 | |
530 // gl_helper scales recursively, so we'll need to do that | 608 // gl_helper scales recursively, so we'll need to do that |
531 // in the reference implementation too. | 609 // in the reference implementation too. |
532 void ScaleSlowRecursive(SkBitmap* input, | 610 void ScaleSlowRecursive(SkBitmap* input, |
533 SkBitmap* output, | 611 SkBitmap* output, |
534 content::GLHelper::ScalerQuality quality) { | 612 content::GLHelper::ScalerQuality quality) { |
535 if (quality == content::GLHelper::SCALER_QUALITY_FAST || | 613 if (quality == content::GLHelper::SCALER_QUALITY_FAST || |
536 quality == content::GLHelper::SCALER_QUALITY_GOOD) { | 614 quality == content::GLHelper::SCALER_QUALITY_GOOD) { |
537 ScaleSlow(input, output, quality); | 615 ScaleSlow(input, output, quality); |
538 return; | 616 return; |
539 } | 617 } |
(...skipping 28 matching lines...) Expand all Loading... | |
568 } | 646 } |
569 } | 647 } |
570 | 648 |
571 SkBitmap tmp; | 649 SkBitmap tmp; |
572 tmp.allocN32Pixels(xtmp, ytmp); | 650 tmp.allocN32Pixels(xtmp, ytmp); |
573 | 651 |
574 ScaleSlowRecursive(input, &tmp, quality); | 652 ScaleSlowRecursive(input, &tmp, quality); |
575 ScaleSlowRecursive(&tmp, output, quality); | 653 ScaleSlowRecursive(&tmp, output, quality); |
576 } | 654 } |
577 | 655 |
656 // Creates an RGBA SkBitmap | |
657 scoped_ptr<SkBitmap> CreateTestBitmap(int width, | |
658 int height, | |
659 int test_pattern) { | |
660 scoped_ptr<SkBitmap> bitmap(new SkBitmap); | |
661 bitmap->allocPixels(SkImageInfo::Make( | |
662 width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | |
663 | |
664 for (int x = 0; x < width; ++x) { | |
665 for (int y = 0; y < height; ++y) { | |
666 switch (test_pattern) { | |
667 case 0: // Smooth test pattern | |
668 SetChannel(bitmap.get(), x, y, 0, x * 10); | |
669 SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10); | |
670 SetChannel(bitmap.get(), x, y, 1, y * 10); | |
671 SetChannel(bitmap.get(), x, y, 2, (x + y) * 10); | |
672 SetChannel(bitmap.get(), x, y, 3, 255); | |
673 break; | |
674 case 1: // Small blocks | |
675 SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0); | |
676 SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0); | |
677 SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0); | |
678 SetChannel(bitmap.get(), x, y, 3, 255); | |
679 break; | |
680 case 2: // Medium blocks | |
681 SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50); | |
682 SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50); | |
683 SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5); | |
684 SetChannel(bitmap.get(), x, y, 3, 255); | |
685 break; | |
686 } | |
687 } | |
688 } | |
689 return bitmap.Pass(); | |
690 } | |
691 | |
692 // Binds texture and framebuffer and loads the bitmap pixels into the texture. | |
693 void BindTextureAndFrameBuffer(WebGLId texture, | |
694 WebGLId framebuffer, | |
695 SkBitmap* bitmap, | |
696 int width, | |
697 int height) { | |
698 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); | |
699 context_->bindTexture(GL_TEXTURE_2D, texture); | |
700 context_->texImage2D(GL_TEXTURE_2D, | |
701 0, | |
702 GL_RGBA, | |
703 width, | |
704 height, | |
705 0, | |
706 GL_RGBA, | |
707 GL_UNSIGNED_BYTE, | |
708 bitmap->getPixels()); | |
709 } | |
710 | |
711 // Create a test image, transform it using | |
712 // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation | |
713 // and compare the results. | |
714 void TestCropScaleReadbackAndCleanTexture(int xsize, | |
715 int ysize, | |
716 int scaled_xsize, | |
717 int scaled_ysize, | |
718 int test_pattern, | |
719 SkColorType out_color_type, | |
720 bool swizzle, | |
721 size_t quality_index) { | |
722 DCHECK(out_color_type == kAlpha_8_SkColorType || | |
723 out_color_type == kRGBA_8888_SkColorType || | |
724 out_color_type == kBGRA_8888_SkColorType); | |
725 WebGLId src_texture = context_->createTexture(); | |
726 WebGLId framebuffer = context_->createFramebuffer(); | |
727 scoped_ptr<SkBitmap> input_pixels = | |
728 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); | |
729 BindTextureAndFrameBuffer( | |
730 src_texture, framebuffer, input_pixels.get(), xsize, ysize); | |
731 | |
732 std::string message = base::StringPrintf( | |
733 "input size: %dx%d " | |
734 "output size: %dx%d " | |
735 "pattern: %d , quality: %s, " | |
736 "out_color_type: %d", | |
737 xsize, | |
738 ysize, | |
739 scaled_xsize, | |
740 scaled_ysize, | |
741 test_pattern, | |
742 kQualityNames[quality_index], | |
743 out_color_type); | |
744 | |
745 // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture. | |
746 SkBitmap output_pixels; | |
747 output_pixels.allocPixels(SkImageInfo::Make( | |
748 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); | |
749 base::RunLoop run_loop; | |
750 gfx::Size encoded_texture_size; | |
751 helper_->CropScaleReadbackAndCleanTexture( | |
752 src_texture, | |
753 gfx::Size(xsize, ysize), | |
754 gfx::Rect(xsize, ysize), | |
755 gfx::Size(scaled_xsize, scaled_ysize), | |
756 static_cast<unsigned char*>(output_pixels.getPixels()), | |
757 out_color_type, | |
758 base::Bind(&callcallback, run_loop.QuitClosure()), | |
759 kQualities[quality_index]); | |
760 run_loop.Run(); | |
761 // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back. | |
762 FlipSKBitmap(&output_pixels); | |
763 | |
764 // If the bitmap shouldn't have changed - compare against input. | |
765 if (xsize == scaled_xsize && ysize == scaled_ysize && | |
766 out_color_type != kAlpha_8_SkColorType) { | |
767 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; | |
768 Compare(input_pixels.get(), | |
769 &output_pixels, | |
770 2, | |
no sievers
2014/08/25 19:34:52
If there was no scaling should the tolerance be 0?
mfomitchev
2014/08/25 20:05:04
Done.
| |
771 NULL, | |
772 dummy_stages, | |
773 message + " comparing against input"); | |
774 return; | |
775 } | |
776 | |
777 // Now transform the bitmap using the reference implementation. | |
778 SkBitmap scaled_pixels; | |
779 scaled_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, | |
780 scaled_ysize, | |
781 kRGBA_8888_SkColorType, | |
782 kPremul_SkAlphaType)); | |
783 SkBitmap truth_pixels; | |
784 // Step 1: Scale | |
785 ScaleSlowRecursive( | |
786 input_pixels.get(), &scaled_pixels, kQualities[quality_index]); | |
787 // Step 2: Encode to grayscale if needed. | |
788 if (out_color_type == 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 } else { | |
793 truth_pixels = scaled_pixels; | |
794 } | |
795 | |
796 // Now compare the results. | |
797 SkAutoLockPixels lock_input(truth_pixels); | |
798 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; | |
799 Compare(&truth_pixels, | |
800 &output_pixels, | |
801 2, | |
802 input_pixels.get(), | |
803 dummy_stages, | |
804 message + " comparing against transformed/scaled"); | |
805 | |
806 context_->deleteTexture(src_texture); | |
807 context_->deleteFramebuffer(framebuffer); | |
808 } | |
809 | |
578 // Scaling test: Create a test image, scale it using GLHelperScaling | 810 // Scaling test: Create a test image, scale it using GLHelperScaling |
579 // and a reference implementation and compare the results. | 811 // and a reference implementation and compare the results. |
580 void TestScale(int xsize, | 812 void TestScale(int xsize, |
581 int ysize, | 813 int ysize, |
582 int scaled_xsize, | 814 int scaled_xsize, |
583 int scaled_ysize, | 815 int scaled_ysize, |
584 int test_pattern, | 816 int test_pattern, |
585 size_t quality, | 817 size_t quality_index, |
586 bool flip) { | 818 bool flip) { |
587 WebGLId src_texture = context_->createTexture(); | 819 WebGLId src_texture = context_->createTexture(); |
588 WebGLId framebuffer = context_->createFramebuffer(); | 820 WebGLId framebuffer = context_->createFramebuffer(); |
589 SkBitmap input_pixels; | 821 scoped_ptr<SkBitmap> input_pixels = |
590 input_pixels.allocN32Pixels(xsize, ysize); | 822 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); |
591 | 823 BindTextureAndFrameBuffer( |
592 for (int x = 0; x < xsize; ++x) { | 824 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 | 825 |
629 std::string message = base::StringPrintf( | 826 std::string message = base::StringPrintf( |
630 "input size: %dx%d " | 827 "input size: %dx%d " |
631 "output size: %dx%d " | 828 "output size: %dx%d " |
632 "pattern: %d quality: %s", | 829 "pattern: %d quality: %s", |
633 xsize, | 830 xsize, |
634 ysize, | 831 ysize, |
635 scaled_xsize, | 832 scaled_xsize, |
636 scaled_ysize, | 833 scaled_ysize, |
637 test_pattern, | 834 test_pattern, |
638 kQualityNames[quality]); | 835 kQualityNames[quality_index]); |
639 | 836 |
640 std::vector<GLHelperScaling::ScalerStage> stages; | 837 std::vector<GLHelperScaling::ScalerStage> stages; |
641 helper_scaling_->ComputeScalerStages(kQualities[quality], | 838 helper_scaling_->ComputeScalerStages(kQualities[quality_index], |
642 gfx::Size(xsize, ysize), | 839 gfx::Size(xsize, ysize), |
643 gfx::Rect(0, 0, xsize, ysize), | 840 gfx::Rect(0, 0, xsize, ysize), |
644 gfx::Size(scaled_xsize, scaled_ysize), | 841 gfx::Size(scaled_xsize, scaled_ysize), |
645 flip, | 842 flip, |
646 false, | 843 false, |
647 &stages); | 844 &stages); |
648 ValidateScalerStages(kQualities[quality], | 845 ValidateScalerStages(kQualities[quality_index], |
649 stages, | 846 stages, |
650 gfx::Size(scaled_xsize, scaled_ysize), | 847 gfx::Size(scaled_xsize, scaled_ysize), |
651 message); | 848 message); |
652 | 849 |
653 WebGLId dst_texture = | 850 WebGLId dst_texture = |
654 helper_->CopyAndScaleTexture(src_texture, | 851 helper_->CopyAndScaleTexture(src_texture, |
655 gfx::Size(xsize, ysize), | 852 gfx::Size(xsize, ysize), |
656 gfx::Size(scaled_xsize, scaled_ysize), | 853 gfx::Size(scaled_xsize, scaled_ysize), |
657 flip, | 854 flip, |
658 kQualities[quality]); | 855 kQualities[quality_index]); |
659 | 856 |
660 SkBitmap output_pixels; | 857 SkBitmap output_pixels; |
661 output_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); | 858 output_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, |
859 scaled_ysize, | |
860 kRGBA_8888_SkColorType, | |
861 kPremul_SkAlphaType)); | |
662 | 862 |
663 helper_->ReadbackTextureSync( | 863 helper_->ReadbackTextureSync( |
664 dst_texture, | 864 dst_texture, |
665 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), | 865 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), |
666 static_cast<unsigned char*>(output_pixels.getPixels()), | 866 static_cast<unsigned char*>(output_pixels.getPixels()), |
667 kRGBA_8888_SkColorType); | 867 kRGBA_8888_SkColorType); |
668 if (flip) { | 868 if (flip) { |
669 // Flip the pixels back. | 869 // Flip the pixels back. |
670 FlipSKBitmap(&output_pixels); | 870 FlipSKBitmap(&output_pixels); |
671 } | 871 } |
872 | |
873 // If the bitmap shouldn't have changed - compare against input. | |
672 if (xsize == scaled_xsize && ysize == scaled_ysize) { | 874 if (xsize == scaled_xsize && ysize == scaled_ysize) { |
673 Compare(&input_pixels, | 875 Compare(input_pixels.get(), |
674 &output_pixels, | 876 &output_pixels, |
675 2, | 877 2, |
676 NULL, | 878 NULL, |
677 stages, | 879 stages, |
678 message + " comparing against input"); | 880 message + " comparing against input"); |
881 return; | |
679 } | 882 } |
883 | |
884 // Now scale the bitmap using the reference implementation. | |
680 SkBitmap truth_pixels; | 885 SkBitmap truth_pixels; |
681 truth_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); | 886 truth_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, |
682 | 887 scaled_ysize, |
683 ScaleSlowRecursive(&input_pixels, &truth_pixels, kQualities[quality]); | 888 kRGBA_8888_SkColorType, |
889 kPremul_SkAlphaType)); | |
890 ScaleSlowRecursive( | |
891 input_pixels.get(), &truth_pixels, kQualities[quality_index]); | |
684 Compare(&truth_pixels, | 892 Compare(&truth_pixels, |
685 &output_pixels, | 893 &output_pixels, |
686 2, | 894 2, |
687 &input_pixels, | 895 input_pixels.get(), |
688 stages, | 896 stages, |
689 message + " comparing against scaled"); | 897 message + " comparing against scaled"); |
690 | 898 |
691 context_->deleteTexture(src_texture); | 899 context_->deleteTexture(src_texture); |
692 context_->deleteTexture(dst_texture); | 900 context_->deleteTexture(dst_texture); |
693 context_->deleteFramebuffer(framebuffer); | 901 context_->deleteFramebuffer(framebuffer); |
694 } | 902 } |
695 | 903 |
696 // Create a scaling pipeline and check that it is made up of | 904 // Create a scaling pipeline and check that it is made up of |
697 // valid scaling operations. | 905 // valid scaling operations. |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1006 base::Bind(&callcallback, | 1214 base::Bind(&callcallback, |
1007 run_loop.QuitClosure())); | 1215 run_loop.QuitClosure())); |
1008 run_loop.Run(); | 1216 run_loop.Run(); |
1009 } else { | 1217 } else { |
1010 helper_->ReadbackTextureSync(src_texture, | 1218 helper_->ReadbackTextureSync(src_texture, |
1011 gfx::Rect(src_size), | 1219 gfx::Rect(src_size), |
1012 pixels, | 1220 pixels, |
1013 color_type); | 1221 color_type); |
1014 } | 1222 } |
1015 } | 1223 } |
1016 | |
1017 // Test basic format readback. | 1224 // Test basic format readback. |
1018 bool TestTextureFormatReadback(const gfx::Size& src_size, | 1225 bool TestTextureFormatReadback(const gfx::Size& src_size, |
1019 SkColorType color_type, | 1226 SkColorType color_type, |
1020 bool async) { | 1227 bool async) { |
1021 SkImageInfo info = | 1228 SkImageInfo info = |
1022 SkImageInfo::Make(src_size.width(), | 1229 SkImageInfo::Make(src_size.width(), |
1023 src_size.height(), | 1230 src_size.height(), |
1024 color_type, | 1231 color_type, |
1025 kPremul_SkAlphaType); | 1232 kPremul_SkAlphaType); |
1026 if (!helper_->IsReadbackConfigSupported(color_type)) { | 1233 if (!helper_->IsReadbackConfigSupported(color_type)) { |
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1593 } | 1800 } |
1594 } | 1801 } |
1595 } | 1802 } |
1596 } | 1803 } |
1597 | 1804 |
1598 // Per pixel tests, all sizes are small so that we can print | 1805 // Per pixel tests, all sizes are small so that we can print |
1599 // out the generated bitmaps. | 1806 // out the generated bitmaps. |
1600 TEST_F(GLHelperPixelTest, ScaleTest) { | 1807 TEST_F(GLHelperPixelTest, ScaleTest) { |
1601 int sizes[] = {3, 6, 16}; | 1808 int sizes[] = {3, 6, 16}; |
1602 for (int flip = 0; flip <= 1; flip++) { | 1809 for (int flip = 0; flip <= 1; flip++) { |
1603 for (size_t q = 0; q < arraysize(kQualities); q++) { | 1810 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index++) { |
1604 for (int x = 0; x < 3; x++) { | 1811 for (int x = 0; x < 3; x++) { |
1605 for (int y = 0; y < 3; y++) { | 1812 for (int y = 0; y < 3; y++) { |
1606 for (int dst_x = 0; dst_x < 3; dst_x++) { | 1813 for (int dst_x = 0; dst_x < 3; dst_x++) { |
1607 for (int dst_y = 0; dst_y < 3; dst_y++) { | 1814 for (int dst_y = 0; dst_y < 3; dst_y++) { |
1608 for (int pattern = 0; pattern < 3; pattern++) { | 1815 for (int pattern = 0; pattern < 3; pattern++) { |
1609 TestScale(sizes[x], | 1816 TestScale(sizes[x], |
1610 sizes[y], | 1817 sizes[y], |
1611 sizes[dst_x], | 1818 sizes[dst_x], |
1612 sizes[dst_y], | 1819 sizes[dst_y], |
1613 pattern, | 1820 pattern, |
1614 q, | 1821 q_index, |
1615 flip == 1); | 1822 flip == 1); |
1616 if (HasFailure()) { | 1823 if (HasFailure()) { |
1617 return; | 1824 return; |
1618 } | 1825 } |
1619 } | 1826 } |
1620 } | 1827 } |
1621 } | 1828 } |
1622 } | 1829 } |
1623 } | 1830 } |
1624 } | 1831 } |
1625 } | 1832 } |
1626 } | 1833 } |
1627 | 1834 |
1835 // Per pixel tests, all sizes are small so that we can print | |
1836 // out the generated bitmaps. | |
1837 TEST_F(GLHelperPixelTest, CropScaleReadbackAndCleanTextureTest) { | |
1838 const int kSizes[] = {3, 6, 16}; | |
1839 const SkColorType kColorTypes[] = { | |
1840 kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}; | |
1841 for (size_t color_type = 0; color_type < arraysize(kColorTypes); | |
1842 color_type++) { | |
1843 // Test BEST and FAST qualities, skip GOOD | |
1844 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index += 2) { | |
1845 for (size_t x = 0; x < arraysize(kSizes); x++) { | |
1846 for (size_t y = 0; y < arraysize(kSizes); y++) { | |
1847 for (size_t dst_x = 0; dst_x < arraysize(kSizes); dst_x++) { | |
1848 for (size_t dst_y = 0; dst_y < arraysize(kSizes); dst_y++) { | |
1849 for (int pattern = 0; pattern < 3; pattern++) { | |
1850 TestCropScaleReadbackAndCleanTexture(kSizes[x], | |
1851 kSizes[y], | |
1852 kSizes[dst_x], | |
1853 kSizes[dst_y], | |
1854 pattern, | |
1855 kColorTypes[color_type], | |
1856 false, | |
1857 q_index); | |
1858 if (HasFailure()) | |
1859 return; | |
1860 } | |
1861 } | |
1862 } | |
1863 } | |
1864 } | |
1865 } | |
1866 } | |
1867 } | |
1868 | |
1628 // Validate that all scaling generates valid pipelines. | 1869 // Validate that all scaling generates valid pipelines. |
1629 TEST_F(GLHelperTest, ValidateScalerPipelines) { | 1870 TEST_F(GLHelperTest, ValidateScalerPipelines) { |
1630 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; | 1871 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; |
1631 for (size_t q = 0; q < arraysize(kQualities); q++) { | 1872 for (size_t q = 0; q < arraysize(kQualities); q++) { |
1632 for (size_t x = 0; x < arraysize(sizes); x++) { | 1873 for (size_t x = 0; x < arraysize(sizes); x++) { |
1633 for (size_t y = 0; y < arraysize(sizes); y++) { | 1874 for (size_t y = 0; y < arraysize(sizes); y++) { |
1634 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { | 1875 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++) { | 1876 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { |
1636 TestScalerPipeline( | 1877 TestScalerPipeline( |
1637 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); | 1878 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); | 1942 base::CommandLine::Init(argc, argv); |
1702 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); | 1943 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); |
1703 #if defined(OS_MACOSX) | 1944 #if defined(OS_MACOSX) |
1704 base::mac::ScopedNSAutoreleasePool pool; | 1945 base::mac::ScopedNSAutoreleasePool pool; |
1705 #endif | 1946 #endif |
1706 | 1947 |
1707 content::UnitTestTestSuite runner(suite); | 1948 content::UnitTestTestSuite runner(suite); |
1708 base::MessageLoop message_loop; | 1949 base::MessageLoop message_loop; |
1709 return runner.Run(); | 1950 return runner.Run(); |
1710 } | 1951 } |
OLD | NEW |