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