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"
33 #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_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"
49 struct vg_context
*_vg_context
= 0;
51 struct vg_context
* vg_current_context(void)
57 * A depth/stencil rb will be needed regardless of what the visual says.
60 choose_depth_stencil_format(struct vg_context
*ctx
)
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
,
68 enum pipe_format
*fmt
;
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
))
76 ctx
->ds_format
= *fmt
;
78 return (ctx
->ds_format
!= PIPE_FORMAT_NONE
);
81 void vg_set_current_context(struct vg_context
*ctx
)
84 api_make_dispatch_current((ctx
) ? ctx
->dispatch
: NULL
);
87 struct vg_context
* vg_create_context(struct pipe_context
*pipe
,
89 struct vg_context
*share
)
91 struct vg_context
*ctx
;
93 ctx
= CALLOC_STRUCT(vg_context
);
96 if (!choose_depth_stencil_format(ctx
)) {
101 ctx
->dispatch
= api_create_dispatch();
103 vg_init_state(&ctx
->state
.vg
);
104 ctx
->state
.dirty
= ALL_DIRTY
;
106 ctx
->cso_context
= cso_create_context(pipe
);
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
;
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;
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;
129 vg_set_error(ctx
, VG_NO_ERROR
);
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();
137 ctx
->renderer
= renderer_create(ctx
);
138 ctx
->sc
= shaders_cache_create(ctx
);
139 ctx
->shader
= shader_create(ctx
);
141 ctx
->blit
= util_create_blit(ctx
->pipe
, ctx
->cso_context
);
146 void vg_destroy_context(struct vg_context
*ctx
)
148 struct pipe_resource
**cbuf
= &ctx
->mask
.cbuf
;
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
);
157 pipe_resource_reference(cbuf
, NULL
);
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
);
168 cso_release_all(ctx
->cso_context
);
169 cso_destroy_context(ctx
->cso_context
);
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
]);
177 api_destroy_dispatch(ctx
->dispatch
);
182 void vg_init_object(struct vg_object
*obj
, struct vg_context
*ctx
, enum vg_object_type type
)
186 obj
->handle
= create_handle(obj
);
189 /** free object resources, but not the object itself */
190 void vg_free_object(struct vg_object
*obj
)
194 destroy_handle(obj
->handle
);
197 VGboolean
vg_context_is_object_valid(struct vg_context
*ctx
,
198 enum vg_object_type type
,
202 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
205 return cso_hash_contains(hash
, (unsigned)(long)object
);
210 void vg_context_add_object(struct vg_context
*ctx
,
211 enum vg_object_type type
,
215 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
218 cso_hash_insert(hash
, (unsigned)(long)ptr
, ptr
);
222 void vg_context_remove_object(struct vg_context
*ctx
,
223 enum vg_object_type type
,
227 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
230 cso_hash_take(hash
, (unsigned)(long)ptr
);
234 static struct pipe_resource
*
235 create_texture(struct pipe_context
*pipe
, enum pipe_format format
,
236 VGint width
, VGint height
)
238 struct pipe_resource templ
;
240 memset(&templ
, 0, sizeof(templ
));
242 if (format
!= PIPE_FORMAT_NONE
) {
243 templ
.format
= format
;
246 templ
.format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
249 templ
.target
= PIPE_TEXTURE_2D
;
250 templ
.width0
= width
;
251 templ
.height0
= height
;
253 templ
.array_size
= 1;
254 templ
.last_level
= 0;
256 if (util_format_get_component_bits(format
, UTIL_FORMAT_COLORSPACE_ZS
, 1)) {
257 templ
.bind
= PIPE_BIND_DEPTH_STENCIL
;
259 templ
.bind
= (PIPE_BIND_DISPLAY_TARGET
|
260 PIPE_BIND_RENDER_TARGET
|
261 PIPE_BIND_SAMPLER_VIEW
);
264 return pipe
->screen
->resource_create(pipe
->screen
, &templ
);
267 static struct pipe_sampler_view
*
268 create_tex_and_view(struct pipe_context
*pipe
, enum pipe_format format
,
269 VGint width
, VGint height
)
271 struct pipe_resource
*texture
;
272 struct pipe_sampler_view view_templ
;
273 struct pipe_sampler_view
*view
;
275 texture
= create_texture(pipe
, format
, width
, height
);
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
);
289 vg_context_update_surface_mask_view(struct vg_context
*ctx
,
290 uint width
, uint height
)
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
;
296 if (old_sampler_view
&&
297 old_sampler_view
->texture
->width0
== width
&&
298 old_sampler_view
->texture
->height0
== height
)
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
306 stfb
->surface_mask_view
= create_tex_and_view(pipe
,
307 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
309 if (!stfb
->surface_mask_view
) {
310 if (old_sampler_view
)
311 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
315 /* XXX could this call be avoided? */
316 vg_validate_state(ctx
);
318 /* alpha mask starts with 1.f alpha */
319 mask_fill(0, 0, width
, height
, 1.f
);
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
),
330 pipe
->resource_copy_region(pipe
,
331 stfb
->surface_mask_view
->texture
,
333 old_sampler_view
->texture
,
337 /* Free the old texture
339 if (old_sampler_view
)
340 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
344 vg_context_update_blend_texture_view(struct vg_context
*ctx
,
345 uint width
, uint height
)
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
;
352 old
->texture
->width0
== width
&&
353 old
->texture
->height0
== height
)
356 stfb
->blend_texture_view
= create_tex_and_view(pipe
,
357 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
359 pipe_sampler_view_reference(&old
, NULL
);
363 vg_context_update_depth_stencil_rb(struct vg_context
* ctx
,
364 uint width
, uint height
)
366 struct st_renderbuffer
*dsrb
= ctx
->draw_buffer
->dsrb
;
367 struct pipe_context
*pipe
= ctx
->pipe
;
368 struct pipe_surface surf_tmpl
;
370 if ((dsrb
->width
== width
&& dsrb
->height
== height
) && dsrb
->texture
)
373 /* unreference existing ones */
374 pipe_surface_reference(&dsrb
->surface
, NULL
);
375 pipe_resource_reference(&dsrb
->texture
, NULL
);
376 dsrb
->width
= dsrb
->height
= 0;
378 dsrb
->texture
= create_texture(pipe
, dsrb
->format
, width
, height
);
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
,
388 if (!dsrb
->surface
) {
389 pipe_resource_reference(&dsrb
->texture
, NULL
);
394 dsrb
->height
= height
;
396 assert(dsrb
->surface
->width
== width
);
397 assert(dsrb
->surface
->height
== height
);
402 void vg_validate_state(struct vg_context
*ctx
)
404 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
406 vg_manager_validate_framebuffer(ctx
);
408 if (vg_context_update_depth_stencil_rb(ctx
, stfb
->width
, stfb
->height
))
409 ctx
->state
.dirty
|= DEPTH_STENCIL_DIRTY
;
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
;
416 renderer_validate(ctx
->renderer
, ctx
->state
.dirty
,
417 ctx
->draw_buffer
, &ctx
->state
.vg
);
419 ctx
->state
.dirty
= 0;
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
);
426 VGboolean
vg_object_is_valid(VGHandle object
, enum vg_object_type type
)
428 struct vg_object
*obj
= handle_to_object(object
);
429 if (obj
&& is_aligned(obj
) && obj
->type
== type
)
435 void vg_set_error(struct vg_context
*ctx
,
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
442 if (ctx
->_error
== VG_NO_ERROR
)
446 static void vg_prepare_blend_texture(struct vg_context
*ctx
,
447 struct pipe_sampler_view
*src
)
449 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
450 struct pipe_surface
*surf
;
451 struct pipe_surface surf_tmpl
;
453 vg_context_update_blend_texture_view(ctx
, stfb
->width
, stfb
->height
);
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
,
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
);
467 pipe_surface_reference(&surf
, NULL
);
471 struct pipe_sampler_view
*vg_prepare_blend_surface(struct vg_context
*ctx
)
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
;
479 vg_validate_state(ctx
);
481 u_sampler_view_default_template(&view_templ
, strb
->texture
, strb
->texture
->format
);
482 view
= pipe
->create_sampler_view(pipe
, strb
->texture
, &view_templ
);
484 vg_prepare_blend_texture(ctx
, view
);
486 pipe_sampler_view_reference(&view
, NULL
);
488 return stfb
->blend_texture_view
;
492 struct pipe_sampler_view
*vg_prepare_blend_surface_from_mask(struct vg_context
*ctx
)
494 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
496 vg_validate_state(ctx
);
498 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
499 vg_prepare_blend_texture(ctx
, stfb
->surface_mask_view
);
501 return stfb
->blend_texture_view
;
504 struct pipe_sampler_view
*vg_get_surface_mask(struct vg_context
*ctx
)
506 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
508 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
510 return stfb
->surface_mask_view
;
514 * A transformation from window coordinates to paint coordinates.
516 VGboolean
vg_get_paint_matrix(struct vg_context
*ctx
,
517 const struct matrix
*paint_to_user
,
518 const struct matrix
*user_to_surface
,
523 /* get user-to-paint matrix */
524 memcpy(mat
, paint_to_user
, sizeof(*paint_to_user
));
525 if (!matrix_invert(mat
))
528 /* get surface-to-user matrix */
529 memcpy(&tmp
, user_to_surface
, sizeof(*user_to_surface
));
530 if (!matrix_invert(&tmp
))
533 matrix_mult(mat
, &tmp
);