renderer.c revision d18fb4822bc71944867b66e6de966e4e55bbe574
1/**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.  All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include "renderer.h"
28
29#include "vg_context.h"
30
31#include "pipe/p_context.h"
32#include "pipe/p_state.h"
33#include "util/u_inlines.h"
34#include "pipe/p_screen.h"
35#include "pipe/p_shader_tokens.h"
36
37#include "util/u_draw_quad.h"
38#include "util/u_format.h"
39#include "util/u_simple_shaders.h"
40#include "util/u_memory.h"
41#include "util/u_rect.h"
42#include "util/u_sampler.h"
43#include "util/u_surface.h"
44
45#include "cso_cache/cso_context.h"
46
47struct renderer {
48   struct pipe_context *pipe;
49   struct vg_context *owner;
50
51   struct cso_context *cso;
52
53   void *fs;
54
55   VGfloat vertices[4][2][4];
56};
57
58static void setup_shaders(struct renderer *ctx)
59{
60   struct pipe_context *pipe = ctx->pipe;
61   /* fragment shader */
62   ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D,
63                                           TGSI_INTERPOLATE_LINEAR);
64}
65
66static struct pipe_resource *
67setup_vertex_data(struct renderer *ctx,
68                  float x0, float y0, float x1, float y1, float z)
69{
70   ctx->vertices[0][0][0] = x0;
71   ctx->vertices[0][0][1] = y0;
72   ctx->vertices[0][0][2] = z;
73   ctx->vertices[0][1][0] = 0.0f; /*s*/
74   ctx->vertices[0][1][1] = 0.0f; /*t*/
75
76   ctx->vertices[1][0][0] = x1;
77   ctx->vertices[1][0][1] = y0;
78   ctx->vertices[1][0][2] = z;
79   ctx->vertices[1][1][0] = 1.0f; /*s*/
80   ctx->vertices[1][1][1] = 0.0f; /*t*/
81
82   ctx->vertices[2][0][0] = x1;
83   ctx->vertices[2][0][1] = y1;
84   ctx->vertices[2][0][2] = z;
85   ctx->vertices[2][1][0] = 1.0f;
86   ctx->vertices[2][1][1] = 1.0f;
87
88   ctx->vertices[3][0][0] = x0;
89   ctx->vertices[3][0][1] = y1;
90   ctx->vertices[3][0][2] = z;
91   ctx->vertices[3][1][0] = 0.0f;
92   ctx->vertices[3][1][1] = 1.0f;
93
94   return pipe_user_buffer_create( ctx->pipe->screen,
95                                   ctx->vertices,
96                                   sizeof(ctx->vertices),
97				   PIPE_BIND_VERTEX_BUFFER);
98}
99
100static struct pipe_resource *
101setup_vertex_data_tex(struct renderer *ctx,
102                      float x0, float y0, float x1, float y1,
103                      float s0, float t0, float s1, float t1,
104                      float z)
105{
106   ctx->vertices[0][0][0] = x0;
107   ctx->vertices[0][0][1] = y0;
108   ctx->vertices[0][0][2] = z;
109   ctx->vertices[0][1][0] = s0; /*s*/
110   ctx->vertices[0][1][1] = t0; /*t*/
111
112   ctx->vertices[1][0][0] = x1;
113   ctx->vertices[1][0][1] = y0;
114   ctx->vertices[1][0][2] = z;
115   ctx->vertices[1][1][0] = s1; /*s*/
116   ctx->vertices[1][1][1] = t0; /*t*/
117
118   ctx->vertices[2][0][0] = x1;
119   ctx->vertices[2][0][1] = y1;
120   ctx->vertices[2][0][2] = z;
121   ctx->vertices[2][1][0] = s1;
122   ctx->vertices[2][1][1] = t1;
123
124   ctx->vertices[3][0][0] = x0;
125   ctx->vertices[3][0][1] = y1;
126   ctx->vertices[3][0][2] = z;
127   ctx->vertices[3][1][0] = s0;
128   ctx->vertices[3][1][1] = t1;
129
130   return pipe_user_buffer_create( ctx->pipe->screen,
131                                   ctx->vertices,
132                                   sizeof(ctx->vertices),
133				   PIPE_BIND_VERTEX_BUFFER);
134}
135
136
137static struct pipe_resource *
138setup_vertex_data_qtex(struct renderer *ctx,
139                       float x0, float y0, float x1, float y1,
140                       float x2, float y2, float x3, float y3,
141                       float s0, float t0, float s1, float t1,
142                       float z)
143{
144   ctx->vertices[0][0][0] = x0;
145   ctx->vertices[0][0][1] = y0;
146   ctx->vertices[0][0][2] = z;
147   ctx->vertices[0][1][0] = s0; /*s*/
148   ctx->vertices[0][1][1] = t0; /*t*/
149
150   ctx->vertices[1][0][0] = x1;
151   ctx->vertices[1][0][1] = y1;
152   ctx->vertices[1][0][2] = z;
153   ctx->vertices[1][1][0] = s1; /*s*/
154   ctx->vertices[1][1][1] = t0; /*t*/
155
156   ctx->vertices[2][0][0] = x2;
157   ctx->vertices[2][0][1] = y2;
158   ctx->vertices[2][0][2] = z;
159   ctx->vertices[2][1][0] = s1;
160   ctx->vertices[2][1][1] = t1;
161
162   ctx->vertices[3][0][0] = x3;
163   ctx->vertices[3][0][1] = y3;
164   ctx->vertices[3][0][2] = z;
165   ctx->vertices[3][1][0] = s0;
166   ctx->vertices[3][1][1] = t1;
167
168   return pipe_user_buffer_create( ctx->pipe->screen,
169                                   ctx->vertices,
170                                   sizeof(ctx->vertices),
171				   PIPE_BIND_VERTEX_BUFFER);
172}
173
174struct renderer * renderer_create(struct vg_context *owner)
175{
176   VGint i;
177   struct renderer *renderer = CALLOC_STRUCT(renderer);
178
179   if (!renderer)
180      return NULL;
181
182   renderer->owner = owner;
183   renderer->pipe = owner->pipe;
184   renderer->cso = owner->cso_context;
185
186   setup_shaders(renderer);
187
188   /* init vertex data that doesn't change */
189   for (i = 0; i < 4; i++) {
190      renderer->vertices[i][0][3] = 1.0f; /* w */
191      renderer->vertices[i][1][2] = 0.0f; /* r */
192      renderer->vertices[i][1][3] = 1.0f; /* q */
193   }
194
195   return renderer;
196}
197
198void renderer_destroy(struct renderer *ctx)
199{
200#if 0
201   if (ctx->fs) {
202      cso_delete_fragment_shader(ctx->cso, ctx->fs);
203      ctx->fs = NULL;
204   }
205#endif
206   free(ctx);
207}
208
209void renderer_draw_quad(struct renderer *r,
210                        VGfloat x1, VGfloat y1,
211                        VGfloat x2, VGfloat y2,
212                        VGfloat depth)
213{
214   struct pipe_resource *buf;
215
216   buf = setup_vertex_data(r, x1, y1, x2, y2, depth);
217
218   if (buf) {
219      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
220      util_draw_vertex_buffer(r->pipe, buf, 0,
221                              PIPE_PRIM_TRIANGLE_FAN,
222                              4,  /* verts */
223                              2); /* attribs/vert */
224
225      pipe_resource_reference( &buf,
226                             NULL );
227   }
228}
229
230void renderer_draw_texture(struct renderer *r,
231                           struct pipe_resource *tex,
232                           VGfloat x1offset, VGfloat y1offset,
233                           VGfloat x2offset, VGfloat y2offset,
234                           VGfloat x1, VGfloat y1,
235                           VGfloat x2, VGfloat y2)
236{
237   struct pipe_context *pipe = r->pipe;
238   struct pipe_resource *buf;
239   VGfloat s0, t0, s1, t1;
240
241   assert(tex->width0 != 0);
242   assert(tex->height0 != 0);
243
244   s0 = x1offset / tex->width0;
245   s1 = x2offset / tex->width0;
246   t0 = y1offset / tex->height0;
247   t1 = y2offset / tex->height0;
248
249   cso_save_vertex_shader(r->cso);
250   /* shaders */
251   cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner));
252
253   /* draw quad */
254   buf = setup_vertex_data_tex(r, x1, y1, x2, y2,
255                               s0, t0, s1, t1, 0.0f);
256
257   if (buf) {
258      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
259      util_draw_vertex_buffer(pipe, buf, 0,
260                           PIPE_PRIM_TRIANGLE_FAN,
261                           4,  /* verts */
262                           2); /* attribs/vert */
263
264      pipe_resource_reference( &buf,
265                             NULL );
266   }
267
268   cso_restore_vertex_shader(r->cso);
269}
270
271void renderer_copy_texture(struct renderer *ctx,
272                           struct pipe_sampler_view *src,
273                           VGfloat sx1, VGfloat sy1,
274                           VGfloat sx2, VGfloat sy2,
275                           struct pipe_resource *dst,
276                           VGfloat dx1, VGfloat dy1,
277                           VGfloat dx2, VGfloat dy2)
278{
279   struct pipe_context *pipe = ctx->pipe;
280   struct pipe_screen *screen = pipe->screen;
281   struct pipe_resource *tex = src->texture;
282   struct pipe_resource *buf;
283   struct pipe_surface *dst_surf = screen->get_tex_surface(
284      screen, dst, 0, 0, 0,
285      PIPE_BIND_RENDER_TARGET);
286   struct pipe_framebuffer_state fb;
287   float s0, t0, s1, t1;
288
289   assert(tex->width0 != 0);
290   assert(tex->height0 != 0);
291   assert(dst->width0 != 0);
292   assert(dst->height0 != 0);
293
294#if 0
295   debug_printf("copy texture [%f, %f, %f, %f], [%f, %f, %f, %f]\n",
296                sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
297#endif
298
299#if 1
300   s0 = sx1 / tex->width0;
301   s1 = sx2 / tex->width0;
302   t0 = sy1 / tex->height0;
303   t1 = sy2 / tex->height0;
304#else
305   s0 = 0;
306   s1 = 1;
307   t0 = 0;
308   t1 = 1;
309#endif
310
311   assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D,
312                                      0, PIPE_BIND_RENDER_TARGET, 0));
313
314   /* save state (restored below) */
315   cso_save_blend(ctx->cso);
316   cso_save_samplers(ctx->cso);
317   cso_save_fragment_sampler_views(ctx->cso);
318   cso_save_framebuffer(ctx->cso);
319   cso_save_fragment_shader(ctx->cso);
320   cso_save_vertex_shader(ctx->cso);
321
322   cso_save_viewport(ctx->cso);
323
324
325   /* set misc state we care about */
326   {
327      struct pipe_blend_state blend;
328      memset(&blend, 0, sizeof(blend));
329      blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
330      blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
331      blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
332      blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
333      blend.rt[0].colormask = PIPE_MASK_RGBA;
334      cso_set_blend(ctx->cso, &blend);
335   }
336
337   /* sampler */
338   {
339      struct pipe_sampler_state sampler;
340      memset(&sampler, 0, sizeof(sampler));
341      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
342      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
343      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
344      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
345      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
346      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
347      sampler.normalized_coords = 1;
348      cso_single_sampler(ctx->cso, 0, &sampler);
349      cso_single_sampler_done(ctx->cso);
350   }
351
352   vg_set_viewport(ctx->owner, VEGA_Y0_TOP);
353
354   /* texture */
355   cso_set_fragment_sampler_views(ctx->cso, 1, &src);
356
357   /* shaders */
358   cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner));
359   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
360
361   /* drawing dest */
362   memset(&fb, 0, sizeof(fb));
363   fb.width = dst_surf->width;
364   fb.height = dst_surf->height;
365   fb.nr_cbufs = 1;
366   fb.cbufs[0] = dst_surf;
367   {
368      VGint i;
369      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
370         fb.cbufs[i] = 0;
371   }
372   cso_set_framebuffer(ctx->cso, &fb);
373
374   /* draw quad */
375   buf = setup_vertex_data_tex(ctx,
376                         dx1, dy1,
377                         dx2, dy2,
378                         s0, t0, s1, t1,
379                         0.0f);
380
381   if (buf) {
382      cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems);
383      util_draw_vertex_buffer(ctx->pipe, buf, 0,
384                              PIPE_PRIM_TRIANGLE_FAN,
385                              4,  /* verts */
386                              2); /* attribs/vert */
387
388      pipe_resource_reference( &buf,
389                             NULL );
390   }
391
392   /* restore state we changed */
393   cso_restore_blend(ctx->cso);
394   cso_restore_samplers(ctx->cso);
395   cso_restore_fragment_sampler_views(ctx->cso);
396   cso_restore_framebuffer(ctx->cso);
397   cso_restore_vertex_shader(ctx->cso);
398   cso_restore_fragment_shader(ctx->cso);
399   cso_restore_viewport(ctx->cso);
400
401   pipe_surface_reference(&dst_surf, NULL);
402}
403
404void renderer_copy_surface(struct renderer *ctx,
405                           struct pipe_surface *src,
406                           int srcX0, int srcY0,
407                           int srcX1, int srcY1,
408                           struct pipe_surface *dst,
409                           int dstX0, int dstY0,
410                           int dstX1, int dstY1,
411                           float z, unsigned filter)
412{
413   struct pipe_context *pipe = ctx->pipe;
414   struct pipe_screen *screen = pipe->screen;
415   struct pipe_resource *buf;
416   struct pipe_sampler_view view_templ;
417   struct pipe_sampler_view *view;
418   struct pipe_resource texTemp, *tex;
419   struct pipe_subresource subsrc, subdst;
420   struct pipe_framebuffer_state fb;
421   struct st_framebuffer *stfb = ctx->owner->draw_buffer;
422   const int srcW = abs(srcX1 - srcX0);
423   const int srcH = abs(srcY1 - srcY0);
424   const int srcLeft = MIN2(srcX0, srcX1);
425   const int srcTop = MIN2(srcY0, srcY1);
426
427   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
428          filter == PIPE_TEX_MIPFILTER_LINEAR);
429
430   if (srcLeft != srcX0) {
431      /* left-right flip */
432      int tmp = dstX0;
433      dstX0 = dstX1;
434      dstX1 = tmp;
435   }
436
437   if (srcTop != srcY0) {
438      /* up-down flip */
439      int tmp = dstY0;
440      dstY0 = dstY1;
441      dstY1 = tmp;
442   }
443
444   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
445                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
446   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
447                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
448   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
449                                      0, PIPE_BIND_RENDER_TARGET, 0));
450
451   /*
452    * XXX for now we're always creating a temporary texture.
453    * Strictly speaking that's not always needed.
454    */
455
456   /* create temp texture */
457   memset(&texTemp, 0, sizeof(texTemp));
458   texTemp.target = PIPE_TEXTURE_2D;
459   texTemp.format = src->format;
460   texTemp.last_level = 0;
461   texTemp.width0 = srcW;
462   texTemp.height0 = srcH;
463   texTemp.depth0 = 1;
464   texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
465
466   tex = screen->resource_create(screen, &texTemp);
467   if (!tex)
468      return;
469
470   u_sampler_view_default_template(&view_templ, tex, tex->format);
471   view = pipe->create_sampler_view(pipe, tex, &view_templ);
472
473   if (!view)
474      return;
475
476   subdst.face = 0;
477   subdst.level = 0;
478   subsrc.face = src->face;
479   subsrc.level = src->level;
480
481   pipe->resource_copy_region(pipe,
482                              tex, subdst, 0, 0, 0,  /* dest */
483                              src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
484                              srcW, srcH);     /* size */
485
486   /* save state (restored below) */
487   cso_save_blend(ctx->cso);
488   cso_save_samplers(ctx->cso);
489   cso_save_fragment_sampler_views(ctx->cso);
490   cso_save_framebuffer(ctx->cso);
491   cso_save_fragment_shader(ctx->cso);
492   cso_save_vertex_shader(ctx->cso);
493   cso_save_viewport(ctx->cso);
494
495   /* set misc state we care about */
496   {
497      struct pipe_blend_state blend;
498      memset(&blend, 0, sizeof(blend));
499      blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
500      blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
501      blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
502      blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
503      blend.rt[0].colormask = PIPE_MASK_RGBA;
504      cso_set_blend(ctx->cso, &blend);
505   }
506
507   vg_set_viewport(ctx->owner, VEGA_Y0_TOP);
508
509   /* sampler */
510   {
511      struct pipe_sampler_state sampler;
512      memset(&sampler, 0, sizeof(sampler));
513      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
514      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
515      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
516      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
517      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
518      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
519      sampler.normalized_coords = 1;
520      cso_single_sampler(ctx->cso, 0, &sampler);
521      cso_single_sampler_done(ctx->cso);
522   }
523
524   /* texture */
525   cso_set_fragment_sampler_views(ctx->cso, 1, &view);
526
527   /* shaders */
528   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
529   cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner));
530
531   /* drawing dest */
532   if (stfb->strb->surface != dst) {
533      memset(&fb, 0, sizeof(fb));
534      fb.width = dst->width;
535      fb.height = dst->height;
536      fb.nr_cbufs = 1;
537      fb.cbufs[0] = dst;
538      fb.zsbuf = stfb->dsrb->surface;
539      cso_set_framebuffer(ctx->cso, &fb);
540   }
541
542   /* draw quad */
543   buf = setup_vertex_data(ctx,
544                           (float) dstX0, (float) dstY0,
545                           (float) dstX1, (float) dstY1, z);
546
547   if (buf) {
548      cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems);
549      util_draw_vertex_buffer(ctx->pipe, buf, 0,
550                              PIPE_PRIM_TRIANGLE_FAN,
551                              4,  /* verts */
552                              2); /* attribs/vert */
553
554      pipe_resource_reference( &buf,
555                             NULL );
556   }
557
558
559   /* restore state we changed */
560   cso_restore_blend(ctx->cso);
561   cso_restore_samplers(ctx->cso);
562   cso_restore_fragment_sampler_views(ctx->cso);
563   cso_restore_framebuffer(ctx->cso);
564   cso_restore_fragment_shader(ctx->cso);
565   cso_restore_vertex_shader(ctx->cso);
566   cso_restore_viewport(ctx->cso);
567
568   pipe_resource_reference(&tex, NULL);
569   pipe_sampler_view_reference(&view, NULL);
570}
571
572void renderer_texture_quad(struct renderer *r,
573                           struct pipe_resource *tex,
574                           VGfloat x1offset, VGfloat y1offset,
575                           VGfloat x2offset, VGfloat y2offset,
576                           VGfloat x1, VGfloat y1,
577                           VGfloat x2, VGfloat y2,
578                           VGfloat x3, VGfloat y3,
579                           VGfloat x4, VGfloat y4)
580{
581   struct pipe_context *pipe = r->pipe;
582   struct pipe_resource *buf;
583   VGfloat s0, t0, s1, t1;
584
585   assert(tex->width0 != 0);
586   assert(tex->height0 != 0);
587
588   s0 = x1offset / tex->width0;
589   s1 = x2offset / tex->width0;
590   t0 = y1offset / tex->height0;
591   t1 = y2offset / tex->height0;
592
593   cso_save_vertex_shader(r->cso);
594   /* shaders */
595   cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner));
596
597   /* draw quad */
598   buf = setup_vertex_data_qtex(r, x1, y1, x2, y2, x3, y3, x4, y4,
599                          s0, t0, s1, t1, 0.0f);
600
601   if (buf) {
602      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
603      util_draw_vertex_buffer(pipe, buf, 0,
604                              PIPE_PRIM_TRIANGLE_FAN,
605                              4,  /* verts */
606                              2); /* attribs/vert */
607
608      pipe_resource_reference(&buf,
609                            NULL);
610   }
611
612   cso_restore_vertex_shader(r->cso);
613}
614