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 "frontend/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
153   memset(&templat, 0, sizeof(templat));
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.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      ctx->buffer_subdata(ctx, constbuf1,
172                          PIPE_MAP_WRITE,
173                          0, sizeof(constants1), constants1);
174
175      pipe_set_constant_buffer(ctx,
176                               PIPE_SHADER_GEOMETRY, 0,
177                               constbuf1);
178   }
179   {
180      ctx->buffer_subdata(ctx, constbuf2,
181                          PIPE_MAP_WRITE,
182                          0, sizeof(constants2), constants2);
183
184      pipe_set_constant_buffer(ctx,
185                               PIPE_SHADER_GEOMETRY, 1,
186                               constbuf2);
187   }
188}
189
190
191static void set_viewport( float x, float y,
192                          float width, float height,
193                          float zNear, float zFar)
194{
195   float z = zFar;
196   float half_width = (float)width / 2.0f;
197   float half_height = (float)height / 2.0f;
198   float half_depth = ((float)zFar - (float)zNear) / 2.0f;
199   struct pipe_viewport_state vp;
200
201   vp.scale[0] = half_width;
202   vp.scale[1] = half_height;
203   vp.scale[2] = half_depth;
204
205   vp.translate[0] = half_width + x;
206   vp.translate[1] = half_height + y;
207   vp.translate[2] = half_depth + z;
208
209   vp.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X;
210   vp.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y;
211   vp.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z;
212   vp.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W;
213
214   ctx->set_viewport_states( ctx, 0, 1, &vp );
215}
216
217static void set_vertices( void )
218{
219   struct pipe_vertex_element ve[4];
220   struct pipe_vertex_buffer vbuf;
221   void *handle;
222
223   memset(ve, 0, sizeof ve);
224
225   ve[0].src_offset = Offset(struct vertex, position);
226   ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
227   ve[1].src_offset = Offset(struct vertex, color);
228   ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
229   ve[2].src_offset = Offset(struct vertex, texcoord);
230   ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
231   ve[3].src_offset = Offset(struct vertex, generic);
232   ve[3].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
233
234   handle = ctx->create_vertex_elements_state(ctx, 4, ve);
235   ctx->bind_vertex_elements_state(ctx, handle);
236
237   memset(&vbuf, 0, sizeof vbuf);
238
239   vbuf.stride = sizeof( struct vertex );
240   vbuf.buffer_offset = 0;
241   if (draw_strip) {
242      vbuf.buffer.resource = pipe_buffer_create_with_data(ctx,
243                                                 PIPE_BIND_VERTEX_BUFFER,
244                                                 PIPE_USAGE_DEFAULT,
245                                                 sizeof(vertices_strip),
246                                                 vertices_strip);
247   } else {
248      vbuf.buffer.resource = pipe_buffer_create_with_data(ctx,
249                                                 PIPE_BIND_VERTEX_BUFFER,
250                                                 PIPE_USAGE_DEFAULT,
251                                                 sizeof(vertices),
252                                                 vertices);
253   }
254
255   ctx->set_vertex_buffers(ctx, 0, 1, 0, false, &vbuf);
256}
257
258static void set_vertex_shader( void )
259{
260   void *handle;
261   const char *text =
262      "VERT\n"
263      "DCL IN[0]\n"
264      "DCL IN[1]\n"
265      "DCL IN[2]\n"
266      "DCL IN[3]\n"
267      "DCL OUT[0], POSITION\n"
268      "DCL OUT[1], COLOR[0]\n"
269      "DCL OUT[2], GENERIC[0]\n"
270      "DCL OUT[3], GENERIC[1]\n"
271      "  MOV OUT[0], IN[0]\n"
272      "  MOV OUT[1], IN[1]\n"
273      "  MOV OUT[2], IN[2]\n"
274      "  MOV OUT[3], IN[3]\n"
275      "  END\n";
276
277   handle = graw_parse_vertex_shader(ctx, text);
278   ctx->bind_vs_state(ctx, handle);
279}
280
281static void set_fragment_shader( void )
282{
283   void *handle;
284   const char *text =
285      "FRAG\n"
286      "DCL IN[0], COLOR, LINEAR\n"
287      "DCL OUT[0], COLOR\n"
288      "  0: MOV OUT[0], IN[0]\n"
289      "  1: END\n";
290
291   handle = graw_parse_fragment_shader(ctx, text);
292   ctx->bind_fs_state(ctx, handle);
293}
294
295
296static void set_geometry_shader( void )
297{
298   FILE *f;
299   char buf[50000];
300   void *handle;
301   int sz;
302
303   if ((f = fopen(filename, "r")) == NULL) {
304      fprintf(stderr, "Couldn't open %s\n", filename);
305      exit(1);
306   }
307
308   sz = fread(buf, 1, sizeof(buf), f);
309   if (!feof(f)) {
310      printf("file too long\n");
311      exit(1);
312   }
313   printf("%.*s\n", sz, buf);
314   buf[sz] = 0;
315
316   handle = graw_parse_geometry_shader(ctx, buf);
317   ctx->bind_gs_state(ctx, handle);
318   fclose(f);
319}
320
321
322static void draw( void )
323{
324   union pipe_color_union clear_color = { {.1,.3,.5,0} };
325
326   ctx->clear(ctx, PIPE_CLEAR_COLOR, NULL, &clear_color, 0, 0);
327   if (draw_strip)
328      util_draw_arrays(ctx, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
329   else
330      util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
331
332   ctx->flush(ctx, NULL, 0);
333
334   graw_save_surface_to_file(ctx, surf, NULL);
335
336   screen->flush_frontbuffer(screen, ctx, rttex, 0, 0, window, NULL);
337}
338
339#define SIZE 16
340
341static void init_tex( void )
342{
343   struct pipe_sampler_view sv_template;
344   struct pipe_sampler_state sampler_desc;
345   struct pipe_resource templat;
346   struct pipe_box box;
347   ubyte tex2d[SIZE][SIZE][4];
348   int s, t;
349
350#if (SIZE != 2)
351   for (s = 0; s < SIZE; s++) {
352      for (t = 0; t < SIZE; t++) {
353         if (0) {
354            int x = (s ^ t) & 1;
355	    tex2d[t][s][0] = (x) ? 0 : 63;
356	    tex2d[t][s][1] = (x) ? 0 : 128;
357	    tex2d[t][s][2] = 0;
358	    tex2d[t][s][3] = 0xff;
359         }
360         else {
361            int x = ((s ^ t) >> 2) & 1;
362	    tex2d[t][s][0] = s*255/(SIZE-1);
363	    tex2d[t][s][1] = t*255/(SIZE-1);
364	    tex2d[t][s][2] = (x) ? 0 : 128;
365	    tex2d[t][s][3] = 0xff;
366         }
367      }
368   }
369#else
370   tex2d[0][0][0] = 0;
371   tex2d[0][0][1] = 255;
372   tex2d[0][0][2] = 255;
373   tex2d[0][0][3] = 0;
374
375   tex2d[0][1][0] = 0;
376   tex2d[0][1][1] = 0;
377   tex2d[0][1][2] = 255;
378   tex2d[0][1][3] = 255;
379
380   tex2d[1][0][0] = 255;
381   tex2d[1][0][1] = 255;
382   tex2d[1][0][2] = 0;
383   tex2d[1][0][3] = 255;
384
385   tex2d[1][1][0] = 255;
386   tex2d[1][1][1] = 0;
387   tex2d[1][1][2] = 0;
388   tex2d[1][1][3] = 255;
389#endif
390
391   memset(&templat, 0, sizeof(templat));
392   templat.target = PIPE_TEXTURE_2D;
393   templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
394   templat.width0 = SIZE;
395   templat.height0 = SIZE;
396   templat.depth0 = 1;
397   templat.array_size = 1;
398   templat.last_level = 0;
399   templat.bind = PIPE_BIND_SAMPLER_VIEW;
400
401
402   samptex = screen->resource_create(screen,
403                                 &templat);
404   if (samptex == NULL)
405      exit(4);
406
407   u_box_2d(0,0,SIZE,SIZE, &box);
408
409   ctx->texture_subdata(ctx,
410                        samptex,
411                        0,
412                        PIPE_MAP_WRITE,
413                        &box,
414                        tex2d,
415                        sizeof tex2d[0],
416         sizeof tex2d);
417
418   /* Possibly read back & compare against original data:
419    */
420   if (0)
421   {
422      struct pipe_transfer *t;
423      uint32_t *ptr;
424      ptr = pipe_texture_map(ctx, samptex,
425                              0, 0, /* level, layer */
426                              PIPE_MAP_READ,
427                              0, 0, SIZE, SIZE, &t); /* x, y, width, height */
428
429      if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
430         assert(0);
431         exit(9);
432      }
433
434      ctx->texture_unmap(ctx, t);
435   }
436
437   memset(&sv_template, 0, sizeof sv_template);
438   sv_template.format = samptex->format;
439   sv_template.texture = samptex;
440   sv_template.swizzle_r = 0;
441   sv_template.swizzle_g = 1;
442   sv_template.swizzle_b = 2;
443   sv_template.swizzle_a = 3;
444   sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
445   if (sv == NULL)
446      exit(5);
447
448   ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &sv);
449
450
451   memset(&sampler_desc, 0, sizeof sampler_desc);
452   sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
453   sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
454   sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
455   sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
456   sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
457   sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
458   sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
459   sampler_desc.compare_func = 0;
460   sampler_desc.normalized_coords = 1;
461   sampler_desc.max_anisotropy = 0;
462
463   sampler = ctx->create_sampler_state(ctx, &sampler_desc);
464   if (sampler == NULL)
465      exit(6);
466
467   ctx->bind_sampler_states(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler);
468
469}
470
471static void init( void )
472{
473   struct pipe_framebuffer_state fb;
474   struct pipe_resource templat;
475   struct pipe_surface surf_tmpl;
476   int i;
477
478   /* It's hard to say whether window or screen should be created
479    * first.  Different environments would prefer one or the other.
480    *
481    * Also, no easy way of querying supported formats if the screen
482    * cannot be created first.
483    */
484   for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
485      screen = graw_create_window_and_screen(0, 0, 300, 300,
486                                             formats[i],
487                                             &window);
488      if (window && screen)
489         break;
490   }
491   if (!screen || !window) {
492      fprintf(stderr, "Unable to create window\n");
493      exit(1);
494   }
495
496   ctx = screen->context_create(screen, NULL, 0);
497   if (ctx == NULL)
498      exit(3);
499
500   memset(&templat, 0, sizeof(templat));
501   templat.target = PIPE_TEXTURE_2D;
502   templat.format = formats[i];
503   templat.width0 = WIDTH;
504   templat.height0 = HEIGHT;
505   templat.depth0 = 1;
506   templat.array_size = 1;
507   templat.last_level = 0;
508   templat.bind = (PIPE_BIND_RENDER_TARGET |
509                   PIPE_BIND_DISPLAY_TARGET);
510
511   rttex = screen->resource_create(screen,
512                                 &templat);
513   if (rttex == NULL)
514      exit(4);
515
516   surf_tmpl.format = templat.format;
517   surf_tmpl.u.tex.level = 0;
518   surf_tmpl.u.tex.first_layer = 0;
519   surf_tmpl.u.tex.last_layer = 0;
520   surf = ctx->create_surface(ctx, rttex, &surf_tmpl);
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.half_pixel_center = 1;
555      rasterizer.bottom_edge_rule = 1;
556      rasterizer.depth_clip_near = 1;
557      rasterizer.depth_clip_far = 1;
558      handle = ctx->create_rasterizer_state(ctx, &rasterizer);
559      ctx->bind_rasterizer_state(ctx, handle);
560   }
561
562   set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
563
564   init_tex();
565   init_fs_constbuf();
566
567   set_vertices();
568   set_vertex_shader();
569   set_fragment_shader();
570   set_geometry_shader();
571}
572
573static void args(int argc, char *argv[])
574{
575   int i;
576
577   for (i = 1; i < argc;) {
578      if (graw_parse_args(&i, argc, argv)) {
579         continue;
580      }
581      if (strcmp(argv[i], "-fps") == 0) {
582         show_fps = 1;
583         i++;
584      }
585      else if (strcmp(argv[i], "-strip") == 0) {
586         draw_strip = 1;
587         i++;
588      }
589      else if (i == argc - 1) {
590         filename = argv[i];
591         i++;
592      }
593      else {
594         usage(argv[0]);
595         exit(1);
596      }
597   }
598
599   if (!filename) {
600      usage(argv[0]);
601      exit(1);
602   }
603}
604
605int main( int argc, char *argv[] )
606{
607   args(argc,argv);
608   init();
609
610   graw_set_display_func( draw );
611   graw_main_loop();
612   return 0;
613}
614