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 unsigned draw_strip = 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 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 149 static void init_fs_constbuf( void ) 150 { 151 struct pipe_resource templat; 152 struct pipe_box box; 153 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.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 0, 177 PIPE_TRANSFER_WRITE, 178 &box, 179 constants1, 180 sizeof constants1, 181 sizeof constants1); 182 183 184 pipe_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 0, 194 PIPE_TRANSFER_WRITE, 195 &box, 196 constants2, 197 sizeof constants2, 198 sizeof constants2); 199 200 201 pipe_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.buffer = pipe_buffer_create_with_data(ctx, 255 PIPE_BIND_VERTEX_BUFFER, 256 PIPE_USAGE_STATIC, 257 sizeof(vertices_strip), 258 vertices_strip); 259 } else { 260 vbuf.buffer = pipe_buffer_create_with_data(ctx, 261 PIPE_BIND_VERTEX_BUFFER, 262 PIPE_USAGE_STATIC, 263 sizeof(vertices), 264 vertices); 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 union pipe_color_union clear_color = { {.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, NULL); 345 346 graw_save_surface_to_file(ctx, surf, NULL); 347 348 screen->flush_frontbuffer(screen, rttex, 0, 0, window); 349 } 350 351 #define SIZE 16 352 353 static void init_tex( void ) 354 { 355 struct pipe_sampler_view sv_template; 356 struct pipe_sampler_state sampler_desc; 357 struct pipe_resource templat; 358 struct pipe_box box; 359 ubyte tex2d[SIZE][SIZE][4]; 360 int s, t; 361 362 #if (SIZE != 2) 363 for (s = 0; s < SIZE; s++) { 364 for (t = 0; t < SIZE; t++) { 365 if (0) { 366 int x = (s ^ t) & 1; 367 tex2d[t][s][0] = (x) ? 0 : 63; 368 tex2d[t][s][1] = (x) ? 0 : 128; 369 tex2d[t][s][2] = 0; 370 tex2d[t][s][3] = 0xff; 371 } 372 else { 373 int x = ((s ^ t) >> 2) & 1; 374 tex2d[t][s][0] = s*255/(SIZE-1); 375 tex2d[t][s][1] = t*255/(SIZE-1); 376 tex2d[t][s][2] = (x) ? 0 : 128; 377 tex2d[t][s][3] = 0xff; 378 } 379 } 380 } 381 #else 382 tex2d[0][0][0] = 0; 383 tex2d[0][0][1] = 255; 384 tex2d[0][0][2] = 255; 385 tex2d[0][0][3] = 0; 386 387 tex2d[0][1][0] = 0; 388 tex2d[0][1][1] = 0; 389 tex2d[0][1][2] = 255; 390 tex2d[0][1][3] = 255; 391 392 tex2d[1][0][0] = 255; 393 tex2d[1][0][1] = 255; 394 tex2d[1][0][2] = 0; 395 tex2d[1][0][3] = 255; 396 397 tex2d[1][1][0] = 255; 398 tex2d[1][1][1] = 0; 399 tex2d[1][1][2] = 0; 400 tex2d[1][1][3] = 255; 401 #endif 402 403 templat.target = PIPE_TEXTURE_2D; 404 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM; 405 templat.width0 = SIZE; 406 templat.height0 = SIZE; 407 templat.depth0 = 1; 408 templat.array_size = 1; 409 templat.last_level = 0; 410 templat.nr_samples = 1; 411 templat.bind = PIPE_BIND_SAMPLER_VIEW; 412 413 414 samptex = screen->resource_create(screen, 415 &templat); 416 if (samptex == NULL) 417 exit(4); 418 419 u_box_2d(0,0,SIZE,SIZE, &box); 420 421 ctx->transfer_inline_write(ctx, 422 samptex, 423 0, 424 PIPE_TRANSFER_WRITE, 425 &box, 426 tex2d, 427 sizeof tex2d[0], 428 sizeof tex2d); 429 430 /* Possibly read back & compare against original data: 431 */ 432 if (0) 433 { 434 struct pipe_transfer *t; 435 uint32_t *ptr; 436 t = pipe_get_transfer(ctx, samptex, 437 0, 0, /* level, layer */ 438 PIPE_TRANSFER_READ, 439 0, 0, SIZE, SIZE); /* x, y, width, height */ 440 441 ptr = ctx->transfer_map(ctx, t); 442 443 if (memcmp(ptr, tex2d, sizeof tex2d) != 0) { 444 assert(0); 445 exit(9); 446 } 447 448 ctx->transfer_unmap(ctx, t); 449 450 ctx->transfer_destroy(ctx, t); 451 } 452 453 memset(&sv_template, 0, sizeof sv_template); 454 sv_template.format = samptex->format; 455 sv_template.texture = samptex; 456 sv_template.swizzle_r = 0; 457 sv_template.swizzle_g = 1; 458 sv_template.swizzle_b = 2; 459 sv_template.swizzle_a = 3; 460 sv = ctx->create_sampler_view(ctx, samptex, &sv_template); 461 if (sv == NULL) 462 exit(5); 463 464 ctx->set_fragment_sampler_views(ctx, 1, &sv); 465 466 467 memset(&sampler_desc, 0, sizeof sampler_desc); 468 sampler_desc.wrap_s = PIPE_TEX_WRAP_REPEAT; 469 sampler_desc.wrap_t = PIPE_TEX_WRAP_REPEAT; 470 sampler_desc.wrap_r = PIPE_TEX_WRAP_REPEAT; 471 sampler_desc.min_img_filter = PIPE_TEX_FILTER_NEAREST; 472 sampler_desc.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 473 sampler_desc.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 474 sampler_desc.compare_mode = PIPE_TEX_COMPARE_NONE; 475 sampler_desc.compare_func = 0; 476 sampler_desc.normalized_coords = 1; 477 sampler_desc.max_anisotropy = 0; 478 479 sampler = ctx->create_sampler_state(ctx, &sampler_desc); 480 if (sampler == NULL) 481 exit(6); 482 483 ctx->bind_fragment_sampler_states(ctx, 1, &sampler); 484 485 } 486 487 static void init( void ) 488 { 489 struct pipe_framebuffer_state fb; 490 struct pipe_resource templat; 491 struct pipe_surface surf_tmpl; 492 int i; 493 494 /* It's hard to say whether window or screen should be created 495 * first. Different environments would prefer one or the other. 496 * 497 * Also, no easy way of querying supported formats if the screen 498 * cannot be created first. 499 */ 500 for (i = 0; formats[i] != PIPE_FORMAT_NONE; i++) { 501 screen = graw_create_window_and_screen(0, 0, 300, 300, 502 formats[i], 503 &window); 504 if (window && screen) 505 break; 506 } 507 if (!screen || !window) { 508 fprintf(stderr, "Unable to create window\n"); 509 exit(1); 510 } 511 512 ctx = screen->context_create(screen, NULL); 513 if (ctx == NULL) 514 exit(3); 515 516 templat.target = PIPE_TEXTURE_2D; 517 templat.format = formats[i]; 518 templat.width0 = WIDTH; 519 templat.height0 = HEIGHT; 520 templat.depth0 = 1; 521 templat.array_size = 1; 522 templat.last_level = 0; 523 templat.nr_samples = 1; 524 templat.bind = (PIPE_BIND_RENDER_TARGET | 525 PIPE_BIND_DISPLAY_TARGET); 526 527 rttex = screen->resource_create(screen, 528 &templat); 529 if (rttex == NULL) 530 exit(4); 531 532 surf_tmpl.format = templat.format; 533 surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; 534 surf_tmpl.u.tex.level = 0; 535 surf_tmpl.u.tex.first_layer = 0; 536 surf_tmpl.u.tex.last_layer = 0; 537 surf = ctx->create_surface(ctx, rttex, &surf_tmpl); 538 if (surf == NULL) 539 exit(5); 540 541 memset(&fb, 0, sizeof fb); 542 fb.nr_cbufs = 1; 543 fb.width = WIDTH; 544 fb.height = HEIGHT; 545 fb.cbufs[0] = surf; 546 547 ctx->set_framebuffer_state(ctx, &fb); 548 549 { 550 struct pipe_blend_state blend; 551 void *handle; 552 memset(&blend, 0, sizeof blend); 553 blend.rt[0].colormask = PIPE_MASK_RGBA; 554 handle = ctx->create_blend_state(ctx, &blend); 555 ctx->bind_blend_state(ctx, handle); 556 } 557 558 { 559 struct pipe_depth_stencil_alpha_state depthstencil; 560 void *handle; 561 memset(&depthstencil, 0, sizeof depthstencil); 562 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil); 563 ctx->bind_depth_stencil_alpha_state(ctx, handle); 564 } 565 566 { 567 struct pipe_rasterizer_state rasterizer; 568 void *handle; 569 memset(&rasterizer, 0, sizeof rasterizer); 570 rasterizer.cull_face = PIPE_FACE_NONE; 571 rasterizer.gl_rasterization_rules = 1; 572 rasterizer.depth_clip = 1; 573 handle = ctx->create_rasterizer_state(ctx, &rasterizer); 574 ctx->bind_rasterizer_state(ctx, handle); 575 } 576 577 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000); 578 579 init_tex(); 580 init_fs_constbuf(); 581 582 set_vertices(); 583 set_vertex_shader(); 584 set_fragment_shader(); 585 set_geometry_shader(); 586 } 587 588 static void args(int argc, char *argv[]) 589 { 590 int i; 591 592 for (i = 1; i < argc;) { 593 if (graw_parse_args(&i, argc, argv)) { 594 continue; 595 } 596 if (strcmp(argv[i], "-fps") == 0) { 597 show_fps = 1; 598 i++; 599 } 600 else if (strcmp(argv[i], "-strip") == 0) { 601 draw_strip = 1; 602 i++; 603 } 604 else if (i == argc - 1) { 605 filename = argv[i]; 606 i++; 607 } 608 else { 609 usage(argv[0]); 610 exit(1); 611 } 612 } 613 614 if (!filename) { 615 usage(argv[0]); 616 exit(1); 617 } 618 } 619 620 int main( int argc, char *argv[] ) 621 { 622 args(argc,argv); 623 init(); 624 625 graw_set_display_func( draw ); 626 graw_main_loop(); 627 return 0; 628 } 629