graw: Export graw_save_surface_to_file().
[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.last_level = 0;
123 templat.nr_samples = 1;
124 templat.bind = PIPE_BIND_CONSTANT_BUFFER;
125
126 constbuf1 = screen->resource_create(screen,
127 &templat);
128 if (constbuf1 == NULL)
129 exit(4);
130
131 constbuf2 = screen->resource_create(screen,
132 &templat);
133 if (constbuf2 == NULL)
134 exit(4);
135
136
137 {
138 u_box_2d(0,0,sizeof(constants1),1, &box);
139
140 ctx->transfer_inline_write(ctx,
141 constbuf1,
142 u_subresource(0,0),
143 PIPE_TRANSFER_WRITE,
144 &box,
145 constants1,
146 sizeof constants1,
147 sizeof constants1);
148
149
150 ctx->set_constant_buffer(ctx,
151 PIPE_SHADER_FRAGMENT, 0,
152 constbuf1);
153 }
154 {
155 u_box_2d(0,0,sizeof(constants2),1, &box);
156
157 ctx->transfer_inline_write(ctx,
158 constbuf2,
159 u_subresource(0,0),
160 PIPE_TRANSFER_WRITE,
161 &box,
162 constants2,
163 sizeof constants2,
164 sizeof constants2);
165
166
167 ctx->set_constant_buffer(ctx,
168 PIPE_SHADER_FRAGMENT, 1,
169 constbuf2);
170 }
171 }
172
173
174 static void set_viewport( float x, float y,
175 float width, float height,
176 float near, float far)
177 {
178 float z = far;
179 float half_width = (float)width / 2.0f;
180 float half_height = (float)height / 2.0f;
181 float half_depth = ((float)far - (float)near) / 2.0f;
182 struct pipe_viewport_state vp;
183
184 vp.scale[0] = half_width;
185 vp.scale[1] = half_height;
186 vp.scale[2] = half_depth;
187 vp.scale[3] = 1.0f;
188
189 vp.translate[0] = half_width + x;
190 vp.translate[1] = half_height + y;
191 vp.translate[2] = half_depth + z;
192 vp.translate[3] = 0.0f;
193
194 ctx->set_viewport_state( ctx, &vp );
195 }
196
197 static void set_vertices( void )
198 {
199 struct pipe_vertex_element ve[3];
200 struct pipe_vertex_buffer vbuf;
201 void *handle;
202
203 memset(ve, 0, sizeof ve);
204
205 ve[0].src_offset = Offset(struct vertex, position);
206 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
207 ve[1].src_offset = Offset(struct vertex, color);
208 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
209 ve[2].src_offset = Offset(struct vertex, texcoord);
210 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
211
212 handle = ctx->create_vertex_elements_state(ctx, 3, ve);
213 ctx->bind_vertex_elements_state(ctx, handle);
214
215
216 vbuf.stride = sizeof( struct vertex );
217 vbuf.max_index = sizeof(vertices) / vbuf.stride;
218 vbuf.buffer_offset = 0;
219 vbuf.buffer = screen->user_buffer_create(screen,
220 vertices,
221 sizeof(vertices),
222 PIPE_BIND_VERTEX_BUFFER);
223
224 ctx->set_vertex_buffers(ctx, 1, &vbuf);
225 }
226
227 static void set_vertex_shader( void )
228 {
229 void *handle;
230 const char *text =
231 "VERT\n"
232 "DCL IN[0]\n"
233 "DCL IN[1]\n"
234 "DCL IN[2]\n"
235 "DCL OUT[0], POSITION\n"
236 "DCL OUT[1], COLOR[0]\n"
237 "DCL OUT[2], GENERIC[0]\n"
238 " MOV OUT[0], IN[0]\n"
239 " MOV OUT[1], IN[1]\n"
240 " MOV OUT[2], IN[2]\n"
241 " END\n";
242
243 handle = graw_parse_vertex_shader(ctx, text);
244 ctx->bind_vs_state(ctx, handle);
245 }
246
247 static void set_fragment_shader( const char *filename )
248 {
249 FILE *f;
250 char buf[50000];
251 void *handle;
252 int sz;
253
254 if ((f = fopen(filename, "r")) == NULL) {
255 fprintf(stderr, "Couldn't open %s\n", filename);
256 exit(1);
257 }
258
259 sz = fread(buf, 1, sizeof(buf), f);
260 if (!feof(f)) {
261 printf("file too long\n");
262 exit(1);
263 }
264 printf("%.*s\n", sz, buf);
265 buf[sz] = 0;
266
267 handle = graw_parse_fragment_shader(ctx, buf);
268 ctx->bind_fs_state(ctx, handle);
269 fclose(f);
270 }
271
272
273 static void draw( void )
274 {
275 float clear_color[4] = {.1,.3,.5,0};
276
277 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
278 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
279 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
280
281 graw_save_surface_to_file(ctx, surf, NULL);
282
283 screen->flush_frontbuffer(screen, surf, window);
284 }
285
286 #define SIZE 16
287
288 static void init_tex( void )
289 {
290 struct pipe_sampler_view sv_template;
291 struct pipe_sampler_state sampler_desc;
292 struct pipe_resource templat;
293 struct pipe_box box;
294 ubyte tex2d[SIZE][SIZE][4];
295 int s, t;
296
297 #if (SIZE != 2)
298 for (s = 0; s < SIZE; s++) {
299 for (t = 0; t < SIZE; t++) {
300 if (0) {
301 int x = (s ^ t) & 1;
302 tex2d[t][s][0] = (x) ? 0 : 63;
303 tex2d[t][s][1] = (x) ? 0 : 128;
304 tex2d[t][s][2] = 0;
305 tex2d[t][s][3] = 0xff;
306 }
307 else {
308 int x = ((s ^ t) >> 2) & 1;
309 tex2d[t][s][0] = s*255/(SIZE-1);
310 tex2d[t][s][1] = t*255/(SIZE-1);
311 tex2d[t][s][2] = (x) ? 0 : 128;
312 tex2d[t][s][3] = 0xff;
313 }
314 }
315 }
316 #else
317 tex2d[0][0][0] = 0;
318 tex2d[0][0][1] = 255;
319 tex2d[0][0][2] = 255;
320 tex2d[0][0][3] = 0;
321
322 tex2d[0][1][0] = 0;
323 tex2d[0][1][1] = 0;
324 tex2d[0][1][2] = 255;
325 tex2d[0][1][3] = 255;
326
327 tex2d[1][0][0] = 255;
328 tex2d[1][0][1] = 255;
329 tex2d[1][0][2] = 0;
330 tex2d[1][0][3] = 255;
331
332 tex2d[1][1][0] = 255;
333 tex2d[1][1][1] = 0;
334 tex2d[1][1][2] = 0;
335 tex2d[1][1][3] = 255;
336 #endif
337
338 templat.target = PIPE_TEXTURE_2D;
339 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
340 templat.width0 = SIZE;
341 templat.height0 = SIZE;
342 templat.depth0 = 1;
343 templat.last_level = 0;
344 templat.nr_samples = 1;
345 templat.bind = PIPE_BIND_SAMPLER_VIEW;
346
347
348 samptex = screen->resource_create(screen,
349 &templat);
350 if (samptex == NULL)
351 exit(4);
352
353 u_box_2d(0,0,SIZE,SIZE, &box);
354
355 ctx->transfer_inline_write(ctx,
356 samptex,
357 u_subresource(0,0),
358 PIPE_TRANSFER_WRITE,
359 &box,
360 tex2d,
361 sizeof tex2d[0],
362 sizeof tex2d);
363
364 /* Possibly read back & compare against original data:
365 */
366 if (0)
367 {
368 struct pipe_transfer *t;
369 uint32_t *ptr;
370 t = pipe_get_transfer(ctx, samptex,
371 0, 0, 0, /* face, level, zslice */
372 PIPE_TRANSFER_READ,
373 0, 0, SIZE, SIZE); /* x, y, width, height */
374
375 ptr = ctx->transfer_map(ctx, t);
376
377 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
378 assert(0);
379 exit(9);
380 }
381
382 ctx->transfer_unmap(ctx, t);
383
384 ctx->transfer_destroy(ctx, t);
385 }
386
387 memset(&sv_template, 0, sizeof sv_template);
388 sv_template.format = samptex->format;
389 sv_template.texture = samptex;
390 sv_template.first_level = 0;
391 sv_template.last_level = 0;
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
423 static void init( void )
424 {
425 struct pipe_framebuffer_state fb;
426 struct pipe_resource templat;
427 int i;
428
429 /* It's hard to say whether window or screen should be created
430 * first. Different environments would prefer one or the other.
431 *
432 * Also, no easy way of querying supported formats if the screen
433 * cannot be created first.
434 */
435 for (i = 0;
436 window == NULL && formats[i] != PIPE_FORMAT_NONE;
437 i++) {
438
439 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
440 formats[i],
441 &window);
442 }
443
444 ctx = screen->context_create(screen, NULL);
445 if (ctx == NULL)
446 exit(3);
447
448 templat.target = PIPE_TEXTURE_2D;
449 templat.format = formats[i];
450 templat.width0 = WIDTH;
451 templat.height0 = HEIGHT;
452 templat.depth0 = 1;
453 templat.last_level = 0;
454 templat.nr_samples = 1;
455 templat.bind = (PIPE_BIND_RENDER_TARGET |
456 PIPE_BIND_DISPLAY_TARGET);
457
458 rttex = screen->resource_create(screen,
459 &templat);
460 if (rttex == NULL)
461 exit(4);
462
463 surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
464 PIPE_BIND_RENDER_TARGET |
465 PIPE_BIND_DISPLAY_TARGET);
466 if (surf == NULL)
467 exit(5);
468
469 memset(&fb, 0, sizeof fb);
470 fb.nr_cbufs = 1;
471 fb.width = WIDTH;
472 fb.height = HEIGHT;
473 fb.cbufs[0] = surf;
474
475 ctx->set_framebuffer_state(ctx, &fb);
476
477 {
478 struct pipe_blend_state blend;
479 void *handle;
480 memset(&blend, 0, sizeof blend);
481 blend.rt[0].colormask = PIPE_MASK_RGBA;
482 handle = ctx->create_blend_state(ctx, &blend);
483 ctx->bind_blend_state(ctx, handle);
484 }
485
486 {
487 struct pipe_depth_stencil_alpha_state depthstencil;
488 void *handle;
489 memset(&depthstencil, 0, sizeof depthstencil);
490 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
491 ctx->bind_depth_stencil_alpha_state(ctx, handle);
492 }
493
494 {
495 struct pipe_rasterizer_state rasterizer;
496 void *handle;
497 memset(&rasterizer, 0, sizeof rasterizer);
498 rasterizer.cull_face = PIPE_FACE_NONE;
499 rasterizer.gl_rasterization_rules = 1;
500 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
501 ctx->bind_rasterizer_state(ctx, handle);
502 }
503
504 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
505
506 init_tex();
507 init_fs_constbuf();
508
509 set_vertices();
510 set_vertex_shader();
511 set_fragment_shader(filename);
512 }
513
514 static void args(int argc, char *argv[])
515 {
516 int i;
517
518 for (i = 1; i < argc;) {
519 if (graw_parse_args(&i, argc, argv)) {
520 continue;
521 }
522 if (strcmp(argv[i], "-fps") == 0) {
523 show_fps = 1;
524 i++;
525 }
526 else if (i == argc - 1) {
527 filename = argv[i];
528 i++;
529 }
530 else {
531 usage(argv[0]);
532 exit(1);
533 }
534 }
535
536 if (!filename) {
537 usage(argv[0]);
538 exit(1);
539 }
540 }
541
542 int main( int argc, char *argv[] )
543 {
544 args(argc,argv);
545 init();
546
547 graw_set_display_func( draw );
548 graw_main_loop();
549 return 0;
550 }