Yuri Wiitala | 0f30893 | 2018-09-13 19:45:22 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "components/viz/common/gl_scaler_test_util.h" |
| 6 | |
| 7 | #include <algorithm> |
| 8 | #include <cmath> |
| 9 | |
Yuri Wiitala | 8bac8fb | 2018-10-30 05:36:58 | [diff] [blame] | 10 | #include "base/files/file_path.h" |
Yuri Wiitala | 0f30893 | 2018-09-13 19:45:22 | [diff] [blame] | 11 | #include "base/logging.h" |
Hans Wennborg | 5bafbb9 | 2020-06-18 09:13:57 | [diff] [blame] | 12 | #include "base/notreached.h" |
Yuri Wiitala | 8bac8fb | 2018-10-30 05:36:58 | [diff] [blame] | 13 | #include "base/path_service.h" |
| 14 | #include "cc/test/pixel_test_utils.h" |
| 15 | #include "components/viz/test/paths.h" |
Yuri Wiitala | 0f30893 | 2018-09-13 19:45:22 | [diff] [blame] | 16 | #include "third_party/skia/include/core/SkColor.h" |
| 17 | #include "third_party/skia/include/core/SkImageInfo.h" |
| 18 | #include "ui/gfx/geometry/rect.h" |
| 19 | |
| 20 | namespace viz { |
| 21 | |
| 22 | using ColorBar = GLScalerTestUtil::ColorBar; |
| 23 | |
| 24 | // static |
| 25 | SkBitmap GLScalerTestUtil::AllocateRGBABitmap(const gfx::Size& size) { |
| 26 | SkBitmap bitmap; |
| 27 | bitmap.allocPixels(SkImageInfo::Make(size.width(), size.height(), |
| 28 | kRGBA_8888_SkColorType, |
| 29 | kUnpremul_SkAlphaType)); |
| 30 | return bitmap; |
| 31 | } |
| 32 | |
| 33 | // static |
| 34 | uint8_t GLScalerTestUtil::ToClamped255(float value) { |
| 35 | value = std::fma(value, 255.0f, 0.5f /* rounding */); |
| 36 | return base::saturated_cast<uint8_t>(value); |
| 37 | } |
| 38 | |
| 39 | // static |
| 40 | std::vector<ColorBar> GLScalerTestUtil::GetScaledSMPTEColorBars( |
| 41 | const gfx::Size& size) { |
| 42 | std::vector<ColorBar> rects; |
| 43 | const SkScalar scale_x = |
| 44 | static_cast<SkScalar>(size.width()) / kSMPTEFullSize.width(); |
| 45 | const SkScalar scale_y = |
| 46 | static_cast<SkScalar>(size.height()) / kSMPTEFullSize.height(); |
| 47 | for (const auto& cr : kSMPTEColorBars) { |
| 48 | const SkRect rect = |
| 49 | SkRect{cr.rect.fLeft * scale_x, cr.rect.fTop * scale_y, |
| 50 | cr.rect.fRight * scale_x, cr.rect.fBottom * scale_y}; |
| 51 | rects.push_back(ColorBar{rect.round(), cr.color}); |
| 52 | } |
| 53 | return rects; |
| 54 | } |
| 55 | |
| 56 | // static |
| 57 | SkBitmap GLScalerTestUtil::CreateSMPTETestImage(const gfx::Size& size) { |
| 58 | SkBitmap result = AllocateRGBABitmap(size); |
| 59 | |
| 60 | // Set all pixels to a color that should not exist in the result. Later, a |
| 61 | // sanity-check will ensure all pixels have been overwritten. |
| 62 | constexpr SkColor kDeadColor = SkColorSetARGB(0xde, 0xad, 0xbe, 0xef); |
| 63 | result.eraseColor(kDeadColor); |
| 64 | |
| 65 | // Set the pixels corresponding to each color bar. |
| 66 | for (const auto& cr : GetScaledSMPTEColorBars(size)) { |
| 67 | result.erase(cr.color, cr.rect); |
| 68 | } |
| 69 | |
| 70 | // Validate that every pixel in the result bitmap has been touched by one of |
| 71 | // the color bars. |
| 72 | for (int y = 0; y < result.height(); ++y) { |
| 73 | for (int x = 0; x < result.width(); ++x) { |
| 74 | if (result.getColor(x, y) == kDeadColor) { |
| 75 | NOTREACHED() << "TEST BUG: Error creating SMPTE test image. Bad size (" |
| 76 | << size.ToString() << ")?"; |
| 77 | return result; |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | return result; |
| 83 | } |
| 84 | |
| 85 | // static |
| 86 | bool GLScalerTestUtil::LooksLikeSMPTETestImage(const SkBitmap& image, |
| 87 | const gfx::Size& src_size, |
| 88 | const gfx::Rect& src_rect, |
| 89 | int fuzzy_pixels, |
| 90 | int* max_color_diff) { |
| 91 | if (image.width() <= 0 || image.height() <= 0) { |
| 92 | return false; |
| 93 | } |
| 94 | |
| 95 | const SkScalar offset_x = static_cast<SkScalar>(src_rect.x()); |
| 96 | const SkScalar offset_y = static_cast<SkScalar>(src_rect.y()); |
| 97 | const SkScalar scale_x = |
| 98 | static_cast<SkScalar>(image.width()) / src_rect.width(); |
| 99 | const SkScalar scale_y = |
| 100 | static_cast<SkScalar>(image.height()) / src_rect.height(); |
| 101 | int measured_max_diff = 0; |
| 102 | for (const auto& cr : GetScaledSMPTEColorBars(src_size)) { |
| 103 | const SkIRect offset_rect = cr.rect.makeOffset(-offset_x, -offset_y); |
| 104 | const SkIRect rect = |
| 105 | SkRect{offset_rect.fLeft * scale_x, offset_rect.fTop * scale_y, |
| 106 | offset_rect.fRight * scale_x, offset_rect.fBottom * scale_y} |
| 107 | .round() |
| 108 | .makeInset(fuzzy_pixels, fuzzy_pixels); |
| 109 | for (int y = std::max(0, rect.fTop), |
| 110 | y_end = std::min(image.height(), rect.fBottom); |
| 111 | y < y_end; ++y) { |
| 112 | for (int x = std::max(0, rect.fLeft), |
| 113 | x_end = std::min(image.width(), rect.fRight); |
| 114 | x < x_end; ++x) { |
| 115 | const SkColor actual = image.getColor(x, y); |
| 116 | measured_max_diff = |
| 117 | std::max({measured_max_diff, |
| 118 | std::abs(static_cast<int>(SkColorGetR(cr.color)) - |
| 119 | static_cast<int>(SkColorGetR(actual))), |
| 120 | std::abs(static_cast<int>(SkColorGetG(cr.color)) - |
| 121 | static_cast<int>(SkColorGetG(actual))), |
| 122 | std::abs(static_cast<int>(SkColorGetB(cr.color)) - |
| 123 | static_cast<int>(SkColorGetB(actual))), |
| 124 | std::abs(static_cast<int>(SkColorGetA(cr.color)) - |
| 125 | static_cast<int>(SkColorGetA(actual)))}); |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | if (max_color_diff) { |
| 131 | const int threshold = *max_color_diff; |
| 132 | *max_color_diff = measured_max_diff; |
| 133 | return measured_max_diff <= threshold; |
| 134 | } |
| 135 | return measured_max_diff == 0; |
| 136 | } |
| 137 | |
| 138 | // static |
| 139 | SkBitmap GLScalerTestUtil::CreateCyclicalTestImage( |
| 140 | const gfx::Size& size, |
| 141 | CyclicalPattern pattern, |
| 142 | const std::vector<SkColor>& cycle, |
| 143 | size_t rotation) { |
| 144 | CHECK(!cycle.empty()); |
| 145 | |
| 146 | // Map SkColors to RGBA data. Also, applies the cycle |rotation| to simplify |
| 147 | // the rest of the code below. |
| 148 | std::vector<uint32_t> cycle_as_rgba(cycle.size()); |
| 149 | for (size_t i = 0; i < cycle.size(); ++i) { |
| 150 | const SkColor color = cycle[(i + rotation) % cycle.size()]; |
| 151 | cycle_as_rgba[i] = ((SkColorGetR(color) << kRedShift) | |
| 152 | (SkColorGetG(color) << kGreenShift) | |
| 153 | (SkColorGetB(color) << kBlueShift) | |
| 154 | (SkColorGetA(color) << kAlphaShift)); |
| 155 | } |
| 156 | |
| 157 | SkBitmap result = AllocateRGBABitmap(size); |
| 158 | switch (pattern) { |
| 159 | case HORIZONTAL_STRIPES: |
| 160 | for (int y = 0; y < size.height(); ++y) { |
| 161 | uint32_t* const pixels = result.getAddr32(0, y); |
| 162 | const uint32_t stripe_rgba = cycle_as_rgba[y % cycle_as_rgba.size()]; |
| 163 | for (int x = 0; x < size.width(); ++x) { |
| 164 | pixels[x] = stripe_rgba; |
| 165 | } |
| 166 | } |
| 167 | break; |
| 168 | |
| 169 | case VERTICAL_STRIPES: |
| 170 | for (int y = 0; y < size.height(); ++y) { |
| 171 | uint32_t* const pixels = result.getAddr32(0, y); |
| 172 | for (int x = 0; x < size.width(); ++x) { |
| 173 | pixels[x] = cycle_as_rgba[x % cycle_as_rgba.size()]; |
| 174 | } |
| 175 | } |
| 176 | break; |
| 177 | |
| 178 | case STAGGERED: |
| 179 | for (int y = 0; y < size.height(); ++y) { |
| 180 | uint32_t* const pixels = result.getAddr32(0, y); |
| 181 | for (int x = 0; x < size.width(); ++x) { |
| 182 | pixels[x] = cycle_as_rgba[(x + y) % cycle_as_rgba.size()]; |
| 183 | } |
| 184 | } |
| 185 | break; |
| 186 | } |
| 187 | |
| 188 | return result; |
| 189 | } |
| 190 | |
| 191 | // static |
| 192 | gfx::ColorSpace GLScalerTestUtil::DefaultRGBColorSpace() { |
| 193 | return gfx::ColorSpace::CreateSRGB(); |
| 194 | } |
| 195 | |
| 196 | // static |
| 197 | gfx::ColorSpace GLScalerTestUtil::DefaultYUVColorSpace() { |
| 198 | return gfx::ColorSpace::CreateREC709(); |
| 199 | } |
| 200 | |
| 201 | // static |
| 202 | void GLScalerTestUtil::ConvertBitmapToYUV(SkBitmap* image) { |
| 203 | const auto transform = gfx::ColorTransform::NewColorTransform( |
| 204 | DefaultRGBColorSpace(), DefaultYUVColorSpace(), |
| 205 | gfx::ColorTransform::Intent::INTENT_ABSOLUTE); |
| 206 | |
| 207 | // Loop, transforming one row of pixels at a time. |
| 208 | std::vector<gfx::ColorTransform::TriStim> stims(image->width()); |
| 209 | for (int y = 0; y < image->height(); ++y) { |
| 210 | uint32_t* const pixels = image->getAddr32(0, y); |
| 211 | for (int x = 0; x < image->width(); ++x) { |
| 212 | stims[x].set_x(((pixels[x] >> kRedShift) & 0xff) / 255.0f); |
| 213 | stims[x].set_y(((pixels[x] >> kGreenShift) & 0xff) / 255.0f); |
| 214 | stims[x].set_z(((pixels[x] >> kBlueShift) & 0xff) / 255.0f); |
| 215 | } |
| 216 | transform->Transform(stims.data(), stims.size()); |
| 217 | for (int x = 0; x < image->width(); ++x) { |
| 218 | pixels[x] = ((ToClamped255(stims[x].x()) << kRedShift) | |
| 219 | (ToClamped255(stims[x].y()) << kGreenShift) | |
| 220 | (ToClamped255(stims[x].z()) << kBlueShift) | |
| 221 | (((pixels[x] >> kAlphaShift) & 0xff) << kAlphaShift)); |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | // static |
| 227 | void GLScalerTestUtil::SwizzleBitmap(SkBitmap* image) { |
| 228 | for (int y = 0; y < image->height(); ++y) { |
| 229 | uint32_t* const pixels = image->getAddr32(0, y); |
| 230 | for (int x = 0; x < image->width(); ++x) { |
| 231 | pixels[x] = ((((pixels[x] >> kBlueShift) & 0xff) << kRedShift) | |
| 232 | (((pixels[x] >> kGreenShift) & 0xff) << kGreenShift) | |
| 233 | (((pixels[x] >> kRedShift) & 0xff) << kBlueShift) | |
| 234 | (((pixels[x] >> kAlphaShift) & 0xff) << kAlphaShift)); |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | // static |
| 240 | SkBitmap GLScalerTestUtil::CreatePackedPlanarBitmap(const SkBitmap& source, |
| 241 | int channel) { |
| 242 | CHECK_EQ(source.width() % 4, 0); |
| 243 | SkBitmap result = |
| 244 | AllocateRGBABitmap(gfx::Size(source.width() / 4, source.height())); |
| 245 | |
| 246 | constexpr int kShiftForChannel[4] = {kRedShift, kGreenShift, kBlueShift, |
| 247 | kAlphaShift}; |
| 248 | const int shift = kShiftForChannel[channel]; |
| 249 | for (int y = 0; y < result.height(); ++y) { |
| 250 | const uint32_t* const src = source.getAddr32(0, y); |
| 251 | uint32_t* const dst = result.getAddr32(0, y); |
| 252 | for (int x = 0; x < result.width(); ++x) { |
| 253 | // (src[0..3]) (dst) |
| 254 | // RGBA RGBA RGBA RGBA --> RRRR (if channel is 0) |
| 255 | dst[x] = ((((src[x * 4 + 0] >> shift) & 0xff) << kRedShift) | |
| 256 | (((src[x * 4 + 1] >> shift) & 0xff) << kGreenShift) | |
| 257 | (((src[x * 4 + 2] >> shift) & 0xff) << kBlueShift) | |
| 258 | (((src[x * 4 + 3] >> shift) & 0xff) << kAlphaShift)); |
| 259 | } |
| 260 | } |
| 261 | return result; |
| 262 | } |
| 263 | |
Yuri Wiitala | f26763f | 2018-10-30 03:06:46 | [diff] [blame] | 264 | // static |
| 265 | void GLScalerTestUtil::UnpackPlanarBitmap(const SkBitmap& plane, |
| 266 | int channel, |
| 267 | SkBitmap* out) { |
| 268 | // The heuristic below auto-adapts to subsampled plane sizes. However, there |
| 269 | // are two cricital requirements: 1) |plane| cannot be empty; 2) |plane| must |
| 270 | // have a size that cleanly unpacks to |out|'s size. |
| 271 | CHECK_GT(plane.width(), 0); |
| 272 | CHECK_GT(plane.height(), 0); |
| 273 | const int col_sampling_ratio = out->width() / plane.width(); |
| 274 | CHECK_EQ(out->width() % plane.width(), 0); |
| 275 | CHECK_GT(col_sampling_ratio, 0); |
| 276 | const int row_sampling_ratio = out->height() / plane.height(); |
| 277 | CHECK_EQ(out->height() % plane.height(), 0); |
| 278 | CHECK_GT(row_sampling_ratio, 0); |
| 279 | const int ch_sampling_ratio = col_sampling_ratio / 4; |
| 280 | CHECK_GT(ch_sampling_ratio, 0); |
| 281 | |
| 282 | // These determine which single byte in each of |out|'s uint32_t-valued pixels |
| 283 | // will be modified. |
| 284 | constexpr int kShiftForChannel[4] = {kRedShift, kGreenShift, kBlueShift, |
| 285 | kAlphaShift}; |
| 286 | const int output_shift = kShiftForChannel[channel]; |
| 287 | const uint32_t output_retain_mask = ~(UINT32_C(0xff) << output_shift); |
| 288 | |
| 289 | // Iterate over the pixels of |out|, sampling each of the 4 components of each |
| 290 | // of |plane|'s pixels. |
| 291 | for (int y = 0; y < out->height(); ++y) { |
| 292 | const uint32_t* const src = plane.getAddr32(0, y / row_sampling_ratio); |
| 293 | uint32_t* const dst = out->getAddr32(0, y); |
| 294 | for (int x = 0; x < out->width(); ++x) { |
| 295 | // Zero-out the existing byte (e.g., if channel==1, then "RGBA" → "R0BA"). |
| 296 | dst[x] &= output_retain_mask; |
| 297 | |
| 298 | // From |src|, grab one of "XYZW". Then, copy it to the target byte in |
| 299 | // |dst| (e.g., if x_src_ch=3, then grab "W" from |src|, and |dst| changes |
| 300 | // from "R0BA" to "RWBA"). |
| 301 | const int x_src = x / col_sampling_ratio; |
| 302 | const int x_src_ch = (x / ch_sampling_ratio) % 4; |
| 303 | dst[x] |= ((src[x_src] >> kShiftForChannel[x_src_ch]) & 0xff) |
| 304 | << output_shift; |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | // static |
| 310 | SkBitmap GLScalerTestUtil::CreateVerticallyFlippedBitmap( |
| 311 | const SkBitmap& source) { |
| 312 | SkBitmap bitmap; |
| 313 | bitmap.allocPixels(source.info()); |
| 314 | CHECK_EQ(bitmap.rowBytes(), source.rowBytes()); |
| 315 | for (int y = 0; y < bitmap.height(); ++y) { |
| 316 | const int src_y = bitmap.height() - y - 1; |
| 317 | memcpy(bitmap.getAddr32(0, y), source.getAddr32(0, src_y), |
| 318 | bitmap.rowBytes()); |
| 319 | } |
| 320 | return bitmap; |
| 321 | } |
| 322 | |
Yuri Wiitala | 8bac8fb | 2018-10-30 05:36:58 | [diff] [blame] | 323 | // static |
| 324 | SkBitmap GLScalerTestUtil::LoadPNGTestImage(const std::string& basename) { |
| 325 | base::FilePath test_dir; |
| 326 | if (!base::PathService::Get(Paths::DIR_TEST_DATA, &test_dir)) { |
| 327 | LOG(ERROR) << "Unable to get Paths::DIR_TEST_DATA from base::PathService."; |
| 328 | return SkBitmap(); |
| 329 | } |
| 330 | const auto source_file = test_dir.AppendASCII(basename); |
| 331 | SkBitmap as_n32; |
| 332 | if (!cc::ReadPNGFile(source_file, &as_n32)) { |
| 333 | return SkBitmap(); |
| 334 | } |
| 335 | SkBitmap as_rgba = |
| 336 | AllocateRGBABitmap(gfx::Size(as_n32.width(), as_n32.height())); |
| 337 | if (!as_n32.readPixels(SkPixmap(as_rgba.info(), as_rgba.getAddr(0, 0), |
| 338 | as_rgba.rowBytes()))) { |
| 339 | return SkBitmap(); |
| 340 | } |
| 341 | return as_rgba; |
| 342 | } |
| 343 | |
Yuri Wiitala | 0f30893 | 2018-09-13 19:45:22 | [diff] [blame] | 344 | // The area and color of the bars in a 1920x1080 HD SMPTE color bars test image |
| 345 | // (https://commons.wikimedia.org/wiki/File:SMPTE_Color_Bars_16x9.svg). The gray |
| 346 | // linear gradient bar is defined as half solid 0-level black and half solid |
| 347 | // full-intensity white). |
| 348 | const ColorBar GLScalerTestUtil::kSMPTEColorBars[30] = { |
| 349 | {{0, 0, 240, 630}, SkColorSetRGB(0x66, 0x66, 0x66)}, |
| 350 | {{240, 0, 445, 630}, SkColorSetRGB(0xbf, 0xbf, 0xbf)}, |
| 351 | {{445, 0, 651, 630}, SkColorSetRGB(0xbf, 0xbf, 0x00)}, |
| 352 | {{651, 0, 857, 630}, SkColorSetRGB(0x00, 0xbf, 0xbf)}, |
| 353 | {{857, 0, 1063, 630}, SkColorSetRGB(0x00, 0xbf, 0x00)}, |
| 354 | {{1063, 0, 1269, 630}, SkColorSetRGB(0xbf, 0x00, 0xbf)}, |
| 355 | {{1269, 0, 1475, 630}, SkColorSetRGB(0xbf, 0x00, 0x00)}, |
| 356 | {{1475, 0, 1680, 630}, SkColorSetRGB(0x00, 0x00, 0xbf)}, |
| 357 | {{1680, 0, 1920, 630}, SkColorSetRGB(0x66, 0x66, 0x66)}, |
| 358 | {{0, 630, 240, 720}, SkColorSetRGB(0x00, 0xff, 0xff)}, |
| 359 | {{240, 630, 445, 720}, SkColorSetRGB(0x00, 0x21, 0x4c)}, |
| 360 | {{445, 630, 1680, 720}, SkColorSetRGB(0xbf, 0xbf, 0xbf)}, |
| 361 | {{1680, 630, 1920, 720}, SkColorSetRGB(0x00, 0x00, 0xff)}, |
| 362 | {{0, 720, 240, 810}, SkColorSetRGB(0xff, 0xff, 0x00)}, |
| 363 | {{240, 720, 445, 810}, SkColorSetRGB(0x32, 0x00, 0x6a)}, |
| 364 | {{445, 720, 1063, 810}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 365 | {{1063, 720, 1680, 810}, SkColorSetRGB(0xff, 0xff, 0xff)}, |
| 366 | {{1680, 720, 1920, 810}, SkColorSetRGB(0xff, 0x00, 0x00)}, |
| 367 | {{0, 810, 240, 1080}, SkColorSetRGB(0x26, 0x26, 0x26)}, |
| 368 | {{240, 810, 549, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 369 | {{549, 810, 960, 1080}, SkColorSetRGB(0xff, 0xff, 0xff)}, |
| 370 | {{960, 810, 1131, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 371 | {{1131, 810, 1200, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 372 | {{1200, 810, 1268, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 373 | {{1268, 810, 1337, 1080}, SkColorSetRGB(0x05, 0x05, 0x05)}, |
| 374 | {{1337, 810, 1405, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 375 | {{1405, 810, 1474, 1080}, SkColorSetRGB(0x0a, 0x0a, 0x0a)}, |
| 376 | {{1474, 810, 1680, 1080}, SkColorSetRGB(0x00, 0x00, 0x00)}, |
| 377 | {{1680, 810, 1920, 1080}, SkColorSetRGB(0x26, 0x26, 0x26)}, |
| 378 | }; |
| 379 | |
| 380 | constexpr gfx::Size GLScalerTestUtil::kSMPTEFullSize; |
| 381 | |
| 382 | GLScalerTestTextureHelper::GLScalerTestTextureHelper( |
| 383 | gpu::gles2::GLES2Interface* gl) |
| 384 | : gl_(gl) { |
| 385 | CHECK(gl_); |
| 386 | } |
| 387 | |
| 388 | GLScalerTestTextureHelper::~GLScalerTestTextureHelper() { |
| 389 | gl_->DeleteTextures(textures_to_delete_.size(), textures_to_delete_.data()); |
| 390 | textures_to_delete_.clear(); |
| 391 | } |
| 392 | |
| 393 | GLuint GLScalerTestTextureHelper::CreateTexture(const gfx::Size& size) { |
| 394 | GLuint texture = 0; |
| 395 | gl_->GenTextures(1, &texture); |
| 396 | gl_->BindTexture(GL_TEXTURE_2D, texture); |
| 397 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 398 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 399 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 400 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 401 | gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, |
| 402 | GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| 403 | gl_->BindTexture(GL_TEXTURE_2D, 0); |
| 404 | |
| 405 | if (texture) { |
| 406 | textures_to_delete_.push_back(texture); |
| 407 | } |
| 408 | |
| 409 | return texture; |
| 410 | } |
| 411 | |
| 412 | GLuint GLScalerTestTextureHelper::UploadTexture(const SkBitmap& bitmap) { |
| 413 | CHECK_EQ(bitmap.colorType(), kRGBA_8888_SkColorType); |
| 414 | |
| 415 | GLuint texture = 0; |
| 416 | gl_->GenTextures(1, &texture); |
| 417 | gl_->BindTexture(GL_TEXTURE_2D, texture); |
| 418 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 419 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 420 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 421 | gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 422 | gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0, |
| 423 | GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getAddr32(0, 0)); |
| 424 | gl_->BindTexture(GL_TEXTURE_2D, 0); |
| 425 | |
| 426 | if (texture) { |
| 427 | textures_to_delete_.push_back(texture); |
| 428 | } |
| 429 | |
| 430 | return texture; |
| 431 | } |
| 432 | |
| 433 | SkBitmap GLScalerTestTextureHelper::DownloadTexture(GLuint texture, |
| 434 | const gfx::Size& size) { |
| 435 | GLuint framebuffer = 0; |
| 436 | gl_->GenFramebuffers(1, &framebuffer); |
| 437 | gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| 438 | gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 439 | texture, 0); |
| 440 | SkBitmap result = GLScalerTestUtil::AllocateRGBABitmap(size); |
| 441 | gl_->ReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE, |
| 442 | result.getAddr32(0, 0)); |
| 443 | gl_->DeleteFramebuffers(1, &framebuffer); |
| 444 | return result; |
| 445 | } |
| 446 | |
| 447 | } // namespace viz |