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