1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
27 #include "vg_context.h"
31 #include "shaders_cache.h"
34 #include "vg_manager.h"
38 #include "pipe/p_context.h"
39 #include "util/u_inlines.h"
41 #include "cso_cache/cso_context.h"
43 #include "util/u_simple_shaders.h"
44 #include "util/u_memory.h"
45 #include "util/u_blit.h"
46 #include "util/u_sampler.h"
47 #include "util/u_surface.h"
48 #include "util/u_format.h"
50 struct vg_context
*_vg_context
= 0;
52 struct vg_context
* vg_current_context(void)
58 * A depth/stencil rb will be needed regardless of what the visual says.
61 choose_depth_stencil_format(struct vg_context
*ctx
)
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
,
69 enum pipe_format
*fmt
;
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))
77 ctx
->ds_format
= *fmt
;
79 return (ctx
->ds_format
!= PIPE_FORMAT_NONE
);
82 void vg_set_current_context(struct vg_context
*ctx
)
85 api_make_dispatch_current((ctx
) ? ctx
->dispatch
: NULL
);
88 struct vg_context
* vg_create_context(struct pipe_context
*pipe
,
90 struct vg_context
*share
)
92 struct vg_context
*ctx
;
94 ctx
= CALLOC_STRUCT(vg_context
);
97 if (!choose_depth_stencil_format(ctx
)) {
102 ctx
->dispatch
= api_create_dispatch();
104 vg_init_state(&ctx
->state
.vg
);
105 ctx
->state
.dirty
= ALL_DIRTY
;
107 ctx
->cso_context
= cso_create_context(pipe
);
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
;
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;
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;
130 vg_set_error(ctx
, VG_NO_ERROR
);
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();
138 ctx
->renderer
= renderer_create(ctx
);
139 ctx
->sc
= shaders_cache_create(ctx
);
140 ctx
->shader
= shader_create(ctx
);
142 ctx
->blit
= util_create_blit(ctx
->pipe
, ctx
->cso_context
);
147 void vg_destroy_context(struct vg_context
*ctx
)
149 struct pipe_resource
**cbuf
= &ctx
->mask
.cbuf
;
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
);
158 pipe_resource_reference(cbuf
, NULL
);
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
);
169 cso_release_all(ctx
->cso_context
);
170 cso_destroy_context(ctx
->cso_context
);
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
]);
178 api_destroy_dispatch(ctx
->dispatch
);
183 void vg_init_object(struct vg_object
*obj
, struct vg_context
*ctx
, enum vg_object_type type
)
189 VGboolean
vg_context_is_object_valid(struct vg_context
*ctx
,
190 enum vg_object_type type
,
194 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
197 return cso_hash_contains(hash
, (unsigned)(long)ptr
);
202 void vg_context_add_object(struct vg_context
*ctx
,
203 enum vg_object_type type
,
207 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
210 cso_hash_insert(hash
, (unsigned)(long)ptr
, ptr
);
214 void vg_context_remove_object(struct vg_context
*ctx
,
215 enum vg_object_type type
,
219 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
222 cso_hash_take(hash
, (unsigned)(long)ptr
);
226 static struct pipe_resource
*
227 create_texture(struct pipe_context
*pipe
, enum pipe_format format
,
228 VGint width
, VGint height
)
230 struct pipe_resource templ
;
232 memset(&templ
, 0, sizeof(templ
));
234 if (format
!= PIPE_FORMAT_NONE
) {
235 templ
.format
= format
;
238 templ
.format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
241 templ
.target
= PIPE_TEXTURE_2D
;
242 templ
.width0
= width
;
243 templ
.height0
= height
;
245 templ
.array_size
= 1;
246 templ
.last_level
= 0;
248 if (util_format_get_component_bits(format
, UTIL_FORMAT_COLORSPACE_ZS
, 1)) {
249 templ
.bind
= PIPE_BIND_DEPTH_STENCIL
;
251 templ
.bind
= (PIPE_BIND_DISPLAY_TARGET
|
252 PIPE_BIND_RENDER_TARGET
|
253 PIPE_BIND_SAMPLER_VIEW
);
256 return pipe
->screen
->resource_create(pipe
->screen
, &templ
);
259 static struct pipe_sampler_view
*
260 create_tex_and_view(struct pipe_context
*pipe
, enum pipe_format format
,
261 VGint width
, VGint height
)
263 struct pipe_resource
*texture
;
264 struct pipe_sampler_view view_templ
;
265 struct pipe_sampler_view
*view
;
267 texture
= create_texture(pipe
, format
, width
, height
);
272 u_sampler_view_default_template(&view_templ
, texture
, texture
->format
);
273 view
= pipe
->create_sampler_view(pipe
, texture
, &view_templ
);
274 /* want the texture to go away if the view is freed */
275 pipe_resource_reference(&texture
, NULL
);
281 vg_context_update_surface_mask_view(struct vg_context
*ctx
,
282 uint width
, uint height
)
284 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
285 struct pipe_sampler_view
*old_sampler_view
= stfb
->surface_mask_view
;
286 struct pipe_context
*pipe
= ctx
->pipe
;
288 if (old_sampler_view
&&
289 old_sampler_view
->texture
->width0
== width
&&
290 old_sampler_view
->texture
->height0
== height
)
294 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
295 this texture and use it as a sampler, so while this wastes some
296 space it makes both of those a lot simpler
298 stfb
->surface_mask_view
= create_tex_and_view(pipe
,
299 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
301 if (!stfb
->surface_mask_view
) {
302 if (old_sampler_view
)
303 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
307 /* XXX could this call be avoided? */
308 vg_validate_state(ctx
);
310 /* alpha mask starts with 1.f alpha */
311 mask_fill(0, 0, width
, height
, 1.f
);
313 /* if we had an old surface copy it over */
314 if (old_sampler_view
) {
315 struct pipe_box src_box
;
316 u_box_origin_2d(MIN2(old_sampler_view
->texture
->width0
,
317 stfb
->surface_mask_view
->texture
->width0
),
318 MIN2(old_sampler_view
->texture
->height0
,
319 stfb
->surface_mask_view
->texture
->height0
),
322 pipe
->resource_copy_region(pipe
,
323 stfb
->surface_mask_view
->texture
,
325 old_sampler_view
->texture
,
329 /* Free the old texture
331 if (old_sampler_view
)
332 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
336 vg_context_update_blend_texture_view(struct vg_context
*ctx
,
337 uint width
, uint height
)
339 struct pipe_context
*pipe
= ctx
->pipe
;
340 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
341 struct pipe_sampler_view
*old
= stfb
->blend_texture_view
;
344 old
->texture
->width0
== width
&&
345 old
->texture
->height0
== height
)
348 stfb
->blend_texture_view
= create_tex_and_view(pipe
,
349 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
351 pipe_sampler_view_reference(&old
, NULL
);
355 vg_context_update_depth_stencil_rb(struct vg_context
* ctx
,
356 uint width
, uint height
)
358 struct st_renderbuffer
*dsrb
= ctx
->draw_buffer
->dsrb
;
359 struct pipe_context
*pipe
= ctx
->pipe
;
360 struct pipe_surface surf_tmpl
;
362 if ((dsrb
->width
== width
&& dsrb
->height
== height
) && dsrb
->texture
)
365 /* unreference existing ones */
366 pipe_surface_reference(&dsrb
->surface
, NULL
);
367 pipe_resource_reference(&dsrb
->texture
, NULL
);
368 dsrb
->width
= dsrb
->height
= 0;
370 dsrb
->texture
= create_texture(pipe
, dsrb
->format
, width
, height
);
374 memset(&surf_tmpl
, 0, sizeof(surf_tmpl
));
375 u_surface_default_template(&surf_tmpl
, dsrb
->texture
,
376 PIPE_BIND_DEPTH_STENCIL
);
377 dsrb
->surface
= pipe
->create_surface(pipe
,
380 if (!dsrb
->surface
) {
381 pipe_resource_reference(&dsrb
->texture
, NULL
);
386 dsrb
->height
= height
;
388 assert(dsrb
->surface
->width
== width
);
389 assert(dsrb
->surface
->height
== height
);
394 void vg_validate_state(struct vg_context
*ctx
)
396 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
398 vg_manager_validate_framebuffer(ctx
);
400 if (vg_context_update_depth_stencil_rb(ctx
, stfb
->width
, stfb
->height
))
401 ctx
->state
.dirty
|= DEPTH_STENCIL_DIRTY
;
403 /* blend state depends on fb format */
404 if (ctx
->state
.dirty
& FRAMEBUFFER_DIRTY
)
405 ctx
->state
.dirty
|= BLEND_DIRTY
;
407 renderer_validate(ctx
->renderer
, ctx
->state
.dirty
,
408 ctx
->draw_buffer
, &ctx
->state
.vg
);
410 ctx
->state
.dirty
= 0;
412 shader_set_masking(ctx
->shader
, ctx
->state
.vg
.masking
);
413 shader_set_image_mode(ctx
->shader
, ctx
->state
.vg
.image_mode
);
414 shader_set_color_transform(ctx
->shader
, ctx
->state
.vg
.color_transform
);
417 VGboolean
vg_object_is_valid(void *ptr
, enum vg_object_type type
)
419 struct vg_object
*obj
= ptr
;
420 if (ptr
&& is_aligned(obj
) && obj
->type
== type
)
426 void vg_set_error(struct vg_context
*ctx
,
429 /*vgGetError returns the oldest error code provided by
430 * an API call on the current context since the previous
431 * call to vgGetError on that context (or since the creation
433 if (ctx
->_error
== VG_NO_ERROR
)
437 static void vg_prepare_blend_texture(struct vg_context
*ctx
,
438 struct pipe_sampler_view
*src
)
440 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
441 struct pipe_surface
*surf
;
442 struct pipe_surface surf_tmpl
;
444 vg_context_update_blend_texture_view(ctx
, stfb
->width
, stfb
->height
);
446 memset(&surf_tmpl
, 0, sizeof(surf_tmpl
));
447 u_surface_default_template(&surf_tmpl
, stfb
->blend_texture_view
->texture
,
448 PIPE_BIND_RENDER_TARGET
);
449 surf
= ctx
->pipe
->create_surface(ctx
->pipe
,
450 stfb
->blend_texture_view
->texture
,
453 util_blit_pixels_tex(ctx
->blit
,
454 src
, 0, 0, stfb
->width
, stfb
->height
,
455 surf
, 0, 0, stfb
->width
, stfb
->height
,
456 0.0, PIPE_TEX_MIPFILTER_NEAREST
);
458 pipe_surface_reference(&surf
, NULL
);
462 struct pipe_sampler_view
*vg_prepare_blend_surface(struct vg_context
*ctx
)
464 struct pipe_context
*pipe
= ctx
->pipe
;
465 struct pipe_sampler_view
*view
;
466 struct pipe_sampler_view view_templ
;
467 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
468 struct st_renderbuffer
*strb
= stfb
->strb
;
470 vg_validate_state(ctx
);
472 u_sampler_view_default_template(&view_templ
, strb
->texture
, strb
->texture
->format
);
473 view
= pipe
->create_sampler_view(pipe
, strb
->texture
, &view_templ
);
475 vg_prepare_blend_texture(ctx
, view
);
477 pipe_sampler_view_reference(&view
, NULL
);
479 return stfb
->blend_texture_view
;
483 struct pipe_sampler_view
*vg_prepare_blend_surface_from_mask(struct vg_context
*ctx
)
485 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
487 vg_validate_state(ctx
);
489 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
490 vg_prepare_blend_texture(ctx
, stfb
->surface_mask_view
);
492 return stfb
->blend_texture_view
;
495 struct pipe_sampler_view
*vg_get_surface_mask(struct vg_context
*ctx
)
497 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
499 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
501 return stfb
->surface_mask_view
;
505 * A transformation from window coordinates to paint coordinates.
507 VGboolean
vg_get_paint_matrix(struct vg_context
*ctx
,
508 const struct matrix
*paint_to_user
,
509 const struct matrix
*user_to_surface
,
514 /* get user-to-paint matrix */
515 memcpy(mat
, paint_to_user
, sizeof(*paint_to_user
));
516 if (!matrix_invert(mat
))
519 /* get surface-to-user matrix */
520 memcpy(&tmp
, user_to_surface
, sizeof(*user_to_surface
));
521 if (!matrix_invert(&tmp
))
524 matrix_mult(mat
, &tmp
);