vg_context.c revision a91128030e6c19609f6bb66a871382bbe4e3e2a4
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 37#include "pipe/p_context.h" 38#include "util/u_inlines.h" 39 40#include "cso_cache/cso_context.h" 41 42#include "util/u_memory.h" 43#include "util/u_blit.h" 44#include "util/u_sampler.h" 45#include "util/u_surface.h" 46#include "util/u_format.h" 47 48struct vg_context *_vg_context = 0; 49 50struct vg_context * vg_current_context(void) 51{ 52 return _vg_context; 53} 54 55/** 56 * A depth/stencil rb will be needed regardless of what the visual says. 57 */ 58static boolean 59choose_depth_stencil_format(struct vg_context *ctx) 60{ 61 struct pipe_screen *screen = ctx->pipe->screen; 62 enum pipe_format formats[] = { 63 PIPE_FORMAT_Z24_UNORM_S8_USCALED, 64 PIPE_FORMAT_S8_USCALED_Z24_UNORM, 65 PIPE_FORMAT_NONE 66 }; 67 enum pipe_format *fmt; 68 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, 0)) 72 break; 73 } 74 75 ctx->ds_format = *fmt; 76 77 return (ctx->ds_format != PIPE_FORMAT_NONE); 78} 79 80void vg_set_current_context(struct vg_context *ctx) 81{ 82 _vg_context = ctx; 83 api_make_dispatch_current((ctx) ? ctx->dispatch : NULL); 84} 85 86struct vg_context * vg_create_context(struct pipe_context *pipe, 87 const void *visual, 88 struct vg_context *share) 89{ 90 struct vg_context *ctx; 91 92 ctx = CALLOC_STRUCT(vg_context); 93 94 ctx->pipe = pipe; 95 if (!choose_depth_stencil_format(ctx)) { 96 FREE(ctx); 97 return NULL; 98 } 99 100 ctx->dispatch = api_create_dispatch(); 101 102 vg_init_state(&ctx->state.vg); 103 ctx->state.dirty = ALL_DIRTY; 104 105 ctx->cso_context = cso_create_context(pipe); 106 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; 110 111 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; 119 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; 127 128 vg_set_error(ctx, VG_NO_ERROR); 129 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(); 135 136 ctx->renderer = renderer_create(ctx); 137 ctx->sc = shaders_cache_create(ctx); 138 ctx->shader = shader_create(ctx); 139 140 ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context); 141 142 return ctx; 143} 144 145void vg_destroy_context(struct vg_context *ctx) 146{ 147 struct pipe_resource **cbuf = &ctx->mask.cbuf; 148 149 util_destroy_blit(ctx->blit); 150 renderer_destroy(ctx->renderer); 151 shaders_cache_destroy(ctx->sc); 152 shader_destroy(ctx->shader); 153 paint_destroy(ctx->default_paint); 154 155 if (*cbuf) 156 pipe_resource_reference(cbuf, NULL); 157 158 if (ctx->mask.union_fs) 159 vg_shader_destroy(ctx, ctx->mask.union_fs); 160 if (ctx->mask.intersect_fs) 161 vg_shader_destroy(ctx, ctx->mask.intersect_fs); 162 if (ctx->mask.subtract_fs) 163 vg_shader_destroy(ctx, ctx->mask.subtract_fs); 164 if (ctx->mask.set_fs) 165 vg_shader_destroy(ctx, ctx->mask.set_fs); 166 167 cso_release_all(ctx->cso_context); 168 cso_destroy_context(ctx->cso_context); 169 170 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]); 171 cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]); 172 cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]); 173 cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]); 174 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]); 175 176 api_destroy_dispatch(ctx->dispatch); 177 178 FREE(ctx); 179} 180 181void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type) 182{ 183 obj->type = type; 184 obj->ctx = ctx; 185} 186 187VGboolean vg_context_is_object_valid(struct vg_context *ctx, 188 enum vg_object_type type, 189 void *ptr) 190{ 191 if (ctx) { 192 struct cso_hash *hash = ctx->owned_objects[type]; 193 if (!hash) 194 return VG_FALSE; 195 return cso_hash_contains(hash, (unsigned)(long)ptr); 196 } 197 return VG_FALSE; 198} 199 200void vg_context_add_object(struct vg_context *ctx, 201 enum vg_object_type type, 202 void *ptr) 203{ 204 if (ctx) { 205 struct cso_hash *hash = ctx->owned_objects[type]; 206 if (!hash) 207 return; 208 cso_hash_insert(hash, (unsigned)(long)ptr, ptr); 209 } 210} 211 212void vg_context_remove_object(struct vg_context *ctx, 213 enum vg_object_type type, 214 void *ptr) 215{ 216 if (ctx) { 217 struct cso_hash *hash = ctx->owned_objects[type]; 218 if (!hash) 219 return; 220 cso_hash_take(hash, (unsigned)(long)ptr); 221 } 222} 223 224static struct pipe_resource * 225create_texture(struct pipe_context *pipe, enum pipe_format format, 226 VGint width, VGint height) 227{ 228 struct pipe_resource templ; 229 230 memset(&templ, 0, sizeof(templ)); 231 232 if (format != PIPE_FORMAT_NONE) { 233 templ.format = format; 234 } 235 else { 236 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; 237 } 238 239 templ.target = PIPE_TEXTURE_2D; 240 templ.width0 = width; 241 templ.height0 = height; 242 templ.depth0 = 1; 243 templ.array_size = 1; 244 templ.last_level = 0; 245 246 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { 247 templ.bind = PIPE_BIND_DEPTH_STENCIL; 248 } else { 249 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 250 PIPE_BIND_RENDER_TARGET | 251 PIPE_BIND_SAMPLER_VIEW); 252 } 253 254 return pipe->screen->resource_create(pipe->screen, &templ); 255} 256 257static struct pipe_sampler_view * 258create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, 259 VGint width, VGint height) 260{ 261 struct pipe_resource *texture; 262 struct pipe_sampler_view view_templ; 263 struct pipe_sampler_view *view; 264 265 texture = create_texture(pipe, format, width, height); 266 267 if (!texture) 268 return NULL; 269 270 u_sampler_view_default_template(&view_templ, texture, texture->format); 271 view = pipe->create_sampler_view(pipe, texture, &view_templ); 272 /* want the texture to go away if the view is freed */ 273 pipe_resource_reference(&texture, NULL); 274 275 return view; 276} 277 278static void 279vg_context_update_surface_mask_view(struct vg_context *ctx, 280 uint width, uint height) 281{ 282 struct st_framebuffer *stfb = ctx->draw_buffer; 283 struct pipe_sampler_view *old_sampler_view = stfb->surface_mask_view; 284 struct pipe_context *pipe = ctx->pipe; 285 286 if (old_sampler_view && 287 old_sampler_view->texture->width0 == width && 288 old_sampler_view->texture->height0 == height) 289 return; 290 291 /* 292 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to 293 this texture and use it as a sampler, so while this wastes some 294 space it makes both of those a lot simpler 295 */ 296 stfb->surface_mask_view = create_tex_and_view(pipe, 297 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 298 299 if (!stfb->surface_mask_view) { 300 if (old_sampler_view) 301 pipe_sampler_view_reference(&old_sampler_view, NULL); 302 return; 303 } 304 305 /* XXX could this call be avoided? */ 306 vg_validate_state(ctx); 307 308 /* alpha mask starts with 1.f alpha */ 309 mask_fill(0, 0, width, height, 1.f); 310 311 /* if we had an old surface copy it over */ 312 if (old_sampler_view) { 313 struct pipe_box src_box; 314 u_box_origin_2d(MIN2(old_sampler_view->texture->width0, 315 stfb->surface_mask_view->texture->width0), 316 MIN2(old_sampler_view->texture->height0, 317 stfb->surface_mask_view->texture->height0), 318 &src_box); 319 320 pipe->resource_copy_region(pipe, 321 stfb->surface_mask_view->texture, 322 0, 0, 0, 0, 323 old_sampler_view->texture, 324 0, &src_box); 325 } 326 327 /* Free the old texture 328 */ 329 if (old_sampler_view) 330 pipe_sampler_view_reference(&old_sampler_view, NULL); 331} 332 333static void 334vg_context_update_blend_texture_view(struct vg_context *ctx, 335 uint width, uint height) 336{ 337 struct pipe_context *pipe = ctx->pipe; 338 struct st_framebuffer *stfb = ctx->draw_buffer; 339 struct pipe_sampler_view *old = stfb->blend_texture_view; 340 341 if (old && 342 old->texture->width0 == width && 343 old->texture->height0 == height) 344 return; 345 346 stfb->blend_texture_view = create_tex_and_view(pipe, 347 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 348 349 pipe_sampler_view_reference(&old, NULL); 350} 351 352static boolean 353vg_context_update_depth_stencil_rb(struct vg_context * ctx, 354 uint width, uint height) 355{ 356 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 357 struct pipe_context *pipe = ctx->pipe; 358 struct pipe_surface surf_tmpl; 359 360 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 361 return FALSE; 362 363 /* unreference existing ones */ 364 pipe_surface_reference(&dsrb->surface, NULL); 365 pipe_resource_reference(&dsrb->texture, NULL); 366 dsrb->width = dsrb->height = 0; 367 368 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 369 if (!dsrb->texture) 370 return TRUE; 371 372 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 373 u_surface_default_template(&surf_tmpl, dsrb->texture, 374 PIPE_BIND_DEPTH_STENCIL); 375 dsrb->surface = pipe->create_surface(pipe, 376 dsrb->texture, 377 &surf_tmpl); 378 if (!dsrb->surface) { 379 pipe_resource_reference(&dsrb->texture, NULL); 380 return TRUE; 381 } 382 383 dsrb->width = width; 384 dsrb->height = height; 385 386 assert(dsrb->surface->width == width); 387 assert(dsrb->surface->height == height); 388 389 return TRUE; 390} 391 392void vg_validate_state(struct vg_context *ctx) 393{ 394 struct st_framebuffer *stfb = ctx->draw_buffer; 395 396 vg_manager_validate_framebuffer(ctx); 397 398 if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height)) 399 ctx->state.dirty |= DEPTH_STENCIL_DIRTY; 400 401 /* blend state depends on fb format */ 402 if (ctx->state.dirty & FRAMEBUFFER_DIRTY) 403 ctx->state.dirty |= BLEND_DIRTY; 404 405 renderer_validate(ctx->renderer, ctx->state.dirty, 406 ctx->draw_buffer, &ctx->state.vg); 407 408 ctx->state.dirty = 0; 409 410 shader_set_masking(ctx->shader, ctx->state.vg.masking); 411 shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode); 412 shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform); 413} 414 415VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type) 416{ 417 struct vg_object *obj = ptr; 418 if (ptr && is_aligned(obj) && obj->type == type) 419 return VG_TRUE; 420 else 421 return VG_FALSE; 422} 423 424void vg_set_error(struct vg_context *ctx, 425 VGErrorCode code) 426{ 427 /*vgGetError returns the oldest error code provided by 428 * an API call on the current context since the previous 429 * call to vgGetError on that context (or since the creation 430 of the context).*/ 431 if (ctx->_error == VG_NO_ERROR) 432 ctx->_error = code; 433} 434 435static void vg_prepare_blend_texture(struct vg_context *ctx, 436 struct pipe_sampler_view *src) 437{ 438 struct st_framebuffer *stfb = ctx->draw_buffer; 439 struct pipe_surface *surf; 440 struct pipe_surface surf_tmpl; 441 442 vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height); 443 444 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 445 u_surface_default_template(&surf_tmpl, stfb->blend_texture_view->texture, 446 PIPE_BIND_RENDER_TARGET); 447 surf = ctx->pipe->create_surface(ctx->pipe, 448 stfb->blend_texture_view->texture, 449 &surf_tmpl); 450 if (surf) { 451 util_blit_pixels_tex(ctx->blit, 452 src, 0, 0, stfb->width, stfb->height, 453 surf, 0, 0, stfb->width, stfb->height, 454 0.0, PIPE_TEX_MIPFILTER_NEAREST); 455 456 pipe_surface_reference(&surf, NULL); 457 } 458} 459 460struct pipe_sampler_view *vg_prepare_blend_surface(struct vg_context *ctx) 461{ 462 struct pipe_context *pipe = ctx->pipe; 463 struct pipe_sampler_view *view; 464 struct pipe_sampler_view view_templ; 465 struct st_framebuffer *stfb = ctx->draw_buffer; 466 struct st_renderbuffer *strb = stfb->strb; 467 468 vg_validate_state(ctx); 469 470 u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format); 471 view = pipe->create_sampler_view(pipe, strb->texture, &view_templ); 472 473 vg_prepare_blend_texture(ctx, view); 474 475 pipe_sampler_view_reference(&view, NULL); 476 477 return stfb->blend_texture_view; 478} 479 480 481struct pipe_sampler_view *vg_prepare_blend_surface_from_mask(struct vg_context *ctx) 482{ 483 struct st_framebuffer *stfb = ctx->draw_buffer; 484 485 vg_validate_state(ctx); 486 487 vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); 488 vg_prepare_blend_texture(ctx, stfb->surface_mask_view); 489 490 return stfb->blend_texture_view; 491} 492 493struct pipe_sampler_view *vg_get_surface_mask(struct vg_context *ctx) 494{ 495 struct st_framebuffer *stfb = ctx->draw_buffer; 496 497 vg_context_update_surface_mask_view(ctx, stfb->width, stfb->height); 498 499 return stfb->surface_mask_view; 500} 501 502/** 503 * A transformation from window coordinates to paint coordinates. 504 */ 505VGboolean vg_get_paint_matrix(struct vg_context *ctx, 506 const struct matrix *paint_to_user, 507 const struct matrix *user_to_surface, 508 struct matrix *mat) 509{ 510 struct matrix tmp; 511 512 /* get user-to-paint matrix */ 513 memcpy(mat, paint_to_user, sizeof(*paint_to_user)); 514 if (!matrix_invert(mat)) 515 return VG_FALSE; 516 517 /* get surface-to-user matrix */ 518 memcpy(&tmp, user_to_surface, sizeof(*user_to_surface)); 519 if (!matrix_invert(&tmp)) 520 return VG_FALSE; 521 522 matrix_mult(mat, &tmp); 523 524 return VG_TRUE; 525} 526