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