1/************************************************************************** 2 * 3 * Copyright 2009, VMware, Inc. 4 * All Rights Reserved. 5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29#include "util/format/u_format.h" 30#include "util/u_memory.h" 31#include "util/u_inlines.h" 32#include "util/u_box.h" 33#include "pipe/p_context.h" 34#include "pipe-loader/pipe_loader.h" 35#include "frontend/drisw_api.h" 36#include "state_tracker/st_context.h" 37 38#include "dri_screen.h" 39#include "dri_context.h" 40#include "dri_drawable.h" 41#include "dri_helpers.h" 42#include "dri_query_renderer.h" 43 44DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE); 45 46static inline void 47get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h) 48{ 49 __DRIscreen *sPriv = dPriv->driScreenPriv; 50 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 51 52 loader->getDrawableInfo(dPriv, 53 x, y, w, h, 54 dPriv->loaderPrivate); 55} 56 57static inline void 58put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height) 59{ 60 __DRIscreen *sPriv = dPriv->driScreenPriv; 61 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 62 63 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 64 0, 0, width, height, 65 data, dPriv->loaderPrivate); 66} 67 68static inline void 69put_image2(__DRIdrawable *dPriv, void *data, int x, int y, 70 unsigned width, unsigned height, unsigned stride) 71{ 72 __DRIscreen *sPriv = dPriv->driScreenPriv; 73 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 74 75 loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 76 x, y, width, height, stride, 77 data, dPriv->loaderPrivate); 78} 79 80static inline void 81put_image_shm(__DRIdrawable *dPriv, int shmid, char *shmaddr, 82 unsigned offset, unsigned offset_x, int x, int y, 83 unsigned width, unsigned height, unsigned stride) 84{ 85 __DRIscreen *sPriv = dPriv->driScreenPriv; 86 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 87 88 /* if we have the newer interface, don't have to add the offset_x here. */ 89 if (loader->base.version > 4 && loader->putImageShm2) 90 loader->putImageShm2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 91 x, y, width, height, stride, 92 shmid, shmaddr, offset, dPriv->loaderPrivate); 93 else 94 loader->putImageShm(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 95 x, y, width, height, stride, 96 shmid, shmaddr, offset + offset_x, dPriv->loaderPrivate); 97} 98 99static inline void 100get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data) 101{ 102 __DRIscreen *sPriv = dPriv->driScreenPriv; 103 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 104 105 loader->getImage(dPriv, 106 x, y, width, height, 107 data, dPriv->loaderPrivate); 108} 109 110static inline void 111get_image2(__DRIdrawable *dPriv, int x, int y, int width, int height, int stride, void *data) 112{ 113 __DRIscreen *sPriv = dPriv->driScreenPriv; 114 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 115 116 /* getImage2 support is only in version 3 or newer */ 117 if (loader->base.version < 3) 118 return; 119 120 loader->getImage2(dPriv, 121 x, y, width, height, stride, 122 data, dPriv->loaderPrivate); 123} 124 125static inline bool 126get_image_shm(__DRIdrawable *dPriv, int x, int y, int width, int height, 127 struct pipe_resource *res) 128{ 129 __DRIscreen *sPriv = dPriv->driScreenPriv; 130 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 131 struct winsys_handle whandle; 132 133 whandle.type = WINSYS_HANDLE_TYPE_SHMID; 134 135 if (loader->base.version < 4 || !loader->getImageShm) 136 return FALSE; 137 138 if (!res->screen->resource_get_handle(res->screen, NULL, res, &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) 139 return FALSE; 140 141 if (loader->base.version > 5 && loader->getImageShm2) 142 return loader->getImageShm2(dPriv, x, y, width, height, whandle.handle, dPriv->loaderPrivate); 143 144 loader->getImageShm(dPriv, x, y, width, height, whandle.handle, dPriv->loaderPrivate); 145 return TRUE; 146} 147 148static void 149drisw_update_drawable_info(struct dri_drawable *drawable) 150{ 151 __DRIdrawable *dPriv = drawable->dPriv; 152 int x, y; 153 154 get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h); 155} 156 157static void 158drisw_get_image(struct dri_drawable *drawable, 159 int x, int y, unsigned width, unsigned height, unsigned stride, 160 void *data) 161{ 162 __DRIdrawable *dPriv = drawable->dPriv; 163 int draw_x, draw_y, draw_w, draw_h; 164 165 get_drawable_info(dPriv, &draw_x, &draw_y, &draw_w, &draw_h); 166 get_image2(dPriv, x, y, draw_w, draw_h, stride, data); 167} 168 169static void 170drisw_put_image(struct dri_drawable *drawable, 171 void *data, unsigned width, unsigned height) 172{ 173 __DRIdrawable *dPriv = drawable->dPriv; 174 175 put_image(dPriv, data, width, height); 176} 177 178static void 179drisw_put_image2(struct dri_drawable *drawable, 180 void *data, int x, int y, unsigned width, unsigned height, 181 unsigned stride) 182{ 183 __DRIdrawable *dPriv = drawable->dPriv; 184 185 put_image2(dPriv, data, x, y, width, height, stride); 186} 187 188static inline void 189drisw_put_image_shm(struct dri_drawable *drawable, 190 int shmid, char *shmaddr, unsigned offset, 191 unsigned offset_x, 192 int x, int y, unsigned width, unsigned height, 193 unsigned stride) 194{ 195 __DRIdrawable *dPriv = drawable->dPriv; 196 197 put_image_shm(dPriv, shmid, shmaddr, offset, offset_x, x, y, width, height, stride); 198} 199 200static inline void 201drisw_present_texture(struct pipe_context *pipe, __DRIdrawable *dPriv, 202 struct pipe_resource *ptex, struct pipe_box *sub_box) 203{ 204 struct dri_drawable *drawable = dri_drawable(dPriv); 205 struct dri_screen *screen = dri_screen(drawable->sPriv); 206 207 if (screen->swrast_no_present) 208 return; 209 210 screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, sub_box); 211} 212 213static inline void 214drisw_invalidate_drawable(__DRIdrawable *dPriv) 215{ 216 struct dri_drawable *drawable = dri_drawable(dPriv); 217 218 drawable->texture_stamp = dPriv->lastStamp - 1; 219 220 p_atomic_inc(&drawable->base.stamp); 221} 222 223static inline void 224drisw_copy_to_front(struct pipe_context *pipe, 225 __DRIdrawable * dPriv, 226 struct pipe_resource *ptex) 227{ 228 drisw_present_texture(pipe, dPriv, ptex, NULL); 229 230 drisw_invalidate_drawable(dPriv); 231} 232 233/* 234 * Backend functions for st_framebuffer interface and swap_buffers. 235 */ 236 237static void 238drisw_swap_buffers(__DRIdrawable *dPriv) 239{ 240 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 241 struct dri_drawable *drawable = dri_drawable(dPriv); 242 struct dri_screen *screen = dri_screen(drawable->sPriv); 243 struct pipe_resource *ptex; 244 245 if (!ctx) 246 return; 247 248 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 249 250 if (ptex) { 251 struct pipe_fence_handle *fence = NULL; 252 if (ctx->pp) 253 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 254 255 if (ctx->hud) 256 hud_run(ctx->hud, ctx->st->cso_context, ptex); 257 258 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, &fence, NULL, NULL); 259 260 if (drawable->stvis.samples > 1) { 261 /* Resolve the back buffer. */ 262 dri_pipe_blit(ctx->st->pipe, 263 drawable->textures[ST_ATTACHMENT_BACK_LEFT], 264 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); 265 } 266 267 screen->base.screen->fence_finish(screen->base.screen, ctx->st->pipe, 268 fence, PIPE_TIMEOUT_INFINITE); 269 screen->base.screen->fence_reference(screen->base.screen, &fence, NULL); 270 drisw_copy_to_front(ctx->st->pipe, dPriv, ptex); 271 } 272} 273 274static void 275drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y, 276 int w, int h) 277{ 278 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 279 struct dri_drawable *drawable = dri_drawable(dPriv); 280 struct dri_screen *screen = dri_screen(drawable->sPriv); 281 struct pipe_resource *ptex; 282 struct pipe_box box; 283 if (!ctx) 284 return; 285 286 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 287 288 if (ptex) { 289 struct pipe_fence_handle *fence = NULL; 290 if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 291 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 292 293 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, &fence, NULL, NULL); 294 295 screen->base.screen->fence_finish(screen->base.screen, ctx->st->pipe, 296 fence, PIPE_TIMEOUT_INFINITE); 297 screen->base.screen->fence_reference(screen->base.screen, &fence, NULL); 298 299 if (drawable->stvis.samples > 1) { 300 /* Resolve the back buffer. */ 301 dri_pipe_blit(ctx->st->pipe, 302 drawable->textures[ST_ATTACHMENT_BACK_LEFT], 303 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]); 304 } 305 306 u_box_2d(x, dPriv->h - y - h, w, h, &box); 307 drisw_present_texture(ctx->st->pipe, dPriv, ptex, &box); 308 } 309} 310 311static bool 312drisw_flush_frontbuffer(struct dri_context *ctx, 313 struct dri_drawable *drawable, 314 enum st_attachment_type statt) 315{ 316 struct pipe_resource *ptex; 317 318 if (!ctx || statt != ST_ATTACHMENT_FRONT_LEFT) 319 return false; 320 321 if (drawable->stvis.samples > 1) { 322 /* Resolve the front buffer. */ 323 dri_pipe_blit(ctx->st->pipe, 324 drawable->textures[ST_ATTACHMENT_FRONT_LEFT], 325 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]); 326 } 327 ptex = drawable->textures[statt]; 328 329 if (ptex) { 330 drisw_copy_to_front(ctx->st->pipe, ctx->dPriv, ptex); 331 } 332 333 return true; 334} 335 336/** 337 * Allocate framebuffer attachments. 338 * 339 * During fixed-size operation, the function keeps allocating new attachments 340 * as they are requested. Unused attachments are not removed, not until the 341 * framebuffer is resized or destroyed. 342 */ 343static void 344drisw_allocate_textures(struct dri_context *stctx, 345 struct dri_drawable *drawable, 346 const enum st_attachment_type *statts, 347 unsigned count) 348{ 349 struct dri_screen *screen = dri_screen(drawable->sPriv); 350 const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader; 351 struct pipe_resource templ; 352 unsigned width, height; 353 boolean resized; 354 unsigned i; 355 356 width = drawable->dPriv->w; 357 height = drawable->dPriv->h; 358 359 resized = (drawable->old_w != width || 360 drawable->old_h != height); 361 362 /* remove outdated textures */ 363 if (resized) { 364 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 365 pipe_resource_reference(&drawable->textures[i], NULL); 366 pipe_resource_reference(&drawable->msaa_textures[i], NULL); 367 } 368 } 369 370 memset(&templ, 0, sizeof(templ)); 371 templ.target = screen->target; 372 templ.width0 = width; 373 templ.height0 = height; 374 templ.depth0 = 1; 375 templ.array_size = 1; 376 templ.last_level = 0; 377 378 for (i = 0; i < count; i++) { 379 enum pipe_format format; 380 unsigned bind; 381 382 /* the texture already exists or not requested */ 383 if (drawable->textures[statts[i]]) 384 continue; 385 386 dri_drawable_get_format(drawable, statts[i], &format, &bind); 387 388 /* if we don't do any present, no need for display targets */ 389 if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !screen->swrast_no_present) 390 bind |= PIPE_BIND_DISPLAY_TARGET; 391 392 if (format == PIPE_FORMAT_NONE) 393 continue; 394 395 templ.format = format; 396 templ.bind = bind; 397 templ.nr_samples = 0; 398 templ.nr_storage_samples = 0; 399 400 if (statts[i] == ST_ATTACHMENT_FRONT_LEFT && 401 screen->base.screen->resource_create_front && 402 loader->base.version >= 3) { 403 drawable->textures[statts[i]] = 404 screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable); 405 } else 406 drawable->textures[statts[i]] = 407 screen->base.screen->resource_create(screen->base.screen, &templ); 408 409 if (drawable->stvis.samples > 1) { 410 templ.bind = templ.bind & 411 ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET); 412 templ.nr_samples = drawable->stvis.samples; 413 templ.nr_storage_samples = drawable->stvis.samples; 414 drawable->msaa_textures[statts[i]] = 415 screen->base.screen->resource_create(screen->base.screen, &templ); 416 417 dri_pipe_blit(stctx->st->pipe, 418 drawable->msaa_textures[statts[i]], 419 drawable->textures[statts[i]]); 420 } 421 } 422 423 drawable->old_w = width; 424 drawable->old_h = height; 425} 426 427static void 428drisw_update_tex_buffer(struct dri_drawable *drawable, 429 struct dri_context *ctx, 430 struct pipe_resource *res) 431{ 432 __DRIdrawable *dPriv = drawable->dPriv; 433 434 struct st_context *st_ctx = (struct st_context *)ctx->st; 435 struct pipe_context *pipe = st_ctx->pipe; 436 struct pipe_transfer *transfer; 437 char *map; 438 int x, y, w, h; 439 int ximage_stride, line; 440 int cpp = util_format_get_blocksize(res->format); 441 442 get_drawable_info(dPriv, &x, &y, &w, &h); 443 444 map = pipe_texture_map(pipe, res, 445 0, 0, // level, layer, 446 PIPE_MAP_WRITE, 447 x, y, w, h, &transfer); 448 449 /* Copy the Drawable content to the mapped texture buffer */ 450 if (!get_image_shm(dPriv, x, y, w, h, res)) 451 get_image(dPriv, x, y, w, h, map); 452 453 /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. 454 get_image() has a pitch rounded up to 4 bytes. */ 455 ximage_stride = ((w * cpp) + 3) & -4; 456 for (line = h-1; line; --line) { 457 memmove(&map[line * transfer->stride], 458 &map[line * ximage_stride], 459 ximage_stride); 460 } 461 462 pipe_texture_unmap(pipe, transfer); 463} 464 465static __DRIimageExtension driSWImageExtension = { 466 .base = { __DRI_IMAGE, 6 }, 467 468 .createImageFromRenderbuffer = dri2_create_image_from_renderbuffer, 469 .createImageFromTexture = dri2_create_from_texture, 470 .destroyImage = dri2_destroy_image, 471}; 472 473static const __DRIrobustnessExtension dri2Robustness = { 474 .base = { __DRI2_ROBUSTNESS, 1 } 475}; 476 477/* 478 * Backend function for init_screen. 479 */ 480 481static const __DRIextension *drisw_screen_extensions[] = { 482 &driTexBufferExtension.base, 483 &dri2RendererQueryExtension.base, 484 &dri2ConfigQueryExtension.base, 485 &dri2FenceExtension.base, 486 &driSWImageExtension.base, 487 &dri2FlushControlExtension.base, 488 NULL 489}; 490 491static const __DRIextension *drisw_robust_screen_extensions[] = { 492 &driTexBufferExtension.base, 493 &dri2RendererQueryExtension.base, 494 &dri2ConfigQueryExtension.base, 495 &dri2FenceExtension.base, 496 &dri2Robustness.base, 497 &driSWImageExtension.base, 498 &dri2FlushControlExtension.base, 499 NULL 500}; 501 502static const struct drisw_loader_funcs drisw_lf = { 503 .get_image = drisw_get_image, 504 .put_image = drisw_put_image, 505 .put_image2 = drisw_put_image2 506}; 507 508static const struct drisw_loader_funcs drisw_shm_lf = { 509 .get_image = drisw_get_image, 510 .put_image = drisw_put_image, 511 .put_image2 = drisw_put_image2, 512 .put_image_shm = drisw_put_image_shm 513}; 514 515static const __DRIconfig ** 516drisw_init_screen(__DRIscreen * sPriv) 517{ 518 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 519 const __DRIconfig **configs; 520 struct dri_screen *screen; 521 struct pipe_screen *pscreen = NULL; 522 const struct drisw_loader_funcs *lf = &drisw_lf; 523 524 screen = CALLOC_STRUCT(dri_screen); 525 if (!screen) 526 return NULL; 527 528 screen->sPriv = sPriv; 529 screen->fd = sPriv->fd; 530 531 screen->swrast_no_present = debug_get_option_swrast_no_present(); 532 533 sPriv->driverPrivate = (void *)screen; 534 535 if (loader->base.version >= 4) { 536 if (loader->putImageShm) 537 lf = &drisw_shm_lf; 538 } 539 540 bool success = false; 541#ifdef HAVE_DRISW_KMS 542 if (screen->fd != -1) 543 success = pipe_loader_sw_probe_kms(&screen->dev, screen->fd); 544#endif 545 if (!success) 546 success = pipe_loader_sw_probe_dri(&screen->dev, lf); 547 if (success) { 548 pscreen = pipe_loader_create_screen(screen->dev); 549 dri_init_options(screen); 550 } 551 552 if (!pscreen) 553 goto fail; 554 555 configs = dri_init_screen_helper(screen, pscreen); 556 if (!configs) 557 goto fail; 558 559 if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) { 560 sPriv->extensions = drisw_robust_screen_extensions; 561 screen->has_reset_status_query = true; 562 } 563 else 564 sPriv->extensions = drisw_screen_extensions; 565 screen->lookup_egl_image = dri2_lookup_egl_image; 566 567 const __DRIimageLookupExtension *image = sPriv->dri2.image; 568 if (image && 569 image->base.version >= 2 && 570 image->validateEGLImage && 571 image->lookupEGLImageValidated) { 572 screen->validate_egl_image = dri2_validate_egl_image; 573 screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated; 574 } 575 576 return configs; 577fail: 578 dri_destroy_screen_helper(screen); 579 if (screen->dev) 580 pipe_loader_release(&screen->dev, 1); 581 FREE(screen); 582 return NULL; 583} 584 585static boolean 586drisw_create_buffer(__DRIscreen * sPriv, 587 __DRIdrawable * dPriv, 588 const struct gl_config * visual, boolean isPixmap) 589{ 590 struct dri_drawable *drawable = NULL; 591 592 if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap)) 593 return FALSE; 594 595 drawable = dPriv->driverPrivate; 596 597 drawable->allocate_textures = drisw_allocate_textures; 598 drawable->update_drawable_info = drisw_update_drawable_info; 599 drawable->flush_frontbuffer = drisw_flush_frontbuffer; 600 drawable->update_tex_buffer = drisw_update_tex_buffer; 601 602 return TRUE; 603} 604 605/** 606 * DRI driver virtual function table. 607 * 608 * DRI versions differ in their implementation of init_screen and swap_buffers. 609 */ 610const struct __DriverAPIRec galliumsw_driver_api = { 611 .InitScreen = drisw_init_screen, 612 .DestroyScreen = dri_destroy_screen, 613 .CreateBuffer = drisw_create_buffer, 614 .DestroyBuffer = dri_destroy_buffer, 615 .SwapBuffers = drisw_swap_buffers, 616 .CopySubBuffer = drisw_copy_sub_buffer, 617}; 618 619static const struct __DRIDriverVtableExtensionRec galliumsw_vtable = { 620 .base = { __DRI_DRIVER_VTABLE, 1 }, 621 .vtable = &galliumsw_driver_api, 622}; 623 624/* swrast copy sub buffer entrypoint. */ 625static void driswCopySubBuffer(__DRIdrawable *pdp, int x, int y, 626 int w, int h) 627{ 628 assert(pdp->driScreenPriv->swrast_loader); 629 630 pdp->driScreenPriv->driver->CopySubBuffer(pdp, x, y, w, h); 631} 632 633/* for swrast only */ 634const __DRIcopySubBufferExtension driSWCopySubBufferExtension = { 635 .base = { __DRI_COPY_SUB_BUFFER, 1 }, 636 637 .copySubBuffer = driswCopySubBuffer, 638}; 639 640/* This is the table of extensions that the loader will dlsym() for. */ 641const __DRIextension *galliumsw_driver_extensions[] = { 642 &driCoreExtension.base, 643 &driSWRastExtension.base, 644 &driSWCopySubBufferExtension.base, 645 &gallium_config_options.base, 646 &galliumsw_vtable.base, 647 NULL 648}; 649 650/* vim: set sw=3 ts=8 sts=3 expandtab: */ 651