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