vg_manager.c revision 4531356817ec8383ac35932903773de67af92e37
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_api.h" 40#include "vg_manager.h" 41#include "vg_context.h" 42#include "image.h" 43#include "mask.h" 44#include "api.h" 45 46static struct pipe_resource * 47create_texture(struct pipe_context *pipe, enum pipe_format format, 48 VGint width, VGint height) 49{ 50 struct pipe_resource templ; 51 52 memset(&templ, 0, sizeof(templ)); 53 54 if (format != PIPE_FORMAT_NONE) { 55 templ.format = format; 56 } 57 else { 58 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; 59 } 60 61 templ.target = PIPE_TEXTURE_2D; 62 templ.width0 = width; 63 templ.height0 = height; 64 templ.depth0 = 1; 65 templ.last_level = 0; 66 67 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { 68 templ.bind = PIPE_BIND_DEPTH_STENCIL; 69 } else { 70 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 71 PIPE_BIND_RENDER_TARGET | 72 PIPE_BIND_SAMPLER_VIEW); 73 } 74 75 return pipe->screen->resource_create(pipe->screen, &templ); 76} 77 78static struct pipe_sampler_view * 79create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, 80 VGint width, VGint height) 81{ 82 struct pipe_resource *texture; 83 struct pipe_sampler_view view_templ; 84 struct pipe_sampler_view *view; 85 86 texture = create_texture(pipe, format, width, height); 87 88 if (!texture) 89 return NULL; 90 91 u_sampler_view_default_template(&view_templ, texture, texture->format); 92 view = pipe->create_sampler_view(pipe, texture, &view_templ); 93 /* want the texture to go away if the view is freed */ 94 pipe_resource_reference(&texture, NULL); 95 96 return view; 97} 98 99static void 100setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb) 101{ 102 struct pipe_context *pipe = ctx->pipe; 103 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; 104 105 /* 106 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to 107 this texture and use it as a sampler, so while this wastes some 108 space it makes both of those a lot simpler 109 */ 110 stfb->alpha_mask_view = create_tex_and_view(pipe, 111 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); 112 113 if (!stfb->alpha_mask_view) { 114 if (old_sampler_view) 115 pipe_sampler_view_reference(&old_sampler_view, NULL); 116 return; 117 } 118 119 /* XXX could this call be avoided? */ 120 vg_validate_state(ctx); 121 122 /* alpha mask starts with 1.f alpha */ 123 mask_fill(0, 0, stfb->width, stfb->height, 1.f); 124 125 /* if we had an old surface copy it over */ 126 if (old_sampler_view) { 127 struct pipe_subresource subsurf, subold_surf; 128 subsurf.face = 0; 129 subsurf.level = 0; 130 subold_surf.face = 0; 131 subold_surf.level = 0; 132 pipe->resource_copy_region(pipe, 133 stfb->alpha_mask_view->texture, 134 subsurf, 135 0, 0, 0, 136 old_sampler_view->texture, 137 subold_surf, 138 0, 0, 0, 139 MIN2(old_sampler_view->texture->width0, 140 stfb->alpha_mask_view->texture->width0), 141 MIN2(old_sampler_view->texture->height0, 142 stfb->alpha_mask_view->texture->height0)); 143 } 144 145 /* Free the old texture 146 */ 147 if (old_sampler_view) 148 pipe_sampler_view_reference(&old_sampler_view, NULL); 149} 150 151static boolean 152vg_context_update_depth_stencil_rb(struct vg_context * ctx, 153 uint width, uint height) 154{ 155 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 156 struct pipe_context *pipe = ctx->pipe; 157 unsigned surface_usage; 158 159 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 160 return FALSE; 161 162 /* unreference existing ones */ 163 pipe_surface_reference(&dsrb->surface, NULL); 164 pipe_resource_reference(&dsrb->texture, NULL); 165 dsrb->width = dsrb->height = 0; 166 167 /* Probably need dedicated flags for surface usage too: 168 */ 169 surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */ 170 171 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 172 if (!dsrb->texture) 173 return TRUE; 174 175 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, 176 dsrb->texture, 177 0, 0, 0, 178 surface_usage); 179 if (!dsrb->surface) { 180 pipe_resource_reference(&dsrb->texture, NULL); 181 return TRUE; 182 } 183 184 dsrb->width = width; 185 dsrb->height = height; 186 187 assert(dsrb->surface->width == width); 188 assert(dsrb->surface->height == height); 189 190 return TRUE; 191} 192 193static boolean 194vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) 195{ 196 struct st_renderbuffer *strb = ctx->draw_buffer->strb; 197 struct pipe_screen *screen = ctx->pipe->screen; 198 199 if (strb->texture == pt) { 200 pipe_resource_reference(&pt, NULL); 201 return FALSE; 202 } 203 204 /* unreference existing ones */ 205 pipe_surface_reference(&strb->surface, NULL); 206 pipe_resource_reference(&strb->texture, NULL); 207 strb->width = strb->height = 0; 208 209 strb->texture = pt; 210 strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, 211 PIPE_BIND_RENDER_TARGET); 212 if (!strb->surface) { 213 pipe_resource_reference(&strb->texture, NULL); 214 return TRUE; 215 } 216 217 strb->width = pt->width0; 218 strb->height = pt->height0; 219 220 return TRUE; 221} 222 223static void 224vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt) 225{ 226 struct st_framebuffer *stfb = ctx->draw_buffer; 227 boolean new_cbuf, new_zsbuf, new_size; 228 229 new_cbuf = vg_context_update_color_rb(ctx, pt); 230 new_zsbuf = 231 vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0); 232 233 new_size = (stfb->width != pt->width0 || stfb->height != pt->height0); 234 stfb->width = pt->width0; 235 stfb->height = pt->height0; 236 237 if (new_cbuf || new_zsbuf || new_size) { 238 struct pipe_framebuffer_state *state = &ctx->state.g3d.fb; 239 240 memset(state, 0, sizeof(struct pipe_framebuffer_state)); 241 state->width = stfb->width; 242 state->height = stfb->height; 243 state->nr_cbufs = 1; 244 state->cbufs[0] = stfb->strb->surface; 245 state->zsbuf = stfb->dsrb->surface; 246 247 cso_set_framebuffer(ctx->cso_context, state); 248 } 249 250 if (new_zsbuf || new_size) { 251 ctx->state.dirty |= VIEWPORT_DIRTY; 252 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/ 253 254 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0); 255 256 /* we need all the other state already set */ 257 258 setup_new_alpha_mask(ctx, stfb); 259 260 pipe_sampler_view_reference( &stfb->blend_texture_view, NULL); 261 stfb->blend_texture_view = create_tex_and_view(ctx->pipe, 262 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); 263 } 264} 265 266/** 267 * Flush the front buffer if the current context renders to the front buffer. 268 */ 269void 270vg_manager_flush_frontbuffer(struct vg_context *ctx) 271{ 272 struct st_framebuffer *stfb = ctx->draw_buffer; 273 274 if (!stfb) 275 return; 276 277 switch (stfb->strb_att) { 278 case ST_ATTACHMENT_FRONT_LEFT: 279 case ST_ATTACHMENT_FRONT_RIGHT: 280 stfb->iface->flush_front(stfb->iface, stfb->strb_att); 281 break; 282 default: 283 break; 284 } 285} 286 287/** 288 * Re-validate the framebuffer. 289 */ 290void 291vg_manager_validate_framebuffer(struct vg_context *ctx) 292{ 293 struct st_framebuffer *stfb = ctx->draw_buffer; 294 struct pipe_resource *pt; 295 296 /* no binding surface */ 297 if (!stfb) 298 return; 299 300 if (!p_atomic_read(&ctx->draw_buffer_invalid)) 301 return; 302 303 /* validate the fb */ 304 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) 305 return; 306 307 /* 308 * unset draw_buffer_invalid first because vg_context_update_draw_buffer 309 * will cause the framebuffer to be validated again because of a call to 310 * vg_validate_state 311 */ 312 p_atomic_set(&ctx->draw_buffer_invalid, FALSE); 313 vg_context_update_draw_buffer(ctx, pt); 314} 315 316 317static void 318vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi, 319 struct st_framebuffer_iface *stfbi) 320{ 321 struct vg_context *ctx = (struct vg_context *) stctxi; 322 p_atomic_set(&ctx->draw_buffer_invalid, TRUE); 323} 324 325static void 326vg_context_flush(struct st_context_iface *stctxi, unsigned flags, 327 struct pipe_fence_handle **fence) 328{ 329 struct vg_context *ctx = (struct vg_context *) stctxi; 330 ctx->pipe->flush(ctx->pipe, flags, fence); 331 if (flags & PIPE_FLUSH_RENDER_CACHE) 332 vg_manager_flush_frontbuffer(ctx); 333} 334 335static void 336vg_context_destroy(struct st_context_iface *stctxi) 337{ 338 struct vg_context *ctx = (struct vg_context *) stctxi; 339 vg_destroy_context(ctx); 340} 341 342static struct st_context_iface * 343vg_api_create_context(struct st_api *stapi, struct st_manager *smapi, 344 const struct st_context_attribs *attribs, 345 struct st_context_iface *shared_stctxi) 346{ 347 struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi; 348 struct vg_context *ctx; 349 struct pipe_context *pipe; 350 351 if (!(stapi->profile_mask & (1 << attribs->profile))) 352 return NULL; 353 354 /* only 1.0 is supported */ 355 if (attribs->major != 1 || attribs->minor > 0) 356 return NULL; 357 358 pipe = smapi->screen->context_create(smapi->screen, NULL); 359 if (!pipe) 360 return NULL; 361 ctx = vg_create_context(pipe, NULL, shared_ctx); 362 if (!ctx) { 363 pipe->destroy(pipe); 364 return NULL; 365 } 366 367 ctx->iface.destroy = vg_context_destroy; 368 369 ctx->iface.notify_invalid_framebuffer = 370 vg_context_notify_invalid_framebuffer; 371 ctx->iface.flush = vg_context_flush; 372 373 ctx->iface.teximage = NULL; 374 ctx->iface.copy = NULL; 375 376 ctx->iface.st_context_private = (void *) smapi; 377 378 return &ctx->iface; 379} 380 381static struct st_renderbuffer * 382create_renderbuffer(enum pipe_format format) 383{ 384 struct st_renderbuffer *strb; 385 386 strb = CALLOC_STRUCT(st_renderbuffer); 387 if (strb) 388 strb->format = format; 389 390 return strb; 391} 392 393static void 394destroy_renderbuffer(struct st_renderbuffer *strb) 395{ 396 pipe_surface_reference(&strb->surface, NULL); 397 pipe_resource_reference(&strb->texture, NULL); 398 FREE(strb); 399} 400 401/** 402 * Decide the buffer to render to. 403 */ 404static enum st_attachment_type 405choose_attachment(struct st_framebuffer_iface *stfbi) 406{ 407 enum st_attachment_type statt; 408 409 statt = stfbi->visual->render_buffer; 410 if (statt != ST_ATTACHMENT_INVALID) { 411 /* use the buffer given by the visual, unless it is unavailable */ 412 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) { 413 switch (statt) { 414 case ST_ATTACHMENT_BACK_LEFT: 415 statt = ST_ATTACHMENT_FRONT_LEFT; 416 break; 417 case ST_ATTACHMENT_BACK_RIGHT: 418 statt = ST_ATTACHMENT_FRONT_RIGHT; 419 break; 420 default: 421 break; 422 } 423 424 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) 425 statt = ST_ATTACHMENT_INVALID; 426 } 427 } 428 429 return statt; 430} 431 432/** 433 * Bind the context to the given framebuffers. 434 */ 435static boolean 436vg_context_bind_framebuffers(struct st_context_iface *stctxi, 437 struct st_framebuffer_iface *stdrawi, 438 struct st_framebuffer_iface *streadi) 439{ 440 struct vg_context *ctx = (struct vg_context *) stctxi; 441 struct st_framebuffer *stfb; 442 enum st_attachment_type strb_att; 443 444 /* the draw and read framebuffers must be the same */ 445 if (stdrawi != streadi) 446 return FALSE; 447 448 p_atomic_set(&ctx->draw_buffer_invalid, TRUE); 449 450 strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID; 451 452 if (ctx->draw_buffer) { 453 stfb = ctx->draw_buffer; 454 455 /* free the existing fb */ 456 if (!stdrawi || 457 stfb->strb_att != strb_att || 458 stfb->strb->format != stdrawi->visual->color_format) { 459 destroy_renderbuffer(stfb->strb); 460 destroy_renderbuffer(stfb->dsrb); 461 FREE(stfb); 462 463 ctx->draw_buffer = NULL; 464 } 465 } 466 467 if (!stdrawi) 468 return TRUE; 469 470 if (strb_att == ST_ATTACHMENT_INVALID) 471 return FALSE; 472 473 /* create a new fb */ 474 if (!ctx->draw_buffer) { 475 stfb = CALLOC_STRUCT(st_framebuffer); 476 if (!stfb) 477 return FALSE; 478 479 stfb->strb = create_renderbuffer(stdrawi->visual->color_format); 480 if (!stfb->strb) { 481 FREE(stfb); 482 return FALSE; 483 } 484 485 stfb->dsrb = create_renderbuffer(ctx->ds_format); 486 if (!stfb->dsrb) { 487 FREE(stfb->strb); 488 FREE(stfb); 489 return FALSE; 490 } 491 492 stfb->width = 0; 493 stfb->height = 0; 494 stfb->strb_att = strb_att; 495 496 ctx->draw_buffer = stfb; 497 } 498 499 ctx->draw_buffer->iface = stdrawi; 500 501 return TRUE; 502} 503 504static boolean 505vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi, 506 struct st_framebuffer_iface *stdrawi, 507 struct st_framebuffer_iface *streadi) 508{ 509 struct vg_context *ctx = (struct vg_context *) stctxi; 510 511 if (stctxi) 512 vg_context_bind_framebuffers(stctxi, stdrawi, streadi); 513 vg_set_current_context(ctx); 514 515 return TRUE; 516} 517 518static struct st_context_iface * 519vg_api_get_current(struct st_api *stapi) 520{ 521 struct vg_context *ctx = vg_current_context(); 522 523 return (ctx) ? &ctx->iface : NULL; 524} 525 526static st_proc_t 527vg_api_get_proc_address(struct st_api *stapi, const char *procname) 528{ 529 return api_get_proc_address(procname); 530} 531 532static void 533vg_api_destroy(struct st_api *stapi) 534{ 535} 536 537static const struct st_api vg_api = { 538 ST_API_OPENVG, 539 ST_PROFILE_DEFAULT_MASK, 540 vg_api_destroy, 541 vg_api_get_proc_address, 542 vg_api_create_context, 543 vg_api_make_current, 544 vg_api_get_current, 545}; 546 547const struct st_api * 548vg_api_get(void) 549{ 550 return &vg_api; 551} 552