vg_manager.c revision c36c3d86b62b525291b1c6527de3ac5de93a2faf
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright 2009 VMware, Inc. All Rights Reserved. 6 * Copyright (C) 2010 LunarG Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Chia-I Wu <olv@lunarg.com> 28 */ 29 30#include "state_tracker/st_api.h" 31 32#include "pipe/p_context.h" 33#include "pipe/p_screen.h" 34#include "util/u_memory.h" 35#include "util/u_inlines.h" 36#include "util/u_format.h" 37#include "util/u_sampler.h" 38 39#include "vg_manager.h" 40#include "vg_context.h" 41#include "image.h" 42#include "mask.h" 43 44static struct pipe_resource * 45create_texture(struct pipe_context *pipe, enum pipe_format format, 46 VGint width, VGint height) 47{ 48 struct pipe_resource templ; 49 50 memset(&templ, 0, sizeof(templ)); 51 52 if (format != PIPE_FORMAT_NONE) { 53 templ.format = format; 54 } 55 else { 56 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; 57 } 58 59 templ.target = PIPE_TEXTURE_2D; 60 templ.width0 = width; 61 templ.height0 = height; 62 templ.depth0 = 1; 63 templ.last_level = 0; 64 65 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { 66 templ.bind = PIPE_BIND_DEPTH_STENCIL; 67 } else { 68 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 69 PIPE_BIND_RENDER_TARGET | 70 PIPE_BIND_SAMPLER_VIEW); 71 } 72 73 return pipe->screen->resource_create(pipe->screen, &templ); 74} 75 76static struct pipe_sampler_view * 77create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, 78 VGint width, VGint height) 79{ 80 struct pipe_resource *texture; 81 struct pipe_sampler_view view_templ; 82 struct pipe_sampler_view *view; 83 84 texture = create_texture(pipe, format, width, height); 85 86 if (!texture) 87 return NULL; 88 89 u_sampler_view_default_template(&view_templ, texture, texture->format); 90 view = pipe->create_sampler_view(pipe, texture, &view_templ); 91 /* want the texture to go away if the view is freed */ 92 pipe_resource_reference(&texture, NULL); 93 94 return view; 95} 96 97static void 98setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb) 99{ 100 struct pipe_context *pipe = ctx->pipe; 101 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; 102 103 /* 104 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to 105 this texture and use it as a sampler, so while this wastes some 106 space it makes both of those a lot simpler 107 */ 108 stfb->alpha_mask_view = create_tex_and_view(pipe, 109 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); 110 111 if (!stfb->alpha_mask_view) { 112 if (old_sampler_view) 113 pipe_sampler_view_reference(&old_sampler_view, NULL); 114 return; 115 } 116 117 /* XXX could this call be avoided? */ 118 vg_validate_state(ctx); 119 120 /* alpha mask starts with 1.f alpha */ 121 mask_fill(0, 0, stfb->width, stfb->height, 1.f); 122 123 /* if we had an old surface copy it over */ 124 if (old_sampler_view) { 125 struct pipe_subresource subsurf, subold_surf; 126 subsurf.face = 0; 127 subsurf.level = 0; 128 subold_surf.face = 0; 129 subold_surf.level = 0; 130 pipe->resource_copy_region(pipe, 131 stfb->alpha_mask_view->texture, 132 subsurf, 133 0, 0, 0, 134 old_sampler_view->texture, 135 subold_surf, 136 0, 0, 0, 137 MIN2(old_sampler_view->texture->width0, 138 stfb->alpha_mask_view->texture->width0), 139 MIN2(old_sampler_view->texture->height0, 140 stfb->alpha_mask_view->texture->height0)); 141 } 142 143 /* Free the old texture 144 */ 145 if (old_sampler_view) 146 pipe_sampler_view_reference(&old_sampler_view, NULL); 147} 148 149static boolean 150vg_context_update_depth_stencil_rb(struct vg_context * ctx, 151 uint width, uint height) 152{ 153 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 154 struct pipe_context *pipe = ctx->pipe; 155 unsigned surface_usage; 156 157 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 158 return FALSE; 159 160 /* unreference existing ones */ 161 pipe_surface_reference(&dsrb->surface, NULL); 162 pipe_resource_reference(&dsrb->texture, NULL); 163 dsrb->width = dsrb->height = 0; 164 165 /* Probably need dedicated flags for surface usage too: 166 */ 167 surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */ 168 169 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 170 if (!dsrb->texture) 171 return TRUE; 172 173 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, 174 dsrb->texture, 175 0, 0, 0, 176 surface_usage); 177 if (!dsrb->surface) { 178 pipe_resource_reference(&dsrb->texture, NULL); 179 return TRUE; 180 } 181 182 dsrb->width = width; 183 dsrb->height = height; 184 185 assert(dsrb->surface->width == width); 186 assert(dsrb->surface->height == height); 187 188 return TRUE; 189} 190 191static boolean 192vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) 193{ 194 struct st_renderbuffer *strb = ctx->draw_buffer->strb; 195 struct pipe_screen *screen = ctx->pipe->screen; 196 197 if (strb->texture == pt) { 198 pipe_resource_reference(&pt, NULL); 199 return FALSE; 200 } 201 202 /* unreference existing ones */ 203 pipe_surface_reference(&strb->surface, NULL); 204 pipe_resource_reference(&strb->texture, NULL); 205 strb->width = strb->height = 0; 206 207 strb->texture = pt; 208 strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, 209 PIPE_BIND_RENDER_TARGET); 210 if (!strb->surface) { 211 pipe_resource_reference(&strb->texture, NULL); 212 return TRUE; 213 } 214 215 strb->width = pt->width0; 216 strb->height = pt->height0; 217 218 return TRUE; 219} 220 221static void 222vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt) 223{ 224 struct st_framebuffer *stfb = ctx->draw_buffer; 225 boolean new_cbuf, new_zsbuf, new_size; 226 227 new_cbuf = vg_context_update_color_rb(ctx, pt); 228 new_zsbuf = 229 vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0); 230 231 new_size = (stfb->width != pt->width0 || stfb->height != pt->height0); 232 stfb->width = pt->width0; 233 stfb->height = pt->height0; 234 235 if (new_cbuf || new_zsbuf || new_size) { 236 struct pipe_framebuffer_state *state = &ctx->state.g3d.fb; 237 238 memset(state, 0, sizeof(struct pipe_framebuffer_state)); 239 state->width = stfb->width; 240 state->height = stfb->height; 241 state->nr_cbufs = 1; 242 state->cbufs[0] = stfb->strb->surface; 243 state->zsbuf = stfb->dsrb->surface; 244 245 cso_set_framebuffer(ctx->cso_context, state); 246 } 247 248 if (new_zsbuf || new_size) { 249 ctx->state.dirty |= VIEWPORT_DIRTY; 250 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/ 251 252 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0); 253 254 /* we need all the other state already set */ 255 256 setup_new_alpha_mask(ctx, stfb); 257 258 pipe_sampler_view_reference( &stfb->blend_texture_view, NULL); 259 stfb->blend_texture_view = create_tex_and_view(ctx->pipe, 260 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); 261 } 262} 263 264/** 265 * Flush the front buffer if the current context renders to the front buffer. 266 */ 267void 268vg_manager_flush_frontbuffer(struct vg_context *ctx) 269{ 270 struct st_framebuffer *stfb = ctx->draw_buffer; 271 272 if (!stfb) 273 return; 274 275 switch (stfb->strb_att) { 276 case ST_ATTACHMENT_FRONT_LEFT: 277 case ST_ATTACHMENT_FRONT_RIGHT: 278 stfb->iface->flush_front(stfb->iface, stfb->strb_att); 279 break; 280 default: 281 break; 282 } 283} 284 285/** 286 * Re-validate the framebuffer. 287 */ 288void 289vg_manager_validate_framebuffer(struct vg_context *ctx) 290{ 291 struct st_framebuffer *stfb = ctx->draw_buffer; 292 struct pipe_resource *pt; 293 294 /* no binding surface */ 295 if (!stfb) 296 return; 297 298 if (!p_atomic_read(&ctx->draw_buffer_invalid)) 299 return; 300 301 /* validate the fb */ 302 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) 303 return; 304 305 /* 306 * unset draw_buffer_invalid first because vg_context_update_draw_buffer 307 * will cause the framebuffer to be validated again because of a call to 308 * vg_validate_state 309 */ 310 p_atomic_set(&ctx->draw_buffer_invalid, FALSE); 311 vg_context_update_draw_buffer(ctx, pt); 312} 313 314 315static void 316vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi, 317 struct st_framebuffer_iface *stfbi) 318{ 319 struct vg_context *ctx = (struct vg_context *) stctxi; 320 p_atomic_set(&ctx->draw_buffer_invalid, TRUE); 321} 322 323static void 324vg_context_flush(struct st_context_iface *stctxi, unsigned flags, 325 struct pipe_fence_handle **fence) 326{ 327 struct vg_context *ctx = (struct vg_context *) stctxi; 328 ctx->pipe->flush(ctx->pipe, flags, fence); 329 if (flags & PIPE_FLUSH_RENDER_CACHE) 330 vg_manager_flush_frontbuffer(ctx); 331} 332 333static void 334vg_context_destroy(struct st_context_iface *stctxi) 335{ 336 struct vg_context *ctx = (struct vg_context *) stctxi; 337 vg_destroy_context(ctx); 338} 339 340static struct st_context_iface * 341vg_api_create_context(struct st_api *stapi, struct st_manager *smapi, 342 const struct st_visual *visual, 343 struct st_context_iface *shared_stctxi) 344{ 345 struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi; 346 struct vg_context *ctx; 347 struct pipe_context *pipe; 348 349 pipe = smapi->screen->context_create(smapi->screen, NULL); 350 if (!pipe) 351 return NULL; 352 ctx = vg_create_context(pipe, NULL, shared_ctx); 353 if (!ctx) { 354 pipe->destroy(pipe); 355 return NULL; 356 } 357 358 ctx->iface.destroy = vg_context_destroy; 359 360 ctx->iface.notify_invalid_framebuffer = 361 vg_context_notify_invalid_framebuffer; 362 ctx->iface.flush = vg_context_flush; 363 364 ctx->iface.teximage = NULL; 365 ctx->iface.copy = NULL; 366 367 ctx->iface.st_context_private = (void *) smapi; 368 369 return &ctx->iface; 370} 371 372static struct st_renderbuffer * 373create_renderbuffer(enum pipe_format format) 374{ 375 struct st_renderbuffer *strb; 376 377 strb = CALLOC_STRUCT(st_renderbuffer); 378 if (strb) 379 strb->format = format; 380 381 return strb; 382} 383 384static void 385destroy_renderbuffer(struct st_renderbuffer *strb) 386{ 387 pipe_surface_reference(&strb->surface, NULL); 388 pipe_resource_reference(&strb->texture, NULL); 389 free(strb); 390} 391 392/** 393 * Decide the buffer to render to. 394 */ 395static enum st_attachment_type 396choose_attachment(struct st_framebuffer_iface *stfbi) 397{ 398 enum st_attachment_type statt; 399 400 statt = stfbi->visual->render_buffer; 401 if (statt != ST_ATTACHMENT_INVALID) { 402 /* use the buffer given by the visual, unless it is unavailable */ 403 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) { 404 switch (statt) { 405 case ST_ATTACHMENT_BACK_LEFT: 406 statt = ST_ATTACHMENT_FRONT_LEFT; 407 break; 408 case ST_ATTACHMENT_BACK_RIGHT: 409 statt = ST_ATTACHMENT_FRONT_RIGHT; 410 break; 411 default: 412 break; 413 } 414 415 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) 416 statt = ST_ATTACHMENT_INVALID; 417 } 418 } 419 420 return statt; 421} 422 423/** 424 * Bind the context to the given framebuffers. 425 */ 426static boolean 427vg_context_bind_framebuffers(struct st_context_iface *stctxi, 428 struct st_framebuffer_iface *stdrawi, 429 struct st_framebuffer_iface *streadi) 430{ 431 struct vg_context *ctx = (struct vg_context *) stctxi; 432 struct st_framebuffer *stfb; 433 enum st_attachment_type strb_att; 434 435 /* the draw and read framebuffers must be the same */ 436 if (stdrawi != streadi) 437 return FALSE; 438 439 p_atomic_set(&ctx->draw_buffer_invalid, TRUE); 440 441 strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID; 442 443 if (ctx->draw_buffer) { 444 stfb = ctx->draw_buffer; 445 446 /* free the existing fb */ 447 if (!stdrawi || 448 stfb->strb_att != strb_att || 449 stfb->strb->format != stdrawi->visual->color_format || 450 stfb->dsrb->format != stdrawi->visual->depth_stencil_format) { 451 destroy_renderbuffer(stfb->strb); 452 destroy_renderbuffer(stfb->dsrb); 453 free(stfb); 454 455 ctx->draw_buffer = NULL; 456 } 457 } 458 459 if (!stdrawi) 460 return TRUE; 461 462 if (strb_att == ST_ATTACHMENT_INVALID) 463 return FALSE; 464 465 /* create a new fb */ 466 if (!ctx->draw_buffer) { 467 stfb = CALLOC_STRUCT(st_framebuffer); 468 if (!stfb) 469 return FALSE; 470 471 stfb->strb = create_renderbuffer(stdrawi->visual->color_format); 472 if (!stfb->strb) { 473 free(stfb); 474 return FALSE; 475 } 476 477 stfb->dsrb = create_renderbuffer(stdrawi->visual->depth_stencil_format); 478 if (!stfb->dsrb) { 479 free(stfb->strb); 480 free(stfb); 481 return FALSE; 482 } 483 484 stfb->width = 0; 485 stfb->height = 0; 486 stfb->strb_att = strb_att; 487 488 ctx->draw_buffer = stfb; 489 } 490 491 ctx->draw_buffer->iface = stdrawi; 492 493 return TRUE; 494} 495 496static boolean 497vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi, 498 struct st_framebuffer_iface *stdrawi, 499 struct st_framebuffer_iface *streadi) 500{ 501 struct vg_context *ctx = (struct vg_context *) stctxi; 502 503 if (stctxi) 504 vg_context_bind_framebuffers(stctxi, stdrawi, streadi); 505 vg_set_current_context(ctx); 506 507 return TRUE; 508} 509 510static struct st_context_iface * 511vg_api_get_current(struct st_api *stapi) 512{ 513 struct vg_context *ctx = vg_current_context(); 514 515 return (ctx) ? &ctx->iface : NULL; 516} 517 518static boolean 519vg_api_is_visual_supported(struct st_api *stapi, 520 const struct st_visual *visual) 521{ 522 /* the impl requires a depth/stencil buffer */ 523 return util_format_is_depth_and_stencil(visual->depth_stencil_format); 524} 525 526static st_proc_t 527vg_api_get_proc_address(struct st_api *stapi, const char *procname) 528{ 529 /* TODO */ 530 return (st_proc_t) NULL; 531} 532 533static void 534vg_api_destroy(struct st_api *stapi) 535{ 536 free(stapi); 537} 538 539struct st_api st_vg_api = { 540 vg_api_destroy, 541 vg_api_get_proc_address, 542 vg_api_is_visual_supported, 543 vg_api_create_context, 544 vg_api_make_current, 545 vg_api_get_current, 546}; 547 548struct st_api * 549st_api_create_OpenVG(void) 550{ 551 return &st_vg_api; 552} 553