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