gallium: support for array textures and related changes
[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 ctx->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 ctx->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
217 vbuf.stride = sizeof( struct vertex );
218 vbuf.max_index = sizeof(vertices) / vbuf.stride;
219 vbuf.buffer_offset = 0;
220 vbuf.buffer = screen->user_buffer_create(screen,
221 vertices,
222 sizeof(vertices),
223 PIPE_BIND_VERTEX_BUFFER);
224
225 ctx->set_vertex_buffers(ctx, 1, &vbuf);
226 }
227
228 static void set_vertex_shader( void )
229 {
230 void *handle;
231 const char *text =
232 "VERT\n"
233 "DCL IN[0]\n"
234 "DCL IN[1]\n"
235 "DCL IN[2]\n"
236 "DCL OUT[0], POSITION\n"
237 "DCL OUT[1], COLOR[0]\n"
238 "DCL OUT[2], GENERIC[0]\n"
239 " MOV OUT[0], IN[0]\n"
240 " MOV OUT[1], IN[1]\n"
241 " MOV OUT[2], IN[2]\n"
242 " END\n";
243
244 handle = graw_parse_vertex_shader(ctx, text);
245 ctx->bind_vs_state(ctx, handle);
246 }
247
248 static void set_fragment_shader( const char *filename )
249 {
250 FILE *f;
251 char buf[50000];
252 void *handle;
253 int sz;
254
255 if ((f = fopen(filename, "r")) == NULL) {
256 fprintf(stderr, "Couldn't open %s\n", filename);
257 exit(1);
258 }
259
260 sz = fread(buf, 1, sizeof(buf), f);
261 if (!feof(f)) {
262 printf("file too long\n");
263 exit(1);
264 }
265 printf("%.*s\n", sz, buf);
266 buf[sz] = 0;
267
268 handle = graw_parse_fragment_shader(ctx, buf);
269 ctx->bind_fs_state(ctx, handle);
270 fclose(f);
271 }
272
273
274 static void draw( void )
275 {
276 float clear_color[4] = {.1,.3,.5,0};
277
278 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
279 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
280 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
281
282 graw_save_surface_to_file(ctx, surf, NULL);
283
284 screen->flush_frontbuffer(screen, rttex, 0, 0, window);
285 }
286
287 #define SIZE 16
288
289 static void init_tex( void )
290 {
291 struct pipe_sampler_view sv_template;
292 struct pipe_sampler_state sampler_desc;
293 struct pipe_resource templat;
294 struct pipe_box box;
295 ubyte tex2d[SIZE][SIZE][4];
296 int s, t;
297
298 #if (SIZE != 2)
299 for (s = 0; s < SIZE; s++) {
300 for (t = 0; t < SIZE; t++) {
301 if (0) {
302 int x = (s ^ t) & 1;
303 tex2d[t][s][0] = (x) ? 0 : 63;
304 tex2d[t][s][1] = (x) ? 0 : 128;
305 tex2d[t][s][2] = 0;
306 tex2d[t][s][3] = 0xff;
307 }
308 else {
309 int x = ((s ^ t) >> 2) & 1;
310 tex2d[t][s][0] = s*255/(SIZE-1);
311 tex2d[t][s][1] = t*255/(SIZE-1);
312 tex2d[t][s][2] = (x) ? 0 : 128;
313 tex2d[t][s][3] = 0xff;
314 }
315 }
316 }
317 #else
318 tex2d[0][0][0] = 0;
319 tex2d[0][0][1] = 255;
320 tex2d[0][0][2] = 255;
321 tex2d[0][0][3] = 0;
322
323 tex2d[0][1][0] = 0;
324 tex2d[0][1][1] = 0;
325 tex2d[0][1][2] = 255;
326 tex2d[0][1][3] = 255;
327
328 tex2d[1][0][0] = 255;
329 tex2d[1][0][1] = 255;
330 tex2d[1][0][2] = 0;
331 tex2d[1][0][3] = 255;
332
333 tex2d[1][1][0] = 255;
334 tex2d[1][1][1] = 0;
335 tex2d[1][1][2] = 0;
336 tex2d[1][1][3] = 255;
337 #endif
338
339 templat.target = PIPE_TEXTURE_2D;
340 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
341 templat.width0 = SIZE;
342 templat.height0 = SIZE;
343 templat.depth0 = 1;
344 templat.array_size = 1;
345 templat.last_level = 0;
346 templat.nr_samples = 1;
347 templat.bind = PIPE_BIND_SAMPLER_VIEW;
348
349
350 samptex = screen->resource_create(screen,
351 &templat);
352 if (samptex == NULL)
353 exit(4);
354
355 u_box_2d(0,0,SIZE,SIZE, &box);
356
357 ctx->transfer_inline_write(ctx,
358 samptex,
359 0,
360 PIPE_TRANSFER_WRITE,
361 &box,
362 tex2d,
363 sizeof tex2d[0],
364 sizeof tex2d);
365
366 /* Possibly read back & compare against original data:
367 */
368 if (0)
369 {
370 struct pipe_transfer *t;
371 uint32_t *ptr;
372 t = pipe_get_transfer(ctx, samptex,
373 0, 0, /* level, layer */
374 PIPE_TRANSFER_READ,
375 0, 0, SIZE, SIZE); /* x, y, width, height */
376
377 ptr = ctx->transfer_map(ctx, t);
378
379 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
380 assert(0);
381 exit(9);
382 }
383
384 ctx->transfer_unmap(ctx, t);
385
386 ctx->transfer_destroy(ctx, t);
387 }
388
389 memset(&sv_template, 0, sizeof sv_template);
390 sv_template.format = samptex->format;
391 sv_template.texture = samptex;
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 struct pipe_surface surf_tmpl;
428 int i;
429
430 /* It's hard to say whether window or screen should be created
431 * first. Different environments would prefer one or the other.
432 *
433 * Also, no easy way of querying supported formats if the screen
434 * cannot be created first.
435 */
436 for (i = 0;
437 window == NULL && formats[i] != PIPE_FORMAT_NONE;
438 i++) {
439
440 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
441 formats[i],
442 &window);
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 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
506 ctx->bind_rasterizer_state(ctx, handle);
507 }
508
509 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
510
511 init_tex();
512 init_fs_constbuf();
513
514 set_vertices();
515 set_vertex_shader();
516 set_fragment_shader(filename);
517 }
518
519 static void args(int argc, char *argv[])
520 {
521 int i;
522
523 for (i = 1; i < argc;) {
524 if (graw_parse_args(&i, argc, argv)) {
525 continue;
526 }
527 if (strcmp(argv[i], "-fps") == 0) {
528 show_fps = 1;
529 i++;
530 }
531 else if (i == argc - 1) {
532 filename = argv[i];
533 i++;
534 }
535 else {
536 usage(argv[0]);
537 exit(1);
538 }
539 }
540
541 if (!filename) {
542 usage(argv[0]);
543 exit(1);
544 }
545 }
546
547 int main( int argc, char *argv[] )
548 {
549 args(argc,argv);
550 init();
551
552 graw_set_display_func( draw );
553 graw_main_loop();
554 return 0;
555 }