perf/pixel-rate: new pixel throughput microbenchmark
[piglit.git] / tests / spec / ext_shader_image_load_store / image_functions.c
blobd947917f674330c73df83e24949a9486a1f00238
1 /*
2 * Copyright © 2019 Advanced Micro Devices, Inc.
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 /** @file image_functions.c
26 * Test the new GLSL image functions.
28 * Two categories of tests in this file:
29 * - for the functions existing both in ARB_shader_image_load_store and
30 * EXT_shader_image_load_store, we simply build a program to verify that
31 * they're available.
32 * - for the 2 functions that only exist in EXT (atomicIncWrap and atomicDecWrap),
33 * we verify their behavior. Note: on nvidia this test needs to be used with
34 * "-fbo" argument.
37 #include "piglit-util-gl.h"
39 PIGLIT_GL_TEST_CONFIG_BEGIN
41 config.supports_gl_core_version = 32;
43 PIGLIT_GL_TEST_CONFIG_END
45 struct test_data {
46 const char* function_name;
47 unsigned (*compute_ref_value) (int num_exec, unsigned wrap);
48 const char* type;
49 GLuint (*create_texture) (unsigned tex_width);
50 void (*read_texture) (void* data, size_t s);
53 static GLuint
54 create_texture(unsigned tex_width)
56 int* data;
57 GLuint texture;
58 glGenTextures(1, &texture);
59 glBindTexture(GL_TEXTURE_1D, texture);
61 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
62 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
63 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
64 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
66 data = (int*) malloc(tex_width * sizeof(int));
67 memset(data, 0, tex_width * sizeof(int));
68 glTexImage1D(GL_TEXTURE_1D, 0, GL_R32I, tex_width, 0, GL_RED_INTEGER, GL_INT, data);
69 free(data);
71 return texture;
74 static void
75 read_texture(void* data, size_t s)
77 glGetTexImage(GL_TEXTURE_1D, 0,
78 GL_RED_INTEGER,
79 GL_INT,
80 data);
83 static GLuint
84 create_buffer_texture(unsigned tex_width)
86 int* data;
87 GLuint texture, buffer;
88 glGenTextures(1, &texture);
89 glBindTexture(GL_TEXTURE_BUFFER, texture);
91 data = (int*) malloc(tex_width * sizeof(int));
92 memset(data, 0, tex_width * sizeof(int));
94 glGenBuffers(1, &buffer);
95 glBindBuffer(GL_ARRAY_BUFFER, buffer);
96 glBufferStorage(GL_ARRAY_BUFFER, tex_width * sizeof(int), data, GL_MAP_READ_BIT);
98 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer);
99 free(data);
101 return texture;
104 static void
105 read_buffer_texture(void* data, size_t s)
107 GLint buffer;
108 glGetIntegerv(GL_TEXTURE_BINDING_BUFFER, &buffer);
109 glGetBufferSubData(GL_ARRAY_BUFFER, 0, s, data);
110 glDeleteBuffers(1, (GLuint*) &buffer);
113 static enum piglit_result
114 run_test(void * _data)
116 const char* vs =
117 "attribute vec4 piglit_vertex;\n"
118 "void main()\n"
119 "{\n"
120 "gl_Position = piglit_vertex;\n"
121 "}\n";
123 static const char* fs_template =
124 "#version 150\n"
125 "#extension GL_EXT_shader_image_load_store : enable\n"
126 "uniform int index;\n"
127 "uniform uint wrap_value;\n"
128 "layout(size1x32) uniform %s image;\n"
129 "void main() {\n"
130 " uint res = %s(image, index, wrap_value);\n"
131 " gl_FragColor.rgb = vec3(float(res) / float(wrap_value));\n"
132 " gl_FragColor.a = 1.0;\n"
133 "}\n";
135 char fs[1024];
136 bool pass = true;
137 const struct test_data* test = (const struct test_data*) _data;
139 sprintf(fs, fs_template, test->type, test->function_name);
141 GLint program = piglit_build_simple_program(vs, fs);
142 GLint image_location = glGetUniformLocation(program, "image");
143 GLint wrap_location = glGetUniformLocation(program, "wrap_value");
144 GLint index_location = glGetUniformLocation(program, "index");
146 int texture_size[] = {32, 50, 60, 128};
147 int wrap_value[] = {12, 29, 17, 41};
148 GLint read_back[128];
149 for (int i = 0; i < ARRAY_SIZE(texture_size); i++) {
150 GLuint texture = test->create_texture(texture_size[i]);
151 int index = rand() % texture_size[i];
152 glBindImageTextureEXT(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
154 glUseProgram(program);
155 glUniform1i(image_location, 0);
156 glUniform1ui(wrap_location, wrap_value[i]);
157 glUniform1i(index_location, index);
159 piglit_draw_rect(-1, -1, 2.0, 2.0);
161 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT |
162 GL_BUFFER_UPDATE_BARRIER_BIT |
163 GL_PIXEL_BUFFER_BARRIER_BIT |
164 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
166 test->read_texture(read_back, texture_size[i] * sizeof(int));
168 GLuint ref_value = test->compute_ref_value(piglit_width * piglit_height, wrap_value[i]);
170 /* The first component of the pixel at index has been written to by all invocations */
171 pass = pass && read_back[index] == ref_value;
173 /* All other pixels/components should be untouched */
174 for (int j = 0; j < texture_size[i]; j++) {
175 pass = pass && (j == index || read_back[j] == 0);
177 glDeleteTextures(1, &texture);
179 piglit_present_results();
182 glDeleteProgram(program);
183 return pass && piglit_check_gl_error(GL_NO_ERROR) ?
184 PIGLIT_PASS : PIGLIT_FAIL;
187 static enum piglit_result
188 run_compile_test(void * data)
190 /* Type of the uniform variable used in imageStore */
191 static const char* v_value_type[] = { "vec4", "ivec4", "uvec4" };
192 /* Type of the uniform variable used in the atomic operations */
193 static const char* i_value_type[] = { "float", "int", "uint" };
194 /* Layout qualifier for the image */
195 static const char* qualifiers[] = {
196 "size1x8", "size1x16", "size1x32", "size2x32", "size4x32"
198 /* 'coord' variable */
199 static const char* coords[] = {
200 "int coord = 0",
201 "ivec2 coord = ivec2(0)",
202 "ivec3 coord = ivec3(0)",
204 /* Types of the image variable using a 'int' for the coord */
205 static const char* types_int[] = {
206 "image1D", "iimage1D", "uimage1D", "imageBuffer", NULL,
208 /* Types of the image variable using a 'ivec2' for the coord */
209 static const char* types_ivec2[] = {
210 "image2D", "iimage2D", "uimage2D",
211 "image2DRect", "iimage2DRect", "uimage2DRect",
212 "image1DArray", "iimage1DArray", "uimage1DArray",
213 NULL
215 /* Types of the image variable using a 'ivec3' for the coord */
216 static const char* types_ivec3[] = {
217 "image3D", "iimage3D", "uimage3D",
218 "imageCube", "iimageCube", "uimageCube",
219 "image2DArray", "iimage2DArray", "uimage2DArray",
220 "imageCubeArray", "iimageCubeArray", "uimageCubeArray",
221 NULL
223 /* Fragment shader template */
224 static const char* fs_template =
225 "#version 150\n"
226 "#extension GL_ARB_ES3_1_compatibility: %s\n"
227 "#extension GL_EXT_shader_image_load_store : enable\n"
228 "uniform uint wrap_value;\n"
229 "uniform %s v_value;\n"
230 "uniform %s i_value;\n"
231 "layout(%s) uniform %s image;\n"
232 "void main() {\n"
233 " %s;\n"
234 " %s;\n"
235 "}\n";
237 char fs[2048];
238 enum piglit_result res = PIGLIT_PASS;
240 static const char** types[] = {
241 types_int, types_ivec2, types_ivec3
244 const bool atomicOp = strstr(data, "Atomic") != NULL;
245 const bool atomicOpWrap = atomicOp && strstr(data, "Wrap") != NULL;
246 const bool atomicOpExchange = atomicOp && strstr(data, "Exchange") != NULL;
247 bool enable_arb_es31_compat = false;
249 for (int i = 0; i < ARRAY_SIZE(qualifiers); i++) {
250 for (int j = 0; j < ARRAY_SIZE(types); j++) {
251 for (int k = 0; types[j][k]; k++) {
252 bool is_valid = true;
253 bool floatImageType = strncmp(types[j][k], "image", 5) == 0;
254 bool signedImageType = strncmp(types[j][k], "iimage", 6) == 0;
256 /* The EXT_shader_image_load_store spec says:
257 * These functions [atomic functions] support 32-bit unsigned integer
258 * operands and 32-bit signed integer operands.
260 if (atomicOp && floatImageType) {
261 is_valid = false;
262 /* The GL_ARB_ES3_1_compatibility says:
263 * a new GLSL built-in function, imageAtomicExchange, which performs atomic
264 * exchanges on r32f floating point images.
266 if (atomicOpExchange && piglit_is_extension_supported("GL_ARB_ES3_1_compatibility")) {
267 enable_arb_es31_compat = true;
268 is_valid = true;
272 /* The EXT_shader_image_load_store spec says:
273 * These functions [imageAtomicIncWrap and imageAtomicDecWrap] support
274 * only 32-bit unsigned integer operands.
276 if (atomicOpWrap && signedImageType)
277 is_valid = false;
279 /* The EXT_shader_image_load_store spec says:
280 * A layout of "size1x8" is illegal for image variables associated
281 * with floating-point data types.
283 if (floatImageType && i == 0)
284 is_valid = false;
286 /* The says:
287 * The format of the image unit must be in the "1x32" equivalence
288 * class [...] otherwise the atomic operation is invalid.
290 if (atomicOp && i != 2)
291 is_valid = false;
293 /* Build the fragment template */
294 sprintf(fs, fs_template,
295 enable_arb_es31_compat ? "enable" : "disable",
296 v_value_type[k % 3],
297 i_value_type[k % 3],
298 qualifiers[i],
299 types[j][k],
300 coords[j],
301 (char*) data);
303 /* And verify we can build the fragment shader */
304 GLint program = piglit_compile_shader_text_nothrow(GL_FRAGMENT_SHADER, fs, is_valid);
305 if (is_valid != (bool) program) {
306 res = PIGLIT_FAIL;
308 if (program)
309 glDeleteShader(program);
314 return res;
317 static unsigned compute_imageAtomicIncWrap(int num_exec, unsigned wrap)
319 unsigned value = 0;
320 /* The EXT_shader_image_load_store spec says:
322 * imageAtomicIncWrap() computes a new value by adding one to the contents of
323 * the selected texel, and then forcing the result to zero if and only if the
324 * incremented value is greater than or equal to <wrap>. These functions
325 * support only 32-bit unsigned integer operands.
327 for (int i = 0; i < num_exec; i++) {
328 value += 1;
329 /* nvidia and amdgpu-pro drivers interprets the spec as > instead of >= */
330 if (value > wrap) {
331 value = 0;
334 return value;
337 static unsigned compute_imageAtomicDecWrap(int num_exec, unsigned wrap)
339 unsigned value = 0;
340 /* The EXT_shader_image_load_store spec says:
342 * imageAtomicDecWrap() computes a new value by subtracting one from the
343 * contents of the selected texel, and then forcing the result to <wrap>-1 if
344 * the original value read from the selected texel was either zero or greater
345 * than <wrap>. These functions support only 32-bit unsigned integer
346 * operands.
348 for (int i = 0; i < num_exec; i++) {
349 if (value == 0 || value > wrap) {
350 /* nvidia and amdgpu-pro drivers wraps to "wrap" and not "wrap - 1" */
351 value = wrap;
352 } else {
353 value -= 1;
356 return value;
359 void
360 piglit_init(int argc, char **argv)
362 struct test_data test_data[] = {
364 "imageAtomicIncWrap",
365 compute_imageAtomicIncWrap,
366 "uimage1D",
367 create_texture,
368 read_texture
371 "imageAtomicIncWrap",
372 compute_imageAtomicIncWrap,
373 "uimageBuffer",
374 create_buffer_texture,
375 read_buffer_texture
378 "imageAtomicDecWrap",
379 compute_imageAtomicDecWrap,
380 "uimage1D",
381 create_texture,
382 read_texture
385 "imageAtomicDecWrap",
386 compute_imageAtomicDecWrap,
387 "uimageBuffer",
388 create_buffer_texture,
389 read_buffer_texture
392 const struct piglit_subtest tests[] =
395 "imageAtomicIncWrap uimage1D",
396 NULL,
397 run_test,
398 &test_data[0],
401 "imageAtomicIncWrap uimageBuffer",
402 NULL,
403 run_test,
404 &test_data[1],
407 "imageAtomicDecWrap uimage1D",
408 NULL,
409 run_test,
410 &test_data[2],
413 "imageAtomicDecWrap uimageBuffer",
414 NULL,
415 run_test,
416 &test_data[3],
418 /* Compile only tests */
420 "imageLoad",
421 NULL,
422 run_compile_test,
423 "imageLoad(image, coord)",
426 "imageStore",
427 NULL,
428 run_compile_test,
429 "imageStore(image, coord, v_value)",
432 "imageAtomicAdd",
433 NULL,
434 run_compile_test,
435 "imageAtomicAdd(image, coord, i_value)",
438 "imageAtomicMin",
439 NULL,
440 run_compile_test,
441 "imageAtomicMin(image, coord, i_value)",
444 "imageAtomicMax",
445 NULL,
446 run_compile_test,
447 "imageAtomicMax(image, coord, i_value)",
450 "imageAtomicAnd",
451 NULL,
452 run_compile_test,
453 "imageAtomicAnd(image, coord, i_value)",
456 "imageAtomicOr",
457 NULL,
458 run_compile_test,
459 "imageAtomicOr(image, coord, i_value)",
462 "imageAtomicXor",
463 NULL,
464 run_compile_test,
465 "imageAtomicXor(image, coord, i_value)",
468 "imageAtomicExchange",
469 NULL,
470 run_compile_test,
471 "imageAtomicExchange(image, coord, i_value)",
474 "imageAtomicCompSwap",
475 NULL,
476 run_compile_test,
477 "imageAtomicCompSwap(image, coord, i_value, i_value)",
480 "imageAtomicIncWrap",
481 NULL,
482 run_compile_test,
483 "imageAtomicIncWrap(image, coord, wrap_value)",
486 "imageAtomicDecWrap",
487 NULL,
488 run_compile_test,
489 "imageAtomicDecWrap(image, coord, wrap_value)",
491 {0},
494 piglit_require_extension("GL_EXT_shader_image_load_store");
496 enum piglit_result result = PIGLIT_PASS;
498 result = piglit_run_selected_subtests(
499 tests,
500 NULL,
502 PIGLIT_PASS);
504 piglit_report_result(result);
507 enum piglit_result
508 piglit_display(void)
510 return PIGLIT_FAIL;