renderer.c revision 3b71cb6ad6dabfefc9363a35872f4e70e1125603
1/**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.  All Rights Reserved.
4 * Copyright 2010 LunarG, Inc.  All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "renderer.h"
29
30#include "vg_context.h"
31#include "image.h"
32
33#include "pipe/p_context.h"
34#include "pipe/p_state.h"
35#include "util/u_inlines.h"
36#include "pipe/p_screen.h"
37#include "pipe/p_shader_tokens.h"
38
39#include "util/u_draw_quad.h"
40#include "util/u_simple_shaders.h"
41#include "util/u_memory.h"
42#include "util/u_sampler.h"
43
44#include "cso_cache/cso_context.h"
45#include "tgsi/tgsi_ureg.h"
46
47typedef enum {
48   RENDERER_STATE_INIT,
49   RENDERER_STATE_COPY,
50   RENDERER_STATE_DRAWTEX,
51   RENDERER_STATE_SCISSOR,
52   RENDERER_STATE_CLEAR,
53   RENDERER_STATE_FILTER,
54   RENDERER_STATE_POLYGON_STENCIL,
55   RENDERER_STATE_POLYGON_FILL,
56   NUM_RENDERER_STATES
57} RendererState;
58
59typedef enum {
60   RENDERER_VS_PLAIN,
61   RENDERER_VS_COLOR,
62   RENDERER_VS_TEXTURE,
63   NUM_RENDERER_VS
64} RendererVs;
65
66typedef enum {
67   RENDERER_FS_COLOR,
68   RENDERER_FS_TEXTURE,
69   RENDERER_FS_SCISSOR,
70   NUM_RENDERER_FS
71} RendererFs;
72
73struct renderer {
74   struct pipe_context *pipe;
75   struct vg_context *owner;
76
77   struct cso_context *cso;
78
79   void *fs;
80
81   VGfloat vertices[4][2][4];
82
83   void *cached_vs[NUM_RENDERER_VS];
84   void *cached_fs[NUM_RENDERER_FS];
85
86   RendererState state;
87
88   /* state data */
89   union {
90      struct {
91         VGint tex_width;
92         VGint tex_height;
93      } copy;
94
95      struct {
96         VGint tex_width;
97         VGint tex_height;
98      } drawtex;
99
100      struct {
101         VGboolean restore_dsa;
102      } scissor;
103
104      struct {
105         VGboolean use_sampler;
106         VGint tex_width, tex_height;
107      } filter;
108
109      struct {
110         struct pipe_depth_stencil_alpha_state dsa;
111         VGboolean manual_two_sides;
112         VGboolean restore_dsa;
113      } polygon_stencil;
114   } u;
115};
116
117/**
118 * Return VG_TRUE if the renderer can use the resource as the asked bindings.
119 */
120static VGboolean renderer_can_support(struct renderer *renderer,
121                                      struct pipe_resource *res,
122                                      unsigned bindings)
123{
124   struct pipe_screen *screen = renderer->pipe->screen;
125
126   return screen->is_format_supported(screen,
127         res->format, res->target, 0, bindings, 0);
128}
129
130/**
131 * Create a simple vertex shader that passes through position and the given
132 * attribute.
133 */
134static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name)
135{
136   struct ureg_program *ureg;
137   struct ureg_src src[2], constants[2];
138   struct ureg_dst dst[2], tmp;
139   int i;
140
141   ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
142   if (!ureg)
143      return NULL;
144
145   /* position in surface coordinates */
146   src[0] = ureg_DECL_vs_input(ureg, 0);
147   dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
148   tmp = ureg_DECL_temporary(ureg);
149   for (i = 0; i < 2; i++)
150      constants[i] = ureg_DECL_constant(ureg, i);
151
152   /* transform to clipped coordinates */
153   ureg_MUL(ureg, tmp, src[0], constants[0]);
154   ureg_ADD(ureg, tmp, ureg_src(tmp), constants[1]);
155   ureg_MOV(ureg, dst[0], ureg_src(tmp));
156
157   if (semantic_name >= 0) {
158      src[1] = ureg_DECL_vs_input(ureg, 1);
159      dst[1] = ureg_DECL_output(ureg, semantic_name, 0);
160      ureg_MOV(ureg, dst[1], src[1]);
161   }
162
163   ureg_END(ureg);
164
165   return ureg_create_shader_and_destroy(ureg, pipe);
166}
167
168/**
169 * Set renderer vertex shader.
170 *
171 * This function modifies vertex_shader state.
172 */
173static void renderer_set_vs(struct renderer *r, RendererVs id)
174{
175   /* create as needed */
176   if (!r->cached_vs[id]) {
177      int semantic_name = -1;
178
179      switch (id) {
180      case RENDERER_VS_PLAIN:
181         break;
182      case RENDERER_VS_COLOR:
183         semantic_name = TGSI_SEMANTIC_COLOR;
184         break;
185      case RENDERER_VS_TEXTURE:
186         semantic_name = TGSI_SEMANTIC_GENERIC;
187         break;
188      default:
189         assert(!"Unknown renderer vs id");
190         break;
191      }
192
193      r->cached_vs[id] = create_passthrough_vs(r->pipe, semantic_name);
194   }
195
196   cso_set_vertex_shader_handle(r->cso, r->cached_vs[id]);
197}
198
199/**
200 * Create a simple fragment shader that sets the depth to 0.0f.
201 */
202static void *create_scissor_fs(struct pipe_context *pipe)
203{
204   struct ureg_program *ureg;
205   struct ureg_dst out;
206   struct ureg_src imm;
207
208   ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
209   out = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
210   imm = ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f);
211
212   ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_Z), imm);
213   ureg_END(ureg);
214
215   return ureg_create_shader_and_destroy(ureg, pipe);
216}
217
218/**
219 * Set renderer fragment shader.
220 *
221 * This function modifies fragment_shader state.
222 */
223static void renderer_set_fs(struct renderer *r, RendererFs id)
224{
225   /* create as needed */
226   if (!r->cached_fs[id]) {
227      void *fs = NULL;
228
229      switch (id) {
230      case RENDERER_FS_COLOR:
231         fs = util_make_fragment_passthrough_shader(r->pipe);
232         break;
233      case RENDERER_FS_TEXTURE:
234         fs = util_make_fragment_tex_shader(r->pipe,
235               TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR);
236         break;
237      case RENDERER_FS_SCISSOR:
238         fs = create_scissor_fs(r->pipe);
239         break;
240      default:
241         assert(!"Unknown renderer fs id");
242         break;
243      }
244
245      r->cached_fs[id] = fs;
246   }
247
248   cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]);
249}
250
251/**
252 * Set renderer target.
253 *
254 * This function modifies framebuffer and viewport states.
255 */
256static void renderer_set_target(struct renderer *r,
257                                struct pipe_surface *cbuf,
258                                struct pipe_surface *zsbuf,
259                                VGboolean y0_top)
260{
261   struct pipe_framebuffer_state fb;
262
263   memset(&fb, 0, sizeof(fb));
264   fb.width = cbuf->width;
265   fb.height = cbuf->height;
266   fb.cbufs[0] = cbuf;
267   fb.nr_cbufs = 1;
268   fb.zsbuf = zsbuf;
269   cso_set_framebuffer(r->cso, &fb);
270
271   vg_set_viewport(r->owner, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM);
272}
273
274/**
275 * Set renderer blend state.  Blending is disabled.
276 *
277 * This function modifies blend state.
278 */
279static void renderer_set_blend(struct renderer *r,
280                               VGbitfield channel_mask)
281{
282   struct pipe_blend_state blend;
283
284   memset(&blend, 0, sizeof(blend));
285
286   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
287   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
288   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
289   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
290
291   if (channel_mask & VG_RED)
292      blend.rt[0].colormask |= PIPE_MASK_R;
293   if (channel_mask & VG_GREEN)
294      blend.rt[0].colormask |= PIPE_MASK_G;
295   if (channel_mask & VG_BLUE)
296      blend.rt[0].colormask |= PIPE_MASK_B;
297   if (channel_mask & VG_ALPHA)
298      blend.rt[0].colormask |= PIPE_MASK_A;
299
300   cso_set_blend(r->cso, &blend);
301}
302
303/**
304 * Set renderer sampler and view states.
305 *
306 * This function modifies samplers and fragment_sampler_views states.
307 */
308static void renderer_set_samplers(struct renderer *r,
309                                  uint num_views,
310                                  struct pipe_sampler_view **views)
311{
312   struct pipe_sampler_state sampler;
313   unsigned tex_filter = PIPE_TEX_FILTER_NEAREST;
314   unsigned tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
315   uint i;
316
317   memset(&sampler, 0, sizeof(sampler));
318
319   sampler.min_img_filter = tex_filter;
320   sampler.mag_img_filter = tex_filter;
321   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
322
323   sampler.wrap_s = tex_wrap;
324   sampler.wrap_t = tex_wrap;
325   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
326
327   sampler.normalized_coords = 1;
328
329   /* set samplers */
330   for (i = 0; i < num_views; i++)
331      cso_single_sampler(r->cso, i, &sampler);
332   cso_single_sampler_done(r->cso);
333
334   /* set views */
335   cso_set_fragment_sampler_views(r->cso, num_views, views);
336}
337
338/**
339 * Set custom renderer fragment shader, and optionally set samplers and views
340 * and upload the fragment constant buffer.
341 *
342 * This function modifies fragment_shader, samplers and fragment_sampler_views
343 * states.
344 */
345static void renderer_set_custom_fs(struct renderer *renderer,
346                                   void *fs,
347                                   const struct pipe_sampler_state **samplers,
348                                   struct pipe_sampler_view **views,
349                                   VGint num_samplers,
350                                   const void *const_buffer,
351                                   VGint const_buffer_len)
352{
353   cso_set_fragment_shader_handle(renderer->cso, fs);
354
355   /* set samplers and views */
356   if (num_samplers) {
357      cso_set_samplers(renderer->cso, num_samplers, samplers);
358      cso_set_fragment_sampler_views(renderer->cso, num_samplers, views);
359   }
360
361   /* upload fs constant buffer */
362   if (const_buffer_len) {
363      struct pipe_resource *cbuf;
364
365      cbuf = pipe_buffer_create(renderer->pipe->screen,
366            PIPE_BIND_CONSTANT_BUFFER, const_buffer_len);
367      pipe_buffer_write(renderer->pipe, cbuf, 0,
368            const_buffer_len, const_buffer);
369      renderer->pipe->set_constant_buffer(renderer->pipe,
370            PIPE_SHADER_FRAGMENT, 0, cbuf);
371
372      /* destroy cbuf automatically */
373      pipe_resource_reference(&cbuf, NULL);
374   }
375}
376
377/**
378 * Setup renderer quad position.
379 */
380static void renderer_quad_pos(struct renderer *r,
381                              VGfloat x0, VGfloat y0,
382                              VGfloat x1, VGfloat y1,
383                              VGboolean scissor)
384{
385   VGfloat z;
386
387   /* the depth test is used for scissoring */
388   z = (scissor) ? 0.0f : 1.0f;
389
390   /* positions */
391   r->vertices[0][0][0] = x0;
392   r->vertices[0][0][1] = y0;
393   r->vertices[0][0][2] = z;
394
395   r->vertices[1][0][0] = x1;
396   r->vertices[1][0][1] = y0;
397   r->vertices[1][0][2] = z;
398
399   r->vertices[2][0][0] = x1;
400   r->vertices[2][0][1] = y1;
401   r->vertices[2][0][2] = z;
402
403   r->vertices[3][0][0] = x0;
404   r->vertices[3][0][1] = y1;
405   r->vertices[3][0][2] = z;
406}
407
408/**
409 * Setup renderer quad texture coordinates.
410 */
411static void renderer_quad_texcoord(struct renderer *r,
412                                   VGfloat x0, VGfloat y0,
413                                   VGfloat x1, VGfloat y1,
414                                   VGint tex_width, VGint tex_height)
415{
416   VGfloat s0, t0, s1, t1, r0, q0;
417   VGint i;
418
419   s0 = x0 / tex_width;
420   s1 = x1 / tex_width;
421   t0 = y0 / tex_height;
422   t1 = y1 / tex_height;
423   r0 = 0.0f;
424   q0 = 1.0f;
425
426   /* texcoords */
427   r->vertices[0][1][0] = s0;
428   r->vertices[0][1][1] = t0;
429
430   r->vertices[1][1][0] = s1;
431   r->vertices[1][1][1] = t0;
432
433   r->vertices[2][1][0] = s1;
434   r->vertices[2][1][1] = t1;
435
436   r->vertices[3][1][0] = s0;
437   r->vertices[3][1][1] = t1;
438
439   for (i = 0; i < 4; i++) {
440      r->vertices[i][1][2] = r0;
441      r->vertices[i][1][3] = q0;
442   }
443}
444
445/**
446 * Draw renderer quad.
447 */
448static void renderer_quad_draw(struct renderer *r)
449{
450   struct pipe_resource *buf;
451
452   buf = pipe_user_buffer_create(r->pipe->screen,
453                                 r->vertices,
454                                 sizeof(r->vertices),
455                                 PIPE_BIND_VERTEX_BUFFER);
456   if (buf) {
457      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
458      util_draw_vertex_buffer(r->pipe, buf, 0,
459                              PIPE_PRIM_TRIANGLE_FAN,
460                              Elements(r->vertices),     /* verts */
461                              Elements(r->vertices[0])); /* attribs/vert */
462
463      pipe_resource_reference(&buf, NULL);
464   }
465}
466
467/**
468 * Prepare the renderer for copying.
469 */
470VGboolean renderer_copy_begin(struct renderer *renderer,
471                              struct pipe_surface *dst,
472                              VGboolean y0_top,
473                              struct pipe_sampler_view *src)
474{
475   assert(renderer->state == RENDERER_STATE_INIT);
476
477   /* sanity check */
478   if (!renderer_can_support(renderer,
479            dst->texture, PIPE_BIND_RENDER_TARGET) ||
480       !renderer_can_support(renderer,
481          src->texture, PIPE_BIND_SAMPLER_VIEW))
482      return VG_FALSE;
483
484   cso_save_framebuffer(renderer->cso);
485   cso_save_viewport(renderer->cso);
486   cso_save_blend(renderer->cso);
487   cso_save_samplers(renderer->cso);
488   cso_save_fragment_sampler_views(renderer->cso);
489   cso_save_fragment_shader(renderer->cso);
490   cso_save_vertex_shader(renderer->cso);
491
492   renderer_set_target(renderer, dst, NULL, y0_top);
493
494   renderer_set_blend(renderer, ~0);
495   renderer_set_samplers(renderer, 1, &src);
496
497   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
498   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
499
500   /* remember the texture size */
501   renderer->u.copy.tex_width = src->texture->width0;
502   renderer->u.copy.tex_height = src->texture->height0;
503   renderer->state = RENDERER_STATE_COPY;
504
505   return VG_TRUE;
506}
507
508/**
509 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
510 * sampled from within the rectangle given by (sx, sy, sw, sh).
511 *
512 * The coordinates are in surface coordinates.
513 */
514void renderer_copy(struct renderer *renderer,
515                   VGint x, VGint y, VGint w, VGint h,
516                   VGint sx, VGint sy, VGint sw, VGint sh)
517{
518   assert(renderer->state == RENDERER_STATE_COPY);
519
520   /* there is no depth buffer for scissoring anyway */
521   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
522   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
523         renderer->u.copy.tex_width,
524         renderer->u.copy.tex_height);
525
526   renderer_quad_draw(renderer);
527}
528
529/**
530 * End copying and restore the states.
531 */
532void renderer_copy_end(struct renderer *renderer)
533{
534   assert(renderer->state == RENDERER_STATE_COPY);
535
536   cso_restore_framebuffer(renderer->cso);
537   cso_restore_viewport(renderer->cso);
538   cso_restore_blend(renderer->cso);
539   cso_restore_samplers(renderer->cso);
540   cso_restore_fragment_sampler_views(renderer->cso);
541   cso_restore_fragment_shader(renderer->cso);
542   cso_restore_vertex_shader(renderer->cso);
543
544   renderer->state = RENDERER_STATE_INIT;
545}
546
547/**
548 * Prepare the renderer for textured drawing.
549 */
550VGboolean renderer_drawtex_begin(struct renderer *renderer,
551                                 struct pipe_sampler_view *src)
552{
553   assert(renderer->state == RENDERER_STATE_INIT);
554
555   if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW))
556      return VG_FALSE;
557
558   cso_save_blend(renderer->cso);
559   cso_save_samplers(renderer->cso);
560   cso_save_fragment_sampler_views(renderer->cso);
561   cso_save_fragment_shader(renderer->cso);
562   cso_save_vertex_shader(renderer->cso);
563
564   renderer_set_blend(renderer, ~0);
565
566   renderer_set_samplers(renderer, 1, &src);
567
568   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
569   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
570
571   /* remember the texture size */
572   renderer->u.drawtex.tex_width = src->texture->width0;
573   renderer->u.drawtex.tex_height = src->texture->height0;
574   renderer->state = RENDERER_STATE_DRAWTEX;
575
576   return VG_TRUE;
577}
578
579/**
580 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
581 * sampled from within the rectangle given by (sx, sy, sw, sh).
582 *
583 * The coordinates are in surface coordinates.
584 */
585void renderer_drawtex(struct renderer *renderer,
586                      VGint x, VGint y, VGint w, VGint h,
587                      VGint sx, VGint sy, VGint sw, VGint sh)
588{
589   assert(renderer->state == RENDERER_STATE_DRAWTEX);
590
591   /* with scissoring */
592   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_TRUE);
593   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
594         renderer->u.drawtex.tex_width,
595         renderer->u.drawtex.tex_height);
596
597   renderer_quad_draw(renderer);
598}
599
600/**
601 * End textured drawing and restore the states.
602 */
603void renderer_drawtex_end(struct renderer *renderer)
604{
605   assert(renderer->state == RENDERER_STATE_DRAWTEX);
606
607   cso_restore_blend(renderer->cso);
608   cso_restore_samplers(renderer->cso);
609   cso_restore_fragment_sampler_views(renderer->cso);
610   cso_restore_fragment_shader(renderer->cso);
611   cso_restore_vertex_shader(renderer->cso);
612
613   renderer->state = RENDERER_STATE_INIT;
614}
615
616/**
617 * Prepare the renderer for scissor update.  This will reset the depth buffer
618 * to 1.0f.
619 */
620VGboolean renderer_scissor_begin(struct renderer *renderer,
621                                 VGboolean restore_dsa)
622{
623   struct pipe_depth_stencil_alpha_state dsa;
624
625   assert(renderer->state == RENDERER_STATE_INIT);
626
627   if (restore_dsa)
628      cso_save_depth_stencil_alpha(renderer->cso);
629   cso_save_blend(renderer->cso);
630   cso_save_fragment_shader(renderer->cso);
631
632   /* enable depth writes */
633   memset(&dsa, 0, sizeof(dsa));
634   dsa.depth.enabled = 1;
635   dsa.depth.writemask = 1;
636   dsa.depth.func = PIPE_FUNC_ALWAYS;
637   cso_set_depth_stencil_alpha(renderer->cso, &dsa);
638
639   /* disable color writes */
640   renderer_set_blend(renderer, 0);
641   renderer_set_fs(renderer, RENDERER_FS_SCISSOR);
642
643   renderer->u.scissor.restore_dsa = restore_dsa;
644   renderer->state = RENDERER_STATE_SCISSOR;
645
646   /* clear the depth buffer to 1.0f */
647   renderer->pipe->clear(renderer->pipe,
648         PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0f, 0);
649
650   return VG_TRUE;
651}
652
653/**
654 * Add a scissor rectangle.  Depth values inside the rectangle will be set to
655 * 0.0f.
656 */
657void renderer_scissor(struct renderer *renderer,
658                      VGint x, VGint y, VGint width, VGint height)
659{
660   assert(renderer->state == RENDERER_STATE_SCISSOR);
661
662   renderer_quad_pos(renderer, x, y, x + width, y + height, VG_FALSE);
663   renderer_quad_draw(renderer);
664}
665
666/**
667 * End scissor update and restore the states.
668 */
669void renderer_scissor_end(struct renderer *renderer)
670{
671   assert(renderer->state == RENDERER_STATE_SCISSOR);
672
673   if (renderer->u.scissor.restore_dsa)
674      cso_restore_depth_stencil_alpha(renderer->cso);
675   cso_restore_blend(renderer->cso);
676   cso_restore_fragment_shader(renderer->cso);
677
678   renderer->state = RENDERER_STATE_INIT;
679}
680
681/**
682 * Prepare the renderer for clearing.
683 */
684VGboolean renderer_clear_begin(struct renderer *renderer)
685{
686   assert(renderer->state == RENDERER_STATE_INIT);
687
688   cso_save_blend(renderer->cso);
689   cso_save_fragment_shader(renderer->cso);
690   cso_save_vertex_shader(renderer->cso);
691
692   renderer_set_blend(renderer, ~0);
693   renderer_set_fs(renderer, RENDERER_FS_COLOR);
694   renderer_set_vs(renderer, RENDERER_VS_COLOR);
695
696   renderer->state = RENDERER_STATE_CLEAR;
697
698   return VG_TRUE;
699}
700
701/**
702 * Clear the framebuffer with the specified region and color.
703 *
704 * The coordinates are in surface coordinates.
705 */
706void renderer_clear(struct renderer *renderer,
707                    VGint x, VGint y, VGint width, VGint height,
708                    const VGfloat color[4])
709{
710   VGuint i;
711
712   assert(renderer->state == RENDERER_STATE_CLEAR);
713
714   renderer_quad_pos(renderer, x, y, x + width, y + height, VG_TRUE);
715   for (i = 0; i < 4; i++)
716      memcpy(renderer->vertices[i][1], color, sizeof(VGfloat) * 4);
717
718   renderer_quad_draw(renderer);
719}
720
721/**
722 * End clearing and retore the states.
723 */
724void renderer_clear_end(struct renderer *renderer)
725{
726   assert(renderer->state == RENDERER_STATE_CLEAR);
727
728   cso_restore_blend(renderer->cso);
729   cso_restore_fragment_shader(renderer->cso);
730   cso_restore_vertex_shader(renderer->cso);
731
732   renderer->state = RENDERER_STATE_INIT;
733}
734
735/**
736 * Prepare the renderer for image filtering.
737 */
738VGboolean renderer_filter_begin(struct renderer *renderer,
739                                struct pipe_resource *dst,
740                                VGboolean y0_top,
741                                VGbitfield channel_mask,
742                                const struct pipe_sampler_state **samplers,
743                                struct pipe_sampler_view **views,
744                                VGint num_samplers,
745                                void *fs,
746                                const void *const_buffer,
747                                VGint const_buffer_len)
748{
749   struct pipe_surface *surf;
750
751   assert(renderer->state == RENDERER_STATE_INIT);
752
753   if (!fs)
754      return VG_FALSE;
755   if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET))
756      return VG_FALSE;
757
758   surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen,
759         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
760   if (!surf)
761      return VG_FALSE;
762
763   cso_save_framebuffer(renderer->cso);
764   cso_save_viewport(renderer->cso);
765   cso_save_blend(renderer->cso);
766
767   /* set the image as the target */
768   renderer_set_target(renderer, surf, NULL, y0_top);
769   pipe_surface_reference(&surf, NULL);
770
771   renderer_set_blend(renderer, channel_mask);
772
773   if (num_samplers) {
774      struct pipe_resource *tex;
775
776      cso_save_samplers(renderer->cso);
777      cso_save_fragment_sampler_views(renderer->cso);
778      cso_save_fragment_shader(renderer->cso);
779      cso_save_vertex_shader(renderer->cso);
780
781      renderer_set_custom_fs(renderer, fs,
782                             samplers, views, num_samplers,
783                             const_buffer, const_buffer_len);
784      renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
785
786      tex = views[0]->texture;
787      renderer->u.filter.tex_width = tex->width0;
788      renderer->u.filter.tex_height = tex->height0;
789      renderer->u.filter.use_sampler = VG_TRUE;
790   }
791   else {
792      cso_save_fragment_shader(renderer->cso);
793
794      renderer_set_custom_fs(renderer, fs, NULL, NULL, 0,
795                             const_buffer, const_buffer_len);
796
797      renderer->u.filter.use_sampler = VG_FALSE;
798   }
799
800   renderer->state = RENDERER_STATE_FILTER;
801
802   return VG_TRUE;
803}
804
805/**
806 * Draw into a rectangle of the destination with the specified region of the
807 * texture(s).
808 *
809 * The coordinates are in surface coordinates.
810 */
811void renderer_filter(struct renderer *renderer,
812                    VGint x, VGint y, VGint w, VGint h,
813                    VGint sx, VGint sy, VGint sw, VGint sh)
814{
815   assert(renderer->state == RENDERER_STATE_FILTER);
816
817   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
818   if (renderer->u.filter.use_sampler) {
819      renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
820            renderer->u.filter.tex_width,
821            renderer->u.filter.tex_height);
822   }
823
824   renderer_quad_draw(renderer);
825}
826
827/**
828 * End image filtering and restore the states.
829 */
830void renderer_filter_end(struct renderer *renderer)
831{
832   assert(renderer->state == RENDERER_STATE_FILTER);
833
834   if (renderer->u.filter.use_sampler) {
835      cso_restore_samplers(renderer->cso);
836      cso_restore_fragment_sampler_views(renderer->cso);
837      cso_restore_vertex_shader(renderer->cso);
838   }
839
840   cso_restore_framebuffer(renderer->cso);
841   cso_restore_viewport(renderer->cso);
842   cso_restore_blend(renderer->cso);
843   cso_restore_fragment_shader(renderer->cso);
844
845   renderer->state = RENDERER_STATE_INIT;
846}
847
848/**
849 * Prepare the renderer for polygon silhouette rendering.
850 */
851VGboolean renderer_polygon_stencil_begin(struct renderer *renderer,
852                                         struct pipe_vertex_element *velem,
853                                         VGFillRule rule,
854                                         VGboolean restore_dsa)
855{
856   struct pipe_depth_stencil_alpha_state *dsa;
857   VGboolean manual_two_sides;
858
859   assert(renderer->state == RENDERER_STATE_INIT);
860
861   cso_save_blend(renderer->cso);
862   cso_save_depth_stencil_alpha(renderer->cso);
863
864   cso_set_vertex_elements(renderer->cso, 1, velem);
865
866   /* disable color writes */
867   renderer_set_blend(renderer, 0);
868
869   manual_two_sides = VG_FALSE;
870   dsa = &renderer->u.polygon_stencil.dsa;
871   memset(dsa, 0, sizeof(*dsa));
872   if (rule == VG_EVEN_ODD) {
873      dsa->stencil[0].enabled = 1;
874      dsa->stencil[0].writemask = 1;
875      dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
876      dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
877      dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
878      dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
879      dsa->stencil[0].valuemask = ~0;
880   }
881   else {
882      assert(rule == VG_NON_ZERO);
883
884      /* front face */
885      dsa->stencil[0].enabled = 1;
886      dsa->stencil[0].writemask = ~0;
887      dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
888      dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
889      dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
890      dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
891      dsa->stencil[0].valuemask = ~0;
892
893      if (renderer->pipe->screen->get_param(renderer->pipe->screen,
894                                            PIPE_CAP_TWO_SIDED_STENCIL)) {
895         /* back face */
896         dsa->stencil[1] = dsa->stencil[0];
897         dsa->stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
898      }
899      else {
900         manual_two_sides = VG_TRUE;
901      }
902   }
903   cso_set_depth_stencil_alpha(renderer->cso, dsa);
904
905   if (manual_two_sides)
906      cso_save_rasterizer(renderer->cso);
907
908   renderer->u.polygon_stencil.manual_two_sides = manual_two_sides;
909   renderer->u.polygon_stencil.restore_dsa = restore_dsa;
910   renderer->state = RENDERER_STATE_POLYGON_STENCIL;
911
912   return VG_TRUE;
913}
914
915/**
916 * Render a polygon silhouette to stencil buffer.
917 */
918void renderer_polygon_stencil(struct renderer *renderer,
919                              struct pipe_vertex_buffer *vbuf,
920                              VGuint mode, VGuint start, VGuint count)
921{
922   assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
923
924   renderer->pipe->set_vertex_buffers(renderer->pipe, 1, vbuf);
925
926   if (!renderer->u.polygon_stencil.manual_two_sides) {
927      util_draw_arrays(renderer->pipe, mode, start, count);
928   }
929   else {
930      struct pipe_rasterizer_state raster;
931      struct pipe_depth_stencil_alpha_state dsa;
932
933      /* TODO do not access owner state */
934      raster = renderer->owner->state.g3d.rasterizer;
935      dsa = renderer->u.polygon_stencil.dsa;
936
937      /* front */
938      raster.cull_face = PIPE_FACE_BACK;
939      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
940
941      cso_set_rasterizer(renderer->cso, &raster);
942      cso_set_depth_stencil_alpha(renderer->cso, &dsa);
943      util_draw_arrays(renderer->pipe, mode, start, count);
944
945      /* back */
946      raster.cull_face = PIPE_FACE_FRONT;
947      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
948
949      cso_set_rasterizer(renderer->cso, &raster);
950      cso_set_depth_stencil_alpha(renderer->cso, &dsa);
951      util_draw_arrays(renderer->pipe, mode, start, count);
952   }
953}
954
955/**
956 * End polygon silhouette rendering.
957 */
958void renderer_polygon_stencil_end(struct renderer *renderer)
959{
960   assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
961
962   if (renderer->u.polygon_stencil.manual_two_sides)
963      cso_restore_rasterizer(renderer->cso);
964
965   /* restore color writes */
966   cso_restore_blend(renderer->cso);
967
968   if (renderer->u.polygon_stencil.restore_dsa)
969      cso_restore_depth_stencil_alpha(renderer->cso);
970
971   renderer->state = RENDERER_STATE_INIT;
972}
973
974/**
975 * Prepare the renderer for polygon filling.
976 */
977VGboolean renderer_polygon_fill_begin(struct renderer *renderer,
978                                      VGboolean save_dsa)
979{
980   struct pipe_depth_stencil_alpha_state dsa;
981   struct pipe_stencil_ref sr;
982
983   assert(renderer->state == RENDERER_STATE_INIT);
984
985   if (save_dsa)
986      cso_save_depth_stencil_alpha(renderer->cso);
987
988   /* only need a fixed 0. Rely on default or move it out at least? */
989   memset(&sr, 0, sizeof(sr));
990   cso_set_stencil_ref(renderer->cso, &sr);
991
992   /* setup stencil ops */
993   memset(&dsa, 0, sizeof(dsa));
994   dsa.stencil[0].enabled = 1;
995   dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
996   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
997   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
998   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
999   dsa.stencil[0].valuemask = ~0;
1000   dsa.stencil[0].writemask = ~0;
1001   /* TODO do not access owner state */
1002   dsa.depth = renderer->owner->state.g3d.dsa.depth;
1003   cso_set_depth_stencil_alpha(renderer->cso, &dsa);
1004
1005   renderer->state = RENDERER_STATE_POLYGON_FILL;
1006
1007   return VG_TRUE;
1008}
1009
1010/**
1011 * Fill a polygon.
1012 */
1013void renderer_polygon_fill(struct renderer *renderer,
1014                           VGfloat min_x, VGfloat min_y,
1015                           VGfloat max_x, VGfloat max_y)
1016{
1017   assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
1018
1019   renderer_quad_pos(renderer, min_x, min_y, max_x, max_y, VG_TRUE);
1020   renderer_quad_draw(renderer);
1021}
1022
1023/**
1024 * End polygon filling.
1025 */
1026void renderer_polygon_fill_end(struct renderer *renderer)
1027{
1028   assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
1029
1030   cso_restore_depth_stencil_alpha(renderer->cso);
1031
1032   renderer->state = RENDERER_STATE_INIT;
1033}
1034
1035static void setup_shaders(struct renderer *ctx)
1036{
1037   struct pipe_context *pipe = ctx->pipe;
1038   /* fragment shader */
1039   ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D,
1040                                           TGSI_INTERPOLATE_LINEAR);
1041}
1042
1043struct renderer * renderer_create(struct vg_context *owner)
1044{
1045   VGint i;
1046   struct renderer *renderer = CALLOC_STRUCT(renderer);
1047
1048   if (!renderer)
1049      return NULL;
1050
1051   renderer->owner = owner;
1052   renderer->pipe = owner->pipe;
1053   renderer->cso = owner->cso_context;
1054
1055   setup_shaders(renderer);
1056
1057   /* init vertex data that doesn't change */
1058   for (i = 0; i < 4; i++)
1059      renderer->vertices[i][0][3] = 1.0f; /* w */
1060
1061   renderer->state = RENDERER_STATE_INIT;
1062
1063   return renderer;
1064}
1065
1066void renderer_destroy(struct renderer *ctx)
1067{
1068   int i;
1069
1070   for (i = 0; i < NUM_RENDERER_VS; i++) {
1071      if (ctx->cached_vs[i])
1072         cso_delete_vertex_shader(ctx->cso, ctx->cached_vs[i]);
1073   }
1074   for (i = 0; i < NUM_RENDERER_FS; i++) {
1075      if (ctx->cached_fs[i])
1076         cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]);
1077   }
1078
1079#if 0
1080   if (ctx->fs) {
1081      cso_delete_fragment_shader(ctx->cso, ctx->fs);
1082      ctx->fs = NULL;
1083   }
1084#endif
1085   FREE(ctx);
1086}
1087
1088void renderer_draw_quad(struct renderer *r,
1089                        VGfloat x1, VGfloat y1,
1090                        VGfloat x2, VGfloat y2,
1091                        VGfloat depth)
1092{
1093   assert(r->state == RENDERER_STATE_INIT);
1094   assert(floatsEqual(depth, 0.0f));
1095
1096   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
1097   renderer_quad_draw(r);
1098}
1099
1100void renderer_draw_texture(struct renderer *r,
1101                           struct pipe_resource *tex,
1102                           VGfloat x1offset, VGfloat y1offset,
1103                           VGfloat x2offset, VGfloat y2offset,
1104                           VGfloat x1, VGfloat y1,
1105                           VGfloat x2, VGfloat y2)
1106{
1107   assert(r->state == RENDERER_STATE_INIT);
1108   assert(tex->width0 != 0);
1109   assert(tex->height0 != 0);
1110
1111   cso_save_vertex_shader(r->cso);
1112
1113   renderer_set_vs(r, RENDERER_VS_TEXTURE);
1114
1115   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
1116   renderer_quad_texcoord(r, x1offset, y1offset,
1117         x2offset, y2offset, tex->width0, tex->height0);
1118   renderer_quad_draw(r);
1119
1120   cso_restore_vertex_shader(r->cso);
1121}
1122
1123void renderer_copy_texture(struct renderer *ctx,
1124                           struct pipe_sampler_view *src,
1125                           VGfloat sx1, VGfloat sy1,
1126                           VGfloat sx2, VGfloat sy2,
1127                           struct pipe_resource *dst,
1128                           VGfloat dx1, VGfloat dy1,
1129                           VGfloat dx2, VGfloat dy2)
1130{
1131   struct pipe_surface *surf;
1132   VGint x, y, w, h, sx, sy, sw, sh;
1133
1134   /* get the destination surface */
1135   surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen,
1136         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
1137   if (!surf)
1138      return;
1139
1140   assert(ctx->state == RENDERER_STATE_INIT);
1141   assert(src->texture->width0 != 0);
1142   assert(src->texture->height0 != 0);
1143   assert(dst->width0 != 0);
1144   assert(dst->height0 != 0);
1145
1146   x = (VGint) dx1;
1147   y = (VGint) dy1;
1148   w = (VGint) (dx2 - dx1);
1149   h = (VGint) (dy2 - dy1);
1150   assert(floatsEqual(x, dx1) &&
1151          floatsEqual(y, dy1) &&
1152          floatsEqual(w, (dx2 - dx1)) &&
1153          floatsEqual(h, (dy2 - dy1)));
1154
1155   sx = (VGint) sx1;
1156   sy = (VGint) sy1;
1157   sw = (VGint) (sx2 - sx1);
1158   sh = (VGint) (sy2 - sy1);
1159   assert(floatsEqual(sx, sx1) &&
1160          floatsEqual(sy, sy1) &&
1161          floatsEqual(sw, (sx2 - sx1)) &&
1162          floatsEqual(sh, (sy2 - sy1)));
1163
1164   if (renderer_copy_begin(ctx, surf, VG_TRUE, src)) {
1165      renderer_copy(ctx, x, y, w, h, sx, sy, sw, sh);
1166      renderer_copy_end(ctx);
1167   }
1168
1169   pipe_surface_reference(&surf, NULL);
1170}
1171
1172void renderer_copy_surface(struct renderer *ctx,
1173                           struct pipe_surface *src,
1174                           int srcX0, int srcY0,
1175                           int srcX1, int srcY1,
1176                           struct pipe_surface *dst,
1177                           int dstX0, int dstY0,
1178                           int dstX1, int dstY1,
1179                           float z, unsigned filter)
1180{
1181   struct pipe_context *pipe = ctx->pipe;
1182   struct pipe_screen *screen = pipe->screen;
1183   struct pipe_sampler_view view_templ;
1184   struct pipe_sampler_view *view;
1185   struct pipe_resource texTemp, *tex;
1186   struct pipe_subresource subsrc, subdst;
1187   struct st_framebuffer *stfb = ctx->owner->draw_buffer;
1188   const int srcW = abs(srcX1 - srcX0);
1189   const int srcH = abs(srcY1 - srcY0);
1190   const int srcLeft = MIN2(srcX0, srcX1);
1191   const int srcTop = MIN2(srcY0, srcY1);
1192
1193   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
1194          filter == PIPE_TEX_MIPFILTER_LINEAR);
1195
1196   if (srcLeft != srcX0) {
1197      /* left-right flip */
1198      int tmp = dstX0;
1199      dstX0 = dstX1;
1200      dstX1 = tmp;
1201   }
1202
1203   if (srcTop != srcY0) {
1204      /* up-down flip */
1205      int tmp = dstY0;
1206      dstY0 = dstY1;
1207      dstY1 = tmp;
1208   }
1209
1210   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
1211                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
1212   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
1213                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
1214   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
1215                                      0, PIPE_BIND_RENDER_TARGET, 0));
1216
1217   /*
1218    * XXX for now we're always creating a temporary texture.
1219    * Strictly speaking that's not always needed.
1220    */
1221
1222   /* create temp texture */
1223   memset(&texTemp, 0, sizeof(texTemp));
1224   texTemp.target = PIPE_TEXTURE_2D;
1225   texTemp.format = src->format;
1226   texTemp.last_level = 0;
1227   texTemp.width0 = srcW;
1228   texTemp.height0 = srcH;
1229   texTemp.depth0 = 1;
1230   texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
1231
1232   tex = screen->resource_create(screen, &texTemp);
1233   if (!tex)
1234      return;
1235
1236   u_sampler_view_default_template(&view_templ, tex, tex->format);
1237   view = pipe->create_sampler_view(pipe, tex, &view_templ);
1238
1239   if (!view)
1240      return;
1241
1242   subdst.face = 0;
1243   subdst.level = 0;
1244   subsrc.face = src->face;
1245   subsrc.level = src->level;
1246
1247   pipe->resource_copy_region(pipe,
1248                              tex, subdst, 0, 0, 0,  /* dest */
1249                              src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
1250                              srcW, srcH);     /* size */
1251
1252   assert(floatsEqual(z, 0.0f));
1253
1254   /* draw */
1255   if (stfb->strb->surface == dst) {
1256      /* transform back to surface coordinates */
1257      dstY0 = dst->height - dstY0;
1258      dstY1 = dst->height - dstY1;
1259
1260      if (renderer_drawtex_begin(ctx, view)) {
1261         renderer_drawtex(ctx,
1262               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
1263               0, 0, view->texture->width0, view->texture->height0);
1264         renderer_drawtex_end(ctx);
1265      }
1266   }
1267   else {
1268      if (renderer_copy_begin(ctx, dst, VG_TRUE, view)) {
1269         renderer_copy(ctx,
1270               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
1271               0, 0, view->texture->width0, view->texture->height0);
1272         renderer_copy_end(ctx);
1273      }
1274   }
1275}
1276
1277void renderer_texture_quad(struct renderer *r,
1278                           struct pipe_resource *tex,
1279                           VGfloat x1offset, VGfloat y1offset,
1280                           VGfloat x2offset, VGfloat y2offset,
1281                           VGfloat x1, VGfloat y1,
1282                           VGfloat x2, VGfloat y2,
1283                           VGfloat x3, VGfloat y3,
1284                           VGfloat x4, VGfloat y4)
1285{
1286   const VGfloat z = 0.0f;
1287
1288   assert(r->state == RENDERER_STATE_INIT);
1289   assert(tex->width0 != 0);
1290   assert(tex->height0 != 0);
1291
1292   cso_save_vertex_shader(r->cso);
1293
1294   renderer_set_vs(r, RENDERER_VS_TEXTURE);
1295
1296   /* manually set up positions */
1297   r->vertices[0][0][0] = x1;
1298   r->vertices[0][0][1] = y1;
1299   r->vertices[0][0][2] = z;
1300
1301   r->vertices[1][0][0] = x2;
1302   r->vertices[1][0][1] = y2;
1303   r->vertices[1][0][2] = z;
1304
1305   r->vertices[2][0][0] = x3;
1306   r->vertices[2][0][1] = y3;
1307   r->vertices[2][0][2] = z;
1308
1309   r->vertices[3][0][0] = x4;
1310   r->vertices[3][0][1] = y4;
1311   r->vertices[3][0][2] = z;
1312
1313   /* texcoords */
1314   renderer_quad_texcoord(r, x1offset, y1offset,
1315         x2offset, y2offset, tex->width0, tex->height0);
1316
1317   renderer_quad_draw(r);
1318
1319   cso_restore_vertex_shader(r->cso);
1320}
1321