gl_test_utils.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. // Copyright (c) 2012 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/tests/gl_test_utils.h"
  5. #include <GLES2/gl2extchromium.h>
  6. #include <stdint.h>
  7. #include <stdio.h>
  8. #include <memory>
  9. #include <string>
  10. #include "base/command_line.h"
  11. #include "base/logging.h"
  12. #include "build/build_config.h"
  13. #include "gpu/command_buffer/common/gles2_cmd_utils.h"
  14. #include "gpu/config/gpu_driver_bug_workarounds.h"
  15. #include "gpu/config/gpu_info_collector.h"
  16. #include "gpu/config/gpu_preferences.h"
  17. #include "gpu/config/gpu_util.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #include "ui/gfx/geometry/size.h"
  20. #include "ui/gl/gl_version_info.h"
  21. #include "ui/gl/init/gl_factory.h"
  22. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  23. #include "ui/gl/gl_image_native_pixmap.h"
  24. #endif
  25. namespace gpu {
  26. // GCC requires these declarations, but MSVC requires they not be present.
  27. #ifndef COMPILER_MSVC
  28. const uint8_t GLTestHelper::kCheckClearValue;
  29. #endif
  30. gl::GLDisplay* GLTestHelper::InitializeGL(gl::GLImplementation gl_impl) {
  31. gl::GLDisplay* display = nullptr;
  32. if (gl_impl == gl::GLImplementation::kGLImplementationNone) {
  33. display = gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
  34. /*system_device_id=*/0);
  35. } else {
  36. if (!gl::init::InitializeStaticGLBindingsImplementation(
  37. gl::GLImplementationParts(gl_impl),
  38. /*fallback_to_software_gl=*/false))
  39. return nullptr;
  40. display = gl::init::InitializeGLOneOffPlatformImplementation(
  41. /*fallback_to_software_gl=*/false,
  42. /*disable_gl_drawing=*/false,
  43. /*init_extensions=*/false,
  44. /*system_device_id=*/0);
  45. }
  46. if (!display)
  47. return nullptr;
  48. gpu::GPUInfo gpu_info;
  49. gpu::CollectGraphicsInfoForTesting(&gpu_info);
  50. gpu::GLManager::g_gpu_feature_info = gpu::ComputeGpuFeatureInfo(
  51. gpu_info, gpu::GpuPreferences(), base::CommandLine::ForCurrentProcess(),
  52. nullptr // needs_more_info
  53. );
  54. gl::init::SetDisabledExtensionsPlatform(
  55. gpu::GLManager::g_gpu_feature_info.disabled_extensions);
  56. if (!gl::init::InitializeExtensionSettingsOneOffPlatform(display))
  57. return nullptr;
  58. return display;
  59. }
  60. gl::GLDisplay* GLTestHelper::InitializeGLDefault() {
  61. return GLTestHelper::InitializeGL(
  62. gl::GLImplementation::kGLImplementationNone);
  63. }
  64. bool GLTestHelper::HasExtension(const char* extension) {
  65. // Pad with an extra space to ensure that |extension| is not a substring of
  66. // another extension.
  67. std::string extensions =
  68. std::string(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))) +
  69. " ";
  70. std::string extension_padded = std::string(extension) + " ";
  71. return extensions.find(extension_padded) != std::string::npos;
  72. }
  73. bool GLTestHelper::CheckGLError(const char* msg, int line) {
  74. bool success = true;
  75. GLenum error = GL_NO_ERROR;
  76. while ((error = glGetError()) != GL_NO_ERROR) {
  77. success = false;
  78. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), error)
  79. << "GL ERROR in " << msg << " at line " << line << " : " << error;
  80. }
  81. return success;
  82. }
  83. GLuint GLTestHelper::CompileShader(GLenum type, const char* shaderSrc) {
  84. GLuint shader = glCreateShader(type);
  85. // Load the shader source
  86. glShaderSource(shader, 1, &shaderSrc, nullptr);
  87. // Compile the shader
  88. glCompileShader(shader);
  89. return shader;
  90. }
  91. GLuint GLTestHelper::LoadShader(GLenum type, const char* shaderSrc) {
  92. GLuint shader = CompileShader(type, shaderSrc);
  93. // Check the compile status
  94. GLint value = 0;
  95. glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
  96. if (value == 0) {
  97. char buffer[1024];
  98. GLsizei length = 0;
  99. glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
  100. std::string log(buffer, length);
  101. EXPECT_EQ(1, value) << "Error compiling shader: " << log;
  102. glDeleteShader(shader);
  103. shader = 0;
  104. }
  105. return shader;
  106. }
  107. GLuint GLTestHelper::LinkProgram(
  108. GLuint vertex_shader, GLuint fragment_shader) {
  109. // Create the program object
  110. GLuint program = glCreateProgram();
  111. glAttachShader(program, vertex_shader);
  112. glAttachShader(program, fragment_shader);
  113. // Link the program
  114. glLinkProgram(program);
  115. return program;
  116. }
  117. GLuint GLTestHelper::SetupProgram(
  118. GLuint vertex_shader, GLuint fragment_shader) {
  119. GLuint program = LinkProgram(vertex_shader, fragment_shader);
  120. // Check the link status
  121. GLint linked = 0;
  122. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  123. if (linked == 0) {
  124. char buffer[1024];
  125. GLsizei length = 0;
  126. glGetProgramInfoLog(program, sizeof(buffer), &length, buffer);
  127. std::string log(buffer, length);
  128. EXPECT_EQ(1, linked) << "Error linking program: " << log;
  129. glDeleteProgram(program);
  130. program = 0;
  131. }
  132. return program;
  133. }
  134. GLuint GLTestHelper::LoadProgram(
  135. const char* vertex_shader_source,
  136. const char* fragment_shader_source) {
  137. GLuint vertex_shader = LoadShader(
  138. GL_VERTEX_SHADER, vertex_shader_source);
  139. GLuint fragment_shader = LoadShader(
  140. GL_FRAGMENT_SHADER, fragment_shader_source);
  141. if (!vertex_shader || !fragment_shader) {
  142. return 0;
  143. }
  144. return SetupProgram(vertex_shader, fragment_shader);
  145. }
  146. GLuint GLTestHelper::SetupUnitQuad(GLint position_location) {
  147. GLuint vbo = 0;
  148. glGenBuffers(1, &vbo);
  149. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  150. static const float vertices[] = {
  151. 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
  152. 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
  153. };
  154. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  155. glEnableVertexAttribArray(position_location);
  156. glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
  157. return vbo;
  158. }
  159. std::vector<GLuint> GLTestHelper::SetupIndexedUnitQuad(
  160. GLint position_location) {
  161. GLuint array_buffer = SetupUnitQuad(position_location);
  162. static const uint8_t indices[] = {0, 1, 2, 3, 4, 5};
  163. GLuint index_buffer = 0;
  164. glGenBuffers(1, &index_buffer);
  165. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
  166. glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6, indices, GL_STATIC_DRAW);
  167. std::vector<GLuint> buffers(2);
  168. buffers[0] = array_buffer;
  169. buffers[1] = index_buffer;
  170. return buffers;
  171. }
  172. GLuint GLTestHelper::SetupColorsForUnitQuad(
  173. GLint location, const GLfloat color[4], GLenum usage) {
  174. GLuint vbo = 0;
  175. glGenBuffers(1, &vbo);
  176. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  177. GLfloat vertices[6 * 4];
  178. for (int ii = 0; ii < 6; ++ii) {
  179. for (int jj = 0; jj < 4; ++jj) {
  180. vertices[ii * 4 + jj] = color[jj];
  181. }
  182. }
  183. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, usage);
  184. glEnableVertexAttribArray(location);
  185. glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0);
  186. return vbo;
  187. }
  188. bool GLTestHelper::CheckPixels(GLint x,
  189. GLint y,
  190. GLsizei width,
  191. GLsizei height,
  192. GLint tolerance,
  193. const uint8_t* color,
  194. const uint8_t* mask) {
  195. std::vector<uint8_t> colors(width * height * 4);
  196. for (int i = 0; i < width * height * 4; i += 4)
  197. memcpy(&colors[i], color, 4);
  198. return CheckPixels(x, y, width, height, tolerance, colors, mask);
  199. }
  200. bool GLTestHelper::CheckPixels(GLint x,
  201. GLint y,
  202. GLsizei width,
  203. GLsizei height,
  204. GLint tolerance,
  205. const std::vector<uint8_t>& expected,
  206. const uint8_t* mask) {
  207. GLsizei size = width * height * 4;
  208. std::vector<uint8_t> pixels(size, kCheckClearValue);
  209. glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
  210. int bad_count = 0;
  211. for (GLint yy = 0; yy < height; ++yy) {
  212. for (GLint xx = 0; xx < width; ++xx) {
  213. int offset = yy * width * 4 + xx * 4;
  214. for (int jj = 0; jj < 4; ++jj) {
  215. uint8_t actual = pixels[offset + jj];
  216. uint8_t expected_component = expected[offset + jj];
  217. int diff = actual - expected_component;
  218. diff = diff < 0 ? -diff: diff;
  219. if ((!mask || mask[jj]) && diff > tolerance) {
  220. EXPECT_EQ(static_cast<int>(expected_component),
  221. static_cast<int>(actual))
  222. << " at " << (xx + x) << ", " << (yy + y) << " channel " << jj;
  223. ++bad_count;
  224. // Exit early just so we don't spam the log but we print enough
  225. // to hopefully make it easy to diagnose the issue.
  226. if (bad_count > 16) {
  227. return false;
  228. }
  229. }
  230. }
  231. }
  232. }
  233. return bad_count == 0;
  234. }
  235. namespace {
  236. void Set16BitValue(uint8_t dest[2], uint16_t value) {
  237. dest[0] = value & 0xFFu;
  238. dest[1] = value >> 8;
  239. }
  240. void Set32BitValue(uint8_t dest[4], uint32_t value) {
  241. dest[0] = (value >> 0) & 0xFFu;
  242. dest[1] = (value >> 8) & 0xFFu;
  243. dest[2] = (value >> 16) & 0xFFu;
  244. dest[3] = (value >> 24) & 0xFFu;
  245. }
  246. struct BitmapHeaderFile {
  247. uint8_t magic[2];
  248. uint8_t size[4];
  249. uint8_t reserved[4];
  250. uint8_t offset[4];
  251. };
  252. struct BitmapInfoHeader{
  253. uint8_t size[4];
  254. uint8_t width[4];
  255. uint8_t height[4];
  256. uint8_t planes[2];
  257. uint8_t bit_count[2];
  258. uint8_t compression[4];
  259. uint8_t size_image[4];
  260. uint8_t x_pels_per_meter[4];
  261. uint8_t y_pels_per_meter[4];
  262. uint8_t clr_used[4];
  263. uint8_t clr_important[4];
  264. };
  265. } // namespace
  266. bool GLTestHelper::SaveBackbufferAsBMP(
  267. const char* filename, int width, int height) {
  268. FILE* fp = fopen(filename, "wb");
  269. EXPECT_TRUE(fp != nullptr);
  270. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  271. int num_pixels = width * height;
  272. int size = num_pixels * 4;
  273. std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
  274. uint8_t* pixels = data.get();
  275. glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  276. // RGBA to BGRA
  277. for (int ii = 0; ii < num_pixels; ++ii) {
  278. int offset = ii * 4;
  279. uint8_t t = pixels[offset + 0];
  280. pixels[offset + 0] = pixels[offset + 2];
  281. pixels[offset + 2] = t;
  282. }
  283. BitmapHeaderFile bhf;
  284. BitmapInfoHeader bih;
  285. bhf.magic[0] = 'B';
  286. bhf.magic[1] = 'M';
  287. Set32BitValue(bhf.size, 0);
  288. Set32BitValue(bhf.reserved, 0);
  289. Set32BitValue(bhf.offset, sizeof(bhf) + sizeof(bih));
  290. Set32BitValue(bih.size, sizeof(bih));
  291. Set32BitValue(bih.width, width);
  292. Set32BitValue(bih.height, height);
  293. Set16BitValue(bih.planes, 1);
  294. Set16BitValue(bih.bit_count, 32);
  295. Set32BitValue(bih.compression, 0);
  296. Set32BitValue(bih.x_pels_per_meter, 0);
  297. Set32BitValue(bih.y_pels_per_meter, 0);
  298. Set32BitValue(bih.clr_used, 0);
  299. Set32BitValue(bih.clr_important, 0);
  300. fwrite(&bhf, sizeof(bhf), 1, fp);
  301. fwrite(&bih, sizeof(bih), 1, fp);
  302. fwrite(pixels, size, 1, fp);
  303. fclose(fp);
  304. return true;
  305. }
  306. void GLTestHelper::DrawTextureQuad(const GLenum texture_target,
  307. const char* vertex_src,
  308. const char* fragment_src,
  309. const char* position_name,
  310. const char* sampler_name,
  311. const char* face_name) {
  312. GLuint program = GLTestHelper::LoadProgram(vertex_src, fragment_src);
  313. EXPECT_NE(program, 0u);
  314. glUseProgram(program);
  315. GLint position_loc = glGetAttribLocation(program, position_name);
  316. GLint sampler_location = glGetUniformLocation(program, sampler_name);
  317. ASSERT_NE(position_loc, -1);
  318. ASSERT_NE(sampler_location, -1);
  319. GLint face_loc = -1;
  320. if (gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(texture_target) ==
  321. GL_TEXTURE_CUBE_MAP) {
  322. ASSERT_NE(face_name, nullptr);
  323. face_loc = glGetUniformLocation(program, face_name);
  324. ASSERT_NE(face_loc, -1);
  325. glUniform1i(face_loc, texture_target);
  326. }
  327. GLuint vertex_buffer = GLTestHelper::SetupUnitQuad(position_loc);
  328. ASSERT_NE(vertex_buffer, 0u);
  329. glActiveTexture(GL_TEXTURE0);
  330. glUniform1i(sampler_location, 0);
  331. glDrawArrays(GL_TRIANGLES, 0, 6);
  332. glDeleteProgram(program);
  333. glDeleteBuffers(1, &vertex_buffer);
  334. }
  335. GpuCommandBufferTestEGL::GpuCommandBufferTestEGL() : gl_reinitialized_(false) {}
  336. GpuCommandBufferTestEGL::~GpuCommandBufferTestEGL() {}
  337. bool GpuCommandBufferTestEGL::InitializeEGL(int width, int height) {
  338. gl::GLImplementation current_impl = gl::GetGLImplementation();
  339. if (!(current_impl == gl::kGLImplementationEGLGLES2 ||
  340. current_impl == gl::kGLImplementationEGLANGLE)) {
  341. gpu::GPUInfo gpu_info;
  342. gpu::CollectContextGraphicsInfo(&gpu_info);
  343. gpu::CollectBasicGraphicsInfo(base::CommandLine::ForCurrentProcess(),
  344. &gpu_info);
  345. // See crbug.com/822716, the ATI proprietary driver has eglGetProcAddress
  346. // but eglInitialize crashes with x11.
  347. if (gpu_info.gl_vendor.find("ATI Technologies Inc.") != std::string::npos) {
  348. LOG(INFO) << "Skip test, ATI proprietary driver crashes with egl/x11";
  349. return false;
  350. }
  351. // The native EGL driver is not supported with the passthrough command
  352. // decoder, in that case use ANGLE
  353. gl::GLImplementationParts new_impl(gl::kGLImplementationEGLGLES2);
  354. if (gpu_info.passthrough_cmd_decoder)
  355. new_impl = gl::GLImplementationParts(gl::kGLImplementationEGLANGLE);
  356. const auto allowed_impls = gl::init::GetAllowedGLImplementations();
  357. if (!new_impl.IsAllowed(allowed_impls)) {
  358. LOG(INFO) << "Skip test, no EGL implementation is available";
  359. return false;
  360. }
  361. gl_reinitialized_ = true;
  362. gl::init::ShutdownGL(gl_display_, false /* due_to_fallback */);
  363. gl_display_ = GLTestHelper::InitializeGL(new_impl.gl);
  364. if (!gl_display_) {
  365. LOG(INFO) << "Skip test, failed to initialize EGL";
  366. return false;
  367. }
  368. }
  369. current_impl = gl::GetGLImplementation();
  370. DCHECK(current_impl == gl::kGLImplementationEGLGLES2 ||
  371. current_impl == gl::kGLImplementationEGLANGLE);
  372. // Make the GL context current now to get all extensions.
  373. GLManager::Options options;
  374. options.size = gfx::Size(width, height);
  375. gl_.Initialize(options);
  376. gl_.MakeCurrent();
  377. gl_extensions_ =
  378. gfx::MakeExtensionSet(gl::GetGLExtensionsFromCurrentContext());
  379. gl::GLVersionInfo gl_version_info(
  380. reinterpret_cast<const char*>(glGetString(GL_VERSION)),
  381. reinterpret_cast<const char*>(glGetString(GL_RENDERER)), gl_extensions_);
  382. bool result = gl::init::GetGLWindowSystemBindingInfo(
  383. gl_version_info, &window_system_binding_info_);
  384. DCHECK(result);
  385. egl_extensions_ =
  386. gfx::MakeExtensionSet(window_system_binding_info_.extensions);
  387. return true;
  388. }
  389. void GpuCommandBufferTestEGL::RestoreGLDefault() {
  390. gl_.Destroy();
  391. if (gl_reinitialized_) {
  392. gl::init::ShutdownGL(gl_display_, false /* due_to_fallback */);
  393. gl_display_ = GLTestHelper::InitializeGLDefault();
  394. }
  395. gl_reinitialized_ = false;
  396. gl_extensions_.clear();
  397. egl_extensions_.clear();
  398. window_system_binding_info_ = gl::GLWindowSystemBindingInfo();
  399. }
  400. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  401. scoped_refptr<gl::GLImageNativePixmap>
  402. GpuCommandBufferTestEGL::CreateGLImageNativePixmap(gfx::BufferFormat format,
  403. gfx::Size size,
  404. uint8_t* pixels) const {
  405. // Upload raw pixels to a new GL texture.
  406. GLuint tex_client_id = 0;
  407. glGenTextures(1, &tex_client_id);
  408. DCHECK_NE(0u, tex_client_id);
  409. glBindTexture(GL_TEXTURE_2D, tex_client_id);
  410. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  411. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  412. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  413. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  414. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
  415. GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  416. // Make sure the texture exists in the service side.
  417. glFinish();
  418. // This works because the test run in a similar mode as In-Process-GPU.
  419. unsigned int tex_service_id = 0;
  420. gl_.decoder()->GetServiceTextureId(tex_client_id, &tex_service_id);
  421. EXPECT_NE(0u, tex_service_id);
  422. // Create an EGLImage from the real texture id.
  423. auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
  424. bool result = image->InitializeFromTexture(tex_service_id);
  425. DCHECK(result);
  426. // The test will own the EGLImage no need to keep a reference on the GL
  427. // texture after returning from this function. This is covered by the
  428. // EGL_KHR_image_base.txt specification, i.e. the underlying memory remains
  429. // allocated as long as there is at least one sibling (like ref count).
  430. glDeleteTextures(1, &tex_client_id);
  431. return image;
  432. }
  433. gfx::NativePixmapHandle GpuCommandBufferTestEGL::CreateNativePixmapHandle(
  434. gfx::BufferFormat format,
  435. gfx::Size size,
  436. uint8_t* pixels) {
  437. scoped_refptr<gl::GLImageNativePixmap> image =
  438. CreateGLImageNativePixmap(format, size, pixels);
  439. EXPECT_TRUE(image);
  440. EXPECT_EQ(size, image->GetSize());
  441. // Export the EGLImage as dmabuf fds
  442. // The test will own the dmabuf fds so no need to keep a reference on the
  443. // EGLImage after returning from this function.
  444. return image->ExportHandle();
  445. }
  446. #endif
  447. } // namespace gpu