1 /************************************************************************** 2 * 3 * Copyright 2009, VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 /* 28 * Author: Keith Whitwell <keithw (at) vmware.com> 29 * Author: Jakob Bornecrantz <wallbraker (at) gmail.com> 30 */ 31 32 #include "dri_screen.h" 33 #include "dri_context.h" 34 #include "dri_drawable.h" 35 36 #include "pipe/p_screen.h" 37 #include "util/u_format.h" 38 #include "util/u_memory.h" 39 #include "util/u_inlines.h" 40 41 static uint32_t drifb_ID = 0; 42 43 static void 44 swap_fences_unref(struct dri_drawable *draw); 45 46 static boolean 47 dri_st_framebuffer_validate(struct st_context_iface *stctx, 48 struct st_framebuffer_iface *stfbi, 49 const enum st_attachment_type *statts, 50 unsigned count, 51 struct pipe_resource **out) 52 { 53 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private; 54 struct dri_drawable *drawable = 55 (struct dri_drawable *) stfbi->st_manager_private; 56 struct dri_screen *screen = dri_screen(drawable->sPriv); 57 unsigned statt_mask, new_mask; 58 boolean new_stamp; 59 int i; 60 unsigned int lastStamp; 61 struct pipe_resource **textures = 62 drawable->stvis.samples > 1 ? drawable->msaa_textures 63 : drawable->textures; 64 65 statt_mask = 0x0; 66 for (i = 0; i < count; i++) 67 statt_mask |= (1 << statts[i]); 68 69 /* record newly allocated textures */ 70 new_mask = (statt_mask & ~drawable->texture_mask); 71 72 /* 73 * dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the 74 * client stamp. It has the value of the server stamp when last 75 * checked. 76 */ 77 do { 78 lastStamp = drawable->dPriv->lastStamp; 79 new_stamp = (drawable->texture_stamp != lastStamp); 80 81 if (new_stamp || new_mask || screen->broken_invalidate) { 82 if (new_stamp && drawable->update_drawable_info) 83 drawable->update_drawable_info(drawable); 84 85 drawable->allocate_textures(ctx, drawable, statts, count); 86 87 /* add existing textures */ 88 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 89 if (textures[i]) 90 statt_mask |= (1 << i); 91 } 92 93 drawable->texture_stamp = lastStamp; 94 drawable->texture_mask = statt_mask; 95 } 96 } while (lastStamp != drawable->dPriv->lastStamp); 97 98 if (!out) 99 return TRUE; 100 101 /* Set the window-system buffers for the state tracker. */ 102 for (i = 0; i < count; i++) 103 pipe_resource_reference(&out[i], textures[statts[i]]); 104 105 return TRUE; 106 } 107 108 static boolean 109 dri_st_framebuffer_flush_front(struct st_context_iface *stctx, 110 struct st_framebuffer_iface *stfbi, 111 enum st_attachment_type statt) 112 { 113 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private; 114 struct dri_drawable *drawable = 115 (struct dri_drawable *) stfbi->st_manager_private; 116 117 /* XXX remove this and just set the correct one on the framebuffer */ 118 drawable->flush_frontbuffer(ctx, drawable, statt); 119 120 return TRUE; 121 } 122 123 /** 124 * The state tracker framebuffer interface flush_swapbuffers callback 125 */ 126 static boolean 127 dri_st_framebuffer_flush_swapbuffers(struct st_context_iface *stctx, 128 struct st_framebuffer_iface *stfbi) 129 { 130 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private; 131 struct dri_drawable *drawable = 132 (struct dri_drawable *) stfbi->st_manager_private; 133 134 if (drawable->flush_swapbuffers) 135 drawable->flush_swapbuffers(ctx, drawable); 136 137 return TRUE; 138 } 139 140 /** 141 * This is called when we need to set up GL rendering to a new X window. 142 */ 143 boolean 144 dri_create_buffer(__DRIscreen * sPriv, 145 __DRIdrawable * dPriv, 146 const struct gl_config * visual, boolean isPixmap) 147 { 148 struct dri_screen *screen = sPriv->driverPrivate; 149 struct dri_drawable *drawable = NULL; 150 151 if (isPixmap) 152 goto fail; /* not implemented */ 153 154 drawable = CALLOC_STRUCT(dri_drawable); 155 if (drawable == NULL) 156 goto fail; 157 158 dri_fill_st_visual(&drawable->stvis, screen, visual); 159 160 /* setup the st_framebuffer_iface */ 161 drawable->base.visual = &drawable->stvis; 162 drawable->base.flush_front = dri_st_framebuffer_flush_front; 163 drawable->base.validate = dri_st_framebuffer_validate; 164 drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers; 165 drawable->base.st_manager_private = (void *) drawable; 166 167 drawable->screen = screen; 168 drawable->sPriv = sPriv; 169 drawable->dPriv = dPriv; 170 drawable->desired_fences = screen->default_throttle_frames; 171 if (drawable->desired_fences > DRI_SWAP_FENCES_MAX) 172 drawable->desired_fences = DRI_SWAP_FENCES_MAX; 173 174 dPriv->driverPrivate = (void *)drawable; 175 p_atomic_set(&drawable->base.stamp, 1); 176 drawable->base.ID = p_atomic_inc_return(&drifb_ID); 177 drawable->base.state_manager = &screen->base; 178 179 return GL_TRUE; 180 fail: 181 FREE(drawable); 182 return GL_FALSE; 183 } 184 185 void 186 dri_destroy_buffer(__DRIdrawable * dPriv) 187 { 188 struct dri_drawable *drawable = dri_drawable(dPriv); 189 struct dri_screen *screen = drawable->screen; 190 struct st_api *stapi = screen->st_api; 191 int i; 192 193 pipe_surface_reference(&drawable->drisw_surface, NULL); 194 195 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 196 pipe_resource_reference(&drawable->textures[i], NULL); 197 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 198 pipe_resource_reference(&drawable->msaa_textures[i], NULL); 199 200 swap_fences_unref(drawable); 201 202 /* Notify the st manager that this drawable is no longer valid */ 203 stapi->destroy_drawable(stapi, &drawable->base); 204 205 FREE(drawable); 206 } 207 208 /** 209 * Validate the texture at an attachment. Allocate the texture if it does not 210 * exist. Used by the TFP extension. 211 */ 212 static void 213 dri_drawable_validate_att(struct dri_context *ctx, 214 struct dri_drawable *drawable, 215 enum st_attachment_type statt) 216 { 217 enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; 218 unsigned i, count = 0; 219 220 /* check if buffer already exists */ 221 if (drawable->texture_mask & (1 << statt)) 222 return; 223 224 /* make sure DRI2 does not destroy existing buffers */ 225 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 226 if (drawable->texture_mask & (1 << i)) { 227 statts[count++] = i; 228 } 229 } 230 statts[count++] = statt; 231 232 drawable->texture_stamp = drawable->dPriv->lastStamp - 1; 233 234 drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL); 235 } 236 237 /** 238 * These are used for GLX_EXT_texture_from_pixmap 239 */ 240 static void 241 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 242 GLint format, __DRIdrawable *dPriv) 243 { 244 struct dri_context *ctx = dri_context(pDRICtx); 245 struct st_context_iface *st = ctx->st; 246 struct dri_drawable *drawable = dri_drawable(dPriv); 247 struct pipe_resource *pt; 248 249 if (st->thread_finish) 250 st->thread_finish(st); 251 252 dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT); 253 254 /* Use the pipe resource associated with the X drawable */ 255 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 256 257 if (pt) { 258 enum pipe_format internal_format = pt->format; 259 260 if (format == __DRI_TEXTURE_FORMAT_RGB) { 261 /* only need to cover the formats recognized by dri_fill_st_visual */ 262 switch (internal_format) { 263 case PIPE_FORMAT_B10G10R10A2_UNORM: 264 internal_format = PIPE_FORMAT_B10G10R10X2_UNORM; 265 break; 266 case PIPE_FORMAT_BGRA8888_UNORM: 267 internal_format = PIPE_FORMAT_BGRX8888_UNORM; 268 break; 269 case PIPE_FORMAT_ARGB8888_UNORM: 270 internal_format = PIPE_FORMAT_XRGB8888_UNORM; 271 break; 272 default: 273 break; 274 } 275 } 276 277 drawable->update_tex_buffer(drawable, ctx, pt); 278 279 ctx->st->teximage(ctx->st, 280 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 281 0, internal_format, pt, FALSE); 282 } 283 } 284 285 static void 286 dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 287 __DRIdrawable *dPriv) 288 { 289 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 290 } 291 292 const __DRItexBufferExtension driTexBufferExtension = { 293 .base = { __DRI_TEX_BUFFER, 2 }, 294 295 .setTexBuffer = dri_set_tex_buffer, 296 .setTexBuffer2 = dri_set_tex_buffer2, 297 .releaseTexBuffer = NULL, 298 }; 299 300 /** 301 * Get the format and binding of an attachment. 302 */ 303 void 304 dri_drawable_get_format(struct dri_drawable *drawable, 305 enum st_attachment_type statt, 306 enum pipe_format *format, 307 unsigned *bind) 308 { 309 switch (statt) { 310 case ST_ATTACHMENT_FRONT_LEFT: 311 case ST_ATTACHMENT_BACK_LEFT: 312 case ST_ATTACHMENT_FRONT_RIGHT: 313 case ST_ATTACHMENT_BACK_RIGHT: 314 /* Other pieces of the driver stack get confused and behave incorrectly 315 * when they get an sRGB drawable. st/mesa receives "drawable->stvis" 316 * though other means and handles it correctly, so we don't really need 317 * to use an sRGB format here. 318 */ 319 *format = util_format_linear(drawable->stvis.color_format); 320 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 321 break; 322 case ST_ATTACHMENT_DEPTH_STENCIL: 323 *format = drawable->stvis.depth_stencil_format; 324 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 325 break; 326 default: 327 *format = PIPE_FORMAT_NONE; 328 *bind = 0; 329 break; 330 } 331 } 332 333 334 /** 335 * swap_fences_pop_front - pull a fence from the throttle queue 336 * 337 * If the throttle queue is filled to the desired number of fences, 338 * pull fences off the queue until the number is less than the desired 339 * number of fences, and return the last fence pulled. 340 */ 341 static struct pipe_fence_handle * 342 swap_fences_pop_front(struct dri_drawable *draw) 343 { 344 struct pipe_screen *screen = draw->screen->base.screen; 345 struct pipe_fence_handle *fence = NULL; 346 347 if (draw->desired_fences == 0) 348 return NULL; 349 350 if (draw->cur_fences >= draw->desired_fences) { 351 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 352 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 353 draw->tail &= DRI_SWAP_FENCES_MASK; 354 --draw->cur_fences; 355 } 356 return fence; 357 } 358 359 360 /** 361 * swap_fences_push_back - push a fence onto the throttle queue 362 * 363 * push a fence onto the throttle queue and pull fences of the queue 364 * so that the desired number of fences are on the queue. 365 */ 366 static void 367 swap_fences_push_back(struct dri_drawable *draw, 368 struct pipe_fence_handle *fence) 369 { 370 struct pipe_screen *screen = draw->screen->base.screen; 371 372 if (!fence || draw->desired_fences == 0) 373 return; 374 375 while(draw->cur_fences == draw->desired_fences) 376 swap_fences_pop_front(draw); 377 378 draw->cur_fences++; 379 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 380 fence); 381 draw->head &= DRI_SWAP_FENCES_MASK; 382 } 383 384 385 /** 386 * swap_fences_unref - empty the throttle queue 387 * 388 * pulls fences of the throttle queue until it is empty. 389 */ 390 static void 391 swap_fences_unref(struct dri_drawable *draw) 392 { 393 struct pipe_screen *screen = draw->screen->base.screen; 394 395 while(draw->cur_fences) { 396 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 397 draw->tail &= DRI_SWAP_FENCES_MASK; 398 --draw->cur_fences; 399 } 400 } 401 402 void 403 dri_pipe_blit(struct pipe_context *pipe, 404 struct pipe_resource *dst, 405 struct pipe_resource *src) 406 { 407 struct pipe_blit_info blit; 408 409 if (!dst || !src) 410 return; 411 412 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample 413 * Fragment Operations): 414 * 415 * If a framebuffer object is not bound, after all operations have 416 * been completed on the multisample buffer, the sample values for 417 * each color in the multisample buffer are combined to produce a 418 * single color value, and that value is written into the 419 * corresponding color buffers selected by DrawBuffer or 420 * DrawBuffers. An implementation may defer the writing of the color 421 * buffers until a later time, but the state of the framebuffer must 422 * behave as if the color buffers were updated as each fragment was 423 * processed. The method of combination is not specified. If the 424 * framebuffer contains sRGB values, then it is recommended that the 425 * an average of sample values is computed in a linearized space, as 426 * for blending (see section 4.1.7). 427 * 428 * In other words, to do a resolve operation in a linear space, we have 429 * to set sRGB formats if the original resources were sRGB, so don't use 430 * util_format_linear. 431 */ 432 433 memset(&blit, 0, sizeof(blit)); 434 blit.dst.resource = dst; 435 blit.dst.box.width = dst->width0; 436 blit.dst.box.height = dst->height0; 437 blit.dst.box.depth = 1; 438 blit.dst.format = dst->format; 439 blit.src.resource = src; 440 blit.src.box.width = src->width0; 441 blit.src.box.height = src->height0; 442 blit.src.box.depth = 1; 443 blit.src.format = src->format; 444 blit.mask = PIPE_MASK_RGBA; 445 blit.filter = PIPE_TEX_FILTER_NEAREST; 446 447 pipe->blit(pipe, &blit); 448 } 449 450 static void 451 dri_postprocessing(struct dri_context *ctx, 452 struct dri_drawable *drawable, 453 enum st_attachment_type att) 454 { 455 struct pipe_resource *src = drawable->textures[att]; 456 struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]; 457 458 if (ctx->pp && src) 459 pp_run(ctx->pp, src, src, zsbuf); 460 } 461 462 /** 463 * DRI2 flush extension, the flush_with_flags function. 464 * 465 * \param context the context 466 * \param drawable the drawable to flush 467 * \param flags a combination of _DRI2_FLUSH_xxx flags 468 * \param throttle_reason the reason for throttling, 0 = no throttling 469 */ 470 void 471 dri_flush(__DRIcontext *cPriv, 472 __DRIdrawable *dPriv, 473 unsigned flags, 474 enum __DRI2throttleReason reason) 475 { 476 struct dri_context *ctx = dri_context(cPriv); 477 struct dri_drawable *drawable = dri_drawable(dPriv); 478 struct st_context_iface *st; 479 unsigned flush_flags; 480 boolean swap_msaa_buffers = FALSE; 481 482 if (!ctx) { 483 assert(0); 484 return; 485 } 486 487 st = ctx->st; 488 if (st->thread_finish) 489 st->thread_finish(st); 490 491 if (drawable) { 492 /* prevent recursion */ 493 if (drawable->flushing) 494 return; 495 496 drawable->flushing = TRUE; 497 } 498 else { 499 flags &= ~__DRI2_FLUSH_DRAWABLE; 500 } 501 502 /* Flush the drawable. */ 503 if ((flags & __DRI2_FLUSH_DRAWABLE) && 504 drawable->textures[ST_ATTACHMENT_BACK_LEFT]) { 505 struct pipe_context *pipe = st->pipe; 506 507 if (drawable->stvis.samples > 1 && 508 reason == __DRI2_THROTTLE_SWAPBUFFER) { 509 /* Resolve the MSAA back buffer. */ 510 dri_pipe_blit(st->pipe, 511 drawable->textures[ST_ATTACHMENT_BACK_LEFT], 512 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); 513 514 if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] && 515 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) { 516 swap_msaa_buffers = TRUE; 517 } 518 519 /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */ 520 } 521 522 dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT); 523 524 if (ctx->hud) { 525 hud_run(ctx->hud, ctx->st->cso_context, 526 drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 527 } 528 529 pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 530 531 if (pipe->invalidate_resource && 532 (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) { 533 if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 534 pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 535 if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]) 536 pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]); 537 } 538 } 539 540 flush_flags = 0; 541 if (flags & __DRI2_FLUSH_CONTEXT) 542 flush_flags |= ST_FLUSH_FRONT; 543 if (reason == __DRI2_THROTTLE_SWAPBUFFER) 544 flush_flags |= ST_FLUSH_END_OF_FRAME; 545 546 /* Flush the context and throttle if needed. */ 547 if (dri_screen(ctx->sPriv)->throttling_enabled && 548 drawable && 549 (reason == __DRI2_THROTTLE_SWAPBUFFER || 550 reason == __DRI2_THROTTLE_FLUSHFRONT)) { 551 /* Throttle. 552 * 553 * This pulls a fence off the throttling queue and waits for it if the 554 * number of fences on the throttling queue has reached the desired 555 * number. 556 * 557 * Then flushes to insert a fence at the current rendering position, and 558 * pushes that fence on the queue. This requires that the st_context_iface 559 * flush method returns a fence even if there are no commands to flush. 560 */ 561 struct pipe_screen *screen = drawable->screen->base.screen; 562 struct pipe_fence_handle *fence; 563 564 fence = swap_fences_pop_front(drawable); 565 if (fence) { 566 (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 567 screen->fence_reference(screen, &fence, NULL); 568 } 569 570 st->flush(st, flush_flags, &fence); 571 572 if (fence) { 573 swap_fences_push_back(drawable, fence); 574 screen->fence_reference(screen, &fence, NULL); 575 } 576 } 577 else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) { 578 st->flush(st, flush_flags, NULL); 579 } 580 581 if (drawable) { 582 drawable->flushing = FALSE; 583 } 584 585 /* Swap the MSAA front and back buffers, so that reading 586 * from the front buffer after SwapBuffers returns what was 587 * in the back buffer. 588 */ 589 if (swap_msaa_buffers) { 590 struct pipe_resource *tmp = 591 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]; 592 593 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] = 594 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]; 595 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp; 596 597 /* Now that we have swapped the buffers, this tells the state 598 * tracker to revalidate the framebuffer. 599 */ 600 p_atomic_inc(&drawable->base.stamp); 601 } 602 } 603 604 /** 605 * dri_throttle - A DRI2ThrottleExtension throttling function. 606 */ 607 static void 608 dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv, 609 enum __DRI2throttleReason reason) 610 { 611 dri_flush(cPriv, dPriv, 0, reason); 612 } 613 614 615 const __DRI2throttleExtension dri2ThrottleExtension = { 616 .base = { __DRI2_THROTTLE, 1 }, 617 618 .throttle = dri_throttle, 619 }; 620 621 622 /* vim: set sw=3 ts=8 sts=3 expandtab: */ 623