vg_context.c revision 0d3a6a505d537b879f31be0ed14fa8577717efaf
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 "vg_context.h"
28
29#include "paint.h"
30#include "renderer.h"
31#include "shaders_cache.h"
32#include "shader.h"
33#include "asm_util.h"
34#include "st_inlines.h"
35
36#include "pipe/p_context.h"
37#include "pipe/p_inlines.h"
38#include "pipe/p_shader_tokens.h"
39
40#include "cso_cache/cso_context.h"
41
42#include "util/u_simple_shaders.h"
43#include "util/u_memory.h"
44#include "util/u_blit.h"
45
46struct vg_context *_vg_context = 0;
47
48struct vg_context * vg_current_context(void)
49{
50   return _vg_context;
51}
52
53static void init_clear(struct vg_context *st)
54{
55   struct pipe_context *pipe = st->pipe;
56
57   /* rasterizer state: bypass clipping */
58   memset(&st->clear.raster, 0, sizeof(st->clear.raster));
59   st->clear.raster.gl_rasterization_rules = 1;
60
61   /* fragment shader state: color pass-through program */
62   st->clear.fs =
63      util_make_fragment_passthrough_shader(pipe);
64}
65void vg_set_current_context(struct vg_context *ctx)
66{
67   _vg_context = ctx;
68}
69
70struct vg_context * vg_create_context(struct pipe_context *pipe,
71                                      const void *visual,
72                                      struct vg_context *share)
73{
74   struct vg_context *ctx;
75
76   ctx = CALLOC_STRUCT(vg_context);
77
78   ctx->pipe = pipe;
79
80   vg_init_state(&ctx->state.vg);
81   ctx->state.dirty = ALL_DIRTY;
82
83   ctx->cso_context = cso_create_context(pipe);
84
85   init_clear(ctx);
86
87   ctx->default_paint = paint_create(ctx);
88   ctx->state.vg.stroke_paint = ctx->default_paint;
89   ctx->state.vg.fill_paint = ctx->default_paint;
90
91
92   ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
93   ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
94   ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
95   ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
96   ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
97   ctx->mask.sampler.normalized_coords = 0;
98
99   ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
100   ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
101   ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
102   ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
103   ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
104   ctx->blend_sampler.normalized_coords = 0;
105
106   vg_set_error(ctx, VG_NO_ERROR);
107
108   ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
109   ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
110   ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
111   ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
112   ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
113
114   ctx->renderer = renderer_create(ctx);
115   ctx->sc = shaders_cache_create(ctx);
116   ctx->shader = shader_create(ctx);
117
118   ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
119
120   return ctx;
121}
122
123void vg_destroy_context(struct vg_context *ctx)
124{
125   struct pipe_buffer **cbuf = &ctx->mask.cbuf;
126   struct pipe_buffer **vsbuf = &ctx->vs_const_buffer;
127
128   util_destroy_blit(ctx->blit);
129   renderer_destroy(ctx->renderer);
130   shaders_cache_destroy(ctx->sc);
131   shader_destroy(ctx->shader);
132   paint_destroy(ctx->default_paint);
133
134   if (*cbuf)
135      pipe_buffer_reference(cbuf, NULL);
136
137   if (*vsbuf)
138      pipe_buffer_reference(vsbuf, NULL);
139
140   if (ctx->clear.fs) {
141      cso_delete_fragment_shader(ctx->cso_context, ctx->clear.fs);
142      ctx->clear.fs = NULL;
143   }
144
145   if (ctx->plain_vs) {
146      vg_shader_destroy(ctx, ctx->plain_vs);
147      ctx->plain_vs = NULL;
148   }
149   if (ctx->clear_vs) {
150      vg_shader_destroy(ctx, ctx->clear_vs);
151      ctx->clear_vs = NULL;
152   }
153   if (ctx->texture_vs) {
154      vg_shader_destroy(ctx, ctx->texture_vs);
155      ctx->texture_vs = NULL;
156   }
157
158   if (ctx->pass_through_depth_fs)
159      vg_shader_destroy(ctx, ctx->pass_through_depth_fs);
160   if (ctx->mask.union_fs)
161      vg_shader_destroy(ctx, ctx->mask.union_fs);
162   if (ctx->mask.intersect_fs)
163      vg_shader_destroy(ctx, ctx->mask.intersect_fs);
164   if (ctx->mask.subtract_fs)
165      vg_shader_destroy(ctx, ctx->mask.subtract_fs);
166   if (ctx->mask.set_fs)
167      vg_shader_destroy(ctx, ctx->mask.set_fs);
168
169   cso_release_all(ctx->cso_context);
170   cso_destroy_context(ctx->cso_context);
171
172   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
173   cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
174   cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
175   cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
176   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
177
178   free(ctx);
179}
180
181void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
182{
183   obj->type = type;
184   obj->ctx = ctx;
185}
186
187VGboolean vg_context_is_object_valid(struct vg_context *ctx,
188                                enum vg_object_type type,
189                                void *ptr)
190{
191    if (ctx) {
192       struct cso_hash *hash = ctx->owned_objects[type];
193       if (!hash)
194          return VG_FALSE;
195       return cso_hash_contains(hash, (unsigned)(long)ptr);
196    }
197    return VG_FALSE;
198}
199
200void vg_context_add_object(struct vg_context *ctx,
201                           enum vg_object_type type,
202                           void *ptr)
203{
204    if (ctx) {
205       struct cso_hash *hash = ctx->owned_objects[type];
206       if (!hash)
207          return;
208       cso_hash_insert(hash, (unsigned)(long)ptr, ptr);
209    }
210}
211
212void vg_context_remove_object(struct vg_context *ctx,
213                              enum vg_object_type type,
214                              void *ptr)
215{
216   if (ctx) {
217      struct cso_hash *hash = ctx->owned_objects[type];
218      if (!hash)
219         return;
220      cso_hash_take(hash, (unsigned)(long)ptr);
221   }
222}
223
224static void update_clip_state(struct vg_context *ctx)
225{
226   struct pipe_depth_stencil_alpha_state *dsa = &ctx->state.g3d.dsa;
227   struct vg_state *state =  &ctx->state.vg;
228
229   memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
230
231   if (state->scissoring) {
232      struct pipe_blend_state *blend = &ctx->state.g3d.blend;
233      struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
234      int i;
235
236      dsa->depth.writemask = 1;/*glDepthMask(TRUE);*/
237      dsa->depth.func = PIPE_FUNC_ALWAYS;
238      dsa->depth.enabled = 1;
239
240      cso_save_blend(ctx->cso_context);
241      cso_save_fragment_shader(ctx->cso_context);
242      /* set a passthrough shader */
243      if (!ctx->pass_through_depth_fs)
244         ctx->pass_through_depth_fs = shader_create_from_text(ctx->pipe,
245                                                              pass_through_depth_asm,
246                                                              40,
247                                                              PIPE_SHADER_FRAGMENT);
248      cso_set_fragment_shader_handle(ctx->cso_context,
249                                     ctx->pass_through_depth_fs->driver);
250      cso_set_depth_stencil_alpha(ctx->cso_context, dsa);
251
252      ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0, 0);
253
254      /* disable color writes */
255      blend->rt[0].colormask = 0; /*disable colorwrites*/
256      cso_set_blend(ctx->cso_context, blend);
257
258      /* enable scissoring */
259      for (i = 0; i < state->scissor_rects_num; ++i) {
260         const float x      = state->scissor_rects[i * 4 + 0].f;
261         const float y      = state->scissor_rects[i * 4 + 1].f;
262         const float width  = state->scissor_rects[i * 4 + 2].f;
263         const float height = state->scissor_rects[i * 4 + 3].f;
264         VGfloat minx, miny, maxx, maxy;
265
266         minx = 0;
267         miny = 0;
268         maxx = fb->width;
269         maxy = fb->height;
270
271         if (x > minx)
272            minx = x;
273         if (y > miny)
274            miny = y;
275
276         if (x + width < maxx)
277            maxx = x + width;
278         if (y + height < maxy)
279            maxy = y + height;
280
281         /* check for null space */
282         if (minx >= maxx || miny >= maxy)
283            minx = miny = maxx = maxy = 0;
284
285         /*glClear(GL_DEPTH_BUFFER_BIT);*/
286         renderer_draw_quad(ctx->renderer, minx, miny, maxx, maxy, 0.0f);
287      }
288
289      cso_restore_blend(ctx->cso_context);
290      cso_restore_fragment_shader(ctx->cso_context);
291
292      dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */
293      dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/
294      dsa->depth.func = PIPE_FUNC_GEQUAL;
295   }
296}
297
298void vg_validate_state(struct vg_context *ctx)
299{
300   if ((ctx->state.dirty & BLEND_DIRTY)) {
301      struct pipe_blend_state *blend = &ctx->state.g3d.blend;
302      memset(blend, 0, sizeof(struct pipe_blend_state));
303      blend->rt[0].blend_enable = 1;
304      blend->rt[0].colormask = PIPE_MASK_RGBA;
305
306      switch (ctx->state.vg.blend_mode) {
307      case VG_BLEND_SRC:
308         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
309         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
310         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
311         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
312         blend->rt[0].blend_enable = 0;
313         break;
314      case VG_BLEND_SRC_OVER:
315         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
316         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
317         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
318         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
319         break;
320      case VG_BLEND_DST_OVER:
321         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_INV_DST_ALPHA;
322         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
323         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
324         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
325         break;
326      case VG_BLEND_SRC_IN:
327         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
328         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
329         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
330         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
331         break;
332      case VG_BLEND_DST_IN:
333         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ZERO;
334         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
335         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
336         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
337         break;
338      case VG_BLEND_MULTIPLY:
339      case VG_BLEND_SCREEN:
340      case VG_BLEND_DARKEN:
341      case VG_BLEND_LIGHTEN:
342         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
343         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
344         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
345         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
346         blend->rt[0].blend_enable = 0;
347         break;
348      case VG_BLEND_ADDITIVE:
349         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
350         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
351         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ONE;
352         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
353         break;
354      default:
355         assert(!"not implemented blend mode");
356      }
357      cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend);
358   }
359   if ((ctx->state.dirty & RASTERIZER_DIRTY)) {
360      struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer;
361      memset(raster, 0, sizeof(struct pipe_rasterizer_state));
362      raster->gl_rasterization_rules = 1;
363      cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer);
364   }
365   if ((ctx->state.dirty & VIEWPORT_DIRTY)) {
366      struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
367      const VGint param_bytes = 8 * sizeof(VGfloat);
368      VGfloat vs_consts[8] = {
369         2.f/fb->width, 2.f/fb->height, 1, 1,
370         -1, -1, 0, 0
371      };
372      struct pipe_buffer **cbuf = &ctx->vs_const_buffer;
373
374      vg_set_viewport(ctx, VEGA_Y0_BOTTOM);
375
376      pipe_buffer_reference(cbuf, NULL);
377      *cbuf = pipe_buffer_create(ctx->pipe->screen, 16,
378                                        PIPE_BUFFER_USAGE_CONSTANT,
379                                        param_bytes);
380
381      if (*cbuf) {
382         st_no_flush_pipe_buffer_write(ctx, *cbuf,
383                                       0, param_bytes, vs_consts);
384      }
385      ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, *cbuf);
386   }
387   if ((ctx->state.dirty & VS_DIRTY)) {
388      cso_set_vertex_shader_handle(ctx->cso_context,
389                                   vg_plain_vs(ctx));
390   }
391
392   /* must be last because it renders to the depth buffer*/
393   if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) {
394      update_clip_state(ctx);
395      cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa);
396   }
397
398   shader_set_masking(ctx->shader, ctx->state.vg.masking);
399   shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
400
401   ctx->state.dirty = NONE_DIRTY;
402}
403
404VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type)
405{
406   struct vg_object *obj = ptr;
407   if (ptr && is_aligned(obj) && obj->type == type)
408      return VG_TRUE;
409   else
410      return VG_FALSE;
411}
412
413void vg_set_error(struct vg_context *ctx,
414                  VGErrorCode code)
415{
416   /*vgGetError returns the oldest error code provided by
417    * an API call on the current context since the previous
418    * call to vgGetError on that context (or since the creation
419    of the context).*/
420   if (ctx->_error == VG_NO_ERROR)
421      ctx->_error = code;
422}
423
424void vg_prepare_blend_surface(struct vg_context *ctx)
425{
426   struct pipe_surface *dest_surface = NULL;
427   struct pipe_context *pipe = ctx->pipe;
428   struct st_framebuffer *stfb = ctx->draw_buffer;
429   struct st_renderbuffer *strb = stfb->strb;
430
431   /* first finish all pending rendering */
432   vgFinish();
433
434   dest_surface = pipe->screen->get_tex_surface(pipe->screen,
435                                                stfb->blend_texture,
436                                                0, 0, 0,
437                                                PIPE_BUFFER_USAGE_GPU_WRITE);
438   /* flip it, because we want to use it as a sampler */
439   util_blit_pixels_tex(ctx->blit,
440                        strb->texture,
441                        0, strb->height,
442                        strb->width, 0,
443                        dest_surface,
444                        0, 0,
445                        strb->width, strb->height,
446                        0.0, PIPE_TEX_MIPFILTER_NEAREST);
447
448   if (dest_surface)
449      pipe_surface_reference(&dest_surface, NULL);
450
451   /* make sure it's complete */
452   vgFinish();
453}
454
455
456void vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
457{
458   struct pipe_surface *dest_surface = NULL;
459   struct pipe_context *pipe = ctx->pipe;
460   struct st_framebuffer *stfb = ctx->draw_buffer;
461   struct st_renderbuffer *strb = stfb->strb;
462
463   vg_validate_state(ctx);
464
465   /* first finish all pending rendering */
466   vgFinish();
467
468   dest_surface = pipe->screen->get_tex_surface(pipe->screen,
469                                                stfb->blend_texture,
470                                                0, 0, 0,
471                                                PIPE_BUFFER_USAGE_GPU_WRITE);
472
473   /* flip it, because we want to use it as a sampler */
474   util_blit_pixels_tex(ctx->blit,
475                        stfb->alpha_mask,
476                        0, strb->height,
477                        strb->width, 0,
478                        dest_surface,
479                        0, 0,
480                        strb->width, strb->height,
481                        0.0, PIPE_TEX_MIPFILTER_NEAREST);
482
483   /* make sure it's complete */
484   vgFinish();
485
486   if (dest_surface)
487      pipe_surface_reference(&dest_surface, NULL);
488}
489
490void * vg_plain_vs(struct vg_context *ctx)
491{
492   if (!ctx->plain_vs) {
493      ctx->plain_vs = shader_create_from_text(ctx->pipe,
494                                              vs_plain_asm,
495                                              200,
496                                              PIPE_SHADER_VERTEX);
497   }
498
499   return ctx->plain_vs->driver;
500}
501
502
503void * vg_clear_vs(struct vg_context *ctx)
504{
505   if (!ctx->clear_vs) {
506      ctx->clear_vs = shader_create_from_text(ctx->pipe,
507                                              vs_clear_asm,
508                                              200,
509                                              PIPE_SHADER_VERTEX);
510   }
511
512   return ctx->clear_vs->driver;
513}
514
515void * vg_texture_vs(struct vg_context *ctx)
516{
517   if (!ctx->texture_vs) {
518      ctx->texture_vs = shader_create_from_text(ctx->pipe,
519                                                vs_texture_asm,
520                                                200,
521                                                PIPE_SHADER_VERTEX);
522   }
523
524   return ctx->texture_vs->driver;
525}
526
527void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation)
528{
529   struct pipe_viewport_state viewport;
530   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
531   VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f;
532
533   viewport.scale[0] =  fb->width / 2.f;
534   viewport.scale[1] =  fb->height / y_scale;
535   viewport.scale[2] =  1.0;
536   viewport.scale[3] =  1.0;
537   viewport.translate[0] = fb->width / 2.f;
538   viewport.translate[1] = fb->height / 2.f;
539   viewport.translate[2] = 0.0;
540   viewport.translate[3] = 0.0;
541
542   cso_set_viewport(ctx->cso_context, &viewport);
543}
544