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