polygon.c revision 9c264642c385557d64b9bc6bbe31d2d15e703aff
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_resource *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_resource_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_resource_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					  PIPE_BIND_VERTEX_BUFFER);
283      poly->dirty = VG_FALSE;
284   }
285
286
287   /* tell pipe about the vertex buffer */
288   memset(&vbuffer, 0, sizeof(vbuffer));
289   vbuffer.buffer = poly->vbuf;
290   vbuffer.stride = COMPONENTS * sizeof(float);  /* vertex size */
291   vbuffer.buffer_offset = 0;
292   vbuffer.max_index = poly->num_verts - 1;
293   pipe->set_vertex_buffers(pipe, 1, &vbuffer);
294
295   /* tell pipe about the vertex attributes */
296   memset(&velement, 0, sizeof(velement));
297   velement.src_offset = 0;
298   velement.instance_divisor = 0;
299   velement.vertex_buffer_index = 0;
300   velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
301   cso_set_vertex_elements(ctx->cso_context, 1, &velement);
302
303   /* draw */
304   pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN,
305                     0, poly->num_verts);
306}
307
308void polygon_fill(struct polygon *poly, struct vg_context *ctx)
309{
310   struct pipe_depth_stencil_alpha_state dsa;
311   struct pipe_stencil_ref sr;
312   struct pipe_blend_state blend;
313   VGfloat bounds[4];
314   VGfloat min_x, min_y, max_x, max_y;
315   assert(poly);
316   polygon_bounding_rect(poly, bounds);
317   min_x = bounds[0];
318   min_y = bounds[1];
319   max_x = bounds[0] + bounds[2];
320   max_y = bounds[1] + bounds[3];
321
322#if DEBUG_POLYGON
323   debug_printf("Poly bounds are [%f, %f], [%f, %f]\n",
324                min_x, min_y, max_x, max_y);
325#endif
326
327   set_blend_for_fill(&blend);
328
329   memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
330   memset(&sr, 0, sizeof(struct pipe_stencil_ref));
331   /* only need a fixed 0. Rely on default or move it out at least? */
332   cso_set_stencil_ref(ctx->cso_context, &sr);
333
334   cso_save_blend(ctx->cso_context);
335   cso_save_depth_stencil_alpha(ctx->cso_context);
336
337   dsa.stencil[0].enabled = 1;
338   if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
339      dsa.stencil[0].writemask = 1;
340      dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
341      dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
342      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
343      dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
344      dsa.stencil[0].valuemask = ~0;
345
346      cso_set_blend(ctx->cso_context, &blend);
347      cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
348      draw_polygon(ctx, poly);
349   } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
350      struct pipe_screen *screen = ctx->pipe->screen;
351
352      if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
353         /* front */
354         dsa.stencil[0].writemask = ~0;
355         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
356         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
357         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
358         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
359         dsa.stencil[0].valuemask = ~0;
360
361         /* back */
362         dsa.stencil[1].enabled = 1;
363         dsa.stencil[1].writemask = ~0;
364         dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
365         dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
366         dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
367         dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
368         dsa.stencil[1].valuemask = ~0;
369
370         cso_set_blend(ctx->cso_context, &blend);
371         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
372         draw_polygon(ctx, poly);
373      } else {
374         struct pipe_rasterizer_state raster;
375
376         memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
377
378         cso_save_rasterizer(ctx->cso_context);
379         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
380         dsa.stencil[0].valuemask = ~0;
381
382         raster.cull_face = PIPE_FACE_BACK;
383         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
384         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
385         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
386
387         cso_set_blend(ctx->cso_context, &blend);
388         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
389         cso_set_rasterizer(ctx->cso_context, &raster);
390         draw_polygon(ctx, poly);
391
392         raster.cull_face = PIPE_FACE_FRONT;
393         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
394         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
395         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
396         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
397         cso_set_rasterizer(ctx->cso_context, &raster);
398         draw_polygon(ctx, poly);
399
400         cso_restore_rasterizer(ctx->cso_context);
401      }
402   }
403
404   /* restore color writes */
405   cso_restore_blend(ctx->cso_context);
406   /* setup stencil ops */
407   dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
408   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
409   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
410   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
411   dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
412   dsa.stencil[1].enabled = 0;
413   memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
414          sizeof(struct pipe_depth_state));
415   cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
416
417   /* render the quad to propagate the rendering from stencil */
418   renderer_draw_quad(ctx->renderer, min_x, min_y,
419                      max_x, max_y, 0.0f/*depth should be disabled*/);
420
421   cso_restore_depth_stencil_alpha(ctx->cso_context);
422}
423
424void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx)
425{
426   struct array *polys = polyarray->array;
427   struct pipe_depth_stencil_alpha_state dsa;
428   struct pipe_stencil_ref sr;
429   struct pipe_blend_state blend;
430   VGfloat min_x = polyarray->min_x;
431   VGfloat min_y = polyarray->min_y;
432   VGfloat max_x = polyarray->max_x;
433   VGfloat max_y = polyarray->max_y;
434   VGint i;
435
436
437#if DEBUG_POLYGON
438   debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n",
439                __FUNCTION__,
440                min_x, min_y, max_x, max_y);
441#endif
442
443   set_blend_for_fill(&blend);
444
445   memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
446   memset(&sr, 0, sizeof(struct pipe_stencil_ref));
447   /* only need a fixed 0. Rely on default or move it out at least? */
448   cso_set_stencil_ref(ctx->cso_context, &sr);
449
450   cso_save_blend(ctx->cso_context);
451   cso_save_depth_stencil_alpha(ctx->cso_context);
452
453   dsa.stencil[0].enabled = 1;
454   if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
455      dsa.stencil[0].writemask = 1;
456      dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
457      dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
458      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
459      dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
460      dsa.stencil[0].valuemask = ~0;
461
462      cso_set_blend(ctx->cso_context, &blend);
463      cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
464      for (i = 0; i < polys->num_elements; ++i) {
465         struct polygon *poly = (((struct polygon**)polys->data)[i]);
466         draw_polygon(ctx, poly);
467      }
468   } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
469      struct pipe_screen *screen = ctx->pipe->screen;
470
471      if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
472         /* front */
473         dsa.stencil[0].writemask = ~0;
474         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
475         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
476         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
477         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
478         dsa.stencil[0].valuemask = ~0;
479
480         /* back */
481         dsa.stencil[1].enabled = 1;
482         dsa.stencil[1].writemask = ~0;
483         dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
484         dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
485         dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
486         dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
487         dsa.stencil[1].valuemask = ~0;
488
489         cso_set_blend(ctx->cso_context, &blend);
490         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
491         for (i = 0; i < polys->num_elements; ++i) {
492            struct polygon *poly = (((struct polygon**)polys->data)[i]);
493            draw_polygon(ctx, poly);
494         }
495      } else {
496         struct pipe_rasterizer_state raster;
497
498         memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
499
500         cso_save_rasterizer(ctx->cso_context);
501         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
502         dsa.stencil[0].valuemask = ~0;
503
504         raster.cull_face = PIPE_FACE_BACK;
505         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
506         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
507         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
508
509         cso_set_blend(ctx->cso_context, &blend);
510         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
511         cso_set_rasterizer(ctx->cso_context, &raster);
512         for (i = 0; i < polys->num_elements; ++i) {
513            struct polygon *poly = (((struct polygon**)polys->data)[i]);
514            draw_polygon(ctx, poly);
515         }
516
517         raster.cull_face = PIPE_FACE_FRONT;
518         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
519         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
520         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
521         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
522         cso_set_rasterizer(ctx->cso_context, &raster);
523         for (i = 0; i < polys->num_elements; ++i) {
524            struct polygon *poly = (((struct polygon**)polys->data)[i]);
525            draw_polygon(ctx, poly);
526         }
527
528         cso_restore_rasterizer(ctx->cso_context);
529      }
530   }
531
532   /* restore color writes */
533   cso_restore_blend(ctx->cso_context);
534   /* setup stencil ops */
535   dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
536   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
537   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
538   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
539   dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
540   dsa.stencil[1].enabled = 0;
541   memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
542          sizeof(struct pipe_depth_state));
543   cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
544
545   /* render the quad to propagate the rendering from stencil */
546   renderer_draw_quad(ctx->renderer, min_x, min_y,
547                      max_x, max_y, 0.0f/*depth should be disabled*/);
548
549   cso_restore_depth_stencil_alpha(ctx->cso_context);
550}
551