graw: emit warnings when context/surface creation failes
[mesa.git] / src / gallium / tests / graw / gs-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_debug.h" /* debug_dump_surface_bmp() */
14 #include "util/u_inlines.h"
15 #include "util/u_memory.h" /* Offset() */
16 #include "util/u_draw_quad.h"
17 #include "util/u_box.h"
18
19 static const char *filename = NULL;
20 unsigned show_fps = 0;
21 unsigned draw_strip = 0;
22
23
24 static void usage(char *name)
25 {
26 fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
27 #ifndef WIN32
28 fprintf(stderr, "\n" );
29 fprintf(stderr, "options:\n");
30 fprintf(stderr, " -fps show frames per second\n");
31 fprintf(stderr, " -strip renders a triangle strip\n");
32 #endif
33 }
34
35
36 enum pipe_format formats[] = {
37 PIPE_FORMAT_R8G8B8A8_UNORM,
38 PIPE_FORMAT_B8G8R8A8_UNORM,
39 PIPE_FORMAT_NONE
40 };
41
42 static const int WIDTH = 250;
43 static const int HEIGHT = 250;
44
45 static struct pipe_screen *screen = NULL;
46 static struct pipe_context *ctx = NULL;
47 static struct pipe_resource *rttex = NULL;
48 static struct pipe_resource *constbuf1 = NULL;
49 static struct pipe_resource *constbuf2 = NULL;
50 static struct pipe_surface *surf = NULL;
51 static struct pipe_sampler_view *sv = NULL;
52 static void *sampler = NULL;
53 static void *window = NULL;
54 static struct pipe_resource *samptex = NULL;
55
56 struct vertex {
57 float position[4];
58 float color[4];
59 float texcoord[4];
60 float generic[4];
61 };
62
63 /* Vertex data matches progs/fp/fp-tri.c, but flipped in Y dimension
64 * so that the final images are the same.
65 */
66 static struct vertex vertices[] =
67 {
68 { { 0.9, 0.9, 0.0, 1.0 },
69 { 0, 0, 1, 1 },
70 { 1, 1, 0, 1 },
71 { 1, 0, 1, 0 }
72 },
73
74 { { 0.9, -0.9, 0.0, 1.0 },
75 { 1, 0, 0, 1 },
76 { 1, -1, 0, 1 },
77 { 0, 1, 0, 1 }
78 },
79
80 { {-0.9, 0.0, 0.0, 1.0 },
81 { 0, 1, 0, 1 },
82 { -1, 0, 0, 1 },
83 { 0, 0, 1, 1 }
84 },
85 };
86
87 static struct vertex vertices_strip[] =
88 {
89 { { 0.9, 0.9, 0.0, 1.0 },
90 { 0, 0, 1, 1 },
91 { 1, 1, 0, 1 },
92 { 1, 0, 0, 1 }
93 },
94
95 { { 0.9, -0.9, 0.0, 1.0 },
96 { 1, 0, 0, 1 },
97 { 1, -1, 0, 1 },
98 { 0, 1, 0, 1 }
99 },
100
101 { {-0.9, 0.9, 0.0, 1.0 },
102 { 0, 1, 0, 1 },
103 { -1, 1, 0, 1 },
104 { 0, 0, 1, 1 }
105 },
106
107 { {-0.9, -0.9, 0.0, 1.0 },
108 { 1, 1, 0, 1 },
109 { -1, -1, 0, 1 },
110 { 1, 1, 0, 1 }
111 },
112 };
113
114 static float constants1[] =
115 { 0.4, 0, 0, 1,
116 1, 1, 1, 1,
117 2, 2, 2, 2,
118 4, 8, 16, 32,
119
120 3, 0, 0, 0,
121 0, .5, 0, 0,
122 0, 0, 1, 0,
123 0, 0, 0, 1,
124
125 1, 0, 0, 0.5,
126 0, 1, 0, 0.5,
127 0, 0, 1, 0,
128 0, 0, 0, 1,
129 };
130
131
132 static float constants2[] =
133 { 1, 0, 0, 1,
134 0, 1, 0, 1,
135 0, 0, 1, 1,
136 0, 0, 0, 1,
137
138 1, 1, 0, 1,
139 1, .5, 0, 1,
140 0, 1, 1, 1,
141 1, 0, 1, 1,
142
143 1, 0, 0, 0.5,
144 0, 1, 0, 0.5,
145 0, 0, 1, 0,
146 0, 0, 0, 1,
147 };
148
149
150 static void init_fs_constbuf( void )
151 {
152 struct pipe_resource templat;
153 struct pipe_box box;
154
155 templat.target = PIPE_BUFFER;
156 templat.format = PIPE_FORMAT_R8_UNORM;
157 templat.width0 = sizeof(constants1);
158 templat.height0 = 1;
159 templat.depth0 = 1;
160 templat.last_level = 0;
161 templat.nr_samples = 1;
162 templat.bind = PIPE_BIND_CONSTANT_BUFFER;
163
164 constbuf1 = screen->resource_create(screen, &templat);
165 if (constbuf1 == NULL)
166 exit(4);
167 constbuf2 = screen->resource_create(screen, &templat);
168 if (constbuf2 == NULL)
169 exit(4);
170
171 {
172 u_box_2d(0,0,sizeof(constants1),1, &box);
173
174 ctx->transfer_inline_write(ctx,
175 constbuf1,
176 u_subresource(0,0),
177 PIPE_TRANSFER_WRITE,
178 &box,
179 constants1,
180 sizeof constants1,
181 sizeof constants1);
182
183
184 ctx->set_constant_buffer(ctx,
185 PIPE_SHADER_GEOMETRY, 0,
186 constbuf1);
187 }
188 {
189 u_box_2d(0,0,sizeof(constants2),1, &box);
190
191 ctx->transfer_inline_write(ctx,
192 constbuf2,
193 u_subresource(0,0),
194 PIPE_TRANSFER_WRITE,
195 &box,
196 constants2,
197 sizeof constants2,
198 sizeof constants2);
199
200
201 ctx->set_constant_buffer(ctx,
202 PIPE_SHADER_GEOMETRY, 1,
203 constbuf2);
204 }
205 }
206
207
208 static void set_viewport( float x, float y,
209 float width, float height,
210 float near, float far)
211 {
212 float z = far;
213 float half_width = (float)width / 2.0f;
214 float half_height = (float)height / 2.0f;
215 float half_depth = ((float)far - (float)near) / 2.0f;
216 struct pipe_viewport_state vp;
217
218 vp.scale[0] = half_width;
219 vp.scale[1] = half_height;
220 vp.scale[2] = half_depth;
221 vp.scale[3] = 1.0f;
222
223 vp.translate[0] = half_width + x;
224 vp.translate[1] = half_height + y;
225 vp.translate[2] = half_depth + z;
226 vp.translate[3] = 0.0f;
227
228 ctx->set_viewport_state( ctx, &vp );
229 }
230
231 static void set_vertices( void )
232 {
233 struct pipe_vertex_element ve[4];
234 struct pipe_vertex_buffer vbuf;
235 void *handle;
236
237 memset(ve, 0, sizeof ve);
238
239 ve[0].src_offset = Offset(struct vertex, position);
240 ve[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
241 ve[1].src_offset = Offset(struct vertex, color);
242 ve[1].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
243 ve[2].src_offset = Offset(struct vertex, texcoord);
244 ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
245 ve[3].src_offset = Offset(struct vertex, generic);
246 ve[3].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
247
248 handle = ctx->create_vertex_elements_state(ctx, 4, ve);
249 ctx->bind_vertex_elements_state(ctx, handle);
250
251 vbuf.stride = sizeof( struct vertex );
252 vbuf.buffer_offset = 0;
253 if (draw_strip) {
254 vbuf.max_index = sizeof(vertices_strip) / vbuf.stride;
255 vbuf.buffer = screen->user_buffer_create(screen,
256 vertices_strip,
257 sizeof(vertices_strip),
258 PIPE_BIND_VERTEX_BUFFER);
259 } else {
260 vbuf.max_index = sizeof(vertices) / vbuf.stride;
261 vbuf.buffer = screen->user_buffer_create(screen,
262 vertices,
263 sizeof(vertices),
264 PIPE_BIND_VERTEX_BUFFER);
265 }
266
267 ctx->set_vertex_buffers(ctx, 1, &vbuf);
268 }
269
270 static void set_vertex_shader( void )
271 {
272 void *handle;
273 const char *text =
274 "VERT\n"
275 "DCL IN[0]\n"
276 "DCL IN[1]\n"
277 "DCL IN[2]\n"
278 "DCL IN[3]\n"
279 "DCL OUT[0], POSITION\n"
280 "DCL OUT[1], COLOR[0]\n"
281 "DCL OUT[2], GENERIC[0]\n"
282 "DCL OUT[3], GENERIC[1]\n"
283 " MOV OUT[0], IN[0]\n"
284 " MOV OUT[1], IN[1]\n"
285 " MOV OUT[2], IN[2]\n"
286 " MOV OUT[3], IN[3]\n"
287 " END\n";
288
289 handle = graw_parse_vertex_shader(ctx, text);
290 ctx->bind_vs_state(ctx, handle);
291 }
292
293 static void set_fragment_shader( void )
294 {
295 void *handle;
296 const char *text =
297 "FRAG\n"
298 "DCL IN[0], COLOR, LINEAR\n"
299 "DCL OUT[0], COLOR\n"
300 " 0: MOV OUT[0], IN[0]\n"
301 " 1: END\n";
302
303 handle = graw_parse_fragment_shader(ctx, text);
304 ctx->bind_fs_state(ctx, handle);
305 }
306
307
308 static void set_geometry_shader( void )
309 {
310 FILE *f;
311 char buf[50000];
312 void *handle;
313 int sz;
314
315 if ((f = fopen(filename, "r")) == NULL) {
316 fprintf(stderr, "Couldn't open %s\n", filename);
317 exit(1);
318 }
319
320 sz = fread(buf, 1, sizeof(buf), f);
321 if (!feof(f)) {
322 printf("file too long\n");
323 exit(1);
324 }
325 printf("%.*s\n", sz, buf);
326 buf[sz] = 0;
327
328 handle = graw_parse_geometry_shader(ctx, buf);
329 ctx->bind_gs_state(ctx, handle);
330 fclose(f);
331 }
332
333
334 static void draw( void )
335 {
336 float clear_color[4] = {.1,.3,.5,0};
337
338 ctx->clear(ctx, PIPE_CLEAR_COLOR, clear_color, 0, 0);
339 if (draw_strip)
340 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLE_STRIP, 0, 4);
341 else
342 util_draw_arrays(ctx, PIPE_PRIM_TRIANGLES, 0, 3);
343
344 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
345
346 #if 0
347 /* At the moment, libgraw leaks out/makes available some of the
348 * symbols from gallium/auxiliary, including these debug helpers.
349 * Will eventually want to bless some of these paths, and lock the
350 * others down so they aren't accessible from test programs.
351 *
352 * This currently just happens to work on debug builds - a release
353 * build will probably fail to link here:
354 */
355 debug_dump_surface_bmp(ctx, "result.bmp", surf);
356 #endif
357
358 screen->flush_frontbuffer(screen, surf, window);
359 }
360
361 #define SIZE 16
362
363 static void init_tex( void )
364 {
365 struct pipe_sampler_view sv_template;
366 struct pipe_sampler_state sampler_desc;
367 struct pipe_resource templat;
368 struct pipe_box box;
369 ubyte tex2d[SIZE][SIZE][4];
370 int s, t;
371
372 #if (SIZE != 2)
373 for (s = 0; s < SIZE; s++) {
374 for (t = 0; t < SIZE; t++) {
375 if (0) {
376 int x = (s ^ t) & 1;
377 tex2d[t][s][0] = (x) ? 0 : 63;
378 tex2d[t][s][1] = (x) ? 0 : 128;
379 tex2d[t][s][2] = 0;
380 tex2d[t][s][3] = 0xff;
381 }
382 else {
383 int x = ((s ^ t) >> 2) & 1;
384 tex2d[t][s][0] = s*255/(SIZE-1);
385 tex2d[t][s][1] = t*255/(SIZE-1);
386 tex2d[t][s][2] = (x) ? 0 : 128;
387 tex2d[t][s][3] = 0xff;
388 }
389 }
390 }
391 #else
392 tex2d[0][0][0] = 0;
393 tex2d[0][0][1] = 255;
394 tex2d[0][0][2] = 255;
395 tex2d[0][0][3] = 0;
396
397 tex2d[0][1][0] = 0;
398 tex2d[0][1][1] = 0;
399 tex2d[0][1][2] = 255;
400 tex2d[0][1][3] = 255;
401
402 tex2d[1][0][0] = 255;
403 tex2d[1][0][1] = 255;
404 tex2d[1][0][2] = 0;
405 tex2d[1][0][3] = 255;
406
407 tex2d[1][1][0] = 255;
408 tex2d[1][1][1] = 0;
409 tex2d[1][1][2] = 0;
410 tex2d[1][1][3] = 255;
411 #endif
412
413 templat.target = PIPE_TEXTURE_2D;
414 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
415 templat.width0 = SIZE;
416 templat.height0 = SIZE;
417 templat.depth0 = 1;
418 templat.last_level = 0;
419 templat.nr_samples = 1;
420 templat.bind = PIPE_BIND_SAMPLER_VIEW;
421
422
423 samptex = screen->resource_create(screen,
424 &templat);
425 if (samptex == NULL)
426 exit(4);
427
428 u_box_2d(0,0,SIZE,SIZE, &box);
429
430 ctx->transfer_inline_write(ctx,
431 samptex,
432 u_subresource(0,0),
433 PIPE_TRANSFER_WRITE,
434 &box,
435 tex2d,
436 sizeof tex2d[0],
437 sizeof tex2d);
438
439 /* Possibly read back & compare against original data:
440 */
441 if (0)
442 {
443 struct pipe_transfer *t;
444 uint32_t *ptr;
445 t = pipe_get_transfer(ctx, samptex,
446 0, 0, 0, /* face, level, zslice */
447 PIPE_TRANSFER_READ,
448 0, 0, SIZE, SIZE); /* x, y, width, height */
449
450 ptr = ctx->transfer_map(ctx, t);
451
452 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) {
453 assert(0);
454 exit(9);
455 }
456
457 ctx->transfer_unmap(ctx, t);
458
459 ctx->transfer_destroy(ctx, t);
460 }
461
462 memset(&sv_template, 0, sizeof sv_template);
463 sv_template.format = samptex->format;
464 sv_template.texture = samptex;
465 sv_template.first_level = 0;
466 sv_template.last_level = 0;
467 sv_template.swizzle_r = 0;
468 sv_template.swizzle_g = 1;
469 sv_template.swizzle_b = 2;
470 sv_template.swizzle_a = 3;
471 sv = ctx->create_sampler_view(ctx, samptex, &sv_template);
472 if (sv == NULL)
473 exit(5);
474
475 ctx->set_fragment_sampler_views(ctx, 1, &sv);
476
477
478 memset(&sampler_desc, 0, sizeof sampler_desc);
479 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT;
480 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT;
481 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT;
482 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST;
483 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
484 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
485 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE;
486 sampler_desc.compare_func = 0;
487 sampler_desc.normalized_coords = 1;
488 sampler_desc.max_anisotropy = 0;
489
490 sampler = ctx->create_sampler_state(ctx, &sampler_desc);
491 if (sampler == NULL)
492 exit(6);
493
494 ctx->bind_fragment_sampler_states(ctx, 1, &sampler);
495
496 }
497
498 static void init( void )
499 {
500 struct pipe_framebuffer_state fb;
501 struct pipe_resource templat;
502 int i;
503
504 /* It's hard to say whether window or screen should be created
505 * first. Different environments would prefer one or the other.
506 *
507 * Also, no easy way of querying supported formats if the screen
508 * cannot be created first.
509 */
510 for (i = 0;
511 window == NULL && formats[i] != PIPE_FORMAT_NONE;
512 i++) {
513
514 screen = graw_create_window_and_screen(0,0,WIDTH,HEIGHT,
515 formats[i],
516 &window);
517 }
518
519 ctx = screen->context_create(screen, NULL);
520 if (ctx == NULL)
521 exit(3);
522
523 templat.target = PIPE_TEXTURE_2D;
524 templat.format = formats[i];
525 templat.width0 = WIDTH;
526 templat.height0 = HEIGHT;
527 templat.depth0 = 1;
528 templat.last_level = 0;
529 templat.nr_samples = 1;
530 templat.bind = (PIPE_BIND_RENDER_TARGET |
531 PIPE_BIND_DISPLAY_TARGET);
532
533 rttex = screen->resource_create(screen,
534 &templat);
535 if (rttex == NULL)
536 exit(4);
537
538 surf = screen->get_tex_surface(screen, rttex, 0, 0, 0,
539 PIPE_BIND_RENDER_TARGET |
540 PIPE_BIND_DISPLAY_TARGET);
541 if (surf == NULL)
542 exit(5);
543
544 memset(&fb, 0, sizeof fb);
545 fb.nr_cbufs = 1;
546 fb.width = WIDTH;
547 fb.height = HEIGHT;
548 fb.cbufs[0] = surf;
549
550 ctx->set_framebuffer_state(ctx, &fb);
551
552 {
553 struct pipe_blend_state blend;
554 void *handle;
555 memset(&blend, 0, sizeof blend);
556 blend.rt[0].colormask = PIPE_MASK_RGBA;
557 handle = ctx->create_blend_state(ctx, &blend);
558 ctx->bind_blend_state(ctx, handle);
559 }
560
561 {
562 struct pipe_depth_stencil_alpha_state depthstencil;
563 void *handle;
564 memset(&depthstencil, 0, sizeof depthstencil);
565 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil);
566 ctx->bind_depth_stencil_alpha_state(ctx, handle);
567 }
568
569 {
570 struct pipe_rasterizer_state rasterizer;
571 void *handle;
572 memset(&rasterizer, 0, sizeof rasterizer);
573 rasterizer.cull_face = PIPE_FACE_NONE;
574 rasterizer.gl_rasterization_rules = 1;
575 handle = ctx->create_rasterizer_state(ctx, &rasterizer);
576 ctx->bind_rasterizer_state(ctx, handle);
577 }
578
579 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000);
580
581 init_tex();
582 init_fs_constbuf();
583
584 set_vertices();
585 set_vertex_shader();
586 set_fragment_shader();
587 set_geometry_shader();
588 }
589
590 static void args(int argc, char *argv[])
591 {
592 int i;
593
594 for (i = 1; i < argc; i++) {
595 if (strcmp(argv[i], "-fps") == 0) {
596 show_fps = 1;
597 }
598 else if (strcmp(argv[i], "-strip") == 0) {
599 draw_strip = 1;
600 }
601 else if (i == argc - 1) {
602 filename = argv[i];
603 }
604 else {
605 usage(argv[0]);
606 exit(1);
607 }
608 }
609
610 if (!filename) {
611 usage(argv[0]);
612 exit(1);
613 }
614 }
615
616 int main( int argc, char *argv[] )
617 {
618 args(argc,argv);
619 init();
620
621 graw_set_display_func( draw );
622 graw_main_loop();
623 return 0;
624 }