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