perf/pixel-rate: new pixel throughput microbenchmark
[piglit.git] / tests / spec / ext_texture_norm16 / render.c
bloba773e70b18a08ed066d55e718dc34abfd07b9d72
1 /*
2 * Copyright © 2018 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 /**
25 * @file
26 * Basic tests for formats added by GL_EXT_texture_norm16 extension
28 * https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_norm16.txt
30 * Test includes:
31 * - texture uploads
32 * - mipmap generation
33 * - framebuffer creation
34 * - rendering to
35 * - reading from
36 * - interaction with GL_EXT_copy_image
37 * - interaction with GL_OES_texture_buffer
40 #include "piglit-util-gl.h"
42 PIGLIT_GL_TEST_CONFIG_BEGIN
43 config.supports_gl_es_version = 31;
44 config.window_visual = PIGLIT_GL_VISUAL_RGBA;
45 PIGLIT_GL_TEST_CONFIG_END
47 #define PIGLIT_RESULT(x) x ? PIGLIT_PASS : PIGLIT_FAIL
49 static const char vs_source[] =
50 "#version 310 es\n"
51 "layout(location = 0) in highp vec4 vertex;\n"
52 "layout(location = 1) in highp vec4 uv;\n"
53 "out highp vec2 tex_coord;\n"
54 "\n"
55 "void main()\n"
56 "{\n"
57 " gl_Position = vertex;\n"
58 " tex_coord = uv.st;\n"
59 "}\n";
61 static const char fs_source[] =
62 "#version 310 es\n"
63 "layout(location = 0) uniform sampler2D texture;\n"
64 "in highp vec2 tex_coord;\n"
65 "out highp vec4 color;\n"
66 "void main()\n"
67 "{\n"
68 " color = texture2D(texture, tex_coord);\n"
69 "}\n";
71 static const char fs_buf_source[] =
72 "#version 310 es\n"
73 "#extension GL_OES_texture_buffer : require\n"
74 "layout(location = 0) uniform highp samplerBuffer buf;\n"
75 "in highp vec2 tex_coord;\n"
76 "out highp vec4 color;\n"
77 "void main()\n"
78 "{\n"
79 " color = texelFetch(buf, 0);\n"
80 "}\n";
82 /* trianglestrip, interleaved vertices + texcoords */
83 static const GLfloat vertex_data[] = {
84 -1.0f, 1.0f,
85 0.0f, 1.0f,
86 1.0f, 1.0f,
87 1.0f, 1.0f,
88 -1.0f, -1.0f,
89 0.0f, 0.0f,
90 1.0f, -1.0f,
91 1.0f, 0.0f
94 static struct fmt_test {
95 GLenum iformat;
96 GLenum base_format;
97 unsigned bpp;
98 GLenum type;
99 bool req_render;
100 bool can_read;
101 bool can_texbuf;
102 } tests[] = {
103 { GL_R16_EXT, GL_RED, 2, GL_UNSIGNED_SHORT, true, true, true },
104 { GL_RG16_EXT, GL_RG, 4, GL_UNSIGNED_SHORT, true, true, true },
105 { GL_RGB16_EXT, GL_RGB, 6, GL_UNSIGNED_SHORT, false, true, false },
106 { GL_RGBA16_EXT, GL_RGBA, 8, GL_UNSIGNED_SHORT, true, true, true },
107 { GL_R16_SNORM_EXT, GL_RED, 2, GL_SHORT, false, false, false },
108 { GL_RG16_SNORM_EXT, GL_RG, 4, GL_SHORT, false, false, false },
109 { GL_RGB16_SNORM_EXT, GL_RGB, 6, GL_SHORT, false, false, false },
110 { GL_RGBA16_SNORM_EXT, GL_RGBA, 8, GL_SHORT, false, false, false },
113 static GLuint prog;
114 static GLuint buf_prog;
116 static void
117 upload(const struct fmt_test *test, void *data)
119 /* glGenerateMipmap only for color renderable formats. */
120 if (test->req_render) {
121 glTexStorage2D(GL_TEXTURE_2D, 4, test->iformat, piglit_width,
122 piglit_height);
123 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, piglit_width,
124 piglit_height, test->base_format, test->type,
125 data);
126 glGenerateMipmap(GL_TEXTURE_2D);
127 return;
129 glTexImage2D(GL_TEXTURE_2D, 0, test->iformat, piglit_width,
130 piglit_height, 0, test->base_format, test->type, data);
133 static unsigned
134 get_max_value(GLenum type)
136 return type == GL_SHORT ? SHRT_MAX : USHRT_MAX;
139 static void
140 value_for_format(const struct fmt_test *test, unsigned short *value)
142 unsigned short val = get_max_value(test->type);
144 /* red */
145 value[0] = val;
146 /* yellow */
147 if (test->bpp > 2)
148 value[1] = val;
149 /* pink */
150 if (test->bpp > 4) {
151 value[2] = val;
152 value[1] = 0;
154 /* blue */
155 if (test->bpp > 6) {
156 value[3] = val;
157 value[0] = 0;
161 static void
162 generate_data(const struct fmt_test *test)
164 unsigned pixels = piglit_width * piglit_height;
165 char *data = malloc (pixels * test->bpp);
166 unsigned short *p = (unsigned short *) data;
168 for (unsigned i = 0; i < pixels; i++, p += test->bpp / 2)
169 value_for_format(test, p);
171 upload(test, data);
172 free(data);
175 static GLuint
176 create_empty_texture()
178 GLuint tex;
179 glGenTextures(1, &tex);
180 glBindTexture(GL_TEXTURE_2D, tex);
182 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
183 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
187 return tex;
190 static GLuint
191 create_texture(const struct fmt_test *test)
193 GLuint tex = create_empty_texture();
194 generate_data(test);
195 return tex;
198 static GLuint
199 create_rbo(const struct fmt_test *test)
201 GLuint rbo;
202 glGenRenderbuffers(1, &rbo);
203 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
204 glRenderbufferStorage(GL_RENDERBUFFER, test->iformat, piglit_width,
205 piglit_height);
206 return rbo;
209 static GLuint
210 create_fbo(const struct fmt_test *test, GLuint *tex)
212 GLuint fbo;
213 GLuint fbo_tex = create_texture(test);
215 *tex = fbo_tex;
217 glGenFramebuffers(1, &fbo);
218 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
219 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
220 GL_TEXTURE_2D, fbo_tex, 0);
221 return fbo;
224 static void
225 render_texture(GLuint texture, GLenum target, GLuint fbo_target)
227 glBindTexture(target, texture);
228 glBindFramebuffer(GL_FRAMEBUFFER, fbo_target);
230 glViewport(0, 0, piglit_width, piglit_height);
232 glClear(GL_COLOR_BUFFER_BIT);
233 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
236 static bool
237 verify_contents(const struct fmt_test *test)
239 bool result = true;
240 unsigned amount = piglit_width * piglit_height;
241 unsigned short *pix = malloc (amount * 8);
242 glReadPixels(0, 0, piglit_width, piglit_height, GL_RGBA, test->type,
243 pix);
245 /* Setup expected value, alpha is always max in the test. */
246 unsigned short value[4] = { 0 };
247 value_for_format(test, value);
248 value[3] = get_max_value(test->type);
250 unsigned short *p = pix;
251 for (unsigned i = 0; i < amount; i++, p += 4) {
252 if (memcmp(p, value, sizeof(value)) == 0)
253 continue;
255 piglit_report_subtest_result(PIGLIT_FAIL,
256 "format %s read fail",
257 piglit_get_gl_enum_name(test->iformat));
258 result = false;
259 break;
262 free(pix);
263 return result;
266 static bool
267 verify_contents_float(const struct fmt_test *test)
269 /* Setup expected value, alpha is always max in the test. */
270 unsigned short value[4] = { 0 };
271 unsigned short max = get_max_value(test->type);
272 value_for_format(test, value);
273 value[3] = max;
275 const float expected[4] = {
276 value[0] / max,
277 value[1] / max,
278 value[2] / max,
279 value[3] / max,
282 bool res = piglit_probe_rect_rgba(0, 0, piglit_width, piglit_height,
283 expected);
284 return res;
287 static bool
288 test_copy_image(const struct fmt_test *test, GLuint src, GLuint *texture)
290 bool result = true;
291 GLuint tex = create_texture(test);
292 *texture = tex;
293 glCopyImageSubData(src, GL_TEXTURE_2D, 0, 0, 0, 0, tex, GL_TEXTURE_2D,
294 0, 0, 0, 0, piglit_width, piglit_height, 0);
296 if (!piglit_check_gl_error(GL_NO_ERROR)) {
297 piglit_report_subtest_result(PIGLIT_FAIL,
298 "format %s copyimage fail",
299 piglit_get_gl_enum_name(test->iformat));
300 result = false;
302 return result;
305 static bool
306 buffer_test(const struct fmt_test *test)
308 GLuint tex, tbo;
310 /* Setup expected value, alpha is always max in the test. */
311 unsigned short tbo_data[4] = { 0 };
312 value_for_format(test, tbo_data);
313 tbo_data[3] = get_max_value(test->type);
315 glGenBuffers(1, &tbo);
316 glBindBuffer(GL_TEXTURE_BUFFER, tbo);
317 glBufferData(GL_TEXTURE_BUFFER, sizeof(tbo_data), tbo_data,
318 GL_STATIC_DRAW);
320 glGenTextures(1, &tex);
321 glBindTexture(GL_TEXTURE_BUFFER, tex);
323 glTexBuffer(GL_TEXTURE_BUFFER, test->iformat, tbo);
325 if (!piglit_check_gl_error(GL_NO_ERROR))
326 return false;
328 glUseProgram(buf_prog);
329 glUniform1i(0 /* explicit loc */, 0);
331 render_texture(tex, GL_TEXTURE_BUFFER, 0);
333 if (!verify_contents_float(test))
334 return false;
336 piglit_present_results();
338 glDeleteTextures(1, &tex);
340 glBindBuffer(GL_TEXTURE_BUFFER, 0);
342 return true;
346 static bool
347 test_format(const struct fmt_test *test)
349 bool pass = true;
351 if (piglit_is_extension_supported("GL_OES_texture_buffer") &&
352 test->can_texbuf) {
353 bool buf_test = buffer_test(test);
354 piglit_report_subtest_result(PIGLIT_RESULT(buf_test),
355 "format %s TBO test",
356 piglit_get_gl_enum_name(test->iformat));
357 pass &= buf_test;
360 glUseProgram(prog);
361 glUniform1i(0 /* explicit loc */, 0);
363 /* Create a texture, upload data */
364 const GLuint texture = create_texture(test);
366 glBindTexture(GL_TEXTURE_2D, texture);
368 /* Can only texture from. */
369 if (!test->req_render) {
370 /* Render texture to window and verify contents. */
371 render_texture(texture, GL_TEXTURE_2D, 0);
372 bool render_test = verify_contents_float(test);
373 piglit_present_results();
374 glDeleteTextures(1, &texture);
375 pass &= render_test;
376 return pass;
379 /* Test glRenderbufferStorage. */
380 GLuint rbo = create_rbo(test);
381 if (!rbo || !piglit_check_gl_error(GL_NO_ERROR)) {
382 piglit_report_subtest_result(PIGLIT_FAIL,
383 "format %s RBO test",
384 piglit_get_gl_enum_name(test->iformat));
385 pass &= false;
386 } else {
387 piglit_report_subtest_result(PIGLIT_PASS,
388 "format %s RBO test",
389 piglit_get_gl_enum_name(test->iformat));
391 glDeleteRenderbuffers(1, &rbo);
393 /* Create framebuffer object. */
394 GLuint fbo_tex;
395 const GLuint fbo = create_fbo(test, &fbo_tex);
397 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
398 GL_FRAMEBUFFER_COMPLETE) {
399 piglit_report_subtest_result(PIGLIT_FAIL,
400 "format %s fbo fail",
401 piglit_get_gl_enum_name(test->iformat));
402 pass &= false;
405 render_texture(texture, GL_TEXTURE_2D, fbo);
407 /* Test glCopyTexImage2D by copying current fbo content to
408 * a texture, rendering copy back to fbo and verifying fbo contents.
410 GLuint tmp_tex = create_empty_texture();
411 glCopyTexImage2D(GL_TEXTURE_2D, 0, test->iformat, 0, 0, piglit_width,
412 piglit_height, 0);
414 render_texture(tmp_tex, GL_TEXTURE_2D, fbo);
416 /* If format can be read, verify contents. */
417 if (test->can_read)
418 pass &= verify_contents(test);
420 glDeleteTextures(1, &tmp_tex);
422 /* If GL_EXT_copy_image is supported then create another
423 * texture, copy contents and render result to fbo.
425 GLuint texture_copy = 0;
426 if (piglit_is_extension_supported("GL_EXT_copy_image")) {
427 bool copy_pass =
428 test_copy_image(test, texture, &texture_copy);
429 pass &= copy_pass;
430 piglit_report_subtest_result(PIGLIT_RESULT(copy_pass),
431 "copy image format %s",
432 piglit_get_gl_enum_name(test->iformat));
433 render_texture(texture_copy, GL_TEXTURE_2D, fbo);
436 /* If format can be read, verify contents. */
437 if (test->can_read)
438 pass &= verify_contents(test);
440 /* Render fbo contents to window. */
441 render_texture(fbo_tex, GL_TEXTURE_2D, 0);
443 piglit_present_results();
445 glDeleteFramebuffers(1, &fbo);
446 glDeleteTextures(1, &texture);
447 glDeleteTextures(1, &texture_copy);
449 return pass;
452 enum piglit_result
453 piglit_display(void)
455 glEnableVertexAttribArray(0);
456 glEnableVertexAttribArray(1);
458 glActiveTexture(GL_TEXTURE0);
460 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
461 vertex_data);
462 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
463 (void*) (vertex_data + (2 * sizeof(float))));
465 bool pass = true;
467 struct fmt_test *test = tests;
468 /* Toggle 'req_rend' for EXT_render_snorm compatible formats. */
469 if (piglit_is_extension_supported("GL_EXT_render_snorm")) {
470 for (unsigned i = 0; i < ARRAY_SIZE(tests); i++, test++) {
471 switch (test->iformat) {
472 case GL_R16_SNORM_EXT:
473 case GL_RG16_SNORM_EXT:
474 case GL_RGBA16_SNORM_EXT:
475 test->req_render = true;
476 test->can_read = true;
481 /* Loop over each format. */
482 test = tests;
483 for (unsigned i = 0; i < ARRAY_SIZE(tests); i++, test++) {
484 bool fmt_pass = test_format(test);
485 piglit_report_subtest_result(PIGLIT_RESULT(fmt_pass),
486 "format %s",
487 piglit_get_gl_enum_name(test->iformat));
488 pass &= fmt_pass;
491 if (!piglit_check_gl_error(GL_NO_ERROR))
492 piglit_report_result(PIGLIT_FAIL);
494 return PIGLIT_RESULT(pass);
497 void
498 piglit_init(int argc, char **argv)
500 piglit_require_extension("GL_EXT_texture_norm16");
502 prog = piglit_build_simple_program(vs_source, fs_source);
504 if (piglit_is_extension_supported("GL_OES_texture_buffer"))
505 buf_prog = piglit_build_simple_program(vs_source,
506 fs_buf_source);