vg_manager.c revision 438359597cd4254558f4d2fd5b54eb32c03e1b4c
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 100vg_context_update_alpha_mask_view(struct vg_context *ctx, 101 uint width, uint height) 102{ 103 struct st_framebuffer *stfb = ctx->draw_buffer; 104 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; 105 struct pipe_context *pipe = ctx->pipe; 106 107 if (old_sampler_view && 108 old_sampler_view->texture->width0 == width && 109 old_sampler_view->texture->height0 == height) 110 return; 111 112 /* 113 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to 114 this texture and use it as a sampler, so while this wastes some 115 space it makes both of those a lot simpler 116 */ 117 stfb->alpha_mask_view = create_tex_and_view(pipe, 118 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 119 120 if (!stfb->alpha_mask_view) { 121 if (old_sampler_view) 122 pipe_sampler_view_reference(&old_sampler_view, NULL); 123 return; 124 } 125 126 /* XXX could this call be avoided? */ 127 vg_validate_state(ctx); 128 129 /* alpha mask starts with 1.f alpha */ 130 mask_fill(0, 0, width, height, 1.f); 131 132 /* if we had an old surface copy it over */ 133 if (old_sampler_view) { 134 struct pipe_subresource subsurf, subold_surf; 135 subsurf.face = 0; 136 subsurf.level = 0; 137 subold_surf.face = 0; 138 subold_surf.level = 0; 139 pipe->resource_copy_region(pipe, 140 stfb->alpha_mask_view->texture, 141 subsurf, 142 0, 0, 0, 143 old_sampler_view->texture, 144 subold_surf, 145 0, 0, 0, 146 MIN2(old_sampler_view->texture->width0, 147 stfb->alpha_mask_view->texture->width0), 148 MIN2(old_sampler_view->texture->height0, 149 stfb->alpha_mask_view->texture->height0)); 150 } 151 152 /* Free the old texture 153 */ 154 if (old_sampler_view) 155 pipe_sampler_view_reference(&old_sampler_view, NULL); 156} 157 158static void 159vg_context_update_blend_texture_view(struct vg_context *ctx, 160 uint width, uint height) 161{ 162 struct pipe_context *pipe = ctx->pipe; 163 struct st_framebuffer *stfb = ctx->draw_buffer; 164 struct pipe_sampler_view *old = stfb->blend_texture_view; 165 166 if (old && 167 old->texture->width0 == width && 168 old->texture->height0 == height) 169 return; 170 171 stfb->blend_texture_view = create_tex_and_view(pipe, 172 PIPE_FORMAT_B8G8R8A8_UNORM, width, height); 173 174 pipe_sampler_view_reference(&old, NULL); 175} 176 177static boolean 178vg_context_update_depth_stencil_rb(struct vg_context * ctx, 179 uint width, uint height) 180{ 181 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; 182 struct pipe_context *pipe = ctx->pipe; 183 unsigned surface_usage; 184 185 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) 186 return FALSE; 187 188 /* unreference existing ones */ 189 pipe_surface_reference(&dsrb->surface, NULL); 190 pipe_resource_reference(&dsrb->texture, NULL); 191 dsrb->width = dsrb->height = 0; 192 193 /* Probably need dedicated flags for surface usage too: 194 */ 195 surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */ 196 197 dsrb->texture = create_texture(pipe, dsrb->format, width, height); 198 if (!dsrb->texture) 199 return TRUE; 200 201 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, 202 dsrb->texture, 203 0, 0, 0, 204 surface_usage); 205 if (!dsrb->surface) { 206 pipe_resource_reference(&dsrb->texture, NULL); 207 return TRUE; 208 } 209 210 dsrb->width = width; 211 dsrb->height = height; 212 213 assert(dsrb->surface->width == width); 214 assert(dsrb->surface->height == height); 215 216 return TRUE; 217} 218 219static boolean 220vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) 221{ 222 struct st_renderbuffer *strb = ctx->draw_buffer->strb; 223 struct pipe_screen *screen = ctx->pipe->screen; 224 225 if (strb->texture == pt) { 226 pipe_resource_reference(&pt, NULL); 227 return FALSE; 228 } 229 230 /* unreference existing ones */ 231 pipe_surface_reference(&strb->surface, NULL); 232 pipe_resource_reference(&strb->texture, NULL); 233 strb->width = strb->height = 0; 234 235 strb->texture = pt; 236 strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, 237 PIPE_BIND_RENDER_TARGET); 238 if (!strb->surface) { 239 pipe_resource_reference(&strb->texture, NULL); 240 return TRUE; 241 } 242 243 strb->width = pt->width0; 244 strb->height = pt->height0; 245 246 return TRUE; 247} 248 249/** 250 * Flush the front buffer if the current context renders to the front buffer. 251 */ 252void 253vg_manager_flush_frontbuffer(struct vg_context *ctx) 254{ 255 struct st_framebuffer *stfb = ctx->draw_buffer; 256 257 if (!stfb) 258 return; 259 260 switch (stfb->strb_att) { 261 case ST_ATTACHMENT_FRONT_LEFT: 262 case ST_ATTACHMENT_FRONT_RIGHT: 263 stfb->iface->flush_front(stfb->iface, stfb->strb_att); 264 break; 265 default: 266 break; 267 } 268} 269 270/** 271 * Re-validate the framebuffer. 272 */ 273void 274vg_manager_validate_framebuffer(struct vg_context *ctx) 275{ 276 struct st_framebuffer *stfb = ctx->draw_buffer; 277 struct pipe_resource *pt; 278 279 /* no binding surface */ 280 if (!stfb) 281 return; 282 283 if (!p_atomic_read(&ctx->draw_buffer_invalid)) 284 return; 285 286 /* validate the fb */ 287 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) 288 return; 289 290 p_atomic_set(&ctx->draw_buffer_invalid, FALSE); 291 292 if (vg_context_update_color_rb(ctx, pt) || 293 stfb->width != pt->width0 || 294 stfb->height != pt->height0) 295 ctx->state.dirty |= FRAMEBUFFER_DIRTY; 296 297 if (vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0)) 298 ctx->state.dirty |= DEPTH_STENCIL_DIRTY; 299 300 stfb->width = pt->width0; 301 stfb->height = pt->height0; 302 303 /* TODO create as needed */ 304 vg_context_update_alpha_mask_view(ctx, stfb->width, stfb->height); 305 vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height); 306} 307 308static void 309vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi, 310 struct st_framebuffer_iface *stfbi) 311{ 312 struct vg_context *ctx = (struct vg_context *) stctxi; 313 p_atomic_set(&ctx->draw_buffer_invalid, TRUE); 314} 315 316static void 317vg_context_flush(struct st_context_iface *stctxi, unsigned flags, 318 struct pipe_fence_handle **fence) 319{ 320 struct vg_context *ctx = (struct vg_context *) stctxi; 321 ctx->pipe->flush(ctx->pipe, flags, fence); 322 if (flags & PIPE_FLUSH_RENDER_CACHE) 323 vg_manager_flush_frontbuffer(ctx); 324} 325 326static void 327vg_context_destroy(struct st_context_iface *stctxi) 328{ 329 struct vg_context *ctx = (struct vg_context *) stctxi; 330 vg_destroy_context(ctx); 331} 332 333static struct st_context_iface * 334vg_api_create_context(struct st_api *stapi, struct st_manager *smapi, 335 const struct st_context_attribs *attribs, 336 struct st_context_iface *shared_stctxi) 337{ 338 struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi; 339 struct vg_context *ctx; 340 struct pipe_context *pipe; 341 342 if (!(stapi->profile_mask & (1 << attribs->profile))) 343 return NULL; 344 345 /* only 1.0 is supported */ 346 if (attribs->major > 1 || (attribs->major == 1 && attribs->minor > 0)) 347 return NULL; 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 destroy_renderbuffer(stfb->strb); 451 destroy_renderbuffer(stfb->dsrb); 452 FREE(stfb); 453 454 ctx->draw_buffer = NULL; 455 } 456 } 457 458 if (!stdrawi) 459 return TRUE; 460 461 if (strb_att == ST_ATTACHMENT_INVALID) 462 return FALSE; 463 464 /* create a new fb */ 465 if (!ctx->draw_buffer) { 466 stfb = CALLOC_STRUCT(st_framebuffer); 467 if (!stfb) 468 return FALSE; 469 470 stfb->strb = create_renderbuffer(stdrawi->visual->color_format); 471 if (!stfb->strb) { 472 FREE(stfb); 473 return FALSE; 474 } 475 476 stfb->dsrb = create_renderbuffer(ctx->ds_format); 477 if (!stfb->dsrb) { 478 FREE(stfb->strb); 479 FREE(stfb); 480 return FALSE; 481 } 482 483 stfb->width = 0; 484 stfb->height = 0; 485 stfb->strb_att = strb_att; 486 487 ctx->draw_buffer = stfb; 488 } 489 490 ctx->draw_buffer->iface = stdrawi; 491 492 return TRUE; 493} 494 495static boolean 496vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi, 497 struct st_framebuffer_iface *stdrawi, 498 struct st_framebuffer_iface *streadi) 499{ 500 struct vg_context *ctx = (struct vg_context *) stctxi; 501 502 if (stctxi) 503 vg_context_bind_framebuffers(stctxi, stdrawi, streadi); 504 vg_set_current_context(ctx); 505 506 return TRUE; 507} 508 509static struct st_context_iface * 510vg_api_get_current(struct st_api *stapi) 511{ 512 struct vg_context *ctx = vg_current_context(); 513 514 return (ctx) ? &ctx->iface : NULL; 515} 516 517static st_proc_t 518vg_api_get_proc_address(struct st_api *stapi, const char *procname) 519{ 520 return api_get_proc_address(procname); 521} 522 523static void 524vg_api_destroy(struct st_api *stapi) 525{ 526} 527 528static const struct st_api vg_api = { 529 "Vega " VEGA_VERSION_STRING, 530 ST_API_OPENVG, 531 ST_PROFILE_DEFAULT_MASK, 532 vg_api_destroy, 533 vg_api_get_proc_address, 534 vg_api_create_context, 535 vg_api_make_current, 536 vg_api_get_current, 537}; 538 539const struct st_api * 540vg_api_get(void) 541{ 542 return &vg_api; 543} 544