vg_context.c revision 3f0a966807f03a364edea0272ddf45f08ab7ce4f
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 "vg_manager.h"
34#include "api.h"
35#include "mask.h"
36#include "handle.h"
37
38#include "pipe/p_context.h"
39#include "util/u_inlines.h"
40
41#include "cso_cache/cso_context.h"
42
43#include "util/u_memory.h"
44#include "util/u_blit.h"
45#include "util/u_sampler.h"
46#include "util/u_surface.h"
47#include "util/u_format.h"
48
49struct vg_context *_vg_context = 0;
50
51struct vg_context * vg_current_context(void)
52{
53   return _vg_context;
54}
55
56/**
57 * A depth/stencil rb will be needed regardless of what the visual says.
58 */
59static boolean
60choose_depth_stencil_format(struct vg_context *ctx)
61{
62   struct pipe_screen *screen = ctx->pipe->screen;
63   enum pipe_format formats[] = {
64      PIPE_FORMAT_Z24_UNORM_S8_USCALED,
65      PIPE_FORMAT_S8_USCALED_Z24_UNORM,
66      PIPE_FORMAT_NONE
67   };
68   enum pipe_format *fmt;
69
70   for (fmt = formats; *fmt != PIPE_FORMAT_NONE; fmt++) {
71      if (screen->is_format_supported(screen, *fmt,
72               PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0))
73         break;
74   }
75
76   ctx->ds_format = *fmt;
77
78   return (ctx->ds_format != PIPE_FORMAT_NONE);
79}
80
81void vg_set_current_context(struct vg_context *ctx)
82{
83   _vg_context = ctx;
84   api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
85}
86
87struct vg_context * vg_create_context(struct pipe_context *pipe,
88                                      const void *visual,
89                                      struct vg_context *share)
90{
91   struct vg_context *ctx;
92
93   ctx = CALLOC_STRUCT(vg_context);
94
95   ctx->pipe = pipe;
96   if (!choose_depth_stencil_format(ctx)) {
97      FREE(ctx);
98      return NULL;
99   }
100
101   ctx->dispatch = api_create_dispatch();
102
103   vg_init_state(&ctx->state.vg);
104   ctx->state.dirty = ALL_DIRTY;
105
106   ctx->cso_context = cso_create_context(pipe);
107
108   ctx->default_paint = paint_create(ctx);
109   ctx->state.vg.stroke_paint = ctx->default_paint;
110   ctx->state.vg.fill_paint = ctx->default_paint;
111
112
113   ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
114   ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
115   ctx->mask.sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
116   ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
117   ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
118   ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
119   ctx->mask.sampler.normalized_coords = 0;
120
121   ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
122   ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
123   ctx->blend_sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
124   ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
125   ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
126   ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
127   ctx->blend_sampler.normalized_coords = 0;
128
129   vg_set_error(ctx, VG_NO_ERROR);
130
131   ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
132   ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
133   ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
134   ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
135   ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
136
137   ctx->renderer = renderer_create(ctx);
138   ctx->sc = shaders_cache_create(ctx);
139   ctx->shader = shader_create(ctx);
140
141   ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
142
143   return ctx;
144}
145
146void vg_destroy_context(struct vg_context *ctx)
147{
148   struct pipe_resource **cbuf = &ctx->mask.cbuf;
149
150   util_destroy_blit(ctx->blit);
151   renderer_destroy(ctx->renderer);
152   shaders_cache_destroy(ctx->sc);
153   shader_destroy(ctx->shader);
154   paint_destroy(ctx->default_paint);
155
156   if (*cbuf)
157      pipe_resource_reference(cbuf, NULL);
158
159   if (ctx->mask.union_fs)
160      vg_shader_destroy(ctx, ctx->mask.union_fs);
161   if (ctx->mask.intersect_fs)
162      vg_shader_destroy(ctx, ctx->mask.intersect_fs);
163   if (ctx->mask.subtract_fs)
164      vg_shader_destroy(ctx, ctx->mask.subtract_fs);
165   if (ctx->mask.set_fs)
166      vg_shader_destroy(ctx, ctx->mask.set_fs);
167
168   cso_release_all(ctx->cso_context);
169   cso_destroy_context(ctx->cso_context);
170
171   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
172   cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
173   cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
174   cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
175   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
176
177   api_destroy_dispatch(ctx->dispatch);
178
179   FREE(ctx);
180}
181
182void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
183{
184   obj->type = type;
185   obj->ctx = ctx;
186   obj->handle = create_handle(obj);
187}
188
189/** free object resources, but not the object itself */
190void vg_free_object(struct vg_object *obj)
191{
192   obj->type = 0;
193   obj->ctx = NULL;
194   destroy_handle(obj->handle);
195}
196
197VGboolean vg_context_is_object_valid(struct vg_context *ctx,
198                                enum vg_object_type type,
199                                VGHandle object)
200{
201    if (ctx) {
202       struct cso_hash *hash = ctx->owned_objects[type];
203       if (!hash)
204          return VG_FALSE;
205       return cso_hash_contains(hash, (unsigned)(long)object);
206    }
207    return VG_FALSE;
208}
209
210void vg_context_add_object(struct vg_context *ctx,
211                           enum vg_object_type type,
212                           void *ptr)
213{
214    if (ctx) {
215       struct cso_hash *hash = ctx->owned_objects[type];
216       if (!hash)
217          return;
218       cso_hash_insert(hash, (unsigned)(long)ptr, ptr);
219    }
220}
221
222void vg_context_remove_object(struct vg_context *ctx,
223                              enum vg_object_type type,
224                              void *ptr)
225{
226   if (ctx) {
227      struct cso_hash *hash = ctx->owned_objects[type];
228      if (!hash)
229         return;
230      cso_hash_take(hash, (unsigned)(long)ptr);
231   }
232}
233
234static struct pipe_resource *
235create_texture(struct pipe_context *pipe, enum pipe_format format,
236                    VGint width, VGint height)
237{
238   struct pipe_resource templ;
239
240   memset(&templ, 0, sizeof(templ));
241
242   if (format != PIPE_FORMAT_NONE) {
243      templ.format = format;
244   }
245   else {
246      templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
247   }
248
249   templ.target = PIPE_TEXTURE_2D;
250   templ.width0 = width;
251   templ.height0 = height;
252   templ.depth0 = 1;
253   templ.array_size = 1;
254   templ.last_level = 0;
255
256   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
257      templ.bind = PIPE_BIND_DEPTH_STENCIL;
258   } else {
259      templ.bind = (PIPE_BIND_DISPLAY_TARGET |
260                    PIPE_BIND_RENDER_TARGET |
261                    PIPE_BIND_SAMPLER_VIEW);
262   }
263
264   return pipe->screen->resource_create(pipe->screen, &templ);
265}
266
267static struct pipe_sampler_view *
268create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
269                    VGint width, VGint height)
270{
271   struct pipe_resource *texture;
272   struct pipe_sampler_view view_templ;
273   struct pipe_sampler_view *view;
274
275   texture = create_texture(pipe, format, width, height);
276
277   if (!texture)
278      return NULL;
279
280   u_sampler_view_default_template(&view_templ, texture, texture->format);
281   view = pipe->create_sampler_view(pipe, texture, &view_templ);
282   /* want the texture to go away if the view is freed */
283   pipe_resource_reference(&texture, NULL);
284
285   return view;
286}
287
288static void
289vg_context_update_surface_mask_view(struct vg_context *ctx,
290                                    uint width, uint height)
291{
292   struct st_framebuffer *stfb = ctx->draw_buffer;
293   struct pipe_sampler_view *old_sampler_view = stfb->surface_mask_view;
294   struct pipe_context *pipe = ctx->pipe;
295
296   if (old_sampler_view &&
297       old_sampler_view->texture->width0 == width &&
298       old_sampler_view->texture->height0 == height)
299      return;
300
301   /*
302     we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
303     this texture and use it as a sampler, so while this wastes some
304     space it makes both of those a lot simpler
305   */
306   stfb->surface_mask_view = create_tex_and_view(pipe,
307         PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
308
309   if (!stfb->surface_mask_view) {
310      if (old_sampler_view)
311         pipe_sampler_view_reference(&old_sampler_view, NULL);
312      return;
313   }
314
315   /* XXX could this call be avoided? */
316   vg_validate_state(ctx);
317
318   /* alpha mask starts with 1.f alpha */
319   mask_fill(0, 0, width, height, 1.f);
320
321   /* if we had an old surface copy it over */
322   if (old_sampler_view) {
323      struct pipe_box src_box;
324      u_box_origin_2d(MIN2(old_sampler_view->texture->width0,
325                           stfb->surface_mask_view->texture->width0),
326                      MIN2(old_sampler_view->texture->height0,
327                           stfb->surface_mask_view->texture->height0),
328                      &src_box);
329
330      pipe->resource_copy_region(pipe,
331                                 stfb->surface_mask_view->texture,
332                                 0, 0, 0, 0,
333                                 old_sampler_view->texture,
334                                 0, &src_box);
335   }
336
337   /* Free the old texture
338    */
339   if (old_sampler_view)
340      pipe_sampler_view_reference(&old_sampler_view, NULL);
341}
342
343static void
344vg_context_update_blend_texture_view(struct vg_context *ctx,
345                                     uint width, uint height)
346{
347   struct pipe_context *pipe = ctx->pipe;
348   struct st_framebuffer *stfb = ctx->draw_buffer;
349   struct pipe_sampler_view *old = stfb->blend_texture_view;
350
351   if (old &&
352       old->texture->width0 == width &&
353       old->texture->height0 == height)
354      return;
355
356   stfb->blend_texture_view = create_tex_and_view(pipe,
357         PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
358
359   pipe_sampler_view_reference(&old, NULL);
360}
361
362static boolean
363vg_context_update_depth_stencil_rb(struct vg_context * ctx,
364                                   uint width, uint height)
365{
366   struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
367   struct pipe_context *pipe = ctx->pipe;
368   struct pipe_surface surf_tmpl;
369
370   if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
371      return FALSE;
372
373   /* unreference existing ones */
374   pipe_surface_reference(&dsrb->surface, NULL);
375   pipe_resource_reference(&dsrb->texture, NULL);
376   dsrb->width = dsrb->height = 0;
377
378   dsrb->texture = create_texture(pipe, dsrb->format, width, height);
379   if (!dsrb->texture)
380      return TRUE;
381
382   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
383   u_surface_default_template(&surf_tmpl, dsrb->texture,
384                              PIPE_BIND_DEPTH_STENCIL);
385   dsrb->surface = pipe->create_surface(pipe,
386                                        dsrb->texture,
387                                        &surf_tmpl);
388   if (!dsrb->surface) {
389      pipe_resource_reference(&dsrb->texture, NULL);
390      return TRUE;
391   }
392
393   dsrb->width = width;
394   dsrb->height = height;
395
396   assert(dsrb->surface->width == width);
397   assert(dsrb->surface->height == height);
398
399   return TRUE;
400}
401
402void vg_validate_state(struct vg_context *ctx)
403{
404   struct st_framebuffer *stfb = ctx->draw_buffer;
405
406   vg_manager_validate_framebuffer(ctx);
407
408   if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height))
409      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
410
411   /* blend state depends on fb format and paint color */
412   if ((ctx->state.dirty & FRAMEBUFFER_DIRTY) ||
413       (ctx->state.dirty & PAINT_DIRTY))
414      ctx->state.dirty |= BLEND_DIRTY;
415
416   renderer_validate(ctx->renderer, ctx->state.dirty,
417         ctx->draw_buffer, &ctx->state.vg);
418
419   ctx->state.dirty = 0;
420
421   shader_set_masking(ctx->shader, ctx->state.vg.masking);
422   shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
423   shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform);
424}
425
426VGboolean vg_object_is_valid(VGHandle object, enum vg_object_type type)
427{
428   struct vg_object *obj = handle_to_object(object);
429   if (obj && is_aligned(obj) && obj->type == type)
430      return VG_TRUE;
431   else
432      return VG_FALSE;
433}
434
435void vg_set_error(struct vg_context *ctx,
436                  VGErrorCode code)
437{
438   /*vgGetError returns the oldest error code provided by
439    * an API call on the current context since the previous
440    * call to vgGetError on that context (or since the creation
441    of the context).*/
442   if (ctx->_error == VG_NO_ERROR)
443      ctx->_error = code;
444}
445
446static void vg_prepare_blend_texture(struct vg_context *ctx,
447                                     struct pipe_sampler_view *src)
448{
449   struct st_framebuffer *stfb = ctx->draw_buffer;
450   struct pipe_surface *surf;
451   struct pipe_surface surf_tmpl;
452
453   vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height);
454
455   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
456   u_surface_default_template(&surf_tmpl, stfb->blend_texture_view->texture,
457                              PIPE_BIND_RENDER_TARGET);
458   surf = ctx->pipe->create_surface(ctx->pipe,
459                                    stfb->blend_texture_view->texture,
460                                    &surf_tmpl);
461   if (surf) {
462      util_blit_pixels_tex(ctx->blit,
463                           src, 0, 0, stfb->width, stfb->height,
464                           surf, 0, 0, stfb->width, stfb->height,
465                           0.0, PIPE_TEX_MIPFILTER_NEAREST);
466
467      pipe_surface_reference(&surf, NULL);
468   }
469}
470
471struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx)
472{
473   struct pipe_context *pipe = ctx->pipe;
474   struct pipe_sampler_view *view;
475   struct pipe_sampler_view view_templ;
476   struct st_framebuffer *stfb = ctx->draw_buffer;
477   struct st_renderbuffer *strb = stfb->strb;
478
479   vg_validate_state(ctx);
480
481   u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format);
482   view = pipe->create_sampler_view(pipe, strb->texture, &view_templ);
483
484   vg_prepare_blend_texture(ctx, view);
485
486   pipe_sampler_view_reference(&view, NULL);
487
488   return stfb->blend_texture_view;
489}
490
491
492struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
493{
494   struct st_framebuffer *stfb = ctx->draw_buffer;
495
496   vg_validate_state(ctx);
497
498   vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height);
499   vg_prepare_blend_texture(ctx, stfb->surface_mask_view);
500
501   return stfb->blend_texture_view;
502}
503
504struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx)
505{
506   struct st_framebuffer *stfb = ctx->draw_buffer;
507
508   vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height);
509
510   return stfb->surface_mask_view;
511}
512
513/**
514 * A transformation from window coordinates to paint coordinates.
515 */
516VGboolean vg_get_paint_matrix(struct vg_context *ctx,
517                              const struct matrix *paint_to_user,
518                              const struct matrix *user_to_surface,
519                              struct matrix *mat)
520{
521   struct matrix tmp;
522
523   /* get user-to-paint matrix */
524   memcpy(mat, paint_to_user, sizeof(*paint_to_user));
525   if (!matrix_invert(mat))
526      return VG_FALSE;
527
528   /* get surface-to-user matrix */
529   memcpy(&tmp, user_to_surface, sizeof(*user_to_surface));
530   if (!matrix_invert(&tmp))
531      return VG_FALSE;
532
533   matrix_mult(mat, &tmp);
534
535   return VG_TRUE;
536}
537