static bool check(const struct grid_info grid, const struct image_info img) { const int n = num_images_for_stages(grid, ~0); const int m = max_image_units(); uint32_t pixels[N], expect[N]; int i; for (i = 0; i < N; ++i) { if (i < m) { /* * The sum at this location is just the number * of times that the image with index i was * bound to the pipeline. */ expect[i] = (n - i + m - 1) / m; } else { /* * No image has a non-zero value at this * location, so the sum is zero. */ expect[i] = 0; } } return download_result(grid, pixels) && check_pixels_v(img, pixels, expect); }
bool init_fb(const struct grid_info grid) { bool ret = true; if (grid.stages & GL_COMPUTE_SHADER_BIT) { const struct image_info img = image_info_for_grid(grid); const unsigned n = product(grid.size) * image_num_components(grid.format); uint32_t *pixels = malloc(n * sizeof(*pixels)); ret = init_pixels(img, pixels, 0.5, 0.5, 0.5, 0.5) && upload_image(img, max_image_units(), pixels); free(pixels); } else { ret = generate_fb(grid, 0); glClearColor(0.5, 0.5, 0.5, 0.5); glClear(GL_COLOR_BUFFER_BIT); glClearDepth(0.5); glClear(GL_DEPTH_BUFFER_BIT); } return ret; }
/** * Bind all image uniforms present in the program to the available * image units, re-using the same unit several times if necessary in * cyclical order. */ static bool bind_images(const struct grid_info grid, GLuint prog) { const unsigned m = max_image_units(); const struct image_stage_info *stage; for (stage = image_stages(); stage->name; ++stage) { if (grid.stages & stage->bit) { const unsigned first = num_images_for_stages(grid, stage->bit - 1); const unsigned n = num_images_for_stage(grid, stage); const unsigned stage_idx = stage - image_stages(); int i; for (i = 0; i < n; ++i) { char *name = NULL; asprintf(&name, "imgs_%d[%d]", stage_idx, i); if (!set_uniform_int(prog, name, (first + i) % m)) return false; free(name); } } } return true; }
/** * Bind a number of texture objects to different image units and check * that the image unit state was updated correctly. */ static bool run_test_binding(void) { const struct image_unit_action *action; bool ret = true; int i; for (action = actions; action->action; ++action) ret &= exec_action(*action); for (i = 0; i < max_image_units(); ++i) ret &= check_action(get_last_unit_action(i)); return ret; }
static bool init_images(const struct image_info img) { uint32_t pixels[N]; int unit, i; for (unit = 0; unit < max_image_units(); ++unit) { for (i = 0; i < N; ++i) pixels[i] = (i == unit ? 1 : 0); if (!upload_image(img, unit, pixels)) return false; } return true; }
bool download_result(const struct grid_info grid, uint32_t *r_pixels) { if (grid.stages & GL_COMPUTE_SHADER_BIT) { /* No actual framebuffer. Results are returned into * an image. */ return download_image(image_info_for_grid(grid), max_image_units(), r_pixels); } else { glReadPixels(0, 0, grid.size.x, grid.size.y, grid.format->pixel_format, image_base_type(grid.format), r_pixels); return piglit_check_gl_error(GL_NO_ERROR); } }
/** * Execute the given action. */ static bool exec_action(const struct image_unit_action a) { if (a.action == BIND_NEW) { const GLenum format = (get_image_format(a.format) ? a.format : GL_RGBA32F); const struct image_info img = image_info(a.obj, format, W, H); const unsigned num_levels = image_num_levels(img); uint32_t pixels[4 * N * M] = { 0 }; if (!upload_image_levels(img, num_levels, 0, a.idx, pixels)) return false; glBindImageTexture(a.idx, get_texture(a.idx), a.level, a.layered, a.layer, a.access, a.format); } else if (a.action == BIND_IDX) { const unsigned idx = MIN2(a.idx, max_image_units()); glBindImageTexture(idx, get_texture(a.obj), a.level, a.layered, a.layer, a.access, a.format); } else if (a.action == BIND_OBJ) { glBindImageTexture(a.idx, a.obj, a.level, a.layered, a.layer, a.access, a.format); } else if (a.action == DELETE_IDX) { GLuint tex = get_texture(a.idx); glDeleteTextures(1, &tex); } else { abort(); } return piglit_check_gl_error(a.expect_status); }
/** * Test binding image uniforms to image units for a simple shader * program. */ static bool run_test_uniform(void) { const struct grid_info grid = grid_info(GL_FRAGMENT_SHADER, GL_RGBA32F, W, H); GLuint prog = generate_program( grid, GL_FRAGMENT_SHADER, concat(image_hunk(image_info_for_grid(grid), ""), hunk("uniform IMAGE_T imgs[2];\n" "\n" "GRID_T op(ivec2 idx, GRID_T x) {\n" " imageStore(imgs[0], IMAGE_ADDR(idx), x);\n" " imageStore(imgs[1], IMAGE_ADDR(idx), x);\n" " return x;\n" "}\n"), NULL)); const int loc = glGetUniformLocation(prog, "imgs"); bool ret = prog && check_uniform_int(prog, loc, 0) && check_uniform_int(prog, loc + 1, 0); int v[2]; glUseProgram(prog); /* * Image uniforms are bound to image units using * glUniform1i{v}. */ glUniform1i(loc, 3); ret &= check_uniform_int(prog, loc, 3) && check_uniform_int(prog, loc + 1, 0); glUniform1i(loc + 1, 3); ret &= check_uniform_int(prog, loc, 3) && check_uniform_int(prog, loc + 1, 3); v[0] = 4; v[1] = 5; glUniform1iv(loc, 2, v); ret &= check_uniform_int(prog, loc, 4) && check_uniform_int(prog, loc + 1, 5); /* * GL_INVALID_VALUE is generated if the value specified is * greater than or equal to the value of GL_MAX_IMAGE_UNITS. */ glUniform1i(loc, max_image_units()); ret &= piglit_check_gl_error(GL_INVALID_VALUE); v[0] = 3; v[1] = max_image_units() + 1; glUniform1iv(loc, 2, v); ret &= piglit_check_gl_error(GL_INVALID_VALUE); /* * GL_INVALID_VALUE is generated if the value specified is * less than zero. */ glUniform1i(loc, -1); ret &= piglit_check_gl_error(GL_INVALID_VALUE); v[0] = 3; v[1] = -4; glUniform1iv(loc, 2, v); ret &= piglit_check_gl_error(GL_INVALID_VALUE); /* * GL_INVALID_OPERATION is generated by Uniform* functions * other than Uniform1i{v}. */ CHECK_INVAL_2(glUniform, 1f, 1ui, (loc, 0), ret); CHECK_INVAL_3(glUniform, 2i, 2f, 2ui, (loc, 0, 0), ret); CHECK_INVAL_3(glUniform, 3i, 3f, 3ui, (loc, 0, 0, 0), ret); CHECK_INVAL_3(glUniform, 4i, 4f, 4ui, (loc, 0, 0, 0, 0), ret); CHECK_INVAL_2(glUniform, 1fv, 1uiv, (loc, 1, (void *)v), ret); CHECK_INVAL_3(glUniform, 2iv, 2fv, 2uiv, (loc, 1, (void *)v), ret); CHECK_INVAL_3(glUniform, 3iv, 3fv, 3uiv, (loc, 1, (void *)v), ret); CHECK_INVAL_3(glUniform, 4iv, 4fv, 4uiv, (loc, 1, (void *)v), ret); CHECK_INVAL_3(glUniformMatrix, 2fv, 3fv, 4fv, (loc, 1, GL_FALSE, (float *)v), ret); CHECK_INVAL_3(glUniformMatrix, 2x3fv, 3x2fv, 2x4fv, (loc, 1, GL_FALSE, (float *)v), ret); CHECK_INVAL_3(glUniformMatrix, 4x2fv, 3x4fv, 4x3fv, (loc, 1, GL_FALSE, (float *)v), ret); if (piglit_is_extension_supported("GL_ARB_gpu_shader_fp64")) { CHECK_INVAL_1(glUniform, 1d, (loc, 0), ret); CHECK_INVAL_1(glUniform, 2d, (loc, 0, 0), ret); CHECK_INVAL_1(glUniform, 3d, (loc, 0, 0, 0), ret); CHECK_INVAL_1(glUniform, 4d, (loc, 0, 0, 0, 0), ret); CHECK_INVAL_2(glUniform, 1dv, 2dv, (loc, 1, (double *)v), ret); CHECK_INVAL_2(glUniform, 3dv, 4dv, (loc, 1, (double *)v), ret); CHECK_INVAL_3(glUniformMatrix, 2dv, 3dv, 4dv, (loc, 1, GL_FALSE, (double *)v), ret); CHECK_INVAL_3(glUniformMatrix, 2x3dv, 3x2dv, 2x4dv, (loc, 1, GL_FALSE, (double *)v), ret); CHECK_INVAL_3(glUniformMatrix, 4x2dv, 3x4dv, 4x3dv, (loc, 1, GL_FALSE, (double *)v), ret); } glDeleteProgram(prog); return ret; }
bool draw_grid(const struct grid_info grid, GLuint prog) { static GLuint lprog; if (lprog != prog) { glUseProgram(prog); lprog = prog; } if (grid.stages & GL_COMPUTE_SHADER_BIT) { set_uniform_int(prog, "ret_img", max_image_units()); glDispatchCompute(1, grid.size.y, 1); } else if (grid.stages & (GL_TESS_CONTROL_SHADER_BIT | GL_TESS_EVALUATION_SHADER_BIT)) { static struct image_extent size; static GLuint vao, vbo; if (size.x != grid.size.x || size.y != grid.size.y) { size = grid.size; if (!generate_grid_arrays( &vao, &vbo, 1.0 / size.x - 1.0, 1.0 / size.y - 1.0, 2.0 / size.x, 2.0 / size.y, size.x, size.y)) return false; } glBindVertexArray(vao); glPatchParameteri(GL_PATCH_VERTICES, 4); glDrawArrays(GL_PATCHES, 0, product(size)); } else if (grid.stages & (GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT)) { static struct image_extent size; static GLuint vao, vbo; if (size.x != grid.size.x || size.y != grid.size.y) { size = grid.size; if (!generate_grid_arrays( &vao, &vbo, 1.0 / size.x - 1.0, 1.0 / size.y - 1.0, 2.0 / size.x, 2.0 / size.y, size.x, size.y)) return false; } glBindVertexArray(vao); glDrawArrays(GL_POINTS, 0, product(size)); } else { static struct image_extent size; static GLuint vao, vbo; if (size.x != grid.size.x || size.y != grid.size.y) { float vp[4]; glGetFloati_v(GL_VIEWPORT, 0, vp); size = grid.size; if (!generate_grid_arrays( &vao, &vbo, -1.0, -1.0, 2.0 * size.x / vp[2], 2.0 * size.y / vp[3], 2, 2)) return false; } glBindVertexArray(vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } return piglit_check_gl_error(GL_NO_ERROR); }