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_sampler.h"
45 #include "util/u_surface.h"
46 #include "util/u_format.h"
48 struct vg_context
*_vg_context
= 0;
50 struct vg_context
* vg_current_context(void)
56 * A depth/stencil rb will be needed regardless of what the visual says.
59 choose_depth_stencil_format(struct vg_context
*ctx
)
61 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
62 enum pipe_format formats
[] = {
63 PIPE_FORMAT_Z24_UNORM_S8_UINT
,
64 PIPE_FORMAT_S8_UINT_Z24_UNORM
,
67 enum pipe_format
*fmt
;
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
))
75 ctx
->ds_format
= *fmt
;
77 return (ctx
->ds_format
!= PIPE_FORMAT_NONE
);
80 void vg_set_current_context(struct vg_context
*ctx
)
83 api_make_dispatch_current((ctx
) ? ctx
->dispatch
: NULL
);
86 struct vg_context
* vg_create_context(struct pipe_context
*pipe
,
88 struct vg_context
*share
)
90 struct vg_context
*ctx
;
92 ctx
= CALLOC_STRUCT(vg_context
);
95 if (!choose_depth_stencil_format(ctx
)) {
100 ctx
->dispatch
= api_create_dispatch();
102 vg_init_state(&ctx
->state
.vg
);
103 ctx
->state
.dirty
= ALL_DIRTY
;
105 ctx
->cso_context
= cso_create_context(pipe
);
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
;
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;
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;
128 vg_set_error(ctx
, VG_NO_ERROR
);
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();
136 ctx
->renderer
= renderer_create(ctx
);
137 ctx
->sc
= shaders_cache_create(ctx
);
138 ctx
->shader
= shader_create(ctx
);
143 void vg_destroy_context(struct vg_context
*ctx
)
145 struct pipe_resource
**cbuf
= &ctx
->mask
.cbuf
;
147 renderer_destroy(ctx
->renderer
);
148 shaders_cache_destroy(ctx
->sc
);
149 shader_destroy(ctx
->shader
);
150 paint_destroy(ctx
->default_paint
);
153 pipe_resource_reference(cbuf
, NULL
);
155 if (ctx
->mask
.union_fs
)
156 vg_shader_destroy(ctx
, ctx
->mask
.union_fs
);
157 if (ctx
->mask
.intersect_fs
)
158 vg_shader_destroy(ctx
, ctx
->mask
.intersect_fs
);
159 if (ctx
->mask
.subtract_fs
)
160 vg_shader_destroy(ctx
, ctx
->mask
.subtract_fs
);
161 if (ctx
->mask
.set_fs
)
162 vg_shader_destroy(ctx
, ctx
->mask
.set_fs
);
164 cso_destroy_context(ctx
->cso_context
);
166 cso_hash_delete(ctx
->owned_objects
[VG_OBJECT_PAINT
]);
167 cso_hash_delete(ctx
->owned_objects
[VG_OBJECT_IMAGE
]);
168 cso_hash_delete(ctx
->owned_objects
[VG_OBJECT_MASK
]);
169 cso_hash_delete(ctx
->owned_objects
[VG_OBJECT_FONT
]);
170 cso_hash_delete(ctx
->owned_objects
[VG_OBJECT_PATH
]);
172 api_destroy_dispatch(ctx
->dispatch
);
177 void vg_init_object(struct vg_object
*obj
, struct vg_context
*ctx
, enum vg_object_type type
)
181 obj
->handle
= create_handle(obj
);
184 /** free object resources, but not the object itself */
185 void vg_free_object(struct vg_object
*obj
)
189 destroy_handle(obj
->handle
);
192 VGboolean
vg_context_is_object_valid(struct vg_context
*ctx
,
193 enum vg_object_type type
,
197 struct cso_hash
*hash
= ctx
->owned_objects
[type
];
200 return cso_hash_contains(hash
, (unsigned) handle
);
205 void vg_context_add_object(struct vg_context
*ctx
,
206 struct vg_object
*obj
)
209 struct cso_hash
*hash
= ctx
->owned_objects
[obj
->type
];
212 cso_hash_insert(hash
, (unsigned) obj
->handle
, obj
);
216 void vg_context_remove_object(struct vg_context
*ctx
,
217 struct vg_object
*obj
)
220 struct cso_hash
*hash
= ctx
->owned_objects
[obj
->type
];
223 cso_hash_take(hash
, (unsigned) obj
->handle
);
227 static struct pipe_resource
*
228 create_texture(struct pipe_context
*pipe
, enum pipe_format format
,
229 VGint width
, VGint height
)
231 struct pipe_resource templ
;
233 memset(&templ
, 0, sizeof(templ
));
235 if (format
!= PIPE_FORMAT_NONE
) {
236 templ
.format
= format
;
239 templ
.format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
242 templ
.target
= PIPE_TEXTURE_2D
;
243 templ
.width0
= width
;
244 templ
.height0
= height
;
246 templ
.array_size
= 1;
247 templ
.last_level
= 0;
249 if (util_format_get_component_bits(format
, UTIL_FORMAT_COLORSPACE_ZS
, 1)) {
250 templ
.bind
= PIPE_BIND_DEPTH_STENCIL
;
252 templ
.bind
= (PIPE_BIND_DISPLAY_TARGET
|
253 PIPE_BIND_RENDER_TARGET
|
254 PIPE_BIND_SAMPLER_VIEW
);
257 return pipe
->screen
->resource_create(pipe
->screen
, &templ
);
260 static struct pipe_sampler_view
*
261 create_tex_and_view(struct pipe_context
*pipe
, enum pipe_format format
,
262 VGint width
, VGint height
)
264 struct pipe_resource
*texture
;
265 struct pipe_sampler_view view_templ
;
266 struct pipe_sampler_view
*view
;
268 texture
= create_texture(pipe
, format
, width
, height
);
273 u_sampler_view_default_template(&view_templ
, texture
, texture
->format
);
274 view
= pipe
->create_sampler_view(pipe
, texture
, &view_templ
);
275 /* want the texture to go away if the view is freed */
276 pipe_resource_reference(&texture
, NULL
);
282 vg_context_update_surface_mask_view(struct vg_context
*ctx
,
283 uint width
, uint height
)
285 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
286 struct pipe_sampler_view
*old_sampler_view
= stfb
->surface_mask_view
;
287 struct pipe_context
*pipe
= ctx
->pipe
;
289 if (old_sampler_view
&&
290 old_sampler_view
->texture
->width0
== width
&&
291 old_sampler_view
->texture
->height0
== height
)
295 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
296 this texture and use it as a sampler, so while this wastes some
297 space it makes both of those a lot simpler
299 stfb
->surface_mask_view
= create_tex_and_view(pipe
,
300 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
302 if (!stfb
->surface_mask_view
) {
303 if (old_sampler_view
)
304 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
308 /* XXX could this call be avoided? */
309 vg_validate_state(ctx
);
311 /* alpha mask starts with 1.f alpha */
312 mask_fill(0, 0, width
, height
, 1.f
);
314 /* if we had an old surface copy it over */
315 if (old_sampler_view
) {
316 struct pipe_box src_box
;
317 u_box_origin_2d(MIN2(old_sampler_view
->texture
->width0
,
318 stfb
->surface_mask_view
->texture
->width0
),
319 MIN2(old_sampler_view
->texture
->height0
,
320 stfb
->surface_mask_view
->texture
->height0
),
323 pipe
->resource_copy_region(pipe
,
324 stfb
->surface_mask_view
->texture
,
326 old_sampler_view
->texture
,
330 /* Free the old texture
332 if (old_sampler_view
)
333 pipe_sampler_view_reference(&old_sampler_view
, NULL
);
337 vg_context_update_blend_texture_view(struct vg_context
*ctx
,
338 uint width
, uint height
)
340 struct pipe_context
*pipe
= ctx
->pipe
;
341 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
342 struct pipe_sampler_view
*old
= stfb
->blend_texture_view
;
345 old
->texture
->width0
== width
&&
346 old
->texture
->height0
== height
)
349 stfb
->blend_texture_view
= create_tex_and_view(pipe
,
350 PIPE_FORMAT_B8G8R8A8_UNORM
, width
, height
);
352 pipe_sampler_view_reference(&old
, NULL
);
356 vg_context_update_depth_stencil_rb(struct vg_context
* ctx
,
357 uint width
, uint height
)
359 struct st_renderbuffer
*dsrb
= ctx
->draw_buffer
->dsrb
;
360 struct pipe_context
*pipe
= ctx
->pipe
;
361 struct pipe_surface surf_tmpl
;
363 if ((dsrb
->width
== width
&& dsrb
->height
== height
) && dsrb
->texture
)
366 /* unreference existing ones */
367 pipe_surface_reference(&dsrb
->surface
, NULL
);
368 pipe_resource_reference(&dsrb
->texture
, NULL
);
369 dsrb
->width
= dsrb
->height
= 0;
371 dsrb
->texture
= create_texture(pipe
, dsrb
->format
, width
, height
);
375 u_surface_default_template(&surf_tmpl
, dsrb
->texture
);
376 dsrb
->surface
= pipe
->create_surface(pipe
,
379 if (!dsrb
->surface
) {
380 pipe_resource_reference(&dsrb
->texture
, NULL
);
385 dsrb
->height
= height
;
387 assert(dsrb
->surface
->width
== width
);
388 assert(dsrb
->surface
->height
== height
);
393 void vg_validate_state(struct vg_context
*ctx
)
395 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
397 vg_manager_validate_framebuffer(ctx
);
399 if (vg_context_update_depth_stencil_rb(ctx
, stfb
->width
, stfb
->height
))
400 ctx
->state
.dirty
|= DEPTH_STENCIL_DIRTY
;
402 /* blend state depends on fb format and paint color */
403 if ((ctx
->state
.dirty
& FRAMEBUFFER_DIRTY
) ||
404 (ctx
->state
.dirty
& PAINT_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(VGHandle object
, enum vg_object_type type
)
419 struct vg_object
*obj
= handle_to_object(object
);
420 if (obj
&& 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_context
*pipe
= ctx
->pipe
;
442 struct pipe_blit_info info
;
444 vg_context_update_blend_texture_view(ctx
, stfb
->width
, stfb
->height
);
446 memset(&info
, 0, sizeof info
);
447 info
.dst
.resource
= stfb
->blend_texture_view
->texture
;
452 info
.dst
.box
.width
= stfb
->width
;
453 info
.dst
.box
.height
= stfb
->height
;
454 info
.dst
.box
.depth
= 1;
455 info
.dst
.format
= stfb
->blend_texture_view
->format
;
456 info
.src
.resource
= src
->texture
;
457 info
.src
.level
= src
->u
.tex
.first_level
;
460 info
.src
.box
.z
= src
->u
.tex
.first_layer
;
461 info
.src
.box
.width
= stfb
->width
;
462 info
.src
.box
.height
= stfb
->height
;
463 info
.src
.box
.depth
= 1;
464 info
.src
.format
= src
->format
;
465 info
.mask
= PIPE_MASK_RGBA
;
466 info
.filter
= PIPE_TEX_MIPFILTER_NEAREST
;
467 info
.scissor_enable
= 0;
469 pipe
->blit(pipe
, &info
);
472 struct pipe_sampler_view
*vg_prepare_blend_surface(struct vg_context
*ctx
)
474 struct pipe_context
*pipe
= ctx
->pipe
;
475 struct pipe_sampler_view
*view
;
476 struct pipe_sampler_view view_templ
;
477 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
478 struct st_renderbuffer
*strb
= stfb
->strb
;
480 vg_validate_state(ctx
);
482 u_sampler_view_default_template(&view_templ
, strb
->texture
, strb
->texture
->format
);
483 view
= pipe
->create_sampler_view(pipe
, strb
->texture
, &view_templ
);
485 vg_prepare_blend_texture(ctx
, view
);
487 pipe_sampler_view_reference(&view
, NULL
);
489 return stfb
->blend_texture_view
;
493 struct pipe_sampler_view
*vg_prepare_blend_surface_from_mask(struct vg_context
*ctx
)
495 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
497 vg_validate_state(ctx
);
499 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
500 vg_prepare_blend_texture(ctx
, stfb
->surface_mask_view
);
502 return stfb
->blend_texture_view
;
505 struct pipe_sampler_view
*vg_get_surface_mask(struct vg_context
*ctx
)
507 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
509 vg_context_update_surface_mask_view(ctx
, stfb
->width
, stfb
->height
);
511 return stfb
->surface_mask_view
;
515 * A transformation from window coordinates to paint coordinates.
517 VGboolean
vg_get_paint_matrix(struct vg_context
*ctx
,
518 const struct matrix
*paint_to_user
,
519 const struct matrix
*user_to_surface
,
524 /* get user-to-paint matrix */
525 memcpy(mat
, paint_to_user
, sizeof(*paint_to_user
));
526 if (!matrix_invert(mat
))
529 /* get surface-to-user matrix */
530 memcpy(&tmp
, user_to_surface
, sizeof(*user_to_surface
));
531 if (!matrix_invert(&tmp
))
534 matrix_mult(mat
, &tmp
);