mesa/sso: replace Shader binding point with _Shader
[mesa.git] / src / mesa / main / pipelineobj.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright © 2013 Gregory Hainaut <gregory.hainaut@gmail.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 * IN THE SOFTWARE.
24 */
25
26 /**
27 * \file pipelineobj.c
28 * \author Hainaut Gregory <gregory.hainaut@gmail.com>
29 *
30 * Implementation of pipeline object related API functions. Based on
31 * GL_ARB_separate_shader_objects extension.
32 */
33
34 #include "main/glheader.h"
35 #include "main/context.h"
36 #include "main/dispatch.h"
37 #include "main/enums.h"
38 #include "main/hash.h"
39 #include "main/mtypes.h"
40 #include "main/pipelineobj.h"
41 #include "main/shaderapi.h"
42 #include "main/shaderobj.h"
43 #include "main/transformfeedback.h"
44 #include "main/uniforms.h"
45 #include "program/program.h"
46 #include "program/prog_parameter.h"
47 #include "ralloc.h"
48 #include <stdbool.h>
49 #include "../glsl/glsl_parser_extras.h"
50 #include "../glsl/ir_uniform.h"
51
52 /**
53 * Delete a pipeline object.
54 */
55 void
56 _mesa_delete_pipeline_object(struct gl_context *ctx,
57 struct gl_pipeline_object *obj)
58 {
59 unsigned i;
60
61 _mesa_reference_shader_program(ctx, &obj->_CurrentFragmentProgram, NULL);
62
63 for (i = 0; i < MESA_SHADER_STAGES; i++)
64 _mesa_reference_shader_program(ctx, &obj->CurrentProgram[i], NULL);
65
66 _mesa_reference_shader_program(ctx, &obj->ActiveProgram, NULL);
67 mtx_destroy(&obj->Mutex);
68 ralloc_free(obj);
69 }
70
71 /**
72 * Allocate and initialize a new pipeline object.
73 */
74 static struct gl_pipeline_object *
75 _mesa_new_pipeline_object(struct gl_context *ctx, GLuint name)
76 {
77 struct gl_pipeline_object *obj = rzalloc(NULL, struct gl_pipeline_object);
78 if (obj) {
79 obj->Name = name;
80 mtx_init(&obj->Mutex, mtx_plain);
81 obj->RefCount = 1;
82 obj->Flags = _mesa_get_shader_flags();
83 }
84
85 return obj;
86 }
87
88 /**
89 * Initialize pipeline object state for given context.
90 */
91 void
92 _mesa_init_pipeline(struct gl_context *ctx)
93 {
94 ctx->Pipeline.Objects = _mesa_NewHashTable();
95
96 ctx->Pipeline.Current = NULL;
97
98 /* Install a default Pipeline */
99 ctx->Pipeline.Default = _mesa_new_pipeline_object(ctx, 0);
100 _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default);
101 }
102
103
104 /**
105 * Callback for deleting a pipeline object. Called by _mesa_HashDeleteAll().
106 */
107 static void
108 delete_pipelineobj_cb(GLuint id, void *data, void *userData)
109 {
110 struct gl_pipeline_object *obj = (struct gl_pipeline_object *) data;
111 struct gl_context *ctx = (struct gl_context *) userData;
112 _mesa_delete_pipeline_object(ctx, obj);
113 }
114
115
116 /**
117 * Free pipeline state for given context.
118 */
119 void
120 _mesa_free_pipeline_data(struct gl_context *ctx)
121 {
122 _mesa_HashDeleteAll(ctx->Pipeline.Objects, delete_pipelineobj_cb, ctx);
123 _mesa_DeleteHashTable(ctx->Pipeline.Objects);
124
125 _mesa_reference_pipeline_object(ctx, &ctx->_Shader, NULL);
126 _mesa_delete_pipeline_object(ctx, ctx->Pipeline.Default);
127
128 }
129
130 /**
131 * Look up the pipeline object for the given ID.
132 *
133 * \returns
134 * Either a pointer to the pipeline object with the specified ID or \c NULL for
135 * a non-existent ID. The spec defines ID 0 as being technically
136 * non-existent.
137 */
138 static inline struct gl_pipeline_object *
139 lookup_pipeline_object(struct gl_context *ctx, GLuint id)
140 {
141 if (id == 0)
142 return NULL;
143 else
144 return (struct gl_pipeline_object *)
145 _mesa_HashLookup(ctx->Pipeline.Objects, id);
146 }
147
148 /**
149 * Add the given pipeline object to the pipeline object pool.
150 */
151 static void
152 save_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
153 {
154 if (obj->Name > 0) {
155 _mesa_HashInsert(ctx->Pipeline.Objects, obj->Name, obj);
156 }
157 }
158
159 /**
160 * Remove the given pipeline object from the pipeline object pool.
161 * Do not deallocate the pipeline object though.
162 */
163 static void
164 remove_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj)
165 {
166 if (obj->Name > 0) {
167 _mesa_HashRemove(ctx->Pipeline.Objects, obj->Name);
168 }
169 }
170
171 /**
172 * Set ptr to obj w/ reference counting.
173 * Note: this should only be called from the _mesa_reference_pipeline_object()
174 * inline function.
175 */
176 void
177 _mesa_reference_pipeline_object_(struct gl_context *ctx,
178 struct gl_pipeline_object **ptr,
179 struct gl_pipeline_object *obj)
180 {
181 assert(*ptr != obj);
182
183 if (*ptr) {
184 /* Unreference the old pipeline object */
185 GLboolean deleteFlag = GL_FALSE;
186 struct gl_pipeline_object *oldObj = *ptr;
187
188 mtx_lock(&oldObj->Mutex);
189 ASSERT(oldObj->RefCount > 0);
190 oldObj->RefCount--;
191 deleteFlag = (oldObj->RefCount == 0);
192 mtx_unlock(&oldObj->Mutex);
193
194 if (deleteFlag) {
195 _mesa_delete_pipeline_object(ctx, oldObj);
196 }
197
198 *ptr = NULL;
199 }
200 ASSERT(!*ptr);
201
202 if (obj) {
203 /* reference new pipeline object */
204 mtx_lock(&obj->Mutex);
205 if (obj->RefCount == 0) {
206 /* this pipeline's being deleted (look just above) */
207 /* Not sure this can ever really happen. Warn if it does. */
208 _mesa_problem(NULL, "referencing deleted pipeline object");
209 *ptr = NULL;
210 }
211 else {
212 obj->RefCount++;
213 *ptr = obj;
214 }
215 mtx_unlock(&obj->Mutex);
216 }
217 }
218
219 /**
220 * Bound program to severals stages of the pipeline
221 */
222 void GLAPIENTRY
223 _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
224 {
225 }
226
227 /**
228 * Use the named shader program for subsequent glUniform calls (if pipeline
229 * bound)
230 */
231 void GLAPIENTRY
232 _mesa_ActiveShaderProgram(GLuint pipeline, GLuint program)
233 {
234 GET_CURRENT_CONTEXT(ctx);
235 struct gl_shader_program *shProg = NULL;
236 struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline);
237
238 if (program != 0) {
239 shProg = _mesa_lookup_shader_program_err(ctx, program,
240 "glActiveShaderProgram(program)");
241 if (shProg == NULL)
242 return;
243 }
244
245 if (!pipe) {
246 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveShaderProgram(pipeline)");
247 return;
248 }
249
250 /* Object is created by any Pipeline call but glGenProgramPipelines,
251 * glIsProgramPipeline and GetProgramPipelineInfoLog
252 */
253 pipe->EverBound = GL_TRUE;
254
255 if ((shProg != NULL) && !shProg->LinkStatus) {
256 _mesa_error(ctx, GL_INVALID_OPERATION,
257 "glActiveShaderProgram(program %u not linked)", shProg->Name);
258 return;
259 }
260
261 _mesa_reference_shader_program(ctx, &pipe->ActiveProgram, shProg);
262 }
263
264 /**
265 * Make program of the pipeline current
266 */
267 void GLAPIENTRY
268 _mesa_BindProgramPipeline(GLuint pipeline)
269 {
270 }
271
272 /**
273 * Delete a set of pipeline objects.
274 *
275 * \param n Number of pipeline objects to delete.
276 * \param ids pipeline of \c n pipeline object IDs.
277 */
278 void GLAPIENTRY
279 _mesa_DeleteProgramPipelines(GLsizei n, const GLuint *pipelines)
280 {
281 GET_CURRENT_CONTEXT(ctx);
282 GLsizei i;
283
284 if (n < 0) {
285 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgramPipelines(n<0)");
286 return;
287 }
288
289 for (i = 0; i < n; i++) {
290 struct gl_pipeline_object *obj =
291 lookup_pipeline_object(ctx, pipelines[i]);
292
293 if (obj) {
294 ASSERT(obj->Name == pipelines[i]);
295
296 /* If the pipeline object is currently bound, the spec says "If an
297 * object that is currently bound is deleted, the binding for that
298 * object reverts to zero and no program pipeline object becomes
299 * current."
300 */
301 if (obj == ctx->Pipeline.Current) {
302 _mesa_BindProgramPipeline(0);
303 }
304
305 /* The ID is immediately freed for re-use */
306 remove_pipeline_object(ctx, obj);
307
308 /* Unreference the pipeline object.
309 * If refcount hits zero, the object will be deleted.
310 */
311 _mesa_reference_pipeline_object(ctx, &obj, NULL);
312 }
313 }
314 }
315
316 /**
317 * Generate a set of unique pipeline object IDs and store them in \c pipelines.
318 * \param n Number of IDs to generate.
319 * \param pipelines pipeline of \c n locations to store the IDs.
320 */
321 void GLAPIENTRY
322 _mesa_GenProgramPipelines(GLsizei n, GLuint *pipelines)
323 {
324 GET_CURRENT_CONTEXT(ctx);
325
326 GLuint first;
327 GLint i;
328
329 if (n < 0) {
330 _mesa_error(ctx, GL_INVALID_VALUE, "glGenProgramPipelines(n<0)");
331 return;
332 }
333
334 if (!pipelines) {
335 return;
336 }
337
338 first = _mesa_HashFindFreeKeyBlock(ctx->Pipeline.Objects, n);
339
340 for (i = 0; i < n; i++) {
341 struct gl_pipeline_object *obj;
342 GLuint name = first + i;
343
344 obj = _mesa_new_pipeline_object(ctx, name);
345 if (!obj) {
346 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenProgramPipelines");
347 return;
348 }
349
350 save_pipeline_object(ctx, obj);
351 pipelines[i] = first + i;
352 }
353
354 }
355
356 /**
357 * Determine if ID is the name of an pipeline object.
358 *
359 * \param id ID of the potential pipeline object.
360 * \return \c GL_TRUE if \c id is the name of a pipeline object,
361 * \c GL_FALSE otherwise.
362 */
363 GLboolean GLAPIENTRY
364 _mesa_IsProgramPipeline(GLuint pipeline)
365 {
366 GET_CURRENT_CONTEXT(ctx);
367
368 struct gl_pipeline_object *obj = lookup_pipeline_object(ctx, pipeline);
369 if (obj == NULL)
370 return GL_FALSE;
371
372 return obj->EverBound;
373 }
374
375 /**
376 * glGetProgramPipelineiv() - get pipeline shader state.
377 */
378 void GLAPIENTRY
379 _mesa_GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params)
380 {
381 GET_CURRENT_CONTEXT(ctx);
382 struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline);
383
384 /* Are geometry shaders available in this context?
385 */
386 const bool has_gs = _mesa_has_geometry_shaders(ctx);
387
388 if (!pipe) {
389 _mesa_error(ctx, GL_INVALID_OPERATION,
390 "glGetProgramPipelineiv(pipeline)");
391 return;
392 }
393
394 /* Object is created by any Pipeline call but glGenProgramPipelines,
395 * glIsProgramPipeline and GetProgramPipelineInfoLog
396 */
397 pipe->EverBound = GL_TRUE;
398
399 switch (pname) {
400 case GL_ACTIVE_PROGRAM:
401 *params = pipe->ActiveProgram ? pipe->ActiveProgram->Name : 0;
402 return;
403 case GL_INFO_LOG_LENGTH:
404 /* FINISHME: Implement the info log.
405 */
406 *params = 0;
407 return;
408 case GL_VALIDATE_STATUS:
409 /* FINISHME: Implement validation status.
410 */
411 *params = 0;
412 return;
413 case GL_VERTEX_SHADER:
414 *params = pipe->CurrentProgram[MESA_SHADER_VERTEX]
415 ? pipe->CurrentProgram[MESA_SHADER_VERTEX]->Name : 0;
416 return;
417 case GL_TESS_EVALUATION_SHADER:
418 /* NOT YET SUPPORTED */
419 break;
420 case GL_TESS_CONTROL_SHADER:
421 /* NOT YET SUPPORTED */
422 break;
423 case GL_GEOMETRY_SHADER:
424 if (!has_gs)
425 break;
426 *params = pipe->CurrentProgram[MESA_SHADER_GEOMETRY]
427 ? pipe->CurrentProgram[MESA_SHADER_GEOMETRY]->Name : 0;
428 return;
429 case GL_FRAGMENT_SHADER:
430 *params = pipe->CurrentProgram[MESA_SHADER_FRAGMENT]
431 ? pipe->CurrentProgram[MESA_SHADER_FRAGMENT]->Name : 0;
432 return;
433 default:
434 break;
435 }
436
437 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramPipelineiv(pname=%s)",
438 _mesa_lookup_enum_by_nr(pname));
439 }
440
441 /**
442 * Check compatibility of pipeline's program
443 */
444 void GLAPIENTRY
445 _mesa_ValidateProgramPipeline(GLuint pipeline)
446 {
447 }
448
449 void GLAPIENTRY
450 _mesa_GetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize,
451 GLsizei *length, GLchar *infoLog)
452 {
453 }