gallium: rename 'state tracker' to 'frontend'
[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 "frontend/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_inlines.h"
14 #include "util/u_memory.h" /* Offset() */
15 #include "util/u_draw_quad.h"
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
153 memset(&templat, 0, sizeof(templat));
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.array_size = 1;
160 templat.last_level = 0;
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 ctx->buffer_subdata(ctx, constbuf1,
172 PIPE_TRANSFER_WRITE,
173 0, sizeof(constants1), constants1);
174
175 pipe_set_constant_buffer(ctx,
176 PIPE_SHADER_GEOMETRY, 0,
177 constbuf1);
178 }
179 {
180 ctx->buffer_subdata(ctx, constbuf2,
181 PIPE_TRANSFER_WRITE,
182 0, sizeof(constants2), constants2);
183
184 pipe_set_constant_buffer(ctx,
185 PIPE_SHADER_GEOMETRY, 1,
186 constbuf2);
187 }
188 }
189
190
191 static void set_viewport( float x, float y,
192 float width, float height,
193 float zNear, float zFar)
194 {
195 float z = zFar;
196 float half_width = (float)width / 2.0f;
197 float half_height = (float)height / 2.0f;
198 float half_depth = ((float)zFar - (float)zNear) / 2.0f;
199 struct pipe_viewport_state vp;
200
201 vp.scale[0] = half_width;
202 vp.scale[1] = half_height;
203 vp.scale[2] = half_depth;
204
205 vp.translate[0] = half_width + x;
206 vp.translate[1] = half_height + y;
207 vp.translate[2] = half_depth + z;
208
209 ctx->set_viewport_states( ctx, 0, 1, &vp );
210 }
211
212 static void set_vertices( void )
213 {
214 struct pipe_vertex_element ve[4];
215 struct pipe_vertex_buffer vbuf;
216 void *handle;
217
218 memset(ve, 0, sizeof ve);
219
220 ve[0].src_offset = Offset(struct vertex, position);
221 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
222 ve[1].src_offset = Offset(struct vertex, color);
223 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
224 ve[2].src_offset = Offset(struct vertex, texcoord);
225 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
226 ve[3].src_offset = Offset(struct vertex, generic);
227 ve[3].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
228
229 handle = ctx->create_vertex_elements_state(ctx, 4, ve);
230 ctx->bind_vertex_elements_state(ctx, handle);
231
232 memset(&vbuf, 0, sizeof vbuf);
233
234 vbuf.stride = sizeof( struct vertex );
235 vbuf.buffer_offset = 0;
236 if (draw_strip) {
237 vbuf.buffer.resource = pipe_buffer_create_with_data(ctx,
238 PIPE_BIND_VERTEX_BUFFER,
239 PIPE_USAGE_DEFAULT,
240 sizeof(vertices_strip),
241 vertices_strip);
242 } else {
243 vbuf.buffer.resource = pipe_buffer_create_with_data(ctx,
244 PIPE_BIND_VERTEX_BUFFER,
245 PIPE_USAGE_DEFAULT,
246 sizeof(vertices),
247 vertices);
248 }
249
250 ctx->set_vertex_buffers(ctx, 0, 1, &vbuf);
251 }
252
253 static void set_vertex_shader( void )
254 {
255 void *handle;
256 const char *text =
257 "VERT\n"
258 "DCL IN[0]\n"
259 "DCL IN[1]\n"
260 "DCL IN[2]\n"
261 "DCL IN[3]\n"
262 "DCL OUT[0], POSITION\n"
263 "DCL OUT[1], COLOR[0]\n"
264 "DCL OUT[2], GENERIC[0]\n"
265 "DCL OUT[3], GENERIC[1]\n"
266 " MOV OUT[0], IN[0]\n"
267 " MOV OUT[1], IN[1]\n"
268 " MOV OUT[2], IN[2]\n"
269 " MOV OUT[3], IN[3]\n"
270 " END\n";
271
272 handle = graw_parse_vertex_shader(ctx, text);
273 ctx->bind_vs_state(ctx, handle);
274 }
275
276 static void set_fragment_shader( void )
277 {
278 void *handle;
279 const char *text =
280 "FRAG\n"
281 "DCL IN[0], COLOR, LINEAR\n"
282 "DCL OUT[0], COLOR\n"
283 " 0: MOV OUT[0], IN[0]\n"
284 " 1: END\n";
285
286 handle = graw_parse_fragment_shader(ctx, text);
287 ctx->bind_fs_state(ctx, handle);
288 }
289
290
291 static void set_geometry_shader( void )
292 {
293 FILE *f;
294 char buf[50000];
295 void *handle;
296 int sz;
297
298 if ((f = fopen(filename, "r")) == NULL) {
299 fprintf(stderr, "Couldn't open %s\n", filename);
300 exit(1);
301 }
302
303 sz = fread(buf, 1, sizeof(buf), f);
304 if (!feof(f)) {
305 printf("file too long\n");
306 exit(1);
307 }
308 printf("%.*s\n", sz, buf);
309 buf[sz] = 0;
310
311 handle = graw_parse_geometry_shader(ctx, buf);
312 ctx->bind_gs_state(ctx, handle);
313 fclose(f);
314 }
315
316
317 static void draw( void )
318 {
319 union pipe_color_union clear_color = { {.1,.3,.5,0} };
320
321 ctx->clear(ctx, PIPE_CLEAR_COLOR, NULL, &clear_color, 0, 0);
322 if (draw_strip)
323 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
324 else
325 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
326
327 ctx->flush(ctx, NULL, 0);
328
329 graw_save_surface_to_file(ctx, surf, NULL);
330
331 screen->flush_frontbuffer(screen, rttex, 0, 0, window, NULL);
332 }
333
334 #define SIZE 16
335
336 static void init_tex( void )
337 {
338 struct pipe_sampler_view sv_template;
339 struct pipe_sampler_state sampler_desc;
340 struct pipe_resource templat;
341 struct pipe_box box;
342 ubyte tex2d[SIZE][SIZE][4];
343 int s, t;
344
345 #if (SIZE != 2)
346 for (s = 0; s < SIZE; s++) {
347 for (t = 0; t < SIZE; t++) {
348 if (0) {
349 int x = (s ^ t) & 1;
350 tex2d[t][s][0] = (x) ? 0 : 63;
351 tex2d[t][s][1] = (x) ? 0 : 128;
352 tex2d[t][s][2] = 0;
353 tex2d[t][s][3] = 0xff;
354 }
355 else {
356 int x = ((s ^ t) >> 2) & 1;
357 tex2d[t][s][0] = s*255/(SIZE-1);
358 tex2d[t][s][1] = t*255/(SIZE-1);
359 tex2d[t][s][2] = (x) ? 0 : 128;
360 tex2d[t][s][3] = 0xff;
361 }
362 }
363 }
364 #else
365 tex2d[0][0][0] = 0;
366 tex2d[0][0][1] = 255;
367 tex2d[0][0][2] = 255;
368 tex2d[0][0][3] = 0;
369
370 tex2d[0][1][0] = 0;
371 tex2d[0][1][1] = 0;
372 tex2d[0][1][2] = 255;
373 tex2d[0][1][3] = 255;
374
375 tex2d[1][0][0] = 255;
376 tex2d[1][0][1] = 255;
377 tex2d[1][0][2] = 0;
378 tex2d[1][0][3] = 255;
379
380 tex2d[1][1][0] = 255;
381 tex2d[1][1][1] = 0;
382 tex2d[1][1][2] = 0;
383 tex2d[1][1][3] = 255;
384 #endif
385
386 memset(&templat, 0, sizeof(templat));
387 templat.target = PIPE_TEXTURE_2D;
388 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
389 templat.width0 = SIZE;
390 templat.height0 = SIZE;
391 templat.depth0 = 1;
392 templat.array_size = 1;
393 templat.last_level = 0;
394 templat.bind = PIPE_BIND_SAMPLER_VIEW;
395
396
397 samptex = screen->resource_create(screen,
398 &templat);
399 if (samptex == NULL)
400 exit(4);
401
402 u_box_2d(0,0,SIZE,SIZE, &box);
403
404 ctx->texture_subdata(ctx,
405 samptex,
406 0,
407 PIPE_TRANSFER_WRITE,
408 &box,
409 tex2d,
410 sizeof tex2d[0],
411 sizeof tex2d);
412
413 /* Possibly read back & compare against original data:
414 */
415 if (0)
416 {
417 struct pipe_transfer *t;
418 uint32_t *ptr;
419 ptr = pipe_transfer_map(ctx, samptex,
420 0, 0, /* level, layer */
421 PIPE_TRANSFER_READ,
422 0, 0, SIZE, SIZE, &t); /* x, y, width, height */
423
424 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
425 assert(0);
426 exit(9);
427 }
428
429 ctx->transfer_unmap(ctx, t);
430 }
431
432 memset(&sv_template, 0, sizeof sv_template);
433 sv_template.format = samptex->format;
434 sv_template.texture = samptex;
435 sv_template.swizzle_r = 0;
436 sv_template.swizzle_g = 1;
437 sv_template.swizzle_b = 2;
438 sv_template.swizzle_a = 3;
439 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
440 if (sv == NULL)
441 exit(5);
442
443 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &sv);
444
445
446 memset(&sampler_desc, 0, sizeof sampler_desc);
447 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
448 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
449 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
450 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
451 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
452 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
453 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
454 sampler_desc.compare_func = 0;
455 sampler_desc.normalized_coords = 1;
456 sampler_desc.max_anisotropy = 0;
457
458 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
459 if (sampler == NULL)
460 exit(6);
461
462 ctx->bind_sampler_states(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler);
463
464 }
465
466 static void init( void )
467 {
468 struct pipe_framebuffer_state fb;
469 struct pipe_resource templat;
470 struct pipe_surface surf_tmpl;
471 int i;
472
473 /* It's hard to say whether window or screen should be created
474 * first. Different environments would prefer one or the other.
475 *
476 * Also, no easy way of querying supported formats if the screen
477 * cannot be created first.
478 */
479 for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
480 screen = graw_create_window_and_screen(0, 0, 300, 300,
481 formats[i],
482 &window);
483 if (window && screen)
484 break;
485 }
486 if (!screen || !window) {
487 fprintf(stderr, "Unable to create window\n");
488 exit(1);
489 }
490
491 ctx = screen->context_create(screen, NULL, 0);
492 if (ctx == NULL)
493 exit(3);
494
495 memset(&templat, 0, sizeof(templat));
496 templat.target = PIPE_TEXTURE_2D;
497 templat.format = formats[i];
498 templat.width0 = WIDTH;
499 templat.height0 = HEIGHT;
500 templat.depth0 = 1;
501 templat.array_size = 1;
502 templat.last_level = 0;
503 templat.bind = (PIPE_BIND_RENDER_TARGET |
504 PIPE_BIND_DISPLAY_TARGET);
505
506 rttex = screen->resource_create(screen,
507 &templat);
508 if (rttex == NULL)
509 exit(4);
510
511 surf_tmpl.format = templat.format;
512 surf_tmpl.u.tex.level = 0;
513 surf_tmpl.u.tex.first_layer = 0;
514 surf_tmpl.u.tex.last_layer = 0;
515 surf = ctx->create_surface(ctx, rttex, &surf_tmpl);
516 if (surf == NULL)
517 exit(5);
518
519 memset(&fb, 0, sizeof fb);
520 fb.nr_cbufs = 1;
521 fb.width = WIDTH;
522 fb.height = HEIGHT;
523 fb.cbufs[0] = surf;
524
525 ctx->set_framebuffer_state(ctx, &fb);
526
527 {
528 struct pipe_blend_state blend;
529 void *handle;
530 memset(&blend, 0, sizeof blend);
531 blend.rt[0].colormask = PIPE_MASK_RGBA;
532 handle = ctx->create_blend_state(ctx, &blend);
533 ctx->bind_blend_state(ctx, handle);
534 }
535
536 {
537 struct pipe_depth_stencil_alpha_state depthstencil;
538 void *handle;
539 memset(&depthstencil, 0, sizeof depthstencil);
540 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
541 ctx->bind_depth_stencil_alpha_state(ctx, handle);
542 }
543
544 {
545 struct pipe_rasterizer_state rasterizer;
546 void *handle;
547 memset(&rasterizer, 0, sizeof rasterizer);
548 rasterizer.cull_face = PIPE_FACE_NONE;
549 rasterizer.half_pixel_center = 1;
550 rasterizer.bottom_edge_rule = 1;
551 rasterizer.depth_clip_near = 1;
552 rasterizer.depth_clip_far = 1;
553 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
554 ctx->bind_rasterizer_state(ctx, handle);
555 }
556
557 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
558
559 init_tex();
560 init_fs_constbuf();
561
562 set_vertices();
563 set_vertex_shader();
564 set_fragment_shader();
565 set_geometry_shader();
566 }
567
568 static void args(int argc, char *argv[])
569 {
570 int i;
571
572 for (i = 1; i < argc;) {
573 if (graw_parse_args(&i, argc, argv)) {
574 continue;
575 }
576 if (strcmp(argv[i], "-fps") == 0) {
577 show_fps = 1;
578 i++;
579 }
580 else if (strcmp(argv[i], "-strip") == 0) {
581 draw_strip = 1;
582 i++;
583 }
584 else if (i == argc - 1) {
585 filename = argv[i];
586 i++;
587 }
588 else {
589 usage(argv[0]);
590 exit(1);
591 }
592 }
593
594 if (!filename) {
595 usage(argv[0]);
596 exit(1);
597 }
598 }
599
600 int main( int argc, char *argv[] )
601 {
602 args(argc,argv);
603 init();
604
605 graw_set_display_func( draw );
606 graw_main_loop();
607 return 0;
608 }