2 * Copyright (C) 2014 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
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
26 * Utility code for running a grid of shader invocations abstracting
27 * out the details of the specific shader stage it's run on.
33 concat(char *hunk0
, ...)
41 while ((hunk
= va_arg(ap
, char *))) {
43 (void)!asprintf(&s
, "%s\n%s", t
, hunk
);
53 image_hunk(const struct image_info img
, const char *prefix
)
58 "#define %sBASE_T %s\n"
59 "#define %sDATA_T %s\n"
60 "#define %sSCALE vec4(%.8e, %.8e, %.8e, %.8e)\n"
61 "#define %sIMAGE_ADDR_(addr_t, ext, i) %s\n"
62 "#define %sIMAGE_ADDR(idx)"
63 " %sIMAGE_ADDR_(%s, ivec4(%d, %d, %d, %d),"
64 " ((idx).x + W * (idx).y))\n"
65 "#define %sIMAGE_LAYOUT_Q layout(%s)\n"
66 "#define %sIMAGE_BARE_T %s%s\n"
67 "#define %sIMAGE_UNIFORM_T %sIMAGE_LAYOUT_Q uniform %sIMAGE_BARE_T\n",
68 prefix
, image_scalar_type_name(img
.format
),
69 prefix
, image_vector_type_name(img
.format
),
70 prefix
, image_format_scale(img
.format
).x
,
71 image_format_scale(img
.format
).y
,
72 image_format_scale(img
.format
).z
,
73 image_format_scale(img
.format
).w
,
74 prefix
, (image_target_samples(img
.target
) > 1 ?
75 "addr_t(ivec3(i / ext.x % ext.y,"
76 " i / ext.x / ext.y % ext.z,"
77 " i / ext.x / ext.y / ext.z)),"
79 "addr_t(ivec3(i % ext.x,"
81 " i / ext.x / ext.y))"),
82 prefix
, prefix
, img
.target
->addr_type_name
,
83 img
.size
.x
, img
.size
.y
, img
.size
.z
, img
.size
.w
,
84 prefix
, img
.format
->name
,
85 prefix
, image_type_name(img
.format
), img
.target
->name
,
86 prefix
, prefix
, prefix
);
91 header_hunk(const struct grid_info grid
)
95 (void)!asprintf(&s
, "#version 150\n"
96 "#extension GL_ARB_shader_image_load_store : enable\n"
100 "#define GRID_T %s\n"
101 "#define RET_IMAGE_UNIFORM_T layout(%s) uniform %s2D\n",
102 grid
.size
.x
, grid
.size
.y
, product(grid
.size
),
103 image_vector_type_name(grid
.format
),
104 grid
.format
->name
, image_type_name(grid
.format
));
109 generate_stage_source(const struct grid_info grid
,
110 unsigned stage
, const char *_body
)
112 char *header
= header_hunk(grid
);
113 char *body
= hunk(_body
? _body
:
114 "GRID_T op(ivec2 idx, GRID_T x) {\n"
119 case GL_VERTEX_SHADER
:
122 hunk("in vec4 piglit_vertex;\n"
124 "flat out GRID_T vcolor;\n"
127 " ivec2 idx = ivec2((piglit_vertex + 1.0).xy *"
128 " vec2(W, H) / 2);\n"
130 " vcolor = op(idx, GRID_T(0));\n"
132 " gl_Position = piglit_vertex;\n"
135 case GL_TESS_CONTROL_SHADER
:
138 hunk("#extension GL_ARB_tessellation_shader : enable\n"),
140 hunk("layout(vertices=4) out;\n"
143 "flat in GRID_T vcolor[];\n"
144 "out ivec2 tcidx[];\n"
145 "out GRID_T tccolor[];\n"
148 " if (gl_InvocationID == 0) {\n"
149 " /* No subdivisions, thanks. */\n"
150 " gl_TessLevelInner[0] = 1;\n"
151 " gl_TessLevelInner[1] = 1;\n"
152 " gl_TessLevelOuter[0] = 1;\n"
153 " gl_TessLevelOuter[1] = 1;\n"
154 " gl_TessLevelOuter[2] = 1;\n"
155 " gl_TessLevelOuter[3] = 1;\n"
157 " tccolor[gl_InvocationID] ="
158 " op(vidx[gl_InvocationID],"
159 " vcolor[gl_InvocationID]);\n"
160 " tcidx[gl_InvocationID] = vidx[gl_InvocationID];\n"
161 " gl_out[gl_InvocationID].gl_Position ="
162 " gl_in[gl_InvocationID].gl_Position;\n"
165 case GL_TESS_EVALUATION_SHADER
:
168 hunk("#extension GL_ARB_tessellation_shader : enable\n"),
170 hunk("layout(quads, point_mode) in;\n"
172 "in ivec2 tcidx[];\n"
173 "in GRID_T tccolor[];\n"
175 "flat out GRID_T tecolor;\n"
178 " int idx = ((gl_TessCoord.x > 0.5 ? 1 : 0) +"
179 " (gl_TessCoord.y > 0.5 ? 2 : 0));\n"
181 " tecolor = op(tcidx[idx], tccolor[idx]);\n"
182 " teidx = tcidx[idx];\n"
183 " gl_Position = gl_in[idx].gl_Position;\n"
186 case GL_GEOMETRY_SHADER
:
189 hunk(grid
.stages
& (GL_TESS_CONTROL_SHADER_BIT
|
190 GL_TESS_EVALUATION_SHADER_BIT
) ?
191 "#define IN(name) te##name\n" :
192 "#define IN(name) v##name\n"),
194 hunk("layout(points) in;\n"
195 "layout(points, max_vertices=1) out;\n"
197 "in ivec2 IN(idx)[];\n"
198 "flat in GRID_T IN(color)[];\n"
199 "flat out GRID_T gcolor;\n"
202 " gcolor = op(IN(idx)[0], IN(color)[0]);\n"
203 " gl_Position = gl_in[0].gl_Position;\n"
207 case GL_FRAGMENT_SHADER
:
210 hunk(grid
.stages
& (GL_TESS_CONTROL_SHADER_BIT
|
211 GL_TESS_EVALUATION_SHADER_BIT
|
212 GL_GEOMETRY_SHADER_BIT
) ?
213 "#define IN(name) g##name\n" :
214 "#define IN(name) v##name\n"),
216 hunk("flat in GRID_T IN(color);\n"
217 "out GRID_T fcolor;\n"
220 " fcolor = op(ivec2(gl_FragCoord), IN(color));\n"
223 case GL_COMPUTE_SHADER
:
226 hunk("#extension GL_ARB_compute_shader : enable\n"),
228 hunk("layout (local_size_x = W) in;\n"
230 "RET_IMAGE_UNIFORM_T ret_img;\n"
233 " ivec2 idx = ivec2(gl_GlobalInvocationID);\n"
234 " GRID_T x = op(idx, GRID_T(0));\n"
235 " imageStore(ret_img, idx, x);\n"
243 static inline unsigned
244 get_stage_idx(const struct image_stage_info
*stage
)
246 return ffs(stage
->bit
) - 1;
250 * Generate a full program pipeline using the shader code provided in
251 * the \a sources array.
254 generate_program_v(const struct grid_info grid
, const char **sources
)
256 const unsigned basic_stages
= (GL_FRAGMENT_SHADER_BIT
|
257 GL_VERTEX_SHADER_BIT
);
258 const unsigned tess_stages
= (GL_TESS_CONTROL_SHADER_BIT
|
259 GL_TESS_EVALUATION_SHADER_BIT
);
260 const unsigned graphic_stages
= (basic_stages
| tess_stages
|
261 GL_GEOMETRY_SHADER_BIT
);
262 const unsigned stages
=
264 /* Make a full pipeline if a tesselation shader was
266 (grid
.stages
& tess_stages
? graphic_stages
: 0) |
267 /* Make sure there is always a vertex and fragment
268 * shader if we're doing graphics. */
269 (grid
.stages
& graphic_stages
? basic_stages
: 0));
270 GLuint prog
= glCreateProgram();
271 const struct image_stage_info
*stage
;
273 for (stage
= known_image_stages(); stage
->stage
; ++stage
) {
274 if (stages
& stage
->bit
) {
275 char *source
= generate_stage_source(
277 sources
[get_stage_idx(stage
)]);
278 GLuint shader
= piglit_compile_shader_text_nothrow(
279 stage
->stage
, source
);
284 glDeleteProgram(prog
);
288 glAttachShader(prog
, shader
);
289 glDeleteShader(shader
);
293 glBindAttribLocation(prog
, PIGLIT_ATTRIB_POS
, "piglit_vertex");
294 glBindAttribLocation(prog
, PIGLIT_ATTRIB_TEX
, "piglit_texcoord");
297 if (!piglit_link_check_status(prog
)) {
298 glDeleteProgram(prog
);
306 generate_program(const struct grid_info grid
, ...)
308 char *sources
[6] = { NULL
};
315 for (stages
= grid
.stages
; stages
;) {
316 const struct image_stage_info
*stage
=
317 get_image_stage(va_arg(ap
, GLenum
));
318 char *source
= va_arg(ap
, char *);
321 assert(get_stage_idx(stage
) < ARRAY_SIZE(sources
));
322 sources
[get_stage_idx(stage
)] = source
;
323 stages
&= ~stage
->bit
;
329 prog
= generate_program_v(grid
, (const char **)sources
);
331 for (i
= 0; i
< ARRAY_SIZE(sources
); ++i
)
338 draw_grid(const struct grid_info grid
, GLuint prog
)
347 if (grid
.stages
& GL_COMPUTE_SHADER_BIT
) {
348 set_uniform_int(prog
, "ret_img", max_image_units());
349 glDispatchCompute(1, grid
.size
.y
, 1);
351 } else if (grid
.stages
& (GL_TESS_CONTROL_SHADER_BIT
|
352 GL_TESS_EVALUATION_SHADER_BIT
)) {
353 static struct image_extent size
;
354 static GLuint vao
, vbo
;
356 if (size
.x
!= grid
.size
.x
|| size
.y
!= grid
.size
.y
) {
359 if (!generate_grid_arrays(
361 1.0 / size
.x
- 1.0, 1.0 / size
.y
- 1.0,
362 2.0 / size
.x
, 2.0 / size
.y
,
367 glBindVertexArray(vao
);
368 glPatchParameteri(GL_PATCH_VERTICES
, 4);
369 glDrawArrays(GL_PATCHES
, 0, product(size
));
371 } else if (grid
.stages
& (GL_VERTEX_SHADER_BIT
|
372 GL_GEOMETRY_SHADER_BIT
)) {
373 static struct image_extent size
;
374 static GLuint vao
, vbo
;
376 if (size
.x
!= grid
.size
.x
|| size
.y
!= grid
.size
.y
) {
379 if (!generate_grid_arrays(
381 1.0 / size
.x
- 1.0, 1.0 / size
.y
- 1.0,
382 2.0 / size
.x
, 2.0 / size
.y
,
387 glBindVertexArray(vao
);
388 glDrawArrays(GL_POINTS
, 0, product(size
));
391 static struct image_extent size
;
392 static GLuint vao
, vbo
;
394 if (size
.x
!= grid
.size
.x
|| size
.y
!= grid
.size
.y
) {
397 glGetFloati_v(GL_VIEWPORT
, 0, vp
);
400 if (!generate_grid_arrays(
401 &vao
, &vbo
, -1.0, -1.0,
402 2.0 * size
.x
/ vp
[2], 2.0 * size
.y
/ vp
[3],
408 glBindVertexArray(vao
);
409 glDrawArrays(GL_TRIANGLE_STRIP
, 0, 4);
412 return piglit_check_gl_error(GL_NO_ERROR
);
416 generate_grid_arrays(GLuint
*vao
, GLuint
*vbo
,
417 float x
, float y
, float dx
, float dy
,
418 unsigned nx
, unsigned ny
)
420 float (*verts
)[4] = malloc(sizeof(*verts
) * nx
* ny
);
423 for (i
= 0; i
< nx
; ++i
) {
424 for (j
= 0; j
< ny
; ++j
) {
425 const unsigned k
= (nx
* (j
& ~1) + 2 * (i
& ~1) +
426 (i
& 1) + 2 * (j
& 1));
427 verts
[k
][0] = x
+ i
* dx
;
428 verts
[k
][1] = y
+ j
* dy
;
435 glGenVertexArrays(1, vao
);
436 glGenBuffers(1, vbo
);
439 glBindVertexArray(*vao
);
440 glBindBuffer(GL_ARRAY_BUFFER
, *vbo
);
441 glBufferData(GL_ARRAY_BUFFER
, sizeof(*verts
) * nx
* ny
,
442 verts
, GL_STATIC_DRAW
);
444 glVertexAttribPointer(PIGLIT_ATTRIB_POS
, 4, GL_FLOAT
,
446 glEnableVertexAttribArray(PIGLIT_ATTRIB_POS
);
449 return piglit_check_gl_error(GL_NO_ERROR
);