polygon.c revision 1f57069c68f7bf812d4d2e054c5ced3ed72cfa10
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 "paint.h" 33#include "renderer.h" 34#include "util_array.h" 35#include "VG/openvg.h" 36 37#include "pipe/p_context.h" 38#include "pipe/p_defines.h" 39#include "pipe/p_state.h" 40#include "util/u_inlines.h" 41#include "pipe/p_screen.h" 42 43#include "util/u_draw_quad.h" 44#include "util/u_math.h" 45 46#include <string.h> 47#include <stdlib.h> 48 49#define DEBUG_POLYGON 0 50 51#define COMPONENTS 2 52 53struct polygon 54{ 55 VGfloat *data; 56 VGint size; 57 58 VGint num_verts; 59 60 VGboolean dirty; 61 struct pipe_buffer *vbuf; 62 struct pipe_screen *screen; 63}; 64 65static float *ptr_to_vertex(float *data, int idx) 66{ 67 return data + (idx * COMPONENTS); 68} 69 70#if 0 71static void polygon_print(struct polygon *poly) 72{ 73 int i; 74 float *vert; 75 debug_printf("Polygon %p, size = %d\n", poly, poly->num_verts); 76 for (i = 0; i < poly->num_verts; ++i) { 77 vert = ptr_to_vertex(poly->data, i); 78 debug_printf("%f, %f, ", vert[0], vert[1]); 79 } 80 debug_printf("\nend\n"); 81} 82#endif 83 84 85struct polygon * polygon_create(int size) 86{ 87 struct polygon *poly = (struct polygon*)malloc(sizeof(struct polygon)); 88 89 poly->data = malloc(sizeof(float) * COMPONENTS * size); 90 poly->size = size; 91 poly->num_verts = 0; 92 poly->dirty = VG_TRUE; 93 poly->vbuf = NULL; 94 95 return poly; 96} 97 98struct polygon * polygon_create_from_data(float *data, int size) 99{ 100 struct polygon *poly = polygon_create(size); 101 102 memcpy(poly->data, data, sizeof(float) * COMPONENTS * size); 103 poly->num_verts = size; 104 poly->dirty = VG_TRUE; 105 poly->vbuf = NULL; 106 107 return poly; 108} 109 110void polygon_destroy(struct polygon *poly) 111{ 112 if (poly->vbuf) 113 pipe_buffer_reference(&poly->vbuf, NULL); 114 115 free(poly->data); 116 free(poly); 117} 118 119void polygon_resize(struct polygon *poly, int new_size) 120{ 121 float *data = (float*)malloc(sizeof(float) * COMPONENTS * new_size); 122 int size = MIN2(sizeof(float) * COMPONENTS * new_size, 123 sizeof(float) * COMPONENTS * poly->size); 124 memcpy(data, poly->data, size); 125 free(poly->data); 126 poly->data = data; 127 poly->size = new_size; 128 poly->dirty = VG_TRUE; 129} 130 131int polygon_size(struct polygon *poly) 132{ 133 return poly->size; 134} 135 136int polygon_vertex_count(struct polygon *poly) 137{ 138 return poly->num_verts; 139} 140 141float * polygon_data(struct polygon *poly) 142{ 143 return poly->data; 144} 145 146void polygon_vertex_append(struct polygon *p, 147 float x, float y) 148{ 149 float *vert; 150#if DEBUG_POLYGON 151 debug_printf("Append vertex [%f, %f]\n", x, y); 152#endif 153 if (p->num_verts >= p->size) { 154 polygon_resize(p, p->size * 2); 155 } 156 157 vert = ptr_to_vertex(p->data, p->num_verts); 158 vert[0] = x; 159 vert[1] = y; 160 ++p->num_verts; 161 p->dirty = VG_TRUE; 162} 163 164void polygon_set_vertex(struct polygon *p, int idx, 165 float x, float y) 166{ 167 float *vert; 168 if (idx >= p->num_verts) { 169 /*fixme: error reporting*/ 170 abort(); 171 return; 172 } 173 174 vert = ptr_to_vertex(p->data, idx); 175 vert[0] = x; 176 vert[1] = y; 177 p->dirty = VG_TRUE; 178} 179 180void polygon_vertex(struct polygon *p, int idx, 181 float *vertex) 182{ 183 float *vert; 184 if (idx >= p->num_verts) { 185 /*fixme: error reporting*/ 186 abort(); 187 return; 188 } 189 190 vert = ptr_to_vertex(p->data, idx); 191 vertex[0] = vert[0]; 192 vertex[1] = vert[1]; 193} 194 195void polygon_bounding_rect(struct polygon *p, 196 float *rect) 197{ 198 int i; 199 float minx, miny, maxx, maxy; 200 float *vert = ptr_to_vertex(p->data, 0); 201 minx = vert[0]; 202 maxx = vert[0]; 203 miny = vert[1]; 204 maxy = vert[1]; 205 206 for (i = 1; i < p->num_verts; ++i) { 207 vert = ptr_to_vertex(p->data, i); 208 minx = MIN2(vert[0], minx); 209 miny = MIN2(vert[1], miny); 210 211 maxx = MAX2(vert[0], maxx); 212 maxy = MAX2(vert[1], maxy); 213 } 214 215 rect[0] = minx; 216 rect[1] = miny; 217 rect[2] = maxx - minx; 218 rect[3] = maxy - miny; 219} 220 221int polygon_contains_point(struct polygon *p, 222 float x, float y) 223{ 224 return 0; 225} 226 227void polygon_append_polygon(struct polygon *dst, 228 struct polygon *src) 229{ 230 if (dst->num_verts + src->num_verts >= dst->size) { 231 polygon_resize(dst, dst->num_verts + src->num_verts * 1.5); 232 } 233 memcpy(ptr_to_vertex(dst->data, dst->num_verts), 234 src->data, src->num_verts * COMPONENTS * sizeof(VGfloat)); 235 dst->num_verts += src->num_verts; 236} 237 238VGboolean polygon_is_closed(struct polygon *p) 239{ 240 VGfloat start[2], end[2]; 241 242 polygon_vertex(p, 0, start); 243 polygon_vertex(p, p->num_verts - 1, end); 244 245 return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]); 246} 247 248static void set_blend_for_fill(struct pipe_blend_state *blend) 249{ 250 memset(blend, 0, sizeof(struct pipe_blend_state)); 251 blend->rt[0].colormask = 0; /*disable colorwrites*/ 252 253 blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; 254 blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; 255 blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 256 blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; 257} 258 259static void draw_polygon(struct vg_context *ctx, 260 struct polygon *poly) 261{ 262 int vert_size; 263 struct pipe_context *pipe; 264 struct pipe_vertex_buffer vbuffer; 265 struct pipe_vertex_element velement; 266 267 vert_size = poly->num_verts * COMPONENTS * sizeof(float); 268 269 /*polygon_print(poly);*/ 270 271 pipe = ctx->pipe; 272 273 if (poly->vbuf == NULL || poly->dirty) { 274 if (poly->vbuf) { 275 pipe_buffer_reference(&poly->vbuf, 276 NULL); 277 } 278 poly->screen = pipe->screen; 279 poly->vbuf= pipe_user_buffer_create(poly->screen, 280 poly->data, 281 vert_size); 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 pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, 304 0, poly->num_verts); 305} 306 307void polygon_fill(struct polygon *poly, struct vg_context *ctx) 308{ 309 struct pipe_depth_stencil_alpha_state dsa; 310 struct pipe_stencil_ref sr; 311 struct pipe_blend_state blend; 312 VGfloat bounds[4]; 313 VGfloat min_x, min_y, max_x, max_y; 314 assert(poly); 315 polygon_bounding_rect(poly, bounds); 316 min_x = bounds[0]; 317 min_y = bounds[1]; 318 max_x = bounds[0] + bounds[2]; 319 max_y = bounds[1] + bounds[3]; 320 321#if DEBUG_POLYGON 322 debug_printf("Poly bounds are [%f, %f], [%f, %f]\n", 323 min_x, min_y, max_x, max_y); 324#endif 325 326 set_blend_for_fill(&blend); 327 328 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 329 memset(&sr, 0, sizeof(struct pipe_stencil_ref)); 330 /* only need a fixed 0. Rely on default or move it out at least? */ 331 cso_set_stencil_ref(ctx->cso_context, &sr); 332 333 cso_save_blend(ctx->cso_context); 334 cso_save_depth_stencil_alpha(ctx->cso_context); 335 336 dsa.stencil[0].enabled = 1; 337 if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { 338 dsa.stencil[0].writemask = 1; 339 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 340 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 341 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; 342 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 343 dsa.stencil[0].valuemask = ~0; 344 345 cso_set_blend(ctx->cso_context, &blend); 346 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 347 draw_polygon(ctx, poly); 348 } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { 349 struct pipe_screen *screen = ctx->pipe->screen; 350 351 if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { 352 /* front */ 353 dsa.stencil[0].writemask = ~0; 354 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 355 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 356 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 357 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 358 dsa.stencil[0].valuemask = ~0; 359 360 /* back */ 361 dsa.stencil[1].enabled = 1; 362 dsa.stencil[1].writemask = ~0; 363 dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; 364 dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; 365 dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 366 dsa.stencil[1].func = PIPE_FUNC_ALWAYS; 367 dsa.stencil[1].valuemask = ~0; 368 369 cso_set_blend(ctx->cso_context, &blend); 370 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 371 draw_polygon(ctx, poly); 372 } else { 373 struct pipe_rasterizer_state raster; 374 375 memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); 376 377 cso_save_rasterizer(ctx->cso_context); 378 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 379 dsa.stencil[0].valuemask = ~0; 380 381 raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH; 382 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 383 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 384 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 385 386 cso_set_blend(ctx->cso_context, &blend); 387 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 388 cso_set_rasterizer(ctx->cso_context, &raster); 389 draw_polygon(ctx, poly); 390 391 raster.cull_mode = raster.front_winding; 392 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 393 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 394 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 395 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 396 cso_set_rasterizer(ctx->cso_context, &raster); 397 draw_polygon(ctx, poly); 398 399 cso_restore_rasterizer(ctx->cso_context); 400 } 401 } 402 403 /* restore color writes */ 404 cso_restore_blend(ctx->cso_context); 405 /* setup stencil ops */ 406 dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; 407 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; 408 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; 409 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; 410 dsa.stencil[0].valuemask = dsa.stencil[0].writemask; 411 dsa.stencil[1].enabled = 0; 412 memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, 413 sizeof(struct pipe_depth_state)); 414 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 415 416 /* render the quad to propagate the rendering from stencil */ 417 renderer_draw_quad(ctx->renderer, min_x, min_y, 418 max_x, max_y, 0.0f/*depth should be disabled*/); 419 420 cso_restore_depth_stencil_alpha(ctx->cso_context); 421} 422 423void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) 424{ 425 struct array *polys = polyarray->array; 426 struct pipe_depth_stencil_alpha_state dsa; 427 struct pipe_stencil_ref sr; 428 struct pipe_blend_state blend; 429 VGfloat min_x = polyarray->min_x; 430 VGfloat min_y = polyarray->min_y; 431 VGfloat max_x = polyarray->max_x; 432 VGfloat max_y = polyarray->max_y; 433 VGint i; 434 435 436#if DEBUG_POLYGON 437 debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n", 438 __FUNCTION__, 439 min_x, min_y, max_x, max_y); 440#endif 441 442 set_blend_for_fill(&blend); 443 444 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 445 memset(&sr, 0, sizeof(struct pipe_stencil_ref)); 446 /* only need a fixed 0. Rely on default or move it out at least? */ 447 cso_set_stencil_ref(ctx->cso_context, &sr); 448 449 cso_save_blend(ctx->cso_context); 450 cso_save_depth_stencil_alpha(ctx->cso_context); 451 452 dsa.stencil[0].enabled = 1; 453 if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { 454 dsa.stencil[0].writemask = 1; 455 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 456 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 457 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; 458 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 459 dsa.stencil[0].valuemask = ~0; 460 461 cso_set_blend(ctx->cso_context, &blend); 462 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 463 for (i = 0; i < polys->num_elements; ++i) { 464 struct polygon *poly = (((struct polygon**)polys->data)[i]); 465 draw_polygon(ctx, poly); 466 } 467 } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { 468 struct pipe_screen *screen = ctx->pipe->screen; 469 470 if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { 471 /* front */ 472 dsa.stencil[0].writemask = ~0; 473 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 474 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 475 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 476 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 477 dsa.stencil[0].valuemask = ~0; 478 479 /* back */ 480 dsa.stencil[1].enabled = 1; 481 dsa.stencil[1].writemask = ~0; 482 dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; 483 dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; 484 dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 485 dsa.stencil[1].func = PIPE_FUNC_ALWAYS; 486 dsa.stencil[1].valuemask = ~0; 487 488 cso_set_blend(ctx->cso_context, &blend); 489 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 490 for (i = 0; i < polys->num_elements; ++i) { 491 struct polygon *poly = (((struct polygon**)polys->data)[i]); 492 draw_polygon(ctx, poly); 493 } 494 } else { 495 struct pipe_rasterizer_state raster; 496 497 memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); 498 499 cso_save_rasterizer(ctx->cso_context); 500 dsa.stencil[0].func = PIPE_FUNC_ALWAYS; 501 dsa.stencil[0].valuemask = ~0; 502 503 raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH; 504 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 505 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 506 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; 507 508 cso_set_blend(ctx->cso_context, &blend); 509 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 510 cso_set_rasterizer(ctx->cso_context, &raster); 511 for (i = 0; i < polys->num_elements; ++i) { 512 struct polygon *poly = (((struct polygon**)polys->data)[i]); 513 draw_polygon(ctx, poly); 514 } 515 516 raster.cull_mode = raster.front_winding; 517 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; 518 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; 519 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; 520 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 521 cso_set_rasterizer(ctx->cso_context, &raster); 522 for (i = 0; i < polys->num_elements; ++i) { 523 struct polygon *poly = (((struct polygon**)polys->data)[i]); 524 draw_polygon(ctx, poly); 525 } 526 527 cso_restore_rasterizer(ctx->cso_context); 528 } 529 } 530 531 /* restore color writes */ 532 cso_restore_blend(ctx->cso_context); 533 /* setup stencil ops */ 534 dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; 535 dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; 536 dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; 537 dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; 538 dsa.stencil[0].valuemask = dsa.stencil[0].writemask; 539 dsa.stencil[1].enabled = 0; 540 memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, 541 sizeof(struct pipe_depth_state)); 542 cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); 543 544 /* render the quad to propagate the rendering from stencil */ 545 renderer_draw_quad(ctx->renderer, min_x, min_y, 546 max_x, max_y, 0.0f/*depth should be disabled*/); 547 548 cso_restore_depth_stencil_alpha(ctx->cso_context); 549} 550