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