summaryrefslogtreecommitdiff
path: root/tests/spec/arb_separate_shader_objects/api-errors.c
blob: 1d6069e11df74fae17342fe87bdd8490451dc506 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 */

/**
 * \file api-errors.c
 * Verify miscelaneous API error conditions from the specification.
 */
#include "piglit-util-gl.h"
#include "sso-common.h"

PIGLIT_GL_TEST_CONFIG_BEGIN

	config.supports_gl_compat_version = 10;
	config.supports_gl_core_version = 31;

	config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGB;

PIGLIT_GL_TEST_CONFIG_END

static bool
relink_program_created_by_glCreateShaderProgram(void)
{
	static const char *code = "void main() { gl_Position = vec4(0); }";
	GLuint prog = 0;
	GLuint vs = 0;
	bool pass = true;

	prog = glCreateShaderProgramv(GL_VERTEX_SHADER, 1,
				      (const GLchar * const*) &code);
	if (!piglit_link_check_status(prog)) {
		pass = false;
		goto done;
	}

	if (!piglit_check_gl_error(0)) {
		pass = false;
		goto done;
	}

	/* Issue #14 of the GL_ARB_separate_shader_objects spec says:
	 *
	 *     "14. Should glLinkProgram work to re-link a shader created with
	 *          glCreateShaderProgram?
	 *
	 *          RESOLVED: NO because the shader created by
	 *          glCreateShaderProgram is detached and deleted as part of
	 *          the glCreateShaderProgram sequence.  This means if you
	 *          call glLinkProgram on a program returned from
	 *          glCreateShaderProgram, you'll find the re-link fails
	 *          because no shader object is attached.
	 *
	 *          An application is free to attach one or more new shader
	 *          objects to the program and then relink would work.
	 *
	 *          This is fine because re-linking isn't necessary/expected."
	 */
	glLinkProgram(prog);

	if (piglit_is_core_profile) {
		if (piglit_link_check_status(prog)) {
			printf("Relinking program without any shaders "
			       "attached succeeded, but it should have "
			       "failed.\n");
			pass = false;
		}
	} else if (!piglit_link_check_status(prog)) {
		printf("Relinking program without any shaders attached "
		       "failed, but it should have succeeded.\n");
		pass = false;
	}

	pass = piglit_check_gl_error(0) && pass;

	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, code);
	if (vs == 0) {
		pass = false;
		goto done;
	}

	glAttachShader(prog, vs);

	glLinkProgram(prog);

	if (!piglit_link_check_status(prog)) {
		printf("Relinking program after reattaching a vertex shader "
		       "failed, but it should have succeeded.\n");
		pass = false;
	}

	pass = piglit_check_gl_error(0) && pass;

 done:
	glDeleteProgram(prog);
	glDeleteShader(vs);

	piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL,
				     "relink a program created by "
				     "glCreateShaderProgramv");
	return pass;
}

static bool
glUseProgramStages_for_a_missing_stage(void)
{
	static const char *vs_code = "void main() { gl_Position = vec4(0); }";
	static const char *fs_code = "void main() { }";

	GLuint vs_prog = 0;
	GLuint fs_prog = 0;
	GLuint prog;
	GLuint pipe = 0;
	bool pass = true;

	vs_prog = glCreateShaderProgramv(GL_VERTEX_SHADER, 1,
					 (const GLchar * const*) &vs_code);
	fs_prog = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1,
					 (const GLchar * const*) &fs_code);

	glGenProgramPipelines(1, &pipe);
	glBindProgramPipeline(pipe);
	glUseProgramStages(pipe, GL_VERTEX_SHADER_BIT, vs_prog);
	glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, fs_prog);

	/* Sanity check.
	 */
	glGetProgramPipelineiv(pipe, GL_FRAGMENT_SHADER, (GLint *) &prog);
	if (prog != fs_prog) {
		printf("Sanity check failed - fragment shader program "
		       "mismatch.\n");
		pass = false;
	}

	glGetProgramPipelineiv(pipe, GL_VERTEX_SHADER, (GLint *) &prog);
	if (prog != vs_prog) {
		printf("Sanity check failed - vertex shader program "
		       "mismatch.\n");
		pass = false;
	}

	pass = piglit_check_gl_error(0) && pass;

	/* Issue #7 of the GL_ARB_separate_shader_objects spec says:
	 *
	 *     "7.  What happens if you have a program object current for a
	 *          shader stage, but the program object doesn't contain an
	 *          executable for that stage?
	 *
	 *          RESOLVED: This is not an error; instead it is as though
	 *          there were no program bound to that stage.  We have two
	 *          different notions for programs bound to shader stages.  A
	 *          program is "current" for a stage if it bound to that stage
	 *          in the active program pipeline object.  A program is
	 *          "active" for a stage if it is current and it has an
	 *          executable for this stage.  In this case, the program
	 *          would be current but not active.
	 *
	 *          When no program is active for a stage, the stage will be
	 *          replaced with fixed functionality logic (compatibility
	 *          profile vertex and fragment), disabled (tessellation
	 *          control and evaluation, geometry), or have undefined
	 *          results (core profile vertex and fragment).
	 *
	 *          Support for programs that are current but not active is
	 *          intentional behavior.  Consider an example where an
	 *          application wants to use two different types of separate
	 *          program object -- one for all types of vertex processing
	 *          and a second for fragment processing.  Some of the vertex
	 *          pipe programs might include tessellation or geometry
	 *          shaders; others might only include a vertex shader.  With
	 *          this configuration, the application can use code like the
	 *          following:
	 *
	 *            #define GL_ALL_VERTEX_PIPE_SHADER_BITS	\
	 *                (GL_VERTEX_SHADER_BIT             |	\
	 *                 GL_TESS_CONTROL_SHADER_BIT       |	\
	 *                 GL_TESS_EVALUATION_SHADER_BIT    |	\
	 *                 GL_GEOMETRY_SHADER_BIT)
	 *
	 *            glUseProgramStages(pipeline,
	 *                               GL_ALL_VERTEX_PIPE_SHADER_BITS,
	 *                               vertex_pipe_program);
	 *            glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT,
	 *                               fragment_pipe_program);
	 *
	 *        Such code wouldn't have to determine if
	 *        <vertex_pipe_program> has tessellation or geometry shaders.
	 *        Instead, it simply sets all possible bits, which removes the
	 *        old program from all non-fragment stages.  For stages not
	 *        present in the new program, the program will be current but
	 *        not active, and it will be as though no program were bound
	 *        to such stages."
	 *
	 * Further, the body of the spec says:
	 *
	 *     "If UseProgramStages is called with <program> set to zero or
	 *     with a program object that contains no executable code for a
	 *     given stages, it is as if the pipeline object has no
	 *     programmable stage configured for the indicated shader stages."
	 *
	 * This indicated to me that the "program == 0" and "program doesn't
	 * have the specified stage" cases should both cause
	 * glGetProgramPipelineiv to return zero for the GL_*_SHADER query.
	 */
	glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, vs_prog);

	glGetProgramPipelineiv(pipe, GL_FRAGMENT_SHADER, (GLint *) &prog);
	if (prog != 0) {
		printf("Using a program that lacks a particular stage for that "
		       "stage did not cause the stage to use program 0.\n");
		pass = false;
	}

	pass = piglit_check_gl_error(0) && pass;

	piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL,
				     "glUseProgramStages of a program that "
				     "lacks a specified stage");

	return pass;
}

static bool
glActiveShaderProgram_while_transform_feedback_is_active(void)
{
	static const char *vs_code = "void main() { gl_Position = vec4(0); }";
	static const char *fs_code = "void main() { }";

	GLuint vs_prog = 0;
	GLuint fs_prog = 0;
	GLuint pipe = 0;
	GLuint xfb = 0;
	GLuint buf = 0;
	bool pass = true;
	static const char *varyings[] = {"gl_Position"};

	if (!CreateShaderProgram_with_xfb(vs_code, varyings, 1, &vs_prog)) {
		pass = false;
		goto done;
	}

	fs_prog = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1,
					 (const GLchar * const*) &fs_code);

	glGenProgramPipelines(1, &pipe);
	glBindProgramPipeline(pipe);
	glUseProgramStages(pipe, GL_VERTEX_SHADER_BIT, vs_prog);
	glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, fs_prog);

	configure_transform_feedback_object(&xfb, &buf);

	pass = piglit_check_gl_error(0) && pass;

	glBeginTransformFeedback(GL_TRIANGLES);

	pass = piglit_check_gl_error(0) && pass;

	/* Issue #6b of the GL_ARB_separate_shader_objects spec says:
	 *
	 *     "6b. Should the active program be allowed to changed within
	 *          transform feedback mode?
	 *
	 *          RESOLVED:  Yes.
	 *
	 *          The active program simply allows uniforms to be changed
	 *          but doesn't actually change how the graphics pipeline
	 *          itself is configured or what programs are used for vertex,
	 *          geometry, and fragment processing."
	 */
	glActiveShaderProgram(pipe, vs_prog);
	glActiveShaderProgram(pipe, fs_prog);

	pass = piglit_check_gl_error(0) && pass;

	glEndTransformFeedback();

	pass = piglit_check_gl_error(0) && pass;

 done:
	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);

	glDeleteTransformFeedbacks(1, &xfb);
	glDeleteBuffers(1, &buf);
	glDeleteProgram(vs_prog);
	glDeleteProgram(fs_prog);

	pass = piglit_check_gl_error(0) && pass;

	piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL,
				     "glActiveShaderProgram while transform "
				     "feedback is active");

	return pass;
}

static bool
glBindProgramPipeline_while_transform_feedback_is_active(void)
{
	/* This is already covered by the "bind_pipeline" mode of the
	 * ext_transform_feedback-api-errors test.
	 */
	return true;
}

void
piglit_init(int argc, char **argv)
{
	bool pass = true;

	piglit_require_vertex_shader();
	piglit_require_fragment_shader();
	piglit_require_extension("GL_ARB_separate_shader_objects");

	pass = relink_program_created_by_glCreateShaderProgram() && pass;
	pass = glUseProgramStages_for_a_missing_stage() && pass;

	if (piglit_is_extension_supported("GL_ARB_transform_feedback2")) {
		pass = glActiveShaderProgram_while_transform_feedback_is_active()
			&& pass;
		pass = glBindProgramPipeline_while_transform_feedback_is_active()
			&& pass;
	}

	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
}

enum piglit_result
piglit_display(void)
{
	return PIGLIT_FAIL;
}