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;
20
21
22static void usage(char *name)
23{
24   fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
25#ifndef _WIN32
26   fprintf(stderr, "\n" );
27   fprintf(stderr, "options:\n");
28   fprintf(stderr, "    -fps  show frames per second\n");
29#endif
30}
31
32
33enum pipe_format formats[] = {
34   PIPE_FORMAT_RGBA8888_UNORM,
35   PIPE_FORMAT_BGRA8888_UNORM,
36   PIPE_FORMAT_NONE
37};
38
39static const int WIDTH = 250;
40static const int HEIGHT = 250;
41
42static struct pipe_screen *screen = NULL;
43static struct pipe_context *ctx = NULL;
44static struct pipe_resource *rttex = NULL;
45static struct pipe_surface *surf = NULL;
46static struct pipe_sampler_view *sv = NULL;
47static void *sampler = NULL;
48static void *window = NULL;
49static struct pipe_resource *samptex = NULL;
50
51struct vertex {
52   float position[4];
53   float color[4];
54   float texcoord[4];
55};
56
57/* Vertex data matches progs/fp/fp-tri.c, but flipped in Y dimension
58 * so that the final images are the same.
59 */
60static struct vertex vertices[] =
61{
62   { { 0.9, 0.9, 0.0, 1.0 },
63     { 0, 0, 1, 1 },
64     { 1, 1, 0, 1 } },
65
66   { { 0.9,  -0.9, 0.0, 1.0 },
67     { 1, 0, 0, 1 },
68     { 1, -1, 0, 1 } },
69
70   { {-0.9,  0.0, 0.0, 1.0 },
71     { 0, 1, 0, 1 },
72     { -1, 0, 0, 1 } },
73};
74
75static float constants1[] =
76{  0.4, 0, 0,  1,
77   1,   1, 1,  1,
78   2,   2, 2,  2,
79   4,   8, 16, 32,
80
81   3,  0, 0, 0,
82   0, .5, 0, 0,
83   1,  0, 0, 1,
84   0,  0, 0, 1,
85
86   1, 0, 0, 0.5,
87   0, 1, 0, 0.5,
88   0, 0, 1, 0,
89   0, 0, 0, 1,
90};
91
92
93static float constants2[] =
94{  1, 0, 0,  1,
95   0, 1, 0,  1,
96   0, 0, 1,  1,
97   0, 0, 0,  0,
98
99   1,  1, 0, 1,
100   1, .5, 0, 1,
101   1,  0, 0, 1,
102   0,  0, 0, 1,
103
104   1, 0, 0, 0.5,
105   0, 1, 0, 0.5,
106   0, 0, 1, 0,
107   0, 0, 0, 1,
108};
109
110static void init_fs_constbuf( void )
111{
112   struct pipe_constant_buffer cb1;
113   struct pipe_constant_buffer cb2;
114
115   memset(&cb1, 0, sizeof cb1);
116   cb1.buffer_size = sizeof constants1;
117   cb1.user_buffer = constants1;
118
119   ctx->set_constant_buffer(ctx,
120                            PIPE_SHADER_FRAGMENT, 0,
121                            &cb1);
122
123   memset(&cb2, 0, sizeof cb2);
124   cb2.buffer_size = sizeof constants2;
125   cb2.user_buffer = constants2;
126
127   ctx->set_constant_buffer(ctx,
128                            PIPE_SHADER_FRAGMENT, 1,
129                            &cb2);
130}
131
132
133static void set_viewport( float x, float y,
134                          float width, float height,
135                          float zNear, float zFar)
136{
137   float z = zFar;
138   float half_width = (float)width / 2.0f;
139   float half_height = (float)height / 2.0f;
140   float half_depth = ((float)zFar - (float)zNear) / 2.0f;
141   struct pipe_viewport_state vp;
142
143   vp.scale[0] = half_width;
144   vp.scale[1] = half_height;
145   vp.scale[2] = half_depth;
146
147   vp.translate[0] = half_width + x;
148   vp.translate[1] = half_height + y;
149   vp.translate[2] = half_depth + z;
150
151   ctx->set_viewport_states( ctx, 0, 1, &vp );
152}
153
154static void set_vertices( void )
155{
156   struct pipe_vertex_element ve[3];
157   struct pipe_vertex_buffer vbuf;
158   void *handle;
159
160   memset(ve, 0, sizeof ve);
161
162   ve[0].src_offset = Offset(struct vertex, position);
163   ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
164   ve[1].src_offset = Offset(struct vertex, color);
165   ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
166   ve[2].src_offset = Offset(struct vertex, texcoord);
167   ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
168
169   handle = ctx->create_vertex_elements_state(ctx, 3, ve);
170   ctx->bind_vertex_elements_state(ctx, handle);
171
172   memset(&vbuf, 0, sizeof vbuf);
173
174   vbuf.stride = sizeof( struct vertex );
175   vbuf.buffer_offset = 0;
176   vbuf.buffer.resource = pipe_buffer_create_with_data(ctx,
177                                              PIPE_BIND_VERTEX_BUFFER,
178                                              PIPE_USAGE_DEFAULT,
179                                              sizeof(vertices),
180                                              vertices);
181
182   ctx->set_vertex_buffers(ctx, 0, 1, &vbuf);
183}
184
185static void set_vertex_shader( void )
186{
187   void *handle;
188   const char *text =
189      "VERT\n"
190      "DCL IN[0]\n"
191      "DCL IN[1]\n"
192      "DCL IN[2]\n"
193      "DCL OUT[0], POSITION\n"
194      "DCL OUT[1], COLOR[0]\n"
195      "DCL OUT[2], GENERIC[0]\n"
196      "  MOV OUT[0], IN[0]\n"
197      "  MOV OUT[1], IN[1]\n"
198      "  MOV OUT[2], IN[2]\n"
199      "  END\n";
200
201   handle = graw_parse_vertex_shader(ctx, text);
202   ctx->bind_vs_state(ctx, handle);
203}
204
205static void set_fragment_shader( const char *filename )
206{
207   FILE *f;
208   char buf[50000];
209   void *handle;
210   int sz;
211
212   if ((f = fopen(filename, "r")) == NULL) {
213      fprintf(stderr, "Couldn't open %s\n", filename);
214      exit(1);
215   }
216
217   sz = fread(buf, 1, sizeof(buf), f);
218   if (!feof(f)) {
219      printf("file too long\n");
220      exit(1);
221   }
222   printf("%.*s\n", sz, buf);
223   buf[sz] = 0;
224
225   handle = graw_parse_fragment_shader(ctx, buf);
226   ctx->bind_fs_state(ctx, handle);
227   fclose(f);
228}
229
230
231static void draw( void )
232{
233   union pipe_color_union clear_color = { {.1,.3,.5,0} };
234
235   ctx->clear(ctx, PIPE_CLEAR_COLOR, &clear_color, 0, 0);
236   util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
237   ctx->flush(ctx, NULL, 0);
238
239   graw_save_surface_to_file(ctx, surf, NULL);
240
241   screen->flush_frontbuffer(screen, rttex, 0, 0, window, NULL);
242}
243
244#define SIZE 16
245
246static void init_tex( void )
247{
248   struct pipe_sampler_view sv_template;
249   struct pipe_sampler_state sampler_desc;
250   struct pipe_resource templat;
251   struct pipe_box box;
252   ubyte tex2d[SIZE][SIZE][4];
253   int s, t;
254
255#if (SIZE != 2)
256   for (s = 0; s < SIZE; s++) {
257      for (t = 0; t < SIZE; t++) {
258         if (0) {
259            int x = (s ^ t) & 1;
260	    tex2d[t][s][0] = (x) ? 0 : 63;
261	    tex2d[t][s][1] = (x) ? 0 : 128;
262	    tex2d[t][s][2] = 0;
263	    tex2d[t][s][3] = 0xff;
264         }
265         else {
266            int x = ((s ^ t) >> 2) & 1;
267	    tex2d[t][s][0] = s*255/(SIZE-1);
268	    tex2d[t][s][1] = t*255/(SIZE-1);
269	    tex2d[t][s][2] = (x) ? 0 : 128;
270	    tex2d[t][s][3] = 0xff;
271         }
272      }
273   }
274#else
275   tex2d[0][0][0] = 0;
276   tex2d[0][0][1] = 255;
277   tex2d[0][0][2] = 255;
278   tex2d[0][0][3] = 0;
279
280   tex2d[0][1][0] = 0;
281   tex2d[0][1][1] = 0;
282   tex2d[0][1][2] = 255;
283   tex2d[0][1][3] = 255;
284
285   tex2d[1][0][0] = 255;
286   tex2d[1][0][1] = 255;
287   tex2d[1][0][2] = 0;
288   tex2d[1][0][3] = 255;
289
290   tex2d[1][1][0] = 255;
291   tex2d[1][1][1] = 0;
292   tex2d[1][1][2] = 0;
293   tex2d[1][1][3] = 255;
294#endif
295
296   memset(&templat, 0, sizeof(templat));
297   templat.target = PIPE_TEXTURE_2D;
298   templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
299   templat.width0 = SIZE;
300   templat.height0 = SIZE;
301   templat.depth0 = 1;
302   templat.array_size = 1;
303   templat.last_level = 0;
304   templat.bind = PIPE_BIND_SAMPLER_VIEW;
305
306
307   samptex = screen->resource_create(screen,
308                                 &templat);
309   if (samptex == NULL)
310      exit(4);
311
312   u_box_2d(0,0,SIZE,SIZE, &box);
313
314   ctx->texture_subdata(ctx,
315                        samptex,
316                        0,
317                        PIPE_TRANSFER_WRITE,
318                        &box,
319                        tex2d,
320                        sizeof tex2d[0],
321                        sizeof tex2d);
322
323   /* Possibly read back & compare against original data:
324    */
325   if (0)
326   {
327      struct pipe_transfer *t;
328      uint32_t *ptr;
329      ptr = pipe_transfer_map(ctx, samptex,
330                              0, 0, /* level, layer */
331                              PIPE_TRANSFER_READ,
332                              0, 0, SIZE, SIZE, &t); /* x, y, width, height */
333
334      if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
335         assert(0);
336         exit(9);
337      }
338
339      ctx->transfer_unmap(ctx, t);
340   }
341
342   memset(&sv_template, 0, sizeof sv_template);
343   sv_template.format = samptex->format;
344   sv_template.texture = samptex;
345   sv_template.swizzle_r = 0;
346   sv_template.swizzle_g = 1;
347   sv_template.swizzle_b = 2;
348   sv_template.swizzle_a = 3;
349   sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
350   if (sv == NULL)
351      exit(5);
352
353   ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &sv);
354
355
356   memset(&sampler_desc, 0, sizeof sampler_desc);
357   sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
358   sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
359   sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
360   sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
361   sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
362   sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
363   sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
364   sampler_desc.compare_func = 0;
365   sampler_desc.normalized_coords = 1;
366   sampler_desc.max_anisotropy = 0;
367
368   sampler = ctx->create_sampler_state(ctx, &sampler_desc);
369   if (sampler == NULL)
370      exit(6);
371
372   ctx->bind_sampler_states(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler);
373
374}
375
376static void init( void )
377{
378   struct pipe_framebuffer_state fb;
379   struct pipe_resource templat;
380   struct pipe_surface surf_tmpl;
381   int i;
382
383   /* It's hard to say whether window or screen should be created
384    * first.  Different environments would prefer one or the other.
385    *
386    * Also, no easy way of querying supported formats if the screen
387    * cannot be created first.
388    */
389   for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
390      screen = graw_create_window_and_screen(0, 0, 300, 300,
391                                             formats[i],
392                                             &window);
393      if (window && screen)
394         break;
395   }
396   if (!screen || !window) {
397      fprintf(stderr, "Unable to create window\n");
398      exit(1);
399   }
400
401   ctx = screen->context_create(screen, NULL, 0);
402   if (ctx == NULL)
403      exit(3);
404
405   memset(&templat, 0, sizeof(templat));
406   templat.target = PIPE_TEXTURE_2D;
407   templat.format = formats[i];
408   templat.width0 = WIDTH;
409   templat.height0 = HEIGHT;
410   templat.depth0 = 1;
411   templat.array_size = 1;
412   templat.last_level = 0;
413   templat.bind = (PIPE_BIND_RENDER_TARGET |
414                   PIPE_BIND_DISPLAY_TARGET);
415
416   rttex = screen->resource_create(screen,
417                                 &templat);
418   if (rttex == NULL)
419      exit(4);
420
421   surf_tmpl.format = templat.format;
422   surf_tmpl.u.tex.level = 0;
423   surf_tmpl.u.tex.first_layer = 0;
424   surf_tmpl.u.tex.last_layer = 0;
425   surf = ctx->create_surface(ctx, rttex, &surf_tmpl);
426   if (surf == NULL)
427      exit(5);
428
429   memset(&fb, 0, sizeof fb);
430   fb.nr_cbufs = 1;
431   fb.width = WIDTH;
432   fb.height = HEIGHT;
433   fb.cbufs[0] = surf;
434
435   ctx->set_framebuffer_state(ctx, &fb);
436
437   {
438      struct pipe_blend_state blend;
439      void *handle;
440      memset(&blend, 0, sizeof blend);
441      blend.rt[0].colormask = PIPE_MASK_RGBA;
442      handle = ctx->create_blend_state(ctx, &blend);
443      ctx->bind_blend_state(ctx, handle);
444   }
445
446   {
447      struct pipe_depth_stencil_alpha_state depthstencil;
448      void *handle;
449      memset(&depthstencil, 0, sizeof depthstencil);
450      handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
451      ctx->bind_depth_stencil_alpha_state(ctx, handle);
452   }
453
454   {
455      struct pipe_rasterizer_state rasterizer;
456      void *handle;
457      memset(&rasterizer, 0, sizeof rasterizer);
458      rasterizer.cull_face = PIPE_FACE_NONE;
459      rasterizer.half_pixel_center = 1;
460      rasterizer.bottom_edge_rule = 1;
461      rasterizer.depth_clip_near = 1;
462      rasterizer.depth_clip_far = 1;
463      handle = ctx->create_rasterizer_state(ctx, &rasterizer);
464      ctx->bind_rasterizer_state(ctx, handle);
465   }
466
467   set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
468
469   init_tex();
470   init_fs_constbuf();
471
472   set_vertices();
473   set_vertex_shader();
474   set_fragment_shader(filename);
475}
476
477static void args(int argc, char *argv[])
478{
479   int i;
480
481   for (i = 1; i < argc;) {
482      if (graw_parse_args(&i, argc, argv)) {
483         continue;
484      }
485      if (strcmp(argv[i], "-fps") == 0) {
486         show_fps = 1;
487         i++;
488      }
489      else if (i == argc - 1) {
490         filename = argv[i];
491         i++;
492      }
493      else {
494         usage(argv[0]);
495         exit(1);
496      }
497   }
498
499   if (!filename) {
500      usage(argv[0]);
501      exit(1);
502   }
503}
504
505int main( int argc, char *argv[] )
506{
507   args(argc,argv);
508   init();
509
510   graw_set_display_func( draw );
511   graw_main_loop();
512   return 0;
513}
514