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