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