gl_bind_uniform_location_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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 <GLES2/gl2.h>
  5. #include <GLES2/gl2ext.h>
  6. #include <GLES2/gl2extchromium.h>
  7. #include <stdint.h>
  8. #include "gpu/command_buffer/tests/gl_manager.h"
  9. #include "gpu/command_buffer/tests/gl_test_utils.h"
  10. #include "testing/gmock/include/gmock/gmock.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #define SHADER(Src) #Src
  13. namespace gpu {
  14. class BindUniformLocationTest : public testing::TestWithParam<bool> {
  15. protected:
  16. static const GLsizei kResolution = 4;
  17. void SetUp() override {
  18. GLManager::Options options;
  19. options.size = gfx::Size(kResolution, kResolution);
  20. options.force_shader_name_hashing = GetParam();
  21. gl_.Initialize(options);
  22. }
  23. void TearDown() override { gl_.Destroy(); }
  24. GLManager gl_;
  25. };
  26. TEST_P(BindUniformLocationTest, Basic) {
  27. ASSERT_TRUE(
  28. GLTestHelper::HasExtension("GL_CHROMIUM_bind_uniform_location"));
  29. static const char* v_shader_str = SHADER(
  30. attribute vec4 a_position;
  31. void main()
  32. {
  33. gl_Position = a_position;
  34. }
  35. );
  36. static const char* f_shader_str = SHADER(
  37. precision mediump float;
  38. uniform vec4 u_colorC;
  39. uniform vec4 u_colorB[2];
  40. uniform vec4 u_colorA;
  41. void main()
  42. {
  43. gl_FragColor = u_colorA + u_colorB[0] + u_colorB[1] + u_colorC;
  44. }
  45. );
  46. GLint color_a_location = 3;
  47. GLint color_b_location = 10;
  48. GLint color_c_location = 5;
  49. GLuint vertex_shader = GLTestHelper::LoadShader(
  50. GL_VERTEX_SHADER, v_shader_str);
  51. GLuint fragment_shader = GLTestHelper::LoadShader(
  52. GL_FRAGMENT_SHADER, f_shader_str);
  53. GLuint program = glCreateProgram();
  54. glBindUniformLocationCHROMIUM(program, color_a_location, "u_colorA");
  55. glBindUniformLocationCHROMIUM(program, color_b_location, "u_colorB[0]");
  56. glBindUniformLocationCHROMIUM(program, color_c_location, "u_colorC");
  57. glAttachShader(program, vertex_shader);
  58. glAttachShader(program, fragment_shader);
  59. // Link the program
  60. glLinkProgram(program);
  61. // Check the link status
  62. GLint linked = 0;
  63. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  64. EXPECT_EQ(1, linked);
  65. GLint position_loc = glGetAttribLocation(program, "a_position");
  66. GLTestHelper::SetupUnitQuad(position_loc);
  67. glUseProgram(program);
  68. static const float color_b[] = {
  69. 0.0f, 0.50f, 0.0f, 0.0f,
  70. 0.0f, 0.0f, 0.75f, 0.0f,
  71. };
  72. glUniform4f(color_a_location, 0.25f, 0.0f, 0.0f, 0.0f);
  73. glUniform4fv(color_b_location, 2, color_b);
  74. glUniform4f(color_c_location, 0.0f, 0.0f, 0.0f, 1.0f);
  75. glDrawArrays(GL_TRIANGLES, 0, 6);
  76. static const uint8_t expected[] = {64, 128, 192, 255};
  77. EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kResolution, kResolution, 1,
  78. expected, nullptr));
  79. GLTestHelper::CheckGLError("no errors", __LINE__);
  80. }
  81. TEST_P(BindUniformLocationTest, ConflictsDetection) {
  82. ASSERT_TRUE(
  83. GLTestHelper::HasExtension("GL_CHROMIUM_bind_uniform_location"));
  84. static const char* v_shader_str = SHADER(
  85. attribute vec4 a_position;
  86. void main()
  87. {
  88. gl_Position = a_position;
  89. }
  90. );
  91. static const char* f_shader_str = SHADER(
  92. precision mediump float;
  93. uniform vec4 u_colorA;
  94. uniform vec4 u_colorB;
  95. void main()
  96. {
  97. gl_FragColor = u_colorA + u_colorB;
  98. }
  99. );
  100. GLint color_a_location = 3;
  101. GLint color_b_location = 4;
  102. GLuint vertex_shader = GLTestHelper::LoadShader(
  103. GL_VERTEX_SHADER, v_shader_str);
  104. GLuint fragment_shader = GLTestHelper::LoadShader(
  105. GL_FRAGMENT_SHADER, f_shader_str);
  106. GLuint program = glCreateProgram();
  107. glAttachShader(program, vertex_shader);
  108. glAttachShader(program, fragment_shader);
  109. glBindUniformLocationCHROMIUM(program, color_a_location, "u_colorA");
  110. // Bind u_colorB to location a, causing conflicts, link should fail.
  111. glBindUniformLocationCHROMIUM(program, color_a_location, "u_colorB");
  112. glLinkProgram(program);
  113. GLint linked = 0;
  114. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  115. EXPECT_EQ(0, linked);
  116. // Bind u_colorB to location b, no conflicts, link should succeed.
  117. glBindUniformLocationCHROMIUM(program, color_b_location, "u_colorB");
  118. glLinkProgram(program);
  119. linked = 0;
  120. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  121. EXPECT_EQ(1, linked);
  122. GLTestHelper::CheckGLError("no errors", __LINE__);
  123. }
  124. TEST_P(BindUniformLocationTest, Compositor) {
  125. ASSERT_TRUE(
  126. GLTestHelper::HasExtension("GL_CHROMIUM_bind_uniform_location"));
  127. static const char* v_shader_str = SHADER(
  128. attribute vec4 a_position;
  129. attribute vec2 a_texCoord;
  130. uniform mat4 matrix;
  131. uniform vec2 color_a[4];
  132. uniform vec4 color_b;
  133. varying vec4 v_color;
  134. void main()
  135. {
  136. v_color.xy = color_a[0] + color_a[1];
  137. v_color.zw = color_a[2] + color_a[3];
  138. v_color += color_b;
  139. gl_Position = matrix * a_position;
  140. }
  141. );
  142. static const char* f_shader_str = SHADER(
  143. precision mediump float;
  144. varying vec4 v_color;
  145. uniform float alpha;
  146. uniform vec4 multiplier;
  147. uniform vec3 color_c[8];
  148. void main()
  149. {
  150. vec4 color_c_sum = vec4(0.0);
  151. color_c_sum.xyz += color_c[0];
  152. color_c_sum.xyz += color_c[1];
  153. color_c_sum.xyz += color_c[2];
  154. color_c_sum.xyz += color_c[3];
  155. color_c_sum.xyz += color_c[4];
  156. color_c_sum.xyz += color_c[5];
  157. color_c_sum.xyz += color_c[6];
  158. color_c_sum.xyz += color_c[7];
  159. color_c_sum.w = alpha;
  160. color_c_sum *= multiplier;
  161. gl_FragColor = v_color + color_c_sum;
  162. }
  163. );
  164. int counter = 6;
  165. int matrix_location = counter++;
  166. int color_a_location = counter++;
  167. int color_b_location = counter++;
  168. int alpha_location = counter++;
  169. int multiplier_location = counter++;
  170. int color_c_location = counter++;
  171. GLuint vertex_shader = GLTestHelper::LoadShader(
  172. GL_VERTEX_SHADER, v_shader_str);
  173. GLuint fragment_shader = GLTestHelper::LoadShader(
  174. GL_FRAGMENT_SHADER, f_shader_str);
  175. GLuint program = glCreateProgram();
  176. glBindUniformLocationCHROMIUM(program, matrix_location, "matrix");
  177. glBindUniformLocationCHROMIUM(program, color_a_location, "color_a");
  178. glBindUniformLocationCHROMIUM(program, color_b_location, "color_b");
  179. glBindUniformLocationCHROMIUM(program, alpha_location, "alpha");
  180. glBindUniformLocationCHROMIUM(program, multiplier_location, "multiplier");
  181. glBindUniformLocationCHROMIUM(program, color_c_location, "color_c");
  182. glAttachShader(program, vertex_shader);
  183. glAttachShader(program, fragment_shader);
  184. // Link the program
  185. glLinkProgram(program);
  186. // Check the link status
  187. GLint linked = 0;
  188. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  189. EXPECT_EQ(1, linked);
  190. GLint position_loc = glGetAttribLocation(program, "a_position");
  191. GLTestHelper::SetupUnitQuad(position_loc);
  192. glUseProgram(program);
  193. static const float color_a[] = {
  194. 0.1f, 0.1f, 0.1f, 0.1f,
  195. 0.1f, 0.1f, 0.1f, 0.1f,
  196. };
  197. static const float color_c[] = {
  198. 0.1f, 0.1f, 0.1f,
  199. 0.1f, 0.1f, 0.1f,
  200. 0.1f, 0.1f, 0.1f,
  201. 0.1f, 0.1f, 0.1f,
  202. 0.1f, 0.1f, 0.1f,
  203. 0.1f, 0.1f, 0.1f,
  204. 0.1f, 0.1f, 0.1f,
  205. 0.1f, 0.1f, 0.1f,
  206. };
  207. static const float identity[] = {
  208. 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
  209. };
  210. glUniformMatrix4fv(matrix_location, 1, false, identity);
  211. glUniform2fv(color_a_location, 4, color_a);
  212. glUniform4f(color_b_location, 0.2f, 0.2f, 0.2f, 0.2f);
  213. glUniform1f(alpha_location, 0.8f);
  214. glUniform4f(multiplier_location, 0.5f, 0.5f, 0.5f, 0.5f);
  215. glUniform3fv(color_c_location, 8, color_c);
  216. glDrawArrays(GL_TRIANGLES, 0, 6);
  217. static const uint8_t expected[] = {204, 204, 204, 204};
  218. EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kResolution, kResolution, 1,
  219. expected, nullptr));
  220. GLTestHelper::CheckGLError("no errors", __LINE__);
  221. }
  222. TEST_P(BindUniformLocationTest, UnusedUniformUpdate) {
  223. ASSERT_TRUE(GLTestHelper::HasExtension("GL_CHROMIUM_bind_uniform_location"));
  224. // clang-format off
  225. static const char* kVertexShaderString = SHADER(
  226. attribute vec4 a_position;
  227. void main() {
  228. gl_Position = a_position;
  229. }
  230. );
  231. static const char* kFragmentShaderString = SHADER(
  232. precision mediump float;
  233. uniform vec4 u_colorA;
  234. uniform float u_colorU;
  235. uniform vec4 u_colorC;
  236. void main() {
  237. gl_FragColor = u_colorA + u_colorC;
  238. }
  239. );
  240. // clang-format on
  241. const GLint kColorULocation = 1;
  242. const GLint kNonexistingLocation = 5;
  243. const GLint kUnboundLocation = 6;
  244. GLuint vertex_shader =
  245. GLTestHelper::LoadShader(GL_VERTEX_SHADER, kVertexShaderString);
  246. GLuint fragment_shader =
  247. GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShaderString);
  248. GLuint program = glCreateProgram();
  249. glBindUniformLocationCHROMIUM(program, kColorULocation, "u_colorU");
  250. // The non-existing uniform should behave like existing, but optimized away
  251. // uniform.
  252. glBindUniformLocationCHROMIUM(program, kNonexistingLocation, "nonexisting");
  253. // Let A and C be assigned automatic locations.
  254. glAttachShader(program, vertex_shader);
  255. glAttachShader(program, fragment_shader);
  256. glLinkProgram(program);
  257. GLint linked = 0;
  258. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  259. EXPECT_EQ(1, linked);
  260. glUseProgram(program);
  261. // No errors on bound locations, since caller does not know
  262. // if the driver optimizes them away or not.
  263. glUniform1f(kColorULocation, 0.25f);
  264. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  265. // No errors on bound locations of names that do not exist
  266. // in the shader. Otherwise it would be inconsistent wrt the
  267. // optimization case.
  268. glUniform1f(kNonexistingLocation, 0.25f);
  269. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  270. // The above are equal to updating -1.
  271. glUniform1f(-1, 0.25f);
  272. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  273. // No errors when updating with other type either.
  274. // The type can not be known with the non-existing case.
  275. glUniform2f(kColorULocation, 0.25f, 0.25f);
  276. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  277. glUniform2f(kNonexistingLocation, 0.25f, 0.25f);
  278. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  279. glUniform2f(-1, 0.25f, 0.25f);
  280. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  281. // Ensure that driver or ANGLE has optimized the variable
  282. // away and the test tests what it is supposed to.
  283. EXPECT_EQ(-1, glGetUniformLocation(program, "u_colorU"));
  284. // The bound location gets marked as used and the driver
  285. // does not allocate other variables to that location.
  286. EXPECT_NE(kColorULocation, glGetUniformLocation(program, "u_colorA"));
  287. EXPECT_NE(kColorULocation, glGetUniformLocation(program, "u_colorC"));
  288. EXPECT_NE(kNonexistingLocation, glGetUniformLocation(program, "u_colorA"));
  289. EXPECT_NE(kNonexistingLocation, glGetUniformLocation(program, "u_colorC"));
  290. // Unintuitive: while specifying value works, getting the value does not.
  291. GLfloat get_result = 0.0f;
  292. glGetUniformfv(program, kColorULocation, &get_result);
  293. EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
  294. glGetUniformfv(program, kNonexistingLocation, &get_result);
  295. EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
  296. glGetUniformfv(program, -1, &get_result);
  297. EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
  298. // Updating an unbound, non-existing location still causes
  299. // an error.
  300. glUniform1f(kUnboundLocation, 0.25f);
  301. EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
  302. }
  303. // Test for a bug where using a sampler caused GL error if the program had
  304. // uniforms that were optimized away by the driver. This was only a problem with
  305. // glBindUniformLocationCHROMIUM implementation. This could be reproed by
  306. // binding the sampler to a location higher than the amount of active uniforms.
  307. TEST_P(BindUniformLocationTest, UseSamplerWhenUnusedUniforms) {
  308. enum {
  309. kTexLocation = 54
  310. };
  311. // clang-format off
  312. static const char* vertexShaderString = SHADER(
  313. void main() {
  314. gl_Position = vec4(0);
  315. }
  316. );
  317. static const char* fragmentShaderString = SHADER(
  318. uniform sampler2D tex;
  319. void main() {
  320. gl_FragColor = texture2D(tex, vec2(1));
  321. }
  322. );
  323. // clang-format on
  324. GLuint vs = GLTestHelper::CompileShader(GL_VERTEX_SHADER, vertexShaderString);
  325. GLuint fs = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER,
  326. fragmentShaderString);
  327. GLuint program = glCreateProgram();
  328. glBindUniformLocationCHROMIUM(program, kTexLocation, "tex");
  329. glAttachShader(program, vs);
  330. glAttachShader(program, fs);
  331. glLinkProgram(program);
  332. GLint linked = 0;
  333. glGetProgramiv(program, GL_LINK_STATUS, &linked);
  334. EXPECT_NE(0, linked);
  335. glUseProgram(program);
  336. glUniform1i(kTexLocation, 0);
  337. EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
  338. }
  339. INSTANTIATE_TEST_SUITE_P(WithAndWithoutShaderNameMapping,
  340. BindUniformLocationTest,
  341. ::testing::Bool());
  342. } // namespace gpu