OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <fcntl.h> | 5 #include <fcntl.h> |
6 #include <stdio.h> | 6 #include <stdio.h> |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <sys/mman.h> | 9 #include <sys/mman.h> |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 | 12 |
13 #include "main.h" | 13 #include "main.h" |
14 #include "shaders.h" | |
15 #include "utils.h" | 14 #include "utils.h" |
16 #include "yuv2rgb.h" | 15 #include "yuv2rgb.h" |
17 | 16 |
| 17 #include "all_tests.h" |
| 18 #include "testbase.h" |
| 19 |
18 | 20 |
19 const int enabled_tests_max = 8; | 21 const int enabled_tests_max = 8; |
| 22 // TODO: fix enabled_tests. |
20 const char *enabled_tests[enabled_tests_max+1] = {NULL}; | 23 const char *enabled_tests[enabled_tests_max+1] = {NULL}; |
21 int seconds_to_run = 0; | 24 int seconds_to_run = 0; |
22 | 25 |
23 // Runs Bench on a test function f and prints out results. Bench function | |
24 // returns the slope and bias of a linear model relating the argument passed to | |
25 // f and time it took f to run. Normally the argument of f is assumed to be | |
26 // number of iterations an operation is executed. | |
27 // | |
28 // coefficient is multiplied (if inverse is false) or divided (if inverse is | |
29 // true) by the slope and the result is printed. | |
30 // | |
31 // The test will not run if enabled_tests is nonempty and no string in | |
32 // enabled_tests is contained in name. | |
33 // | |
34 // Examples: | |
35 // coefficient = width * height (measured in pixels), inverse = true | |
36 // returns the throughput in megapixels per second; | |
37 // | |
38 // coefficient = 1, inverse = false | |
39 // returns number of operations per second. | |
40 void RunTest(BenchFunc f, const char *name, float coefficient, bool inverse) { | |
41 float slope; | |
42 int64_t bias; | |
43 | |
44 if (enabled_tests[0]) { | |
45 bool found = false; | |
46 for (const char **e = enabled_tests; *e; e++) | |
47 if (strstr(name, *e)) { | |
48 found = true; | |
49 break; | |
50 } | |
51 if (!found) | |
52 return; | |
53 } | |
54 | |
55 GLenum err = glGetError(); | |
56 if (err != 0) { | |
57 printf("# %s failed, glGetError returned 0x%x.\n", name, err); | |
58 // float() in python will happily parse Nan. | |
59 printf("%s: Nan\n", name); | |
60 } else { | |
61 if (Bench(f, &slope, &bias)) { | |
62 printf("%s: %g\n", name, coefficient * (inverse ? 1.f / slope : slope)); | |
63 } else { | |
64 printf("# %s is too slow, returning zero.\n", name); | |
65 printf("%s: 0\n", name); | |
66 } | |
67 } | |
68 } | |
69 | |
70 static int arg1 = 0; | |
71 static void *arg2 = NULL; | |
72 | |
73 void SwapTestFunc(int iter) { | |
74 for (int i = 0 ; i < iter; ++i) { | |
75 SwapBuffers(); | |
76 } | |
77 } | |
78 | |
79 void SwapTest() { | |
80 RunTest(SwapTestFunc, "us_swap_swap", 1.f, false); | |
81 } | |
82 | |
83 void ClearTestFunc(int iter) { | |
84 GLbitfield mask = arg1; | |
85 glClear(mask); | |
86 glFlush(); // Kick GPU as soon as possible | |
87 for (int i = 0 ; i < iter-1; ++i) { | |
88 glClear(mask); | |
89 } | |
90 } | |
91 | |
92 | |
93 void ClearTest() { | |
94 arg1 = GL_COLOR_BUFFER_BIT; | |
95 RunTest(ClearTestFunc, "mpixels_sec_clear_color", g_width * g_height, true); | |
96 | |
97 arg1 = GL_DEPTH_BUFFER_BIT; | |
98 RunTest(ClearTestFunc, "mpixels_sec_clear_depth", g_width * g_height, true); | |
99 | |
100 arg1 = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; | |
101 RunTest(ClearTestFunc, "mpixels_sec_clear_colordepth", | |
102 g_width * g_height, true); | |
103 | |
104 arg1 = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | |
105 RunTest(ClearTestFunc, "mpixels_sec_clear_depthstencil", | |
106 g_width * g_height, true); | |
107 | |
108 arg1 = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | |
109 RunTest(ClearTestFunc, "mpixels_sec_clear_colordepthstencil", | |
110 g_width * g_height, true); | |
111 } | |
112 | |
113 | |
114 GLuint SetupVBO(GLenum target, GLsizeiptr size, const GLvoid *data) { | |
115 GLuint buf = ~0; | |
116 glGenBuffers(1, &buf); | |
117 glBindBuffer(target, buf); | |
118 glBufferData(target, size, data, GL_STATIC_DRAW); | |
119 CHECK(!glGetError()); | |
120 return buf; | |
121 } | |
122 | |
123 | |
124 GLuint SetupTexture(GLsizei size_log2) { | |
125 GLsizei size = 1 << size_log2; | |
126 GLuint name = ~0; | |
127 glGenTextures(1, &name); | |
128 glBindTexture(GL_TEXTURE_2D, name); | |
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
131 | |
132 unsigned char *pixels = new unsigned char[size * size * 4]; | |
133 if (!pixels) | |
134 return 0; | |
135 | |
136 for (GLint level = 0; size > 0; level++, size /= 2) { | |
137 unsigned char *p = pixels; | |
138 for (int i = 0; i < size; i++) { | |
139 for (int j = 0; j < size; j++) { | |
140 *p++ = level %3 != 0 ? (i ^ j) << level : 0; | |
141 *p++ = level %3 != 1 ? (i ^ j) << level : 0; | |
142 *p++ = level %3 != 2 ? (i ^ j) << level : 0; | |
143 *p++ = 255; | |
144 } | |
145 } | |
146 if (size == 1) { | |
147 unsigned char *p = pixels; | |
148 *p++ = 255; | |
149 *p++ = 255; | |
150 *p++ = 255; | |
151 *p++ = 255; | |
152 } | |
153 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, size, size, 0, | |
154 GL_RGBA, GL_UNSIGNED_BYTE, pixels); | |
155 } | |
156 delete[] pixels; | |
157 return name; | |
158 } | |
159 | |
160 | |
161 static void DrawArraysTestFunc(int iter); | |
162 static void FillRateTestNormal(const char *name, float coeff=1.f); | |
163 | |
164 #ifndef USE_EGL | |
165 static void FillRateTestBlendDepth(const char *name); | |
166 | |
167 void FillRateTest() { | |
168 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |
169 glDisable(GL_DEPTH_TEST); | |
170 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
171 | |
172 GLfloat buffer_vertex[8] = { | |
173 -1.f, -1.f, | |
174 1.f, -1.f, | |
175 -1.f, 1.f, | |
176 1.f, 1.f, | |
177 }; | |
178 GLfloat buffer_texture[8] = { | |
179 0.f, 0.f, | |
180 1.f, 0.f, | |
181 0.f, 1.f, | |
182 1.f, 1.f, | |
183 }; | |
184 glEnableClientState(GL_VERTEX_ARRAY); | |
185 | |
186 GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER, | |
187 sizeof(buffer_vertex), buffer_vertex); | |
188 glVertexPointer(2, GL_FLOAT, 0, 0); | |
189 | |
190 GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER, | |
191 sizeof(buffer_texture), buffer_texture); | |
192 glTexCoordPointer(2, GL_FLOAT, 0, 0); | |
193 | |
194 glColor4f(1.f, 0.f, 0.f, 1.f); | |
195 FillRateTestNormal("fill_solid"); | |
196 FillRateTestBlendDepth("fill_solid"); | |
197 | |
198 glColor4f(1.f, 1.f, 1.f, 1.f); | |
199 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
200 glEnable(GL_TEXTURE_2D); | |
201 | |
202 GLuint texture = SetupTexture(9); | |
203 FillRateTestNormal("fill_tex_nearest"); | |
204 | |
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
207 FillRateTestNormal("fill_tex_bilinear"); | |
208 | |
209 // lod = 0.5 | |
210 glScalef(0.7071f, 0.7071f, 1.f); | |
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
212 GL_LINEAR_MIPMAP_NEAREST); | |
213 FillRateTestNormal("fill_tex_trilinear_nearest_05", 0.7071f * 0.7071f); | |
214 | |
215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
216 GL_LINEAR_MIPMAP_LINEAR); | |
217 FillRateTestNormal("fill_tex_trilinear_linear_05", 0.7071f * 0.7071f); | |
218 | |
219 // lod = 0.4 | |
220 glLoadIdentity(); | |
221 glScalef(0.758f, 0.758f, 1.f); | |
222 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
223 GL_LINEAR_MIPMAP_LINEAR); | |
224 FillRateTestNormal("fill_tex_trilinear_linear_04", 0.758f * 0.758f); | |
225 | |
226 // lod = 0.1 | |
227 glLoadIdentity(); | |
228 glScalef(0.933f, 0.933f, 1.f); | |
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
230 GL_LINEAR_MIPMAP_LINEAR); | |
231 FillRateTestNormal("fill_tex_trilinear_linear_01", 0.933f * 0.933f); | |
232 | |
233 glDeleteBuffers(1, &vbo_vertex); | |
234 glDeleteBuffers(1, &vbo_texture); | |
235 glDeleteTextures(1, &texture); | |
236 } | |
237 #endif | |
238 | |
239 | |
240 static void FillRateTestNormal(const char *name, float coeff) { | |
241 const int buffer_len = 64; | |
242 char buffer[buffer_len]; | |
243 snprintf(buffer, buffer_len, "mpixels_sec_%s", name); | |
244 RunTest(DrawArraysTestFunc, buffer, coeff * g_width * g_height, true); | |
245 } | |
246 | |
247 #ifndef USE_EGL | |
248 static void FillRateTestBlendDepth(const char *name) { | |
249 const int buffer_len = 64; | |
250 char buffer[buffer_len]; | |
251 | |
252 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
253 glEnable(GL_BLEND); | |
254 snprintf(buffer, buffer_len, "mpixels_sec_%s_blended", name); | |
255 RunTest(DrawArraysTestFunc, buffer, g_width * g_height, true); | |
256 glDisable(GL_BLEND); | |
257 | |
258 glEnable(GL_DEPTH_TEST); | |
259 glDepthFunc(GL_NOTEQUAL); | |
260 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_neq", name); | |
261 RunTest(DrawArraysTestFunc, buffer, g_width * g_height, true); | |
262 glDepthFunc(GL_NEVER); | |
263 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_never", name); | |
264 RunTest(DrawArraysTestFunc, buffer, g_width * g_height, true); | |
265 glDisable(GL_DEPTH_TEST); | |
266 } | |
267 #endif | |
268 | |
269 | |
270 static void DrawArraysTestFunc(int iter) { | |
271 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
272 glFlush(); | |
273 for (int i = 0; i < iter-1; ++i) { | |
274 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
275 } | |
276 } | |
277 | |
278 | |
279 static void DrawElementsTestFunc(int iter) { | |
280 glDrawElements(GL_TRIANGLES, arg1, GL_UNSIGNED_INT, 0); | |
281 glFlush(); | |
282 for (int i = 0 ; i < iter-1; ++i) { | |
283 glDrawElements(GL_TRIANGLES, arg1, GL_UNSIGNED_INT, 0); | |
284 } | |
285 } | |
286 | |
287 // Generates a tautological lattice. | |
288 static void CreateLattice(GLfloat **vertices, GLsizeiptr *size, | |
289 GLfloat size_x, GLfloat size_y, | |
290 int width, int height) | |
291 { | |
292 GLfloat *vptr = *vertices = new GLfloat[2 * (width + 1) * (height + 1)]; | |
293 for (int j = 0; j <= height; j++) { | |
294 for (int i = 0; i <= width; i++) { | |
295 *vptr++ = i * size_x; | |
296 *vptr++ = j * size_y; | |
297 } | |
298 } | |
299 *size = (vptr - *vertices) * sizeof(GLfloat); | |
300 } | |
301 | |
302 // Generates a mesh of 2*width*height triangles. The ratio of front facing to | |
303 // back facing triangles is culled_ratio/RAND_MAX. Returns the number of | |
304 // vertices in the mesh. | |
305 static int CreateMesh(GLuint **indices, GLsizeiptr *size, | |
306 int width, int height, int culled_ratio) { | |
307 srand(0); | |
308 | |
309 GLuint *iptr = *indices = new GLuint[2 * 3 * (width * height)]; | |
310 const int swath_height = 4; | |
311 | |
312 CHECK(width % swath_height == 0 && height % swath_height == 0); | |
313 | |
314 for (int j = 0; j < height; j += swath_height) { | |
315 for (int i = 0; i < width; i++) { | |
316 for (int j2 = 0; j2 < swath_height; j2++) { | |
317 GLuint first = (j + j2) * (width + 1) + i; | |
318 GLuint second = first + 1; | |
319 GLuint third = first + (width + 1); | |
320 GLuint fourth = third + 1; | |
321 | |
322 bool flag = rand() < culled_ratio; | |
323 *iptr++ = first; | |
324 *iptr++ = flag ? second : third; | |
325 *iptr++ = flag ? third : second; | |
326 | |
327 *iptr++ = fourth; | |
328 *iptr++ = flag ? third : second; | |
329 *iptr++ = flag ? second : third; | |
330 } | |
331 } | |
332 } | |
333 *size = (iptr - *indices) * sizeof(GLuint); | |
334 | |
335 return iptr - *indices; | |
336 } | |
337 | |
338 #ifndef USE_EGL | |
339 void TriangleSetupTest() { | |
340 glViewport(-g_width, -g_height, g_width*2, g_height*2); | |
341 | |
342 // Larger meshes make this test too slow for devices that do 1 mtri/sec. | |
343 GLint width = 64; | |
344 GLint height = 64; | |
345 | |
346 GLfloat *vertices = NULL; | |
347 GLsizeiptr vertex_buffer_size = 0; | |
348 CreateLattice(&vertices, &vertex_buffer_size, 1.f / g_width, 1.f / g_height, | |
349 width, height); | |
350 GLuint vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, | |
351 vertex_buffer_size, vertices); | |
352 glVertexPointer(2, GL_FLOAT, 0, 0); | |
353 glEnableClientState(GL_VERTEX_ARRAY); | |
354 | |
355 GLuint *indices = NULL; | |
356 GLuint index_buffer = 0; | |
357 GLsizeiptr index_buffer_size = 0; | |
358 | |
359 { | |
360 arg1 = CreateMesh(&indices, &index_buffer_size, width, height, 0); | |
361 | |
362 index_buffer = SetupVBO(GL_ELEMENT_ARRAY_BUFFER, | |
363 index_buffer_size, indices); | |
364 RunTest(DrawElementsTestFunc, "mtri_sec_triangle_setup", arg1 / 3, true); | |
365 glEnable(GL_CULL_FACE); | |
366 RunTest(DrawElementsTestFunc, "mtri_sec_triangle_setup_all_culled", | |
367 arg1 / 3, true); | |
368 glDisable(GL_CULL_FACE); | |
369 | |
370 glDeleteBuffers(1, &index_buffer); | |
371 delete[] indices; | |
372 } | |
373 | |
374 { | |
375 glColor4f(0.f, 1.f, 1.f, 1.f); | |
376 arg1 = CreateMesh(&indices, &index_buffer_size, width, height, | |
377 RAND_MAX / 2); | |
378 | |
379 index_buffer = SetupVBO(GL_ELEMENT_ARRAY_BUFFER, | |
380 index_buffer_size, indices); | |
381 glEnable(GL_CULL_FACE); | |
382 RunTest(DrawElementsTestFunc, "mtri_sec_triangle_setup_half_culled", | |
383 arg1 / 3, true); | |
384 | |
385 glDeleteBuffers(1, &index_buffer); | |
386 delete[] indices; | |
387 } | |
388 | |
389 glDeleteBuffers(1, &vertex_buffer); | |
390 delete[] vertices; | |
391 } | |
392 #endif | |
393 | |
394 | |
395 void AttributeFetchShaderTest() { | |
396 GLint width = 64; | |
397 GLint height = 64; | |
398 | |
399 glViewport(-g_width, -g_height, g_width*2, g_height*2); | |
400 | |
401 GLfloat *vertices = NULL; | |
402 GLsizeiptr vertex_buffer_size = 0; | |
403 CreateLattice(&vertices, &vertex_buffer_size, 1.f / g_width, 1.f / g_height, | |
404 width, height); | |
405 GLuint vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, | |
406 vertex_buffer_size, vertices); | |
407 | |
408 GLuint *indices = NULL; | |
409 GLuint index_buffer = 0; | |
410 GLsizeiptr index_buffer_size = 0; | |
411 | |
412 // Everything will be back-face culled. | |
413 arg1 = CreateMesh(&indices, &index_buffer_size, width, height, 0); | |
414 index_buffer = SetupVBO(GL_ELEMENT_ARRAY_BUFFER, | |
415 index_buffer_size, indices); | |
416 | |
417 glEnable(GL_CULL_FACE); | |
418 | |
419 GLuint vertex_buffers[8]; | |
420 for (GLuint i = 0; i < sizeof(vertex_buffers)/sizeof(vertex_buffers[0]); i++) | |
421 vertex_buffers[i] = vertex_buffer; | |
422 | |
423 ShaderProgram program = AttributeFetchShaderProgram(1, vertex_buffers); | |
424 RunTest(DrawElementsTestFunc, | |
425 "mvtx_sec_attribute_fetch_shader", arg1, true); | |
426 glDeleteProgram(program); | |
427 | |
428 program = AttributeFetchShaderProgram(2, vertex_buffers); | |
429 RunTest(DrawElementsTestFunc, | |
430 "mvtx_sec_attribute_fetch_shader_2_attr", arg1, true); | |
431 glDeleteProgram(program); | |
432 | |
433 program = AttributeFetchShaderProgram(4, vertex_buffers); | |
434 RunTest(DrawElementsTestFunc, | |
435 "mvtx_sec_attribute_fetch_shader_4_attr", arg1, true); | |
436 glDeleteProgram(program); | |
437 | |
438 program = AttributeFetchShaderProgram(8, vertex_buffers); | |
439 RunTest(DrawElementsTestFunc, | |
440 "mvtx_sec_attribute_fetch_shader_8_attr", arg1, true); | |
441 glDeleteProgram(program); | |
442 | |
443 glDeleteBuffers(1, &index_buffer); | |
444 delete[] indices; | |
445 | |
446 glDeleteBuffers(1, &vertex_buffer); | |
447 delete[] vertices; | |
448 } | |
449 | |
450 | |
451 void VaryingsAndDdxyShaderTest() { | |
452 glViewport(-g_width, -g_height, g_width*2, g_height*2); | |
453 | |
454 const int c = 4; | |
455 GLfloat *vertices = NULL; | |
456 GLsizeiptr vertex_buffer_size = 0; | |
457 CreateLattice(&vertices, &vertex_buffer_size, 1.f / c, 1.f / c, c, c); | |
458 GLuint vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, | |
459 vertex_buffer_size, vertices); | |
460 | |
461 GLuint *indices = NULL; | |
462 GLuint index_buffer = 0; | |
463 GLsizeiptr index_buffer_size = 0; | |
464 | |
465 arg1 = CreateMesh(&indices, &index_buffer_size, c, c, 0); | |
466 index_buffer = SetupVBO(GL_ELEMENT_ARRAY_BUFFER, | |
467 index_buffer_size, indices); | |
468 | |
469 ShaderProgram program = VaryingsShaderProgram(1, vertex_buffer); | |
470 RunTest(DrawElementsTestFunc, | |
471 "mpixels_sec_varyings_shader_1", g_width * g_height, true); | |
472 glDeleteProgram(program); | |
473 | |
474 program = VaryingsShaderProgram(2, vertex_buffer); | |
475 RunTest(DrawElementsTestFunc, | |
476 "mpixels_sec_varyings_shader_2", g_width * g_height, true); | |
477 glDeleteProgram(program); | |
478 | |
479 program = VaryingsShaderProgram(4, vertex_buffer); | |
480 RunTest(DrawElementsTestFunc, | |
481 "mpixels_sec_varyings_shader_4", g_width * g_height, true); | |
482 glDeleteProgram(program); | |
483 | |
484 program = VaryingsShaderProgram(8, vertex_buffer); | |
485 RunTest(DrawElementsTestFunc, | |
486 "mpixels_sec_varyings_shader_8", g_width * g_height, true); | |
487 glDeleteProgram(program); | |
488 | |
489 program = DdxDdyShaderProgram(true, vertex_buffer); | |
490 RunTest(DrawElementsTestFunc, | |
491 "mpixels_sec_ddx_shader", g_width * g_height, true); | |
492 glDeleteProgram(program); | |
493 | |
494 program = DdxDdyShaderProgram(false, vertex_buffer); | |
495 RunTest(DrawElementsTestFunc, | |
496 "mpixels_sec_ddy_shader", g_width * g_height, true); | |
497 glDeleteProgram(program); | |
498 | |
499 glDeleteBuffers(1, &index_buffer); | |
500 delete[] indices; | |
501 | |
502 glDeleteBuffers(1, &vertex_buffer); | |
503 delete[] vertices; | |
504 } | |
505 | |
506 | |
507 void YuvToRgbShaderTestHelper(int type, const char *name) { | |
508 size_t size = 0; | |
509 GLuint texture[2]; | |
510 ShaderProgram program = 0; | |
511 GLuint vertex_buffer = 0; | |
512 GLfloat vertices[8] = { | |
513 0.f, 0.f, | |
514 1.f, 0.f, | |
515 0.f, 1.f, | |
516 1.f, 1.f, | |
517 }; | |
518 char evenodd[2] = {0, 255}; | |
519 const int pixel_height = YUV2RGB_HEIGHT * 2 / 3; | |
520 | |
521 char *pixels = static_cast<char *>(MmapFile(YUV2RGB_NAME, &size)); | |
522 if (!pixels) { | |
523 printf("# Could not open image file: %s\n", YUV2RGB_NAME); | |
524 goto done; | |
525 } | |
526 if (size != YUV2RGB_SIZE) { | |
527 printf("# Image file of wrong size, got %d, expected %d\n", | |
528 static_cast<int>(size), YUV2RGB_SIZE); | |
529 goto done; | |
530 } | |
531 | |
532 glGenTextures(2, texture); | |
533 glActiveTexture(GL_TEXTURE0); | |
534 glBindTexture(GL_TEXTURE_2D, texture[0]); | |
535 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
536 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
537 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH, YUV2RGB_HEIGHT, | |
538 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); | |
539 | |
540 glActiveTexture(GL_TEXTURE1); | |
541 glBindTexture(GL_TEXTURE_2D, texture[1]); | |
542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
543 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
544 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, | |
545 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd); | |
546 | |
547 glViewport(-YUV2RGB_WIDTH, -pixel_height, YUV2RGB_WIDTH*2, pixel_height * 2); | |
548 vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, sizeof(vertices), vertices); | |
549 | |
550 program = YuvToRgbShaderProgram(type, vertex_buffer, | |
551 YUV2RGB_WIDTH, pixel_height); | |
552 | |
553 if (program) { | |
554 float coeff = 1.f * | |
555 (YUV2RGB_WIDTH < g_width ? | |
556 static_cast<float>(YUV2RGB_WIDTH) / g_width : 1.f) * | |
557 (pixel_height < g_height ? | |
558 static_cast<float>(pixel_height) / g_height : 1.f); | |
559 FillRateTestNormal(name, coeff); | |
560 } else { | |
561 printf("# Could not set up YUV shader.\n"); | |
562 } | |
563 | |
564 done: | |
565 glDeleteProgram(program); | |
566 glDeleteTextures(2, texture); | |
567 glDeleteBuffers(1, &vertex_buffer); | |
568 munmap(pixels, size); | |
569 } | |
570 | |
571 void YuvToRgbShaderTest1() { | |
572 YuvToRgbShaderTestHelper(1, "yuv_shader_1"); | |
573 } | |
574 | |
575 void YuvToRgbShaderTest2() { | |
576 YuvToRgbShaderTestHelper(2, "yuv_shader_2"); | |
577 } | |
578 | |
579 static uint32_t texture_base[WINDOW_HEIGHT*WINDOW_WIDTH]; | |
580 static uint32_t texture_update[WINDOW_HEIGHT*WINDOW_WIDTH]; | |
581 #ifndef USE_EGL | |
582 static GLuint compositing_textures[5]; | |
583 static ShaderProgram compositing_background_program = 0; | |
584 static ShaderProgram compositing_foreground_program = 0; | |
585 #endif | |
586 | |
587 void InitBaseTexture() { | |
588 for (int y = 0; y < WINDOW_HEIGHT; y++) { | |
589 for (int x = 0; x < WINDOW_WIDTH; x++) { | |
590 // This color is gray, half alpha. | |
591 texture_base[y*WINDOW_WIDTH+x] = 0x80808080; | |
592 } | |
593 } | |
594 } | |
595 | |
596 // UpdateTexture simulates Chrome updating tab contents. | |
597 // We cause a bunch of read and write cpu memory bandwidth. | |
598 // It's a very rough approximation. | |
599 void UpdateTexture() { | |
600 memcpy(texture_update, texture_base, sizeof(texture_base)); | |
601 } | |
602 | |
603 void LoadTexture() { | |
604 // Use GL_RGBA for compatibility with GLES2.0. | |
605 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
606 WINDOW_WIDTH, WINDOW_HEIGHT, 0, | |
607 GL_RGBA, GL_UNSIGNED_BYTE, texture_update); | |
608 } | |
609 | |
610 #ifndef USE_EGL | |
611 // Test how fast we can do full-screen compositing of images | |
612 // continuously updated from the CPU. | |
613 // This tests both GPU compositing performance and also | |
614 // CPU -> GPU data transfer speed. | |
615 // It is a basic perf test to make sure we have enough performance | |
616 // to run a compositing window manager. | |
617 void CompositingTestFunc(int iter) { | |
618 for (int i = 0 ; i < iter; ++i) { | |
619 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
620 | |
621 // Draw the background | |
622 glDisable(GL_BLEND); | |
623 glDisable(GL_DEPTH_TEST); | |
624 // We have to blend three textures, but we use multi-texture for this | |
625 // blending, not fb blend, to avoid the external memory traffic | |
626 glActiveTexture(GL_TEXTURE0); | |
627 glBindTexture(GL_TEXTURE_2D, compositing_textures[0]); | |
628 glActiveTexture(GL_TEXTURE1); | |
629 glBindTexture(GL_TEXTURE_2D, compositing_textures[1]); | |
630 glActiveTexture(GL_TEXTURE2); | |
631 glBindTexture(GL_TEXTURE_2D, compositing_textures[2]); | |
632 // Set up the texture coordinate arrays | |
633 glClientActiveTexture(GL_TEXTURE0); | |
634 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
635 glClientActiveTexture(GL_TEXTURE1); | |
636 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
637 glClientActiveTexture(GL_TEXTURE2); | |
638 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
639 // Use the right shader | |
640 glUseProgram(compositing_background_program); | |
641 // Draw the quad | |
642 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
643 | |
644 // Set up one texture coordinate array | |
645 glClientActiveTexture(GL_TEXTURE0); | |
646 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
647 glClientActiveTexture(GL_TEXTURE1); | |
648 glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
649 glClientActiveTexture(GL_TEXTURE2); | |
650 glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
651 // Use the right shader | |
652 glUseProgram(compositing_foreground_program); | |
653 | |
654 // Compositing is blending, so we shall blend. | |
655 glEnable(GL_BLEND); | |
656 // Depth test is on for window occlusion | |
657 glEnable(GL_DEPTH_TEST); | |
658 | |
659 // Draw window number one | |
660 // This update acts like a chrome webkit sw rendering update. | |
661 glActiveTexture(GL_TEXTURE0); | |
662 glBindTexture(GL_TEXTURE_2D, compositing_textures[3]); | |
663 UpdateTexture(); | |
664 // TODO(papakipos): this LoadTexture is likely doing more CPU memory copies | |
665 // than we would like. | |
666 LoadTexture(); | |
667 // TODO(papakipos): add color interpolation here, and modulate | |
668 // texture against it. | |
669 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
670 | |
671 // Draw window number two | |
672 // This is a static window, so we don't update it. | |
673 glActiveTexture(GL_TEXTURE0); | |
674 glBindTexture(GL_TEXTURE_2D, compositing_textures[4]); | |
675 // TODO(papakipos): add color interpolation here, and modulate | |
676 // texture against it. | |
677 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
678 } | |
679 } | |
680 | |
681 void InitializeCompositing() { | |
682 InitBaseTexture(); | |
683 | |
684 glClearColor(0.f, 0.f, 0.f, 0.f); | |
685 glDisable(GL_DEPTH_TEST); | |
686 glDisable(GL_BLEND); | |
687 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
688 glDepthFunc(GL_LEQUAL); | |
689 | |
690 glGenTextures(5, compositing_textures); | |
691 glActiveTexture(GL_TEXTURE0); | |
692 for (int i = 0; i < 5; i++) { | |
693 glBindTexture(GL_TEXTURE_2D, compositing_textures[i]); | |
694 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
695 GL_LINEAR); | |
696 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, | |
697 GL_LINEAR); | |
698 } | |
699 | |
700 glColor4f(1.f, 1.f, 1.f, 1.f); | |
701 | |
702 // Set up the vertex arrays for drawing textured quads later on. | |
703 glEnableClientState(GL_VERTEX_ARRAY); | |
704 GLfloat buffer_vertex[8] = { | |
705 -1.f, -1.f, | |
706 1.f, -1.f, | |
707 -1.f, 1.f, | |
708 1.f, 1.f, | |
709 }; | |
710 GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER, | |
711 sizeof(buffer_vertex), buffer_vertex); | |
712 glVertexPointer(2, GL_FLOAT, 0, 0); | |
713 | |
714 GLfloat buffer_texture[8] = { | |
715 0.f, 0.f, | |
716 1.f, 0.f, | |
717 0.f, 1.f, | |
718 1.f, 1.f, | |
719 }; | |
720 GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER, | |
721 sizeof(buffer_texture), buffer_texture); | |
722 for (int i = 0; i < 3; i++) { | |
723 glClientActiveTexture(GL_TEXTURE0 + i); | |
724 glTexCoordPointer(2, GL_FLOAT, 0, 0); | |
725 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
726 } | |
727 | |
728 // Set up the static background textures. | |
729 UpdateTexture(); | |
730 UpdateTexture(); | |
731 UpdateTexture(); | |
732 // Load these textures into bound texture ids and keep using them | |
733 // from there to avoid having to reload this texture every frame | |
734 glActiveTexture(GL_TEXTURE0); | |
735 glBindTexture(GL_TEXTURE_2D, compositing_textures[0]); | |
736 LoadTexture(); | |
737 glActiveTexture(GL_TEXTURE1); | |
738 glBindTexture(GL_TEXTURE_2D, compositing_textures[1]); | |
739 LoadTexture(); | |
740 glActiveTexture(GL_TEXTURE2); | |
741 glBindTexture(GL_TEXTURE_2D, compositing_textures[2]); | |
742 LoadTexture(); | |
743 | |
744 glActiveTexture(GL_TEXTURE0); | |
745 glBindTexture(GL_TEXTURE_2D, compositing_textures[3]); | |
746 UpdateTexture(); | |
747 LoadTexture(); | |
748 | |
749 glActiveTexture(GL_TEXTURE0); | |
750 glBindTexture(GL_TEXTURE_2D, compositing_textures[4]); | |
751 UpdateTexture(); | |
752 LoadTexture(); | |
753 | |
754 // Set up vertex & fragment shaders. | |
755 compositing_background_program = | |
756 TripleTextureBlendShaderProgram(vbo_vertex, | |
757 vbo_texture, vbo_texture, vbo_texture); | |
758 compositing_foreground_program = | |
759 BasicTextureShaderProgram(vbo_vertex, vbo_texture); | |
760 if ((!compositing_background_program) || | |
761 (!compositing_foreground_program)) { | |
762 printf("# Could not set up compositing shader.\n"); | |
763 } | |
764 | |
765 glVertexPointer(2, GL_FLOAT, 0, 0); | |
766 } | |
767 | |
768 void TeardownCompositing() { | |
769 glDeleteProgram(compositing_background_program); | |
770 glDeleteProgram(compositing_foreground_program); | |
771 } | |
772 | |
773 // Notes on the window manager compositing test: | |
774 // Depth | |
775 // Depth complexity = 3: background, active window, static window | |
776 // Background: may be a tex-blend of three images (2.5d effect) | |
777 // The windows -- at most two, fullscreen | |
778 // Depth test is on, passing most of the time. | |
779 // A lot of texture min-filtering -- not modelled | |
780 // One of the two windows is getting live browser frame updates -- not mod | |
781 // The live window runs at x/2 and y/2 size -- not modelled | |
782 // The two windows are modulated by color interpolation to get gradient | |
783 static float screen_scale_factor = (1e6f* | |
784 (WINDOW_WIDTH*WINDOW_HEIGHT)/ | |
785 (1280.f*768)); | |
786 | |
787 void WindowManagerCompositingTest() { | |
788 InitializeCompositing(); | |
789 RunTest(CompositingTestFunc, "1280x768_fps_compositing", | |
790 screen_scale_factor, true); | |
791 TeardownCompositing(); | |
792 } | |
793 | |
794 void NoFillWindowManagerCompositingTest() { | |
795 glScissor(0, 0, 1, 1); | |
796 glEnable(GL_SCISSOR_TEST); | |
797 InitializeCompositing(); | |
798 RunTest(CompositingTestFunc, "1280x768_fps_no_fill_compositing", | |
799 screen_scale_factor, true); | |
800 TeardownCompositing(); | |
801 } | |
802 #endif | |
803 | |
804 void ReadPixelTestFunc(int iter) { | |
805 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, arg2); | |
806 CHECK(glGetError() == 0); | |
807 for (int i = 0; i < iter; i++) | |
808 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, arg2); | |
809 } | |
810 | |
811 // TODO: better test names. | |
812 void ReadPixelTest() { | |
813 // One GL_RGBA pixel takes 4 bytes. | |
814 const int row_size = g_width * 4; | |
815 // Default GL_PACK_ALIGNMENT is 4, round up pixel row size to multiple of 4. | |
816 // This is a no-op because row_size is already divisible by 4. | |
817 // One is added so that we can test reads into unaligned location. | |
818 char* pixels = new char[((row_size + 3) & ~3) * g_height + 1]; | |
819 | |
820 arg2 = pixels; | |
821 RunTest(ReadPixelTestFunc, "mpixels_sec_pixel_read", | |
822 g_width * g_height, true); | |
823 | |
824 // Reducing GL_PACK_ALIGNMENT can only make rows smaller. No need to | |
825 // reallocate the buffer. | |
826 glPixelStorei(GL_PACK_ALIGNMENT, 1); | |
827 RunTest(ReadPixelTestFunc, "mpixels_sec_pixel_read_2", | |
828 g_width * g_height, true); | |
829 | |
830 arg2 = static_cast<void*>(pixels + 1); | |
831 RunTest(ReadPixelTestFunc, "mpixels_sec_pixel_read_3", | |
832 g_width * g_height, true); | |
833 | |
834 delete[] pixels; | |
835 } | |
836 | 26 |
837 // TODO: use proper command line parsing library. | 27 // TODO: use proper command line parsing library. |
838 static void ParseArgs(int argc, char *argv[]) { | 28 static void ParseArgs(int argc, char *argv[]) { |
839 const char **enabled_tests_ptr = enabled_tests; | 29 const char **enabled_tests_ptr = enabled_tests; |
840 bool test_name_arg = false; | 30 bool test_name_arg = false; |
841 bool duration_arg = false; | 31 bool duration_arg = false; |
842 for (int i = 0; i < argc; i++) { | 32 for (int i = 0; i < argc; i++) { |
843 if (test_name_arg) { | 33 if (test_name_arg) { |
844 test_name_arg = false; | 34 test_name_arg = false; |
845 *enabled_tests_ptr++ = argv[i]; | 35 *enabled_tests_ptr++ = argv[i]; |
(...skipping 13 matching lines...) Expand all Loading... |
859 | 49 |
860 | 50 |
861 int main(int argc, char *argv[]) { | 51 int main(int argc, char *argv[]) { |
862 SetBasePathFromArgv0(argv[0], "src"); | 52 SetBasePathFromArgv0(argv[0], "src"); |
863 ParseArgs(argc, argv); | 53 ParseArgs(argc, argv); |
864 if (!Init()) { | 54 if (!Init()) { |
865 printf("# Failed to initialize.\n"); | 55 printf("# Failed to initialize.\n"); |
866 return 1; | 56 return 1; |
867 } | 57 } |
868 | 58 |
869 void (*test[])() = { | 59 glbench::TestBase* tests[] = { |
870 SwapTest, | 60 glbench::GetSwapTest(), |
871 ClearTest, | 61 glbench::GetClearTest(), |
872 AttributeFetchShaderTest, | 62 glbench::GetFillRateTest(), |
873 VaryingsAndDdxyShaderTest, | 63 glbench::GetYuvToRgbTest(1, "yuv_shader_1"), |
874 YuvToRgbShaderTest1, | 64 glbench::GetYuvToRgbTest(2, "yuv_shader_2"), |
875 YuvToRgbShaderTest2, | 65 glbench::GetReadPixelTest(), |
876 #ifndef USE_EGL | 66 glbench::GetTriangleSetupTest(), |
877 FillRateTest, | 67 glbench::GetAttributeFetchShaderTest(), |
878 TriangleSetupTest, | 68 glbench::GetVaryingsAndDdxyShaderTest(), |
879 NoFillWindowManagerCompositingTest, | 69 glbench::GetWindowManagerCompositingTest(false), |
880 WindowManagerCompositingTest, | 70 glbench::GetWindowManagerCompositingTest(true), |
881 #endif | |
882 ReadPixelTest, | |
883 }; | 71 }; |
884 | 72 |
885 uint64_t done = GetUTime() + 1000000ULL * seconds_to_run; | 73 for (unsigned int i = 0; i < arraysize(tests); i++) { |
886 do { | 74 InitContext(); |
887 for (unsigned int i = 0; i < sizeof(test) / sizeof(*test); i++) { | 75 tests[i]->Run(); |
888 InitContext(); | 76 DestroyContext(); |
889 test[i](); | 77 delete tests[i]; |
890 GLenum err = glGetError(); | 78 tests[i] = NULL; |
891 if (err != 0) | 79 } |
892 printf("# glGetError returned non-zero: 0x%x\n", err); | |
893 DestroyContext(); | |
894 } | |
895 } while (GetUTime() < done); | |
896 | 80 |
897 return 0; | 81 return 0; |
898 } | 82 } |
OLD | NEW |