vg_context.c revision 859106f196ade77f59f8787b071739901cd1a843
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 "vg_manager.h" 35#include "api.h" 36#include "mask.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_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" 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.array_size = 1; 246 templ.last_level = 0; 247 248 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { 249 templ.bind = PIPE_BIND_DEPTH_STENCIL; 250 } else { 251 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 252 PIPE_BIND_RENDER_TARGET | 253 PIPE_BIND_SAMPLER_VIEW); 254 } 255 256 return pipe->screen->resource_create(pipe->screen, &templ); 257} 258 259static struct pipe_sampler_view * 260create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, 261 VGint width, VGint height) 262{ 263 struct pipe_resource *texture; 264 struct pipe_sampler_view view_templ; 265 struct pipe_sampler_view *view; 266 267 texture = create_texture(pipe, format, width, height); 268 269 if (!texture) 270 return NULL; 271 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); 276 277 return view; 278} 279 280static void 281vg_context_update_surface_mask_view(struct vg_context *ctx, 282 uint width, uint height) 283{ 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; 287 288 if (old_sampler_view && 289 old_sampler_view->texture->width0 == width && 290 old_sampler_view->texture->height0 == height) 291 return; 292 293 /* 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 297 */ 298 stfb->surface_mask_view = create_tex_and_view(pipe, 299 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 300 301 if (!stfb->surface_mask_view) { 302 if (old_sampler_view) 303 pipe_sampler_view_reference(&old_sampler_view, NULL); 304 return; 305 } 306 307 /* XXX could this call be avoided? */ 308 vg_validate_state(ctx); 309 310 /* alpha mask starts with 1.f alpha */ 311 mask_fill(0, 0, width, height, 1.f); 312 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), 320 &src_box); 321 322 pipe->resource_copy_region(pipe, 323 stfb->surface_mask_view->texture, 324 0, 0, 0, 0, 325 old_sampler_view->texture, 326 0, &src_box); 327 } 328 329 /* Free the old texture 330 */ 331 if (old_sampler_view) 332 pipe_sampler_view_reference(&old_sampler_view, NULL); 333} 334 335static void 336vg_context_update_blend_texture_view(struct vg_context *ctx, 337 uint width, uint height) 338{ 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; 342 343 if (old && 344 old->texture->width0 == width && 345 old->texture->height0 == height) 346 return; 347 348 stfb->blend_texture_view = create_tex_and_view(pipe, 349 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 350 351 pipe_sampler_view_reference(&old, NULL); 352} 353 354static boolean 355vg_context_update_depth_stencil_rb(struct vg_context * ctx, 356 uint width, uint height) 357{ 358 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 359 struct pipe_context *pipe = ctx->pipe; 360 struct pipe_surface surf_tmpl; 361 362 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 363 return FALSE; 364 365 /* unreference existing ones */ 366 pipe_surface_reference(&dsrb->surface, NULL); 367 pipe_resource_reference(&dsrb->texture, NULL); 368 dsrb->width = dsrb->height = 0; 369 370 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 371 if (!dsrb->texture) 372 return TRUE; 373 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, 378 dsrb->texture, 379 &surf_tmpl); 380 if (!dsrb->surface) { 381 pipe_resource_reference(&dsrb->texture, NULL); 382 return TRUE; 383 } 384 385 dsrb->width = width; 386 dsrb->height = height; 387 388 assert(dsrb->surface->width == width); 389 assert(dsrb->surface->height == height); 390 391 return TRUE; 392} 393 394void vg_validate_state(struct vg_context *ctx) 395{ 396 struct st_framebuffer *stfb = ctx->draw_buffer; 397 398 vg_manager_validate_framebuffer(ctx); 399 400 if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height)) 401 ctx->state.dirty |= DEPTH_STENCIL_DIRTY; 402 403 /* blend state depends on fb format */ 404 if (ctx->state.dirty & FRAMEBUFFER_DIRTY) 405 ctx->state.dirty |= BLEND_DIRTY; 406 407 renderer_validate(ctx->renderer, ctx->state.dirty, 408 ctx->draw_buffer, &ctx->state.vg); 409 410 ctx->state.dirty = 0; 411 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); 415} 416 417VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type) 418{ 419 struct vg_object *obj = ptr; 420 if (ptr && is_aligned(obj) && obj->type == type) 421 return VG_TRUE; 422 else 423 return VG_FALSE; 424} 425 426void vg_set_error(struct vg_context *ctx, 427 VGErrorCode code) 428{ 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 432 of the context).*/ 433 if (ctx->_error == VG_NO_ERROR) 434 ctx->_error = code; 435} 436 437static void vg_prepare_blend_texture(struct vg_context *ctx, 438 struct pipe_sampler_view *src) 439{ 440 struct st_framebuffer *stfb = ctx->draw_buffer; 441 struct pipe_surface *surf; 442 struct pipe_surface surf_tmpl; 443 444 vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height); 445 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, 451 &surf_tmpl); 452 if (surf) { 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); 457 458 pipe_surface_reference(&surf, NULL); 459 } 460} 461 462struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx) 463{ 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; 469 470 vg_validate_state(ctx); 471 472 u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format); 473 view = pipe->create_sampler_view(pipe, strb->texture, &view_templ); 474 475 vg_prepare_blend_texture(ctx, view); 476 477 pipe_sampler_view_reference(&view, NULL); 478 479 return stfb->blend_texture_view; 480} 481 482 483struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx) 484{ 485 struct st_framebuffer *stfb = ctx->draw_buffer; 486 487 vg_validate_state(ctx); 488 489 vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); 490 vg_prepare_blend_texture(ctx, stfb->surface_mask_view); 491 492 return stfb->blend_texture_view; 493} 494 495struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx) 496{ 497 struct st_framebuffer *stfb = ctx->draw_buffer; 498 499 vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); 500 501 return stfb->surface_mask_view; 502} 503 504/** 505 * A transformation from window coordinates to paint coordinates. 506 */ 507VGboolean vg_get_paint_matrix(struct vg_context *ctx, 508 const struct matrix *paint_to_user, 509 const struct matrix *user_to_surface, 510 struct matrix *mat) 511{ 512 struct matrix tmp; 513 514 /* get user-to-paint matrix */ 515 memcpy(mat, paint_to_user, sizeof(*paint_to_user)); 516 if (!matrix_invert(mat)) 517 return VG_FALSE; 518 519 /* get surface-to-user matrix */ 520 memcpy(&tmp, user_to_surface, sizeof(*user_to_surface)); 521 if (!matrix_invert(&tmp)) 522 return VG_FALSE; 523 524 matrix_mult(mat, &tmp); 525 526 return VG_TRUE; 527} 528