graw: new tri-instanced.c program to test instanced drawing
[mesa.git] / src / gallium / tests / graw / gs-test.c
1 /* Display a cleared blue window. This demo has no dependencies on
2 * any utility code, just the graw interface and gallium.
3 */
4
5 #include "state_tracker/graw.h"
6 #include "pipe/p_screen.h"
7 #include "pipe/p_context.h"
8 #include "pipe/p_shader_tokens.h"
9 #include "pipe/p_state.h"
10 #include "pipe/p_defines.h"
11 #include <stdio.h> /* for fread(), etc */
12
13 #include "util/u_debug.h" /* debug_dump_surface_bmp() */
14 #include "util/u_inlines.h"
15 #include "util/u_memory.h" /* Offset() */
16 #include "util/u_box.h"
17
18 static const char *filename = NULL;
19 unsigned show_fps = 0;
20 unsigned draw_strip = 0;
21
22
23 static void usage(char *name)
24 {
25 fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
26 #ifndef WIN32
27 fprintf(stderr, "\n" );
28 fprintf(stderr, "options:\n");
29 fprintf(stderr, " -fps show frames per second\n");
30 fprintf(stderr, " -strip renders a triangle strip\n");
31 #endif
32 }
33
34
35 enum pipe_format formats[] = {
36 PIPE_FORMAT_R8G8B8A8_UNORM,
37 PIPE_FORMAT_B8G8R8A8_UNORM,
38 PIPE_FORMAT_NONE
39 };
40
41 static const int WIDTH = 250;
42 static const int HEIGHT = 250;
43
44 static struct pipe_screen *screen = NULL;
45 static struct pipe_context *ctx = NULL;
46 static struct pipe_resource *rttex = NULL;
47 static struct pipe_resource *constbuf1 = NULL;
48 static struct pipe_resource *constbuf2 = NULL;
49 static struct pipe_surface *surf = NULL;
50 static struct pipe_sampler_view *sv = NULL;
51 static void *sampler = NULL;
52 static void *window = NULL;
53 static struct pipe_resource *samptex = NULL;
54
55 struct vertex {
56 float position[4];
57 float color[4];
58 float texcoord[4];
59 float generic[4];
60 };
61
62 /* Vertex data matches progs/fp/fp-tri.c, but flipped in Y dimension
63 * so that the final images are the same.
64 */
65 static struct vertex vertices[] =
66 {
67 { { 0.9, 0.9, 0.0, 1.0 },
68 { 0, 0, 1, 1 },
69 { 1, 1, 0, 1 },
70 { 1, 0, 1, 0 }
71 },
72
73 { { 0.9, -0.9, 0.0, 1.0 },
74 { 1, 0, 0, 1 },
75 { 1, -1, 0, 1 },
76 { 0, 1, 0, 1 }
77 },
78
79 { {-0.9, 0.0, 0.0, 1.0 },
80 { 0, 1, 0, 1 },
81 { -1, 0, 0, 1 },
82 { 0, 0, 1, 1 }
83 },
84 };
85
86 static struct vertex vertices_strip[] =
87 {
88 { { 0.9, 0.9, 0.0, 1.0 },
89 { 0, 0, 1, 1 },
90 { 1, 1, 0, 1 },
91 { 1, 0, 0, 1 }
92 },
93
94 { { 0.9, -0.9, 0.0, 1.0 },
95 { 1, 0, 0, 1 },
96 { 1, -1, 0, 1 },
97 { 0, 1, 0, 1 }
98 },
99
100 { {-0.9, 0.9, 0.0, 1.0 },
101 { 0, 1, 0, 1 },
102 { -1, 1, 0, 1 },
103 { 0, 0, 1, 1 }
104 },
105
106 { {-0.9, -0.9, 0.0, 1.0 },
107 { 1, 1, 0, 1 },
108 { -1, -1, 0, 1 },
109 { 1, 1, 0, 1 }
110 },
111 };
112
113 static float constants1[] =
114 { 0.4, 0, 0, 1,
115 1, 1, 1, 1,
116 2, 2, 2, 2,
117 4, 8, 16, 32,
118
119 3, 0, 0, 0,
120 0, .5, 0, 0,
121 0, 0, 1, 0,
122 0, 0, 0, 1,
123
124 1, 0, 0, 0.5,
125 0, 1, 0, 0.5,
126 0, 0, 1, 0,
127 0, 0, 0, 1,
128 };
129
130
131 static float constants2[] =
132 { 1, 0, 0, 1,
133 0, 1, 0, 1,
134 0, 0, 1, 1,
135 0, 0, 0, 1,
136
137 1, 1, 0, 1,
138 1, .5, 0, 1,
139 0, 1, 1, 1,
140 1, 0, 1, 1,
141
142 1, 0, 0, 0.5,
143 0, 1, 0, 0.5,
144 0, 0, 1, 0,
145 0, 0, 0, 1,
146 };
147
148
149 static void init_fs_constbuf( void )
150 {
151 struct pipe_resource templat;
152 struct pipe_box box;
153
154 templat.target = PIPE_BUFFER;
155 templat.format = PIPE_FORMAT_R8_UNORM;
156 templat.width0 = sizeof(constants1);
157 templat.height0 = 1;
158 templat.depth0 = 1;
159 templat.last_level = 0;
160 templat.nr_samples = 1;
161 templat.bind = PIPE_BIND_CONSTANT_BUFFER;
162
163 constbuf1 = screen->resource_create(screen, &templat);
164 if (constbuf1 == NULL)
165 exit(4);
166 constbuf2 = screen->resource_create(screen, &templat);
167 if (constbuf2 == NULL)
168 exit(4);
169
170 {
171 u_box_2d(0,0,sizeof(constants1),1, &box);
172
173 ctx->transfer_inline_write(ctx,
174 constbuf1,
175 u_subresource(0,0),
176 PIPE_TRANSFER_WRITE,
177 &box,
178 constants1,
179 sizeof constants1,
180 sizeof constants1);
181
182
183 ctx->set_constant_buffer(ctx,
184 PIPE_SHADER_GEOMETRY, 0,
185 constbuf1);
186 }
187 {
188 u_box_2d(0,0,sizeof(constants2),1, &box);
189
190 ctx->transfer_inline_write(ctx,
191 constbuf2,
192 u_subresource(0,0),
193 PIPE_TRANSFER_WRITE,
194 &box,
195 constants2,
196 sizeof constants2,
197 sizeof constants2);
198
199
200 ctx->set_constant_buffer(ctx,
201 PIPE_SHADER_GEOMETRY, 1,
202 constbuf2);
203 }
204 }
205
206
207 static void set_viewport( float x, float y,
208 float width, float height,
209 float near, float far)
210 {
211 float z = far;
212 float half_width = (float)width / 2.0f;
213 float half_height = (float)height / 2.0f;
214 float half_depth = ((float)far - (float)near) / 2.0f;
215 struct pipe_viewport_state vp;
216
217 vp.scale[0] = half_width;
218 vp.scale[1] = half_height;
219 vp.scale[2] = half_depth;
220 vp.scale[3] = 1.0f;
221
222 vp.translate[0] = half_width + x;
223 vp.translate[1] = half_height + y;
224 vp.translate[2] = half_depth + z;
225 vp.translate[3] = 0.0f;
226
227 ctx->set_viewport_state( ctx, &vp );
228 }
229
230 static void set_vertices( void )
231 {
232 struct pipe_vertex_element ve[4];
233 struct pipe_vertex_buffer vbuf;
234 void *handle;
235
236 memset(ve, 0, sizeof ve);
237
238 ve[0].src_offset = Offset(struct vertex, position);
239 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
240 ve[1].src_offset = Offset(struct vertex, color);
241 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
242 ve[2].src_offset = Offset(struct vertex, texcoord);
243 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
244 ve[3].src_offset = Offset(struct vertex, generic);
245 ve[3].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
246
247 handle = ctx->create_vertex_elements_state(ctx, 4, ve);
248 ctx->bind_vertex_elements_state(ctx, handle);
249
250 vbuf.stride = sizeof( struct vertex );
251 vbuf.buffer_offset = 0;
252 if (draw_strip) {
253 vbuf.max_index = sizeof(vertices_strip) / vbuf.stride;
254 vbuf.buffer = screen->user_buffer_create(screen,
255 vertices_strip,
256 sizeof(vertices_strip),
257 PIPE_BIND_VERTEX_BUFFER);
258 } else {
259 vbuf.max_index = sizeof(vertices) / vbuf.stride;
260 vbuf.buffer = screen->user_buffer_create(screen,
261 vertices,
262 sizeof(vertices),
263 PIPE_BIND_VERTEX_BUFFER);
264 }
265
266 ctx->set_vertex_buffers(ctx, 1, &vbuf);
267 }
268
269 static void set_vertex_shader( void )
270 {
271 void *handle;
272 const char *text =
273 "VERT\n"
274 "DCL IN[0]\n"
275 "DCL IN[1]\n"
276 "DCL IN[2]\n"
277 "DCL IN[3]\n"
278 "DCL OUT[0], POSITION\n"
279 "DCL OUT[1], COLOR[0]\n"
280 "DCL OUT[2], GENERIC[0]\n"
281 "DCL OUT[3], GENERIC[1]\n"
282 " MOV OUT[0], IN[0]\n"
283 " MOV OUT[1], IN[1]\n"
284 " MOV OUT[2], IN[2]\n"
285 " MOV OUT[3], IN[3]\n"
286 " END\n";
287
288 handle = graw_parse_vertex_shader(ctx, text);
289 ctx->bind_vs_state(ctx, handle);
290 }
291
292 static void set_fragment_shader( void )
293 {
294 void *handle;
295 const char *text =
296 "FRAG\n"
297 "DCL IN[0], COLOR, LINEAR\n"
298 "DCL OUT[0], COLOR\n"
299 " 0: MOV OUT[0], IN[0]\n"
300 " 1: END\n";
301
302 handle = graw_parse_fragment_shader(ctx, text);
303 ctx->bind_fs_state(ctx, handle);
304 }
305
306
307 static void set_geometry_shader( void )
308 {
309 FILE *f;
310 char buf[50000];
311 void *handle;
312 int sz;
313
314 if ((f = fopen(filename, "r")) == NULL) {
315 fprintf(stderr, "Couldn't open %s\n", filename);
316 exit(1);
317 }
318
319 sz = fread(buf, 1, sizeof(buf), f);
320 if (!feof(f)) {
321 printf("file too long\n");
322 exit(1);
323 }
324 printf("%.*s\n", sz, buf);
325 buf[sz] = 0;
326
327 handle = graw_parse_geometry_shader(ctx, buf);
328 ctx->bind_gs_state(ctx, handle);
329 fclose(f);
330 }
331
332
333 static void draw( void )
334 {
335 float clear_color[4] = {.1,.3,.5,0};
336
337 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
338 if (draw_strip)
339 ctx->draw_arrays(ctx, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
340 else
341 ctx->draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
342
343 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
344
345 #if 0
346 /* At the moment, libgraw leaks out/makes available some of the
347 * symbols from gallium/auxiliary, including these debug helpers.
348 * Will eventually want to bless some of these paths, and lock the
349 * others down so they aren't accessible from test programs.
350 *
351 * This currently just happens to work on debug builds - a release
352 * build will probably fail to link here:
353 */
354 debug_dump_surface_bmp(ctx, "result.bmp", surf);
355 #endif
356
357 screen->flush_frontbuffer(screen, surf, window);
358 }
359
360 #define SIZE 16
361
362 static void init_tex( void )
363 {
364 struct pipe_sampler_view sv_template;
365 struct pipe_sampler_state sampler_desc;
366 struct pipe_resource templat;
367 struct pipe_box box;
368 ubyte tex2d[SIZE][SIZE][4];
369 int s, t;
370
371 #if (SIZE != 2)
372 for (s = 0; s < SIZE; s++) {
373 for (t = 0; t < SIZE; t++) {
374 if (0) {
375 int x = (s ^ t) & 1;
376 tex2d[t][s][0] = (x) ? 0 : 63;
377 tex2d[t][s][1] = (x) ? 0 : 128;
378 tex2d[t][s][2] = 0;
379 tex2d[t][s][3] = 0xff;
380 }
381 else {
382 int x = ((s ^ t) >> 2) & 1;
383 tex2d[t][s][0] = s*255/(SIZE-1);
384 tex2d[t][s][1] = t*255/(SIZE-1);
385 tex2d[t][s][2] = (x) ? 0 : 128;
386 tex2d[t][s][3] = 0xff;
387 }
388 }
389 }
390 #else
391 tex2d[0][0][0] = 0;
392 tex2d[0][0][1] = 255;
393 tex2d[0][0][2] = 255;
394 tex2d[0][0][3] = 0;
395
396 tex2d[0][1][0] = 0;
397 tex2d[0][1][1] = 0;
398 tex2d[0][1][2] = 255;
399 tex2d[0][1][3] = 255;
400
401 tex2d[1][0][0] = 255;
402 tex2d[1][0][1] = 255;
403 tex2d[1][0][2] = 0;
404 tex2d[1][0][3] = 255;
405
406 tex2d[1][1][0] = 255;
407 tex2d[1][1][1] = 0;
408 tex2d[1][1][2] = 0;
409 tex2d[1][1][3] = 255;
410 #endif
411
412 templat.target = PIPE_TEXTURE_2D;
413 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
414 templat.width0 = SIZE;
415 templat.height0 = SIZE;
416 templat.depth0 = 1;
417 templat.last_level = 0;
418 templat.nr_samples = 1;
419 templat.bind = PIPE_BIND_SAMPLER_VIEW;
420
421
422 samptex = screen->resource_create(screen,
423 &templat);
424 if (samptex == NULL)
425 exit(4);
426
427 u_box_2d(0,0,SIZE,SIZE, &box);
428
429 ctx->transfer_inline_write(ctx,
430 samptex,
431 u_subresource(0,0),
432 PIPE_TRANSFER_WRITE,
433 &box,
434 tex2d,
435 sizeof tex2d[0],
436 sizeof tex2d);
437
438 /* Possibly read back & compare against original data:
439 */
440 if (0)
441 {
442 struct pipe_transfer *t;
443 uint32_t *ptr;
444 t = pipe_get_transfer(ctx, samptex,
445 0, 0, 0, /* face, level, zslice */
446 PIPE_TRANSFER_READ,
447 0, 0, SIZE, SIZE); /* x, y, width, height */
448
449 ptr = ctx->transfer_map(ctx, t);
450
451 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
452 assert(0);
453 exit(9);
454 }
455
456 ctx->transfer_unmap(ctx, t);
457
458 ctx->transfer_destroy(ctx, t);
459 }
460
461 memset(&sv_template, 0, sizeof sv_template);
462 sv_template.format = samptex->format;
463 sv_template.texture = samptex;
464 sv_template.first_level = 0;
465 sv_template.last_level = 0;
466 sv_template.swizzle_r = 0;
467 sv_template.swizzle_g = 1;
468 sv_template.swizzle_b = 2;
469 sv_template.swizzle_a = 3;
470 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
471 if (sv == NULL)
472 exit(5);
473
474 ctx->set_fragment_sampler_views(ctx, 1, &sv);
475
476
477 memset(&sampler_desc, 0, sizeof sampler_desc);
478 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
479 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
480 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
481 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
482 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
483 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
484 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
485 sampler_desc.compare_func = 0;
486 sampler_desc.normalized_coords = 1;
487 sampler_desc.max_anisotropy = 0;
488
489 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
490 if (sampler == NULL)
491 exit(6);
492
493 ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
494
495 }
496
497 static void init( void )
498 {
499 struct pipe_framebuffer_state fb;
500 struct pipe_resource templat;
501 int i;
502
503 /* It's hard to say whether window or screen should be created
504 * first. Different environments would prefer one or the other.
505 *
506 * Also, no easy way of querying supported formats if the screen
507 * cannot be created first.
508 */
509 for (i = 0;
510 window == NULL && formats[i] != PIPE_FORMAT_NONE;
511 i++) {
512
513 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
514 formats[i],
515 &window);
516 }
517
518 ctx = screen->context_create(screen, NULL);
519 if (ctx == NULL)
520 exit(3);
521
522 templat.target = PIPE_TEXTURE_2D;
523 templat.format = formats[i];
524 templat.width0 = WIDTH;
525 templat.height0 = HEIGHT;
526 templat.depth0 = 1;
527 templat.last_level = 0;
528 templat.nr_samples = 1;
529 templat.bind = (PIPE_BIND_RENDER_TARGET |
530 PIPE_BIND_DISPLAY_TARGET);
531
532 rttex = screen->resource_create(screen,
533 &templat);
534 if (rttex == NULL)
535 exit(4);
536
537 surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
538 PIPE_BIND_RENDER_TARGET |
539 PIPE_BIND_DISPLAY_TARGET);
540 if (surf == NULL)
541 exit(5);
542
543 memset(&fb, 0, sizeof fb);
544 fb.nr_cbufs = 1;
545 fb.width = WIDTH;
546 fb.height = HEIGHT;
547 fb.cbufs[0] = surf;
548
549 ctx->set_framebuffer_state(ctx, &fb);
550
551 {
552 struct pipe_blend_state blend;
553 void *handle;
554 memset(&blend, 0, sizeof blend);
555 blend.rt[0].colormask = PIPE_MASK_RGBA;
556 handle = ctx->create_blend_state(ctx, &blend);
557 ctx->bind_blend_state(ctx, handle);
558 }
559
560 {
561 struct pipe_depth_stencil_alpha_state depthstencil;
562 void *handle;
563 memset(&depthstencil, 0, sizeof depthstencil);
564 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
565 ctx->bind_depth_stencil_alpha_state(ctx, handle);
566 }
567
568 {
569 struct pipe_rasterizer_state rasterizer;
570 void *handle;
571 memset(&rasterizer, 0, sizeof rasterizer);
572 rasterizer.cull_face = PIPE_FACE_NONE;
573 rasterizer.gl_rasterization_rules = 1;
574 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
575 ctx->bind_rasterizer_state(ctx, handle);
576 }
577
578 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
579
580 init_tex();
581 init_fs_constbuf();
582
583 set_vertices();
584 set_vertex_shader();
585 set_fragment_shader();
586 set_geometry_shader();
587 }
588
589 static void args(int argc, char *argv[])
590 {
591 int i;
592
593 for (i = 1; i < argc; i++) {
594 if (strcmp(argv[i], "-fps") == 0) {
595 show_fps = 1;
596 }
597 else if (strcmp(argv[i], "-strip") == 0) {
598 draw_strip = 1;
599 }
600 else if (i == argc - 1) {
601 filename = argv[i];
602 }
603 else {
604 usage(argv[0]);
605 exit(1);
606 }
607 }
608
609 if (!filename) {
610 usage(argv[0]);
611 exit(1);
612 }
613 }
614
615 int main( int argc, char *argv[] )
616 {
617 args(argc,argv);
618 init();
619
620 graw_set_display_func( draw );
621 graw_main_loop();
622 return 0;
623 }