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