renderer.c revision decf6ed810eae473d043a4a399a5a84f1378a725
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
452   tex = screen->texture_create(screen, &texTemp);
453   if (!tex)
454      return;
455
456   texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0,
457                                     PIPE_BUFFER_USAGE_GPU_WRITE);
458
459   /* load temp texture */
460   if (pipe->surface_copy) {
461      pipe->surface_copy(pipe,
462                         texSurf, 0, 0,   /* dest */
463                         src, srcLeft, srcTop, /* src */
464                         srcW, srcH);     /* size */
465   } else {
466      util_surface_copy(pipe, FALSE,
467                        texSurf, 0, 0,   /* dest */
468                        src, srcLeft, srcTop, /* src */
469                        srcW, srcH);     /* size */
470   }
471
472   /* free the surface, update the texture if necessary.*/
473   screen->tex_surface_destroy(texSurf);
474
475   /* save state (restored below) */
476   cso_save_blend(ctx->cso);
477   cso_save_samplers(ctx->cso);
478   cso_save_sampler_textures(ctx->cso);
479   cso_save_framebuffer(ctx->cso);
480   cso_save_fragment_shader(ctx->cso);
481   cso_save_vertex_shader(ctx->cso);
482   cso_save_viewport(ctx->cso);
483
484   /* set misc state we care about */
485   {
486      struct pipe_blend_state blend;
487      memset(&blend, 0, sizeof(blend));
488      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
489      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
490      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
491      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
492      blend.colormask = PIPE_MASK_RGBA;
493      cso_set_blend(ctx->cso, &blend);
494   }
495
496   vg_set_viewport(ctx->owner, VEGA_Y0_TOP);
497
498   /* sampler */
499   {
500      struct pipe_sampler_state sampler;
501      memset(&sampler, 0, sizeof(sampler));
502      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
503      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
504      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
505      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
506      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
507      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
508      sampler.normalized_coords = 1;
509      cso_single_sampler(ctx->cso, 0, &sampler);
510      cso_single_sampler_done(ctx->cso);
511   }
512
513   /* texture */
514   cso_set_sampler_textures(ctx->cso, 1, &tex);
515
516   /* shaders */
517   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
518   cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner));
519
520   /* drawing dest */
521   if (stfb->strb->surface != dst) {
522      memset(&fb, 0, sizeof(fb));
523      fb.width = dst->width;
524      fb.height = dst->height;
525      fb.nr_cbufs = 1;
526      fb.cbufs[0] = dst;
527      fb.zsbuf = stfb->dsrb->surface;
528      cso_set_framebuffer(ctx->cso, &fb);
529   }
530
531   /* draw quad */
532   buf = setup_vertex_data(ctx,
533                           (float) dstX0, (float) dstY0,
534                           (float) dstX1, (float) dstY1, z);
535
536   if (buf) {
537      util_draw_vertex_buffer(ctx->pipe, buf, 0,
538                              PIPE_PRIM_TRIANGLE_FAN,
539                              4,  /* verts */
540                              2); /* attribs/vert */
541
542      pipe_buffer_reference( &buf,
543                             NULL );
544   }
545
546
547   /* restore state we changed */
548   cso_restore_blend(ctx->cso);
549   cso_restore_samplers(ctx->cso);
550   cso_restore_sampler_textures(ctx->cso);
551   cso_restore_framebuffer(ctx->cso);
552   cso_restore_fragment_shader(ctx->cso);
553   cso_restore_vertex_shader(ctx->cso);
554   cso_restore_viewport(ctx->cso);
555
556   pipe_texture_reference(&tex, NULL);
557}
558
559void renderer_texture_quad(struct renderer *r,
560                           struct pipe_texture *tex,
561                           VGfloat x1offset, VGfloat y1offset,
562                           VGfloat x2offset, VGfloat y2offset,
563                           VGfloat x1, VGfloat y1,
564                           VGfloat x2, VGfloat y2,
565                           VGfloat x3, VGfloat y3,
566                           VGfloat x4, VGfloat y4)
567{
568   struct pipe_context *pipe = r->pipe;
569   struct pipe_buffer *buf;
570   VGfloat s0, t0, s1, t1;
571
572   assert(tex->width0 != 0);
573   assert(tex->height0 != 0);
574
575   s0 = x1offset / tex->width0;
576   s1 = x2offset / tex->width0;
577   t0 = y1offset / tex->height0;
578   t1 = y2offset / tex->height0;
579
580   cso_save_vertex_shader(r->cso);
581   /* shaders */
582   cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner));
583
584   /* draw quad */
585   buf = setup_vertex_data_qtex(r, x1, y1, x2, y2, x3, y3, x4, y4,
586                          s0, t0, s1, t1, 0.0f);
587
588   if (buf) {
589      util_draw_vertex_buffer(pipe, buf, 0,
590                              PIPE_PRIM_TRIANGLE_FAN,
591                              4,  /* verts */
592                              2); /* attribs/vert */
593
594      pipe_buffer_reference(&buf,
595                            NULL);
596   }
597
598   cso_restore_vertex_shader(r->cso);
599}
600