Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
  3.  * All Rights Reserved.
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a
  6.  * copy of this software and associated documentation files (the
  7.  * "Software"), to deal in the Software without restriction, including
  8.  * without limitation the rights to use, copy, modify, merge, publish,
  9.  * distribute, sub license, and/or sell copies of the Software, and to
  10.  * permit persons to whom the Software is furnished to do so, subject to
  11.  * the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice (including the
  14.  * next paragraph) shall be included in all copies or substantial portions
  15.  * of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  20.  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  21.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24.  *
  25.  *
  26.  * Author: Alan Hourihane <alanh@tungstengraphics.com>
  27.  * Author: Jakob Bornecrantz <wallbraker@gmail.com>
  28.  *
  29.  */
  30.  
  31. #include "xorg-server.h"
  32. #include "xf86.h"
  33. #include "xf86_OSproc.h"
  34.  
  35. #include "xorg_tracker.h"
  36. #include "xorg_exa.h"
  37.  
  38. #include "dri2.h"
  39.  
  40. #include "pipe/p_state.h"
  41. #include "util/u_inlines.h"
  42.  
  43. #include "util/u_format.h"
  44.  
  45. #include "state_tracker/drm_driver.h"
  46.  
  47. /* Make all the #if cases in the code esier to read */
  48. #ifndef DRI2INFOREC_VERSION
  49. #define DRI2INFOREC_VERSION 1
  50. #endif
  51.  
  52. #if DRI2INFOREC_VERSION == 2
  53. static Bool set_format_in_do_create_buffer;
  54. #endif
  55.  
  56. typedef struct {
  57.     PixmapPtr pPixmap;
  58.     struct pipe_resource *tex;
  59.     struct pipe_fence_handle *fence;
  60. } *BufferPrivatePtr;
  61.  
  62. static Bool
  63. dri2_do_create_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format)
  64. {
  65.     struct pipe_resource *tex = NULL;
  66.     ScreenPtr pScreen = pDraw->pScreen;
  67.     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
  68.     modesettingPtr ms = modesettingPTR(pScrn);
  69.     struct exa_pixmap_priv *exa_priv;
  70.     BufferPrivatePtr private = buffer->driverPrivate;
  71.     PixmapPtr pPixmap;
  72.     struct winsys_handle whandle;
  73.  
  74.     if (pDraw->type == DRAWABLE_PIXMAP)
  75.         pPixmap = (PixmapPtr) pDraw;
  76.     else
  77.         pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw);
  78.     exa_priv = exaGetPixmapDriverPrivate(pPixmap);
  79.  
  80.  
  81.     switch (buffer->attachment) {
  82.     default:
  83.         if (buffer->attachment != DRI2BufferFakeFrontLeft ||
  84.             pDraw->type != DRAWABLE_PIXMAP) {
  85.             private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width,
  86.                                                         pDraw->height,
  87.                                                         pDraw->depth,
  88.                                                         0);
  89.         }
  90.         break;
  91.     case DRI2BufferFrontLeft:
  92.         break;
  93.     case DRI2BufferStencil:
  94. #if DRI2INFOREC_VERSION >= 3
  95.     case DRI2BufferDepthStencil:
  96. #else
  97.     /* Works on old X servers because sanity checking is for the weak */
  98.     case 9:
  99. #endif
  100.         if (exa_priv->depth_stencil_tex &&
  101.             !util_format_is_depth_or_stencil(exa_priv->depth_stencil_tex->format))
  102.             exa_priv->depth_stencil_tex = NULL;
  103.         /* Fall through */
  104.     case DRI2BufferDepth:
  105.         if (exa_priv->depth_stencil_tex)
  106.             pipe_resource_reference(&tex, exa_priv->depth_stencil_tex);
  107.         else {
  108.             struct pipe_resource template;
  109.             unsigned depthBits = (format != 0) ? format : pDraw->depth;
  110.             memset(&template, 0, sizeof(template));
  111.             template.target = PIPE_TEXTURE_2D;
  112.             if (buffer->attachment == DRI2BufferDepth) {
  113.                switch(depthBits) {
  114.                case 16:
  115.                   template.format = PIPE_FORMAT_Z16_UNORM;
  116.                   break;
  117.                case 32:
  118.                   template.format = PIPE_FORMAT_Z32_UNORM;
  119.                   break;
  120.                default:
  121.                   template.format = ms->ds_depth_bits_last ?
  122.                                     PIPE_FORMAT_Z24X8_UNORM : PIPE_FORMAT_X8Z24_UNORM;
  123.                   break;
  124.                }
  125.             } else {
  126.                template.format = ms->ds_depth_bits_last ?
  127.                                  PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_S8_UINT_Z24_UNORM;
  128.             }
  129.             template.width0 = pDraw->width;
  130.             template.height0 = pDraw->height;
  131.             template.depth0 = 1;
  132.             template.array_size = 1;
  133.             template.last_level = 0;
  134.             template.bind = PIPE_BIND_DEPTH_STENCIL |
  135.                 PIPE_BIND_SHARED;
  136.             tex = ms->screen->resource_create(ms->screen, &template);
  137.             pipe_resource_reference(&exa_priv->depth_stencil_tex, tex);
  138.         }
  139.         break;
  140.     }
  141.  
  142.     if (!private->pPixmap) {
  143.         private->pPixmap = pPixmap;
  144.         pPixmap->refcnt++;
  145.     }
  146.  
  147.     if (!tex) {
  148.         /* First call to make sure we have a pixmap private */
  149.         exaMoveInPixmap(private->pPixmap);
  150.         xorg_exa_set_shared_usage(private->pPixmap);
  151.         pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL);
  152.         /* Second call to make sure texture has valid contents */
  153.         exaMoveInPixmap(private->pPixmap);
  154.         tex = xorg_exa_get_texture(private->pPixmap);
  155.     }
  156.  
  157.     if (!tex)
  158.         FatalError("NO TEXTURE IN DRI2\n");
  159.  
  160.     memset(&whandle, 0, sizeof(whandle));
  161.     whandle.type = DRM_API_HANDLE_TYPE_SHARED;
  162.  
  163.     ms->screen->resource_get_handle(ms->screen, tex, &whandle);
  164.  
  165.     buffer->name = whandle.handle;
  166.     buffer->pitch = whandle.stride;
  167.     buffer->cpp = 4;
  168.     buffer->driverPrivate = private;
  169.     buffer->flags = 0; /* not tiled */
  170. #if DRI2INFOREC_VERSION == 2
  171.     /* ABI forwards/backwards compatibility */
  172.     if (set_format_in_do_create_buffer)
  173.         ((DRI2Buffer2Ptr)buffer)->format = 0;
  174. #elif DRI2INFOREC_VERSION >= 3
  175.     buffer->format = 0;
  176. #endif
  177.     private->tex = tex;
  178.  
  179.     return TRUE;
  180. }
  181.  
  182. static void
  183. dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
  184. {
  185.     ScreenPtr pScreen = pDraw->pScreen;
  186.     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
  187.     modesettingPtr ms = modesettingPTR(pScrn);
  188.     BufferPrivatePtr private = buffer->driverPrivate;
  189.     struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap);
  190.  
  191.     pipe_resource_reference(&private->tex, NULL);
  192.     ms->screen->fence_reference(ms->screen, &private->fence, NULL);
  193.     pipe_resource_reference(&exa_priv->depth_stencil_tex, NULL);
  194.     (*pScreen->DestroyPixmap)(private->pPixmap);
  195. }
  196.  
  197. #if DRI2INFOREC_VERSION >= 2
  198.  
  199. static DRI2Buffer2Ptr
  200. dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format)
  201. {
  202.     DRI2Buffer2Ptr buffer;
  203.     BufferPrivatePtr private;
  204.  
  205.     buffer = calloc(1, sizeof *buffer);
  206.     if (!buffer)
  207.         return NULL;
  208.  
  209.     private = calloc(1, sizeof *private);
  210.     if (!private) {
  211.         goto fail;
  212.     }
  213.  
  214.     buffer->attachment = attachment;
  215.     buffer->driverPrivate = private;
  216.  
  217.     /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
  218.     if (dri2_do_create_buffer(pDraw, (DRI2BufferPtr)buffer, format))
  219.         return buffer;
  220.  
  221.     free(private);
  222. fail:
  223.     free(buffer);
  224.     return NULL;
  225. }
  226.  
  227. static void
  228. dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
  229. {
  230.     /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
  231.     dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer);
  232.  
  233.     free(buffer->driverPrivate);
  234.     free(buffer);
  235. }
  236.  
  237. #endif /* DRI2INFOREC_VERSION >= 2 */
  238.  
  239. #if DRI2INFOREC_VERSION <= 2
  240.  
  241. static DRI2BufferPtr
  242. dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments, int count)
  243. {
  244.     BufferPrivatePtr privates;
  245.     DRI2BufferPtr buffers;
  246.     int i;
  247.  
  248.     buffers = calloc(count, sizeof *buffers);
  249.     if (!buffers)
  250.         goto fail_buffers;
  251.  
  252.     privates = calloc(count, sizeof *privates);
  253.     if (!privates)
  254.         goto fail_privates;
  255.  
  256.     for (i = 0; i < count; i++) {
  257.         buffers[i].attachment = attachments[i];
  258.         buffers[i].driverPrivate = &privates[i];
  259.  
  260.         if (!dri2_do_create_buffer(pDraw, &buffers[i], 0))
  261.             goto fail;
  262.     }
  263.  
  264.     return buffers;
  265.  
  266. fail:
  267.     free(privates);
  268. fail_privates:
  269.     free(buffers);
  270. fail_buffers:
  271.     return NULL;
  272. }
  273.  
  274. static void
  275. dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count)
  276. {
  277.     int i;
  278.  
  279.     for (i = 0; i < count; i++) {
  280.         dri2_do_destroy_buffer(pDraw, &buffers[i]);
  281.     }
  282.  
  283.     if (buffers) {
  284.         free(buffers[0].driverPrivate);
  285.         free(buffers);
  286.     }
  287. }
  288.  
  289. #endif /* DRI2INFOREC_VERSION <= 2 */
  290.  
  291. static void
  292. dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
  293.                  DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer)
  294. {
  295.     ScreenPtr pScreen = pDraw->pScreen;
  296.     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
  297.     modesettingPtr ms = modesettingPTR(pScrn);
  298.     BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate;
  299.     BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate;
  300.     DrawablePtr src_draw;
  301.     DrawablePtr dst_draw;
  302.     GCPtr gc;
  303.     RegionPtr copy_clip;
  304.     Bool save_accel;
  305.     CustomizerPtr cust = ms->cust;
  306.  
  307.     /*
  308.      * In driCreateBuffers we dewrap windows into the
  309.      * backing pixmaps in order to get to the texture.
  310.      * We need to use the real drawable in CopyArea
  311.      * so that cliprects and offsets are correct.
  312.      */
  313.     src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
  314.        &src_priv->pPixmap->drawable;
  315.     dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
  316.        &dst_priv->pPixmap->drawable;
  317.  
  318.     /*
  319.      * The clients implements glXWaitX with a copy front to fake and then
  320.      * waiting on the server to signal its completion of it. While
  321.      * glXWaitGL is a client side flush and a copy from fake to front.
  322.      * This is how it is done in the DRI2 protocol, how ever depending
  323.      * which type of drawables the server does things a bit differently
  324.      * then what the protocol says as the fake and front are the same.
  325.      *
  326.      * for pixmaps glXWaitX is a server flush.
  327.      * for pixmaps glXWaitGL is a client flush.
  328.      * for windows glXWaitX is a copy from front to fake then a server flush.
  329.      * for windows glXWaitGL is a client flush then a copy from fake to front.
  330.      *
  331.      * XXX in the windows case this code always flushes but that isn't a
  332.      * must in the glXWaitGL case but we don't know if this is a glXWaitGL
  333.      * or a glFlush/glFinish call.
  334.      */
  335.     if (dst_priv->pPixmap == src_priv->pPixmap) {
  336.         /* pixmap glXWaitX */
  337.         if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
  338.             pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
  339.             ms->ctx->flush(ms->ctx, NULL, 0);
  340.             return;
  341.         }
  342.         /* pixmap glXWaitGL */
  343.         if (pDestBuffer->attachment == DRI2BufferFrontLeft &&
  344.             pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) {
  345.             return;
  346.         } else {
  347.             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
  348.                 "copying between the same pixmap\n");
  349.         }
  350.     }
  351.  
  352.     gc = GetScratchGC(pDraw->depth, pScreen);
  353.     copy_clip = REGION_CREATE(pScreen, NULL, 0);
  354.     REGION_COPY(pScreen, copy_clip, pRegion);
  355.     (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
  356.     ValidateGC(dst_draw, gc);
  357.  
  358.     /* If this is a full buffer swap, throttle on the previous one */
  359.     if (ms->swapThrottling &&
  360.         dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) {
  361.         BoxPtr extents = REGION_EXTENTS(pScreen, pRegion);
  362.  
  363.         if (extents->x1 == 0 && extents->y1 == 0 &&
  364.             extents->x2 == pDraw->width && extents->y2 == pDraw->height) {
  365.             ms->screen->fence_finish(ms->screen, dst_priv->fence,
  366.                                      PIPE_TIMEOUT_INFINITE);
  367.             ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL);
  368.         }
  369.     }
  370.  
  371.     /* Try to make sure the blit will be accelerated */
  372.     save_accel = ms->exa->accel;
  373.     ms->exa->accel = TRUE;
  374.  
  375.     if (pSrcBuffer->attachment != DRI2BufferFrontLeft) {
  376.         /* In case it won't be though, make sure the GPU copy contents of the
  377.          * source pixmap will be used for the software fallback - presumably the
  378.          * client modified them before calling in here.
  379.          */
  380.         exaMoveInPixmap(src_priv->pPixmap);
  381.         DamageRegionAppend(src_draw, pRegion);
  382.         DamageRegionProcessPending(src_draw);
  383.     }
  384.  
  385.    if (cust && cust->winsys_context_throttle)
  386.        cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_SWAP);
  387.  
  388.     (*gc->ops->CopyArea)(src_draw, dst_draw, gc,
  389.                          0, 0, pDraw->width, pDraw->height, 0, 0);
  390.     ms->exa->accel = save_accel;
  391.  
  392.     FreeScratchGC(gc);
  393.  
  394.     ms->ctx->flush(ms->ctx,
  395.                    (pDestBuffer->attachment == DRI2BufferFrontLeft
  396.                     && ms->swapThrottling) ?
  397.                    &dst_priv->fence : NULL, 0);
  398.  
  399.    if (cust && cust->winsys_context_throttle)
  400.        cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER);
  401.  
  402. }
  403.  
  404. Bool
  405. xorg_dri2_init(ScreenPtr pScreen)
  406. {
  407.     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
  408.     modesettingPtr ms = modesettingPTR(pScrn);
  409.     DRI2InfoRec dri2info;
  410. #if DRI2INFOREC_VERSION >= 2
  411.     int major, minor;
  412.  
  413.     if (xf86LoaderCheckSymbol("DRI2Version")) {
  414.         DRI2Version(&major, &minor);
  415.     } else {
  416.         /* Assume version 1.0 */
  417.         major = 1;
  418.         minor = 0;
  419.     }
  420. #endif
  421.  
  422.     dri2info.version = min(DRI2INFOREC_VERSION, 3);
  423.     dri2info.fd = ms->fd;
  424.  
  425.     dri2info.driverName = pScrn->driverName;
  426.     dri2info.deviceName = "/dev/dri/card0"; /* FIXME */
  427.  
  428. #if DRI2INFOREC_VERSION >= 2
  429.     dri2info.CreateBuffer = dri2_create_buffer;
  430.     dri2info.DestroyBuffer = dri2_destroy_buffer;
  431. #endif
  432.  
  433.     /* For X servers in the 1.6.x series there where two DRI2 version.
  434.      * This allows us to build one binary that works on both servers.
  435.      */
  436. #if DRI2INFOREC_VERSION == 2
  437.     if (minor == 0) {
  438.         set_format_in_do_create_buffer = FALSE;
  439.         dri2info.CreateBuffers = dri2_create_buffers;
  440.         dri2info.DestroyBuffers = dri2_destroy_buffers;
  441.     } else
  442.         set_format_in_do_create_buffer = FALSE;
  443. #endif
  444.  
  445.     /* For version 1 set these unconditionaly. */
  446. #if DRI2INFOREC_VERSION == 1
  447.     dri2info.CreateBuffers = dri2_create_buffers;
  448.     dri2info.DestroyBuffers = dri2_destroy_buffers;
  449. #endif
  450.     dri2info.CopyRegion = dri2_copy_region;
  451.     dri2info.Wait = NULL;
  452.  
  453.     ms->d_depth_bits_last =
  454.          ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24X8_UNORM,
  455.                                          PIPE_TEXTURE_2D,
  456.                                          0,
  457.                                          PIPE_BIND_DEPTH_STENCIL);
  458.     ms->ds_depth_bits_last =
  459.          ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24_UNORM_S8_UINT,
  460.                                          PIPE_TEXTURE_2D,
  461.                                          0,
  462.                                          PIPE_BIND_DEPTH_STENCIL);
  463.  
  464.     return DRI2ScreenInit(pScreen, &dri2info);
  465. }
  466.  
  467. void
  468. xorg_dri2_close(ScreenPtr pScreen)
  469. {
  470.     DRI2CloseScreen(pScreen);
  471. }
  472.  
  473. /* vim: set sw=4 ts=8 sts=4: */
  474.