tests/graw: add fp-test
[mesa.git] / src / gallium / tests / graw / fp-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 <unistd.h> /* for sleep() */
12 #include <stdio.h> /* for fread(), etc */
13
14 #include "util/u_debug.h" /* debug_dump_surface_bmp() */
15 #include "util/u_inlines.h"
16 #include "util/u_memory.h" /* Offset() */
17 #include "util/u_box.h"
18
19 static const char *filename = NULL;
20 unsigned show_fps = 0;
21
22
23 static void usage(char *name)
24 {
25 fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
26 #ifndef WIN32
27 fprintf(stderr, "\n" );
28 fprintf(stderr, "options:\n");
29 fprintf(stderr, " -fps show frames per second\n");
30 #endif
31 }
32
33
34 enum pipe_format formats[] = {
35 PIPE_FORMAT_R8G8B8A8_UNORM,
36 PIPE_FORMAT_B8G8R8A8_UNORM,
37 PIPE_FORMAT_NONE
38 };
39
40 static const int WIDTH = 250;
41 static const int HEIGHT = 250;
42
43 static struct pipe_screen *screen = NULL;
44 static struct pipe_context *ctx = NULL;
45 static struct pipe_resource *rttex = NULL;
46 static struct pipe_resource *constbuf = 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 constants[] =
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 0, 0, 1, 0,
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 static void init_fs_constbuf( void )
95 {
96 struct pipe_resource templat;
97 struct pipe_box box;
98
99 templat.target = PIPE_BUFFER;
100 templat.format = PIPE_FORMAT_R8_UNORM;
101 templat.width0 = sizeof(constants);
102 templat.height0 = 1;
103 templat.depth0 = 1;
104 templat.last_level = 0;
105 templat.nr_samples = 1;
106 templat.bind = PIPE_BIND_CONSTANT_BUFFER;
107
108 constbuf = screen->resource_create(screen,
109 &templat);
110 if (constbuf == NULL)
111 exit(4);
112
113
114 u_box_2d(0,0,sizeof(constants),1, &box);
115
116 ctx->transfer_inline_write(ctx,
117 constbuf,
118 u_subresource(0,0),
119 PIPE_TRANSFER_WRITE,
120 &box,
121 constants,
122 sizeof constants,
123 sizeof constants);
124
125
126 ctx->set_constant_buffer(ctx,
127 PIPE_SHADER_FRAGMENT, 0,
128 constbuf);
129 }
130
131
132 static void set_viewport( float x, float y,
133 float width, float height,
134 float near, float far)
135 {
136 float z = far;
137 float half_width = (float)width / 2.0f;
138 float half_height = (float)height / 2.0f;
139 float half_depth = ((float)far - (float)near) / 2.0f;
140 struct pipe_viewport_state vp;
141
142 vp.scale[0] = half_width;
143 vp.scale[1] = half_height;
144 vp.scale[2] = half_depth;
145 vp.scale[3] = 1.0f;
146
147 vp.translate[0] = half_width + x;
148 vp.translate[1] = half_height + y;
149 vp.translate[2] = half_depth + z;
150 vp.translate[3] = 0.0f;
151
152 ctx->set_viewport_state( ctx, &vp );
153 }
154
155 static void set_vertices( void )
156 {
157 struct pipe_vertex_element ve[3];
158 struct pipe_vertex_buffer vbuf;
159 void *handle;
160
161 memset(ve, 0, sizeof ve);
162
163 ve[0].src_offset = Offset(struct vertex, position);
164 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
165 ve[1].src_offset = Offset(struct vertex, color);
166 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
167 ve[2].src_offset = Offset(struct vertex, texcoord);
168 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
169
170 handle = ctx->create_vertex_elements_state(ctx, 3, ve);
171 ctx->bind_vertex_elements_state(ctx, handle);
172
173
174 vbuf.stride = sizeof( struct vertex );
175 vbuf.max_index = sizeof(vertices) / vbuf.stride;
176 vbuf.buffer_offset = 0;
177 vbuf.buffer = screen->user_buffer_create(screen,
178 vertices,
179 sizeof(vertices),
180 PIPE_BIND_VERTEX_BUFFER);
181
182 ctx->set_vertex_buffers(ctx, 1, &vbuf);
183 }
184
185 static void set_vertex_shader( void )
186 {
187 void *handle;
188 const char *text =
189 "VERT\n"
190 "DCL IN[0]\n"
191 "DCL IN[1]\n"
192 "DCL IN[2]\n"
193 "DCL OUT[0], POSITION\n"
194 "DCL OUT[1], COLOR[0]\n"
195 "DCL OUT[2], GENERIC[0]\n"
196 " MOV OUT[0], IN[0]\n"
197 " MOV OUT[1], IN[1]\n"
198 " MOV OUT[2], IN[2]\n"
199 " END\n";
200
201 handle = graw_parse_vertex_shader(ctx, text);
202 ctx->bind_vs_state(ctx, handle);
203 }
204
205 static void set_fragment_shader( const char *filename )
206 {
207 FILE *f;
208 char buf[50000];
209 void *handle;
210 int sz;
211
212 if ((f = fopen(filename, "r")) == NULL) {
213 fprintf(stderr, "Couldn't open %s\n", filename);
214 exit(1);
215 }
216
217 sz = fread(buf, 1, sizeof(buf), f);
218 if (!feof(f)) {
219 printf("file too long\n");
220 exit(1);
221 }
222 printf("%.*s\n", sz, buf);
223 buf[sz] = 0;
224
225 handle = graw_parse_fragment_shader(ctx, buf);
226 ctx->bind_fs_state(ctx, handle);
227 }
228
229
230 static void draw( void )
231 {
232 float clear_color[4] = {.1,.3,.5,0};
233
234 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
235 ctx->draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
236 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
237
238 #if 0
239 /* At the moment, libgraw leaks out/makes available some of the
240 * symbols from gallium/auxiliary, including these debug helpers.
241 * Will eventually want to bless some of these paths, and lock the
242 * others down so they aren't accessible from test programs.
243 *
244 * This currently just happens to work on debug builds - a release
245 * build will probably fail to link here:
246 */
247 debug_dump_surface_bmp(ctx, "result.bmp", surf);
248 #endif
249
250 screen->flush_frontbuffer(screen, surf, window);
251 }
252
253 #define SIZE 16
254
255 static void init_tex( void )
256 {
257 struct pipe_sampler_view sv_template;
258 struct pipe_sampler_state sampler_desc;
259 struct pipe_resource templat;
260 struct pipe_box box;
261 ubyte tex2d[SIZE][SIZE][4];
262 int s, t;
263
264 #if (SIZE != 2)
265 for (s = 0; s < SIZE; s++) {
266 for (t = 0; t < SIZE; t++) {
267 if (0) {
268 int x = (s ^ t) & 1;
269 tex2d[t][s][0] = (x) ? 0 : 63;
270 tex2d[t][s][1] = (x) ? 0 : 128;
271 tex2d[t][s][2] = 0;
272 tex2d[t][s][3] = 0xff;
273 }
274 else {
275 int x = ((s ^ t) >> 2) & 1;
276 tex2d[t][s][0] = s*255/(SIZE-1);
277 tex2d[t][s][1] = t*255/(SIZE-1);
278 tex2d[t][s][2] = (x) ? 0 : 128;
279 tex2d[t][s][3] = 0xff;
280 }
281 }
282 }
283 #else
284 tex2d[0][0][0] = 0;
285 tex2d[0][0][1] = 255;
286 tex2d[0][0][2] = 255;
287 tex2d[0][0][3] = 0;
288
289 tex2d[0][1][0] = 0;
290 tex2d[0][1][1] = 0;
291 tex2d[0][1][2] = 255;
292 tex2d[0][1][3] = 255;
293
294 tex2d[1][0][0] = 255;
295 tex2d[1][0][1] = 255;
296 tex2d[1][0][2] = 0;
297 tex2d[1][0][3] = 255;
298
299 tex2d[1][1][0] = 255;
300 tex2d[1][1][1] = 0;
301 tex2d[1][1][2] = 0;
302 tex2d[1][1][3] = 255;
303 #endif
304
305 templat.target = PIPE_TEXTURE_2D;
306 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
307 templat.width0 = SIZE;
308 templat.height0 = SIZE;
309 templat.depth0 = 1;
310 templat.last_level = 0;
311 templat.nr_samples = 1;
312 templat.bind = PIPE_BIND_SAMPLER_VIEW;
313
314
315 samptex = screen->resource_create(screen,
316 &templat);
317 if (samptex == NULL)
318 exit(4);
319
320 u_box_2d(0,0,SIZE,SIZE, &box);
321
322 ctx->transfer_inline_write(ctx,
323 samptex,
324 u_subresource(0,0),
325 PIPE_TRANSFER_WRITE,
326 &box,
327 tex2d,
328 sizeof tex2d[0],
329 sizeof tex2d);
330
331 /* Possibly read back & compare against original data:
332 */
333 if (0)
334 {
335 struct pipe_transfer *t;
336 uint32_t *ptr;
337 t = pipe_get_transfer(ctx, samptex,
338 0, 0, 0, /* face, level, zslice */
339 PIPE_TRANSFER_READ,
340 0, 0, SIZE, SIZE); /* x, y, width, height */
341
342 ptr = ctx->transfer_map(ctx, t);
343
344 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
345 assert(0);
346 exit(9);
347 }
348
349 ctx->transfer_unmap(ctx, t);
350
351 ctx->transfer_destroy(ctx, t);
352 }
353
354 memset(&sv_template, 0, sizeof sv_template);
355 sv_template.format = samptex->format;
356 sv_template.texture = samptex;
357 sv_template.first_level = 0;
358 sv_template.last_level = 0;
359 sv_template.swizzle_r = 0;
360 sv_template.swizzle_g = 1;
361 sv_template.swizzle_b = 2;
362 sv_template.swizzle_a = 3;
363 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
364 if (sv == NULL)
365 exit(5);
366
367 ctx->set_fragment_sampler_views(ctx, 1, &sv);
368
369
370 memset(&sampler_desc, 0, sizeof sampler_desc);
371 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
372 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
373 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
374 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
375 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
376 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
377 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
378 sampler_desc.compare_func = 0;
379 sampler_desc.normalized_coords = 1;
380 sampler_desc.max_anisotropy = 0;
381
382 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
383 if (sampler == NULL)
384 exit(6);
385
386 ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
387
388 }
389
390 static void init( void )
391 {
392 struct pipe_framebuffer_state fb;
393 struct pipe_resource templat;
394 int i;
395
396 /* It's hard to say whether window or screen should be created
397 * first. Different environments would prefer one or the other.
398 *
399 * Also, no easy way of querying supported formats if the screen
400 * cannot be created first.
401 */
402 for (i = 0;
403 window == NULL && formats[i] != PIPE_FORMAT_NONE;
404 i++) {
405
406 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
407 formats[i],
408 &window);
409 }
410
411 ctx = screen->context_create(screen, NULL);
412 if (ctx == NULL)
413 exit(3);
414
415 templat.target = PIPE_TEXTURE_2D;
416 templat.format = formats[i];
417 templat.width0 = WIDTH;
418 templat.height0 = HEIGHT;
419 templat.depth0 = 1;
420 templat.last_level = 0;
421 templat.nr_samples = 1;
422 templat.bind = (PIPE_BIND_RENDER_TARGET |
423 PIPE_BIND_DISPLAY_TARGET);
424
425 rttex = screen->resource_create(screen,
426 &templat);
427 if (rttex == NULL)
428 exit(4);
429
430 surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
431 PIPE_BIND_RENDER_TARGET |
432 PIPE_BIND_DISPLAY_TARGET);
433 if (surf == NULL)
434 exit(5);
435
436 memset(&fb, 0, sizeof fb);
437 fb.nr_cbufs = 1;
438 fb.width = WIDTH;
439 fb.height = HEIGHT;
440 fb.cbufs[0] = surf;
441
442 ctx->set_framebuffer_state(ctx, &fb);
443
444 {
445 struct pipe_blend_state blend;
446 void *handle;
447 memset(&blend, 0, sizeof blend);
448 blend.rt[0].colormask = PIPE_MASK_RGBA;
449 handle = ctx->create_blend_state(ctx, &blend);
450 ctx->bind_blend_state(ctx, handle);
451 }
452
453 {
454 struct pipe_depth_stencil_alpha_state depthstencil;
455 void *handle;
456 memset(&depthstencil, 0, sizeof depthstencil);
457 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
458 ctx->bind_depth_stencil_alpha_state(ctx, handle);
459 }
460
461 {
462 struct pipe_rasterizer_state rasterizer;
463 void *handle;
464 memset(&rasterizer, 0, sizeof rasterizer);
465 rasterizer.cull_face = PIPE_FACE_NONE;
466 rasterizer.gl_rasterization_rules = 1;
467 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
468 ctx->bind_rasterizer_state(ctx, handle);
469 }
470
471 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
472
473 init_tex();
474 init_fs_constbuf();
475
476 set_vertices();
477 set_vertex_shader();
478 set_fragment_shader(filename);
479 }
480
481 static void args(int argc, char *argv[])
482 {
483 int i;
484
485 for (i = 1; i < argc; i++) {
486 if (strcmp(argv[i], "-fps") == 0) {
487 show_fps = 1;
488 }
489 else if (i == argc - 1) {
490 filename = argv[i];
491 }
492 else {
493 usage(argv[0]);
494 exit(1);
495 }
496 }
497
498 if (!filename) {
499 usage(argv[0]);
500 exit(1);
501 }
502 }
503
504 int main( int argc, char *argv[] )
505 {
506 args(argc,argv);
507 init();
508
509 graw_set_display_func( draw );
510 graw_main_loop();
511 return 0;
512 }