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@vmware.com> 29 * Author: Jakob Bornecrantz <wallbraker@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 41static uint32_t drifb_ID = 0; 42 43static void 44swap_fences_unref(struct dri_drawable *draw); 45 46static boolean 47dri_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 108static boolean 109dri_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 */ 126static boolean 127dri_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 */ 143boolean 144dri_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; 180fail: 181 FREE(drawable); 182 return GL_FALSE; 183} 184 185void 186dri_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 */ 212static void 213dri_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 */ 240static void 241dri_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_R10G10B10A2_UNORM: 267 internal_format = PIPE_FORMAT_R10G10B10X2_UNORM; 268 break; 269 case PIPE_FORMAT_BGRA8888_UNORM: 270 internal_format = PIPE_FORMAT_BGRX8888_UNORM; 271 break; 272 case PIPE_FORMAT_ARGB8888_UNORM: 273 internal_format = PIPE_FORMAT_XRGB8888_UNORM; 274 break; 275 default: 276 break; 277 } 278 } 279 280 drawable->update_tex_buffer(drawable, ctx, pt); 281 282 ctx->st->teximage(ctx->st, 283 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 284 0, internal_format, pt, FALSE); 285 } 286} 287 288static void 289dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 290 __DRIdrawable *dPriv) 291{ 292 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 293} 294 295const __DRItexBufferExtension driTexBufferExtension = { 296 .base = { __DRI_TEX_BUFFER, 2 }, 297 298 .setTexBuffer = dri_set_tex_buffer, 299 .setTexBuffer2 = dri_set_tex_buffer2, 300 .releaseTexBuffer = NULL, 301}; 302 303/** 304 * Get the format and binding of an attachment. 305 */ 306void 307dri_drawable_get_format(struct dri_drawable *drawable, 308 enum st_attachment_type statt, 309 enum pipe_format *format, 310 unsigned *bind) 311{ 312 switch (statt) { 313 case ST_ATTACHMENT_FRONT_LEFT: 314 case ST_ATTACHMENT_BACK_LEFT: 315 case ST_ATTACHMENT_FRONT_RIGHT: 316 case ST_ATTACHMENT_BACK_RIGHT: 317 /* Other pieces of the driver stack get confused and behave incorrectly 318 * when they get an sRGB drawable. st/mesa receives "drawable->stvis" 319 * though other means and handles it correctly, so we don't really need 320 * to use an sRGB format here. 321 */ 322 *format = util_format_linear(drawable->stvis.color_format); 323 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 324 break; 325 case ST_ATTACHMENT_DEPTH_STENCIL: 326 *format = drawable->stvis.depth_stencil_format; 327 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 328 break; 329 default: 330 *format = PIPE_FORMAT_NONE; 331 *bind = 0; 332 break; 333 } 334} 335 336 337/** 338 * swap_fences_pop_front - pull a fence from the throttle queue 339 * 340 * If the throttle queue is filled to the desired number of fences, 341 * pull fences off the queue until the number is less than the desired 342 * number of fences, and return the last fence pulled. 343 */ 344static struct pipe_fence_handle * 345swap_fences_pop_front(struct dri_drawable *draw) 346{ 347 struct pipe_screen *screen = draw->screen->base.screen; 348 struct pipe_fence_handle *fence = NULL; 349 350 if (draw->desired_fences == 0) 351 return NULL; 352 353 if (draw->cur_fences >= draw->desired_fences) { 354 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 355 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 356 draw->tail &= DRI_SWAP_FENCES_MASK; 357 --draw->cur_fences; 358 } 359 return fence; 360} 361 362 363/** 364 * swap_fences_push_back - push a fence onto the throttle queue 365 * 366 * push a fence onto the throttle queue and pull fences of the queue 367 * so that the desired number of fences are on the queue. 368 */ 369static void 370swap_fences_push_back(struct dri_drawable *draw, 371 struct pipe_fence_handle *fence) 372{ 373 struct pipe_screen *screen = draw->screen->base.screen; 374 375 if (!fence || draw->desired_fences == 0) 376 return; 377 378 while(draw->cur_fences == draw->desired_fences) 379 swap_fences_pop_front(draw); 380 381 draw->cur_fences++; 382 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 383 fence); 384 draw->head &= DRI_SWAP_FENCES_MASK; 385} 386 387 388/** 389 * swap_fences_unref - empty the throttle queue 390 * 391 * pulls fences of the throttle queue until it is empty. 392 */ 393static void 394swap_fences_unref(struct dri_drawable *draw) 395{ 396 struct pipe_screen *screen = draw->screen->base.screen; 397 398 while(draw->cur_fences) { 399 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 400 draw->tail &= DRI_SWAP_FENCES_MASK; 401 --draw->cur_fences; 402 } 403} 404 405void 406dri_pipe_blit(struct pipe_context *pipe, 407 struct pipe_resource *dst, 408 struct pipe_resource *src) 409{ 410 struct pipe_blit_info blit; 411 412 if (!dst || !src) 413 return; 414 415 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample 416 * Fragment Operations): 417 * 418 * If a framebuffer object is not bound, after all operations have 419 * been completed on the multisample buffer, the sample values for 420 * each color in the multisample buffer are combined to produce a 421 * single color value, and that value is written into the 422 * corresponding color buffers selected by DrawBuffer or 423 * DrawBuffers. An implementation may defer the writing of the color 424 * buffers until a later time, but the state of the framebuffer must 425 * behave as if the color buffers were updated as each fragment was 426 * processed. The method of combination is not specified. If the 427 * framebuffer contains sRGB values, then it is recommended that the 428 * an average of sample values is computed in a linearized space, as 429 * for blending (see section 4.1.7). 430 * 431 * In other words, to do a resolve operation in a linear space, we have 432 * to set sRGB formats if the original resources were sRGB, so don't use 433 * util_format_linear. 434 */ 435 436 memset(&blit, 0, sizeof(blit)); 437 blit.dst.resource = dst; 438 blit.dst.box.width = dst->width0; 439 blit.dst.box.height = dst->height0; 440 blit.dst.box.depth = 1; 441 blit.dst.format = dst->format; 442 blit.src.resource = src; 443 blit.src.box.width = src->width0; 444 blit.src.box.height = src->height0; 445 blit.src.box.depth = 1; 446 blit.src.format = src->format; 447 blit.mask = PIPE_MASK_RGBA; 448 blit.filter = PIPE_TEX_FILTER_NEAREST; 449 450 pipe->blit(pipe, &blit); 451} 452 453static void 454dri_postprocessing(struct dri_context *ctx, 455 struct dri_drawable *drawable, 456 enum st_attachment_type att) 457{ 458 struct pipe_resource *src = drawable->textures[att]; 459 struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]; 460 461 if (ctx->pp && src) 462 pp_run(ctx->pp, src, src, zsbuf); 463} 464 465/** 466 * DRI2 flush extension, the flush_with_flags function. 467 * 468 * \param context the context 469 * \param drawable the drawable to flush 470 * \param flags a combination of _DRI2_FLUSH_xxx flags 471 * \param throttle_reason the reason for throttling, 0 = no throttling 472 */ 473void 474dri_flush(__DRIcontext *cPriv, 475 __DRIdrawable *dPriv, 476 unsigned flags, 477 enum __DRI2throttleReason reason) 478{ 479 struct dri_context *ctx = dri_context(cPriv); 480 struct dri_drawable *drawable = dri_drawable(dPriv); 481 struct st_context_iface *st; 482 unsigned flush_flags; 483 boolean swap_msaa_buffers = FALSE; 484 485 if (!ctx) { 486 assert(0); 487 return; 488 } 489 490 st = ctx->st; 491 if (st->thread_finish) 492 st->thread_finish(st); 493 494 if (drawable) { 495 /* prevent recursion */ 496 if (drawable->flushing) 497 return; 498 499 drawable->flushing = TRUE; 500 } 501 else { 502 flags &= ~__DRI2_FLUSH_DRAWABLE; 503 } 504 505 /* Flush the drawable. */ 506 if ((flags & __DRI2_FLUSH_DRAWABLE) && 507 drawable->textures[ST_ATTACHMENT_BACK_LEFT]) { 508 struct pipe_context *pipe = st->pipe; 509 510 if (drawable->stvis.samples > 1 && 511 reason == __DRI2_THROTTLE_SWAPBUFFER) { 512 /* Resolve the MSAA back buffer. */ 513 dri_pipe_blit(st->pipe, 514 drawable->textures[ST_ATTACHMENT_BACK_LEFT], 515 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); 516 517 if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] && 518 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) { 519 swap_msaa_buffers = TRUE; 520 } 521 522 /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */ 523 } 524 525 dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT); 526 527 if (pipe->invalidate_resource && 528 (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) { 529 if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 530 pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 531 if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]) 532 pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]); 533 } 534 535 if (ctx->hud) { 536 hud_run(ctx->hud, ctx->st->cso_context, 537 drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 538 } 539 540 pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 541 } 542 543 flush_flags = 0; 544 if (flags & __DRI2_FLUSH_CONTEXT) 545 flush_flags |= ST_FLUSH_FRONT; 546 if (reason == __DRI2_THROTTLE_SWAPBUFFER) 547 flush_flags |= ST_FLUSH_END_OF_FRAME; 548 549 /* Flush the context and throttle if needed. */ 550 if (dri_screen(ctx->sPriv)->default_throttle_frames && 551 drawable && 552 (reason == __DRI2_THROTTLE_SWAPBUFFER || 553 reason == __DRI2_THROTTLE_FLUSHFRONT)) { 554 /* Throttle. 555 * 556 * This pulls a fence off the throttling queue and waits for it if the 557 * number of fences on the throttling queue has reached the desired 558 * number. 559 * 560 * Then flushes to insert a fence at the current rendering position, and 561 * pushes that fence on the queue. This requires that the st_context_iface 562 * flush method returns a fence even if there are no commands to flush. 563 */ 564 struct pipe_screen *screen = drawable->screen->base.screen; 565 struct pipe_fence_handle *oldest_fence, *new_fence = NULL; 566 567 st->flush(st, flush_flags, &new_fence); 568 569 oldest_fence = swap_fences_pop_front(drawable); 570 if (oldest_fence) { 571 screen->fence_finish(screen, NULL, oldest_fence, PIPE_TIMEOUT_INFINITE); 572 screen->fence_reference(screen, &oldest_fence, NULL); 573 } 574 575 if (new_fence) { 576 swap_fences_push_back(drawable, new_fence); 577 screen->fence_reference(screen, &new_fence, NULL); 578 } 579 } 580 else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) { 581 st->flush(st, flush_flags, NULL); 582 } 583 584 if (drawable) { 585 drawable->flushing = FALSE; 586 } 587 588 /* Swap the MSAA front and back buffers, so that reading 589 * from the front buffer after SwapBuffers returns what was 590 * in the back buffer. 591 */ 592 if (swap_msaa_buffers) { 593 struct pipe_resource *tmp = 594 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]; 595 596 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] = 597 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]; 598 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp; 599 600 /* Now that we have swapped the buffers, this tells the state 601 * tracker to revalidate the framebuffer. 602 */ 603 p_atomic_inc(&drawable->base.stamp); 604 } 605} 606 607/** 608 * dri_throttle - A DRI2ThrottleExtension throttling function. 609 */ 610static void 611dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv, 612 enum __DRI2throttleReason reason) 613{ 614 dri_flush(cPriv, dPriv, 0, reason); 615} 616 617 618const __DRI2throttleExtension dri2ThrottleExtension = { 619 .base = { __DRI2_THROTTLE, 1 }, 620 621 .throttle = dri_throttle, 622}; 623 624 625/* vim: set sw=3 ts=8 sts=3 expandtab: */ 626