Chromium Code Reviews| 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 |