f31034406f619dcf890cd4d5bfc99a6d50550ff8
[mesa.git] / src / gallium / tests / graw / fs-test.c
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
18 static const char *filename = NULL;
19 unsigned show_fps = 0;
20
21
22 static 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
33 enum pipe_format formats[] = {
34 PIPE_FORMAT_R8G8B8A8_UNORM,
35 PIPE_FORMAT_B8G8R8A8_UNORM,
36 PIPE_FORMAT_NONE
37 };
38
39 static const int WIDTH = 250;
40 static const int HEIGHT = 250;
41
42 static struct pipe_screen *screen = NULL;
43 static struct pipe_context *ctx = NULL;
44 static struct pipe_resource *rttex = NULL;
45 static struct pipe_resource *constbuf1 = NULL;
46 static struct pipe_resource *constbuf2 = NULL;
47 static struct pipe_surface *surf = NULL;
48 static struct pipe_sampler_view *sv = NULL;
49 static void *sampler = NULL;
50 static void *window = NULL;
51 static struct pipe_resource *samptex = NULL;
52
53 struct 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 */
62 static 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
77 static 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
95 static 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
112 static 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
175 static 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
198 static 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 memset(&vbuf, 0, sizeof vbuf);
217
218 vbuf.stride = sizeof( struct vertex );
219 vbuf.buffer_offset = 0;
220 vbuf.buffer = pipe_buffer_create_with_data(ctx,
221 PIPE_BIND_VERTEX_BUFFER,
222 PIPE_USAGE_STATIC,
223 sizeof(vertices),
224 vertices);
225
226 ctx->set_vertex_buffers(ctx, 1, &vbuf);
227 }
228
229 static void set_vertex_shader( void )
230 {
231 void *handle;
232 const char *text =
233 "VERT\n"
234 "DCL IN[0]\n"
235 "DCL IN[1]\n"
236 "DCL IN[2]\n"
237 "DCL OUT[0], POSITION\n"
238 "DCL OUT[1], COLOR[0]\n"
239 "DCL OUT[2], GENERIC[0]\n"
240 " MOV OUT[0], IN[0]\n"
241 " MOV OUT[1], IN[1]\n"
242 " MOV OUT[2], IN[2]\n"
243 " END\n";
244
245 handle = graw_parse_vertex_shader(ctx, text);
246 ctx->bind_vs_state(ctx, handle);
247 }
248
249 static void set_fragment_shader( const char *filename )
250 {
251 FILE *f;
252 char buf[50000];
253 void *handle;
254 int sz;
255
256 if ((f = fopen(filename, "r")) == NULL) {
257 fprintf(stderr, "Couldn't open %s\n", filename);
258 exit(1);
259 }
260
261 sz = fread(buf, 1, sizeof(buf), f);
262 if (!feof(f)) {
263 printf("file too long\n");
264 exit(1);
265 }
266 printf("%.*s\n", sz, buf);
267 buf[sz] = 0;
268
269 handle = graw_parse_fragment_shader(ctx, buf);
270 ctx->bind_fs_state(ctx, handle);
271 fclose(f);
272 }
273
274
275 static void draw( void )
276 {
277 union pipe_color_union clear_color = { {.1,.3,.5,0} };
278
279 ctx->clear(ctx, PIPE_CLEAR_COLOR, &clear_color, 0, 0);
280 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
281 ctx->flush(ctx, NULL);
282
283 graw_save_surface_to_file(ctx, surf, NULL);
284
285 screen->flush_frontbuffer(screen, rttex, 0, 0, window);
286 }
287
288 #define SIZE 16
289
290 static void init_tex( void )
291 {
292 struct pipe_sampler_view sv_template;
293 struct pipe_sampler_state sampler_desc;
294 struct pipe_resource templat;
295 struct pipe_box box;
296 ubyte tex2d[SIZE][SIZE][4];
297 int s, t;
298
299 #if (SIZE != 2)
300 for (s = 0; s < SIZE; s++) {
301 for (t = 0; t < SIZE; t++) {
302 if (0) {
303 int x = (s ^ t) & 1;
304 tex2d[t][s][0] = (x) ? 0 : 63;
305 tex2d[t][s][1] = (x) ? 0 : 128;
306 tex2d[t][s][2] = 0;
307 tex2d[t][s][3] = 0xff;
308 }
309 else {
310 int x = ((s ^ t) >> 2) & 1;
311 tex2d[t][s][0] = s*255/(SIZE-1);
312 tex2d[t][s][1] = t*255/(SIZE-1);
313 tex2d[t][s][2] = (x) ? 0 : 128;
314 tex2d[t][s][3] = 0xff;
315 }
316 }
317 }
318 #else
319 tex2d[0][0][0] = 0;
320 tex2d[0][0][1] = 255;
321 tex2d[0][0][2] = 255;
322 tex2d[0][0][3] = 0;
323
324 tex2d[0][1][0] = 0;
325 tex2d[0][1][1] = 0;
326 tex2d[0][1][2] = 255;
327 tex2d[0][1][3] = 255;
328
329 tex2d[1][0][0] = 255;
330 tex2d[1][0][1] = 255;
331 tex2d[1][0][2] = 0;
332 tex2d[1][0][3] = 255;
333
334 tex2d[1][1][0] = 255;
335 tex2d[1][1][1] = 0;
336 tex2d[1][1][2] = 0;
337 tex2d[1][1][3] = 255;
338 #endif
339
340 templat.target = PIPE_TEXTURE_2D;
341 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
342 templat.width0 = SIZE;
343 templat.height0 = SIZE;
344 templat.depth0 = 1;
345 templat.array_size = 1;
346 templat.last_level = 0;
347 templat.nr_samples = 1;
348 templat.bind = PIPE_BIND_SAMPLER_VIEW;
349
350
351 samptex = screen->resource_create(screen,
352 &templat);
353 if (samptex == NULL)
354 exit(4);
355
356 u_box_2d(0,0,SIZE,SIZE, &box);
357
358 ctx->transfer_inline_write(ctx,
359 samptex,
360 0,
361 PIPE_TRANSFER_WRITE,
362 &box,
363 tex2d,
364 sizeof tex2d[0],
365 sizeof tex2d);
366
367 /* Possibly read back & compare against original data:
368 */
369 if (0)
370 {
371 struct pipe_transfer *t;
372 uint32_t *ptr;
373 ptr = pipe_transfer_map(ctx, samptex,
374 0, 0, /* level, layer */
375 PIPE_TRANSFER_READ,
376 0, 0, SIZE, SIZE, &t); /* x, y, width, height */
377
378 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
379 assert(0);
380 exit(9);
381 }
382
383 ctx->transfer_unmap(ctx, t);
384 }
385
386 memset(&sv_template, 0, sizeof sv_template);
387 sv_template.format = samptex->format;
388 sv_template.texture = samptex;
389 sv_template.swizzle_r = 0;
390 sv_template.swizzle_g = 1;
391 sv_template.swizzle_b = 2;
392 sv_template.swizzle_a = 3;
393 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
394 if (sv == NULL)
395 exit(5);
396
397 ctx->set_fragment_sampler_views(ctx, 1, &sv);
398
399
400 memset(&sampler_desc, 0, sizeof sampler_desc);
401 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
402 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
403 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
404 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
405 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
406 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
407 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
408 sampler_desc.compare_func = 0;
409 sampler_desc.normalized_coords = 1;
410 sampler_desc.max_anisotropy = 0;
411
412 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
413 if (sampler == NULL)
414 exit(6);
415
416 ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
417
418 }
419
420 static void init( void )
421 {
422 struct pipe_framebuffer_state fb;
423 struct pipe_resource templat;
424 struct pipe_surface surf_tmpl;
425 int i;
426
427 /* It's hard to say whether window or screen should be created
428 * first. Different environments would prefer one or the other.
429 *
430 * Also, no easy way of querying supported formats if the screen
431 * cannot be created first.
432 */
433 for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) {
434 screen = graw_create_window_and_screen(0, 0, 300, 300,
435 formats[i],
436 &window);
437 if (window && screen)
438 break;
439 }
440 if (!screen || !window) {
441 fprintf(stderr, "Unable to create window\n");
442 exit(1);
443 }
444
445 ctx = screen->context_create(screen, NULL);
446 if (ctx == NULL)
447 exit(3);
448
449 templat.target = PIPE_TEXTURE_2D;
450 templat.format = formats[i];
451 templat.width0 = WIDTH;
452 templat.height0 = HEIGHT;
453 templat.depth0 = 1;
454 templat.array_size = 1;
455 templat.last_level = 0;
456 templat.nr_samples = 1;
457 templat.bind = (PIPE_BIND_RENDER_TARGET |
458 PIPE_BIND_DISPLAY_TARGET);
459
460 rttex = screen->resource_create(screen,
461 &templat);
462 if (rttex == NULL)
463 exit(4);
464
465 surf_tmpl.format = templat.format;
466 surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
467 surf_tmpl.u.tex.level = 0;
468 surf_tmpl.u.tex.first_layer = 0;
469 surf_tmpl.u.tex.last_layer = 0;
470 surf = ctx->create_surface(ctx, rttex, &surf_tmpl);
471 if (surf == NULL)
472 exit(5);
473
474 memset(&fb, 0, sizeof fb);
475 fb.nr_cbufs = 1;
476 fb.width = WIDTH;
477 fb.height = HEIGHT;
478 fb.cbufs[0] = surf;
479
480 ctx->set_framebuffer_state(ctx, &fb);
481
482 {
483 struct pipe_blend_state blend;
484 void *handle;
485 memset(&blend, 0, sizeof blend);
486 blend.rt[0].colormask = PIPE_MASK_RGBA;
487 handle = ctx->create_blend_state(ctx, &blend);
488 ctx->bind_blend_state(ctx, handle);
489 }
490
491 {
492 struct pipe_depth_stencil_alpha_state depthstencil;
493 void *handle;
494 memset(&depthstencil, 0, sizeof depthstencil);
495 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
496 ctx->bind_depth_stencil_alpha_state(ctx, handle);
497 }
498
499 {
500 struct pipe_rasterizer_state rasterizer;
501 void *handle;
502 memset(&rasterizer, 0, sizeof rasterizer);
503 rasterizer.cull_face = PIPE_FACE_NONE;
504 rasterizer.gl_rasterization_rules = 1;
505 rasterizer.depth_clip = 1;
506 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
507 ctx->bind_rasterizer_state(ctx, handle);
508 }
509
510 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
511
512 init_tex();
513 init_fs_constbuf();
514
515 set_vertices();
516 set_vertex_shader();
517 set_fragment_shader(filename);
518 }
519
520 static void args(int argc, char *argv[])
521 {
522 int i;
523
524 for (i = 1; i < argc;) {
525 if (graw_parse_args(&i, argc, argv)) {
526 continue;
527 }
528 if (strcmp(argv[i], "-fps") == 0) {
529 show_fps = 1;
530 i++;
531 }
532 else if (i == argc - 1) {
533 filename = argv[i];
534 i++;
535 }
536 else {
537 usage(argv[0]);
538 exit(1);
539 }
540 }
541
542 if (!filename) {
543 usage(argv[0]);
544 exit(1);
545 }
546 }
547
548 int main( int argc, char *argv[] )
549 {
550 args(argc,argv);
551 init();
552
553 graw_set_display_func( draw );
554 graw_main_loop();
555 return 0;
556 }