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 3// found in the LICENSE file. 4 5#include <stdio.h> 6#include <cmath> 7#include <string> 8#include <vector> 9 10#include <GLES2/gl2.h> 11#include <GLES2/gl2ext.h> 12#include <GLES2/gl2extchromium.h> 13 14#include "base/at_exit.h" 15#include "base/bind.h" 16#include "base/command_line.h" 17#include "base/debug/trace_event.h" 18#include "base/files/file_util.h" 19#include "base/json/json_reader.h" 20#include "base/message_loop/message_loop.h" 21#include "base/run_loop.h" 22#include "base/strings/stringprintf.h" 23#include "base/synchronization/waitable_event.h" 24#include "base/time/time.h" 25#include "content/common/gpu/client/gl_helper.h" 26#include "content/common/gpu/client/gl_helper_readback_support.h" 27#include "content/common/gpu/client/gl_helper_scaling.h" 28#include "content/public/test/unittest_test_suite.h" 29#include "content/test/content_test_suite.h" 30#include "media/base/video_frame.h" 31#include "testing/gtest/include/gtest/gtest.h" 32#include "third_party/skia/include/core/SkBitmap.h" 33#include "third_party/skia/include/core/SkTypes.h" 34#include "ui/gl/gl_implementation.h" 35#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 36 37#if defined(OS_MACOSX) 38#include "base/mac/scoped_nsautorelease_pool.h" 39#endif 40 41namespace content { 42 43using blink::WebGLId; 44using blink::WebGraphicsContext3D; 45using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 46 47content::GLHelper::ScalerQuality kQualities[] = { 48 content::GLHelper::SCALER_QUALITY_BEST, 49 content::GLHelper::SCALER_QUALITY_GOOD, 50 content::GLHelper::SCALER_QUALITY_FAST, }; 51 52const char* kQualityNames[] = {"best", "good", "fast", }; 53 54class GLHelperTest : public testing::Test { 55 protected: 56 virtual void SetUp() { 57 WebGraphicsContext3D::Attributes attributes; 58 bool lose_context_when_out_of_memory = false; 59 context_ = 60 WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( 61 attributes, lose_context_when_out_of_memory); 62 context_->InitializeOnCurrentThread(); 63 context_support_ = context_->GetContextSupport(); 64 helper_.reset( 65 new content::GLHelper(context_->GetGLInterface(), context_support_)); 66 helper_scaling_.reset(new content::GLHelperScaling( 67 context_->GetGLInterface(), helper_.get())); 68 } 69 70 virtual void TearDown() { 71 helper_scaling_.reset(NULL); 72 helper_.reset(NULL); 73 context_.reset(NULL); 74 } 75 76 void StartTracing(const std::string& filter) { 77 base::debug::TraceLog::GetInstance()->SetEnabled( 78 base::debug::CategoryFilter(filter), 79 base::debug::TraceLog::RECORDING_MODE, 80 base::debug::TraceOptions( 81 base::debug::RECORD_UNTIL_FULL)); 82 } 83 84 static void TraceDataCB( 85 const base::Callback<void()>& callback, 86 std::string* output, 87 const scoped_refptr<base::RefCountedString>& json_events_str, 88 bool has_more_events) { 89 if (output->size() > 1) { 90 output->append(","); 91 } 92 output->append(json_events_str->data()); 93 if (!has_more_events) { 94 callback.Run(); 95 } 96 } 97 98 // End tracing, return tracing data in a simple map 99 // of event name->counts. 100 void EndTracing(std::map<std::string, int>* event_counts) { 101 std::string json_data = "["; 102 base::debug::TraceLog::GetInstance()->SetDisabled(); 103 base::RunLoop run_loop; 104 base::debug::TraceLog::GetInstance()->Flush( 105 base::Bind(&GLHelperTest::TraceDataCB, 106 run_loop.QuitClosure(), 107 base::Unretained(&json_data))); 108 run_loop.Run(); 109 json_data.append("]"); 110 111 scoped_ptr<base::Value> trace_data(base::JSONReader::Read(json_data)); 112 base::ListValue* list; 113 CHECK(trace_data->GetAsList(&list)); 114 for (size_t i = 0; i < list->GetSize(); i++) { 115 base::Value* item = NULL; 116 if (list->Get(i, &item)) { 117 base::DictionaryValue* dict; 118 CHECK(item->GetAsDictionary(&dict)); 119 std::string name; 120 CHECK(dict->GetString("name", &name)); 121 std::string trace_type; 122 CHECK(dict->GetString("ph", &trace_type)); 123 // Count all except END traces, as they come in BEGIN/END pairs. 124 if (trace_type != "E") 125 (*event_counts)[name]++; 126 VLOG(1) << "trace name: " << name; 127 } 128 } 129 } 130 131 // Bicubic filter kernel function. 132 static float Bicubic(float x) { 133 const float a = -0.5; 134 x = std::abs(x); 135 float x2 = x * x; 136 float x3 = x2 * x; 137 if (x <= 1) { 138 return (a + 2) * x3 - (a + 3) * x2 + 1; 139 } else if (x < 2) { 140 return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; 141 } else { 142 return 0.0f; 143 } 144 } 145 146 // Look up a single channel value. Works for 4-channel and single channel 147 // bitmaps. Clamp x/y. 148 int Channel(SkBitmap* pixels, int x, int y, int c) { 149 if (pixels->bytesPerPixel() == 4) { 150 uint32* data = 151 pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), 152 std::max(0, std::min(y, pixels->height() - 1))); 153 return (*data) >> (c * 8) & 0xff; 154 } else { 155 DCHECK_EQ(pixels->bytesPerPixel(), 1); 156 DCHECK_EQ(c, 0); 157 return *pixels->getAddr8(std::max(0, std::min(x, pixels->width() - 1)), 158 std::max(0, std::min(y, pixels->height() - 1))); 159 } 160 } 161 162 // Set a single channel value. Works for 4-channel and single channel 163 // bitmaps. Clamp x/y. 164 void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { 165 DCHECK_GE(x, 0); 166 DCHECK_GE(y, 0); 167 DCHECK_LT(x, pixels->width()); 168 DCHECK_LT(y, pixels->height()); 169 if (pixels->bytesPerPixel() == 4) { 170 uint32* data = pixels->getAddr32(x, y); 171 v = std::max(0, std::min(v, 255)); 172 *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); 173 } else { 174 DCHECK_EQ(pixels->bytesPerPixel(), 1); 175 DCHECK_EQ(c, 0); 176 uint8* data = pixels->getAddr8(x, y); 177 v = std::max(0, std::min(v, 255)); 178 *data = v; 179 } 180 } 181 182 // Print all the R, G, B or A values from an SkBitmap in a 183 // human-readable format. 184 void PrintChannel(SkBitmap* pixels, int c) { 185 for (int y = 0; y < pixels->height(); y++) { 186 std::string formatted; 187 for (int x = 0; x < pixels->width(); x++) { 188 formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); 189 } 190 LOG(ERROR) << formatted; 191 } 192 } 193 194 // Print out the individual steps of a scaler pipeline. 195 std::string PrintStages( 196 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages) { 197 std::string ret; 198 for (size_t i = 0; i < scaler_stages.size(); i++) { 199 ret.append(base::StringPrintf("%dx%d -> %dx%d ", 200 scaler_stages[i].src_size.width(), 201 scaler_stages[i].src_size.height(), 202 scaler_stages[i].dst_size.width(), 203 scaler_stages[i].dst_size.height())); 204 bool xy_matters = false; 205 switch (scaler_stages[i].shader) { 206 case GLHelperScaling::SHADER_BILINEAR: 207 ret.append("bilinear"); 208 break; 209 case GLHelperScaling::SHADER_BILINEAR2: 210 ret.append("bilinear2"); 211 xy_matters = true; 212 break; 213 case GLHelperScaling::SHADER_BILINEAR3: 214 ret.append("bilinear3"); 215 xy_matters = true; 216 break; 217 case GLHelperScaling::SHADER_BILINEAR4: 218 ret.append("bilinear4"); 219 xy_matters = true; 220 break; 221 case GLHelperScaling::SHADER_BILINEAR2X2: 222 ret.append("bilinear2x2"); 223 break; 224 case GLHelperScaling::SHADER_BICUBIC_UPSCALE: 225 ret.append("bicubic upscale"); 226 xy_matters = true; 227 break; 228 case GLHelperScaling::SHADER_BICUBIC_HALF_1D: 229 ret.append("bicubic 1/2"); 230 xy_matters = true; 231 break; 232 case GLHelperScaling::SHADER_PLANAR: 233 ret.append("planar"); 234 break; 235 case GLHelperScaling::SHADER_YUV_MRT_PASS1: 236 ret.append("rgb2yuv pass 1"); 237 break; 238 case GLHelperScaling::SHADER_YUV_MRT_PASS2: 239 ret.append("rgb2yuv pass 2"); 240 break; 241 } 242 243 if (xy_matters) { 244 if (scaler_stages[i].scale_x) { 245 ret.append(" X"); 246 } else { 247 ret.append(" Y"); 248 } 249 } 250 ret.append("\n"); 251 } 252 return ret; 253 } 254 255 bool CheckScale(double scale, int samples, bool already_scaled) { 256 // 1:1 is valid if there is one sample. 257 if (samples == 1 && scale == 1.0) { 258 return true; 259 } 260 // Is it an exact down-scale (50%, 25%, etc.?) 261 if (scale == 2.0 * samples) { 262 return true; 263 } 264 // Upscales, only valid if we haven't already scaled in this dimension. 265 if (!already_scaled) { 266 // Is it a valid bilinear upscale? 267 if (samples == 1 && scale <= 1.0) { 268 return true; 269 } 270 // Multi-sample upscale-downscale combination? 271 if (scale > samples / 2.0 && scale < samples) { 272 return true; 273 } 274 } 275 return false; 276 } 277 278 // Make sure that the stages of the scaler pipeline are sane. 279 void ValidateScalerStages( 280 content::GLHelper::ScalerQuality quality, 281 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, 282 const gfx::Size& dst_size, 283 const std::string& message) { 284 bool previous_error = HasFailure(); 285 // First, check that the input size for each stage is equal to 286 // the output size of the previous stage. 287 for (size_t i = 1; i < scaler_stages.size(); i++) { 288 EXPECT_EQ(scaler_stages[i - 1].dst_size.width(), 289 scaler_stages[i].src_size.width()); 290 EXPECT_EQ(scaler_stages[i - 1].dst_size.height(), 291 scaler_stages[i].src_size.height()); 292 EXPECT_EQ(scaler_stages[i].src_subrect.x(), 0); 293 EXPECT_EQ(scaler_stages[i].src_subrect.y(), 0); 294 EXPECT_EQ(scaler_stages[i].src_subrect.width(), 295 scaler_stages[i].src_size.width()); 296 EXPECT_EQ(scaler_stages[i].src_subrect.height(), 297 scaler_stages[i].src_size.height()); 298 } 299 300 // Check the output size matches the destination of the last stage 301 EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.width(), 302 dst_size.width()); 303 EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.height(), 304 dst_size.height()); 305 306 // Used to verify that up-scales are not attempted after some 307 // other scale. 308 bool scaled_x = false; 309 bool scaled_y = false; 310 311 for (size_t i = 0; i < scaler_stages.size(); i++) { 312 // Note: 2.0 means scaling down by 50% 313 double x_scale = 314 static_cast<double>(scaler_stages[i].src_subrect.width()) / 315 static_cast<double>(scaler_stages[i].dst_size.width()); 316 double y_scale = 317 static_cast<double>(scaler_stages[i].src_subrect.height()) / 318 static_cast<double>(scaler_stages[i].dst_size.height()); 319 320 int x_samples = 0; 321 int y_samples = 0; 322 323 // Codify valid scale operations. 324 switch (scaler_stages[i].shader) { 325 case GLHelperScaling::SHADER_PLANAR: 326 case GLHelperScaling::SHADER_YUV_MRT_PASS1: 327 case GLHelperScaling::SHADER_YUV_MRT_PASS2: 328 EXPECT_TRUE(false) << "Invalid shader."; 329 break; 330 331 case GLHelperScaling::SHADER_BILINEAR: 332 if (quality != content::GLHelper::SCALER_QUALITY_FAST) { 333 x_samples = 1; 334 y_samples = 1; 335 } 336 break; 337 case GLHelperScaling::SHADER_BILINEAR2: 338 x_samples = 2; 339 y_samples = 1; 340 break; 341 case GLHelperScaling::SHADER_BILINEAR3: 342 x_samples = 3; 343 y_samples = 1; 344 break; 345 case GLHelperScaling::SHADER_BILINEAR4: 346 x_samples = 4; 347 y_samples = 1; 348 break; 349 case GLHelperScaling::SHADER_BILINEAR2X2: 350 x_samples = 2; 351 y_samples = 2; 352 break; 353 case GLHelperScaling::SHADER_BICUBIC_UPSCALE: 354 if (scaler_stages[i].scale_x) { 355 EXPECT_LT(x_scale, 1.0); 356 EXPECT_EQ(y_scale, 1.0); 357 } else { 358 EXPECT_EQ(x_scale, 1.0); 359 EXPECT_LT(y_scale, 1.0); 360 } 361 break; 362 case GLHelperScaling::SHADER_BICUBIC_HALF_1D: 363 if (scaler_stages[i].scale_x) { 364 EXPECT_EQ(x_scale, 2.0); 365 EXPECT_EQ(y_scale, 1.0); 366 } else { 367 EXPECT_EQ(x_scale, 1.0); 368 EXPECT_EQ(y_scale, 2.0); 369 } 370 break; 371 } 372 373 if (!scaler_stages[i].scale_x) { 374 std::swap(x_samples, y_samples); 375 } 376 377 if (x_samples) { 378 EXPECT_TRUE(CheckScale(x_scale, x_samples, scaled_x)) 379 << "x_scale = " << x_scale; 380 } 381 if (y_samples) { 382 EXPECT_TRUE(CheckScale(y_scale, y_samples, scaled_y)) 383 << "y_scale = " << y_scale; 384 } 385 386 if (x_scale != 1.0) { 387 scaled_x = true; 388 } 389 if (y_scale != 1.0) { 390 scaled_y = true; 391 } 392 } 393 394 if (HasFailure() && !previous_error) { 395 LOG(ERROR) << "Invalid scaler stages: " << message; 396 LOG(ERROR) << "Scaler stages:"; 397 LOG(ERROR) << PrintStages(scaler_stages); 398 } 399 } 400 401 // Compares two bitmaps taking color types into account. Checks whether each 402 // component of each pixel is no more than |maxdiff| apart. If bitmaps are not 403 // similar enough, prints out |truth|, |other|, |source|, |scaler_stages| 404 // and |message|. 405 void Compare(SkBitmap* truth, 406 SkBitmap* other, 407 int maxdiff, 408 SkBitmap* source, 409 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, 410 std::string message) { 411 EXPECT_EQ(truth->width(), other->width()); 412 EXPECT_EQ(truth->height(), other->height()); 413 bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType && 414 other->colorType() == kBGRA_8888_SkColorType) || 415 (truth->colorType() == kBGRA_8888_SkColorType && 416 other->colorType() == kRGBA_8888_SkColorType); 417 EXPECT_TRUE(swizzle || truth->colorType() == other->colorType()); 418 int bpp = truth->bytesPerPixel(); 419 for (int x = 0; x < truth->width(); x++) { 420 for (int y = 0; y < truth->height(); y++) { 421 for (int c = 0; c < bpp; c++) { 422 int a = Channel(truth, x, y, c); 423 // swizzle when comparing if needed 424 int b = swizzle && (c == 0 || c == 2) 425 ? Channel(other, x, y, (c + 2) & 2) 426 : Channel(other, x, y, c); 427 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c 428 << " " << message; 429 if (std::abs(a - b) > maxdiff) { 430 LOG(ERROR) << "-------expected--------"; 431 for (int i = 0; i < bpp; i++) { 432 LOG(ERROR) << "Channel " << i << ":"; 433 PrintChannel(truth, i); 434 } 435 LOG(ERROR) << "-------actual--------"; 436 for (int i = 0; i < bpp; i++) { 437 LOG(ERROR) << "Channel " << i << ":"; 438 PrintChannel(other, i); 439 } 440 if (source) { 441 LOG(ERROR) << "-------original--------"; 442 for (int i = 0; i < source->bytesPerPixel(); i++) { 443 LOG(ERROR) << "Channel " << i << ":"; 444 PrintChannel(source, i); 445 } 446 } 447 LOG(ERROR) << "-----Scaler stages------"; 448 LOG(ERROR) << PrintStages(scaler_stages); 449 return; 450 } 451 } 452 } 453 } 454 } 455 456 // Get a single R, G, B or A value as a float. 457 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { 458 return Channel(pixels, x, y, c) / 255.0; 459 } 460 461 // Works like a GL_LINEAR lookup on an SkBitmap. 462 float Bilinear(SkBitmap* pixels, float x, float y, int c) { 463 x -= 0.5; 464 y -= 0.5; 465 int base_x = static_cast<int>(floorf(x)); 466 int base_y = static_cast<int>(floorf(y)); 467 x -= base_x; 468 y -= base_y; 469 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + 470 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + 471 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + 472 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); 473 } 474 475 // Encodes an RGBA bitmap to grayscale. 476 // Reference implementation for 477 // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale. 478 void EncodeToGrayscaleSlow(SkBitmap* input, SkBitmap* output) { 479 const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f}; 480 CHECK_EQ(kAlpha_8_SkColorType, output->colorType()); 481 CHECK_EQ(input->width(), output->width()); 482 CHECK_EQ(input->height(), output->height()); 483 CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType); 484 485 for (int dst_y = 0; dst_y < output->height(); dst_y++) { 486 for (int dst_x = 0; dst_x < output->width(); dst_x++) { 487 float c0 = ChannelAsFloat(input, dst_x, dst_y, 0); 488 float c1 = ChannelAsFloat(input, dst_x, dst_y, 1); 489 float c2 = ChannelAsFloat(input, dst_x, dst_y, 2); 490 float value = c0 * kRGBtoGrayscaleColorWeights[0] + 491 c1 * kRGBtoGrayscaleColorWeights[1] + 492 c2 * kRGBtoGrayscaleColorWeights[2]; 493 SetChannel( 494 output, dst_x, dst_y, 0, static_cast<int>(value * 255.0f + 0.5f)); 495 } 496 } 497 } 498 499 // Very slow bicubic / bilinear scaler for reference. 500 void ScaleSlow(SkBitmap* input, 501 SkBitmap* output, 502 content::GLHelper::ScalerQuality quality) { 503 float xscale = static_cast<float>(input->width()) / output->width(); 504 float yscale = static_cast<float>(input->height()) / output->height(); 505 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; 506 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; 507 for (int dst_y = 0; dst_y < output->height(); dst_y++) { 508 for (int dst_x = 0; dst_x < output->width(); dst_x++) { 509 for (int channel = 0; channel < 4; channel++) { 510 float dst_x_in_src = (dst_x + 0.5f) * xscale; 511 float dst_y_in_src = (dst_y + 0.5f) * yscale; 512 513 float value = 0.0f; 514 float sum = 0.0f; 515 switch (quality) { 516 case content::GLHelper::SCALER_QUALITY_BEST: 517 for (int src_y = -10; src_y < input->height() + 10; ++src_y) { 518 float coeff_y = 519 Bicubic((src_y + 0.5f - dst_y_in_src) * clamped_yscale); 520 if (coeff_y == 0.0f) { 521 continue; 522 } 523 for (int src_x = -10; src_x < input->width() + 10; ++src_x) { 524 float coeff = 525 coeff_y * 526 Bicubic((src_x + 0.5f - dst_x_in_src) * clamped_xscale); 527 if (coeff == 0.0f) { 528 continue; 529 } 530 sum += coeff; 531 float c = ChannelAsFloat(input, src_x, src_y, channel); 532 value += c * coeff; 533 } 534 } 535 break; 536 537 case content::GLHelper::SCALER_QUALITY_GOOD: { 538 int xshift = 0, yshift = 0; 539 while ((output->width() << xshift) < input->width()) { 540 xshift++; 541 } 542 while ((output->height() << yshift) < input->height()) { 543 yshift++; 544 } 545 int xmag = 1 << xshift; 546 int ymag = 1 << yshift; 547 if (xmag == 4 && output->width() * 3 >= input->width()) { 548 xmag = 3; 549 } 550 if (ymag == 4 && output->height() * 3 >= input->height()) { 551 ymag = 3; 552 } 553 for (int x = 0; x < xmag; x++) { 554 for (int y = 0; y < ymag; y++) { 555 value += Bilinear(input, 556 (dst_x * xmag + x + 0.5) * xscale / xmag, 557 (dst_y * ymag + y + 0.5) * yscale / ymag, 558 channel); 559 sum += 1.0; 560 } 561 } 562 break; 563 } 564 565 case content::GLHelper::SCALER_QUALITY_FAST: 566 value = Bilinear(input, dst_x_in_src, dst_y_in_src, channel); 567 sum = 1.0; 568 } 569 value /= sum; 570 SetChannel(output, 571 dst_x, 572 dst_y, 573 channel, 574 static_cast<int>(value * 255.0f + 0.5f)); 575 } 576 } 577 } 578 } 579 580 void FlipSKBitmap(SkBitmap* bitmap) { 581 int bpp = bitmap->bytesPerPixel(); 582 DCHECK(bpp == 4 || bpp == 1); 583 int top_line = 0; 584 int bottom_line = bitmap->height() - 1; 585 while (top_line < bottom_line) { 586 for (int x = 0; x < bitmap->width(); x++) { 587 bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line), 588 *bitmap->getAddr32(x, bottom_line)) 589 : std::swap(*bitmap->getAddr8(x, top_line), 590 *bitmap->getAddr8(x, bottom_line)); 591 } 592 top_line++; 593 bottom_line--; 594 } 595 } 596 597 // Swaps red and blue channels in each pixel in a 32-bit bitmap. 598 void SwizzleSKBitmap(SkBitmap* bitmap) { 599 int bpp = bitmap->bytesPerPixel(); 600 DCHECK(bpp == 4); 601 for (int y = 0; y < bitmap->height(); y++) { 602 for (int x = 0; x < bitmap->width(); x++) { 603 // Swap channels 0 and 2 (red and blue) 604 int c0 = Channel(bitmap, x, y, 0); 605 int c2 = Channel(bitmap, x, y, 2); 606 SetChannel(bitmap, x, y, 2, c0); 607 SetChannel(bitmap, x, y, 0, c2); 608 } 609 } 610 } 611 612 // gl_helper scales recursively, so we'll need to do that 613 // in the reference implementation too. 614 void ScaleSlowRecursive(SkBitmap* input, 615 SkBitmap* output, 616 content::GLHelper::ScalerQuality quality) { 617 if (quality == content::GLHelper::SCALER_QUALITY_FAST || 618 quality == content::GLHelper::SCALER_QUALITY_GOOD) { 619 ScaleSlow(input, output, quality); 620 return; 621 } 622 623 float xscale = static_cast<float>(output->width()) / input->width(); 624 625 // This corresponds to all the operations we can do directly. 626 float yscale = static_cast<float>(output->height()) / input->height(); 627 if ((xscale == 1.0f && yscale == 1.0f) || 628 (xscale == 0.5f && yscale == 1.0f) || 629 (xscale == 1.0f && yscale == 0.5f) || 630 (xscale >= 1.0f && yscale == 1.0f) || 631 (xscale == 1.0f && yscale >= 1.0f)) { 632 ScaleSlow(input, output, quality); 633 return; 634 } 635 636 // Now we break the problem down into smaller pieces, using the 637 // operations available. 638 int xtmp = input->width(); 639 int ytmp = input->height(); 640 641 if (output->height() != input->height()) { 642 ytmp = output->height(); 643 while (ytmp < input->height() && ytmp * 2 != input->height()) { 644 ytmp += ytmp; 645 } 646 } else { 647 xtmp = output->width(); 648 while (xtmp < input->width() && xtmp * 2 != input->width()) { 649 xtmp += xtmp; 650 } 651 } 652 653 SkBitmap tmp; 654 tmp.allocN32Pixels(xtmp, ytmp); 655 656 ScaleSlowRecursive(input, &tmp, quality); 657 ScaleSlowRecursive(&tmp, output, quality); 658 } 659 660 // Creates an RGBA SkBitmap 661 scoped_ptr<SkBitmap> CreateTestBitmap(int width, 662 int height, 663 int test_pattern) { 664 scoped_ptr<SkBitmap> bitmap(new SkBitmap); 665 bitmap->allocPixels(SkImageInfo::Make( 666 width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); 667 668 for (int x = 0; x < width; ++x) { 669 for (int y = 0; y < height; ++y) { 670 switch (test_pattern) { 671 case 0: // Smooth test pattern 672 SetChannel(bitmap.get(), x, y, 0, x * 10); 673 SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10); 674 SetChannel(bitmap.get(), x, y, 1, y * 10); 675 SetChannel(bitmap.get(), x, y, 2, (x + y) * 10); 676 SetChannel(bitmap.get(), x, y, 3, 255); 677 break; 678 case 1: // Small blocks 679 SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0); 680 SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0); 681 SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0); 682 SetChannel(bitmap.get(), x, y, 3, 255); 683 break; 684 case 2: // Medium blocks 685 SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50); 686 SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50); 687 SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5); 688 SetChannel(bitmap.get(), x, y, 3, 255); 689 break; 690 } 691 } 692 } 693 return bitmap.Pass(); 694 } 695 696 // Binds texture and framebuffer and loads the bitmap pixels into the texture. 697 void BindTextureAndFrameBuffer(WebGLId texture, 698 WebGLId framebuffer, 699 SkBitmap* bitmap, 700 int width, 701 int height) { 702 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); 703 context_->bindTexture(GL_TEXTURE_2D, texture); 704 context_->texImage2D(GL_TEXTURE_2D, 705 0, 706 GL_RGBA, 707 width, 708 height, 709 0, 710 GL_RGBA, 711 GL_UNSIGNED_BYTE, 712 bitmap->getPixels()); 713 } 714 715 // Create a test image, transform it using 716 // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation 717 // and compare the results. 718 void TestCropScaleReadbackAndCleanTexture(int xsize, 719 int ysize, 720 int scaled_xsize, 721 int scaled_ysize, 722 int test_pattern, 723 SkColorType out_color_type, 724 bool swizzle, 725 size_t quality_index) { 726 DCHECK(out_color_type == kAlpha_8_SkColorType || 727 out_color_type == kRGBA_8888_SkColorType || 728 out_color_type == kBGRA_8888_SkColorType); 729 WebGLId src_texture = context_->createTexture(); 730 WebGLId framebuffer = context_->createFramebuffer(); 731 scoped_ptr<SkBitmap> input_pixels = 732 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); 733 BindTextureAndFrameBuffer( 734 src_texture, framebuffer, input_pixels.get(), xsize, ysize); 735 736 std::string message = base::StringPrintf( 737 "input size: %dx%d " 738 "output size: %dx%d " 739 "pattern: %d , quality: %s, " 740 "out_color_type: %d", 741 xsize, 742 ysize, 743 scaled_xsize, 744 scaled_ysize, 745 test_pattern, 746 kQualityNames[quality_index], 747 out_color_type); 748 749 // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture. 750 SkBitmap output_pixels; 751 output_pixels.allocPixels(SkImageInfo::Make( 752 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); 753 base::RunLoop run_loop; 754 gfx::Size encoded_texture_size; 755 helper_->CropScaleReadbackAndCleanTexture( 756 src_texture, 757 gfx::Size(xsize, ysize), 758 gfx::Rect(xsize, ysize), 759 gfx::Size(scaled_xsize, scaled_ysize), 760 static_cast<unsigned char*>(output_pixels.getPixels()), 761 out_color_type, 762 base::Bind(&callcallback, run_loop.QuitClosure()), 763 kQualities[quality_index]); 764 run_loop.Run(); 765 // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back. 766 FlipSKBitmap(&output_pixels); 767 768 // If the bitmap shouldn't have changed - compare against input. 769 if (xsize == scaled_xsize && ysize == scaled_ysize && 770 out_color_type != kAlpha_8_SkColorType) { 771 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; 772 Compare(input_pixels.get(), 773 &output_pixels, 774 0, 775 NULL, 776 dummy_stages, 777 message + " comparing against input"); 778 return; 779 } 780 781 // Now transform the bitmap using the reference implementation. 782 SkBitmap scaled_pixels; 783 scaled_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, 784 scaled_ysize, 785 kRGBA_8888_SkColorType, 786 kPremul_SkAlphaType)); 787 SkBitmap truth_pixels; 788 // Step 1: Scale 789 ScaleSlowRecursive( 790 input_pixels.get(), &scaled_pixels, kQualities[quality_index]); 791 // Step 2: Encode to grayscale if needed. 792 if (out_color_type == kAlpha_8_SkColorType) { 793 truth_pixels.allocPixels(SkImageInfo::Make( 794 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); 795 EncodeToGrayscaleSlow(&scaled_pixels, &truth_pixels); 796 } else { 797 truth_pixels = scaled_pixels; 798 } 799 800 // Now compare the results. 801 SkAutoLockPixels lock_input(truth_pixels); 802 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; 803 Compare(&truth_pixels, 804 &output_pixels, 805 2, 806 input_pixels.get(), 807 dummy_stages, 808 message + " comparing against transformed/scaled"); 809 810 context_->deleteTexture(src_texture); 811 context_->deleteFramebuffer(framebuffer); 812 } 813 814 // Scaling test: Create a test image, scale it using GLHelperScaling 815 // and a reference implementation and compare the results. 816 void TestScale(int xsize, 817 int ysize, 818 int scaled_xsize, 819 int scaled_ysize, 820 int test_pattern, 821 size_t quality_index, 822 bool flip) { 823 WebGLId src_texture = context_->createTexture(); 824 WebGLId framebuffer = context_->createFramebuffer(); 825 scoped_ptr<SkBitmap> input_pixels = 826 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); 827 BindTextureAndFrameBuffer( 828 src_texture, framebuffer, input_pixels.get(), xsize, ysize); 829 830 std::string message = base::StringPrintf( 831 "input size: %dx%d " 832 "output size: %dx%d " 833 "pattern: %d quality: %s", 834 xsize, 835 ysize, 836 scaled_xsize, 837 scaled_ysize, 838 test_pattern, 839 kQualityNames[quality_index]); 840 841 std::vector<GLHelperScaling::ScalerStage> stages; 842 helper_scaling_->ComputeScalerStages(kQualities[quality_index], 843 gfx::Size(xsize, ysize), 844 gfx::Rect(0, 0, xsize, ysize), 845 gfx::Size(scaled_xsize, scaled_ysize), 846 flip, 847 false, 848 &stages); 849 ValidateScalerStages(kQualities[quality_index], 850 stages, 851 gfx::Size(scaled_xsize, scaled_ysize), 852 message); 853 854 WebGLId dst_texture = 855 helper_->CopyAndScaleTexture(src_texture, 856 gfx::Size(xsize, ysize), 857 gfx::Size(scaled_xsize, scaled_ysize), 858 flip, 859 kQualities[quality_index]); 860 861 SkBitmap output_pixels; 862 output_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, 863 scaled_ysize, 864 kRGBA_8888_SkColorType, 865 kPremul_SkAlphaType)); 866 867 helper_->ReadbackTextureSync( 868 dst_texture, 869 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), 870 static_cast<unsigned char*>(output_pixels.getPixels()), 871 kRGBA_8888_SkColorType); 872 if (flip) { 873 // Flip the pixels back. 874 FlipSKBitmap(&output_pixels); 875 } 876 877 // If the bitmap shouldn't have changed - compare against input. 878 if (xsize == scaled_xsize && ysize == scaled_ysize) { 879 Compare(input_pixels.get(), 880 &output_pixels, 881 0, 882 NULL, 883 stages, 884 message + " comparing against input"); 885 return; 886 } 887 888 // Now scale the bitmap using the reference implementation. 889 SkBitmap truth_pixels; 890 truth_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, 891 scaled_ysize, 892 kRGBA_8888_SkColorType, 893 kPremul_SkAlphaType)); 894 ScaleSlowRecursive( 895 input_pixels.get(), &truth_pixels, kQualities[quality_index]); 896 Compare(&truth_pixels, 897 &output_pixels, 898 2, 899 input_pixels.get(), 900 stages, 901 message + " comparing against scaled"); 902 903 context_->deleteTexture(src_texture); 904 context_->deleteTexture(dst_texture); 905 context_->deleteFramebuffer(framebuffer); 906 } 907 908 // Create a scaling pipeline and check that it is made up of 909 // valid scaling operations. 910 void TestScalerPipeline(size_t quality, 911 int xsize, 912 int ysize, 913 int dst_xsize, 914 int dst_ysize) { 915 std::vector<GLHelperScaling::ScalerStage> stages; 916 helper_scaling_->ComputeScalerStages(kQualities[quality], 917 gfx::Size(xsize, ysize), 918 gfx::Rect(0, 0, xsize, ysize), 919 gfx::Size(dst_xsize, dst_ysize), 920 false, 921 false, 922 &stages); 923 ValidateScalerStages(kQualities[quality], 924 stages, 925 gfx::Size(dst_xsize, dst_ysize), 926 base::StringPrintf( 927 "input size: %dx%d " 928 "output size: %dx%d " 929 "quality: %s", 930 xsize, 931 ysize, 932 dst_xsize, 933 dst_ysize, 934 kQualityNames[quality])); 935 } 936 937 // Create a scaling pipeline and make sure that the steps 938 // are exactly the steps we expect. 939 void CheckPipeline(content::GLHelper::ScalerQuality quality, 940 int xsize, 941 int ysize, 942 int dst_xsize, 943 int dst_ysize, 944 const std::string& description) { 945 std::vector<GLHelperScaling::ScalerStage> stages; 946 helper_scaling_->ComputeScalerStages(quality, 947 gfx::Size(xsize, ysize), 948 gfx::Rect(0, 0, xsize, ysize), 949 gfx::Size(dst_xsize, dst_ysize), 950 false, 951 false, 952 &stages); 953 ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, 954 stages, 955 gfx::Size(dst_xsize, dst_ysize), 956 ""); 957 EXPECT_EQ(PrintStages(stages), description); 958 } 959 960 // Note: Left/Right means Top/Bottom when used for Y dimension. 961 enum Margin { 962 MarginLeft, 963 MarginMiddle, 964 MarginRight, 965 MarginInvalid, 966 }; 967 968 static Margin NextMargin(Margin m) { 969 switch (m) { 970 case MarginLeft: 971 return MarginMiddle; 972 case MarginMiddle: 973 return MarginRight; 974 case MarginRight: 975 return MarginInvalid; 976 default: 977 return MarginInvalid; 978 } 979 } 980 981 int compute_margin(int insize, int outsize, Margin m) { 982 int available = outsize - insize; 983 switch (m) { 984 default: 985 EXPECT_TRUE(false) << "This should not happen."; 986 return 0; 987 case MarginLeft: 988 return 0; 989 case MarginMiddle: 990 return (available / 2) & ~1; 991 case MarginRight: 992 return available; 993 } 994 } 995 996 // Convert 0.0 - 1.0 to 0 - 255 997 int float_to_byte(float v) { 998 int ret = static_cast<int>(floorf(v * 255.0f + 0.5f)); 999 if (ret < 0) { 1000 return 0; 1001 } 1002 if (ret > 255) { 1003 return 255; 1004 } 1005 return ret; 1006 } 1007 1008 static void callcallback(const base::Callback<void()>& callback, 1009 bool result) { 1010 callback.Run(); 1011 } 1012 1013 void PrintPlane(unsigned char* plane, int xsize, int stride, int ysize) { 1014 for (int y = 0; y < ysize; y++) { 1015 std::string formatted; 1016 for (int x = 0; x < xsize; x++) { 1017 formatted.append(base::StringPrintf("%3d, ", plane[y * stride + x])); 1018 } 1019 LOG(ERROR) << formatted << " (" << (plane + y * stride) << ")"; 1020 } 1021 } 1022 1023 // Compare two planes make sure that each component of each pixel 1024 // is no more than |maxdiff| apart. 1025 void ComparePlane(unsigned char* truth, 1026 unsigned char* other, 1027 int maxdiff, 1028 int xsize, 1029 int stride, 1030 int ysize, 1031 SkBitmap* source, 1032 std::string message) { 1033 int truth_stride = stride; 1034 for (int x = 0; x < xsize; x++) { 1035 for (int y = 0; y < ysize; y++) { 1036 int a = other[y * stride + x]; 1037 int b = truth[y * stride + x]; 1038 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " " 1039 << message; 1040 if (std::abs(a - b) > maxdiff) { 1041 LOG(ERROR) << "-------expected--------"; 1042 PrintPlane(truth, xsize, truth_stride, ysize); 1043 LOG(ERROR) << "-------actual--------"; 1044 PrintPlane(other, xsize, stride, ysize); 1045 if (source) { 1046 LOG(ERROR) << "-------before yuv conversion: red--------"; 1047 PrintChannel(source, 0); 1048 LOG(ERROR) << "-------before yuv conversion: green------"; 1049 PrintChannel(source, 1); 1050 LOG(ERROR) << "-------before yuv conversion: blue-------"; 1051 PrintChannel(source, 2); 1052 } 1053 return; 1054 } 1055 } 1056 } 1057 } 1058 1059 void DrawGridToBitmap(int w, int h, 1060 SkColor background_color, 1061 SkColor grid_color, 1062 int grid_pitch, 1063 int grid_width, 1064 SkBitmap& bmp) { 1065 ASSERT_GT(grid_pitch, 0); 1066 ASSERT_GT(grid_width, 0); 1067 ASSERT_NE(background_color, grid_color); 1068 1069 for (int y = 0; y < h; ++y) { 1070 bool y_on_grid = ((y % grid_pitch) < grid_width); 1071 1072 for (int x = 0; x < w; ++x) { 1073 bool on_grid = (y_on_grid || ((x % grid_pitch) < grid_width)); 1074 1075 if (bmp.colorType() == kRGBA_8888_SkColorType || 1076 bmp.colorType() == kBGRA_8888_SkColorType) { 1077 *bmp.getAddr32(x, y) = (on_grid ? grid_color : background_color); 1078 } else if (bmp.colorType() == kRGB_565_SkColorType) { 1079 *bmp.getAddr16(x, y) = (on_grid ? grid_color : background_color); 1080 } 1081 } 1082 } 1083 } 1084 1085 void DrawCheckerToBitmap(int w, int h, 1086 SkColor color1, SkColor color2, 1087 int rect_w, int rect_h, 1088 SkBitmap& bmp) { 1089 ASSERT_GT(rect_w, 0); 1090 ASSERT_GT(rect_h, 0); 1091 ASSERT_NE(color1, color2); 1092 1093 for (int y = 0; y < h; ++y) { 1094 bool y_bit = (((y / rect_h) & 0x1) == 0); 1095 1096 for (int x = 0; x < w; ++x) { 1097 bool x_bit = (((x / rect_w) & 0x1) == 0); 1098 1099 bool use_color2 = (x_bit != y_bit); // xor 1100 if (bmp.colorType() == kRGBA_8888_SkColorType || 1101 bmp.colorType() == kBGRA_8888_SkColorType) { 1102 *bmp.getAddr32(x, y) = (use_color2 ? color2 : color1); 1103 } else if (bmp.colorType() == kRGB_565_SkColorType) { 1104 *bmp.getAddr16(x, y) = (use_color2 ? color2 : color1); 1105 } 1106 } 1107 } 1108 } 1109 1110 bool ColorComponentsClose(SkColor component1, 1111 SkColor component2, 1112 SkColorType color_type) { 1113 int c1 = static_cast<int>(component1); 1114 int c2 = static_cast<int>(component2); 1115 bool result = false; 1116 switch (color_type) { 1117 case kRGBA_8888_SkColorType: 1118 case kBGRA_8888_SkColorType: 1119 result = (std::abs(c1 - c2) == 0); 1120 break; 1121 case kRGB_565_SkColorType: 1122 result = (std::abs(c1 - c2) <= 7); 1123 break; 1124 default: 1125 break; 1126 } 1127 return result; 1128 } 1129 1130 bool ColorsClose(SkColor color1, SkColor color2, SkColorType color_type) { 1131 bool red = ColorComponentsClose(SkColorGetR(color1), 1132 SkColorGetR(color2), color_type); 1133 bool green = ColorComponentsClose(SkColorGetG(color1), 1134 SkColorGetG(color2), color_type); 1135 bool blue = ColorComponentsClose(SkColorGetB(color1), 1136 SkColorGetB(color2), color_type); 1137 bool alpha = ColorComponentsClose(SkColorGetA(color1), 1138 SkColorGetA(color2), color_type); 1139 if (color_type == kRGB_565_SkColorType) { 1140 return red && blue && green; 1141 } 1142 return red && blue && green && alpha; 1143 } 1144 1145 bool IsEqual(const SkBitmap& bmp1, const SkBitmap& bmp2) { 1146 if (bmp1.isNull() && bmp2.isNull()) 1147 return true; 1148 if (bmp1.width() != bmp2.width() || 1149 bmp1.height() != bmp2.height()) { 1150 LOG(ERROR) << "Bitmap geometry check failure"; 1151 return false; 1152 } 1153 if (bmp1.colorType() != bmp2.colorType()) 1154 return false; 1155 1156 SkAutoLockPixels lock1(bmp1); 1157 SkAutoLockPixels lock2(bmp2); 1158 if (!bmp1.getPixels() || !bmp2.getPixels()) { 1159 LOG(ERROR) << "Empty Bitmap!"; 1160 return false; 1161 } 1162 for (int y = 0; y < bmp1.height(); ++y) { 1163 for (int x = 0; x < bmp1.width(); ++x) { 1164 if (!ColorsClose(bmp1.getColor(x,y), 1165 bmp2.getColor(x,y), 1166 bmp1.colorType())) { 1167 LOG(ERROR) << "Bitmap color comparision failure"; 1168 return false; 1169 } 1170 } 1171 } 1172 return true; 1173 } 1174 1175 void BindAndAttachTextureWithPixels(GLuint src_texture, 1176 SkColorType color_type, 1177 const gfx::Size& src_size, 1178 const SkBitmap& input_pixels) { 1179 context_->bindTexture(GL_TEXTURE_2D, src_texture); 1180 GLenum format = 0; 1181 switch (color_type) { 1182 case kBGRA_8888_SkColorType: 1183 format = GL_BGRA_EXT; 1184 break; 1185 case kRGBA_8888_SkColorType: 1186 format = GL_RGBA; 1187 break; 1188 case kRGB_565_SkColorType: 1189 format = GL_RGB; 1190 break; 1191 default: 1192 NOTREACHED(); 1193 } 1194 GLenum type = (color_type == kRGB_565_SkColorType) ? 1195 GL_UNSIGNED_SHORT_5_6_5 : GL_UNSIGNED_BYTE; 1196 context_->texImage2D(GL_TEXTURE_2D, 1197 0, 1198 format, 1199 src_size.width(), 1200 src_size.height(), 1201 0, 1202 format, 1203 type, 1204 input_pixels.getPixels()); 1205 } 1206 1207 void ReadBackTexture(GLuint src_texture, 1208 const gfx::Size& src_size, 1209 unsigned char* pixels, 1210 SkColorType color_type, 1211 bool async) { 1212 if (async) { 1213 base::RunLoop run_loop; 1214 helper_->ReadbackTextureAsync(src_texture, 1215 src_size, 1216 pixels, 1217 color_type, 1218 base::Bind(&callcallback, 1219 run_loop.QuitClosure())); 1220 run_loop.Run(); 1221 } else { 1222 helper_->ReadbackTextureSync(src_texture, 1223 gfx::Rect(src_size), 1224 pixels, 1225 color_type); 1226 } 1227 } 1228 // Test basic format readback. 1229 bool TestTextureFormatReadback(const gfx::Size& src_size, 1230 SkColorType color_type, 1231 bool async) { 1232 SkImageInfo info = 1233 SkImageInfo::Make(src_size.width(), 1234 src_size.height(), 1235 color_type, 1236 kPremul_SkAlphaType); 1237 if (!helper_->IsReadbackConfigSupported(color_type)) { 1238 LOG(INFO) << "Skipping test format not supported" << color_type; 1239 return true; 1240 } 1241 WebGLId src_texture = context_->createTexture(); 1242 SkBitmap input_pixels; 1243 input_pixels.allocPixels(info); 1244 // Test Pattern-1, Fill with Plain color pattern. 1245 // Erase the input bitmap with red color. 1246 input_pixels.eraseColor(SK_ColorRED); 1247 BindAndAttachTextureWithPixels(src_texture, 1248 color_type, 1249 src_size, 1250 input_pixels); 1251 SkBitmap output_pixels; 1252 output_pixels.allocPixels(info); 1253 // Initialize the output bitmap with Green color. 1254 // When the readback is over output bitmap should have the red color. 1255 output_pixels.eraseColor(SK_ColorGREEN); 1256 uint8* pixels = static_cast<uint8*>(output_pixels.getPixels()); 1257 ReadBackTexture(src_texture, src_size, pixels, color_type, async); 1258 bool result = IsEqual(input_pixels, output_pixels); 1259 if (!result) { 1260 LOG(ERROR) << "Bitmap comparision failure Pattern-1"; 1261 return false; 1262 } 1263 const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4; 1264 const SkColor color1 = SK_ColorRED, color2 = SK_ColorBLUE; 1265 // Test Pattern-2, Fill with Grid Pattern. 1266 DrawGridToBitmap(src_size.width(), src_size.height(), 1267 color2, color1, 1268 src_grid_pitch, src_grid_width, 1269 input_pixels); 1270 BindAndAttachTextureWithPixels(src_texture, 1271 color_type, 1272 src_size, 1273 input_pixels); 1274 ReadBackTexture(src_texture, src_size, pixels, color_type, async); 1275 result = IsEqual(input_pixels, output_pixels); 1276 if (!result) { 1277 LOG(ERROR) << "Bitmap comparision failure Pattern-2"; 1278 return false; 1279 } 1280 // Test Pattern-3, Fill with CheckerBoard Pattern. 1281 DrawCheckerToBitmap(src_size.width(), 1282 src_size.height(), 1283 color1, 1284 color2, rect_w, rect_h, input_pixels); 1285 BindAndAttachTextureWithPixels(src_texture, 1286 color_type, 1287 src_size, 1288 input_pixels); 1289 ReadBackTexture(src_texture, src_size, pixels, color_type, async); 1290 result = IsEqual(input_pixels, output_pixels); 1291 if (!result) { 1292 LOG(ERROR) << "Bitmap comparision failure Pattern-3"; 1293 return false; 1294 } 1295 context_->deleteTexture(src_texture); 1296 if (HasFailure()) { 1297 return false; 1298 } 1299 return true; 1300 } 1301 1302 // YUV readback test. Create a test pattern, convert to YUV 1303 // with reference implementation and compare to what gl_helper 1304 // returns. 1305 void TestYUVReadback(int xsize, 1306 int ysize, 1307 int output_xsize, 1308 int output_ysize, 1309 int xmargin, 1310 int ymargin, 1311 int test_pattern, 1312 bool flip, 1313 bool use_mrt, 1314 content::GLHelper::ScalerQuality quality) { 1315 WebGLId src_texture = context_->createTexture(); 1316 SkBitmap input_pixels; 1317 input_pixels.allocN32Pixels(xsize, ysize); 1318 1319 for (int x = 0; x < xsize; ++x) { 1320 for (int y = 0; y < ysize; ++y) { 1321 switch (test_pattern) { 1322 case 0: // Smooth test pattern 1323 SetChannel(&input_pixels, x, y, 0, x * 10); 1324 SetChannel(&input_pixels, x, y, 1, y * 10); 1325 SetChannel(&input_pixels, x, y, 2, (x + y) * 10); 1326 SetChannel(&input_pixels, x, y, 3, 255); 1327 break; 1328 case 1: // Small blocks 1329 SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0); 1330 SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0); 1331 SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0); 1332 SetChannel(&input_pixels, x, y, 3, 255); 1333 break; 1334 case 2: // Medium blocks 1335 SetChannel(&input_pixels, x, y, 0, 10 + x / 2 * 50); 1336 SetChannel(&input_pixels, x, y, 1, 10 + y / 3 * 50); 1337 SetChannel(&input_pixels, x, y, 2, (x + y) / 5 * 50 + 5); 1338 SetChannel(&input_pixels, x, y, 3, 255); 1339 break; 1340 } 1341 } 1342 } 1343 1344 context_->bindTexture(GL_TEXTURE_2D, src_texture); 1345 context_->texImage2D(GL_TEXTURE_2D, 1346 0, 1347 GL_RGBA, 1348 xsize, 1349 ysize, 1350 0, 1351 GL_RGBA, 1352 GL_UNSIGNED_BYTE, 1353 input_pixels.getPixels()); 1354 1355 gpu::Mailbox mailbox; 1356 context_->genMailboxCHROMIUM(mailbox.name); 1357 EXPECT_FALSE(mailbox.IsZero()); 1358 context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 1359 uint32 sync_point = context_->insertSyncPoint(); 1360 1361 std::string message = base::StringPrintf( 1362 "input size: %dx%d " 1363 "output size: %dx%d " 1364 "margin: %dx%d " 1365 "pattern: %d %s %s", 1366 xsize, 1367 ysize, 1368 output_xsize, 1369 output_ysize, 1370 xmargin, 1371 ymargin, 1372 test_pattern, 1373 flip ? "flip" : "noflip", 1374 flip ? "mrt" : "nomrt"); 1375 scoped_ptr<ReadbackYUVInterface> yuv_reader( 1376 helper_->CreateReadbackPipelineYUV( 1377 quality, 1378 gfx::Size(xsize, ysize), 1379 gfx::Rect(0, 0, xsize, ysize), 1380 gfx::Size(output_xsize, output_ysize), 1381 gfx::Rect(xmargin, ymargin, xsize, ysize), 1382 flip, 1383 use_mrt)); 1384 1385 scoped_refptr<media::VideoFrame> output_frame = 1386 media::VideoFrame::CreateFrame( 1387 media::VideoFrame::YV12, 1388 gfx::Size(output_xsize, output_ysize), 1389 gfx::Rect(0, 0, output_xsize, output_ysize), 1390 gfx::Size(output_xsize, output_ysize), 1391 base::TimeDelta::FromSeconds(0)); 1392 scoped_refptr<media::VideoFrame> truth_frame = 1393 media::VideoFrame::CreateFrame( 1394 media::VideoFrame::YV12, 1395 gfx::Size(output_xsize, output_ysize), 1396 gfx::Rect(0, 0, output_xsize, output_ysize), 1397 gfx::Size(output_xsize, output_ysize), 1398 base::TimeDelta::FromSeconds(0)); 1399 1400 base::RunLoop run_loop; 1401 yuv_reader->ReadbackYUV(mailbox, 1402 sync_point, 1403 output_frame.get(), 1404 base::Bind(&callcallback, run_loop.QuitClosure())); 1405 run_loop.Run(); 1406 1407 if (flip) { 1408 FlipSKBitmap(&input_pixels); 1409 } 1410 1411 unsigned char* Y = truth_frame->data(media::VideoFrame::kYPlane); 1412 unsigned char* U = truth_frame->data(media::VideoFrame::kUPlane); 1413 unsigned char* V = truth_frame->data(media::VideoFrame::kVPlane); 1414 int32 y_stride = truth_frame->stride(media::VideoFrame::kYPlane); 1415 int32 u_stride = truth_frame->stride(media::VideoFrame::kUPlane); 1416 int32 v_stride = truth_frame->stride(media::VideoFrame::kVPlane); 1417 memset(Y, 0x00, y_stride * output_ysize); 1418 memset(U, 0x80, u_stride * output_ysize / 2); 1419 memset(V, 0x80, v_stride * output_ysize / 2); 1420 1421 const float kRGBtoYColorWeights[] = {0.257f, 0.504f, 0.098f, 0.0625f}; 1422 const float kRGBtoUColorWeights[] = {-0.148f, -0.291f, 0.439f, 0.5f}; 1423 const float kRGBtoVColorWeights[] = {0.439f, -0.368f, -0.071f, 0.5f}; 1424 1425 for (int y = 0; y < ysize; y++) { 1426 for (int x = 0; x < xsize; x++) { 1427 Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte( 1428 ChannelAsFloat(&input_pixels, x, y, 0) * kRGBtoYColorWeights[0] + 1429 ChannelAsFloat(&input_pixels, x, y, 1) * kRGBtoYColorWeights[1] + 1430 ChannelAsFloat(&input_pixels, x, y, 2) * kRGBtoYColorWeights[2] + 1431 kRGBtoYColorWeights[3]); 1432 } 1433 } 1434 1435 for (int y = 0; y < ysize / 2; y++) { 1436 for (int x = 0; x < xsize / 2; x++) { 1437 U[(y + ymargin / 2) * u_stride + x + xmargin / 2] = 1438 float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * 1439 kRGBtoUColorWeights[0] + 1440 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * 1441 kRGBtoUColorWeights[1] + 1442 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * 1443 kRGBtoUColorWeights[2] + 1444 kRGBtoUColorWeights[3]); 1445 V[(y + ymargin / 2) * v_stride + x + xmargin / 2] = 1446 float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * 1447 kRGBtoVColorWeights[0] + 1448 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * 1449 kRGBtoVColorWeights[1] + 1450 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * 1451 kRGBtoVColorWeights[2] + 1452 kRGBtoVColorWeights[3]); 1453 } 1454 } 1455 1456 ComparePlane(Y, 1457 output_frame->data(media::VideoFrame::kYPlane), 1458 2, 1459 output_xsize, 1460 y_stride, 1461 output_ysize, 1462 &input_pixels, 1463 message + " Y plane"); 1464 ComparePlane(U, 1465 output_frame->data(media::VideoFrame::kUPlane), 1466 2, 1467 output_xsize / 2, 1468 u_stride, 1469 output_ysize / 2, 1470 &input_pixels, 1471 message + " U plane"); 1472 ComparePlane(V, 1473 output_frame->data(media::VideoFrame::kVPlane), 1474 2, 1475 output_xsize / 2, 1476 v_stride, 1477 output_ysize / 2, 1478 &input_pixels, 1479 message + " V plane"); 1480 1481 context_->deleteTexture(src_texture); 1482 } 1483 1484 void TestAddOps(int src, int dst, bool scale_x, bool allow3) { 1485 std::deque<GLHelperScaling::ScaleOp> ops; 1486 GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops); 1487 // Scale factor 3 is a special case. 1488 // It is currently only allowed by itself. 1489 if (allow3 && dst * 3 >= src && dst * 2 < src) { 1490 EXPECT_EQ(ops[0].scale_factor, 3); 1491 EXPECT_EQ(ops.size(), 1U); 1492 EXPECT_EQ(ops[0].scale_x, scale_x); 1493 EXPECT_EQ(ops[0].scale_size, dst); 1494 return; 1495 } 1496 1497 for (size_t i = 0; i < ops.size(); i++) { 1498 EXPECT_EQ(ops[i].scale_x, scale_x); 1499 if (i == 0) { 1500 // Only the first op is allowed to be a scale up. 1501 // (Scaling up *after* scaling down would make it fuzzy.) 1502 EXPECT_TRUE(ops[0].scale_factor == 0 || ops[0].scale_factor == 2); 1503 } else { 1504 // All other operations must be 50% downscales. 1505 EXPECT_EQ(ops[i].scale_factor, 2); 1506 } 1507 } 1508 // Check that the scale factors make sense and add up. 1509 int tmp = dst; 1510 for (int i = static_cast<int>(ops.size() - 1); i >= 0; i--) { 1511 EXPECT_EQ(tmp, ops[i].scale_size); 1512 if (ops[i].scale_factor == 0) { 1513 EXPECT_EQ(i, 0); 1514 EXPECT_GT(tmp, src); 1515 tmp = src; 1516 } else { 1517 tmp *= ops[i].scale_factor; 1518 } 1519 } 1520 EXPECT_EQ(tmp, src); 1521 } 1522 1523 void CheckPipeline2(int xsize, 1524 int ysize, 1525 int dst_xsize, 1526 int dst_ysize, 1527 const std::string& description) { 1528 std::vector<GLHelperScaling::ScalerStage> stages; 1529 helper_scaling_->ConvertScalerOpsToScalerStages( 1530 content::GLHelper::SCALER_QUALITY_GOOD, 1531 gfx::Size(xsize, ysize), 1532 gfx::Rect(0, 0, xsize, ysize), 1533 gfx::Size(dst_xsize, dst_ysize), 1534 false, 1535 false, 1536 &x_ops_, 1537 &y_ops_, 1538 &stages); 1539 EXPECT_EQ(x_ops_.size(), 0U); 1540 EXPECT_EQ(y_ops_.size(), 0U); 1541 ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, 1542 stages, 1543 gfx::Size(dst_xsize, dst_ysize), 1544 ""); 1545 EXPECT_EQ(PrintStages(stages), description); 1546 } 1547 1548 void CheckOptimizationsTest() { 1549 // Basic upscale. X and Y should be combined into one pass. 1550 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000)); 1551 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000)); 1552 CheckPipeline2(1024, 768, 2000, 2000, "1024x768 -> 2000x2000 bilinear\n"); 1553 1554 // X scaled 1/2, Y upscaled, should still be one pass. 1555 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512)); 1556 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000)); 1557 CheckPipeline2(1024, 768, 512, 2000, "1024x768 -> 512x2000 bilinear\n"); 1558 1559 // X upscaled, Y scaled 1/2, one bilinear pass 1560 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000)); 1561 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384)); 1562 CheckPipeline2(1024, 768, 2000, 384, "1024x768 -> 2000x384 bilinear\n"); 1563 1564 // X scaled 1/2, Y scaled 1/2, one bilinear pass 1565 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512)); 1566 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384)); 1567 CheckPipeline2(1024, 768, 512, 384, "1024x768 -> 512x384 bilinear\n"); 1568 1569 // X scaled 1/2, Y scaled to 60%, one bilinear2 pass. 1570 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50)); 1571 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1572 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1573 CheckPipeline2(100, 100, 50, 60, "100x100 -> 50x60 bilinear2 Y\n"); 1574 1575 // X scaled to 60%, Y scaled 1/2, one bilinear2 pass. 1576 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); 1577 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); 1578 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 50)); 1579 CheckPipeline2(100, 100, 60, 50, "100x100 -> 60x50 bilinear2 X\n"); 1580 1581 // X scaled to 60%, Y scaled 60%, one bilinear2x2 pass. 1582 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); 1583 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); 1584 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1585 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1586 CheckPipeline2(100, 100, 60, 60, "100x100 -> 60x60 bilinear2x2\n"); 1587 1588 // X scaled to 40%, Y scaled 40%, two bilinear3 passes. 1589 x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40)); 1590 y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40)); 1591 CheckPipeline2(100, 1592 100, 1593 40, 1594 40, 1595 "100x100 -> 100x40 bilinear3 Y\n" 1596 "100x40 -> 40x40 bilinear3 X\n"); 1597 1598 // X scaled to 60%, Y scaled 40% 1599 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); 1600 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); 1601 y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40)); 1602 CheckPipeline2(100, 1603 100, 1604 60, 1605 40, 1606 "100x100 -> 100x40 bilinear3 Y\n" 1607 "100x40 -> 60x40 bilinear2 X\n"); 1608 1609 // X scaled to 40%, Y scaled 60% 1610 x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40)); 1611 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1612 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1613 CheckPipeline2(100, 1614 100, 1615 40, 1616 60, 1617 "100x100 -> 100x60 bilinear2 Y\n" 1618 "100x60 -> 40x60 bilinear3 X\n"); 1619 1620 // X scaled to 30%, Y scaled 30% 1621 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120)); 1622 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60)); 1623 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 30)); 1624 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1625 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1626 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); 1627 CheckPipeline2(100, 1628 100, 1629 30, 1630 30, 1631 "100x100 -> 100x30 bilinear4 Y\n" 1632 "100x30 -> 30x30 bilinear4 X\n"); 1633 1634 // X scaled to 50%, Y scaled 30% 1635 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50)); 1636 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1637 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1638 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); 1639 CheckPipeline2(100, 100, 50, 30, "100x100 -> 50x30 bilinear4 Y\n"); 1640 1641 // X scaled to 150%, Y scaled 30% 1642 // Note that we avoid combinding X and Y passes 1643 // as that would probably be LESS efficient here. 1644 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 150)); 1645 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120)); 1646 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60)); 1647 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30)); 1648 CheckPipeline2(100, 1649 100, 1650 150, 1651 30, 1652 "100x100 -> 100x30 bilinear4 Y\n" 1653 "100x30 -> 150x30 bilinear\n"); 1654 1655 // X scaled to 1%, Y scaled 1% 1656 x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 128)); 1657 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 64)); 1658 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 32)); 1659 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 16)); 1660 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 8)); 1661 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 4)); 1662 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 2)); 1663 x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 1)); 1664 y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 128)); 1665 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 64)); 1666 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 32)); 1667 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 16)); 1668 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 8)); 1669 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 4)); 1670 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 2)); 1671 y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 1)); 1672 CheckPipeline2(100, 1673 100, 1674 1, 1675 1, 1676 "100x100 -> 100x32 bilinear4 Y\n" 1677 "100x32 -> 100x4 bilinear4 Y\n" 1678 "100x4 -> 64x1 bilinear2x2\n" 1679 "64x1 -> 8x1 bilinear4 X\n" 1680 "8x1 -> 1x1 bilinear4 X\n"); 1681 } 1682 1683 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context_; 1684 gpu::ContextSupport* context_support_; 1685 scoped_ptr<content::GLHelper> helper_; 1686 scoped_ptr<content::GLHelperScaling> helper_scaling_; 1687 std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_; 1688}; 1689 1690class GLHelperPixelTest : public GLHelperTest { 1691 private: 1692 gfx::DisableNullDrawGLBindings enable_pixel_output_; 1693}; 1694 1695TEST_F(GLHelperTest, RGBASyncReadbackTest) { 1696 const int kTestSize = 64; 1697 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1698 kRGBA_8888_SkColorType, 1699 false); 1700 EXPECT_EQ(result, true); 1701} 1702 1703 1704TEST_F(GLHelperTest, BGRASyncReadbackTest) { 1705 const int kTestSize = 64; 1706 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1707 kBGRA_8888_SkColorType, 1708 false); 1709 EXPECT_EQ(result, true); 1710} 1711 1712TEST_F(GLHelperTest, RGB565SyncReadbackTest) { 1713 const int kTestSize = 64; 1714 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1715 kRGB_565_SkColorType, 1716 false); 1717 EXPECT_EQ(result, true); 1718} 1719 1720TEST_F(GLHelperTest, RGBAASyncReadbackTest) { 1721 const int kTestSize = 64; 1722 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1723 kRGBA_8888_SkColorType, 1724 true); 1725 EXPECT_EQ(result, true); 1726} 1727 1728TEST_F(GLHelperTest, BGRAASyncReadbackTest) { 1729 const int kTestSize = 64; 1730 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1731 kBGRA_8888_SkColorType, 1732 true); 1733 EXPECT_EQ(result, true); 1734} 1735 1736TEST_F(GLHelperTest, RGB565ASyncReadbackTest) { 1737 const int kTestSize = 64; 1738 bool result = TestTextureFormatReadback(gfx::Size(kTestSize,kTestSize), 1739 kRGB_565_SkColorType, 1740 true); 1741 EXPECT_EQ(result, true); 1742} 1743 1744TEST_F(GLHelperPixelTest, YUVReadbackOptTest) { 1745 // This test uses the cb_command tracing events to detect how many 1746 // scaling passes are actually performed by the YUV readback pipeline. 1747 StartTracing(TRACE_DISABLED_BY_DEFAULT("cb_command")); 1748 1749 TestYUVReadback(800, 1750 400, 1751 800, 1752 400, 1753 0, 1754 0, 1755 1, 1756 false, 1757 true, 1758 content::GLHelper::SCALER_QUALITY_FAST); 1759 1760 std::map<std::string, int> event_counts; 1761 EndTracing(&event_counts); 1762 int draw_buffer_calls = event_counts["kDrawBuffersEXTImmediate"]; 1763 int draw_arrays_calls = event_counts["kDrawArrays"]; 1764 VLOG(1) << "Draw buffer calls: " << draw_buffer_calls; 1765 VLOG(1) << "DrawArrays calls: " << draw_arrays_calls; 1766 1767 if (draw_buffer_calls) { 1768 // When using MRT, the YUV readback code should only 1769 // execute two draw arrays, and scaling should be integrated 1770 // into those two calls since we are using the FAST scalign 1771 // quality. 1772 EXPECT_EQ(2, draw_arrays_calls); 1773 } else { 1774 // When not using MRT, there are three passes for the YUV, 1775 // and one for the scaling. 1776 EXPECT_EQ(4, draw_arrays_calls); 1777 } 1778} 1779 1780TEST_F(GLHelperPixelTest, YUVReadbackTest) { 1781 int sizes[] = {2, 4, 14}; 1782 for (int flip = 0; flip <= 1; flip++) { 1783 for (int use_mrt = 0; use_mrt <= 1; use_mrt++) { 1784 for (unsigned int x = 0; x < arraysize(sizes); x++) { 1785 for (unsigned int y = 0; y < arraysize(sizes); y++) { 1786 for (unsigned int ox = x; ox < arraysize(sizes); ox++) { 1787 for (unsigned int oy = y; oy < arraysize(sizes); oy++) { 1788 // If output is a subsection of the destination frame, (letterbox) 1789 // then try different variations of where the subsection goes. 1790 for (Margin xm = x < ox ? MarginLeft : MarginRight; 1791 xm <= MarginRight; 1792 xm = NextMargin(xm)) { 1793 for (Margin ym = y < oy ? MarginLeft : MarginRight; 1794 ym <= MarginRight; 1795 ym = NextMargin(ym)) { 1796 for (int pattern = 0; pattern < 3; pattern++) { 1797 TestYUVReadback(sizes[x], 1798 sizes[y], 1799 sizes[ox], 1800 sizes[oy], 1801 compute_margin(sizes[x], sizes[ox], xm), 1802 compute_margin(sizes[y], sizes[oy], ym), 1803 pattern, 1804 flip == 1, 1805 use_mrt == 1, 1806 content::GLHelper::SCALER_QUALITY_GOOD); 1807 if (HasFailure()) { 1808 return; 1809 } 1810 } 1811 } 1812 } 1813 } 1814 } 1815 } 1816 } 1817 } 1818 } 1819} 1820 1821// Per pixel tests, all sizes are small so that we can print 1822// out the generated bitmaps. 1823TEST_F(GLHelperPixelTest, ScaleTest) { 1824 int sizes[] = {3, 6, 16}; 1825 for (int flip = 0; flip <= 1; flip++) { 1826 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index++) { 1827 for (int x = 0; x < 3; x++) { 1828 for (int y = 0; y < 3; y++) { 1829 for (int dst_x = 0; dst_x < 3; dst_x++) { 1830 for (int dst_y = 0; dst_y < 3; dst_y++) { 1831 for (int pattern = 0; pattern < 3; pattern++) { 1832 TestScale(sizes[x], 1833 sizes[y], 1834 sizes[dst_x], 1835 sizes[dst_y], 1836 pattern, 1837 q_index, 1838 flip == 1); 1839 if (HasFailure()) { 1840 return; 1841 } 1842 } 1843 } 1844 } 1845 } 1846 } 1847 } 1848 } 1849} 1850 1851// Per pixel tests, all sizes are small so that we can print 1852// out the generated bitmaps. 1853TEST_F(GLHelperPixelTest, CropScaleReadbackAndCleanTextureTest) { 1854 const int kSizes[] = {3, 6, 16}; 1855 const SkColorType kColorTypes[] = { 1856 kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}; 1857 for (size_t color_type = 0; color_type < arraysize(kColorTypes); 1858 color_type++) { 1859 // Test BEST and FAST qualities, skip GOOD 1860 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index += 2) { 1861 for (size_t x = 0; x < arraysize(kSizes); x++) { 1862 for (size_t y = 0; y < arraysize(kSizes); y++) { 1863 for (size_t dst_x = 0; dst_x < arraysize(kSizes); dst_x++) { 1864 for (size_t dst_y = 0; dst_y < arraysize(kSizes); dst_y++) { 1865 for (int pattern = 0; pattern < 3; pattern++) { 1866 TestCropScaleReadbackAndCleanTexture(kSizes[x], 1867 kSizes[y], 1868 kSizes[dst_x], 1869 kSizes[dst_y], 1870 pattern, 1871 kColorTypes[color_type], 1872 false, 1873 q_index); 1874 if (HasFailure()) 1875 return; 1876 } 1877 } 1878 } 1879 } 1880 } 1881 } 1882 } 1883} 1884 1885// Validate that all scaling generates valid pipelines. 1886TEST_F(GLHelperTest, ValidateScalerPipelines) { 1887 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; 1888 for (size_t q = 0; q < arraysize(kQualities); q++) { 1889 for (size_t x = 0; x < arraysize(sizes); x++) { 1890 for (size_t y = 0; y < arraysize(sizes); y++) { 1891 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { 1892 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { 1893 TestScalerPipeline( 1894 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); 1895 if (HasFailure()) { 1896 return; 1897 } 1898 } 1899 } 1900 } 1901 } 1902 } 1903} 1904 1905// Make sure we don't create overly complicated pipelines 1906// for a few common use cases. 1907TEST_F(GLHelperTest, CheckSpecificPipelines) { 1908 // Upscale should be single pass. 1909 CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 1910 1024, 1911 700, 1912 1280, 1913 720, 1914 "1024x700 -> 1280x720 bilinear\n"); 1915 // Slight downscale should use BILINEAR2X2. 1916 CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 1917 1280, 1918 720, 1919 1024, 1920 700, 1921 "1280x720 -> 1024x700 bilinear2x2\n"); 1922 // Most common tab capture pipeline on the Pixel. 1923 // Should be using two BILINEAR3 passes. 1924 CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 1925 2560, 1926 1476, 1927 1249, 1928 720, 1929 "2560x1476 -> 2560x720 bilinear3 Y\n" 1930 "2560x720 -> 1249x720 bilinear3 X\n"); 1931} 1932 1933TEST_F(GLHelperTest, ScalerOpTest) { 1934 for (int allow3 = 0; allow3 <= 1; allow3++) { 1935 for (int dst = 1; dst < 2049; dst += 1 + (dst >> 3)) { 1936 for (int src = 1; src < 2049; src++) { 1937 TestAddOps(src, dst, allow3 == 1, (src & 1) == 1); 1938 if (HasFailure()) { 1939 LOG(ERROR) << "Failed for src=" << src << " dst=" << dst 1940 << " allow3=" << allow3; 1941 return; 1942 } 1943 } 1944 } 1945 } 1946} 1947 1948TEST_F(GLHelperTest, CheckOptimizations) { 1949 // Test in baseclass since it is friends with GLHelperScaling 1950 CheckOptimizationsTest(); 1951} 1952 1953} // namespace 1954 1955// These tests needs to run against a proper GL environment, so we 1956// need to set it up before we can run the tests. 1957int main(int argc, char** argv) { 1958 base::CommandLine::Init(argc, argv); 1959 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); 1960#if defined(OS_MACOSX) 1961 base::mac::ScopedNSAutoreleasePool pool; 1962#endif 1963 1964 content::UnitTestTestSuite runner(suite); 1965 base::MessageLoop message_loop; 1966 return runner.Run(); 1967} 1968