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 18static const char *filename = NULL; 19unsigned show_fps = 0; 20 21 22static 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 33enum pipe_format formats[] = { 34 PIPE_FORMAT_R8G8B8A8_UNORM, 35 PIPE_FORMAT_B8G8R8A8_UNORM, 36 PIPE_FORMAT_NONE 37}; 38 39static const int WIDTH = 250; 40static const int HEIGHT = 250; 41 42static struct pipe_screen *screen = NULL; 43static struct pipe_context *ctx = NULL; 44static struct pipe_resource *rttex = NULL; 45static struct pipe_resource *constbuf1 = NULL; 46static struct pipe_resource *constbuf2 = NULL; 47static struct pipe_surface *surf = NULL; 48static struct pipe_sampler_view *sv = NULL; 49static void *sampler = NULL; 50static void *window = NULL; 51static struct pipe_resource *samptex = NULL; 52 53struct 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 */ 62static 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 77static 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 95static 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 112static 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 pipe_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 pipe_set_constant_buffer(ctx, 169 PIPE_SHADER_FRAGMENT, 1, 170 constbuf2); 171 } 172} 173 174 175static 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 198static 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.buffer_offset = 0; 219 vbuf.buffer = pipe_buffer_create_with_data(ctx, 220 PIPE_BIND_VERTEX_BUFFER, 221 PIPE_USAGE_STATIC, 222 sizeof(vertices), 223 vertices); 224 225 ctx->set_vertex_buffers(ctx, 1, &vbuf); 226} 227 228static 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 248static 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 274static void draw( void ) 275{ 276 union pipe_color_union clear_color = { {.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, 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 289static 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 423static 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; formats[i] != PIPE_FORMAT_NONE; i++) { 437 screen = graw_create_window_and_screen(0, 0, 300, 300, 438 formats[i], 439 &window); 440 if (window && screen) 441 break; 442 } 443 if (!screen || !window) { 444 fprintf(stderr, "Unable to create window\n"); 445 exit(1); 446 } 447 448 ctx = screen->context_create(screen, NULL); 449 if (ctx == NULL) 450 exit(3); 451 452 templat.target = PIPE_TEXTURE_2D; 453 templat.format = formats[i]; 454 templat.width0 = WIDTH; 455 templat.height0 = HEIGHT; 456 templat.depth0 = 1; 457 templat.array_size = 1; 458 templat.last_level = 0; 459 templat.nr_samples = 1; 460 templat.bind = (PIPE_BIND_RENDER_TARGET | 461 PIPE_BIND_DISPLAY_TARGET); 462 463 rttex = screen->resource_create(screen, 464 &templat); 465 if (rttex == NULL) 466 exit(4); 467 468 surf_tmpl.format = templat.format; 469 surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; 470 surf_tmpl.u.tex.level = 0; 471 surf_tmpl.u.tex.first_layer = 0; 472 surf_tmpl.u.tex.last_layer = 0; 473 surf = ctx->create_surface(ctx, rttex, &surf_tmpl); 474 if (surf == NULL) 475 exit(5); 476 477 memset(&fb, 0, sizeof fb); 478 fb.nr_cbufs = 1; 479 fb.width = WIDTH; 480 fb.height = HEIGHT; 481 fb.cbufs[0] = surf; 482 483 ctx->set_framebuffer_state(ctx, &fb); 484 485 { 486 struct pipe_blend_state blend; 487 void *handle; 488 memset(&blend, 0, sizeof blend); 489 blend.rt[0].colormask = PIPE_MASK_RGBA; 490 handle = ctx->create_blend_state(ctx, &blend); 491 ctx->bind_blend_state(ctx, handle); 492 } 493 494 { 495 struct pipe_depth_stencil_alpha_state depthstencil; 496 void *handle; 497 memset(&depthstencil, 0, sizeof depthstencil); 498 handle = ctx->create_depth_stencil_alpha_state(ctx, &depthstencil); 499 ctx->bind_depth_stencil_alpha_state(ctx, handle); 500 } 501 502 { 503 struct pipe_rasterizer_state rasterizer; 504 void *handle; 505 memset(&rasterizer, 0, sizeof rasterizer); 506 rasterizer.cull_face = PIPE_FACE_NONE; 507 rasterizer.gl_rasterization_rules = 1; 508 rasterizer.depth_clip = 1; 509 handle = ctx->create_rasterizer_state(ctx, &rasterizer); 510 ctx->bind_rasterizer_state(ctx, handle); 511 } 512 513 set_viewport(0, 0, WIDTH, HEIGHT, 30, 1000); 514 515 init_tex(); 516 init_fs_constbuf(); 517 518 set_vertices(); 519 set_vertex_shader(); 520 set_fragment_shader(filename); 521} 522 523static void args(int argc, char *argv[]) 524{ 525 int i; 526 527 for (i = 1; i < argc;) { 528 if (graw_parse_args(&i, argc, argv)) { 529 continue; 530 } 531 if (strcmp(argv[i], "-fps") == 0) { 532 show_fps = 1; 533 i++; 534 } 535 else if (i == argc - 1) { 536 filename = argv[i]; 537 i++; 538 } 539 else { 540 usage(argv[0]); 541 exit(1); 542 } 543 } 544 545 if (!filename) { 546 usage(argv[0]); 547 exit(1); 548 } 549} 550 551int main( int argc, char *argv[] ) 552{ 553 args(argc,argv); 554 init(); 555 556 graw_set_display_func( draw ); 557 graw_main_loop(); 558 return 0; 559} 560