vg_context.c revision e360f91f152615b35857a4d008d0439a3c3285a8
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 "st_inlines.h" 35#include "vg_manager.h" 36#include "api.h" 37#include "mask.h" 38 39#include "pipe/p_context.h" 40#include "util/u_inlines.h" 41 42#include "cso_cache/cso_context.h" 43 44#include "util/u_simple_shaders.h" 45#include "util/u_memory.h" 46#include "util/u_blit.h" 47#include "util/u_sampler.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.last_level = 0; 246 247 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { 248 templ.bind = PIPE_BIND_DEPTH_STENCIL; 249 } else { 250 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 251 PIPE_BIND_RENDER_TARGET | 252 PIPE_BIND_SAMPLER_VIEW); 253 } 254 255 return pipe->screen->resource_create(pipe->screen, &templ); 256} 257 258static struct pipe_sampler_view * 259create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, 260 VGint width, VGint height) 261{ 262 struct pipe_resource *texture; 263 struct pipe_sampler_view view_templ; 264 struct pipe_sampler_view *view; 265 266 texture = create_texture(pipe, format, width, height); 267 268 if (!texture) 269 return NULL; 270 271 u_sampler_view_default_template(&view_templ, texture, texture->format); 272 view = pipe->create_sampler_view(pipe, texture, &view_templ); 273 /* want the texture to go away if the view is freed */ 274 pipe_resource_reference(&texture, NULL); 275 276 return view; 277} 278 279static void 280vg_context_update_alpha_mask_view(struct vg_context *ctx, 281 uint width, uint height) 282{ 283 struct st_framebuffer *stfb = ctx->draw_buffer; 284 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; 285 struct pipe_context *pipe = ctx->pipe; 286 287 if (old_sampler_view && 288 old_sampler_view->texture->width0 == width && 289 old_sampler_view->texture->height0 == height) 290 return; 291 292 /* 293 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to 294 this texture and use it as a sampler, so while this wastes some 295 space it makes both of those a lot simpler 296 */ 297 stfb->alpha_mask_view = create_tex_and_view(pipe, 298 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 299 300 if (!stfb->alpha_mask_view) { 301 if (old_sampler_view) 302 pipe_sampler_view_reference(&old_sampler_view, NULL); 303 return; 304 } 305 306 /* XXX could this call be avoided? */ 307 vg_validate_state(ctx); 308 309 /* alpha mask starts with 1.f alpha */ 310 mask_fill(0, 0, width, height, 1.f); 311 312 /* if we had an old surface copy it over */ 313 if (old_sampler_view) { 314 struct pipe_subresource subsurf, subold_surf; 315 subsurf.face = 0; 316 subsurf.level = 0; 317 subold_surf.face = 0; 318 subold_surf.level = 0; 319 pipe->resource_copy_region(pipe, 320 stfb->alpha_mask_view->texture, 321 subsurf, 322 0, 0, 0, 323 old_sampler_view->texture, 324 subold_surf, 325 0, 0, 0, 326 MIN2(old_sampler_view->texture->width0, 327 stfb->alpha_mask_view->texture->width0), 328 MIN2(old_sampler_view->texture->height0, 329 stfb->alpha_mask_view->texture->height0)); 330 } 331 332 /* Free the old texture 333 */ 334 if (old_sampler_view) 335 pipe_sampler_view_reference(&old_sampler_view, NULL); 336} 337 338static void 339vg_context_update_blend_texture_view(struct vg_context *ctx, 340 uint width, uint height) 341{ 342 struct pipe_context *pipe = ctx->pipe; 343 struct st_framebuffer *stfb = ctx->draw_buffer; 344 struct pipe_sampler_view *old = stfb->blend_texture_view; 345 346 if (old && 347 old->texture->width0 == width && 348 old->texture->height0 == height) 349 return; 350 351 stfb->blend_texture_view = create_tex_and_view(pipe, 352 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 353 354 pipe_sampler_view_reference(&old, NULL); 355} 356 357static boolean 358vg_context_update_depth_stencil_rb(struct vg_context * ctx, 359 uint width, uint height) 360{ 361 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 362 struct pipe_context *pipe = ctx->pipe; 363 unsigned surface_usage; 364 365 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 366 return FALSE; 367 368 /* unreference existing ones */ 369 pipe_surface_reference(&dsrb->surface, NULL); 370 pipe_resource_reference(&dsrb->texture, NULL); 371 dsrb->width = dsrb->height = 0; 372 373 /* Probably need dedicated flags for surface usage too: 374 */ 375 surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */ 376 377 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 378 if (!dsrb->texture) 379 return TRUE; 380 381 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, 382 dsrb->texture, 383 0, 0, 0, 384 surface_usage); 385 if (!dsrb->surface) { 386 pipe_resource_reference(&dsrb->texture, NULL); 387 return TRUE; 388 } 389 390 dsrb->width = width; 391 dsrb->height = height; 392 393 assert(dsrb->surface->width == width); 394 assert(dsrb->surface->height == height); 395 396 return TRUE; 397} 398 399void vg_validate_state(struct vg_context *ctx) 400{ 401 struct st_framebuffer *stfb = ctx->draw_buffer; 402 403 vg_manager_validate_framebuffer(ctx); 404 405 if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height)) 406 ctx->state.dirty |= DEPTH_STENCIL_DIRTY; 407 408 /* TODO create as needed */ 409 vg_context_update_alpha_mask_view(ctx, stfb->width, stfb->height); 410 vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height); 411 412 renderer_validate(ctx->renderer, ctx->state.dirty, 413 ctx->draw_buffer, &ctx->state.vg); 414 415 ctx->state.dirty = NONE_DIRTY; 416 417 shader_set_masking(ctx->shader, ctx->state.vg.masking); 418 shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode); 419 shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform); 420} 421 422VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type) 423{ 424 struct vg_object *obj = ptr; 425 if (ptr && is_aligned(obj) && obj->type == type) 426 return VG_TRUE; 427 else 428 return VG_FALSE; 429} 430 431void vg_set_error(struct vg_context *ctx, 432 VGErrorCode code) 433{ 434 /*vgGetError returns the oldest error code provided by 435 * an API call on the current context since the previous 436 * call to vgGetError on that context (or since the creation 437 of the context).*/ 438 if (ctx->_error == VG_NO_ERROR) 439 ctx->_error = code; 440} 441 442void vg_prepare_blend_surface(struct vg_context *ctx) 443{ 444 struct pipe_surface *dest_surface = NULL; 445 struct pipe_context *pipe = ctx->pipe; 446 struct pipe_sampler_view *view; 447 struct pipe_sampler_view view_templ; 448 struct st_framebuffer *stfb = ctx->draw_buffer; 449 struct st_renderbuffer *strb = stfb->strb; 450 451 /* first finish all pending rendering */ 452 vgFinish(); 453 454 u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format); 455 view = pipe->create_sampler_view(pipe, strb->texture, &view_templ); 456 457 dest_surface = pipe->screen->get_tex_surface(pipe->screen, 458 stfb->blend_texture_view->texture, 459 0, 0, 0, 460 PIPE_BIND_RENDER_TARGET); 461 util_blit_pixels_tex(ctx->blit, 462 view, 463 0, 0, 464 strb->width, strb->height, 465 dest_surface, 466 0, 0, 467 strb->width, strb->height, 468 0.0, PIPE_TEX_MIPFILTER_NEAREST); 469 470 if (dest_surface) 471 pipe_surface_reference(&dest_surface, NULL); 472 473 /* make sure it's complete */ 474 vgFinish(); 475 476 pipe_sampler_view_reference(&view, NULL); 477} 478 479 480void vg_prepare_blend_surface_from_mask(struct vg_context *ctx) 481{ 482 struct pipe_surface *dest_surface = NULL; 483 struct pipe_context *pipe = ctx->pipe; 484 struct st_framebuffer *stfb = ctx->draw_buffer; 485 struct st_renderbuffer *strb = stfb->strb; 486 487 vg_validate_state(ctx); 488 489 /* first finish all pending rendering */ 490 vgFinish(); 491 492 dest_surface = pipe->screen->get_tex_surface(pipe->screen, 493 stfb->blend_texture_view->texture, 494 0, 0, 0, 495 PIPE_BIND_RENDER_TARGET); 496 497 util_blit_pixels_tex(ctx->blit, 498 stfb->alpha_mask_view, 499 0, 0, 500 strb->width, strb->height, 501 dest_surface, 502 0, 0, 503 strb->width, strb->height, 504 0.0, PIPE_TEX_MIPFILTER_NEAREST); 505 506 /* make sure it's complete */ 507 vgFinish(); 508 509 if (dest_surface) 510 pipe_surface_reference(&dest_surface, NULL); 511} 512