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