polygon.c revision 93a7e6d94e09a25bdbe31eedb0759e390ccb6a86
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27#include "polygon.h" 28 29#include "matrix.h" /*for floatsEqual*/ 30#include "vg_context.h" 31#include "vg_state.h" 32#include "renderer.h" 33#include "util_array.h" 34#include "VG/openvg.h" 35 36#include "pipe/p_context.h" 37#include "pipe/p_defines.h" 38#include "pipe/p_state.h" 39#include "util/u_inlines.h" 40#include "pipe/p_screen.h" 41 42#include "util/u_draw_quad.h" 43#include "util/u_math.h" 44 45#include <string.h> 46#include <stdlib.h> 47 48#define DEBUG_POLYGON 0 49 50#define COMPONENTS 2 51 52struct polygon 53{ 54 VGfloat *data; 55 VGint size; 56 57 VGint num_verts; 58 59 VGboolean dirty; 60 struct pipe_resource *vbuf; 61 struct pipe_screen *screen; 62}; 63 64static float *ptr_to_vertex(float *data, int idx) 65{ 66 return data + (idx * COMPONENTS); 67} 68 69#if 0 70static void polygon_print(struct polygon *poly) 71{ 72 int i; 73 float *vert; 74 debug_printf("Polygon %p, size = %d\n", poly, poly->num_verts); 75 for (i = 0; i < poly->num_verts; ++i) { 76 vert = ptr_to_vertex(poly->data, i); 77 debug_printf("%f, %f, ", vert[0], vert[1]); 78 } 79 debug_printf("\nend\n"); 80} 81#endif 82 83 84struct polygon * polygon_create(int size) 85{ 86 struct polygon *poly = (struct polygon*)malloc(sizeof(struct polygon)); 87 88 poly->data = malloc(sizeof(float) * COMPONENTS * size); 89 poly->size = size; 90 poly->num_verts = 0; 91 poly->dirty = VG_TRUE; 92 poly->vbuf = NULL; 93 94 return poly; 95} 96 97struct polygon * polygon_create_from_data(float *data, int size) 98{ 99 struct polygon *poly = polygon_create(size); 100 101 memcpy(poly->data, data, sizeof(float) * COMPONENTS * size); 102 poly->num_verts = size; 103 poly->dirty = VG_TRUE; 104 poly->vbuf = NULL; 105 106 return poly; 107} 108 109void polygon_destroy(struct polygon *poly) 110{ 111 if (poly->vbuf) 112 pipe_resource_reference(&poly->vbuf, NULL); 113 114 free(poly->data); 115 free(poly); 116} 117 118void polygon_resize(struct polygon *poly, int new_size) 119{ 120 float *data = (float*)malloc(sizeof(float) * COMPONENTS * new_size); 121 int size = MIN2(sizeof(float) * COMPONENTS * new_size, 122 sizeof(float) * COMPONENTS * poly->size); 123 memcpy(data, poly->data, size); 124 free(poly->data); 125 poly->data = data; 126 poly->size = new_size; 127 poly->dirty = VG_TRUE; 128} 129 130int polygon_size(struct polygon *poly) 131{ 132 return poly->size; 133} 134 135int polygon_vertex_count(struct polygon *poly) 136{ 137 return poly->num_verts; 138} 139 140float * polygon_data(struct polygon *poly) 141{ 142 return poly->data; 143} 144 145void polygon_vertex_append(struct polygon *p, 146 float x, float y) 147{ 148 float *vert; 149#if DEBUG_POLYGON 150 debug_printf("Append vertex [%f, %f]\n", x, y); 151#endif 152 if (p->num_verts >= p->size) { 153 polygon_resize(p, p->size * 2); 154 } 155 156 vert = ptr_to_vertex(p->data, p->num_verts); 157 vert[0] = x; 158 vert[1] = y; 159 ++p->num_verts; 160 p->dirty = VG_TRUE; 161} 162 163void polygon_set_vertex(struct polygon *p, int idx, 164 float x, float y) 165{ 166 float *vert; 167 if (idx >= p->num_verts) { 168 /*fixme: error reporting*/ 169 abort(); 170 return; 171 } 172 173 vert = ptr_to_vertex(p->data, idx); 174 vert[0] = x; 175 vert[1] = y; 176 p->dirty = VG_TRUE; 177} 178 179void polygon_vertex(struct polygon *p, int idx, 180 float *vertex) 181{ 182 float *vert; 183 if (idx >= p->num_verts) { 184 /*fixme: error reporting*/ 185 abort(); 186 return; 187 } 188 189 vert = ptr_to_vertex(p->data, idx); 190 vertex[0] = vert[0]; 191 vertex[1] = vert[1]; 192} 193 194void polygon_bounding_rect(struct polygon *p, 195 float *rect) 196{ 197 int i; 198 float minx, miny, maxx, maxy; 199 float *vert = ptr_to_vertex(p->data, 0); 200 minx = vert[0]; 201 maxx = vert[0]; 202 miny = vert[1]; 203 maxy = vert[1]; 204 205 for (i = 1; i < p->num_verts; ++i) { 206 vert = ptr_to_vertex(p->data, i); 207 minx = MIN2(vert[0], minx); 208 miny = MIN2(vert[1], miny); 209 210 maxx = MAX2(vert[0], maxx); 211 maxy = MAX2(vert[1], maxy); 212 } 213 214 rect[0] = minx; 215 rect[1] = miny; 216 rect[2] = maxx - minx; 217 rect[3] = maxy - miny; 218} 219 220int polygon_contains_point(struct polygon *p, 221 float x, float y) 222{ 223 return 0; 224} 225 226void polygon_append_polygon(struct polygon *dst, 227 struct polygon *src) 228{ 229 if (dst->num_verts + src->num_verts >= dst->size) { 230 polygon_resize(dst, dst->num_verts + src->num_verts * 1.5); 231 } 232 memcpy(ptr_to_vertex(dst->data, dst->num_verts), 233 src->data, src->num_verts * COMPONENTS * sizeof(VGfloat)); 234 dst->num_verts += src->num_verts; 235} 236 237VGboolean polygon_is_closed(struct polygon *p) 238{ 239 VGfloat start[2], end[2]; 240 241 polygon_vertex(p, 0, start); 242 polygon_vertex(p, p->num_verts - 1, end); 243 244 return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]); 245} 246 247static void set_blend_for_fill(struct pipe_blend_state *blend) 248{ 249 memset(blend, 0, sizeof(struct pipe_blend_state)); 250 blend->rt[0].colormask = 0; /*disable colorwrites*/ 251 252 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; 253 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; 254 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 255 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 256} 257 258static void draw_polygon(struct vg_context *ctx, 259 struct polygon *poly) 260{ 261 int vert_size; 262 struct pipe_context *pipe; 263 struct pipe_vertex_buffer vbuffer; 264 struct pipe_vertex_element velement; 265 266 vert_size = poly->num_verts * COMPONENTS * sizeof(float); 267 268 /*polygon_print(poly);*/ 269 270 pipe = ctx->pipe; 271 272 if (poly->vbuf == NULL || poly->dirty) { 273 if (poly->vbuf) { 274 pipe_resource_reference(&poly->vbuf, 275 NULL); 276 } 277 poly->screen = pipe->screen; 278 poly->vbuf= pipe_user_buffer_create(poly->screen, 279 poly->data, 280 vert_size, 281 PIPE_BIND_VERTEX_BUFFER); 282 poly->dirty = VG_FALSE; 283 } 284 285 286 /* tell pipe about the vertex buffer */ 287 memset(&vbuffer, 0, sizeof(vbuffer)); 288 vbuffer.buffer = poly->vbuf; 289 vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ 290 vbuffer.buffer_offset = 0; 291 vbuffer.max_index = poly->num_verts - 1; 292 pipe->set_vertex_buffers(pipe, 1, &vbuffer); 293 294 /* tell pipe about the vertex attributes */ 295 memset(&velement, 0, sizeof(velement)); 296 velement.src_offset = 0; 297 velement.instance_divisor = 0; 298 velement.vertex_buffer_index = 0; 299 velement.src_format = PIPE_FORMAT_R32G32_FLOAT; 300 cso_set_vertex_elements(ctx->cso_context, 1, &velement); 301 302 /* draw */ 303 util_draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, 0, (uint) poly->num_verts); 304} 305 306void polygon_fill(struct polygon *poly, struct vg_context *ctx) 307{ 308 struct pipe_depth_stencil_alpha_state dsa; 309 struct pipe_stencil_ref sr; 310 struct pipe_blend_state blend; 311 VGfloat bounds[4]; 312 VGfloat min_x, min_y, max_x, max_y; 313 assert(poly); 314 polygon_bounding_rect(poly, bounds); 315 min_x = bounds[0]; 316 min_y = bounds[1]; 317 max_x = bounds[0] + bounds[2]; 318 max_y = bounds[1] + bounds[3]; 319 320#if DEBUG_POLYGON 321 debug_printf("Poly bounds are [%f, %f], [%f, %f]\n", 322 min_x, min_y, max_x, max_y); 323#endif 324 325 set_blend_for_fill(&blend); 326 327 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 328 memset(&sr, 0, sizeof(struct pipe_stencil_ref)); 329 /* only need a fixed 0. Rely on default or move it out at least? */ 330 cso_set_stencil_ref(ctx->cso_context, &sr); 331 332 cso_save_blend(ctx->cso_context); 333 cso_save_depth_stencil_alpha(ctx->cso_context); 334 335 dsa.stencil[0].enabled = 1; 336 if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { 337 dsa.stencil[0].writemask = 1; 338 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 339 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 340 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; 341 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 342 dsa.stencil[0].valuemask = ~0; 343 344 cso_set_blend(ctx->cso_context, &blend); 345 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 346 draw_polygon(ctx, poly); 347 } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { 348 struct pipe_screen *screen = ctx->pipe->screen; 349 350 if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { 351 /* front */ 352 dsa.stencil[0].writemask = ~0; 353 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 354 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 355 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 356 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 357 dsa.stencil[0].valuemask = ~0; 358 359 /* back */ 360 dsa.stencil[1].enabled = 1; 361 dsa.stencil[1].writemask = ~0; 362 dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; 363 dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; 364 dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 365 dsa.stencil[1].func = PIPE_FUNC_ALWAYS; 366 dsa.stencil[1].valuemask = ~0; 367 368 cso_set_blend(ctx->cso_context, &blend); 369 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 370 draw_polygon(ctx, poly); 371 } else { 372 struct pipe_rasterizer_state raster; 373 374 memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); 375 376 cso_save_rasterizer(ctx->cso_context); 377 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 378 dsa.stencil[0].valuemask = ~0; 379 380 raster.cull_face = PIPE_FACE_BACK; 381 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 382 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 383 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 384 385 cso_set_blend(ctx->cso_context, &blend); 386 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 387 cso_set_rasterizer(ctx->cso_context, &raster); 388 draw_polygon(ctx, poly); 389 390 raster.cull_face = PIPE_FACE_FRONT; 391 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 392 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 393 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 394 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 395 cso_set_rasterizer(ctx->cso_context, &raster); 396 draw_polygon(ctx, poly); 397 398 cso_restore_rasterizer(ctx->cso_context); 399 } 400 } 401 402 /* restore color writes */ 403 cso_restore_blend(ctx->cso_context); 404 /* setup stencil ops */ 405 dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; 406 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; 407 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; 408 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; 409 dsa.stencil[0].valuemask = dsa.stencil[0].writemask; 410 dsa.stencil[1].enabled = 0; 411 memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, 412 sizeof(struct pipe_depth_state)); 413 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 414 415 /* render the quad to propagate the rendering from stencil */ 416 renderer_draw_quad(ctx->renderer, min_x, min_y, 417 max_x, max_y, 0.0f/*depth should be disabled*/); 418 419 cso_restore_depth_stencil_alpha(ctx->cso_context); 420} 421 422void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) 423{ 424 struct array *polys = polyarray->array; 425 struct pipe_depth_stencil_alpha_state dsa; 426 struct pipe_stencil_ref sr; 427 struct pipe_blend_state blend; 428 VGfloat min_x = polyarray->min_x; 429 VGfloat min_y = polyarray->min_y; 430 VGfloat max_x = polyarray->max_x; 431 VGfloat max_y = polyarray->max_y; 432 VGint i; 433 434 435#if DEBUG_POLYGON 436 debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n", 437 __FUNCTION__, 438 min_x, min_y, max_x, max_y); 439#endif 440 441 set_blend_for_fill(&blend); 442 443 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 444 memset(&sr, 0, sizeof(struct pipe_stencil_ref)); 445 /* only need a fixed 0. Rely on default or move it out at least? */ 446 cso_set_stencil_ref(ctx->cso_context, &sr); 447 448 cso_save_blend(ctx->cso_context); 449 cso_save_depth_stencil_alpha(ctx->cso_context); 450 451 dsa.stencil[0].enabled = 1; 452 if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { 453 dsa.stencil[0].writemask = 1; 454 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 455 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 456 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; 457 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 458 dsa.stencil[0].valuemask = ~0; 459 460 cso_set_blend(ctx->cso_context, &blend); 461 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 462 for (i = 0; i < polys->num_elements; ++i) { 463 struct polygon *poly = (((struct polygon**)polys->data)[i]); 464 draw_polygon(ctx, poly); 465 } 466 } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { 467 struct pipe_screen *screen = ctx->pipe->screen; 468 469 if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { 470 /* front */ 471 dsa.stencil[0].writemask = ~0; 472 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 473 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 474 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 475 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 476 dsa.stencil[0].valuemask = ~0; 477 478 /* back */ 479 dsa.stencil[1].enabled = 1; 480 dsa.stencil[1].writemask = ~0; 481 dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; 482 dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; 483 dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 484 dsa.stencil[1].func = PIPE_FUNC_ALWAYS; 485 dsa.stencil[1].valuemask = ~0; 486 487 cso_set_blend(ctx->cso_context, &blend); 488 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 489 for (i = 0; i < polys->num_elements; ++i) { 490 struct polygon *poly = (((struct polygon**)polys->data)[i]); 491 draw_polygon(ctx, poly); 492 } 493 } else { 494 struct pipe_rasterizer_state raster; 495 496 memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); 497 498 cso_save_rasterizer(ctx->cso_context); 499 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 500 dsa.stencil[0].valuemask = ~0; 501 502 raster.cull_face = PIPE_FACE_BACK; 503 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 504 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 505 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 506 507 cso_set_blend(ctx->cso_context, &blend); 508 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 509 cso_set_rasterizer(ctx->cso_context, &raster); 510 for (i = 0; i < polys->num_elements; ++i) { 511 struct polygon *poly = (((struct polygon**)polys->data)[i]); 512 draw_polygon(ctx, poly); 513 } 514 515 raster.cull_face = PIPE_FACE_FRONT; 516 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 517 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 518 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 519 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 520 cso_set_rasterizer(ctx->cso_context, &raster); 521 for (i = 0; i < polys->num_elements; ++i) { 522 struct polygon *poly = (((struct polygon**)polys->data)[i]); 523 draw_polygon(ctx, poly); 524 } 525 526 cso_restore_rasterizer(ctx->cso_context); 527 } 528 } 529 530 /* restore color writes */ 531 cso_restore_blend(ctx->cso_context); 532 /* setup stencil ops */ 533 dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; 534 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; 535 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; 536 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; 537 dsa.stencil[0].valuemask = dsa.stencil[0].writemask; 538 dsa.stencil[1].enabled = 0; 539 memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, 540 sizeof(struct pipe_depth_state)); 541 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 542 543 /* render the quad to propagate the rendering from stencil */ 544 renderer_draw_quad(ctx->renderer, min_x, min_y, 545 max_x, max_y, 0.0f/*depth should be disabled*/); 546 547 cso_restore_depth_stencil_alpha(ctx->cso_context); 548} 549