190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <stdio.h>
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <cmath>
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <GLES2/gl2.h>
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <GLES2/gl2ext.h>
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <GLES2/gl2extchromium.h>
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/at_exit.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/bind.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/command_line.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/file_util.h"
189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/run_loop.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/common/gpu/client/gl_helper.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/common/gpu/client/gl_helper_scaling.h"
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/test/unittest_test_suite.h"
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/test/content_test_suite.h"
26558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "gpu/config/gpu_util.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "media/base/video_frame.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/skia/include/core/SkTypes.h"
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gl/gl_surface.h"
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_MACOSX)
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/mac/scoped_nsautorelease_pool.h"
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(TOOLKIT_GTK)
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/gtk_util.h"
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using WebKit::WebGLId;
457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using WebKit::WebGraphicsContext3D;
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)content::GLHelper::ScalerQuality kQualities[] = {
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::GLHelper::SCALER_QUALITY_BEST,
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::GLHelper::SCALER_QUALITY_GOOD,
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  content::GLHelper::SCALER_QUALITY_FAST,
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char *kQualityNames[] = {
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  "best",
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  "good",
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  "fast",
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class GLHelperTest : public testing::Test {
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) protected:
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void SetUp() {
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebGraphicsContext3D::Attributes attributes;
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        CreateOffscreenContext(attributes);
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->makeContextCurrent();
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_.reset(new content::GLHelper(context_.get()));
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_.reset(new content::GLHelperScaling(
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        context_.get(),
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        helper_.get()));
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void TearDown() {
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_.reset(NULL);
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_.reset(NULL);
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_.reset(NULL);
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Bicubic filter kernel function.
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static float Bicubic(float x) {
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const float a = -0.5;
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x = std::abs(x);
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float x2 = x * x;
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float x3 = x2 * x;
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (x <= 1) {
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return (a + 2) * x3 - (a + 3) * x2 + 1;
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else if (x < 2) {
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a;
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return 0.0f;
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Look up a single R/G/B/A value.
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Clamp x/y.
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int Channel(SkBitmap* pixels, int x, int y, int c) {
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    uint32 *data = pixels->getAddr32(
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::max(0, std::min(x, pixels->width() - 1)),
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::max(0, std::min(y, pixels->height() - 1)));
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return (*data) >> (c * 8) & 0xff;
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set a single R/G/B/A value.
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) {
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_GE(x, 0);
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_GE(y, 0);
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_LT(x, pixels->width());
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_LT(y, pixels->height());
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    uint32 *data = pixels->getAddr32(x, y);
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    v = std::max(0, std::min(v, 255));
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8));
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Print all the R, G, B or A values from an SkBitmap in a
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // human-readable format.
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void PrintChannel(SkBitmap* pixels, int c) {
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int y = 0; y < pixels->height(); y++) {
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int x = 0; x < pixels->width(); x++) {
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        printf("%3d, ", Channel(pixels, x, y, c));
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      printf("\n");
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Print out the individual steps of a scaler pipeline.
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string PrintStages(
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const std::vector<GLHelperScaling::ScalerStage> &scaler_stages) {
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string ret;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 0; i < scaler_stages.size(); i++) {
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ret.append(base::StringPrintf("%dx%d -> %dx%d ",
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    scaler_stages[i].src_size.width(),
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    scaler_stages[i].src_size.height(),
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    scaler_stages[i].dst_size.width(),
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    scaler_stages[i].dst_size.height()));
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      bool xy_matters = false;
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      switch (scaler_stages[i].shader) {
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR:
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bilinear");
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR2:
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bilinear2");
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          xy_matters = true;
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR3:
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bilinear3");
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          xy_matters = true;
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR4:
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bilinear4");
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          xy_matters = true;
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR2X2:
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bilinear2x2");
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bicubic upscale");
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          xy_matters = true;
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append("bicubic 1/2");
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          xy_matters = true;
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_PLANAR:
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          ret.append("planar");
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          break;
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_YUV_MRT_PASS1:
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          ret.append("rgb2yuv pass 1");
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          break;
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_YUV_MRT_PASS2:
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          ret.append("rgb2yuv pass 2");
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          break;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (xy_matters) {
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (scaler_stages[i].scale_x) {
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append(" X");
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        } else {
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          ret.append(" Y");
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ret.append("\n");
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return ret;
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool CheckScale(double scale, int samples, bool already_scaled) {
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // 1:1 is valid if there is one sample.
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (samples == 1 && scale == 1.0) {
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return true;
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Is it an exact down-scale (50%, 25%, etc.?)
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (scale == 2.0 * samples) {
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return true;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Upscales, only valid if we haven't already scaled in this dimension.
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!already_scaled) {
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Is it a valid bilinear upscale?
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (samples == 1 && scale <= 1.0) {
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return true;
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Multi-sample upscale-downscale combination?
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (scale > samples / 2.0 && scale < samples) {
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return true;
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Make sure that the stages of the scaler pipeline are sane.
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ValidateScalerStages(
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content::GLHelper::ScalerQuality quality,
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const std::vector<GLHelperScaling::ScalerStage> &scaler_stages,
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const std::string& message) {
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool previous_error = HasFailure();
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // First, check that the input size for each stage is equal to
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the output size of the previous stage.
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 1; i < scaler_stages.size(); i++) {
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i - 1].dst_size.width(),
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                scaler_stages[i].src_size.width());
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i - 1].dst_size.height(),
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                scaler_stages[i].src_size.height());
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i].src_subrect.x(), 0);
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i].src_subrect.y(), 0);
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i].src_subrect.width(),
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                scaler_stages[i].src_size.width());
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(scaler_stages[i].src_subrect.height(),
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                scaler_stages[i].src_size.height());
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Used to verify that up-scales are not attempted after some
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // other scale.
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool scaled_x = false;
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool scaled_y = false;
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 0; i < scaler_stages.size(); i++) {
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Note: 2.0 means scaling down by 50%
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      double x_scale =
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          static_cast<double>(scaler_stages[i].src_subrect.width()) /
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          static_cast<double>(scaler_stages[i].dst_size.width());
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      double y_scale =
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          static_cast<double>(scaler_stages[i].src_subrect.height()) /
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          static_cast<double>(scaler_stages[i].dst_size.height());
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      int x_samples = 0;
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      int y_samples = 0;
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Codify valid scale operations.
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      switch (scaler_stages[i].shader) {
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_PLANAR:
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_YUV_MRT_PASS1:
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        case GLHelperScaling::SHADER_YUV_MRT_PASS2:
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          EXPECT_TRUE(false) << "Invalid shader.";
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          break;
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR:
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if (quality != content::GLHelper::SCALER_QUALITY_FAST) {
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            x_samples = 1;
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            y_samples = 1;
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR2:
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_samples = 2;
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          y_samples = 1;
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR3:
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_samples = 3;
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          y_samples = 1;
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR4:
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_samples = 4;
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          y_samples = 1;
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BILINEAR2X2:
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_samples = 2;
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          y_samples = 2;
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if (scaler_stages[i].scale_x) {
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_LT(x_scale, 1.0);
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(y_scale, 1.0);
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          } else {
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(x_scale, 1.0);
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_LT(y_scale, 1.0);
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if (scaler_stages[i].scale_x) {
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(x_scale, 2.0);
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(y_scale, 1.0);
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          } else {
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(x_scale, 1.0);
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            EXPECT_EQ(y_scale, 2.0);
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          break;
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (!scaler_stages[i].scale_x) {
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::swap(x_samples, y_samples);
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (x_samples) {
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_TRUE(CheckScale(x_scale, x_samples, scaled_x))
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            << "x_scale = " << x_scale;
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (y_samples) {
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_TRUE(CheckScale(y_scale, y_samples, scaled_y))
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            << "y_scale = " << y_scale;
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (x_scale != 1.0) {
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scaled_x = true;
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (y_scale != 1.0) {
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        scaled_y = true;
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (HasFailure() && !previous_error) {
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      printf("Invalid scaler stages: %s\n", message.c_str());
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      printf("Scaler stages:\n%s", PrintStages(scaler_stages).c_str());
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Compare two bitmaps, make sure that each component of each pixel
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // is no more than |maxdiff| apart. If they are not similar enough,
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // prints out |truth|, |other|, |source|, |scaler_stages| and |message|.
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void Compare(SkBitmap* truth,
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               SkBitmap* other,
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               int maxdiff,
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               SkBitmap* source,
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               const std::vector<GLHelperScaling::ScalerStage> &scaler_stages,
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               std::string message) {
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(truth->width(), other->width());
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(truth->height(), other->height());
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int x = 0; x < truth->width(); x++) {
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int y = 0; y < truth->height(); y++) {
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (int c = 0; c < 4; c++) {
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          int a = Channel(truth, x, y, c);
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          int b = Channel(other, x, y, c);
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          EXPECT_NEAR(a, b, maxdiff)
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              << " x=" << x
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              << " y=" << y
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              << " c=" << c
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              << " " << message;
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if (std::abs(a - b) > maxdiff) {
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            printf("-------expected--------\n");
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            PrintChannel(truth, c);
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            printf("-------actual--------\n");
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            PrintChannel(other, c);
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            if (source) {
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              printf("-------before scaling--------\n");
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              PrintChannel(source, c);
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            }
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            printf("-----Scaler stages------\n%s",
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   PrintStages(scaler_stages).c_str());
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            return;
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Get a single R, G, B or A value as a float.
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) {
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return Channel(pixels, x, y, c) / 255.0;
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Works like a GL_LINEAR lookup on an SkBitmap.
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float Bilinear(SkBitmap* pixels, float x, float y, int c) {
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x -= 0.5;
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y -= 0.5;
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int base_x = static_cast<int>(floorf(x));
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int base_y = static_cast<int>(floorf(y));
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x -= base_x;
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y -= base_y;
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) +
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) +
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y +
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y);
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Very slow bicubic / bilinear scaler for reference.
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ScaleSlow(SkBitmap* input,
38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 SkBitmap* output,
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 content::GLHelper::ScalerQuality quality) {
38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float xscale = static_cast<float>(input->width()) / output->width();
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float yscale = static_cast<float>(input->height()) / output->height();
38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale;
38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale;
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int dst_y = 0; dst_y < output->height(); dst_y++) {
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int dst_x = 0; dst_x < output->width(); dst_x++) {
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (int channel = 0; channel < 4; channel++) {
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          float dst_x_in_src = (dst_x + 0.5f) * xscale;
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          float dst_y_in_src = (dst_y + 0.5f) * yscale;
39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          float value = 0.0f;
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          float sum = 0.0f;
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          switch (quality) {
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case content::GLHelper::SCALER_QUALITY_BEST:
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              for (int src_y = -10; src_y < input->height() + 10; ++src_y) {
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                float coeff_y = Bicubic(
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    (src_y + 0.5f - dst_y_in_src) * clamped_yscale);
40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                if (coeff_y == 0.0f) {
40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  continue;
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                }
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                for (int src_x = -10; src_x < input->width() + 10; ++src_x) {
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  float coeff = coeff_y * Bicubic(
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      (src_x + 0.5f - dst_x_in_src) * clamped_xscale);
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  if (coeff == 0.0f) {
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    continue;
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  }
41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  sum += coeff;
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  float c = ChannelAsFloat(input, src_x, src_y, channel);
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  value += c * coeff;
41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                }
41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              break;
41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
41890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case content::GLHelper::SCALER_QUALITY_GOOD: {
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              int xshift = 0, yshift = 0;
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              while ((output->width() << xshift) < input->width()) {
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                xshift++;
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              while ((output->height() << yshift) < input->height()) {
42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                yshift++;
42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              int xmag = 1 << xshift;
42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              int ymag = 1 << yshift;
42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              if (xmag == 4 && output->width() * 3 >= input->width()) {
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                xmag=3;
43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              if (ymag == 4 && output->height() * 3 >= input->height()) {
43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                ymag=3;
43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              for (int x = 0; x < xmag; x++) {
43590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                for (int y = 0; y < ymag; y++) {
43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  value += Bilinear(input,
43790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    (dst_x * xmag + x + 0.5) * xscale / xmag,
43890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    (dst_y * ymag + y + 0.5) * yscale / ymag,
43990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      channel);
44090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  sum += 1.0;
44190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                }
44290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              break;
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            }
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case content::GLHelper::SCALER_QUALITY_FAST:
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              value = Bilinear(input, dst_x_in_src, dst_y_in_src, channel);
44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              sum = 1.0;
44990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          value /= sum;
45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          SetChannel(output, dst_x, dst_y, channel,
45290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     static_cast<int>(value * 255.0f + 0.5f));
45390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // gl_helper scales recursively, so we'll need to do that
46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // in the reference implementation too.
46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ScaleSlowRecursive(SkBitmap* input, SkBitmap* output,
46290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          content::GLHelper::ScalerQuality quality) {
46390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (quality == content::GLHelper::SCALER_QUALITY_FAST ||
46490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        quality == content::GLHelper::SCALER_QUALITY_GOOD) {
46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ScaleSlow(input, output, quality);
46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float xscale = static_cast<float>(output->width()) / input->width();
47090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
47190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // This corresponds to all the operations we can do directly.
47290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float yscale = static_cast<float>(output->height()) / input->height();
47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if ((xscale == 1.0f && yscale == 1.0f) ||
47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (xscale == 0.5f && yscale == 1.0f) ||
47590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (xscale == 1.0f && yscale == 0.5f) ||
47690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (xscale >= 1.0f && yscale == 1.0f) ||
47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (xscale == 1.0f && yscale >= 1.0f)) {
47890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ScaleSlow(input, output, quality);
47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
48190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Now we break the problem down into smaller pieces, using the
48390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // operations available.
48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int xtmp = input->width();
48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int ytmp = input->height();
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (output->height() != input->height()) {
48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ytmp = output->height();
48990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      while (ytmp < input->height() && ytmp * 2 != input->height()) {
49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        ytmp += ytmp;
49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      xtmp = output->width();
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      while (xtmp < input->width() && xtmp * 2 != input->width()) {
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        xtmp += xtmp;
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
49790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkBitmap tmp;
50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tmp.setConfig(SkBitmap::kARGB_8888_Config, xtmp, ytmp);
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tmp.allocPixels();
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkAutoLockPixels lock(tmp);
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScaleSlowRecursive(input, &tmp, quality);
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScaleSlowRecursive(&tmp, output, quality);
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Scaling test: Create a test image, scale it using GLHelperScaling
50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // and a reference implementation and compare the results.
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestScale(int xsize, int ysize,
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 int scaled_xsize, int scaled_ysize,
51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 int test_pattern,
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 size_t quality) {
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebGLId src_texture = context_->createTexture();
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebGLId framebuffer = context_->createFramebuffer();
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkBitmap input_pixels;
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    input_pixels.setConfig(SkBitmap::kARGB_8888_Config, xsize, ysize);
51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    input_pixels.allocPixels();
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkAutoLockPixels lock(input_pixels);
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int x = 0; x < xsize; ++x) {
52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int y = 0; y < ysize; ++y) {
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        switch (test_pattern) {
524868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 0:  // Smooth test pattern
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, x * 10);
52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, y * 10);
52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y) * 10);
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            break;
530868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 1:  // Small blocks
53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0);
53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0);
53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0);
53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            break;
536868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 2:  // Medium blocks
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, 10 + x/2 * 50);
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, 10 + y/3 * 50);
53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y)/5 * 50 + 5);
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            break;
54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->bindTexture(GL_TEXTURE_2D, src_texture);
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->texImage2D(GL_TEXTURE_2D,
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         0,
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         GL_RGBA,
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         xsize,
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         ysize,
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         0,
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         GL_RGBA,
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         GL_UNSIGNED_BYTE,
55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         input_pixels.getPixels());
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string message = base::StringPrintf("input size: %dx%d "
55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             "output size: %dx%d "
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             "pattern: %d quality: %s",
56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             xsize, ysize,
56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             scaled_xsize, scaled_ysize,
56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             test_pattern,
56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                             kQualityNames[quality]);
56590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<GLHelperScaling::ScalerStage> stages;
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_->ComputeScalerStages(
56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        kQualities[quality],
57090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(xsize, ysize),
57190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Rect(0, 0, xsize, ysize),
57290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(scaled_xsize, scaled_ysize),
57390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
57490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
57590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &stages);
57690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ValidateScalerStages(kQualities[quality], stages, message);
57790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
57890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebGLId dst_texture = helper_->CopyAndScaleTexture(
57990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        src_texture,
58090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(xsize, ysize),
58190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(scaled_xsize, scaled_ysize),
58290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
58390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        kQualities[quality]);
58490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
58590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkBitmap output_pixels;
58690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    output_pixels.setConfig(SkBitmap::kARGB_8888_Config,
58790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            scaled_xsize, scaled_ysize);
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    output_pixels.allocPixels();
58990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkAutoLockPixels output_lock(output_pixels);
59090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
59190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_->ReadbackTextureSync(
59290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        dst_texture,
59390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Rect(0, 0, scaled_xsize, scaled_ysize),
59490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        static_cast<unsigned char *>(output_pixels.getPixels()));
59590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
59690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (xsize == scaled_xsize && ysize == scaled_ysize) {
59790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      Compare(&input_pixels,
59890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              &output_pixels,
59990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              2,
60090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              NULL,
60190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              stages,
60290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              message + " comparing against input");
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
60490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkBitmap truth_pixels;
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    truth_pixels.setConfig(SkBitmap::kARGB_8888_Config,
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           scaled_xsize, scaled_ysize);
60790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    truth_pixels.allocPixels();
60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SkAutoLockPixels truth_lock(truth_pixels);
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
61090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScaleSlowRecursive(&input_pixels, &truth_pixels, kQualities[quality]);
61190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Compare(&truth_pixels,
61290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            &output_pixels,
61390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            2,
61490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            &input_pixels,
61590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            stages,
61690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            message + " comparing against scaled");
61790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
61890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->deleteTexture(src_texture);
61990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->deleteTexture(dst_texture);
62090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    context_->deleteFramebuffer(framebuffer);
62190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
62290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
62390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Create a scaling pipeline and check that it is made up of
62490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // valid scaling operations.
62590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestScalerPipeline(size_t quality,
62690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          int xsize, int ysize,
62790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          int dst_xsize, int dst_ysize) {
62890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<GLHelperScaling::ScalerStage> stages;
62990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_->ComputeScalerStages(
63090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        kQualities[quality],
63190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(xsize, ysize),
63290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Rect(0, 0, xsize, ysize),
63390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(dst_xsize, dst_ysize),
63490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
63690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &stages);
63790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ValidateScalerStages(kQualities[quality], stages,
63890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         base::StringPrintf("input size: %dx%d "
63990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                            "output size: %dx%d "
64090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                            "quality: %s",
64190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                            xsize, ysize,
64290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                            dst_xsize, dst_ysize,
64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                            kQualityNames[quality]));
64490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
64590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
64690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Create a scaling pipeline and make sure that the steps
64790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // are exactly the steps we expect.
64890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void CheckPipeline(content::GLHelper::ScalerQuality quality,
64990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     int xsize, int ysize,
65090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     int dst_xsize, int dst_ysize,
65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     const std::string &description) {
65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<GLHelperScaling::ScalerStage> stages;
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_->ComputeScalerStages(
65490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        quality,
65590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(xsize, ysize),
65690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Rect(0, 0, xsize, ysize),
65790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(dst_xsize, dst_ysize),
65890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
65990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
66090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &stages);
66190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ValidateScalerStages(
66290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        content::GLHelper::SCALER_QUALITY_GOOD,
66390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        stages,
66490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "");
66590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(PrintStages(stages), description);
66690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
66790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Note: Left/Right means Top/Bottom when used for Y dimension.
669868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  enum Margin {
670868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MarginLeft,
671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MarginMiddle,
672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MarginRight,
673868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MarginInvalid,
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  };
675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
676868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  static Margin NextMargin(Margin m) {
677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    switch (m) {
678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginLeft:
679868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return MarginMiddle;
680868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginMiddle:
681868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return MarginRight;
682868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginRight:
683868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return MarginInvalid;
684868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      default:
685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return MarginInvalid;
686868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
687868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
689868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int compute_margin(int insize, int outsize, Margin m) {
690868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int available = outsize - insize;
691868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    switch (m) {
692868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      default:
693868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        EXPECT_TRUE(false) << "This should not happen.";
694868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return 0;
695868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginLeft:
696868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return 0;
697868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginMiddle:
698868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return (available / 2) & ~1;
699868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case MarginRight:
700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return available;
701868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
702868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
703868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
704868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Convert 0.0 - 1.0 to 0 - 255
705868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int float_to_byte(float v) {
706868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int ret = static_cast<int>(floorf(v * 255.0f + 0.5f));
707868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (ret < 0) {
708868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return 0;
709868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
710868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (ret > 255) {
711868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return 255;
712868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
713868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ret;
714868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
716868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  static void callcallback(const base::Callback<void()>& callback,
717868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           bool result) {
718868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callback.Run();
719868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
720868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
721868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void PrintPlane(unsigned char *plane, int xsize, int stride, int ysize) {
722868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int y = 0; y < ysize; y++) {
723868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (int x = 0; x < xsize ; x++) {
724868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        printf("%3d, ", plane[y * stride + x]);
725868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      printf("   (%p)\n", plane + y * stride);
727868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
728868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
729868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
730868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Compare two planes make sure that each component of each pixel
731868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // is no more than |maxdiff| apart.
732868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void ComparePlane(unsigned char* truth,
733868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    unsigned char* other,
734868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    int maxdiff,
735868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    int xsize,
736868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    int stride,
737868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    int ysize,
738868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    SkBitmap* source,
739868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    std::string message) {
740868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int x = 0; x < xsize; x++) {
741868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (int y = 0; y < ysize; y++) {
742868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        int a = other[y * stride + x];
743868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        int b = truth[y * stride + x];
744868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        EXPECT_NEAR(a, b, maxdiff)
745868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            << " x=" << x
746868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            << " y=" << y
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            << " " << message;
748868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (std::abs(a - b) > maxdiff) {
749868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          printf("-------expected--------\n");
750868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          PrintPlane(truth, xsize, stride, ysize);
751868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          printf("-------actual--------\n");
752868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          PrintPlane(other, xsize, stride, ysize);
753868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          if (source) {
754868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            printf("-------before yuv conversion: red--------\n");
755868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            PrintChannel(source, 0);
756868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            printf("-------before yuv conversion: green------\n");
757868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            PrintChannel(source, 1);
758868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            printf("-------before yuv conversion: blue-------\n");
759868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            PrintChannel(source, 2);
760868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          }
761868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          return;
762868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
763868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
764868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
765868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
766868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
767868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // YUV readback test. Create a test pattern, convert to YUV
768868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // with reference implementation and compare to what gl_helper
769868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // returns.
770868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void TestYUVReadback(int xsize,
771868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int ysize,
772868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int output_xsize,
773868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int output_ysize,
774868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int xmargin,
775868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int ymargin,
776868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       int test_pattern,
777868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       bool use_mrt) {
778868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    WebGLId src_texture = context_->createTexture();
779868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    SkBitmap input_pixels;
780868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    input_pixels.setConfig(SkBitmap::kARGB_8888_Config, xsize, ysize);
781868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    input_pixels.allocPixels();
782868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    SkAutoLockPixels lock(input_pixels);
783868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
784868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int x = 0; x < xsize; ++x) {
785868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (int y = 0; y < ysize; ++y) {
786868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        switch (test_pattern) {
787868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 0:  // Smooth test pattern
788868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, x * 10);
789868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, y * 10);
790868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y) * 10);
791868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
792868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            break;
793868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 1:  // Small blocks
794868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0);
795868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0);
796868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0);
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
798868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            break;
799868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          case 2:  // Medium blocks
800868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 0, 10 + x/2 * 50);
801868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 1, 10 + y/3 * 50);
802868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 2, (x + y)/5 * 50 + 5);
803868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            SetChannel(&input_pixels, x, y, 3, 255);
804868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            break;
805868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
806868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
807868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
808868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
809868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context_->bindTexture(GL_TEXTURE_2D, src_texture);
810868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context_->texImage2D(GL_TEXTURE_2D,
811868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         0,
812868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         GL_RGBA,
813868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         xsize,
814868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         ysize,
815868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         0,
816868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         GL_RGBA,
817868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         GL_UNSIGNED_BYTE,
818868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         input_pixels.getPixels());
819868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
8207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    gpu::Mailbox mailbox;
8217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    context_->genMailboxCHROMIUM(mailbox.name);
8227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_FALSE(mailbox.IsZero());
8237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
8247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    uint32 sync_point = context_->insertSyncPoint();
8257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
826868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string message = base::StringPrintf("input size: %dx%d "
827868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             "output size: %dx%d "
828868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             "margin: %dx%d "
829868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             "pattern: %d",
830868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             xsize, ysize,
831868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             output_xsize, output_ysize,
832868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             xmargin, ymargin,
833868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             test_pattern);
834868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<ReadbackYUVInterface> yuv_reader(
835868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        helper_->CreateReadbackPipelineYUV(
836868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            content::GLHelper::SCALER_QUALITY_GOOD,
837868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(xsize, ysize),
838868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Rect(0, 0, xsize, ysize),
839868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(output_xsize, output_ysize),
840868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Rect(xmargin, ymargin, xsize, ysize),
841868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            false,
842868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            use_mrt));
843868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
844868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<media::VideoFrame> output_frame =
845868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        media::VideoFrame::CreateFrame(
846868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            media::VideoFrame::YV12,
847868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(output_xsize, output_ysize),
848868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Rect(0, 0, output_xsize, output_ysize),
849868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(output_xsize, output_ysize),
850868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            base::TimeDelta::FromSeconds(0));
851868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<media::VideoFrame> truth_frame =
852868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        media::VideoFrame::CreateFrame(
853868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            media::VideoFrame::YV12,
854868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(output_xsize, output_ysize),
855868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Rect(0, 0, output_xsize, output_ysize),
856868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            gfx::Size(output_xsize, output_ysize),
857868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            base::TimeDelta::FromSeconds(0));
858868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
859868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::RunLoop run_loop;
860868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    yuv_reader->ReadbackYUV(
8617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        mailbox,
8627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sync_point,
863868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        output_frame.get(),
864868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        base::Bind(&callcallback, run_loop.QuitClosure()));
865868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    run_loop.Run();
866868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
867868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    unsigned char* Y = truth_frame->data(media::VideoFrame::kYPlane);
868868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    unsigned char* U = truth_frame->data(media::VideoFrame::kUPlane);
869868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    unsigned char* V = truth_frame->data(media::VideoFrame::kVPlane);
870868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int32 y_stride = truth_frame->stride(media::VideoFrame::kYPlane);
871868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int32 u_stride = truth_frame->stride(media::VideoFrame::kUPlane);
872868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int32 v_stride = truth_frame->stride(media::VideoFrame::kVPlane);
873868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    memset(Y, 0x00, y_stride * output_ysize);
874868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    memset(U, 0x80, u_stride * output_ysize / 2);
875868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    memset(V, 0x80, v_stride * output_ysize / 2);
876868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int y = 0; y < ysize; y++) {
878868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (int x = 0; x < xsize; x++) {
879868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte(
880868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            ChannelAsFloat(&input_pixels, x, y, 0) * 0.257 +
881868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            ChannelAsFloat(&input_pixels, x, y, 1) * 0.504 +
882868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            ChannelAsFloat(&input_pixels, x, y, 2) * 0.098 +
883868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            0.0625);
884868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
885868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
886868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
887868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int y = 0; y < ysize / 2; y++) {
888868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (int x = 0; x < xsize / 2; x++) {
889868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        U[(y + ymargin / 2) * u_stride + x + xmargin / 2] =
890868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            float_to_byte(
891868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * -0.148 +
892868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * -0.291 +
893868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * 0.439 +
894868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                0.5);
895868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        V[(y + ymargin / 2) * v_stride + x + xmargin / 2] =
896868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            float_to_byte(
897868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * 0.439 +
898868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * -0.368 +
899868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * -0.071 +
900868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                0.5);
901868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
902868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
903868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
904868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ComparePlane(Y, output_frame->data(media::VideoFrame::kYPlane), 2,
905868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 output_xsize, y_stride, output_ysize,
906868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 &input_pixels,
907868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 message + " Y plane");
908868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ComparePlane(U, output_frame->data(media::VideoFrame::kUPlane), 2,
909868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 output_xsize / 2, u_stride, output_ysize / 2,
910868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 &input_pixels,
911868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 message + " U plane");
912868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ComparePlane(V, output_frame->data(media::VideoFrame::kVPlane), 2,
913868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 output_xsize / 2, v_stride, output_ysize / 2,
914868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 &input_pixels,
915868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 message + " V plane");
916868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
917868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    context_->deleteTexture(src_texture);
918868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
919868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
92090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void TestAddOps(int src,
92190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  int dst,
92290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  bool scale_x,
92390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  bool allow3) {
92490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::deque<GLHelperScaling::ScaleOp> ops;
92590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
92690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Scale factor 3 is a special case.
92790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // It is currently only allowed by itself.
92890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (allow3 && dst * 3 >= src && dst * 2 < src) {
92990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(ops[0].scale_factor, 3);
93090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(ops.size(), 1U);
93190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(ops[0].scale_x, scale_x);
93290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(ops[0].scale_size, dst);
93390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
93490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
93590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
93690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 0; i < ops.size(); i++) {
93790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(ops[i].scale_x, scale_x);
93890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (i == 0) {
93990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Only the first op is allowed to be a scale up.
94090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // (Scaling up *after* scaling down would make it fuzzy.)
94190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_TRUE(ops[0].scale_factor == 0 ||
94290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    ops[0].scale_factor == 2);
94390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      } else {
94490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // All other operations must be 50% downscales.
94590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_EQ(ops[i].scale_factor, 2);
94690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
94790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
94890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Check that the scale factors make sense and add up.
94990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int tmp = dst;
95090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int i = static_cast<int>(ops.size() - 1); i >= 0; i--) {
95190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(tmp, ops[i].scale_size);
95290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (ops[i].scale_factor == 0) {
95390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_EQ(i, 0);
95490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        EXPECT_GT(tmp, src);
95590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        tmp = src;
95690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      } else {
95790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        tmp *= ops[i].scale_factor;
95890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
95990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
96090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(tmp, src);
96190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
96290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
96390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void CheckPipeline2(int xsize, int ysize,
96490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      int dst_xsize, int dst_ysize,
96590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      const std::string &description) {
96690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<GLHelperScaling::ScalerStage> stages;
96790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    helper_scaling_->ConvertScalerOpsToScalerStages(
96890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        content::GLHelper::SCALER_QUALITY_GOOD,
96990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(xsize, ysize),
97090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Rect(0, 0, xsize, ysize),
97190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::Size(dst_xsize, dst_ysize),
97290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
97390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        false,
97490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &x_ops_,
97590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &y_ops_,
97690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &stages);
97790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(x_ops_.size(), 0U);
97890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(y_ops_.size(), 0U);
97990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ValidateScalerStages(
98090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        content::GLHelper::SCALER_QUALITY_GOOD,
98190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        stages,
98290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "");
98390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(PrintStages(stages), description);
98490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
98590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
98690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void CheckOptimizationsTest() {
98790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Basic upscale. X and Y should be combined into one pass.
98890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
98990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
99090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(1024, 768, 2000, 2000,
99190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "1024x768 -> 2000x2000 bilinear\n");
99290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
99390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled 1/2, Y upscaled, should still be one pass.
99490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
99590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
99690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(1024, 768, 512, 2000,
99790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "1024x768 -> 512x2000 bilinear\n");
99890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
99990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X upscaled, Y scaled 1/2, one bilinear pass
100090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
100190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
100290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(1024, 768, 2000, 384,
100390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "1024x768 -> 2000x384 bilinear\n");
100490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
100590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled 1/2, Y scaled 1/2, one bilinear pass
100690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
100790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
100890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(1024, 768, 2000, 384,
100990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "1024x768 -> 512x384 bilinear\n");
101090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled 1/2, Y scaled to 60%, one bilinear2 pass.
101290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
101390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
101490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
101590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 50, 60,
101690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 50x60 bilinear2 Y\n");
101790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 60%, Y scaled 1/2, one bilinear2 pass.
101990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
102090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
102190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 50));
102290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 50, 60,
102390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 60x50 bilinear2 X\n");
102490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
102590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 60%, Y scaled 60%, one bilinear2x2 pass.
102690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
102790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
102890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
102990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
103090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 60, 60,
103190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 60x60 bilinear2x2\n");
103290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
103390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 40%, Y scaled 40%, two bilinear3 passes.
103490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
103590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
103690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 40, 40,
103790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x40 bilinear3 Y\n"
103890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x40 -> 40x40 bilinear3 X\n");
103990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
104090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 60%, Y scaled 40%
104190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
104290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
104390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
104490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 60, 40,
104590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x40 bilinear3 Y\n"
104690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x40 -> 60x40 bilinear2 X\n");
104790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
104890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 40%, Y scaled 60%
104990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
105090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
105190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
105290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 40, 60,
105390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x60 bilinear2 Y\n"
105490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x60 -> 40x60 bilinear3 X\n");
105590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
105690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 30%, Y scaled 30%
105790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
105890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
105990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 30));
106090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
106190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
106290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
106390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 30, 30,
106490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x30 bilinear4 Y\n"
106590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x30 -> 30x30 bilinear4 X\n");
106690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
106790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 50%, Y scaled 30%
106890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
106990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
107090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
107190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
107290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 50, 30,
107390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 50x30 bilinear4 Y\n");
107490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
107590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 150%, Y scaled 30%
107690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Note that we avoid combinding X and Y passes
107790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // as that would probably be LESS efficient here.
107890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 150));
107990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
108090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
108190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
108290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 150, 30,
108390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x30 bilinear4 Y\n"
108490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x30 -> 150x30 bilinear\n");
108590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
108690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // X scaled to 1%, Y scaled 1%
108790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 128));
108890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 64));
108990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 32));
109090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 16));
109190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 8));
109290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 4));
109390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 2));
109490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 1));
109590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 128));
109690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 64));
109790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 32));
109890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 16));
109990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 8));
110090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 4));
110190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 2));
110290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 1));
110390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPipeline2(100, 100, 30, 30,
110490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x100 -> 100x32 bilinear4 Y\n"
110590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x32 -> 100x4 bilinear4 Y\n"
110690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "100x4 -> 64x1 bilinear2x2\n"
110790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "64x1 -> 8x1 bilinear4 X\n"
110890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   "8x1 -> 1x1 bilinear4 X\n");
110990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
111090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
111190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<WebKit::WebGraphicsContext3D> context_;
111290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<content::GLHelper> helper_;
111390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<content::GLHelperScaling> helper_scaling_;
111490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
111590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
111690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Reenable once http://crbug.com/162291 is fixed.
1118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(GLHelperTest, YUVReadbackTest) {
1119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int sizes[] = { 2, 4, 14 };
1120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (int use_mrt = 0; use_mrt <= 1 ; use_mrt++) {
1121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (unsigned int x = 0; x < arraysize(sizes); x++) {
1122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (unsigned int y = 0; y < arraysize(sizes); y++) {
1123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        for (unsigned int ox = x; ox < arraysize(sizes); ox++) {
1124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          for (unsigned int oy = y; oy < arraysize(sizes); oy++) {
1125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // If output is a subsection of the destination frame, (letterbox)
1126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // then try different variations of where the subsection goes.
1127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            for (Margin xm = x < ox ? MarginLeft : MarginRight;
1128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 xm <= MarginRight;
1129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 xm = NextMargin(xm)) {
1130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              for (Margin ym = y < oy ? MarginLeft : MarginRight;
1131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                   ym <= MarginRight;
1132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                   ym = NextMargin(ym)) {
1133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                for (int pattern = 0; pattern < 3; pattern++) {
1134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  TestYUVReadback(
1135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      sizes[x],
1136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      sizes[y],
1137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      sizes[ox],
1138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      sizes[oy],
1139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      compute_margin(sizes[x], sizes[ox], xm),
1140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      compute_margin(sizes[y], sizes[oy], ym),
1141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      pattern,
1142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      use_mrt == 1);
1143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  if (HasFailure()) {
1144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    return;
1145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  }
1146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                }
1147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              }
1148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            }
1149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          }
1150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
1151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
1152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
1153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
1155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
115790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Per pixel tests, all sizes are small so that we can print
115890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// out the generated bitmaps.
115990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(GLHelperTest, ScaleTest) {
116090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int sizes[] = {3, 6, 16};
116190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t q = 0; q < arraysize(kQualities); q++) {
116290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int x = 0; x < 3; x++) {
116390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int y = 0; y < 3; y++) {
116490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (int dst_x = 0; dst_x < 3; dst_x++) {
116590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          for (int dst_y = 0; dst_y < 3; dst_y++) {
116690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            for (int pattern = 0; pattern < 3; pattern++) {
116790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              TestScale(sizes[x],
116890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        sizes[y],
116990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        sizes[dst_x],
117090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        sizes[dst_y],
117190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        pattern,
117290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        q);
117390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              if (HasFailure()) {
117490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                return;
117590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
117690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            }
117790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
117890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
117990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
118090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
118190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
118290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
118390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
118490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Validate that all scaling generates valid pipelines.
118590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(GLHelperTest, ValidateScalerPipelines) {
118690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096};
118790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t q = 0; q < arraysize(kQualities); q++) {
118890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t x = 0; x < arraysize(sizes); x++) {
118990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (size_t y = 0; y < arraysize(sizes); y++) {
119090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) {
119190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) {
119290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            TestScalerPipeline(q,
119390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                               sizes[x], sizes[y],
119490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                               sizes[dst_x], sizes[dst_y]);
119590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            if (HasFailure()) {
119690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              return;
119790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            }
119890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
119990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
120090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
120190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
120290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
120390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
120490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
120590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Make sure we don't create overly complicated pipelines
120690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// for a few common use cases.
120790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(GLHelperTest, CheckSpecificPipelines) {
120890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Upscale should be single pass.
120990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD,
121090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                1024, 700, 1280, 720,
121190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                "1024x700 -> 1280x720 bilinear\n");
121290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Slight downscale should use BILINEAR2X2.
121390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD,
121490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                1280, 720, 1024, 700,
121590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                "1280x720 -> 1024x700 bilinear2x2\n");
121690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Most common tab capture pipeline on the Pixel.
121790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Should be using two BILINEAR3 passes.
121890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD,
121990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                2560, 1476, 1249, 720,
122090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                "2560x1476 -> 2560x720 bilinear3 Y\n"
122190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                "2560x720 -> 1249x720 bilinear3 X\n");
122290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
122390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
122490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(GLHelperTest, ScalerOpTest) {
122590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (int allow3 = 0; allow3 <= 1; allow3++) {
122690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int dst = 1; dst < 2049; dst += 1 + (dst >> 3)) {
122790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      for (int src = 1; src < 2049; src++) {
122890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        TestAddOps(src, dst, allow3 == 1, (src & 1) == 1);
122990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (HasFailure()) {
123090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          LOG(ERROR) << "Failed for src=" << src
123190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     << " dst=" << dst
123290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     << " allow3=" << allow3;
123390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          return;
123490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
123590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
123690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
123790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
123890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
123990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
124090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST_F(GLHelperTest, CheckOptimizations) {
124190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Test in baseclass since it is friends with GLHelperScaling
124290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CheckOptimizationsTest();
124390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
124490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
124590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
124690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
124790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// These tests needs to run against a proper GL environment, so we
124890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// need to set it up before we can run the tests.
124990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int main(int argc, char** argv) {
125090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CommandLine::Init(argc, argv);
125190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::TestSuite* suite = new content::ContentTestSuite(argc, argv);
125290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_MACOSX)
125390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedNSAutoreleasePool pool;
125490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
125590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(TOOLKIT_GTK)
125690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
125790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
125890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::GLSurface::InitializeOneOff();
1259558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  gpu::ApplyGpuDriverBugWorkarounds(CommandLine::ForCurrentProcess());
126090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content::UnitTestTestSuite runner(suite);
1262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::MessageLoop message_loop;
1263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return runner.Run();
126490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
1265