Merge branch 'lp-offset-twoside'
[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.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 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
340 else
341 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
342
343 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
344
345 graw_save_surface_to_file(ctx, surf, NULL);
346
347 screen->flush_frontbuffer(screen, surf, window);
348 }
349
350 #define SIZE 16
351
352 static void init_tex( void )
353 {
354 struct pipe_sampler_view sv_template;
355 struct pipe_sampler_state sampler_desc;
356 struct pipe_resource templat;
357 struct pipe_box box;
358 ubyte tex2d[SIZE][SIZE][4];
359 int s, t;
360
361 #if (SIZE != 2)
362 for (s = 0; s < SIZE; s++) {
363 for (t = 0; t < SIZE; t++) {
364 if (0) {
365 int x = (s ^ t) & 1;
366 tex2d[t][s][0] = (x) ? 0 : 63;
367 tex2d[t][s][1] = (x) ? 0 : 128;
368 tex2d[t][s][2] = 0;
369 tex2d[t][s][3] = 0xff;
370 }
371 else {
372 int x = ((s ^ t) >> 2) & 1;
373 tex2d[t][s][0] = s*255/(SIZE-1);
374 tex2d[t][s][1] = t*255/(SIZE-1);
375 tex2d[t][s][2] = (x) ? 0 : 128;
376 tex2d[t][s][3] = 0xff;
377 }
378 }
379 }
380 #else
381 tex2d[0][0][0] = 0;
382 tex2d[0][0][1] = 255;
383 tex2d[0][0][2] = 255;
384 tex2d[0][0][3] = 0;
385
386 tex2d[0][1][0] = 0;
387 tex2d[0][1][1] = 0;
388 tex2d[0][1][2] = 255;
389 tex2d[0][1][3] = 255;
390
391 tex2d[1][0][0] = 255;
392 tex2d[1][0][1] = 255;
393 tex2d[1][0][2] = 0;
394 tex2d[1][0][3] = 255;
395
396 tex2d[1][1][0] = 255;
397 tex2d[1][1][1] = 0;
398 tex2d[1][1][2] = 0;
399 tex2d[1][1][3] = 255;
400 #endif
401
402 templat.target = PIPE_TEXTURE_2D;
403 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
404 templat.width0 = SIZE;
405 templat.height0 = SIZE;
406 templat.depth0 = 1;
407 templat.last_level = 0;
408 templat.nr_samples = 1;
409 templat.bind = PIPE_BIND_SAMPLER_VIEW;
410
411
412 samptex = screen->resource_create(screen,
413 &templat);
414 if (samptex == NULL)
415 exit(4);
416
417 u_box_2d(0,0,SIZE,SIZE, &box);
418
419 ctx->transfer_inline_write(ctx,
420 samptex,
421 u_subresource(0,0),
422 PIPE_TRANSFER_WRITE,
423 &box,
424 tex2d,
425 sizeof tex2d[0],
426 sizeof tex2d);
427
428 /* Possibly read back & compare against original data:
429 */
430 if (0)
431 {
432 struct pipe_transfer *t;
433 uint32_t *ptr;
434 t = pipe_get_transfer(ctx, samptex,
435 0, 0, 0, /* face, level, zslice */
436 PIPE_TRANSFER_READ,
437 0, 0, SIZE, SIZE); /* x, y, width, height */
438
439 ptr = ctx->transfer_map(ctx, t);
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 ctx->transfer_destroy(ctx, t);
449 }
450
451 memset(&sv_template, 0, sizeof sv_template);
452 sv_template.format = samptex->format;
453 sv_template.texture = samptex;
454 sv_template.first_level = 0;
455 sv_template.last_level = 0;
456 sv_template.swizzle_r = 0;
457 sv_template.swizzle_g = 1;
458 sv_template.swizzle_b = 2;
459 sv_template.swizzle_a = 3;
460 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
461 if (sv == NULL)
462 exit(5);
463
464 ctx->set_fragment_sampler_views(ctx, 1, &sv);
465
466
467 memset(&sampler_desc, 0, sizeof sampler_desc);
468 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
469 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
470 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
471 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
472 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
473 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
474 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
475 sampler_desc.compare_func = 0;
476 sampler_desc.normalized_coords = 1;
477 sampler_desc.max_anisotropy = 0;
478
479 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
480 if (sampler == NULL)
481 exit(6);
482
483 ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
484
485 }
486
487 static void init( void )
488 {
489 struct pipe_framebuffer_state fb;
490 struct pipe_resource templat;
491 int i;
492
493 /* It's hard to say whether window or screen should be created
494 * first. Different environments would prefer one or the other.
495 *
496 * Also, no easy way of querying supported formats if the screen
497 * cannot be created first.
498 */
499 for (i = 0;
500 window == NULL && formats[i] != PIPE_FORMAT_NONE;
501 i++) {
502
503 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
504 formats[i],
505 &window);
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.last_level = 0;
518 templat.nr_samples = 1;
519 templat.bind = (PIPE_BIND_RENDER_TARGET |
520 PIPE_BIND_DISPLAY_TARGET);
521
522 rttex = screen->resource_create(screen,
523 &templat);
524 if (rttex == NULL)
525 exit(4);
526
527 surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
528 PIPE_BIND_RENDER_TARGET |
529 PIPE_BIND_DISPLAY_TARGET);
530 if (surf == NULL)
531 exit(5);
532
533 memset(&fb, 0, sizeof fb);
534 fb.nr_cbufs = 1;
535 fb.width = WIDTH;
536 fb.height = HEIGHT;
537 fb.cbufs[0] = surf;
538
539 ctx->set_framebuffer_state(ctx, &fb);
540
541 {
542 struct pipe_blend_state blend;
543 void *handle;
544 memset(&blend, 0, sizeof blend);
545 blend.rt[0].colormask = PIPE_MASK_RGBA;
546 handle = ctx->create_blend_state(ctx, &blend);
547 ctx->bind_blend_state(ctx, handle);
548 }
549
550 {
551 struct pipe_depth_stencil_alpha_state depthstencil;
552 void *handle;
553 memset(&depthstencil, 0, sizeof depthstencil);
554 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
555 ctx->bind_depth_stencil_alpha_state(ctx, handle);
556 }
557
558 {
559 struct pipe_rasterizer_state rasterizer;
560 void *handle;
561 memset(&rasterizer, 0, sizeof rasterizer);
562 rasterizer.cull_face = PIPE_FACE_NONE;
563 rasterizer.gl_rasterization_rules = 1;
564 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
565 ctx->bind_rasterizer_state(ctx, handle);
566 }
567
568 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
569
570 init_tex();
571 init_fs_constbuf();
572
573 set_vertices();
574 set_vertex_shader();
575 set_fragment_shader();
576 set_geometry_shader();
577 }
578
579 static void args(int argc, char *argv[])
580 {
581 int i;
582
583 for (i = 1; i < argc;) {
584 if (graw_parse_args(&i, argc, argv)) {
585 continue;
586 }
587 if (strcmp(argv[i], "-fps") == 0) {
588 show_fps = 1;
589 i++;
590 }
591 else if (strcmp(argv[i], "-strip") == 0) {
592 draw_strip = 1;
593 i++;
594 }
595 else if (i == argc - 1) {
596 filename = argv[i];
597 i++;
598 }
599 else {
600 usage(argv[0]);
601 exit(1);
602 }
603 }
604
605 if (!filename) {
606 usage(argv[0]);
607 exit(1);
608 }
609 }
610
611 int main( int argc, char *argv[] )
612 {
613 args(argc,argv);
614 init();
615
616 graw_set_display_func( draw );
617 graw_main_loop();
618 return 0;
619 }