renderer.c revision e5968a5355f0165aa7f3f8e71a27df884e5a3efb
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   NUM_RENDERER_STATES
55} RendererState;
56
57typedef enum {
58   RENDERER_VS_PLAIN,
59   RENDERER_VS_COLOR,
60   RENDERER_VS_TEXTURE,
61   NUM_RENDERER_VS
62} RendererVs;
63
64typedef enum {
65   RENDERER_FS_COLOR,
66   RENDERER_FS_TEXTURE,
67   RENDERER_FS_SCISSOR,
68   NUM_RENDERER_FS
69} RendererFs;
70
71struct renderer {
72   struct pipe_context *pipe;
73   struct vg_context *owner;
74
75   struct cso_context *cso;
76
77   void *fs;
78
79   VGfloat vertices[4][2][4];
80
81   void *cached_vs[NUM_RENDERER_VS];
82   void *cached_fs[NUM_RENDERER_FS];
83
84   RendererState state;
85
86   /* state data */
87   union {
88      struct {
89         VGint tex_width;
90         VGint tex_height;
91      } copy;
92
93      struct {
94         VGint tex_width;
95         VGint tex_height;
96      } drawtex;
97
98      struct {
99         VGboolean restore_dsa;
100      } scissor;
101
102      struct {
103         VGboolean use_sampler;
104         VGint tex_width, tex_height;
105      } filter;
106   } u;
107};
108
109/**
110 * Return VG_TRUE if the renderer can use the resource as the asked bindings.
111 */
112static VGboolean renderer_can_support(struct renderer *renderer,
113                                      struct pipe_resource *res,
114                                      unsigned bindings)
115{
116   struct pipe_screen *screen = renderer->pipe->screen;
117
118   return screen->is_format_supported(screen,
119         res->format, res->target, 0, bindings, 0);
120}
121
122/**
123 * Create a simple vertex shader that passes through position and the given
124 * attribute.
125 */
126static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name)
127{
128   struct ureg_program *ureg;
129   struct ureg_src src[2], constants[2];
130   struct ureg_dst dst[2], tmp;
131   int i;
132
133   ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
134   if (!ureg)
135      return NULL;
136
137   /* position in surface coordinates */
138   src[0] = ureg_DECL_vs_input(ureg, 0);
139   dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
140   tmp = ureg_DECL_temporary(ureg);
141   for (i = 0; i < 2; i++)
142      constants[i] = ureg_DECL_constant(ureg, i);
143
144   /* transform to clipped coordinates */
145   ureg_MUL(ureg, tmp, src[0], constants[0]);
146   ureg_ADD(ureg, tmp, ureg_src(tmp), constants[1]);
147   ureg_MOV(ureg, dst[0], ureg_src(tmp));
148
149   if (semantic_name >= 0) {
150      src[1] = ureg_DECL_vs_input(ureg, 1);
151      dst[1] = ureg_DECL_output(ureg, semantic_name, 0);
152      ureg_MOV(ureg, dst[1], src[1]);
153   }
154
155   ureg_END(ureg);
156
157   return ureg_create_shader_and_destroy(ureg, pipe);
158}
159
160/**
161 * Set renderer vertex shader.
162 *
163 * This function modifies vertex_shader state.
164 */
165static void renderer_set_vs(struct renderer *r, RendererVs id)
166{
167   /* create as needed */
168   if (!r->cached_vs[id]) {
169      int semantic_name = -1;
170
171      switch (id) {
172      case RENDERER_VS_PLAIN:
173         break;
174      case RENDERER_VS_COLOR:
175         semantic_name = TGSI_SEMANTIC_COLOR;
176         break;
177      case RENDERER_VS_TEXTURE:
178         semantic_name = TGSI_SEMANTIC_GENERIC;
179         break;
180      default:
181         assert(!"Unknown renderer vs id");
182         break;
183      }
184
185      r->cached_vs[id] = create_passthrough_vs(r->pipe, semantic_name);
186   }
187
188   cso_set_vertex_shader_handle(r->cso, r->cached_vs[id]);
189}
190
191/**
192 * Create a simple fragment shader that sets the depth to 0.0f.
193 */
194static void *create_scissor_fs(struct pipe_context *pipe)
195{
196   struct ureg_program *ureg;
197   struct ureg_dst out;
198   struct ureg_src imm;
199
200   ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
201   out = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
202   imm = ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f);
203
204   ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_Z), imm);
205   ureg_END(ureg);
206
207   return ureg_create_shader_and_destroy(ureg, pipe);
208}
209
210/**
211 * Set renderer fragment shader.
212 *
213 * This function modifies fragment_shader state.
214 */
215static void renderer_set_fs(struct renderer *r, RendererFs id)
216{
217   /* create as needed */
218   if (!r->cached_fs[id]) {
219      void *fs = NULL;
220
221      switch (id) {
222      case RENDERER_FS_COLOR:
223         fs = util_make_fragment_passthrough_shader(r->pipe);
224         break;
225      case RENDERER_FS_TEXTURE:
226         fs = util_make_fragment_tex_shader(r->pipe,
227               TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR);
228         break;
229      case RENDERER_FS_SCISSOR:
230         fs = create_scissor_fs(r->pipe);
231         break;
232      default:
233         assert(!"Unknown renderer fs id");
234         break;
235      }
236
237      r->cached_fs[id] = fs;
238   }
239
240   cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]);
241}
242
243/**
244 * Set renderer target.
245 *
246 * This function modifies framebuffer and viewport states.
247 */
248static void renderer_set_target(struct renderer *r,
249                                struct pipe_surface *cbuf,
250                                struct pipe_surface *zsbuf,
251                                VGboolean y0_top)
252{
253   struct pipe_framebuffer_state fb;
254
255   memset(&fb, 0, sizeof(fb));
256   fb.width = cbuf->width;
257   fb.height = cbuf->height;
258   fb.cbufs[0] = cbuf;
259   fb.nr_cbufs = 1;
260   fb.zsbuf = zsbuf;
261   cso_set_framebuffer(r->cso, &fb);
262
263   vg_set_viewport(r->owner, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM);
264}
265
266/**
267 * Set renderer blend state.  Blending is disabled.
268 *
269 * This function modifies blend state.
270 */
271static void renderer_set_blend(struct renderer *r,
272                               VGbitfield channel_mask)
273{
274   struct pipe_blend_state blend;
275
276   memset(&blend, 0, sizeof(blend));
277
278   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
279   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
280   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
281   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
282
283   if (channel_mask & VG_RED)
284      blend.rt[0].colormask |= PIPE_MASK_R;
285   if (channel_mask & VG_GREEN)
286      blend.rt[0].colormask |= PIPE_MASK_G;
287   if (channel_mask & VG_BLUE)
288      blend.rt[0].colormask |= PIPE_MASK_B;
289   if (channel_mask & VG_ALPHA)
290      blend.rt[0].colormask |= PIPE_MASK_A;
291
292   cso_set_blend(r->cso, &blend);
293}
294
295/**
296 * Set renderer sampler and view states.
297 *
298 * This function modifies samplers and fragment_sampler_views states.
299 */
300static void renderer_set_samplers(struct renderer *r,
301                                  uint num_views,
302                                  struct pipe_sampler_view **views)
303{
304   struct pipe_sampler_state sampler;
305   unsigned tex_filter = PIPE_TEX_FILTER_NEAREST;
306   unsigned tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
307   uint i;
308
309   memset(&sampler, 0, sizeof(sampler));
310
311   sampler.min_img_filter = tex_filter;
312   sampler.mag_img_filter = tex_filter;
313   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
314
315   sampler.wrap_s = tex_wrap;
316   sampler.wrap_t = tex_wrap;
317   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
318
319   sampler.normalized_coords = 1;
320
321   /* set samplers */
322   for (i = 0; i < num_views; i++)
323      cso_single_sampler(r->cso, i, &sampler);
324   cso_single_sampler_done(r->cso);
325
326   /* set views */
327   cso_set_fragment_sampler_views(r->cso, num_views, views);
328}
329
330/**
331 * Set custom renderer fragment shader, and optionally set samplers and views
332 * and upload the fragment constant buffer.
333 *
334 * This function modifies fragment_shader, samplers and fragment_sampler_views
335 * states.
336 */
337static void renderer_set_custom_fs(struct renderer *renderer,
338                                   void *fs,
339                                   const struct pipe_sampler_state **samplers,
340                                   struct pipe_sampler_view **views,
341                                   VGint num_samplers,
342                                   const void *const_buffer,
343                                   VGint const_buffer_len)
344{
345   cso_set_fragment_shader_handle(renderer->cso, fs);
346
347   /* set samplers and views */
348   if (num_samplers) {
349      cso_set_samplers(renderer->cso, num_samplers, samplers);
350      cso_set_fragment_sampler_views(renderer->cso, num_samplers, views);
351   }
352
353   /* upload fs constant buffer */
354   if (const_buffer_len) {
355      struct pipe_resource *cbuf;
356
357      cbuf = pipe_buffer_create(renderer->pipe->screen,
358            PIPE_BIND_CONSTANT_BUFFER, const_buffer_len);
359      pipe_buffer_write(renderer->pipe, cbuf, 0,
360            const_buffer_len, const_buffer);
361      renderer->pipe->set_constant_buffer(renderer->pipe,
362            PIPE_SHADER_FRAGMENT, 0, cbuf);
363
364      /* destroy cbuf automatically */
365      pipe_resource_reference(&cbuf, NULL);
366   }
367}
368
369/**
370 * Setup renderer quad position.
371 */
372static void renderer_quad_pos(struct renderer *r,
373                              VGfloat x0, VGfloat y0,
374                              VGfloat x1, VGfloat y1,
375                              VGboolean scissor)
376{
377   VGfloat z;
378
379   /* the depth test is used for scissoring */
380   z = (scissor) ? 0.0f : 1.0f;
381
382   /* positions */
383   r->vertices[0][0][0] = x0;
384   r->vertices[0][0][1] = y0;
385   r->vertices[0][0][2] = z;
386
387   r->vertices[1][0][0] = x1;
388   r->vertices[1][0][1] = y0;
389   r->vertices[1][0][2] = z;
390
391   r->vertices[2][0][0] = x1;
392   r->vertices[2][0][1] = y1;
393   r->vertices[2][0][2] = z;
394
395   r->vertices[3][0][0] = x0;
396   r->vertices[3][0][1] = y1;
397   r->vertices[3][0][2] = z;
398}
399
400/**
401 * Setup renderer quad texture coordinates.
402 */
403static void renderer_quad_texcoord(struct renderer *r,
404                                   VGfloat x0, VGfloat y0,
405                                   VGfloat x1, VGfloat y1,
406                                   VGint tex_width, VGint tex_height)
407{
408   VGfloat s0, t0, s1, t1, r0, q0;
409   VGint i;
410
411   s0 = x0 / tex_width;
412   s1 = x1 / tex_width;
413   t0 = y0 / tex_height;
414   t1 = y1 / tex_height;
415   r0 = 0.0f;
416   q0 = 1.0f;
417
418   /* texcoords */
419   r->vertices[0][1][0] = s0;
420   r->vertices[0][1][1] = t0;
421
422   r->vertices[1][1][0] = s1;
423   r->vertices[1][1][1] = t0;
424
425   r->vertices[2][1][0] = s1;
426   r->vertices[2][1][1] = t1;
427
428   r->vertices[3][1][0] = s0;
429   r->vertices[3][1][1] = t1;
430
431   for (i = 0; i < 4; i++) {
432      r->vertices[i][1][2] = r0;
433      r->vertices[i][1][3] = q0;
434   }
435}
436
437/**
438 * Draw renderer quad.
439 */
440static void renderer_quad_draw(struct renderer *r)
441{
442   struct pipe_resource *buf;
443
444   buf = pipe_user_buffer_create(r->pipe->screen,
445                                 r->vertices,
446                                 sizeof(r->vertices),
447                                 PIPE_BIND_VERTEX_BUFFER);
448   if (buf) {
449      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
450      util_draw_vertex_buffer(r->pipe, buf, 0,
451                              PIPE_PRIM_TRIANGLE_FAN,
452                              Elements(r->vertices),     /* verts */
453                              Elements(r->vertices[0])); /* attribs/vert */
454
455      pipe_resource_reference(&buf, NULL);
456   }
457}
458
459/**
460 * Prepare the renderer for copying.
461 */
462VGboolean renderer_copy_begin(struct renderer *renderer,
463                              struct pipe_surface *dst,
464                              VGboolean y0_top,
465                              struct pipe_sampler_view *src)
466{
467   assert(renderer->state == RENDERER_STATE_INIT);
468
469   /* sanity check */
470   if (!renderer_can_support(renderer,
471            dst->texture, PIPE_BIND_RENDER_TARGET) ||
472       !renderer_can_support(renderer,
473          src->texture, PIPE_BIND_SAMPLER_VIEW))
474      return VG_FALSE;
475
476   cso_save_framebuffer(renderer->cso);
477   cso_save_viewport(renderer->cso);
478   cso_save_blend(renderer->cso);
479   cso_save_samplers(renderer->cso);
480   cso_save_fragment_sampler_views(renderer->cso);
481   cso_save_fragment_shader(renderer->cso);
482   cso_save_vertex_shader(renderer->cso);
483
484   renderer_set_target(renderer, dst, NULL, y0_top);
485
486   renderer_set_blend(renderer, ~0);
487   renderer_set_samplers(renderer, 1, &src);
488
489   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
490   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
491
492   /* remember the texture size */
493   renderer->u.copy.tex_width = src->texture->width0;
494   renderer->u.copy.tex_height = src->texture->height0;
495   renderer->state = RENDERER_STATE_COPY;
496
497   return VG_TRUE;
498}
499
500/**
501 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
502 * sampled from within the rectangle given by (sx, sy, sw, sh).
503 *
504 * The coordinates are in surface coordinates.
505 */
506void renderer_copy(struct renderer *renderer,
507                   VGint x, VGint y, VGint w, VGint h,
508                   VGint sx, VGint sy, VGint sw, VGint sh)
509{
510   assert(renderer->state == RENDERER_STATE_COPY);
511
512   /* there is no depth buffer for scissoring anyway */
513   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
514   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
515         renderer->u.copy.tex_width,
516         renderer->u.copy.tex_height);
517
518   renderer_quad_draw(renderer);
519}
520
521/**
522 * End copying and restore the states.
523 */
524void renderer_copy_end(struct renderer *renderer)
525{
526   assert(renderer->state == RENDERER_STATE_COPY);
527
528   cso_restore_framebuffer(renderer->cso);
529   cso_restore_viewport(renderer->cso);
530   cso_restore_blend(renderer->cso);
531   cso_restore_samplers(renderer->cso);
532   cso_restore_fragment_sampler_views(renderer->cso);
533   cso_restore_fragment_shader(renderer->cso);
534   cso_restore_vertex_shader(renderer->cso);
535
536   renderer->state = RENDERER_STATE_INIT;
537}
538
539/**
540 * Prepare the renderer for textured drawing.
541 */
542VGboolean renderer_drawtex_begin(struct renderer *renderer,
543                                 struct pipe_sampler_view *src)
544{
545   assert(renderer->state == RENDERER_STATE_INIT);
546
547   if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW))
548      return VG_FALSE;
549
550   cso_save_blend(renderer->cso);
551   cso_save_samplers(renderer->cso);
552   cso_save_fragment_sampler_views(renderer->cso);
553   cso_save_fragment_shader(renderer->cso);
554   cso_save_vertex_shader(renderer->cso);
555
556   renderer_set_blend(renderer, ~0);
557
558   renderer_set_samplers(renderer, 1, &src);
559
560   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
561   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
562
563   /* remember the texture size */
564   renderer->u.drawtex.tex_width = src->texture->width0;
565   renderer->u.drawtex.tex_height = src->texture->height0;
566   renderer->state = RENDERER_STATE_DRAWTEX;
567
568   return VG_TRUE;
569}
570
571/**
572 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
573 * sampled from within the rectangle given by (sx, sy, sw, sh).
574 *
575 * The coordinates are in surface coordinates.
576 */
577void renderer_drawtex(struct renderer *renderer,
578                      VGint x, VGint y, VGint w, VGint h,
579                      VGint sx, VGint sy, VGint sw, VGint sh)
580{
581   assert(renderer->state == RENDERER_STATE_DRAWTEX);
582
583   /* with scissoring */
584   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_TRUE);
585   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
586         renderer->u.drawtex.tex_width,
587         renderer->u.drawtex.tex_height);
588
589   renderer_quad_draw(renderer);
590}
591
592/**
593 * End textured drawing and restore the states.
594 */
595void renderer_drawtex_end(struct renderer *renderer)
596{
597   assert(renderer->state == RENDERER_STATE_DRAWTEX);
598
599   cso_restore_blend(renderer->cso);
600   cso_restore_samplers(renderer->cso);
601   cso_restore_fragment_sampler_views(renderer->cso);
602   cso_restore_fragment_shader(renderer->cso);
603   cso_restore_vertex_shader(renderer->cso);
604
605   renderer->state = RENDERER_STATE_INIT;
606}
607
608/**
609 * Prepare the renderer for scissor update.  This will reset the depth buffer
610 * to 1.0f.
611 */
612VGboolean renderer_scissor_begin(struct renderer *renderer,
613                                 VGboolean restore_dsa)
614{
615   struct pipe_depth_stencil_alpha_state dsa;
616
617   assert(renderer->state == RENDERER_STATE_INIT);
618
619   if (restore_dsa)
620      cso_save_depth_stencil_alpha(renderer->cso);
621   cso_save_blend(renderer->cso);
622   cso_save_fragment_shader(renderer->cso);
623
624   /* enable depth writes */
625   memset(&dsa, 0, sizeof(dsa));
626   dsa.depth.enabled = 1;
627   dsa.depth.writemask = 1;
628   dsa.depth.func = PIPE_FUNC_ALWAYS;
629   cso_set_depth_stencil_alpha(renderer->cso, &dsa);
630
631   /* disable color writes */
632   renderer_set_blend(renderer, 0);
633   renderer_set_fs(renderer, RENDERER_FS_SCISSOR);
634
635   renderer->u.scissor.restore_dsa = restore_dsa;
636   renderer->state = RENDERER_STATE_SCISSOR;
637
638   /* clear the depth buffer to 1.0f */
639   renderer->pipe->clear(renderer->pipe,
640         PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0f, 0);
641
642   return VG_TRUE;
643}
644
645/**
646 * Add a scissor rectangle.  Depth values inside the rectangle will be set to
647 * 0.0f.
648 */
649void renderer_scissor(struct renderer *renderer,
650                      VGint x, VGint y, VGint width, VGint height)
651{
652   assert(renderer->state == RENDERER_STATE_SCISSOR);
653
654   renderer_quad_pos(renderer, x, y, x + width, y + height, VG_FALSE);
655   renderer_quad_draw(renderer);
656}
657
658/**
659 * End scissor update and restore the states.
660 */
661void renderer_scissor_end(struct renderer *renderer)
662{
663   assert(renderer->state == RENDERER_STATE_SCISSOR);
664
665   if (renderer->u.scissor.restore_dsa)
666      cso_restore_depth_stencil_alpha(renderer->cso);
667   cso_restore_blend(renderer->cso);
668   cso_restore_fragment_shader(renderer->cso);
669
670   renderer->state = RENDERER_STATE_INIT;
671}
672
673/**
674 * Prepare the renderer for clearing.
675 */
676VGboolean renderer_clear_begin(struct renderer *renderer)
677{
678   assert(renderer->state == RENDERER_STATE_INIT);
679
680   cso_save_blend(renderer->cso);
681   cso_save_fragment_shader(renderer->cso);
682   cso_save_vertex_shader(renderer->cso);
683
684   renderer_set_blend(renderer, ~0);
685   renderer_set_fs(renderer, RENDERER_FS_COLOR);
686   renderer_set_vs(renderer, RENDERER_VS_COLOR);
687
688   renderer->state = RENDERER_STATE_CLEAR;
689
690   return VG_TRUE;
691}
692
693/**
694 * Clear the framebuffer with the specified region and color.
695 *
696 * The coordinates are in surface coordinates.
697 */
698void renderer_clear(struct renderer *renderer,
699                    VGint x, VGint y, VGint width, VGint height,
700                    const VGfloat color[4])
701{
702   VGuint i;
703
704   assert(renderer->state == RENDERER_STATE_CLEAR);
705
706   renderer_quad_pos(renderer, x, y, x + width, y + height, VG_TRUE);
707   for (i = 0; i < 4; i++)
708      memcpy(renderer->vertices[i][1], color, sizeof(VGfloat) * 4);
709
710   renderer_quad_draw(renderer);
711}
712
713/**
714 * End clearing and retore the states.
715 */
716void renderer_clear_end(struct renderer *renderer)
717{
718   assert(renderer->state == RENDERER_STATE_CLEAR);
719
720   cso_restore_blend(renderer->cso);
721   cso_restore_fragment_shader(renderer->cso);
722   cso_restore_vertex_shader(renderer->cso);
723
724   renderer->state = RENDERER_STATE_INIT;
725}
726
727/**
728 * Prepare the renderer for image filtering.
729 */
730VGboolean renderer_filter_begin(struct renderer *renderer,
731                                struct pipe_resource *dst,
732                                VGboolean y0_top,
733                                VGbitfield channel_mask,
734                                const struct pipe_sampler_state **samplers,
735                                struct pipe_sampler_view **views,
736                                VGint num_samplers,
737                                void *fs,
738                                const void *const_buffer,
739                                VGint const_buffer_len)
740{
741   struct pipe_surface *surf;
742
743   assert(renderer->state == RENDERER_STATE_INIT);
744
745   if (!fs)
746      return VG_FALSE;
747   if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET))
748      return VG_FALSE;
749
750   surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen,
751         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
752   if (!surf)
753      return VG_FALSE;
754
755   cso_save_framebuffer(renderer->cso);
756   cso_save_viewport(renderer->cso);
757   cso_save_blend(renderer->cso);
758
759   /* set the image as the target */
760   renderer_set_target(renderer, surf, NULL, y0_top);
761   pipe_surface_reference(&surf, NULL);
762
763   renderer_set_blend(renderer, channel_mask);
764
765   if (num_samplers) {
766      struct pipe_resource *tex;
767
768      cso_save_samplers(renderer->cso);
769      cso_save_fragment_sampler_views(renderer->cso);
770      cso_save_fragment_shader(renderer->cso);
771      cso_save_vertex_shader(renderer->cso);
772
773      renderer_set_custom_fs(renderer, fs,
774                             samplers, views, num_samplers,
775                             const_buffer, const_buffer_len);
776      renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
777
778      tex = views[0]->texture;
779      renderer->u.filter.tex_width = tex->width0;
780      renderer->u.filter.tex_height = tex->height0;
781      renderer->u.filter.use_sampler = VG_TRUE;
782   }
783   else {
784      cso_save_fragment_shader(renderer->cso);
785
786      renderer_set_custom_fs(renderer, fs, NULL, NULL, 0,
787                             const_buffer, const_buffer_len);
788
789      renderer->u.filter.use_sampler = VG_FALSE;
790   }
791
792   renderer->state = RENDERER_STATE_FILTER;
793
794   return VG_TRUE;
795}
796
797/**
798 * Draw into a rectangle of the destination with the specified region of the
799 * texture(s).
800 *
801 * The coordinates are in surface coordinates.
802 */
803void renderer_filter(struct renderer *renderer,
804                    VGint x, VGint y, VGint w, VGint h,
805                    VGint sx, VGint sy, VGint sw, VGint sh)
806{
807   assert(renderer->state == RENDERER_STATE_FILTER);
808
809   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
810   if (renderer->u.filter.use_sampler) {
811      renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
812            renderer->u.filter.tex_width,
813            renderer->u.filter.tex_height);
814   }
815
816   renderer_quad_draw(renderer);
817}
818
819/**
820 * End image filtering and restore the states.
821 */
822void renderer_filter_end(struct renderer *renderer)
823{
824   assert(renderer->state == RENDERER_STATE_FILTER);
825
826   if (renderer->u.filter.use_sampler) {
827      cso_restore_samplers(renderer->cso);
828      cso_restore_fragment_sampler_views(renderer->cso);
829      cso_restore_vertex_shader(renderer->cso);
830   }
831
832   cso_restore_framebuffer(renderer->cso);
833   cso_restore_viewport(renderer->cso);
834   cso_restore_blend(renderer->cso);
835   cso_restore_fragment_shader(renderer->cso);
836
837   renderer->state = RENDERER_STATE_INIT;
838}
839
840static void setup_shaders(struct renderer *ctx)
841{
842   struct pipe_context *pipe = ctx->pipe;
843   /* fragment shader */
844   ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D,
845                                           TGSI_INTERPOLATE_LINEAR);
846}
847
848struct renderer * renderer_create(struct vg_context *owner)
849{
850   VGint i;
851   struct renderer *renderer = CALLOC_STRUCT(renderer);
852
853   if (!renderer)
854      return NULL;
855
856   renderer->owner = owner;
857   renderer->pipe = owner->pipe;
858   renderer->cso = owner->cso_context;
859
860   setup_shaders(renderer);
861
862   /* init vertex data that doesn't change */
863   for (i = 0; i < 4; i++)
864      renderer->vertices[i][0][3] = 1.0f; /* w */
865
866   renderer->state = RENDERER_STATE_INIT;
867
868   return renderer;
869}
870
871void renderer_destroy(struct renderer *ctx)
872{
873   int i;
874
875   for (i = 0; i < NUM_RENDERER_VS; i++) {
876      if (ctx->cached_vs[i])
877         cso_delete_vertex_shader(ctx->cso, ctx->cached_vs[i]);
878   }
879   for (i = 0; i < NUM_RENDERER_FS; i++) {
880      if (ctx->cached_fs[i])
881         cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]);
882   }
883
884#if 0
885   if (ctx->fs) {
886      cso_delete_fragment_shader(ctx->cso, ctx->fs);
887      ctx->fs = NULL;
888   }
889#endif
890   FREE(ctx);
891}
892
893void renderer_draw_quad(struct renderer *r,
894                        VGfloat x1, VGfloat y1,
895                        VGfloat x2, VGfloat y2,
896                        VGfloat depth)
897{
898   assert(r->state == RENDERER_STATE_INIT);
899   assert(floatsEqual(depth, 0.0f));
900
901   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
902   renderer_quad_draw(r);
903}
904
905void renderer_draw_texture(struct renderer *r,
906                           struct pipe_resource *tex,
907                           VGfloat x1offset, VGfloat y1offset,
908                           VGfloat x2offset, VGfloat y2offset,
909                           VGfloat x1, VGfloat y1,
910                           VGfloat x2, VGfloat y2)
911{
912   assert(r->state == RENDERER_STATE_INIT);
913   assert(tex->width0 != 0);
914   assert(tex->height0 != 0);
915
916   cso_save_vertex_shader(r->cso);
917
918   renderer_set_vs(r, RENDERER_VS_TEXTURE);
919
920   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
921   renderer_quad_texcoord(r, x1offset, y1offset,
922         x2offset, y2offset, tex->width0, tex->height0);
923   renderer_quad_draw(r);
924
925   cso_restore_vertex_shader(r->cso);
926}
927
928void renderer_copy_texture(struct renderer *ctx,
929                           struct pipe_sampler_view *src,
930                           VGfloat sx1, VGfloat sy1,
931                           VGfloat sx2, VGfloat sy2,
932                           struct pipe_resource *dst,
933                           VGfloat dx1, VGfloat dy1,
934                           VGfloat dx2, VGfloat dy2)
935{
936   struct pipe_surface *surf;
937   VGint x, y, w, h, sx, sy, sw, sh;
938
939   /* get the destination surface */
940   surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen,
941         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
942   if (!surf)
943      return;
944
945   assert(ctx->state == RENDERER_STATE_INIT);
946   assert(src->texture->width0 != 0);
947   assert(src->texture->height0 != 0);
948   assert(dst->width0 != 0);
949   assert(dst->height0 != 0);
950
951   x = (VGint) dx1;
952   y = (VGint) dy1;
953   w = (VGint) (dx2 - dx1);
954   h = (VGint) (dy2 - dy1);
955   assert(floatsEqual(x, dx1) &&
956          floatsEqual(y, dy1) &&
957          floatsEqual(w, (dx2 - dx1)) &&
958          floatsEqual(h, (dy2 - dy1)));
959
960   sx = (VGint) sx1;
961   sy = (VGint) sy1;
962   sw = (VGint) (sx2 - sx1);
963   sh = (VGint) (sy2 - sy1);
964   assert(floatsEqual(sx, sx1) &&
965          floatsEqual(sy, sy1) &&
966          floatsEqual(sw, (sx2 - sx1)) &&
967          floatsEqual(sh, (sy2 - sy1)));
968
969   if (renderer_copy_begin(ctx, surf, VG_TRUE, src)) {
970      renderer_copy(ctx, x, y, w, h, sx, sy, sw, sh);
971      renderer_copy_end(ctx);
972   }
973
974   pipe_surface_reference(&surf, NULL);
975}
976
977void renderer_copy_surface(struct renderer *ctx,
978                           struct pipe_surface *src,
979                           int srcX0, int srcY0,
980                           int srcX1, int srcY1,
981                           struct pipe_surface *dst,
982                           int dstX0, int dstY0,
983                           int dstX1, int dstY1,
984                           float z, unsigned filter)
985{
986   struct pipe_context *pipe = ctx->pipe;
987   struct pipe_screen *screen = pipe->screen;
988   struct pipe_sampler_view view_templ;
989   struct pipe_sampler_view *view;
990   struct pipe_resource texTemp, *tex;
991   struct pipe_subresource subsrc, subdst;
992   struct st_framebuffer *stfb = ctx->owner->draw_buffer;
993   const int srcW = abs(srcX1 - srcX0);
994   const int srcH = abs(srcY1 - srcY0);
995   const int srcLeft = MIN2(srcX0, srcX1);
996   const int srcTop = MIN2(srcY0, srcY1);
997
998   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
999          filter == PIPE_TEX_MIPFILTER_LINEAR);
1000
1001   if (srcLeft != srcX0) {
1002      /* left-right flip */
1003      int tmp = dstX0;
1004      dstX0 = dstX1;
1005      dstX1 = tmp;
1006   }
1007
1008   if (srcTop != srcY0) {
1009      /* up-down flip */
1010      int tmp = dstY0;
1011      dstY0 = dstY1;
1012      dstY1 = tmp;
1013   }
1014
1015   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
1016                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
1017   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
1018                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
1019   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
1020                                      0, PIPE_BIND_RENDER_TARGET, 0));
1021
1022   /*
1023    * XXX for now we're always creating a temporary texture.
1024    * Strictly speaking that's not always needed.
1025    */
1026
1027   /* create temp texture */
1028   memset(&texTemp, 0, sizeof(texTemp));
1029   texTemp.target = PIPE_TEXTURE_2D;
1030   texTemp.format = src->format;
1031   texTemp.last_level = 0;
1032   texTemp.width0 = srcW;
1033   texTemp.height0 = srcH;
1034   texTemp.depth0 = 1;
1035   texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
1036
1037   tex = screen->resource_create(screen, &texTemp);
1038   if (!tex)
1039      return;
1040
1041   u_sampler_view_default_template(&view_templ, tex, tex->format);
1042   view = pipe->create_sampler_view(pipe, tex, &view_templ);
1043
1044   if (!view)
1045      return;
1046
1047   subdst.face = 0;
1048   subdst.level = 0;
1049   subsrc.face = src->face;
1050   subsrc.level = src->level;
1051
1052   pipe->resource_copy_region(pipe,
1053                              tex, subdst, 0, 0, 0,  /* dest */
1054                              src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
1055                              srcW, srcH);     /* size */
1056
1057   assert(floatsEqual(z, 0.0f));
1058
1059   /* draw */
1060   if (stfb->strb->surface == dst) {
1061      /* transform back to surface coordinates */
1062      dstY0 = dst->height - dstY0;
1063      dstY1 = dst->height - dstY1;
1064
1065      if (renderer_drawtex_begin(ctx, view)) {
1066         renderer_drawtex(ctx,
1067               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
1068               0, 0, view->texture->width0, view->texture->height0);
1069         renderer_drawtex_end(ctx);
1070      }
1071   }
1072   else {
1073      if (renderer_copy_begin(ctx, dst, VG_TRUE, view)) {
1074         renderer_copy(ctx,
1075               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
1076               0, 0, view->texture->width0, view->texture->height0);
1077         renderer_copy_end(ctx);
1078      }
1079   }
1080}
1081
1082void renderer_texture_quad(struct renderer *r,
1083                           struct pipe_resource *tex,
1084                           VGfloat x1offset, VGfloat y1offset,
1085                           VGfloat x2offset, VGfloat y2offset,
1086                           VGfloat x1, VGfloat y1,
1087                           VGfloat x2, VGfloat y2,
1088                           VGfloat x3, VGfloat y3,
1089                           VGfloat x4, VGfloat y4)
1090{
1091   const VGfloat z = 0.0f;
1092
1093   assert(r->state == RENDERER_STATE_INIT);
1094   assert(tex->width0 != 0);
1095   assert(tex->height0 != 0);
1096
1097   cso_save_vertex_shader(r->cso);
1098
1099   renderer_set_vs(r, RENDERER_VS_TEXTURE);
1100
1101   /* manually set up positions */
1102   r->vertices[0][0][0] = x1;
1103   r->vertices[0][0][1] = y1;
1104   r->vertices[0][0][2] = z;
1105
1106   r->vertices[1][0][0] = x2;
1107   r->vertices[1][0][1] = y2;
1108   r->vertices[1][0][2] = z;
1109
1110   r->vertices[2][0][0] = x3;
1111   r->vertices[2][0][1] = y3;
1112   r->vertices[2][0][2] = z;
1113
1114   r->vertices[3][0][0] = x4;
1115   r->vertices[3][0][1] = y4;
1116   r->vertices[3][0][2] = z;
1117
1118   /* texcoords */
1119   renderer_quad_texcoord(r, x1offset, y1offset,
1120         x2offset, y2offset, tex->width0, tex->height0);
1121
1122   renderer_quad_draw(r);
1123
1124   cso_restore_vertex_shader(r->cso);
1125}
1126