Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / state_trackers / vega / vg_context.c
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
49 struct vg_context *_vg_context = 0;
50
51 struct 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  */
59 static boolean
60 choose_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))
73          break;
74    }
75
76    ctx->ds_format = *fmt;
77
78    return (ctx->ds_format != PIPE_FORMAT_NONE);
79 }
80
81 void vg_set_current_context(struct vg_context *ctx)
82 {
83    _vg_context = ctx;
84    api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
85 }
86
87 struct 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
146 void 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
182 void 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 */
190 void vg_free_object(struct vg_object *obj)
191 {
192    obj->type = 0;
193    obj->ctx = NULL;
194    destroy_handle(obj->handle);
195 }
196
197 VGboolean 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
210 void 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
222 void 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
234 static struct pipe_resource *
235 create_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
267 static struct pipe_sampler_view *
268 create_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
288 static void
289 vg_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
343 static void
344 vg_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
362 static boolean
363 vg_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
402 void 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
426 VGboolean 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
435 void 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
446 static 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
471 struct 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
492 struct 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
504 struct 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  */
516 VGboolean 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 }