i965/gs: Add a case to brwNewProgram() for geometry shaders.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_program.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 */
31
32 #include <pthread.h>
33 #include "main/imports.h"
34 #include "main/enums.h"
35 #include "main/shaderobj.h"
36 #include "program/prog_parameter.h"
37 #include "program/program.h"
38 #include "program/programopt.h"
39 #include "tnl/tnl.h"
40 #include "glsl/ralloc.h"
41
42 #include "brw_context.h"
43 #include "brw_wm.h"
44
45 static unsigned
46 get_new_program_id(struct intel_screen *screen)
47 {
48 static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
49 pthread_mutex_lock(&m);
50 unsigned id = screen->program_id++;
51 pthread_mutex_unlock(&m);
52 return id;
53 }
54
55 static void brwBindProgram( struct gl_context *ctx,
56 GLenum target,
57 struct gl_program *prog )
58 {
59 struct brw_context *brw = brw_context(ctx);
60
61 switch (target) {
62 case GL_VERTEX_PROGRAM_ARB:
63 brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
64 break;
65 case MESA_GEOMETRY_PROGRAM:
66 brw->state.dirty.brw |= BRW_NEW_GEOMETRY_PROGRAM;
67 break;
68 case GL_FRAGMENT_PROGRAM_ARB:
69 brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
70 break;
71 }
72 }
73
74 static struct gl_program *brwNewProgram( struct gl_context *ctx,
75 GLenum target,
76 GLuint id )
77 {
78 struct brw_context *brw = brw_context(ctx);
79
80 switch (target) {
81 case GL_VERTEX_PROGRAM_ARB: {
82 struct brw_vertex_program *prog = CALLOC_STRUCT(brw_vertex_program);
83 if (prog) {
84 prog->id = get_new_program_id(brw->intelScreen);
85
86 return _mesa_init_vertex_program( ctx, &prog->program,
87 target, id );
88 }
89 else
90 return NULL;
91 }
92
93 case GL_FRAGMENT_PROGRAM_ARB: {
94 struct brw_fragment_program *prog = CALLOC_STRUCT(brw_fragment_program);
95 if (prog) {
96 prog->id = get_new_program_id(brw->intelScreen);
97
98 return _mesa_init_fragment_program( ctx, &prog->program,
99 target, id );
100 }
101 else
102 return NULL;
103 }
104
105 case MESA_GEOMETRY_PROGRAM: {
106 struct brw_geometry_program *prog = CALLOC_STRUCT(brw_geometry_program);
107 if (prog) {
108 prog->id = get_new_program_id(brw->intelScreen);
109
110 return _mesa_init_geometry_program(ctx, &prog->program, target, id);
111 } else {
112 return NULL;
113 }
114 }
115
116 default:
117 return _mesa_new_program(ctx, target, id);
118 }
119 }
120
121 static void brwDeleteProgram( struct gl_context *ctx,
122 struct gl_program *prog )
123 {
124 _mesa_delete_program( ctx, prog );
125 }
126
127
128 static GLboolean
129 brwIsProgramNative(struct gl_context *ctx,
130 GLenum target,
131 struct gl_program *prog)
132 {
133 return true;
134 }
135
136 static GLboolean
137 brwProgramStringNotify(struct gl_context *ctx,
138 GLenum target,
139 struct gl_program *prog)
140 {
141 struct brw_context *brw = brw_context(ctx);
142
143 switch (target) {
144 case GL_FRAGMENT_PROGRAM_ARB: {
145 struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
146 struct brw_fragment_program *newFP = brw_fragment_program(fprog);
147 const struct brw_fragment_program *curFP =
148 brw_fragment_program_const(brw->fragment_program);
149
150 if (newFP == curFP)
151 brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
152 newFP->id = get_new_program_id(brw->intelScreen);
153 break;
154 }
155 case GL_VERTEX_PROGRAM_ARB: {
156 struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
157 struct brw_vertex_program *newVP = brw_vertex_program(vprog);
158 const struct brw_vertex_program *curVP =
159 brw_vertex_program_const(brw->vertex_program);
160
161 if (newVP == curVP)
162 brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
163 if (newVP->program.IsPositionInvariant) {
164 _mesa_insert_mvp_code(ctx, &newVP->program);
165 }
166 newVP->id = get_new_program_id(brw->intelScreen);
167
168 /* Also tell tnl about it:
169 */
170 _tnl_program_string(ctx, target, prog);
171 break;
172 }
173 default:
174 /*
175 * driver->ProgramStringNotify is only called for ARB programs, fixed
176 * function vertex programs, and ir_to_mesa (which isn't used by the
177 * i965 back-end). Therefore, even after geometry shaders are added,
178 * this function should only ever be called with a target of
179 * GL_VERTEX_PROGRAM_ARB or GL_FRAGMENT_PROGRAM_ARB.
180 */
181 assert(!"Unexpected target in brwProgramStringNotify");
182 break;
183 }
184
185 brw_add_texrect_params(prog);
186
187 return true;
188 }
189
190 void
191 brw_add_texrect_params(struct gl_program *prog)
192 {
193 for (int texunit = 0; texunit < BRW_MAX_TEX_UNIT; texunit++) {
194 if (!(prog->TexturesUsed[texunit] & (1 << TEXTURE_RECT_INDEX)))
195 continue;
196
197 int tokens[STATE_LENGTH] = {
198 STATE_INTERNAL,
199 STATE_TEXRECT_SCALE,
200 texunit,
201 0,
202 0
203 };
204
205 _mesa_add_state_reference(prog->Parameters, (gl_state_index *)tokens);
206 }
207 }
208
209 /* Per-thread scratch space is a power-of-two multiple of 1KB. */
210 int
211 brw_get_scratch_size(int size)
212 {
213 int i;
214
215 for (i = 1024; i < size; i *= 2)
216 ;
217
218 return i;
219 }
220
221 void
222 brw_get_scratch_bo(struct brw_context *brw,
223 drm_intel_bo **scratch_bo, int size)
224 {
225 drm_intel_bo *old_bo = *scratch_bo;
226
227 if (old_bo && old_bo->size < size) {
228 drm_intel_bo_unreference(old_bo);
229 old_bo = NULL;
230 }
231
232 if (!old_bo) {
233 *scratch_bo = drm_intel_bo_alloc(brw->bufmgr, "scratch bo", size, 4096);
234 }
235 }
236
237 void brwInitFragProgFuncs( struct dd_function_table *functions )
238 {
239 assert(functions->ProgramStringNotify == _tnl_program_string);
240
241 functions->BindProgram = brwBindProgram;
242 functions->NewProgram = brwNewProgram;
243 functions->DeleteProgram = brwDeleteProgram;
244 functions->IsProgramNative = brwIsProgramNative;
245 functions->ProgramStringNotify = brwProgramStringNotify;
246
247 functions->NewShader = brw_new_shader;
248 functions->NewShaderProgram = brw_new_shader_program;
249 functions->LinkShader = brw_link_shader;
250 }
251
252 void
253 brw_init_shader_time(struct brw_context *brw)
254 {
255 const int max_entries = 4096;
256 brw->shader_time.bo = drm_intel_bo_alloc(brw->bufmgr, "shader time",
257 max_entries * SHADER_TIME_STRIDE,
258 4096);
259 brw->shader_time.shader_programs = rzalloc_array(brw, struct gl_shader_program *,
260 max_entries);
261 brw->shader_time.programs = rzalloc_array(brw, struct gl_program *,
262 max_entries);
263 brw->shader_time.types = rzalloc_array(brw, enum shader_time_shader_type,
264 max_entries);
265 brw->shader_time.cumulative = rzalloc_array(brw, uint64_t,
266 max_entries);
267 brw->shader_time.max_entries = max_entries;
268 }
269
270 static int
271 compare_time(const void *a, const void *b)
272 {
273 uint64_t * const *a_val = a;
274 uint64_t * const *b_val = b;
275
276 /* We don't just subtract because we're turning the value to an int. */
277 if (**a_val < **b_val)
278 return -1;
279 else if (**a_val == **b_val)
280 return 0;
281 else
282 return 1;
283 }
284
285 static void
286 get_written_and_reset(struct brw_context *brw, int i,
287 uint64_t *written, uint64_t *reset)
288 {
289 enum shader_time_shader_type type = brw->shader_time.types[i];
290 assert(type == ST_VS || type == ST_FS8 || type == ST_FS16);
291
292 /* Find where we recorded written and reset. */
293 int wi, ri;
294
295 for (wi = i; brw->shader_time.types[wi] != type + 1; wi++)
296 ;
297
298 for (ri = i; brw->shader_time.types[ri] != type + 2; ri++)
299 ;
300
301 *written = brw->shader_time.cumulative[wi];
302 *reset = brw->shader_time.cumulative[ri];
303 }
304
305 static void
306 print_shader_time_line(const char *stage, const char *name,
307 int shader_num, uint64_t time, uint64_t total)
308 {
309 printf("%-6s%-6s", stage, name);
310
311 if (shader_num != -1)
312 printf("%4d: ", shader_num);
313 else
314 printf(" : ");
315
316 printf("%16lld (%7.2f Gcycles) %4.1f%%\n",
317 (long long)time,
318 (double)time / 1000000000.0,
319 (double)time / total * 100.0);
320 }
321
322 static void
323 brw_report_shader_time(struct brw_context *brw)
324 {
325 if (!brw->shader_time.bo || !brw->shader_time.num_entries)
326 return;
327
328 uint64_t scaled[brw->shader_time.num_entries];
329 uint64_t *sorted[brw->shader_time.num_entries];
330 uint64_t total_by_type[ST_FS16 + 1];
331 memset(total_by_type, 0, sizeof(total_by_type));
332 double total = 0;
333 for (int i = 0; i < brw->shader_time.num_entries; i++) {
334 uint64_t written = 0, reset = 0;
335 enum shader_time_shader_type type = brw->shader_time.types[i];
336
337 sorted[i] = &scaled[i];
338
339 switch (type) {
340 case ST_VS_WRITTEN:
341 case ST_VS_RESET:
342 case ST_FS8_WRITTEN:
343 case ST_FS8_RESET:
344 case ST_FS16_WRITTEN:
345 case ST_FS16_RESET:
346 /* We'll handle these when along with the time. */
347 scaled[i] = 0;
348 continue;
349
350 case ST_VS:
351 case ST_FS8:
352 case ST_FS16:
353 get_written_and_reset(brw, i, &written, &reset);
354 break;
355
356 default:
357 /* I sometimes want to print things that aren't the 3 shader times.
358 * Just print the sum in that case.
359 */
360 written = 1;
361 reset = 0;
362 break;
363 }
364
365 uint64_t time = brw->shader_time.cumulative[i];
366 if (written) {
367 scaled[i] = time / written * (written + reset);
368 } else {
369 scaled[i] = time;
370 }
371
372 switch (type) {
373 case ST_VS:
374 case ST_FS8:
375 case ST_FS16:
376 total_by_type[type] += scaled[i];
377 break;
378 default:
379 break;
380 }
381
382 total += scaled[i];
383 }
384
385 if (total == 0) {
386 printf("No shader time collected yet\n");
387 return;
388 }
389
390 qsort(sorted, brw->shader_time.num_entries, sizeof(sorted[0]), compare_time);
391
392 printf("\n");
393 printf("type ID cycles spent %% of total\n");
394 for (int s = 0; s < brw->shader_time.num_entries; s++) {
395 const char *shader_name;
396 const char *stage;
397 /* Work back from the sorted pointers times to a time to print. */
398 int i = sorted[s] - scaled;
399
400 if (scaled[i] == 0)
401 continue;
402
403 int shader_num = -1;
404 if (brw->shader_time.shader_programs[i]) {
405 shader_num = brw->shader_time.shader_programs[i]->Name;
406
407 /* The fixed function fragment shader generates GLSL IR with a Name
408 * of 0, and nothing else does.
409 */
410 if (shader_num == 0 &&
411 (brw->shader_time.types[i] == ST_FS8 ||
412 brw->shader_time.types[i] == ST_FS16)) {
413 shader_name = "ff";
414 shader_num = -1;
415 } else {
416 shader_name = "glsl";
417 }
418 } else if (brw->shader_time.programs[i]) {
419 shader_num = brw->shader_time.programs[i]->Id;
420 if (shader_num == 0) {
421 shader_name = "ff";
422 shader_num = -1;
423 } else {
424 shader_name = "prog";
425 }
426 } else {
427 shader_name = "other";
428 }
429
430 switch (brw->shader_time.types[i]) {
431 case ST_VS:
432 stage = "vs";
433 break;
434 case ST_FS8:
435 stage = "fs8";
436 break;
437 case ST_FS16:
438 stage = "fs16";
439 break;
440 default:
441 stage = "other";
442 break;
443 }
444
445 print_shader_time_line(stage, shader_name, shader_num,
446 scaled[i], total);
447 }
448
449 printf("\n");
450 print_shader_time_line("total", "vs", -1, total_by_type[ST_VS], total);
451 print_shader_time_line("total", "fs8", -1, total_by_type[ST_FS8], total);
452 print_shader_time_line("total", "fs16", -1, total_by_type[ST_FS16], total);
453 }
454
455 static void
456 brw_collect_shader_time(struct brw_context *brw)
457 {
458 if (!brw->shader_time.bo)
459 return;
460
461 /* This probably stalls on the last rendering. We could fix that by
462 * delaying reading the reports, but it doesn't look like it's a big
463 * overhead compared to the cost of tracking the time in the first place.
464 */
465 drm_intel_bo_map(brw->shader_time.bo, true);
466
467 uint32_t *times = brw->shader_time.bo->virtual;
468
469 for (int i = 0; i < brw->shader_time.num_entries; i++) {
470 brw->shader_time.cumulative[i] += times[i * SHADER_TIME_STRIDE / 4];
471 }
472
473 /* Zero the BO out to clear it out for our next collection.
474 */
475 memset(times, 0, brw->shader_time.bo->size);
476 drm_intel_bo_unmap(brw->shader_time.bo);
477 }
478
479 void
480 brw_collect_and_report_shader_time(struct brw_context *brw)
481 {
482 brw_collect_shader_time(brw);
483
484 if (brw->shader_time.report_time == 0 ||
485 get_time() - brw->shader_time.report_time >= 1.0) {
486 brw_report_shader_time(brw);
487 brw->shader_time.report_time = get_time();
488 }
489 }
490
491 /**
492 * Chooses an index in the shader_time buffer and sets up tracking information
493 * for our printouts.
494 *
495 * Note that this holds on to references to the underlying programs, which may
496 * change their lifetimes compared to normal operation.
497 */
498 int
499 brw_get_shader_time_index(struct brw_context *brw,
500 struct gl_shader_program *shader_prog,
501 struct gl_program *prog,
502 enum shader_time_shader_type type)
503 {
504 struct gl_context *ctx = &brw->ctx;
505
506 int shader_time_index = brw->shader_time.num_entries++;
507 assert(shader_time_index < brw->shader_time.max_entries);
508 brw->shader_time.types[shader_time_index] = type;
509
510 _mesa_reference_shader_program(ctx,
511 &brw->shader_time.shader_programs[shader_time_index],
512 shader_prog);
513
514 _mesa_reference_program(ctx,
515 &brw->shader_time.programs[shader_time_index],
516 prog);
517
518 return shader_time_index;
519 }
520
521 void
522 brw_destroy_shader_time(struct brw_context *brw)
523 {
524 drm_intel_bo_unreference(brw->shader_time.bo);
525 brw->shader_time.bo = NULL;
526 }