gs-test.c revision 90437330e2886fcd351dd11ee0e5aa3e8b523fdc
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_draw_quad.h"
17#include "util/u_box.h"
18
19static const char *filename = NULL;
20unsigned show_fps = 0;
21unsigned draw_strip = 0;
22
23
24static void usage(char *name)
25{
26   fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
27#ifndef WIN32
28   fprintf(stderr, "\n" );
29   fprintf(stderr, "options:\n");
30   fprintf(stderr, "    -fps  show frames per second\n");
31   fprintf(stderr, "    -strip renders a triangle strip\n");
32#endif
33}
34
35
36enum pipe_format formats[] = {
37   PIPE_FORMAT_R8G8B8A8_UNORM,
38   PIPE_FORMAT_B8G8R8A8_UNORM,
39   PIPE_FORMAT_NONE
40};
41
42static const int WIDTH = 250;
43static const int HEIGHT = 250;
44
45static struct pipe_screen *screen = NULL;
46static struct pipe_context *ctx = NULL;
47static struct pipe_resource *rttex = NULL;
48static struct pipe_resource *constbuf1 = NULL;
49static struct pipe_resource *constbuf2 = NULL;
50static struct pipe_surface *surf = NULL;
51static struct pipe_sampler_view *sv = NULL;
52static void *sampler = NULL;
53static void *window = NULL;
54static struct pipe_resource *samptex = NULL;
55
56struct vertex {
57   float position[4];
58   float color[4];
59   float texcoord[4];
60   float generic[4];
61};
62
63/* Vertex data matches progs/fp/fp-tri.c, but flipped in Y dimension
64 * so that the final images are the same.
65 */
66static struct vertex vertices[] =
67{
68   { { 0.9, 0.9, 0.0, 1.0 },
69     { 0, 0, 1, 1 },
70     { 1, 1, 0, 1 },
71     { 1, 0, 1, 0 }
72   },
73
74   { { 0.9,  -0.9, 0.0, 1.0 },
75     { 1, 0, 0, 1 },
76     { 1, -1, 0, 1 },
77     { 0, 1, 0, 1 }
78   },
79
80   { {-0.9,  0.0, 0.0, 1.0 },
81     { 0, 1, 0, 1 },
82     { -1, 0, 0, 1 },
83     { 0, 0, 1, 1 }
84   },
85};
86
87static struct vertex vertices_strip[] =
88{
89   { { 0.9, 0.9, 0.0, 1.0 },
90     { 0, 0, 1, 1 },
91     { 1, 1, 0, 1 },
92     { 1, 0, 0, 1 }
93   },
94
95   { { 0.9,  -0.9, 0.0, 1.0 },
96     { 1, 0, 0, 1 },
97     { 1, -1, 0, 1 },
98     { 0, 1, 0, 1 }
99   },
100
101   { {-0.9,  0.9, 0.0, 1.0 },
102     { 0, 1, 0, 1 },
103     { -1, 1, 0, 1 },
104     { 0, 0, 1, 1 }
105   },
106
107   { {-0.9,  -0.9, 0.0, 1.0 },
108     { 1, 1, 0, 1 },
109     { -1, -1, 0, 1 },
110     { 1, 1, 0, 1 }
111   },
112};
113
114static float constants1[] =
115{  0.4, 0, 0,  1,
116   1,   1, 1,  1,
117   2,   2, 2,  2,
118   4,   8, 16, 32,
119
120   3,  0, 0, 0,
121   0, .5, 0, 0,
122   0,  0, 1, 0,
123   0,  0, 0, 1,
124
125   1, 0, 0, 0.5,
126   0, 1, 0, 0.5,
127   0, 0, 1, 0,
128   0, 0, 0, 1,
129};
130
131
132static float constants2[] =
133{  1, 0, 0,  1,
134   0, 1, 0,  1,
135   0, 0, 1,  1,
136   0, 0, 0,  1,
137
138   1,  1, 0, 1,
139   1, .5, 0, 1,
140   0,  1, 1, 1,
141   1,  0, 1, 1,
142
143   1, 0, 0, 0.5,
144   0, 1, 0, 0.5,
145   0, 0, 1, 0,
146   0, 0, 0, 1,
147};
148
149
150static void init_fs_constbuf( void )
151{
152   struct pipe_resource templat;
153   struct pipe_box box;
154
155   templat.target = PIPE_BUFFER;
156   templat.format = PIPE_FORMAT_R8_UNORM;
157   templat.width0 = sizeof(constants1);
158   templat.height0 = 1;
159   templat.depth0 = 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                                 u_subresource(0,0),
177                                 PIPE_TRANSFER_WRITE,
178                                 &box,
179                                 constants1,
180                                 sizeof constants1,
181                                 sizeof constants1);
182
183
184      ctx->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                                 u_subresource(0,0),
194                                 PIPE_TRANSFER_WRITE,
195                                 &box,
196                                 constants2,
197                                 sizeof constants2,
198                                 sizeof constants2);
199
200
201      ctx->set_constant_buffer(ctx,
202                               PIPE_SHADER_GEOMETRY, 1,
203                               constbuf2);
204   }
205}
206
207
208static void set_viewport( float x, float y,
209                          float width, float height,
210                          float near, float far)
211{
212   float z = far;
213   float half_width = (float)width / 2.0f;
214   float half_height = (float)height / 2.0f;
215   float half_depth = ((float)far - (float)near) / 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   vp.scale[3] = 1.0f;
222
223   vp.translate[0] = half_width + x;
224   vp.translate[1] = half_height + y;
225   vp.translate[2] = half_depth + z;
226   vp.translate[3] = 0.0f;
227
228   ctx->set_viewport_state( ctx, &vp );
229}
230
231static void set_vertices( void )
232{
233   struct pipe_vertex_element ve[4];
234   struct pipe_vertex_buffer vbuf;
235   void *handle;
236
237   memset(ve, 0, sizeof ve);
238
239   ve[0].src_offset = Offset(struct vertex, position);
240   ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
241   ve[1].src_offset = Offset(struct vertex, color);
242   ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
243   ve[2].src_offset = Offset(struct vertex, texcoord);
244   ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
245   ve[3].src_offset = Offset(struct vertex, generic);
246   ve[3].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
247
248   handle = ctx->create_vertex_elements_state(ctx, 4, ve);
249   ctx->bind_vertex_elements_state(ctx, handle);
250
251   vbuf.stride = sizeof( struct vertex );
252   vbuf.buffer_offset = 0;
253   if (draw_strip) {
254      vbuf.max_index = sizeof(vertices_strip) / vbuf.stride;
255      vbuf.buffer = screen->user_buffer_create(screen,
256                                               vertices_strip,
257                                               sizeof(vertices_strip),
258                                               PIPE_BIND_VERTEX_BUFFER);
259   } else {
260      vbuf.max_index = sizeof(vertices) / vbuf.stride;
261      vbuf.buffer = screen->user_buffer_create(screen,
262                                               vertices,
263                                               sizeof(vertices),
264                                               PIPE_BIND_VERTEX_BUFFER);
265   }
266
267   ctx->set_vertex_buffers(ctx, 1, &vbuf);
268}
269
270static 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
293static 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
308static 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
334static void draw( void )
335{
336   float clear_color[4] = {.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, PIPE_FLUSH_RENDER_CACHE, NULL);
345
346#if 0
347   /* At the moment, libgraw leaks out/makes available some of the
348    * symbols from gallium/auxiliary, including these debug helpers.
349    * Will eventually want to bless some of these paths, and lock the
350    * others down so they aren't accessible from test programs.
351    *
352    * This currently just happens to work on debug builds - a release
353    * build will probably fail to link here:
354    */
355   debug_dump_surface_bmp(ctx, "result.bmp", surf);
356#endif
357
358   screen->flush_frontbuffer(screen, surf, window);
359}
360
361#define SIZE 16
362
363static void init_tex( void )
364{
365   struct pipe_sampler_view sv_template;
366   struct pipe_sampler_state sampler_desc;
367   struct pipe_resource templat;
368   struct pipe_box box;
369   ubyte tex2d[SIZE][SIZE][4];
370   int s, t;
371
372#if (SIZE != 2)
373   for (s = 0; s < SIZE; s++) {
374      for (t = 0; t < SIZE; t++) {
375         if (0) {
376            int x = (s ^ t) & 1;
377	    tex2d[t][s][0] = (x) ? 0 : 63;
378	    tex2d[t][s][1] = (x) ? 0 : 128;
379	    tex2d[t][s][2] = 0;
380	    tex2d[t][s][3] = 0xff;
381         }
382         else {
383            int x = ((s ^ t) >> 2) & 1;
384	    tex2d[t][s][0] = s*255/(SIZE-1);
385	    tex2d[t][s][1] = t*255/(SIZE-1);
386	    tex2d[t][s][2] = (x) ? 0 : 128;
387	    tex2d[t][s][3] = 0xff;
388         }
389      }
390   }
391#else
392   tex2d[0][0][0] = 0;
393   tex2d[0][0][1] = 255;
394   tex2d[0][0][2] = 255;
395   tex2d[0][0][3] = 0;
396
397   tex2d[0][1][0] = 0;
398   tex2d[0][1][1] = 0;
399   tex2d[0][1][2] = 255;
400   tex2d[0][1][3] = 255;
401
402   tex2d[1][0][0] = 255;
403   tex2d[1][0][1] = 255;
404   tex2d[1][0][2] = 0;
405   tex2d[1][0][3] = 255;
406
407   tex2d[1][1][0] = 255;
408   tex2d[1][1][1] = 0;
409   tex2d[1][1][2] = 0;
410   tex2d[1][1][3] = 255;
411#endif
412
413   templat.target = PIPE_TEXTURE_2D;
414   templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
415   templat.width0 = SIZE;
416   templat.height0 = SIZE;
417   templat.depth0 = 1;
418   templat.last_level = 0;
419   templat.nr_samples = 1;
420   templat.bind = PIPE_BIND_SAMPLER_VIEW;
421
422
423   samptex = screen->resource_create(screen,
424                                 &templat);
425   if (samptex == NULL)
426      exit(4);
427
428   u_box_2d(0,0,SIZE,SIZE, &box);
429
430   ctx->transfer_inline_write(ctx,
431                              samptex,
432                              u_subresource(0,0),
433                              PIPE_TRANSFER_WRITE,
434                              &box,
435                              tex2d,
436                              sizeof tex2d[0],
437                              sizeof tex2d);
438
439   /* Possibly read back & compare against original data:
440    */
441   if (0)
442   {
443      struct pipe_transfer *t;
444      uint32_t *ptr;
445      t = pipe_get_transfer(ctx, samptex,
446                            0, 0, 0, /* face, level, zslice */
447                            PIPE_TRANSFER_READ,
448                            0, 0, SIZE, SIZE); /* x, y, width, height */
449
450      ptr = ctx->transfer_map(ctx, t);
451
452      if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
453         assert(0);
454         exit(9);
455      }
456
457      ctx->transfer_unmap(ctx, t);
458
459      ctx->transfer_destroy(ctx, t);
460   }
461
462   memset(&sv_template, 0, sizeof sv_template);
463   sv_template.format = samptex->format;
464   sv_template.texture = samptex;
465   sv_template.first_level = 0;
466   sv_template.last_level = 0;
467   sv_template.swizzle_r = 0;
468   sv_template.swizzle_g = 1;
469   sv_template.swizzle_b = 2;
470   sv_template.swizzle_a = 3;
471   sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
472   if (sv == NULL)
473      exit(5);
474
475   ctx->set_fragment_sampler_views(ctx, 1, &sv);
476
477
478   memset(&sampler_desc, 0, sizeof sampler_desc);
479   sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
480   sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
481   sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
482   sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
483   sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
484   sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
485   sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
486   sampler_desc.compare_func = 0;
487   sampler_desc.normalized_coords = 1;
488   sampler_desc.max_anisotropy = 0;
489
490   sampler = ctx->create_sampler_state(ctx, &sampler_desc);
491   if (sampler == NULL)
492      exit(6);
493
494   ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
495
496}
497
498static void init( void )
499{
500   struct pipe_framebuffer_state fb;
501   struct pipe_resource templat;
502   int i;
503
504   /* It's hard to say whether window or screen should be created
505    * first.  Different environments would prefer one or the other.
506    *
507    * Also, no easy way of querying supported formats if the screen
508    * cannot be created first.
509    */
510   for (i = 0;
511        window == NULL && formats[i] != PIPE_FORMAT_NONE;
512        i++) {
513
514      screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
515                                             formats[i],
516                                             &window);
517   }
518
519   ctx = screen->context_create(screen, NULL);
520   if (ctx == NULL)
521      exit(3);
522
523   templat.target = PIPE_TEXTURE_2D;
524   templat.format = formats[i];
525   templat.width0 = WIDTH;
526   templat.height0 = HEIGHT;
527   templat.depth0 = 1;
528   templat.last_level = 0;
529   templat.nr_samples = 1;
530   templat.bind = (PIPE_BIND_RENDER_TARGET |
531                   PIPE_BIND_DISPLAY_TARGET);
532
533   rttex = screen->resource_create(screen,
534                                 &templat);
535   if (rttex == NULL)
536      exit(4);
537
538   surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
539                                  PIPE_BIND_RENDER_TARGET |
540                                  PIPE_BIND_DISPLAY_TARGET);
541   if (surf == NULL)
542      exit(5);
543
544   memset(&fb, 0, sizeof fb);
545   fb.nr_cbufs = 1;
546   fb.width = WIDTH;
547   fb.height = HEIGHT;
548   fb.cbufs[0] = surf;
549
550   ctx->set_framebuffer_state(ctx, &fb);
551
552   {
553      struct pipe_blend_state blend;
554      void *handle;
555      memset(&blend, 0, sizeof blend);
556      blend.rt[0].colormask = PIPE_MASK_RGBA;
557      handle = ctx->create_blend_state(ctx, &blend);
558      ctx->bind_blend_state(ctx, handle);
559   }
560
561   {
562      struct pipe_depth_stencil_alpha_state depthstencil;
563      void *handle;
564      memset(&depthstencil, 0, sizeof depthstencil);
565      handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
566      ctx->bind_depth_stencil_alpha_state(ctx, handle);
567   }
568
569   {
570      struct pipe_rasterizer_state rasterizer;
571      void *handle;
572      memset(&rasterizer, 0, sizeof rasterizer);
573      rasterizer.cull_face = PIPE_FACE_NONE;
574      rasterizer.gl_rasterization_rules = 1;
575      handle = ctx->create_rasterizer_state(ctx, &rasterizer);
576      ctx->bind_rasterizer_state(ctx, handle);
577   }
578
579   set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
580
581   init_tex();
582   init_fs_constbuf();
583
584   set_vertices();
585   set_vertex_shader();
586   set_fragment_shader();
587   set_geometry_shader();
588}
589
590static void args(int argc, char *argv[])
591{
592   int i;
593
594   for (i = 1; i < argc; i++) {
595      if (strcmp(argv[i], "-fps") == 0) {
596         show_fps = 1;
597      }
598      else if (strcmp(argv[i], "-strip") == 0) {
599         draw_strip = 1;
600      }
601      else if (i == argc - 1) {
602	 filename = argv[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
616int 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}
625