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