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