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
18static const char *filename = NULL;
19unsigned show_fps = 0;
20unsigned draw_strip = 0;
21
22
23static 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
35enum pipe_format formats[] = {
36   PIPE_FORMAT_R8G8B8A8_UNORM,
37   PIPE_FORMAT_B8G8R8A8_UNORM,
38   PIPE_FORMAT_NONE
39};
40
41static const int WIDTH = 250;
42static const int HEIGHT = 250;
43
44static struct pipe_screen *screen = NULL;
45static struct pipe_context *ctx = NULL;
46static struct pipe_resource *rttex = NULL;
47static struct pipe_resource *constbuf1 = NULL;
48static struct pipe_resource *constbuf2 = NULL;
49static struct pipe_surface *surf = NULL;
50static struct pipe_sampler_view *sv = NULL;
51static void *sampler = NULL;
52static void *window = NULL;
53static struct pipe_resource *samptex = NULL;
54
55struct 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 */
65static 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
86static 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
113static 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
131static 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
149static 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
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.buffer = pipe_buffer_create_with_data(ctx,
255                                                 PIPE_BIND_VERTEX_BUFFER,
256                                                 PIPE_USAGE_STATIC,
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_STATIC,
263                                                 sizeof(vertices),
264                                                 vertices);
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   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);
345
346   graw_save_surface_to_file(ctx, surf, NULL);
347
348   screen->flush_frontbuffer(screen, rttex, 0, 0, window);
349}
350
351#define SIZE 16
352
353static 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      t = pipe_get_transfer(ctx, samptex,
437                            0, 0, /* level, layer */
438                            PIPE_TRANSFER_READ,
439                            0, 0, SIZE, SIZE); /* x, y, width, height */
440
441      ptr = ctx->transfer_map(ctx, t);
442
443      if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
444         assert(0);
445         exit(9);
446      }
447
448      ctx->transfer_unmap(ctx, t);
449
450      ctx->transfer_destroy(ctx, t);
451   }
452
453   memset(&sv_template, 0, sizeof sv_template);
454   sv_template.format = samptex->format;
455   sv_template.texture = samptex;
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
487static void init( void )
488{
489   struct pipe_framebuffer_state fb;
490   struct pipe_resource templat;
491   struct pipe_surface surf_tmpl;
492   int i;
493
494   /* It's hard to say whether window or screen should be created
495    * first.  Different environments would prefer one or the other.
496    *
497    * Also, no easy way of querying supported formats if the screen
498    * cannot be created first.
499    */
500   for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
501      screen = graw_create_window_and_screen(0, 0, 300, 300,
502                                             formats[i],
503                                             &window);
504      if (window && screen)
505         break;
506   }
507   if (!screen || !window) {
508      fprintf(stderr, "Unable to create window\n");
509      exit(1);
510   }
511
512   ctx = screen->context_create(screen, NULL);
513   if (ctx == NULL)
514      exit(3);
515
516   templat.target = PIPE_TEXTURE_2D;
517   templat.format = formats[i];
518   templat.width0 = WIDTH;
519   templat.height0 = HEIGHT;
520   templat.depth0 = 1;
521   templat.array_size = 1;
522   templat.last_level = 0;
523   templat.nr_samples = 1;
524   templat.bind = (PIPE_BIND_RENDER_TARGET |
525                   PIPE_BIND_DISPLAY_TARGET);
526
527   rttex = screen->resource_create(screen,
528                                 &templat);
529   if (rttex == NULL)
530      exit(4);
531
532   surf_tmpl.format = templat.format;
533   surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
534   surf_tmpl.u.tex.level = 0;
535   surf_tmpl.u.tex.first_layer = 0;
536   surf_tmpl.u.tex.last_layer = 0;
537   surf = ctx->create_surface(ctx, rttex, &surf_tmpl);
538   if (surf == NULL)
539      exit(5);
540
541   memset(&fb, 0, sizeof fb);
542   fb.nr_cbufs = 1;
543   fb.width = WIDTH;
544   fb.height = HEIGHT;
545   fb.cbufs[0] = surf;
546
547   ctx->set_framebuffer_state(ctx, &fb);
548
549   {
550      struct pipe_blend_state blend;
551      void *handle;
552      memset(&blend, 0, sizeof blend);
553      blend.rt[0].colormask = PIPE_MASK_RGBA;
554      handle = ctx->create_blend_state(ctx, &blend);
555      ctx->bind_blend_state(ctx, handle);
556   }
557
558   {
559      struct pipe_depth_stencil_alpha_state depthstencil;
560      void *handle;
561      memset(&depthstencil, 0, sizeof depthstencil);
562      handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
563      ctx->bind_depth_stencil_alpha_state(ctx, handle);
564   }
565
566   {
567      struct pipe_rasterizer_state rasterizer;
568      void *handle;
569      memset(&rasterizer, 0, sizeof rasterizer);
570      rasterizer.cull_face = PIPE_FACE_NONE;
571      rasterizer.gl_rasterization_rules = 1;
572      rasterizer.depth_clip = 1;
573      handle = ctx->create_rasterizer_state(ctx, &rasterizer);
574      ctx->bind_rasterizer_state(ctx, handle);
575   }
576
577   set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
578
579   init_tex();
580   init_fs_constbuf();
581
582   set_vertices();
583   set_vertex_shader();
584   set_fragment_shader();
585   set_geometry_shader();
586}
587
588static void args(int argc, char *argv[])
589{
590   int i;
591
592   for (i = 1; i < argc;) {
593      if (graw_parse_args(&i, argc, argv)) {
594         continue;
595      }
596      if (strcmp(argv[i], "-fps") == 0) {
597         show_fps = 1;
598         i++;
599      }
600      else if (strcmp(argv[i], "-strip") == 0) {
601         draw_strip = 1;
602         i++;
603      }
604      else if (i == argc - 1) {
605         filename = argv[i];
606         i++;
607      }
608      else {
609         usage(argv[0]);
610         exit(1);
611      }
612   }
613
614   if (!filename) {
615      usage(argv[0]);
616      exit(1);
617   }
618}
619
620int main( int argc, char *argv[] )
621{
622   args(argc,argv);
623   init();
624
625   graw_set_display_func( draw );
626   graw_main_loop();
627   return 0;
628}
629