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