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