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 void 42swap_fences_unref(struct dri_drawable *draw); 43 44static boolean 45dri_st_framebuffer_validate(struct st_context_iface *stctx, 46 struct st_framebuffer_iface *stfbi, 47 const enum st_attachment_type *statts, 48 unsigned count, 49 struct pipe_resource **out) 50{ 51 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private; 52 struct dri_drawable *drawable = 53 (struct dri_drawable *) stfbi->st_manager_private; 54 struct dri_screen *screen = dri_screen(drawable->sPriv); 55 unsigned statt_mask, new_mask; 56 boolean new_stamp; 57 int i; 58 unsigned int lastStamp; 59 struct pipe_resource **textures = 60 drawable->stvis.samples > 1 ? drawable->msaa_textures 61 : drawable->textures; 62 63 statt_mask = 0x0; 64 for (i = 0; i < count; i++) 65 statt_mask |= (1 << statts[i]); 66 67 /* record newly allocated textures */ 68 new_mask = (statt_mask & ~drawable->texture_mask); 69 70 /* 71 * dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the 72 * client stamp. It has the value of the server stamp when last 73 * checked. 74 */ 75 do { 76 lastStamp = drawable->dPriv->lastStamp; 77 new_stamp = (drawable->texture_stamp != lastStamp); 78 79 if (new_stamp || new_mask || screen->broken_invalidate) { 80 if (new_stamp && drawable->update_drawable_info) 81 drawable->update_drawable_info(drawable); 82 83 drawable->allocate_textures(ctx, drawable, statts, count); 84 85 /* add existing textures */ 86 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 87 if (textures[i]) 88 statt_mask |= (1 << i); 89 } 90 91 drawable->texture_stamp = lastStamp; 92 drawable->texture_mask = statt_mask; 93 } 94 } while (lastStamp != drawable->dPriv->lastStamp); 95 96 if (!out) 97 return TRUE; 98 99 /* Set the window-system buffers for the state tracker. */ 100 for (i = 0; i < count; i++) { 101 out[i] = NULL; 102 pipe_resource_reference(&out[i], textures[statts[i]]); 103 } 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 * This is called when we need to set up GL rendering to a new X window. 125 */ 126boolean 127dri_create_buffer(__DRIscreen * sPriv, 128 __DRIdrawable * dPriv, 129 const struct gl_config * visual, boolean isPixmap) 130{ 131 struct dri_screen *screen = sPriv->driverPrivate; 132 struct dri_drawable *drawable = NULL; 133 134 if (isPixmap) 135 goto fail; /* not implemented */ 136 137 drawable = CALLOC_STRUCT(dri_drawable); 138 if (drawable == NULL) 139 goto fail; 140 141 dri_fill_st_visual(&drawable->stvis, screen, visual); 142 143 /* setup the st_framebuffer_iface */ 144 drawable->base.visual = &drawable->stvis; 145 drawable->base.flush_front = dri_st_framebuffer_flush_front; 146 drawable->base.validate = dri_st_framebuffer_validate; 147 drawable->base.st_manager_private = (void *) drawable; 148 149 drawable->screen = screen; 150 drawable->sPriv = sPriv; 151 drawable->dPriv = dPriv; 152 drawable->desired_fences = screen->default_throttle_frames; 153 if (drawable->desired_fences > DRI_SWAP_FENCES_MAX) 154 drawable->desired_fences = DRI_SWAP_FENCES_MAX; 155 156 dPriv->driverPrivate = (void *)drawable; 157 p_atomic_set(&drawable->base.stamp, 1); 158 159 return GL_TRUE; 160fail: 161 FREE(drawable); 162 return GL_FALSE; 163} 164 165void 166dri_destroy_buffer(__DRIdrawable * dPriv) 167{ 168 struct dri_drawable *drawable = dri_drawable(dPriv); 169 int i; 170 171 pipe_surface_reference(&drawable->drisw_surface, NULL); 172 173 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 174 pipe_resource_reference(&drawable->textures[i], NULL); 175 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 176 pipe_resource_reference(&drawable->msaa_textures[i], NULL); 177 178 swap_fences_unref(drawable); 179 180 FREE(drawable); 181} 182 183/** 184 * Validate the texture at an attachment. Allocate the texture if it does not 185 * exist. Used by the TFP extension. 186 */ 187static void 188dri_drawable_validate_att(struct dri_context *ctx, 189 struct dri_drawable *drawable, 190 enum st_attachment_type statt) 191{ 192 enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; 193 unsigned i, count = 0; 194 195 /* check if buffer already exists */ 196 if (drawable->texture_mask & (1 << statt)) 197 return; 198 199 /* make sure DRI2 does not destroy existing buffers */ 200 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 201 if (drawable->texture_mask & (1 << i)) { 202 statts[count++] = i; 203 } 204 } 205 statts[count++] = statt; 206 207 drawable->texture_stamp = drawable->dPriv->lastStamp - 1; 208 209 drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL); 210} 211 212/** 213 * These are used for GLX_EXT_texture_from_pixmap 214 */ 215static void 216dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 217 GLint format, __DRIdrawable *dPriv) 218{ 219 struct dri_context *ctx = dri_context(pDRICtx); 220 struct dri_drawable *drawable = dri_drawable(dPriv); 221 struct pipe_resource *pt; 222 223 dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT); 224 225 /* Use the pipe resource associated with the X drawable */ 226 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 227 228 if (pt) { 229 enum pipe_format internal_format = pt->format; 230 231 if (format == __DRI_TEXTURE_FORMAT_RGB) { 232 /* only need to cover the formats recognized by dri_fill_st_visual */ 233 switch (internal_format) { 234 case PIPE_FORMAT_BGRA8888_UNORM: 235 internal_format = PIPE_FORMAT_BGRX8888_UNORM; 236 break; 237 case PIPE_FORMAT_ARGB8888_UNORM: 238 internal_format = PIPE_FORMAT_XRGB8888_UNORM; 239 break; 240 default: 241 break; 242 } 243 } 244 245 drawable->update_tex_buffer(drawable, ctx, pt); 246 247 ctx->st->teximage(ctx->st, 248 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 249 0, internal_format, pt, FALSE); 250 } 251} 252 253static void 254dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 255 __DRIdrawable *dPriv) 256{ 257 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 258} 259 260const __DRItexBufferExtension driTexBufferExtension = { 261 .base = { __DRI_TEX_BUFFER, 2 }, 262 263 .setTexBuffer = dri_set_tex_buffer, 264 .setTexBuffer2 = dri_set_tex_buffer2, 265 .releaseTexBuffer = NULL, 266}; 267 268/** 269 * Get the format and binding of an attachment. 270 */ 271void 272dri_drawable_get_format(struct dri_drawable *drawable, 273 enum st_attachment_type statt, 274 enum pipe_format *format, 275 unsigned *bind) 276{ 277 switch (statt) { 278 case ST_ATTACHMENT_FRONT_LEFT: 279 case ST_ATTACHMENT_BACK_LEFT: 280 case ST_ATTACHMENT_FRONT_RIGHT: 281 case ST_ATTACHMENT_BACK_RIGHT: 282 /* Other pieces of the driver stack get confused and behave incorrectly 283 * when they get an sRGB drawable. st/mesa receives "drawable->stvis" 284 * though other means and handles it correctly, so we don't really need 285 * to use an sRGB format here. 286 */ 287 *format = util_format_linear(drawable->stvis.color_format); 288 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 289 break; 290 case ST_ATTACHMENT_DEPTH_STENCIL: 291 *format = drawable->stvis.depth_stencil_format; 292 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 293 break; 294 default: 295 *format = PIPE_FORMAT_NONE; 296 *bind = 0; 297 break; 298 } 299} 300 301 302/** 303 * swap_fences_pop_front - pull a fence from the throttle queue 304 * 305 * If the throttle queue is filled to the desired number of fences, 306 * pull fences off the queue until the number is less than the desired 307 * number of fences, and return the last fence pulled. 308 */ 309static struct pipe_fence_handle * 310swap_fences_pop_front(struct dri_drawable *draw) 311{ 312 struct pipe_screen *screen = draw->screen->base.screen; 313 struct pipe_fence_handle *fence = NULL; 314 315 if (draw->desired_fences == 0) 316 return NULL; 317 318 if (draw->cur_fences >= draw->desired_fences) { 319 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 320 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 321 draw->tail &= DRI_SWAP_FENCES_MASK; 322 --draw->cur_fences; 323 } 324 return fence; 325} 326 327 328/** 329 * swap_fences_push_back - push a fence onto the throttle queue 330 * 331 * push a fence onto the throttle queue and pull fences of the queue 332 * so that the desired number of fences are on the queue. 333 */ 334static void 335swap_fences_push_back(struct dri_drawable *draw, 336 struct pipe_fence_handle *fence) 337{ 338 struct pipe_screen *screen = draw->screen->base.screen; 339 340 if (!fence || draw->desired_fences == 0) 341 return; 342 343 while(draw->cur_fences == draw->desired_fences) 344 swap_fences_pop_front(draw); 345 346 draw->cur_fences++; 347 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 348 fence); 349 draw->head &= DRI_SWAP_FENCES_MASK; 350} 351 352 353/** 354 * swap_fences_unref - empty the throttle queue 355 * 356 * pulls fences of the throttle queue until it is empty. 357 */ 358static void 359swap_fences_unref(struct dri_drawable *draw) 360{ 361 struct pipe_screen *screen = draw->screen->base.screen; 362 363 while(draw->cur_fences) { 364 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 365 draw->tail &= DRI_SWAP_FENCES_MASK; 366 --draw->cur_fences; 367 } 368} 369 370void 371dri_pipe_blit(struct pipe_context *pipe, 372 struct pipe_resource *dst, 373 struct pipe_resource *src) 374{ 375 struct pipe_blit_info blit; 376 377 if (!dst || !src) 378 return; 379 380 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample 381 * Fragment Operations): 382 * 383 * If a framebuffer object is not bound, after all operations have 384 * been completed on the multisample buffer, the sample values for 385 * each color in the multisample buffer are combined to produce a 386 * single color value, and that value is written into the 387 * corresponding color buffers selected by DrawBuffer or 388 * DrawBuffers. An implementation may defer the writing of the color 389 * buffers until a later time, but the state of the framebuffer must 390 * behave as if the color buffers were updated as each fragment was 391 * processed. The method of combination is not specified. If the 392 * framebuffer contains sRGB values, then it is recommended that the 393 * an average of sample values is computed in a linearized space, as 394 * for blending (see section 4.1.7). 395 * 396 * In other words, to do a resolve operation in a linear space, we have 397 * to set sRGB formats if the original resources were sRGB, so don't use 398 * util_format_linear. 399 */ 400 401 memset(&blit, 0, sizeof(blit)); 402 blit.dst.resource = dst; 403 blit.dst.box.width = dst->width0; 404 blit.dst.box.height = dst->height0; 405 blit.dst.box.depth = 1; 406 blit.dst.format = dst->format; 407 blit.src.resource = src; 408 blit.src.box.width = src->width0; 409 blit.src.box.height = src->height0; 410 blit.src.box.depth = 1; 411 blit.src.format = src->format; 412 blit.mask = PIPE_MASK_RGBA; 413 blit.filter = PIPE_TEX_FILTER_NEAREST; 414 415 pipe->blit(pipe, &blit); 416} 417 418static void 419dri_postprocessing(struct dri_context *ctx, 420 struct dri_drawable *drawable, 421 enum st_attachment_type att) 422{ 423 struct pipe_resource *src = drawable->textures[att]; 424 struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]; 425 426 if (ctx->pp && src) 427 pp_run(ctx->pp, src, src, zsbuf); 428} 429 430/** 431 * DRI2 flush extension, the flush_with_flags function. 432 * 433 * \param context the context 434 * \param drawable the drawable to flush 435 * \param flags a combination of _DRI2_FLUSH_xxx flags 436 * \param throttle_reason the reason for throttling, 0 = no throttling 437 */ 438void 439dri_flush(__DRIcontext *cPriv, 440 __DRIdrawable *dPriv, 441 unsigned flags, 442 enum __DRI2throttleReason reason) 443{ 444 struct dri_context *ctx = dri_context(cPriv); 445 struct dri_drawable *drawable = dri_drawable(dPriv); 446 unsigned flush_flags; 447 boolean swap_msaa_buffers = FALSE; 448 449 if (!ctx) { 450 assert(0); 451 return; 452 } 453 454 if (drawable) { 455 /* prevent recursion */ 456 if (drawable->flushing) 457 return; 458 459 drawable->flushing = TRUE; 460 } 461 else { 462 flags &= ~__DRI2_FLUSH_DRAWABLE; 463 } 464 465 /* Flush the drawable. */ 466 if ((flags & __DRI2_FLUSH_DRAWABLE) && 467 drawable->textures[ST_ATTACHMENT_BACK_LEFT]) { 468 struct pipe_context *pipe = ctx->st->pipe; 469 470 if (drawable->stvis.samples > 1 && 471 reason == __DRI2_THROTTLE_SWAPBUFFER) { 472 /* Resolve the MSAA back buffer. */ 473 dri_pipe_blit(ctx->st->pipe, 474 drawable->textures[ST_ATTACHMENT_BACK_LEFT], 475 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); 476 477 if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] && 478 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) { 479 swap_msaa_buffers = TRUE; 480 } 481 482 /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */ 483 } 484 485 dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT); 486 487 if (ctx->hud) { 488 hud_draw(ctx->hud, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 489 } 490 491 pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]); 492 493 if (pipe->invalidate_resource && 494 (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) { 495 if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 496 pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 497 if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]) 498 pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]); 499 } 500 } 501 502 flush_flags = 0; 503 if (flags & __DRI2_FLUSH_CONTEXT) 504 flush_flags |= ST_FLUSH_FRONT; 505 if (reason == __DRI2_THROTTLE_SWAPBUFFER) 506 flush_flags |= ST_FLUSH_END_OF_FRAME; 507 508 /* Flush the context and throttle if needed. */ 509 if (dri_screen(ctx->sPriv)->throttling_enabled && 510 drawable && 511 (reason == __DRI2_THROTTLE_SWAPBUFFER || 512 reason == __DRI2_THROTTLE_FLUSHFRONT)) { 513 /* Throttle. 514 * 515 * This pulls a fence off the throttling queue and waits for it if the 516 * number of fences on the throttling queue has reached the desired 517 * number. 518 * 519 * Then flushes to insert a fence at the current rendering position, and 520 * pushes that fence on the queue. This requires that the st_context_iface 521 * flush method returns a fence even if there are no commands to flush. 522 */ 523 struct pipe_screen *screen = drawable->screen->base.screen; 524 struct pipe_fence_handle *fence; 525 526 fence = swap_fences_pop_front(drawable); 527 if (fence) { 528 (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 529 screen->fence_reference(screen, &fence, NULL); 530 } 531 532 ctx->st->flush(ctx->st, flush_flags, &fence); 533 534 if (fence) { 535 swap_fences_push_back(drawable, fence); 536 screen->fence_reference(screen, &fence, NULL); 537 } 538 } 539 else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) { 540 ctx->st->flush(ctx->st, flush_flags, NULL); 541 } 542 543 if (drawable) { 544 drawable->flushing = FALSE; 545 } 546 547 /* Swap the MSAA front and back buffers, so that reading 548 * from the front buffer after SwapBuffers returns what was 549 * in the back buffer. 550 */ 551 if (swap_msaa_buffers) { 552 struct pipe_resource *tmp = 553 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]; 554 555 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] = 556 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]; 557 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp; 558 559 /* Now that we have swapped the buffers, this tells the state 560 * tracker to revalidate the framebuffer. 561 */ 562 p_atomic_inc(&drawable->base.stamp); 563 } 564} 565 566/** 567 * dri_throttle - A DRI2ThrottleExtension throttling function. 568 */ 569static void 570dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv, 571 enum __DRI2throttleReason reason) 572{ 573 dri_flush(cPriv, dPriv, 0, reason); 574} 575 576 577const __DRI2throttleExtension dri2ThrottleExtension = { 578 .base = { __DRI2_THROTTLE, 1 }, 579 580 .throttle = dri_throttle, 581}; 582 583 584/* vim: set sw=3 ts=8 sts=3 expandtab: */ 585