gl_helper_unittest.cc 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. // Copyright 2016 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. #include "gpu/command_buffer/client/gl_helper.h"
  5. #include <GLES2/gl2.h>
  6. #include <GLES2/gl2ext.h>
  7. #include <GLES2/gl2extchromium.h>
  8. #include <algorithm>
  9. #include <cmath>
  10. #include <memory>
  11. #include <string>
  12. #include <tuple>
  13. #include <utility>
  14. #include <vector>
  15. #include "base/bind.h"
  16. #include "base/cxx17_backports.h"
  17. #include "base/memory/raw_ptr.h"
  18. #include "base/memory/ref_counted_memory.h"
  19. #include "base/run_loop.h"
  20. #include "base/strings/stringprintf.h"
  21. #include "base/synchronization/waitable_event.h"
  22. #include "base/test/scoped_feature_list.h"
  23. #include "base/threading/thread_task_runner_handle.h"
  24. #include "build/build_config.h"
  25. #include "components/viz/test/test_gpu_service_holder.h"
  26. #include "gpu/command_buffer/client/gl_helper_scaling.h"
  27. #include "gpu/command_buffer/client/gles2_implementation.h"
  28. #include "gpu/command_buffer/client/shared_memory_limits.h"
  29. #include "gpu/ipc/gl_in_process_context.h"
  30. #include "testing/gtest/include/gtest/gtest.h"
  31. #include "third_party/skia/include/core/SkBitmap.h"
  32. #if !BUILDFLAG(IS_ANDROID)
  33. namespace gpu {
  34. namespace {
  35. GLHelper::ScalerQuality kQualities[] = {
  36. GLHelper::SCALER_QUALITY_BEST,
  37. GLHelper::SCALER_QUALITY_GOOD,
  38. GLHelper::SCALER_QUALITY_FAST,
  39. };
  40. const char* kQualityNames[] = {
  41. "best",
  42. "good",
  43. "fast",
  44. };
  45. } // namespace
  46. class GLHelperTest : public testing::Test {
  47. protected:
  48. void SetUp() override {
  49. feature_list_.Init();
  50. ContextCreationAttribs attributes;
  51. attributes.alpha_size = 8;
  52. attributes.depth_size = 24;
  53. attributes.red_size = 8;
  54. attributes.green_size = 8;
  55. attributes.blue_size = 8;
  56. attributes.stencil_size = 8;
  57. attributes.samples = 4;
  58. attributes.sample_buffers = 1;
  59. attributes.bind_generates_resource = false;
  60. context_ = std::make_unique<GLInProcessContext>();
  61. auto result = context_->Initialize(
  62. viz::TestGpuServiceHolder::GetInstance()->task_executor(), attributes,
  63. SharedMemoryLimits(), /*image_factory=*/nullptr);
  64. DCHECK_EQ(result, ContextResult::kSuccess);
  65. gl_ = context_->GetImplementation();
  66. ContextSupport* support = context_->GetImplementation();
  67. helper_ = std::make_unique<GLHelper>(gl_, support);
  68. helper_scaling_ = std::make_unique<GLHelperScaling>(gl_, helper_.get());
  69. }
  70. void TearDown() override {
  71. helper_scaling_.reset(nullptr);
  72. helper_.reset(nullptr);
  73. context_.reset(nullptr);
  74. }
  75. // Bicubic filter kernel function.
  76. static float Bicubic(float x) {
  77. const float a = -0.5;
  78. x = std::abs(x);
  79. float x2 = x * x;
  80. float x3 = x2 * x;
  81. if (x <= 1) {
  82. return (a + 2) * x3 - (a + 3) * x2 + 1;
  83. } else if (x < 2) {
  84. return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a;
  85. } else {
  86. return 0.0f;
  87. }
  88. }
  89. // Look up a single channel value. Works for 4-channel and single channel
  90. // bitmaps. Clamp x/y.
  91. int Channel(SkBitmap* pixels, int x, int y, int c) {
  92. if (pixels->bytesPerPixel() == 4) {
  93. uint32_t* data =
  94. pixels->getAddr32(base::clamp(x, 0, pixels->width() - 1),
  95. base::clamp(y, 0, pixels->height() - 1));
  96. return (*data) >> (c * 8) & 0xff;
  97. } else {
  98. DCHECK_EQ(pixels->bytesPerPixel(), 1);
  99. DCHECK_EQ(c, 0);
  100. return *pixels->getAddr8(base::clamp(x, 0, pixels->width() - 1),
  101. base::clamp(y, 0, pixels->height() - 1));
  102. }
  103. }
  104. // Set a single channel value. Works for 4-channel and single channel
  105. // bitmaps. Clamp x/y.
  106. void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) {
  107. DCHECK_GE(x, 0);
  108. DCHECK_GE(y, 0);
  109. DCHECK_LT(x, pixels->width());
  110. DCHECK_LT(y, pixels->height());
  111. if (pixels->bytesPerPixel() == 4) {
  112. uint32_t* data = pixels->getAddr32(x, y);
  113. v = base::clamp(v, 0, 255);
  114. *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8));
  115. } else {
  116. DCHECK_EQ(pixels->bytesPerPixel(), 1);
  117. DCHECK_EQ(c, 0);
  118. uint8_t* data = pixels->getAddr8(x, y);
  119. v = base::clamp(v, 0, 255);
  120. *data = v;
  121. }
  122. }
  123. // Print all the R, G, B or A values from an SkBitmap in a
  124. // human-readable format.
  125. void PrintChannel(SkBitmap* pixels, int c) {
  126. for (int y = 0; y < pixels->height(); y++) {
  127. std::string formatted;
  128. for (int x = 0; x < pixels->width(); x++) {
  129. formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c)));
  130. }
  131. LOG(ERROR) << formatted;
  132. }
  133. }
  134. // Print out the individual steps of a scaler pipeline.
  135. std::string PrintStages(
  136. const std::vector<GLHelperScaling::ScalerStage>& scaler_stages) {
  137. std::string ret;
  138. for (size_t i = 0; i < scaler_stages.size(); i++) {
  139. ret.append(base::StringPrintf(
  140. "%dx%d -> %dx%d ", scaler_stages[i].scale_from.x(),
  141. scaler_stages[i].scale_from.y(), scaler_stages[i].scale_to.x(),
  142. scaler_stages[i].scale_to.y()));
  143. bool xy_matters = false;
  144. switch (scaler_stages[i].shader) {
  145. case GLHelperScaling::SHADER_BILINEAR:
  146. ret.append("bilinear");
  147. break;
  148. case GLHelperScaling::SHADER_BILINEAR2:
  149. ret.append("bilinear2");
  150. xy_matters = true;
  151. break;
  152. case GLHelperScaling::SHADER_BILINEAR3:
  153. ret.append("bilinear3");
  154. xy_matters = true;
  155. break;
  156. case GLHelperScaling::SHADER_BILINEAR4:
  157. ret.append("bilinear4");
  158. xy_matters = true;
  159. break;
  160. case GLHelperScaling::SHADER_BILINEAR2X2:
  161. ret.append("bilinear2x2");
  162. break;
  163. case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
  164. ret.append("bicubic upscale");
  165. xy_matters = true;
  166. break;
  167. case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
  168. ret.append("bicubic 1/2");
  169. xy_matters = true;
  170. break;
  171. case GLHelperScaling::SHADER_PLANAR:
  172. ret.append("planar");
  173. break;
  174. case GLHelperScaling::SHADER_YUV_MRT_PASS1:
  175. ret.append("rgb2yuv pass 1");
  176. break;
  177. case GLHelperScaling::SHADER_YUV_MRT_PASS2:
  178. ret.append("rgb2yuv pass 2");
  179. break;
  180. }
  181. if (xy_matters) {
  182. if (scaler_stages[i].scale_x) {
  183. ret.append(" X");
  184. } else {
  185. ret.append(" Y");
  186. }
  187. }
  188. ret.append("\n");
  189. }
  190. return ret;
  191. }
  192. bool CheckScale(double scale, int samples, bool already_scaled) {
  193. // 1:1 is valid if there is one sample.
  194. if (samples == 1 && scale == 1.0) {
  195. return true;
  196. }
  197. // Is it an exact down-scale (50%, 25%, etc.?)
  198. if (scale == 2.0 * samples) {
  199. return true;
  200. }
  201. // Upscales, only valid if we haven't already scaled in this dimension.
  202. if (!already_scaled) {
  203. // Is it a valid bilinear upscale?
  204. if (samples == 1 && scale <= 1.0) {
  205. return true;
  206. }
  207. // Multi-sample upscale-downscale combination?
  208. if (scale > samples / 2.0 && scale < samples) {
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. // Make sure that the stages of the scaler pipeline are sane.
  215. void ValidateScalerStages(
  216. GLHelper::ScalerQuality quality,
  217. const std::vector<GLHelperScaling::ScalerStage>& scaler_stages,
  218. const gfx::Vector2d& overall_scale_from,
  219. const gfx::Vector2d& overall_scale_to,
  220. const std::string& message) {
  221. bool previous_error = HasFailure();
  222. // Used to verify that up-scales are not attempted after some
  223. // other scale.
  224. bool scaled_x = false;
  225. bool scaled_y = false;
  226. double combined_x_scale = 1.0;
  227. double combined_y_scale = 1.0;
  228. for (size_t i = 0; i < scaler_stages.size(); i++) {
  229. // Note: 2.0 means scaling down by 50%
  230. double x_scale = static_cast<double>(scaler_stages[i].scale_from.x()) /
  231. static_cast<double>(scaler_stages[i].scale_to.x());
  232. combined_x_scale *= x_scale;
  233. double y_scale = static_cast<double>(scaler_stages[i].scale_from.y()) /
  234. static_cast<double>(scaler_stages[i].scale_to.y());
  235. combined_y_scale *= y_scale;
  236. int x_samples = 0;
  237. int y_samples = 0;
  238. // Codify valid scale operations.
  239. switch (scaler_stages[i].shader) {
  240. case GLHelperScaling::SHADER_PLANAR:
  241. case GLHelperScaling::SHADER_YUV_MRT_PASS1:
  242. case GLHelperScaling::SHADER_YUV_MRT_PASS2:
  243. EXPECT_TRUE(false) << "Invalid shader.";
  244. break;
  245. case GLHelperScaling::SHADER_BILINEAR:
  246. if (quality != GLHelper::SCALER_QUALITY_FAST) {
  247. x_samples = 1;
  248. y_samples = 1;
  249. }
  250. break;
  251. case GLHelperScaling::SHADER_BILINEAR2:
  252. x_samples = 2;
  253. y_samples = 1;
  254. break;
  255. case GLHelperScaling::SHADER_BILINEAR3:
  256. x_samples = 3;
  257. y_samples = 1;
  258. break;
  259. case GLHelperScaling::SHADER_BILINEAR4:
  260. x_samples = 4;
  261. y_samples = 1;
  262. break;
  263. case GLHelperScaling::SHADER_BILINEAR2X2:
  264. x_samples = 2;
  265. y_samples = 2;
  266. break;
  267. case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
  268. if (scaler_stages[i].scale_x) {
  269. EXPECT_LT(x_scale, 1.0);
  270. EXPECT_EQ(y_scale, 1.0);
  271. } else {
  272. EXPECT_EQ(x_scale, 1.0);
  273. EXPECT_LT(y_scale, 1.0);
  274. }
  275. break;
  276. case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
  277. if (scaler_stages[i].scale_x) {
  278. EXPECT_EQ(x_scale, 2.0);
  279. EXPECT_EQ(y_scale, 1.0);
  280. } else {
  281. EXPECT_EQ(x_scale, 1.0);
  282. EXPECT_EQ(y_scale, 2.0);
  283. }
  284. break;
  285. }
  286. if (!scaler_stages[i].scale_x) {
  287. std::swap(x_samples, y_samples);
  288. }
  289. if (x_samples) {
  290. EXPECT_TRUE(CheckScale(x_scale, x_samples, scaled_x))
  291. << "x_scale = " << x_scale;
  292. }
  293. if (y_samples) {
  294. EXPECT_TRUE(CheckScale(y_scale, y_samples, scaled_y))
  295. << "y_scale = " << y_scale;
  296. }
  297. if (x_scale != 1.0) {
  298. scaled_x = true;
  299. }
  300. if (y_scale != 1.0) {
  301. scaled_y = true;
  302. }
  303. }
  304. const double expected_x_scale =
  305. static_cast<double>(overall_scale_from.x()) /
  306. static_cast<double>(overall_scale_to.x());
  307. const double expected_y_scale =
  308. static_cast<double>(overall_scale_from.y()) /
  309. static_cast<double>(overall_scale_to.y());
  310. EXPECT_NEAR(expected_x_scale, combined_x_scale, 1e-9);
  311. EXPECT_NEAR(expected_y_scale, combined_y_scale, 1e-9);
  312. if (HasFailure() && !previous_error) {
  313. LOG(ERROR) << "Invalid scaler stages: " << message;
  314. LOG(ERROR) << "Scaler stages:";
  315. LOG(ERROR) << PrintStages(scaler_stages);
  316. }
  317. }
  318. // Compares two bitmaps taking color types into account. Checks whether each
  319. // component of each pixel is no more than |maxdiff| apart. If bitmaps are not
  320. // similar enough, prints out |truth|, |other|, |source|, |scaler_stages|
  321. // and |message|.
  322. void Compare(SkBitmap* truth,
  323. SkBitmap* other,
  324. int maxdiff,
  325. SkBitmap* source,
  326. const std::vector<GLHelperScaling::ScalerStage>& scaler_stages,
  327. std::string message) {
  328. EXPECT_EQ(truth->width(), other->width());
  329. EXPECT_EQ(truth->height(), other->height());
  330. bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType &&
  331. other->colorType() == kBGRA_8888_SkColorType) ||
  332. (truth->colorType() == kBGRA_8888_SkColorType &&
  333. other->colorType() == kRGBA_8888_SkColorType);
  334. EXPECT_TRUE(swizzle || truth->colorType() == other->colorType());
  335. int bpp = truth->bytesPerPixel();
  336. for (int x = 0; x < truth->width(); x++) {
  337. for (int y = 0; y < truth->height(); y++) {
  338. for (int c = 0; c < bpp; c++) {
  339. int a = Channel(truth, x, y, c);
  340. // swizzle when comparing if needed
  341. int b = swizzle && (c == 0 || c == 2)
  342. ? Channel(other, x, y, (c + 2) & 2)
  343. : Channel(other, x, y, c);
  344. EXPECT_NEAR(a, b, maxdiff)
  345. << " x=" << x << " y=" << y << " c=" << c << " " << message;
  346. if (std::abs(a - b) > maxdiff) {
  347. LOG(ERROR) << "-------expected--------";
  348. for (int i = 0; i < bpp; i++) {
  349. LOG(ERROR) << "Channel " << i << ":";
  350. PrintChannel(truth, i);
  351. }
  352. LOG(ERROR) << "-------actual--------";
  353. for (int i = 0; i < bpp; i++) {
  354. LOG(ERROR) << "Channel " << i << ":";
  355. PrintChannel(other, i);
  356. }
  357. if (source) {
  358. LOG(ERROR) << "-------original--------";
  359. for (int i = 0; i < source->bytesPerPixel(); i++) {
  360. LOG(ERROR) << "Channel " << i << ":";
  361. PrintChannel(source, i);
  362. }
  363. }
  364. LOG(ERROR) << "-----Scaler stages------";
  365. LOG(ERROR) << PrintStages(scaler_stages);
  366. return;
  367. }
  368. }
  369. }
  370. }
  371. }
  372. // Get a single R, G, B or A value as a float.
  373. float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) {
  374. return Channel(pixels, x, y, c) / 255.0;
  375. }
  376. // Works like a GL_LINEAR lookup on an SkBitmap.
  377. float Bilinear(SkBitmap* pixels, float x, float y, int c) {
  378. x -= 0.5;
  379. y -= 0.5;
  380. int base_x = static_cast<int>(floorf(x));
  381. int base_y = static_cast<int>(floorf(y));
  382. x -= base_x;
  383. y -= base_y;
  384. return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) +
  385. ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) +
  386. ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y +
  387. ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y);
  388. }
  389. // Very slow bicubic / bilinear scaler for reference.
  390. void ScaleSlow(SkBitmap* input,
  391. const gfx::Rect& source_rect,
  392. GLHelper::ScalerQuality quality,
  393. SkBitmap* output) {
  394. float xscale = static_cast<float>(source_rect.width()) / output->width();
  395. float yscale = static_cast<float>(source_rect.height()) / output->height();
  396. float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale;
  397. float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale;
  398. for (int dst_y = 0; dst_y < output->height(); dst_y++) {
  399. for (int dst_x = 0; dst_x < output->width(); dst_x++) {
  400. for (int channel = 0; channel < 4; channel++) {
  401. float dst_x_in_src = source_rect.x() + (dst_x + 0.5f) * xscale;
  402. float dst_y_in_src = source_rect.y() + (dst_y + 0.5f) * yscale;
  403. float value = 0.0f;
  404. float sum = 0.0f;
  405. switch (quality) {
  406. case GLHelper::SCALER_QUALITY_BEST:
  407. for (int src_y = source_rect.y() - 10;
  408. src_y < source_rect.bottom() + 10; ++src_y) {
  409. float coeff_y =
  410. Bicubic((src_y + 0.5f - dst_y_in_src) * clamped_yscale);
  411. if (coeff_y == 0.0f) {
  412. continue;
  413. }
  414. for (int src_x = source_rect.x() - 10;
  415. src_x < source_rect.right() + 10; ++src_x) {
  416. float coeff =
  417. coeff_y *
  418. Bicubic((src_x + 0.5f - dst_x_in_src) * clamped_xscale);
  419. if (coeff == 0.0f) {
  420. continue;
  421. }
  422. sum += coeff;
  423. float c = ChannelAsFloat(input, src_x, src_y, channel);
  424. value += c * coeff;
  425. }
  426. }
  427. break;
  428. case GLHelper::SCALER_QUALITY_GOOD: {
  429. int xshift = 0, yshift = 0;
  430. while ((output->width() << xshift) < source_rect.width()) {
  431. xshift++;
  432. }
  433. while ((output->height() << yshift) < source_rect.height()) {
  434. yshift++;
  435. }
  436. int xmag = 1 << xshift;
  437. int ymag = 1 << yshift;
  438. if (xmag == 4 && output->width() * 3 >= source_rect.width()) {
  439. xmag = 3;
  440. }
  441. if (ymag == 4 && output->height() * 3 >= source_rect.height()) {
  442. ymag = 3;
  443. }
  444. for (int x = 0; x < xmag; x++) {
  445. for (int y = 0; y < ymag; y++) {
  446. value += Bilinear(input,
  447. source_rect.x() + (dst_x * xmag + x + 0.5) *
  448. xscale / xmag,
  449. source_rect.y() + (dst_y * ymag + y + 0.5) *
  450. yscale / ymag,
  451. channel);
  452. sum += 1.0;
  453. }
  454. }
  455. break;
  456. }
  457. case GLHelper::SCALER_QUALITY_FAST:
  458. value = Bilinear(input, dst_x_in_src, dst_y_in_src, channel);
  459. sum = 1.0;
  460. }
  461. value /= sum;
  462. SetChannel(output, dst_x, dst_y, channel,
  463. static_cast<int>(value * 255.0f + 0.5f));
  464. }
  465. }
  466. }
  467. }
  468. void FlipSKBitmap(SkBitmap* bitmap) {
  469. int bpp = bitmap->bytesPerPixel();
  470. DCHECK(bpp == 4 || bpp == 1);
  471. int top_line = 0;
  472. int bottom_line = bitmap->height() - 1;
  473. while (top_line < bottom_line) {
  474. for (int x = 0; x < bitmap->width(); x++) {
  475. bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line),
  476. *bitmap->getAddr32(x, bottom_line))
  477. : std::swap(*bitmap->getAddr8(x, top_line),
  478. *bitmap->getAddr8(x, bottom_line));
  479. }
  480. top_line++;
  481. bottom_line--;
  482. }
  483. }
  484. // gl_helper scales recursively, so we'll need to do that
  485. // in the reference implementation too.
  486. void ScaleSlowRecursive(SkBitmap* input,
  487. const gfx::Rect& source_rect,
  488. GLHelper::ScalerQuality quality,
  489. SkBitmap* output) {
  490. if (quality == GLHelper::SCALER_QUALITY_FAST ||
  491. quality == GLHelper::SCALER_QUALITY_GOOD) {
  492. ScaleSlow(input, source_rect, quality, output);
  493. return;
  494. }
  495. float xscale = static_cast<float>(output->width()) / source_rect.width();
  496. // This corresponds to all the operations we can do directly.
  497. float yscale = static_cast<float>(output->height()) / source_rect.height();
  498. if ((xscale == 1.0f && yscale == 1.0f) ||
  499. (xscale == 0.5f && yscale == 1.0f) ||
  500. (xscale == 1.0f && yscale == 0.5f) ||
  501. (xscale >= 1.0f && yscale == 1.0f) ||
  502. (xscale == 1.0f && yscale >= 1.0f)) {
  503. ScaleSlow(input, source_rect, quality, output);
  504. return;
  505. }
  506. // Now we break the problem down into smaller pieces, using the
  507. // operations available.
  508. int xtmp = source_rect.width();
  509. int ytmp = source_rect.height();
  510. if (output->height() != source_rect.height()) {
  511. ytmp = output->height();
  512. while (ytmp < source_rect.height() && ytmp * 2 != source_rect.height()) {
  513. ytmp += ytmp;
  514. }
  515. } else {
  516. xtmp = output->width();
  517. while (xtmp < source_rect.width() && xtmp * 2 != source_rect.width()) {
  518. xtmp += xtmp;
  519. }
  520. }
  521. // Note: The following does not account for scaler overscan. This was
  522. // attempted, but then unit test run time increased by a factor of 30!
  523. SkBitmap tmp;
  524. tmp.allocN32Pixels(xtmp, ytmp);
  525. ScaleSlowRecursive(input, source_rect, quality, &tmp);
  526. ScaleSlowRecursive(&tmp, gfx::Rect(0, 0, xtmp, ytmp), quality, output);
  527. }
  528. // Creates an RGBA SkBitmap with one of the pre-programmed test patterns. The
  529. // pattern starts at the given |origin|. For positions to the left or above
  530. // that point, values are filled-in corresponding to GL_CLAMP_TO_EDGE
  531. // behavior. This is because the reference scaler does not properly account
  532. // for overscan.
  533. std::unique_ptr<SkBitmap> CreateTestBitmap(const gfx::Size& size,
  534. const gfx::Point& origin,
  535. int test_pattern) {
  536. std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
  537. bitmap->allocPixels(SkImageInfo::Make(size.width(), size.height(),
  538. kRGBA_8888_SkColorType,
  539. kPremul_SkAlphaType));
  540. for (int x = 0; x < size.width(); ++x) {
  541. for (int y = 0; y < size.height(); ++y) {
  542. const int s = std::max(0, x - origin.x());
  543. const int t = std::max(0, y - origin.y());
  544. switch (test_pattern) {
  545. case 0: // Smooth test pattern
  546. SetChannel(bitmap.get(), x, y, 0, s * 10);
  547. SetChannel(bitmap.get(), x, y, 0, t == 0 ? s * 50 : s * 10);
  548. SetChannel(bitmap.get(), x, y, 1, t * 10);
  549. SetChannel(bitmap.get(), x, y, 2, (s + t) * 10);
  550. SetChannel(bitmap.get(), x, y, 3, 255);
  551. break;
  552. case 1: // Small blocks
  553. SetChannel(bitmap.get(), x, y, 0, s & 1 ? 255 : 0);
  554. SetChannel(bitmap.get(), x, y, 1, t & 1 ? 255 : 0);
  555. SetChannel(bitmap.get(), x, y, 2, (s + t) & 1 ? 255 : 0);
  556. SetChannel(bitmap.get(), x, y, 3, 255);
  557. break;
  558. case 2: // Medium blocks
  559. SetChannel(bitmap.get(), x, y, 0, 10 + s / 2 * 50);
  560. SetChannel(bitmap.get(), x, y, 1, 10 + t / 3 * 50);
  561. SetChannel(bitmap.get(), x, y, 2, (s + t) / 5 * 50 + 5);
  562. SetChannel(bitmap.get(), x, y, 3, 255);
  563. break;
  564. }
  565. }
  566. }
  567. return bitmap;
  568. }
  569. // Scaling test: Create a test image, scale it using GLHelperScaling
  570. // and a reference implementation and compare the results.
  571. void TestScale(const gfx::Rect& source_rect,
  572. const gfx::Size& scaled_size,
  573. int test_pattern,
  574. size_t quality_index,
  575. bool flip_output) {
  576. // The source texture is meant to be the contents of a framebuffer. Thus, it
  577. // includes (0,0), and all the way out to the lower-right corner of the
  578. // |source_rect|.
  579. const gfx::Size framebuffer_size(source_rect.right(), source_rect.bottom());
  580. std::unique_ptr<SkBitmap> input_pixels =
  581. CreateTestBitmap(framebuffer_size, source_rect.origin(), test_pattern);
  582. GLuint src_texture;
  583. gl_->GenTextures(1, &src_texture);
  584. gl_->BindTexture(GL_TEXTURE_2D, src_texture);
  585. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer_size.width(),
  586. framebuffer_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
  587. input_pixels->getPixels());
  588. std::string message = base::StringPrintf(
  589. "source rect: %s "
  590. "output size: %s "
  591. "pattern: %d quality: %s %s",
  592. source_rect.ToString().c_str(), scaled_size.ToString().c_str(),
  593. test_pattern, kQualityNames[quality_index],
  594. flip_output ? "flipout" : "noflipout");
  595. std::vector<GLHelperScaling::ScalerStage> stages;
  596. const auto scale_from =
  597. gfx::Vector2d(source_rect.width(), source_rect.height());
  598. const auto scale_to =
  599. gfx::Vector2d(scaled_size.width(), scaled_size.height());
  600. helper_scaling_->ComputeScalerStages(kQualities[quality_index], scale_from,
  601. scale_to, false, flip_output, false,
  602. &stages);
  603. ValidateScalerStages(kQualities[quality_index], stages, scale_from,
  604. scale_to, message);
  605. // Scale the source texture, producing the results in a new output
  606. // texture.
  607. std::unique_ptr<GLHelper::ScalerInterface> scaler =
  608. helper_->CreateScaler(kQualities[quality_index], scale_from, scale_to,
  609. false, flip_output, false);
  610. ASSERT_FALSE(scaler->IsSamplingFlippedSource());
  611. ASSERT_EQ(flip_output, scaler->IsFlippingOutput());
  612. GLuint dst_texture = 0;
  613. gl_->GenTextures(1, &dst_texture);
  614. gl_->BindTexture(GL_TEXTURE_2D, dst_texture);
  615. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, scaled_size.width(),
  616. scaled_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
  617. nullptr);
  618. scaler->Scale(src_texture, framebuffer_size, source_rect.OffsetFromOrigin(),
  619. dst_texture, gfx::Rect(scaled_size));
  620. SkBitmap output_pixels;
  621. output_pixels.allocPixels(
  622. SkImageInfo::Make(scaled_size.width(), scaled_size.height(),
  623. kRGBA_8888_SkColorType, kPremul_SkAlphaType));
  624. EXPECT_TRUE(
  625. ReadBackTexture(dst_texture, scaled_size,
  626. static_cast<unsigned char*>(output_pixels.getPixels()),
  627. kRGBA_8888_SkColorType));
  628. if (flip_output) {
  629. // Flip the pixels back.
  630. FlipSKBitmap(&output_pixels);
  631. }
  632. // If the bitmap shouldn't have changed - compare against input.
  633. if (source_rect == gfx::Rect(scaled_size)) {
  634. Compare(input_pixels.get(), &output_pixels, 0, nullptr, stages,
  635. message + " comparing against input");
  636. return;
  637. }
  638. // Now scale the bitmap using the reference implementation.
  639. SkBitmap truth_pixels;
  640. truth_pixels.allocPixels(
  641. SkImageInfo::Make(scaled_size.width(), scaled_size.height(),
  642. kRGBA_8888_SkColorType, kPremul_SkAlphaType));
  643. ScaleSlowRecursive(input_pixels.get(), source_rect,
  644. kQualities[quality_index], &truth_pixels);
  645. // Compare the results produced by the two implementations. Note that the
  646. // reference implementation does not fully account for overscan (see
  647. // comment in ScaleSlowRecursive()), and so the the maxdiff must be
  648. // increased when the bicubic scaler is being used.
  649. const int maxdiff = 2 + (quality_index == 0 ? (2 * stages.size()) : 0);
  650. Compare(&truth_pixels, &output_pixels, maxdiff, input_pixels.get(), stages,
  651. message + " comparing against scaled");
  652. gl_->DeleteTextures(1, &src_texture);
  653. gl_->DeleteTextures(1, &dst_texture);
  654. }
  655. // Scaling patching test: Scale an entire source image, and then scale various
  656. // subsets of the source image; and then confirm that the pixels in the
  657. // subsets exactly match their corresponding ones in the whole. This is
  658. // critical for use cases where the scaler only needs to render the changed
  659. // region of a source image.
  660. void TestScalePatching(const gfx::Vector2d& scale_from,
  661. const gfx::Vector2d& scale_to,
  662. int test_pattern,
  663. size_t quality_index,
  664. bool flipped_source) {
  665. // Generate a source texture representing copied-from-framebuffer content
  666. // with a test pattern that is twice the size of the "from" vector.
  667. const gfx::Size framebuffer_size(scale_from.x() * 2, scale_from.y() * 2);
  668. std::unique_ptr<SkBitmap> test_bitmap =
  669. CreateTestBitmap(framebuffer_size, gfx::Point(), test_pattern);
  670. if (flipped_source)
  671. FlipSKBitmap(test_bitmap.get());
  672. GLuint src_texture;
  673. gl_->GenTextures(1, &src_texture);
  674. gl_->BindTexture(GL_TEXTURE_2D, src_texture);
  675. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer_size.width(),
  676. framebuffer_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
  677. test_bitmap->getPixels());
  678. const std::unique_ptr<GLHelper::ScalerInterface> scaler =
  679. helper_->CreateScaler(kQualities[quality_index], scale_from, scale_to,
  680. flipped_source, false, false);
  681. ASSERT_EQ(flipped_source, scaler->IsSamplingFlippedSource());
  682. ASSERT_FALSE(scaler->IsFlippingOutput());
  683. // Note: These scaler stages are only being computed here for the benefit
  684. // Compare()'s error output messaging, below.
  685. std::vector<GLHelperScaling::ScalerStage> stages;
  686. helper_scaling_->ComputeScalerStages(kQualities[quality_index], scale_from,
  687. scale_to, flipped_source, false, false,
  688. &stages);
  689. // First, produce the entire output image, a full scan of the source to
  690. // produce all the output pixels. The output image is twice the size of the
  691. // "to" vector.
  692. GLuint dst_texture;
  693. gl_->GenTextures(1, &dst_texture);
  694. gl_->BindTexture(GL_TEXTURE_2D, dst_texture);
  695. const gfx::Size entire_output_size(scale_to.x() * 2, scale_to.y() * 2);
  696. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entire_output_size.width(),
  697. entire_output_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
  698. nullptr);
  699. scaler->Scale(src_texture, framebuffer_size, gfx::Vector2dF(), dst_texture,
  700. gfx::Rect(entire_output_size));
  701. SkBitmap entire_output;
  702. entire_output.allocPixels(SkImageInfo::Make(
  703. entire_output_size.width(), entire_output_size.height(),
  704. kRGBA_8888_SkColorType, kPremul_SkAlphaType));
  705. EXPECT_TRUE(
  706. ReadBackTexture(dst_texture, entire_output_size,
  707. static_cast<unsigned char*>(entire_output.getPixels()),
  708. kRGBA_8888_SkColorType));
  709. const std::string human_readable_test_params = base::StringPrintf(
  710. "scale from: %s "
  711. "scale to: %s "
  712. "pattern: %d quality: %s %s",
  713. scale_from.ToString().c_str(), scale_to.ToString().c_str(),
  714. test_pattern, kQualityNames[quality_index],
  715. flipped_source ? "flippedsource" : "");
  716. // Check the entire output image against the reference implementation.
  717. SkBitmap entire_output_ref;
  718. entire_output_ref.allocPixels(SkImageInfo::Make(
  719. entire_output_size.width(), entire_output_size.height(),
  720. kRGBA_8888_SkColorType, kPremul_SkAlphaType));
  721. ScaleSlowRecursive(test_bitmap.get(), gfx::Rect(framebuffer_size),
  722. kQualities[quality_index], &entire_output_ref);
  723. Compare(&entire_output_ref, &entire_output, 2, test_bitmap.get(), stages,
  724. human_readable_test_params + " ENTIRE OUTPUT");
  725. if (HasFailure())
  726. return;
  727. // Now, produce patches at various offsets and compare to the pixels in
  728. // |entire_output|.
  729. const gfx::Size patch_size(scale_to.x(), scale_to.y());
  730. gl_->BindTexture(GL_TEXTURE_2D, dst_texture);
  731. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, patch_size.width(),
  732. patch_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
  733. for (int xoffset = 0; xoffset < scale_to.x(); ++xoffset) {
  734. for (int yoffset = 0; yoffset < scale_to.y(); ++yoffset) {
  735. const gfx::Rect patch_rect(gfx::Point(xoffset, yoffset), patch_size);
  736. // First method of producing a patch: Scale from the same source texture
  737. // and just provide an offset output Rect.
  738. scaler->Scale(src_texture, framebuffer_size, gfx::Vector2dF(),
  739. dst_texture, patch_rect);
  740. SkBitmap patch_output;
  741. patch_output.allocPixels(
  742. SkImageInfo::Make(patch_size.width(), patch_size.height(),
  743. kRGBA_8888_SkColorType, kPremul_SkAlphaType));
  744. EXPECT_TRUE(ReadBackTexture(
  745. dst_texture, patch_size,
  746. static_cast<unsigned char*>(patch_output.getPixels()),
  747. kRGBA_8888_SkColorType));
  748. SkBitmap expected;
  749. SkIRect expected_subrect{patch_rect.x(), patch_rect.y(),
  750. patch_rect.right(), patch_rect.bottom()};
  751. if (flipped_source) {
  752. expected_subrect.fTop = entire_output.height() - patch_rect.bottom();
  753. expected_subrect.fBottom = entire_output.height() - patch_rect.y();
  754. }
  755. ASSERT_TRUE(entire_output.extractSubset(&expected, expected_subrect));
  756. Compare(&expected, &patch_output, 2, test_bitmap.get(), stages,
  757. "METHOD1 " + human_readable_test_params +
  758. " patch rect: " + patch_rect.ToString());
  759. if (HasFailure())
  760. return;
  761. // Second method of producing a patch: First copy just the "region of
  762. // influence" of the source texture, then produced a scaled image from
  763. // that.
  764. gfx::Rect sampling_rect;
  765. gfx::Vector2dF offset;
  766. scaler->ComputeRegionOfInfluence(framebuffer_size, gfx::Vector2dF(),
  767. patch_rect, &sampling_rect, &offset);
  768. // TODO(crbug.com/775740): Only test offsets having whole-numbered
  769. // coordinates until the scalers can account for the other case.
  770. if (offset.x() == std::floor(offset.x()) &&
  771. offset.y() == std::floor(offset.y())) {
  772. GLuint src_subset_texture;
  773. gl_->GenTextures(1, &src_subset_texture);
  774. gl_->BindTexture(GL_TEXTURE_2D, src_subset_texture);
  775. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sampling_rect.width(),
  776. sampling_rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
  777. nullptr);
  778. gl_->CopySubTextureCHROMIUM(
  779. src_texture, 0 /* source_level */, GL_TEXTURE_2D,
  780. src_subset_texture, 0 /* dest_level */, 0 /* xoffset */,
  781. 0 /* yoffset */, sampling_rect.x(), sampling_rect.y(),
  782. sampling_rect.width(), sampling_rect.height(), false, false,
  783. false);
  784. scaler->Scale(src_subset_texture, sampling_rect.size(), offset,
  785. dst_texture, gfx::Rect(patch_size));
  786. gl_->DeleteTextures(1, &src_subset_texture);
  787. EXPECT_TRUE(ReadBackTexture(
  788. dst_texture, patch_size,
  789. static_cast<unsigned char*>(patch_output.getPixels()),
  790. kRGBA_8888_SkColorType));
  791. Compare(&expected, &patch_output, 2, test_bitmap.get(), stages,
  792. "METHOD2 " + human_readable_test_params +
  793. " patch rect: " + patch_rect.ToString());
  794. if (HasFailure())
  795. return;
  796. }
  797. }
  798. }
  799. gl_->DeleteTextures(1, &src_texture);
  800. gl_->DeleteTextures(1, &dst_texture);
  801. }
  802. // Create a scaling pipeline and check that it is made up of
  803. // valid scaling operations.
  804. void TestScalerPipeline(size_t quality,
  805. int xsize,
  806. int ysize,
  807. int dst_xsize,
  808. int dst_ysize) {
  809. std::vector<GLHelperScaling::ScalerStage> stages;
  810. helper_scaling_->ComputeScalerStages(
  811. kQualities[quality], gfx::Vector2d(xsize, ysize),
  812. gfx::Vector2d(dst_xsize, dst_ysize), false, false, false, &stages);
  813. ValidateScalerStages(kQualities[quality], stages,
  814. gfx::Vector2d(xsize, ysize),
  815. gfx::Vector2d(dst_xsize, dst_ysize),
  816. base::StringPrintf("input size: %dx%d "
  817. "output size: %dx%d "
  818. "quality: %s",
  819. xsize, ysize, dst_xsize, dst_ysize,
  820. kQualityNames[quality]));
  821. }
  822. // Create a scaling pipeline and make sure that the steps
  823. // are exactly the steps we expect.
  824. void CheckPipeline(GLHelper::ScalerQuality quality,
  825. int xsize,
  826. int ysize,
  827. int dst_xsize,
  828. int dst_ysize,
  829. const std::string& description) {
  830. std::vector<GLHelperScaling::ScalerStage> stages;
  831. helper_scaling_->ComputeScalerStages(quality, gfx::Vector2d(xsize, ysize),
  832. gfx::Vector2d(dst_xsize, dst_ysize),
  833. false, false, false, &stages);
  834. ValidateScalerStages(GLHelper::SCALER_QUALITY_GOOD, stages,
  835. gfx::Vector2d(xsize, ysize),
  836. gfx::Vector2d(dst_xsize, dst_ysize), "");
  837. EXPECT_EQ(PrintStages(stages), description);
  838. }
  839. void DrawGridToBitmap(int w,
  840. int h,
  841. SkColor background_color,
  842. SkColor grid_color,
  843. int grid_pitch,
  844. int grid_width,
  845. const SkBitmap& bmp) {
  846. ASSERT_GT(grid_pitch, 0);
  847. ASSERT_GT(grid_width, 0);
  848. ASSERT_NE(background_color, grid_color);
  849. for (int y = 0; y < h; ++y) {
  850. bool y_on_grid = ((y % grid_pitch) < grid_width);
  851. for (int x = 0; x < w; ++x) {
  852. bool on_grid = (y_on_grid || ((x % grid_pitch) < grid_width));
  853. *bmp.getAddr32(x, y) = (on_grid ? grid_color : background_color);
  854. }
  855. }
  856. }
  857. void DrawCheckerToBitmap(int w,
  858. int h,
  859. SkColor color1,
  860. SkColor color2,
  861. int rect_w,
  862. int rect_h,
  863. const SkBitmap& bmp) {
  864. ASSERT_GT(rect_w, 0);
  865. ASSERT_GT(rect_h, 0);
  866. ASSERT_NE(color1, color2);
  867. for (int y = 0; y < h; ++y) {
  868. bool y_bit = (((y / rect_h) & 0x1) == 0);
  869. for (int x = 0; x < w; ++x) {
  870. bool x_bit = (((x / rect_w) & 0x1) == 0);
  871. bool use_color2 = (x_bit != y_bit); // xor
  872. *bmp.getAddr32(x, y) = (use_color2 ? color2 : color1);
  873. }
  874. }
  875. }
  876. bool ColorComponentsClose(SkColor component1, SkColor component2) {
  877. int c1 = static_cast<int>(component1);
  878. int c2 = static_cast<int>(component2);
  879. return (std::abs(c1 - c2) == 0);
  880. }
  881. bool ColorsClose(SkColor color1, SkColor color2) {
  882. bool red = ColorComponentsClose(SkColorGetR(color1), SkColorGetR(color2));
  883. bool green = ColorComponentsClose(SkColorGetG(color1), SkColorGetG(color2));
  884. bool blue = ColorComponentsClose(SkColorGetB(color1), SkColorGetB(color2));
  885. bool alpha = ColorComponentsClose(SkColorGetA(color1), SkColorGetA(color2));
  886. return red && blue && green && alpha;
  887. }
  888. bool IsEqual(const SkBitmap& bmp1, const SkBitmap& bmp2) {
  889. if (bmp1.isNull() && bmp2.isNull())
  890. return true;
  891. if (bmp1.width() != bmp2.width() || bmp1.height() != bmp2.height()) {
  892. LOG(ERROR) << "Bitmap geometry check failure";
  893. return false;
  894. }
  895. if (bmp1.colorType() != bmp2.colorType())
  896. return false;
  897. if (!bmp1.getPixels() || !bmp2.getPixels()) {
  898. LOG(ERROR) << "Empty Bitmap!";
  899. return false;
  900. }
  901. for (int y = 0; y < bmp1.height(); ++y) {
  902. for (int x = 0; x < bmp1.width(); ++x) {
  903. if (!ColorsClose(bmp1.getColor(x, y), bmp2.getColor(x, y))) {
  904. LOG(ERROR) << "Bitmap color comparison failure";
  905. return false;
  906. }
  907. }
  908. }
  909. return true;
  910. }
  911. void BindAndAttachTextureWithPixels(GLuint src_texture,
  912. SkColorType color_type,
  913. const gfx::Size& src_size,
  914. const SkBitmap& input_pixels) {
  915. gl_->BindTexture(GL_TEXTURE_2D, src_texture);
  916. const GLenum format =
  917. (color_type == kBGRA_8888_SkColorType) ? GL_BGRA_EXT : GL_RGBA;
  918. gl_->TexImage2D(GL_TEXTURE_2D, 0, format, src_size.width(),
  919. src_size.height(), 0, format, GL_UNSIGNED_BYTE,
  920. input_pixels.getPixels());
  921. }
  922. bool ReadBackTexture(GLuint src_texture,
  923. const gfx::Size& src_size,
  924. unsigned char* pixels,
  925. SkColorType color_type) {
  926. DCHECK(color_type == kRGBA_8888_SkColorType ||
  927. color_type == kBGRA_8888_SkColorType);
  928. base::RunLoop run_loop;
  929. bool success = false;
  930. GLenum format;
  931. if (color_type == kRGBA_8888_SkColorType)
  932. format = GL_RGBA;
  933. else
  934. format = GL_BGRA_EXT;
  935. helper_->ReadbackTextureAsync(
  936. src_texture, GL_TEXTURE_2D, src_size, pixels, format,
  937. base::BindOnce(
  938. [](bool* success, base::OnceClosure callback, bool result) {
  939. *success = result;
  940. std::move(callback).Run();
  941. },
  942. &success, run_loop.QuitClosure()));
  943. run_loop.Run();
  944. return success;
  945. }
  946. // Test basic format readback.
  947. bool TestTextureFormatReadback(const gfx::Size& src_size,
  948. SkColorType color_type) {
  949. SkImageInfo info = SkImageInfo::Make(src_size.width(), src_size.height(),
  950. color_type, kPremul_SkAlphaType);
  951. GLuint src_texture;
  952. gl_->GenTextures(1, &src_texture);
  953. SkBitmap input_pixels;
  954. input_pixels.allocPixels(info);
  955. // Test Pattern-1, Fill with Plain color pattern.
  956. // Erase the input bitmap with red color.
  957. input_pixels.eraseColor(SK_ColorRED);
  958. BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
  959. input_pixels);
  960. SkBitmap output_pixels;
  961. output_pixels.allocPixels(info);
  962. // Initialize the output bitmap with Green color.
  963. // When the readback is over output bitmap should have the red color.
  964. output_pixels.eraseColor(SK_ColorGREEN);
  965. uint8_t* pixels = static_cast<uint8_t*>(output_pixels.getPixels());
  966. if (!ReadBackTexture(src_texture, src_size, pixels, color_type) ||
  967. !IsEqual(input_pixels, output_pixels)) {
  968. LOG(ERROR) << "Bitmap comparison failure Pattern-1";
  969. return false;
  970. }
  971. const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4;
  972. const SkColor color1 = SK_ColorRED, color2 = SK_ColorBLUE;
  973. // Test Pattern-2, Fill with Grid Pattern.
  974. DrawGridToBitmap(src_size.width(), src_size.height(), color2, color1,
  975. src_grid_pitch, src_grid_width, input_pixels);
  976. BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
  977. input_pixels);
  978. if (!ReadBackTexture(src_texture, src_size, pixels, color_type) ||
  979. !IsEqual(input_pixels, output_pixels)) {
  980. LOG(ERROR) << "Bitmap comparison failure Pattern-2";
  981. return false;
  982. }
  983. // Test Pattern-3, Fill with CheckerBoard Pattern.
  984. DrawCheckerToBitmap(src_size.width(), src_size.height(), color1, color2,
  985. rect_w, rect_h, input_pixels);
  986. BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
  987. input_pixels);
  988. if (!ReadBackTexture(src_texture, src_size, pixels, color_type) ||
  989. !IsEqual(input_pixels, output_pixels)) {
  990. LOG(ERROR) << "Bitmap comparison failure Pattern-3";
  991. return false;
  992. }
  993. gl_->DeleteTextures(1, &src_texture);
  994. if (HasFailure()) {
  995. return false;
  996. }
  997. return true;
  998. }
  999. void TestAddOps(int src, int dst, bool scale_x, bool allow3) {
  1000. base::circular_deque<GLHelperScaling::ScaleOp> ops;
  1001. GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
  1002. // Scale factor 3 is a special case.
  1003. // It is currently only allowed by itself.
  1004. if (allow3 && dst * 3 >= src && dst * 2 < src) {
  1005. EXPECT_EQ(ops[0].scale_factor, 3);
  1006. EXPECT_EQ(ops.size(), 1U);
  1007. EXPECT_EQ(ops[0].scale_x, scale_x);
  1008. EXPECT_EQ(ops[0].scale_size, dst);
  1009. return;
  1010. }
  1011. for (size_t i = 0; i < ops.size(); i++) {
  1012. EXPECT_EQ(ops[i].scale_x, scale_x);
  1013. if (i == 0) {
  1014. // Only the first op is allowed to be a scale up.
  1015. // (Scaling up *after* scaling down would make it fuzzy.)
  1016. EXPECT_TRUE(ops[0].scale_factor == 0 || ops[0].scale_factor == 2);
  1017. } else {
  1018. // All other operations must be 50% downscales.
  1019. EXPECT_EQ(ops[i].scale_factor, 2);
  1020. }
  1021. }
  1022. // Check that the scale factors make sense and add up.
  1023. int tmp = dst;
  1024. for (int i = static_cast<int>(ops.size() - 1); i >= 0; i--) {
  1025. EXPECT_EQ(tmp, ops[i].scale_size);
  1026. if (ops[i].scale_factor == 0) {
  1027. EXPECT_EQ(i, 0);
  1028. EXPECT_GT(tmp, src);
  1029. tmp = src;
  1030. } else {
  1031. tmp *= ops[i].scale_factor;
  1032. }
  1033. }
  1034. EXPECT_EQ(tmp, src);
  1035. }
  1036. void CheckPipeline2(int xsize,
  1037. int ysize,
  1038. int dst_xsize,
  1039. int dst_ysize,
  1040. const std::string& description) {
  1041. std::vector<GLHelperScaling::ScalerStage> stages;
  1042. helper_scaling_->ConvertScalerOpsToScalerStages(
  1043. GLHelper::SCALER_QUALITY_GOOD, gfx::Vector2d(xsize, ysize), &x_ops_,
  1044. &y_ops_, &stages);
  1045. EXPECT_EQ(x_ops_.size(), 0U);
  1046. EXPECT_EQ(y_ops_.size(), 0U);
  1047. ValidateScalerStages(GLHelper::SCALER_QUALITY_GOOD, stages,
  1048. gfx::Vector2d(xsize, ysize),
  1049. gfx::Vector2d(dst_xsize, dst_ysize), "");
  1050. EXPECT_EQ(PrintStages(stages), description);
  1051. }
  1052. void CheckOptimizationsTest() {
  1053. // Basic upscale. X and Y should be combined into one pass.
  1054. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
  1055. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
  1056. CheckPipeline2(1024, 768, 2000, 2000, "1024x768 -> 2000x2000 bilinear\n");
  1057. // X scaled 1/2, Y upscaled, should still be one pass.
  1058. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
  1059. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
  1060. CheckPipeline2(1024, 768, 512, 2000, "1024x768 -> 512x2000 bilinear\n");
  1061. // X upscaled, Y scaled 1/2, one bilinear pass
  1062. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
  1063. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
  1064. CheckPipeline2(1024, 768, 2000, 384, "1024x768 -> 2000x384 bilinear\n");
  1065. // X scaled 1/2, Y scaled 1/2, one bilinear pass
  1066. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
  1067. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
  1068. CheckPipeline2(1024, 768, 512, 384, "1024x768 -> 512x384 bilinear\n");
  1069. // X scaled 1/2, Y scaled to 60%, one bilinear2 pass.
  1070. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
  1071. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1072. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1073. CheckPipeline2(100, 100, 50, 60, "100x100 -> 50x60 bilinear2 Y\n");
  1074. // X scaled to 60%, Y scaled 1/2, one bilinear2 pass.
  1075. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
  1076. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
  1077. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 50));
  1078. CheckPipeline2(100, 100, 60, 50, "100x100 -> 60x50 bilinear2 X\n");
  1079. // X scaled to 60%, Y scaled 60%, one bilinear2x2 pass.
  1080. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
  1081. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
  1082. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1083. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1084. CheckPipeline2(100, 100, 60, 60, "100x100 -> 60x60 bilinear2x2\n");
  1085. // X scaled to 40%, Y scaled 40%, two bilinear3 passes.
  1086. x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
  1087. y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
  1088. CheckPipeline2(100, 100, 40, 40,
  1089. "100x100 -> 100x40 bilinear3 Y\n"
  1090. "100x40 -> 40x40 bilinear3 X\n");
  1091. // X scaled to 60%, Y scaled 40%
  1092. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
  1093. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
  1094. y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
  1095. CheckPipeline2(100, 100, 60, 40,
  1096. "100x100 -> 100x40 bilinear3 Y\n"
  1097. "100x40 -> 60x40 bilinear2 X\n");
  1098. // X scaled to 40%, Y scaled 60%
  1099. x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
  1100. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1101. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1102. CheckPipeline2(100, 100, 40, 60,
  1103. "100x100 -> 100x60 bilinear2 Y\n"
  1104. "100x60 -> 40x60 bilinear3 X\n");
  1105. // X scaled to 30%, Y scaled 30%
  1106. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
  1107. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
  1108. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 30));
  1109. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1110. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1111. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
  1112. CheckPipeline2(100, 100, 30, 30,
  1113. "100x100 -> 100x30 bilinear4 Y\n"
  1114. "100x30 -> 30x30 bilinear4 X\n");
  1115. // X scaled to 50%, Y scaled 30%
  1116. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
  1117. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1118. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1119. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
  1120. CheckPipeline2(100, 100, 50, 30, "100x100 -> 50x30 bilinear4 Y\n");
  1121. // X scaled to 150%, Y scaled 30%
  1122. // Note that we avoid combinding X and Y passes
  1123. // as that would probably be LESS efficient here.
  1124. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 150));
  1125. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
  1126. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
  1127. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
  1128. CheckPipeline2(100, 100, 150, 30,
  1129. "100x100 -> 100x30 bilinear4 Y\n"
  1130. "100x30 -> 150x30 bilinear\n");
  1131. // X scaled to 1%, Y scaled 1%
  1132. x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 128));
  1133. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 64));
  1134. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 32));
  1135. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 16));
  1136. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 8));
  1137. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 4));
  1138. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 2));
  1139. x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 1));
  1140. y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 128));
  1141. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 64));
  1142. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 32));
  1143. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 16));
  1144. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 8));
  1145. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 4));
  1146. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 2));
  1147. y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 1));
  1148. CheckPipeline2(100, 100, 1, 1,
  1149. "100x100 -> 100x32 bilinear4 Y\n"
  1150. "100x32 -> 100x4 bilinear4 Y\n"
  1151. "100x4 -> 64x1 bilinear2x2\n"
  1152. "64x1 -> 8x1 bilinear4 X\n"
  1153. "8x1 -> 1x1 bilinear4 X\n");
  1154. }
  1155. base::test::ScopedFeatureList feature_list_;
  1156. std::unique_ptr<GLInProcessContext> context_;
  1157. raw_ptr<gles2::GLES2Interface> gl_;
  1158. std::unique_ptr<GLHelper> helper_;
  1159. std::unique_ptr<GLHelperScaling> helper_scaling_;
  1160. base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
  1161. };
  1162. class GLHelperPixelTest : public GLHelperTest {
  1163. private:
  1164. gl::DisableNullDrawGLBindings enable_pixel_output_;
  1165. };
  1166. TEST_F(GLHelperTest, RGBAASyncReadbackTest) {
  1167. const int kTestSize = 64;
  1168. bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
  1169. kRGBA_8888_SkColorType);
  1170. EXPECT_EQ(result, true);
  1171. }
  1172. TEST_F(GLHelperTest, BGRAASyncReadbackTest) {
  1173. const int kTestSize = 64;
  1174. bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
  1175. kBGRA_8888_SkColorType);
  1176. EXPECT_EQ(result, true);
  1177. }
  1178. int kRGBReadBackSizes[] = {3, 6, 16};
  1179. class GLHelperPixelReadbackTest
  1180. : public GLHelperPixelTest,
  1181. public ::testing::WithParamInterface<std::tuple<unsigned int,
  1182. unsigned int,
  1183. unsigned int,
  1184. unsigned int,
  1185. unsigned int>> {};
  1186. // Per pixel tests, all sizes are small so that we can print
  1187. // out the generated bitmaps.
  1188. TEST_P(GLHelperPixelReadbackTest, ScaleTest) {
  1189. unsigned int q_index = std::get<0>(GetParam());
  1190. unsigned int x = std::get<1>(GetParam());
  1191. unsigned int y = std::get<2>(GetParam());
  1192. unsigned int dst_x = std::get<3>(GetParam());
  1193. unsigned int dst_y = std::get<4>(GetParam());
  1194. for (int flip_output = 0; flip_output <= 1; ++flip_output) {
  1195. for (int pattern = 0; pattern < 3; ++pattern) {
  1196. for (int xoffset = 0; xoffset < 4; ++xoffset) {
  1197. for (int yoffset = 0; yoffset < 4; ++yoffset) {
  1198. TestScale(
  1199. gfx::Rect(xoffset, yoffset, kRGBReadBackSizes[x],
  1200. kRGBReadBackSizes[y]),
  1201. gfx::Size(kRGBReadBackSizes[dst_x], kRGBReadBackSizes[dst_y]),
  1202. pattern, q_index, !!flip_output);
  1203. if (HasFailure()) {
  1204. return;
  1205. }
  1206. }
  1207. }
  1208. }
  1209. }
  1210. }
  1211. // FLAKY: https://crbug.com/871799
  1212. TEST_P(GLHelperPixelReadbackTest, DISABLED_ScalePatching) {
  1213. for (int flipped_source = 0; flipped_source <= 1; ++flipped_source) {
  1214. for (int pattern = 0; pattern < 3; ++pattern) {
  1215. TestScalePatching(
  1216. gfx::Vector2d(kRGBReadBackSizes[std::get<1>(GetParam())],
  1217. kRGBReadBackSizes[std::get<2>(GetParam())]),
  1218. gfx::Vector2d(kRGBReadBackSizes[std::get<3>(GetParam())],
  1219. kRGBReadBackSizes[std::get<4>(GetParam())]),
  1220. pattern, std::get<0>(GetParam()), !!flipped_source);
  1221. if (HasFailure()) {
  1222. return;
  1223. }
  1224. }
  1225. }
  1226. }
  1227. INSTANTIATE_TEST_SUITE_P(
  1228. All,
  1229. GLHelperPixelReadbackTest,
  1230. ::testing::Combine(
  1231. ::testing::Range<unsigned int>(0, std::size(kQualities)),
  1232. ::testing::Range<unsigned int>(0, std::size(kRGBReadBackSizes)),
  1233. ::testing::Range<unsigned int>(0, std::size(kRGBReadBackSizes)),
  1234. ::testing::Range<unsigned int>(0, std::size(kRGBReadBackSizes)),
  1235. ::testing::Range<unsigned int>(0, std::size(kRGBReadBackSizes))));
  1236. // Validate that all scaling generates valid pipelines.
  1237. TEST_F(GLHelperTest, ValidateScalerPipelines) {
  1238. int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096};
  1239. for (size_t q = 0; q < std::size(kQualities); q++) {
  1240. for (size_t x = 0; x < std::size(sizes); x++) {
  1241. for (size_t y = 0; y < std::size(sizes); y++) {
  1242. for (size_t dst_x = 0; dst_x < std::size(sizes); dst_x++) {
  1243. for (size_t dst_y = 0; dst_y < std::size(sizes); dst_y++) {
  1244. TestScalerPipeline(q, sizes[x], sizes[y], sizes[dst_x],
  1245. sizes[dst_y]);
  1246. if (HasFailure()) {
  1247. return;
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. }
  1254. }
  1255. // Make sure we don't create overly complicated pipelines
  1256. // for a few common use cases.
  1257. TEST_F(GLHelperTest, CheckSpecificPipelines) {
  1258. // Upscale should be single pass.
  1259. CheckPipeline(GLHelper::SCALER_QUALITY_GOOD, 1024, 700, 1280, 720,
  1260. "1024x700 -> 1280x720 bilinear\n");
  1261. // Slight downscale should use BILINEAR2X2.
  1262. CheckPipeline(GLHelper::SCALER_QUALITY_GOOD, 1280, 720, 1024, 700,
  1263. "1280x720 -> 1024x700 bilinear2x2\n");
  1264. // Most common tab capture pipeline on the Pixel.
  1265. // Should be using two BILINEAR3 passes.
  1266. CheckPipeline(GLHelper::SCALER_QUALITY_GOOD, 2560, 1476, 1249, 720,
  1267. "2560x1476 -> 2560x720 bilinear3 Y\n"
  1268. "2560x720 -> 1249x720 bilinear3 X\n");
  1269. }
  1270. TEST_F(GLHelperTest, ScalerOpTest) {
  1271. for (int allow3 = 0; allow3 <= 1; allow3++) {
  1272. for (int dst = 1; dst < 2049; dst += 1 + (dst >> 3)) {
  1273. for (int src = 1; src < 2049; src++) {
  1274. TestAddOps(src, dst, allow3 == 1, (src & 1) == 1);
  1275. if (HasFailure()) {
  1276. LOG(ERROR) << "Failed for src=" << src << " dst=" << dst
  1277. << " allow3=" << allow3;
  1278. return;
  1279. }
  1280. }
  1281. }
  1282. }
  1283. }
  1284. TEST_F(GLHelperTest, CheckOptimizations) {
  1285. // Test in baseclass since it is friends with GLHelperScaling
  1286. CheckOptimizationsTest();
  1287. }
  1288. } // namespace gpu
  1289. #endif // BUILDFLAG(IS_ANDROID)