Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * on the rights to use, copy, modify, merge, publish, distribute, sub
  8.  * license, and/or sell copies of the Software, and to permit persons to whom
  9.  * the Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  18.  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  21.  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
  22.  
  23. #include "loader.h"
  24.  
  25. #include "adapter9.h"
  26.  
  27. #include "pipe-loader/pipe_loader.h"
  28.  
  29. #include "pipe/p_screen.h"
  30. #include "pipe/p_state.h"
  31.  
  32. #include "target-helpers/inline_drm_helper.h"
  33. #include "target-helpers/inline_sw_helper.h"
  34. #include "state_tracker/drm_driver.h"
  35.  
  36. #include "d3dadapter/d3dadapter9.h"
  37. #include "d3dadapter/drm.h"
  38.  
  39. #include "xmlconfig.h"
  40. #include "xmlpool.h"
  41.  
  42. #include <drm.h>
  43. #include <sys/ioctl.h>
  44. #include <fcntl.h>
  45. #include <stdio.h>
  46.  
  47. #define DBG_CHANNEL DBG_ADAPTER
  48.  
  49. #define VERSION_DWORD(hi, lo) \
  50.     ((DWORD)( \
  51.         ((DWORD)((hi) & 0xFFFF) << 16) | \
  52.          (DWORD)((lo) & 0xFFFF) \
  53.     ))
  54.  
  55. const char __driConfigOptionsNine[] =
  56. DRI_CONF_BEGIN
  57.     DRI_CONF_SECTION_PERFORMANCE
  58.          DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
  59.     DRI_CONF_SECTION_END
  60.     DRI_CONF_SECTION_NINE
  61.         DRI_CONF_NINE_THROTTLE(-2)
  62.         DRI_CONF_NINE_THREADSUBMIT("false")
  63.     DRI_CONF_SECTION_END
  64. DRI_CONF_END;
  65.  
  66. /* Regarding os versions, we should not define our own as that would simply be
  67.  * weird. Defaulting to Win2k/XP seems sane considering the origin of D3D9. The
  68.  * driver also defaults to being a generic D3D9 driver, which of course only
  69.  * matters if you're actually using the DDI. */
  70. #define VERSION_HIGH    VERSION_DWORD(0x0006, 0x000E) /* winxp, d3d9 */
  71. #define VERSION_LOW     VERSION_DWORD(0x0000, 0x0001) /* version, build */
  72.  
  73. struct d3dadapter9drm_context
  74. {
  75.     struct d3dadapter9_context base;
  76.     struct pipe_loader_device *dev, *swdev;
  77.     int fd;
  78. };
  79.  
  80. static void
  81. drm_destroy( struct d3dadapter9_context *ctx )
  82. {
  83.     struct d3dadapter9drm_context *drm = (struct d3dadapter9drm_context *)ctx;
  84.  
  85.     if (ctx->ref)
  86.         ctx->ref->destroy(ctx->ref);
  87.     /* because ref is a wrapper around hal, freeing ref frees hal too. */
  88.     else if (ctx->hal)
  89.         ctx->hal->destroy(ctx->hal);
  90.  
  91. #if !GALLIUM_STATIC_TARGETS
  92.     if (drm->swdev)
  93.         pipe_loader_release(&drm->swdev, 1);
  94.     if (drm->dev)
  95.         pipe_loader_release(&drm->dev, 1);
  96. #endif
  97.  
  98.     close(drm->fd);
  99.     FREE(ctx);
  100. }
  101.  
  102. /* read a DWORD in the form 0xnnnnnnnn, which is how sysfs pci id stuff is
  103.  * formatted. */
  104. static INLINE DWORD
  105. read_file_dword( const char *name )
  106. {
  107.     char buf[32];
  108.     int fd, r;
  109.  
  110.     fd = open(name, O_RDONLY);
  111.     if (fd < 0) {
  112.         DBG("Unable to get PCI information from `%s'\n", name);
  113.         return 0;
  114.     }
  115.  
  116.     r = read(fd, buf, 32);
  117.     close(fd);
  118.  
  119.     return (r > 0) ? (DWORD)strtol(buf, NULL, 0) : 0;
  120. }
  121.  
  122. /* sysfs doesn't expose the revision as its own file, so this function grabs a
  123.  * dword at an offset in the raw PCI header. The reason this isn't used for all
  124.  * data is that the kernel will make corrections but not expose them in the raw
  125.  * header bytes. */
  126. static INLINE DWORD
  127. read_config_dword( int fd,
  128.                    unsigned offset )
  129. {
  130.     DWORD r = 0;
  131.  
  132.     if (lseek(fd, offset, SEEK_SET) != offset) { return 0; }
  133.     if (read(fd, &r, 4) != 4) { return 0; }
  134.  
  135.     return r;
  136. }
  137.  
  138. static INLINE void
  139. get_bus_info( int fd,
  140.               DWORD *vendorid,
  141.               DWORD *deviceid,
  142.               DWORD *subsysid,
  143.               DWORD *revision )
  144. {
  145.     int vid, did;
  146.  
  147.     if (loader_get_pci_id_for_fd(fd, &vid, &did)) {
  148.         DBG("PCI info: vendor=0x%04x, device=0x%04x\n",
  149.             vid, did);
  150.         *vendorid = vid;
  151.         *deviceid = did;
  152.         *subsysid = 0;
  153.         *revision = 0;
  154.     } else {
  155.         DBG("Unable to detect card. Fake GTX 680.\n");
  156.         *vendorid = 0x10de; /* NV GTX 680 */
  157.         *deviceid = 0x1180;
  158.         *subsysid = 0;
  159.         *revision = 0;
  160.     }
  161. }
  162.  
  163. static INLINE void
  164. read_descriptor( struct d3dadapter9_context *ctx,
  165.                  int fd )
  166. {
  167.     D3DADAPTER_IDENTIFIER9 *drvid = &ctx->identifier;
  168.  
  169.     memset(drvid, 0, sizeof(*drvid));
  170.     get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId,
  171.                  &drvid->SubSysId, &drvid->Revision);
  172.  
  173.     strncpy(drvid->Driver, "libd3dadapter9.so", sizeof(drvid->Driver));
  174.     strncpy(drvid->DeviceName, ctx->hal->get_name(ctx->hal), 32);
  175.     snprintf(drvid->Description, sizeof(drvid->Description),
  176.              "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal));
  177.  
  178.     drvid->DriverVersionLowPart = VERSION_LOW;
  179.     drvid->DriverVersionHighPart = VERSION_HIGH;
  180.  
  181.     /* To make a pseudo-real GUID we use the PCI bus data and some string */
  182.     drvid->DeviceIdentifier.Data1 = drvid->VendorId;
  183.     drvid->DeviceIdentifier.Data2 = drvid->DeviceId;
  184.     drvid->DeviceIdentifier.Data3 = drvid->SubSysId;
  185.     memcpy(drvid->DeviceIdentifier.Data4, "Gallium3D", 8);
  186.  
  187.     drvid->WHQLLevel = 1; /* This fakes WHQL validaion */
  188.  
  189.     /* XXX Fake NVIDIA binary driver on Windows.
  190.      *
  191.      * OS version: 4=95/98/NT4, 5=2000, 6=2000/XP, 7=Vista, 8=Win7
  192.      */
  193.     strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver));
  194.     strncpy(drvid->Description, "NVIDIA GeForce GTX 680", sizeof(drvid->Description));
  195.     drvid->DriverVersionLowPart = VERSION_DWORD(12, 6658); /* minor, build */
  196.     drvid->DriverVersionHighPart = VERSION_DWORD(6, 15); /* OS, major */
  197.     drvid->SubSysId = 0;
  198.     drvid->Revision = 0;
  199.     drvid->DeviceIdentifier.Data1 = 0xaeb2cdd4;
  200.     drvid->DeviceIdentifier.Data2 = 0x6e41;
  201.     drvid->DeviceIdentifier.Data3 = 0x43ea;
  202.     drvid->DeviceIdentifier.Data4[0] = 0x94;
  203.     drvid->DeviceIdentifier.Data4[1] = 0x1c;
  204.     drvid->DeviceIdentifier.Data4[2] = 0x83;
  205.     drvid->DeviceIdentifier.Data4[3] = 0x61;
  206.     drvid->DeviceIdentifier.Data4[4] = 0xcc;
  207.     drvid->DeviceIdentifier.Data4[5] = 0x76;
  208.     drvid->DeviceIdentifier.Data4[6] = 0x07;
  209.     drvid->DeviceIdentifier.Data4[7] = 0x81;
  210.     drvid->WHQLLevel = 0;
  211. }
  212.  
  213. static HRESULT WINAPI
  214. drm_create_adapter( int fd,
  215.                     ID3DAdapter9 **ppAdapter )
  216. {
  217.     struct d3dadapter9drm_context *ctx = CALLOC_STRUCT(d3dadapter9drm_context);
  218.     HRESULT hr;
  219.     int different_device;
  220.     const struct drm_conf_ret *throttle_ret = NULL;
  221.     const struct drm_conf_ret *dmabuf_ret = NULL;
  222.     driOptionCache defaultInitOptions;
  223.     driOptionCache userInitOptions;
  224.     int throttling_value_user = -2;
  225.  
  226. #if !GALLIUM_STATIC_TARGETS
  227.     const char *paths[] = {
  228.         getenv("D3D9_DRIVERS_PATH"),
  229.         getenv("D3D9_DRIVERS_DIR"),
  230.         PIPE_SEARCH_DIR
  231.     };
  232. #endif
  233.  
  234.     if (!ctx) { return E_OUTOFMEMORY; }
  235.  
  236.     ctx->base.destroy = drm_destroy;
  237.  
  238.     fd = loader_get_user_preferred_fd(fd, &different_device);
  239.     ctx->fd = fd;
  240.     ctx->base.linear_framebuffer = !!different_device;
  241.  
  242. #if GALLIUM_STATIC_TARGETS
  243.     ctx->base.hal = dd_create_screen(fd);
  244. #else
  245.     /* use pipe-loader to dlopen appropriate drm driver */
  246.     if (!pipe_loader_drm_probe_fd(&ctx->dev, fd, FALSE)) {
  247.         ERR("Failed to probe drm fd %d.\n", fd);
  248.         FREE(ctx);
  249.         close(fd);
  250.         return D3DERR_DRIVERINTERNALERROR;
  251.     }
  252.  
  253.     /* use pipe-loader to create a drm screen (hal) */
  254.     ctx->base.hal = NULL;
  255.     for (i = 0; !ctx->base.hal && i < Elements(paths); ++i) {
  256.         if (!paths[i]) { continue; }
  257.         ctx->base.hal = pipe_loader_create_screen(ctx->dev, paths[i]);
  258.     }
  259. #endif
  260.     if (!ctx->base.hal) {
  261.         ERR("Unable to load requested driver.\n");
  262.         drm_destroy(&ctx->base);
  263.         return D3DERR_DRIVERINTERNALERROR;
  264.     }
  265.  
  266. #if GALLIUM_STATIC_TARGETS
  267.     dmabuf_ret = dd_configuration(DRM_CONF_SHARE_FD);
  268.     throttle_ret = dd_configuration(DRM_CONF_THROTTLE);
  269. #else
  270.     dmabuf_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_SHARE_FD);
  271.     throttle_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_THROTTLE);
  272. #endif // GALLIUM_STATIC_TARGETS
  273.     if (!dmabuf_ret || !dmabuf_ret->val.val_bool) {
  274.         ERR("The driver is not capable of dma-buf sharing."
  275.             "Abandon to load nine state tracker\n");
  276.         drm_destroy(&ctx->base);
  277.         return D3DERR_DRIVERINTERNALERROR;
  278.     }
  279.  
  280.     if (throttle_ret && throttle_ret->val.val_int != -1) {
  281.         ctx->base.throttling = TRUE;
  282.         ctx->base.throttling_value = throttle_ret->val.val_int;
  283.     } else
  284.         ctx->base.throttling = FALSE;
  285.  
  286.     driParseOptionInfo(&defaultInitOptions, __driConfigOptionsNine);
  287.     driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "nine");
  288.     if (driCheckOption(&userInitOptions, "throttle_value", DRI_INT)) {
  289.         throttling_value_user = driQueryOptioni(&userInitOptions, "throttle_value");
  290.         if (throttling_value_user == -1)
  291.             ctx->base.throttling = FALSE;
  292.         else if (throttling_value_user >= 0) {
  293.             ctx->base.throttling = TRUE;
  294.             ctx->base.throttling_value = throttling_value_user;
  295.         }
  296.     }
  297.  
  298.     if (driCheckOption(&userInitOptions, "vblank_mode", DRI_ENUM))
  299.         ctx->base.vblank_mode = driQueryOptioni(&userInitOptions, "vblank_mode");
  300.     else
  301.         ctx->base.vblank_mode = 1;
  302.  
  303.     if (driCheckOption(&userInitOptions, "thread_submit", DRI_BOOL)) {
  304.         ctx->base.thread_submit = driQueryOptionb(&userInitOptions, "thread_submit");
  305.         if (ctx->base.thread_submit && (throttling_value_user == -2 || throttling_value_user == 0)) {
  306.             ctx->base.throttling_value = 0;
  307.         } else if (ctx->base.thread_submit) {
  308.             DBG("You have set a non standard throttling value in combination with thread_submit."
  309.                 "We advise to use a throttling value of -2/0");
  310.         }
  311.         if (ctx->base.thread_submit && !different_device)
  312.             DBG("You have set thread_submit but do not use a different device than the server."
  313.                 "You should not expect any benefit.");
  314.     }
  315.  
  316.     driDestroyOptionCache(&userInitOptions);
  317.     driDestroyOptionInfo(&defaultInitOptions);
  318.  
  319. #if GALLIUM_STATIC_TARGETS
  320.     ctx->base.ref = ninesw_create_screen(ctx->base.hal);
  321. #else
  322.     /* wrap it to create a software screen that can share resources */
  323.     if (pipe_loader_sw_probe_wrapped(&ctx->swdev, ctx->base.hal)) {
  324.         ctx->base.ref = NULL;
  325.         for (i = 0; !ctx->base.ref && i < Elements(paths); ++i) {
  326.             if (!paths[i]) { continue; }
  327.             ctx->base.ref = pipe_loader_create_screen(ctx->swdev, paths[i]);
  328.         }
  329.     }
  330. #endif
  331.     if (!ctx->base.ref) {
  332.         ERR("Couldn't wrap drm screen to swrast screen. Software devices "
  333.             "will be unavailable.\n");
  334.     }
  335.  
  336.     /* read out PCI info */
  337.     read_descriptor(&ctx->base, fd);
  338.  
  339.     /* create and return new ID3DAdapter9 */
  340.     hr = NineAdapter9_new(&ctx->base, (struct NineAdapter9 **)ppAdapter);
  341.     if (FAILED(hr)) {
  342.         drm_destroy(&ctx->base);
  343.         return hr;
  344.     }
  345.  
  346.     return D3D_OK;
  347. }
  348.  
  349. const struct D3DAdapter9DRM drm9_desc = {
  350.     .major_version = D3DADAPTER9DRM_MAJOR,
  351.     .minor_version = D3DADAPTER9DRM_MINOR,
  352.     .create_adapter = drm_create_adapter
  353. };
  354.