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