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