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 18static const char *filename = NULL; 19unsigned show_fps = 0; 20unsigned draw_strip = 0; 21 22 23static 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 35enum pipe_format formats[] = { 36 PIPE_FORMAT_R8G8B8A8_UNORM, 37 PIPE_FORMAT_B8G8R8A8_UNORM, 38 PIPE_FORMAT_NONE 39}; 40 41static const int WIDTH = 250; 42static const int HEIGHT = 250; 43 44static struct pipe_screen *screen = NULL; 45static struct pipe_context *ctx = NULL; 46static struct pipe_resource *rttex = NULL; 47static struct pipe_resource *constbuf1 = NULL; 48static struct pipe_resource *constbuf2 = NULL; 49static struct pipe_surface *surf = NULL; 50static struct pipe_sampler_view *sv = NULL; 51static void *sampler = NULL; 52static void *window = NULL; 53static struct pipe_resource *samptex = NULL; 54 55struct 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 */ 65static 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 86static 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 113static 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 131static 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 149static 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 191static 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 217static 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 258static 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 281static 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 296static 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 322static 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 341static 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 471static 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 573static 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 605int 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