app_list: Fix sync animation crash.
[chromium-blink-merge.git] / ui / surface / accelerated_surface_transformer_win_unittest.cc
blob67460ad968eb1f6517c8d615506a3c63b7c835d3
1 // Copyright (c) 2013 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.
5 #include <d3d9.h>
6 #include <random>
8 #include "base/basictypes.h"
9 #include "base/file_util.h"
10 #include "base/hash.h"
11 #include "base/scoped_native_library.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/windows_version.h"
16 #include "media/base/simd/convert_rgb_to_yuv.h"
17 #include "media/base/yuv_convert.h"
18 #include "skia/ext/image_operations.h"
19 #include "testing/gtest/include/gtest/gtest-param-test.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/skia/include/core/SkColor.h"
23 #include "ui/gfx/codec/png_codec.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/surface/accelerated_surface_transformer_win.h"
26 #include "ui/surface/accelerated_surface_win.h"
27 #include "ui/surface/d3d9_utils_win.h"
29 namespace d3d_utils = ui_surface_d3d9_utils;
31 using base::win::ScopedComPtr;
32 using std::uniform_int_distribution;
34 namespace {
36 // Debug flag, useful when hacking on tests.
37 const bool kDumpImagesOnFailure = false;
39 SkBitmap ToSkBitmap(IDirect3DSurface9* surface, bool is_single_channel) {
40 D3DLOCKED_RECT locked_rect;
41 EXPECT_HRESULT_SUCCEEDED(
42 surface->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
44 SkBitmap result;
45 gfx::Size size = d3d_utils::GetSize(surface);
46 if (is_single_channel)
47 size = gfx::Size(size.width() * 4, size.height());
48 result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height(),
49 0, kOpaque_SkAlphaType);
50 result.allocPixels();
51 result.lockPixels();
52 for (int y = 0; y < size.height(); ++y) {
53 uint8* row8 = reinterpret_cast<uint8*>(locked_rect.pBits) +
54 (y * locked_rect.Pitch);
55 if (is_single_channel) {
56 for (int x = 0; x < size.width(); ++x) {
57 *result.getAddr32(x, y) = SkColorSetRGB(row8[x], row8[x], row8[x]);
59 } else {
60 uint32* row32 = reinterpret_cast<uint32*>(row8);
61 for (int x = 0; x < size.width(); ++x) {
62 *result.getAddr32(x, y) = row32[x] | 0xFF000000;
66 result.unlockPixels();
67 result.setImmutable();
68 surface->UnlockRect();
69 return result;
72 bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path) {
73 std::vector<unsigned char> png_data;
74 const bool discard_transparency = true;
75 if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
76 discard_transparency,
77 &png_data) &&
78 file_util::CreateDirectory(file_path.DirName())) {
79 char* data = reinterpret_cast<char*>(&png_data[0]);
80 int size = static_cast<int>(png_data.size());
81 return file_util::WriteFile(file_path, data, size) == size;
83 return false;
86 } // namespace
88 // Test fixture for AcceleratedSurfaceTransformer.
90 // This class is parameterized so that it runs only on Vista+. See
91 // WindowsVersionIfVistaOrBetter() for details on this works.
92 class AcceleratedSurfaceTransformerTest : public testing::TestWithParam<int> {
93 public:
94 AcceleratedSurfaceTransformerTest() : color_error_tolerance_(0) {};
96 IDirect3DDevice9Ex* device() { return device_.get(); }
98 virtual void SetUp() {
99 if (!d3d_module_.is_valid()) {
100 if (!d3d_utils::LoadD3D9(&d3d_module_)) {
101 GTEST_FAIL() << "Could not load d3d9.dll";
102 return;
105 if (!d3d_utils::CreateDevice(d3d_module_,
106 D3DDEVTYPE_HAL,
107 D3DPRESENT_INTERVAL_IMMEDIATE,
108 device_.Receive())) {
109 GTEST_FAIL() << "Could not create Direct3D device.";
110 return;
113 SeedRandom("default");
116 virtual void TearDown() {
117 device_ = NULL;
120 // Gets a human-readable identifier of the graphics hardware being used,
121 // intended for use inside of SCOPED_TRACE().
122 std::string GetAdapterInfo() {
123 ScopedComPtr<IDirect3D9> d3d;
124 EXPECT_HRESULT_SUCCEEDED(device()->GetDirect3D(d3d.Receive()));
125 D3DADAPTER_IDENTIFIER9 info;
126 EXPECT_HRESULT_SUCCEEDED(d3d->GetAdapterIdentifier(0, 0, &info));
127 return base::StringPrintf(
128 "Running on graphics hardware: %s", info.Description);
131 void SeedRandom(const char* seed) {
132 rng_.seed(base::Hash(seed));
133 random_dword_.reset();
136 // Driver workaround: on an Intel GPU (Mobile Intel 965 Express), it seems
137 // necessary to flush between drawing and locking, for the synchronization
138 // to behave properly.
139 void BeforeLockWorkaround() {
140 EXPECT_HRESULT_SUCCEEDED(
141 device()->Present(0, 0, 0, 0));
144 void WarnOnMissingFeatures(AcceleratedSurfaceTransformer* gpu_ops) {
145 // Prints a single warning line if some tests are feature-dependent
146 // and the feature is not supported by the current GPU.
147 if (!gpu_ops->device_supports_multiple_render_targets()) {
148 LOG(WARNING) << "MRT not supported, some tests will be skipped. "
149 << GetAdapterInfo();
153 // Locks and fills a surface with a checkerboard pattern where the colors
154 // are random but the total image pattern is horizontally and vertically
155 // symmetric.
156 void FillSymmetricRandomCheckerboard(
157 IDirect3DSurface9* lockable_surface,
158 const gfx::Size& size,
159 int checker_square_size) {
161 D3DLOCKED_RECT locked_rect;
162 ASSERT_HRESULT_SUCCEEDED(
163 lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD));
164 DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
165 ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
166 int pitch = locked_rect.Pitch / sizeof(DWORD);
168 for (int y = 0; y < (size.height() + 1) / 2; y += checker_square_size) {
169 for (int x = 0; x < (size.width() + 1) / 2; x += checker_square_size) {
170 DWORD color = RandomColor();
171 int y_limit = std::min(size.height() / 2, y + checker_square_size - 1);
172 int x_limit = std::min(size.width() / 2, x + checker_square_size - 1);
173 for (int y_lo = y; y_lo <= y_limit; y_lo++) {
174 for (int x_lo = x; x_lo <= x_limit; x_lo++) {
175 int y_hi = size.height() - 1 - y_lo;
176 int x_hi = size.width() - 1 - x_lo;
177 surface[x_lo + y_lo*pitch] = color;
178 surface[x_lo + y_hi*pitch] = color;
179 surface[x_hi + y_lo*pitch] = color;
180 surface[x_hi + y_hi*pitch] = color;
186 lockable_surface->UnlockRect();
189 void FillRandomCheckerboard(
190 IDirect3DSurface9* lockable_surface,
191 const gfx::Size& size,
192 int checker_square_size) {
194 D3DLOCKED_RECT locked_rect;
195 ASSERT_HRESULT_SUCCEEDED(
196 lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD));
197 DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
198 ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
199 int pitch = locked_rect.Pitch / sizeof(DWORD);
201 for (int y = 0; y <= size.height(); y += checker_square_size) {
202 for (int x = 0; x <= size.width(); x += checker_square_size) {
203 DWORD color = RandomColor();
204 int y_limit = std::min(size.height(), y + checker_square_size);
205 int x_limit = std::min(size.width(), x + checker_square_size);
206 for (int square_y = y; square_y < y_limit; square_y++) {
207 for (int square_x = x; square_x < x_limit; square_x++) {
208 surface[square_x + square_y*pitch] = color;
214 lockable_surface->UnlockRect();
217 // Approximate color-equality check. Allows for some rounding error.
218 bool AssertSameColor(DWORD color_a, DWORD color_b) {
219 if (color_a == color_b)
220 return true;
221 uint8* a = reinterpret_cast<uint8*>(&color_a);
222 uint8* b = reinterpret_cast<uint8*>(&color_b);
223 int max_error = 0;
224 for (int i = 0; i < 4; i++)
225 max_error = std::max(max_error,
226 std::abs(static_cast<int>(a[i]) - b[i]));
228 if (max_error <= color_error_tolerance())
229 return true;
231 std::string expected_color =
232 base::StringPrintf("%3d, %3d, %3d, %3d", a[0], a[1], a[2], a[3]);
233 std::string actual_color =
234 base::StringPrintf("%3d, %3d, %3d, %3d", b[0], b[1], b[2], b[3]);
235 EXPECT_EQ(expected_color, actual_color)
236 << "Componentwise color difference was "
237 << max_error << "; max allowed is " << color_error_tolerance();
239 return false;
242 bool AssertSameColor(uint8 color_a, uint8 color_b) {
243 if (color_a == color_b)
244 return true;
245 int max_error = std::abs((int) color_a - (int) color_b);
246 if (max_error <= color_error_tolerance())
247 return true;
248 ADD_FAILURE() << "Colors not equal: "
249 << base::StringPrintf("0x%x", color_a)
250 << " vs. " << base::StringPrintf("0x%x", color_b);
251 return false;
254 // Asserts that an image is symmetric with respect to itself: both
255 // horizontally and vertically, within the tolerance of AssertSameColor.
256 void AssertSymmetry(IDirect3DSurface9* lockable_surface,
257 const gfx::Size& size) {
258 BeforeLockWorkaround();
260 D3DLOCKED_RECT locked_rect;
261 ASSERT_HRESULT_SUCCEEDED(
262 lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
263 ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
264 int pitch = locked_rect.Pitch / sizeof(DWORD);
265 DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
266 for (int y_lo = 0; y_lo < size.height() / 2; y_lo++) {
267 int y_hi = size.height() - 1 - y_lo;
268 for (int x_lo = 0; x_lo < size.width() / 2; x_lo++) {
269 int x_hi = size.width() - 1 - x_lo;
270 if (!AssertSameColor(surface[x_lo + y_lo*pitch],
271 surface[x_hi + y_lo*pitch])) {
272 lockable_surface->UnlockRect();
273 GTEST_FAIL() << "Pixels (" << x_lo << ", " << y_lo << ") vs. "
274 << "(" << x_hi << ", " << y_lo << ")";
276 if (!AssertSameColor(surface[x_hi + y_lo*pitch],
277 surface[x_hi + y_hi*pitch])) {
278 lockable_surface->UnlockRect();
279 GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_lo << ") vs. "
280 << "(" << x_hi << ", " << y_hi << ")";
282 if (!AssertSameColor(surface[x_hi + y_hi*pitch],
283 surface[x_lo + y_hi*pitch])) {
284 lockable_surface->UnlockRect();
285 GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_hi << ") vs. "
286 << "(" << x_lo << ", " << y_hi << ")";
290 lockable_surface->UnlockRect();
293 // Asserts that the actual image is a bit-identical, vertically mirrored
294 // copy of the expected image.
295 void AssertIsInvertedCopy(const gfx::Size& size,
296 IDirect3DSurface9* expected,
297 IDirect3DSurface9* actual) {
298 BeforeLockWorkaround();
300 D3DLOCKED_RECT locked_expected, locked_actual;
301 ASSERT_HRESULT_SUCCEEDED(
302 expected->LockRect(&locked_expected, NULL, D3DLOCK_READONLY));
303 ASSERT_HRESULT_SUCCEEDED(
304 actual->LockRect(&locked_actual, NULL, D3DLOCK_READONLY));
305 ASSERT_EQ(0, locked_expected.Pitch % sizeof(DWORD));
306 int pitch = locked_expected.Pitch / sizeof(DWORD);
307 DWORD* expected_image = reinterpret_cast<DWORD*>(locked_expected.pBits);
308 DWORD* actual_image = reinterpret_cast<DWORD*>(locked_actual.pBits);
309 for (int y = 0; y < size.height(); y++) {
310 int y_actual = size.height() - 1 - y;
311 for (int x = 0; x < size.width(); ++x)
312 if (!AssertSameColor(expected_image[y*pitch + x],
313 actual_image[y_actual*pitch + x])) {
314 expected->UnlockRect();
315 actual->UnlockRect();
316 GTEST_FAIL() << "Pixels (" << x << ", " << y << ") vs. "
317 << "(" << x << ", " << y_actual << ")";
320 expected->UnlockRect();
321 actual->UnlockRect();
324 protected:
325 DWORD RandomColor() {
326 return random_dword_(rng_);
329 void set_color_error_tolerance(int value) {
330 color_error_tolerance_ = value;
333 int color_error_tolerance() {
334 return color_error_tolerance_;
337 void DoResizeBilinearTest(AcceleratedSurfaceTransformer* gpu_ops,
338 const gfx::Size& src_size,
339 const gfx::Size& dst_size,
340 int checkerboard_size) {
342 SCOPED_TRACE(
343 base::StringPrintf(
344 "Resizing %dx%d -> %dx%d at checkerboard size of %d",
345 src_size.width(), src_size.height(),
346 dst_size.width(), dst_size.height(),
347 checkerboard_size));
349 set_color_error_tolerance(4);
351 base::win::ScopedComPtr<IDirect3DSurface9> src, dst;
352 ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(
353 device(), src_size, &src))
354 << "Could not create src render target";
355 ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(
356 device(), dst_size, &dst))
357 << "Could not create dst render target";
359 FillSymmetricRandomCheckerboard(src, src_size, checkerboard_size);
361 ASSERT_TRUE(gpu_ops->ResizeBilinear(src, gfx::Rect(src_size), dst,
362 gfx::Rect(dst_size)));
364 AssertSymmetry(dst, dst_size);
367 void CreateRandomCheckerboardTexture(
368 const gfx::Size& size,
369 int checkerboard_size,
370 base::win::ScopedComPtr<IDirect3DSurface9>* reference_surface,
371 base::win::ScopedComPtr<IDirect3DTexture9>* result) {
372 base::win::ScopedComPtr<IDirect3DSurface9> dst;
373 ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(device(), size,
374 reference_surface));
375 ASSERT_TRUE(d3d_utils::CreateOrReuseRenderTargetTexture(device(), size,
376 result, dst.Receive()));
377 FillRandomCheckerboard(*reference_surface, size, checkerboard_size);
378 ASSERT_HRESULT_SUCCEEDED(
379 device()->StretchRect(
380 *reference_surface, NULL, dst, NULL, D3DTEXF_NONE));
383 void AssertSame(int width_in_bytes, int height, uint8* reference,
384 IDirect3DSurface9* lockable) {
385 BeforeLockWorkaround();
387 D3DLOCKED_RECT locked_rect;
388 ASSERT_HRESULT_SUCCEEDED(
389 lockable->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
390 uint8* actual = reinterpret_cast<uint8*>(locked_rect.pBits);
391 for (int y = 0; y < height; ++y) {
392 for (int x = 0; x < width_in_bytes; ++x) {
393 if (!AssertSameColor(reference[y * width_in_bytes + x],
394 actual[y * locked_rect.Pitch + x])) {
395 lockable->UnlockRect();
396 GTEST_FAIL() << "At pixel (" << x << ", " << y << ")";
400 lockable->UnlockRect();
403 void DoCopyInvertedTest(AcceleratedSurfaceTransformer* gpu_ops,
404 const gfx::Size& size) {
406 SCOPED_TRACE(base::StringPrintf(
407 "CopyInverted @ %dx%d", size.width(), size.height()));
409 set_color_error_tolerance(0);
411 base::win::ScopedComPtr<IDirect3DSurface9> dst, reference_pattern;
412 base::win::ScopedComPtr<IDirect3DTexture9> src;
414 CreateRandomCheckerboardTexture(size, 1, &reference_pattern, &src);
416 // Alloc a slightly larger image 75% of the time, to test that the
417 // viewport is set properly.
418 const int kAlign = 4;
419 gfx::Size alloc_size((size.width() + kAlign - 1) / kAlign * kAlign,
420 (size.height() + kAlign - 1) / kAlign * kAlign);
422 ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(device(), alloc_size,
423 &dst)) << "Could not create dst render target.";
425 ASSERT_TRUE(gpu_ops->CopyInverted(src, dst, size));
426 AssertIsInvertedCopy(size, reference_pattern, dst);
430 void DoYUVConversionTest(AcceleratedSurfaceTransformer* gpu_ops,
431 const gfx::Size& src_size,
432 int checkerboard_size) {
433 // Test the non-MRT implementation, and the MRT implementation as well
434 // (if supported by the device).
435 ASSERT_NO_FATAL_FAILURE(
436 DoYUVConversionTest(gpu_ops, src_size, src_size,
437 checkerboard_size, false));
438 if (gpu_ops->device_supports_multiple_render_targets()) {
439 ASSERT_NO_FATAL_FAILURE(
440 DoYUVConversionTest(gpu_ops, src_size, src_size,
441 checkerboard_size, true));
445 void DoYUVConversionScaleTest(AcceleratedSurfaceTransformer* gpu_ops,
446 const gfx::Size& src_size,
447 const gfx::Size& dst_size) {
448 // Test the non-MRT implementation, and the MRT implementation as well
449 // (if supported by the device).
450 if (gpu_ops->device_supports_multiple_render_targets()) {
451 ASSERT_NO_FATAL_FAILURE(
452 DoYUVConversionTest(gpu_ops, src_size, dst_size, 4, true));
454 ASSERT_NO_FATAL_FAILURE(
455 DoYUVConversionTest(gpu_ops, src_size, dst_size, 4, false));
458 void DoYUVConversionTest(AcceleratedSurfaceTransformer* gpu_ops,
459 const gfx::Size& src_size,
460 const gfx::Size& dst_size,
461 int checkerboard_size,
462 boolean use_multi_render_targets) {
463 SCOPED_TRACE(
464 base::StringPrintf(
465 "YUV Converting %dx%d at checkerboard size of %d; MRT %s",
466 src_size.width(), src_size.height(),
467 checkerboard_size,
468 use_multi_render_targets ? "enabled" : "disabled"));
471 base::win::ScopedComPtr<IDirect3DTexture9> src;
472 base::win::ScopedComPtr<IDirect3DSurface9> reference;
473 base::win::ScopedComPtr<IDirect3DSurface9> dst_y, dst_u, dst_v;
475 // TODO(ncarter): Use a better error metric that measures aggregate error
476 // rather than simply max error. There seems to be slightly more error at
477 // higher resolutions, maybe due to precision issues during rasterization
478 // (or maybe more pixels = more test trials). Results are usually to an
479 // error of 1, but we must use a tolerance of 3.
480 set_color_error_tolerance(3);
481 CreateRandomCheckerboardTexture(src_size, checkerboard_size, &reference,
482 &src);
484 gfx::Size packed_y_size, packed_uv_size;
486 ASSERT_TRUE(gpu_ops->AllocYUVBuffers(dst_size,
487 &packed_y_size,
488 &packed_uv_size,
489 dst_y.Receive(),
490 dst_u.Receive(),
491 dst_v.Receive()));
493 // Actually do the conversion.
494 if (use_multi_render_targets) {
495 ASSERT_TRUE(gpu_ops->TransformRGBToYV12_MRT(src,
496 dst_size,
497 packed_y_size,
498 packed_uv_size,
499 dst_y,
500 dst_u,
501 dst_v));
502 } else {
503 ASSERT_TRUE(gpu_ops->TransformRGBToYV12_WithoutMRT(src,
504 dst_size,
505 packed_y_size,
506 packed_uv_size,
507 dst_y,
508 dst_u,
509 dst_v));
512 // UV size (in bytes/samples) is half, rounded up.
513 gfx::Size uv_size((dst_size.width() + 1) / 2,
514 (dst_size.height() + 1) / 2);
516 // Generate a reference bitmap by calling a software implementation.
517 SkBitmap reference_rgb = ToSkBitmap(reference, false);
518 SkBitmap reference_rgb_scaled;
519 if (dst_size == src_size) {
520 reference_rgb_scaled = reference_rgb;
521 } else {
522 // We'll call Copy to do the bilinear scaling if needed.
523 base::win::ScopedComPtr<IDirect3DSurface9> reference_scaled;
524 ASSERT_TRUE(
525 d3d_utils::CreateOrReuseLockableSurface(
526 device(), dst_size, &reference_scaled));
527 ASSERT_TRUE(gpu_ops->Copy(src, reference_scaled, dst_size));
528 BeforeLockWorkaround();
529 reference_rgb_scaled = ToSkBitmap(reference_scaled, false);
532 scoped_ptr<uint8[]> reference_y(new uint8[dst_size.GetArea()]);
533 scoped_ptr<uint8[]> reference_u(new uint8[uv_size.GetArea()]);
534 scoped_ptr<uint8[]> reference_v(new uint8[uv_size.GetArea()]);
535 reference_rgb_scaled.lockPixels();
536 media::ConvertRGB32ToYUV_SSE2_Reference(
537 reinterpret_cast<uint8*>(reference_rgb_scaled.getAddr32(0, 0)),
538 &reference_y[0],
539 &reference_u[0],
540 &reference_v[0],
541 dst_size.width(),
542 dst_size.height(),
543 reference_rgb_scaled.rowBytes(),
544 dst_size.width(),
545 uv_size.width());
546 reference_rgb_scaled.unlockPixels();
548 // Check for equality of the reference and the actual.
549 AssertSame(dst_size.width(), dst_size.height(), &reference_y[0], dst_y);
550 AssertSame(uv_size.width(), uv_size.height(), &reference_u[0], dst_u);
551 AssertSame(uv_size.width(), uv_size.height(), &reference_v[0], dst_v);
553 if (kDumpImagesOnFailure && HasFatalFailure()) {
554 // Note that this will dump the full u and v buffers, including
555 // extra columns added due to packing. That means up to 7 extra
556 // columns for uv, and up to 3 extra columns for y.
557 WritePNGFile(reference_rgb,
558 base::FilePath(FILE_PATH_LITERAL("test_fail_src.png")));
559 WritePNGFile(reference_rgb_scaled,
560 base::FilePath(
561 FILE_PATH_LITERAL("test_fail_src_scaled.png")));
562 WritePNGFile(ToSkBitmap(dst_y, true),
563 base::FilePath(FILE_PATH_LITERAL("test_fail_y.png")));
564 WritePNGFile(ToSkBitmap(dst_u, true),
565 base::FilePath(FILE_PATH_LITERAL("test_fail_u.png")));
566 WritePNGFile(ToSkBitmap(dst_v, true),
567 base::FilePath(FILE_PATH_LITERAL("test_fail_v.png")));
571 int color_error_tolerance_;
572 uniform_int_distribution<DWORD> random_dword_;
573 std::mt19937 rng_;
574 base::ScopedNativeLibrary d3d_module_;
575 base::win::ScopedComPtr<IDirect3DDevice9Ex> device_;
578 // Fails on some bots because Direct3D isn't allowed.
579 TEST_P(AcceleratedSurfaceTransformerTest, Init) {
580 SCOPED_TRACE(GetAdapterInfo());
581 AcceleratedSurfaceTransformer gpu_ops;
582 ASSERT_TRUE(gpu_ops.Init(device()));
584 WarnOnMissingFeatures(&gpu_ops);
587 // Fails on some bots because Direct3D isn't allowed.
588 TEST_P(AcceleratedSurfaceTransformerTest, TestConsistentRandom) {
589 // This behavior should be the same for every execution on every machine.
590 // Otherwise tests might be flaky and impossible to debug.
591 SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom");
592 ASSERT_EQ(2922058934, RandomColor());
594 SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom");
595 ASSERT_EQ(2922058934, RandomColor());
596 ASSERT_EQ(4050239976, RandomColor());
598 SeedRandom("DifferentSeed");
599 ASSERT_EQ(3904108833, RandomColor());
602 // Fails on some bots because Direct3D isn't allowed.
603 TEST_P(AcceleratedSurfaceTransformerTest, CopyInverted) {
604 // This behavior should be the same for every execution on every machine.
605 // Otherwise tests might be flaky and impossible to debug.
606 SCOPED_TRACE(GetAdapterInfo());
607 SeedRandom("CopyInverted");
609 AcceleratedSurfaceTransformer t;
610 ASSERT_TRUE(t.Init(device()));
612 uniform_int_distribution<int> size(1, 512);
614 for (int i = 0; i < 100; ++i) {
615 ASSERT_NO_FATAL_FAILURE(
616 DoCopyInvertedTest(&t, gfx::Size(size(rng_), size(rng_))))
617 << "At iteration " << i;
621 // Fails on some bots because Direct3D isn't allowed.
622 // Fails on other bots because of ResizeBilinear symmetry failures.
623 // Should pass, at least, on NVIDIA Quadro 600.
624 TEST_P(AcceleratedSurfaceTransformerTest, MixedOperations) {
625 SCOPED_TRACE(GetAdapterInfo());
626 SeedRandom("MixedOperations");
628 AcceleratedSurfaceTransformer t;
629 ASSERT_TRUE(t.Init(device()));
631 ASSERT_NO_FATAL_FAILURE(
632 DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 1));
633 ASSERT_NO_FATAL_FAILURE(
634 DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 2));
635 ASSERT_NO_FATAL_FAILURE(
636 DoCopyInvertedTest(&t, gfx::Size(20, 107)));
637 ASSERT_NO_FATAL_FAILURE(
638 DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 5));
639 ASSERT_NO_FATAL_FAILURE(
640 DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(64, 64), 5));
641 ASSERT_NO_FATAL_FAILURE(
642 DoYUVConversionTest(&t, gfx::Size(128, 128), 1));
643 ASSERT_NO_FATAL_FAILURE(
644 DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(3, 3), 1));
645 ASSERT_NO_FATAL_FAILURE(
646 DoCopyInvertedTest(&t, gfx::Size(1412, 124)));
647 ASSERT_NO_FATAL_FAILURE(
648 DoYUVConversionTest(&t, gfx::Size(100, 200), 1));
649 ASSERT_NO_FATAL_FAILURE(
650 DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 1));
651 ASSERT_NO_FATAL_FAILURE(
652 DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 2));
654 ASSERT_NO_FATAL_FAILURE(
655 DoCopyInvertedTest(&t, gfx::Size(1512, 7)));
656 ASSERT_NO_FATAL_FAILURE(
657 DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 5));
658 ASSERT_NO_FATAL_FAILURE(
659 DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 8));
660 ASSERT_NO_FATAL_FAILURE(
661 DoCopyInvertedTest(&t, gfx::Size(1521, 3)));
662 ASSERT_NO_FATAL_FAILURE(
663 DoYUVConversionTest(&t, gfx::Size(140, 181), 1));
664 ASSERT_NO_FATAL_FAILURE(
665 DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 1));
666 ASSERT_NO_FATAL_FAILURE(
667 DoCopyInvertedTest(&t, gfx::Size(33, 712)));
668 ASSERT_NO_FATAL_FAILURE(
669 DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 8), 8));
670 ASSERT_NO_FATAL_FAILURE(
671 DoCopyInvertedTest(&t, gfx::Size(33, 2)));
672 ASSERT_NO_FATAL_FAILURE(
673 DoResizeBilinearTest(&t, gfx::Size(200, 256), gfx::Size(126, 8), 8));
676 // Tests ResizeBilinear with 16K wide/hight src and dst surfaces.
678 // Fails on some bots because Direct3D isn't allowed.
679 // Should pass, at least, on NVIDIA Quadro 600.
680 TEST_P(AcceleratedSurfaceTransformerTest, LargeSurfaces) {
681 SCOPED_TRACE(GetAdapterInfo());
682 SeedRandom("LargeSurfaces");
684 AcceleratedSurfaceTransformer gpu_ops;
685 ASSERT_TRUE(gpu_ops.Init(device()));
687 D3DCAPS9 caps;
688 ASSERT_HRESULT_SUCCEEDED(
689 device()->GetDeviceCaps(&caps));
691 SCOPED_TRACE(base::StringPrintf(
692 "max texture size: %dx%d, max texture aspect: %d",
693 caps.MaxTextureWidth, caps.MaxTextureHeight, caps.MaxTextureAspectRatio));
695 const int w = caps.MaxTextureWidth;
696 const int h = caps.MaxTextureHeight;
697 const int lo = 256;
699 ASSERT_NO_FATAL_FAILURE(
700 DoResizeBilinearTest(&gpu_ops, gfx::Size(w, lo), gfx::Size(lo, lo), 1));
701 ASSERT_NO_FATAL_FAILURE(
702 DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, h), gfx::Size(lo, lo), 1));
703 ASSERT_NO_FATAL_FAILURE(
704 DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(w, lo), lo));
705 ASSERT_NO_FATAL_FAILURE(
706 DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(lo, h), lo));
707 ASSERT_NO_FATAL_FAILURE(
708 DoCopyInvertedTest(&gpu_ops, gfx::Size(w, lo)));
709 ASSERT_NO_FATAL_FAILURE(
710 DoCopyInvertedTest(&gpu_ops, gfx::Size(lo, h)));
712 ASSERT_NO_FATAL_FAILURE(
713 DoYUVConversionTest(&gpu_ops, gfx::Size(w, lo), 1));
714 ASSERT_NO_FATAL_FAILURE(
715 DoYUVConversionTest(&gpu_ops, gfx::Size(lo, h), 1));
719 // Exercises ResizeBilinear with random minification cases where the
720 // aspect ratio does not change.
722 // Fails on some bots because Direct3D isn't allowed.
723 // Fails on other bots because of StretchRect symmetry failures.
724 // Should pass, at least, on NVIDIA Quadro 600.
725 TEST_P(AcceleratedSurfaceTransformerTest, MinifyUniform) {
726 SCOPED_TRACE(GetAdapterInfo());
727 SeedRandom("MinifyUniform");
729 AcceleratedSurfaceTransformer gpu_ops;
730 ASSERT_TRUE(gpu_ops.Init(device()));
732 const int dims[] = {21, 63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257};
733 const int checkerboards[] = {1, 2, 3, 9};
734 uniform_int_distribution<int> dim(0, arraysize(dims) - 1);
735 uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1);
737 for (int i = 0; i < 300; i++) {
738 // Widths are picked so that dst is smaller than src.
739 int dst_width = dims[dim(rng_)];
740 int src_width = dims[dim(rng_)];
741 if (src_width < dst_width)
742 std::swap(dst_width, src_width);
744 // src_height is picked to preserve aspect ratio.
745 int dst_height = dims[dim(rng_)];
746 int src_height = static_cast<int>(
747 static_cast<int64>(src_width) * dst_height / dst_width);
749 int checkerboard_size = checkerboards[checkerboard(rng_)];
751 ASSERT_NO_FATAL_FAILURE(
752 DoResizeBilinearTest(&gpu_ops,
753 gfx::Size(src_width, src_height), // Src size (larger)
754 gfx::Size(dst_width, dst_height), // Dst size (smaller)
755 checkerboard_size)) << "Failed on iteration " << i;
759 // Exercises ResizeBilinear with random magnification cases where the
760 // aspect ratio does not change.
762 // This test relies on an assertion that resizing preserves symmetry in the
763 // image, but for the current implementation of ResizeBilinear, this does not
764 // seem to be true (fails on NVIDIA Quadro 600; passes on
765 // Intel Mobile 965 Express)
766 TEST_P(AcceleratedSurfaceTransformerTest, DISABLED_MagnifyUniform) {
767 SCOPED_TRACE(GetAdapterInfo());
768 SeedRandom("MagnifyUniform");
770 AcceleratedSurfaceTransformer gpu_ops;
771 ASSERT_TRUE(gpu_ops.Init(device()));
773 const int dims[] = {63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257};
774 const int checkerboards[] = {1, 2, 3, 9};
775 uniform_int_distribution<int> dim(0, arraysize(dims) - 1);
776 uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1);
778 for (int i = 0; i < 50; i++) {
779 // Widths are picked so that src is smaller than dst.
780 int dst_width = dims[dim(rng_)];
781 int src_width = dims[dim(rng_)];
782 if (dst_width < src_width)
783 std::swap(src_width, dst_width);
785 int dst_height = dims[dim(rng_)];
786 int src_height = static_cast<int>(
787 static_cast<int64>(src_width) * dst_height / dst_width);
789 int checkerboard_size = checkerboards[checkerboard(rng_)];
791 ASSERT_NO_FATAL_FAILURE(
792 DoResizeBilinearTest(&gpu_ops,
793 gfx::Size(src_width, src_height), // Src size (smaller)
794 gfx::Size(dst_width, dst_height), // Dst size (larger)
795 checkerboard_size)) << "Failed on iteration " << i;
799 TEST_P(AcceleratedSurfaceTransformerTest, RGBtoYUV) {
800 SeedRandom("RGBtoYUV");
802 AcceleratedSurfaceTransformer gpu_ops;
803 ASSERT_TRUE(gpu_ops.Init(device()));
805 // Start with some easy-to-debug cases. A checkerboard size of 1 is the
806 // best test, but larger checkerboard sizes give more insight into where
807 // a bug might be.
808 ASSERT_NO_FATAL_FAILURE(
809 DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 4));
810 ASSERT_NO_FATAL_FAILURE(
811 DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 2));
812 ASSERT_NO_FATAL_FAILURE(
813 DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 3));
815 // All cases of width (mod 8) and height (mod 8), using 1x1 checkerboard.
816 for (int w = 32; w < 40; ++w) {
817 for (int h = 32; h < 40; ++h) {
818 ASSERT_NO_FATAL_FAILURE(
819 DoYUVConversionTest(&gpu_ops, gfx::Size(w, h), 1));
823 // All the very small sizes which require the most shifting in the
824 // texture coordinates when doing alignment.
825 for (int w = 1; w <= 9; ++w) {
826 for (int h = 1; h <= 9; ++h) {
827 ASSERT_NO_FATAL_FAILURE(
828 DoYUVConversionTest(&gpu_ops, gfx::Size(w, h), 1));
832 // Random medium dimensions.
833 ASSERT_NO_FATAL_FAILURE(
834 DoYUVConversionTest(&gpu_ops, gfx::Size(10, 142), 1));
835 ASSERT_NO_FATAL_FAILURE(
836 DoYUVConversionTest(&gpu_ops, gfx::Size(124, 333), 1));
837 ASSERT_NO_FATAL_FAILURE(
838 DoYUVConversionTest(&gpu_ops, gfx::Size(853, 225), 1));
839 ASSERT_NO_FATAL_FAILURE(
840 DoYUVConversionTest(&gpu_ops, gfx::Size(231, 412), 1));
841 ASSERT_NO_FATAL_FAILURE(
842 DoYUVConversionTest(&gpu_ops, gfx::Size(512, 128), 1));
843 ASSERT_NO_FATAL_FAILURE(
844 DoYUVConversionTest(&gpu_ops, gfx::Size(1024, 768), 1));
846 // Common video/monitor resolutions
847 ASSERT_NO_FATAL_FAILURE(
848 DoYUVConversionTest(&gpu_ops, gfx::Size(800, 768), 1));
849 ASSERT_NO_FATAL_FAILURE(
850 DoYUVConversionTest(&gpu_ops, gfx::Size(1024, 768), 1));
851 ASSERT_NO_FATAL_FAILURE(
852 DoYUVConversionTest(&gpu_ops, gfx::Size(1280, 720), 1));
853 ASSERT_NO_FATAL_FAILURE(
854 DoYUVConversionTest(&gpu_ops, gfx::Size(1280, 720), 2));
855 ASSERT_NO_FATAL_FAILURE(
856 DoYUVConversionTest(&gpu_ops, gfx::Size(1920, 1080), 1));
857 ASSERT_NO_FATAL_FAILURE(
858 DoYUVConversionTest(&gpu_ops, gfx::Size(1920, 1080), 2));
859 ASSERT_NO_FATAL_FAILURE(
860 DoYUVConversionTest(&gpu_ops, gfx::Size(2048, 1536), 1));
863 TEST_P(AcceleratedSurfaceTransformerTest, RGBtoYUVScaled) {
864 SeedRandom("RGBtoYUVScaled");
866 AcceleratedSurfaceTransformer gpu_ops;
867 ASSERT_TRUE(gpu_ops.Init(device()));
869 ASSERT_NO_FATAL_FAILURE(
870 DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(64, 64)));
872 ASSERT_NO_FATAL_FAILURE(
873 DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(16, 16)));
874 ASSERT_NO_FATAL_FAILURE(
875 DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(24, 24)));
876 ASSERT_NO_FATAL_FAILURE(
877 DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(48, 48)));
880 namespace {
882 // Used to suppress test on Windows versions prior to Vista.
883 std::vector<int> WindowsVersionIfVistaOrBetter() {
884 std::vector<int> result;
885 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
886 result.push_back(base::win::GetVersion());
888 return result;
891 } // namespace
893 INSTANTIATE_TEST_CASE_P(VistaAndUp,
894 AcceleratedSurfaceTransformerTest,
895 ::testing::ValuesIn(WindowsVersionIfVistaOrBetter()));