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