101e04c3fSmrg/* 201e04c3fSmrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub 801e04c3fSmrg * license, and/or sell copies of the Software, and to permit persons to whom 901e04c3fSmrg * the Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 1901e04c3fSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2001e04c3fSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2101e04c3fSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 2201e04c3fSmrg 2301e04c3fSmrg/* XXX: header order is slightly screwy here */ 2401e04c3fSmrg#include "loader.h" 2501e04c3fSmrg 2601e04c3fSmrg#include "adapter9.h" 2701e04c3fSmrg 2801e04c3fSmrg#include "pipe-loader/pipe_loader.h" 2901e04c3fSmrg 3001e04c3fSmrg#include "pipe/p_screen.h" 3101e04c3fSmrg#include "pipe/p_state.h" 3201e04c3fSmrg 3301e04c3fSmrg#include "target-helpers/drm_helper.h" 3401e04c3fSmrg#include "target-helpers/sw_helper.h" 357ec681f3Smrg#include "frontend/drm_driver.h" 3601e04c3fSmrg 3701e04c3fSmrg#include "d3dadapter/d3dadapter9.h" 3801e04c3fSmrg#include "d3dadapter/drm.h" 3901e04c3fSmrg 4001e04c3fSmrg#include "util/xmlconfig.h" 417ec681f3Smrg#include "util/driconf.h" 4201e04c3fSmrg 439f464c52Smaya#include "drm-uapi/drm.h" 4401e04c3fSmrg#include <sys/ioctl.h> 4501e04c3fSmrg#include <fcntl.h> 4601e04c3fSmrg#include <stdio.h> 4701e04c3fSmrg 4801e04c3fSmrg#define DBG_CHANNEL DBG_ADAPTER 4901e04c3fSmrg 507ec681f3Smrgconst driOptionDescription __driConfigOptionsNine[] = { 5101e04c3fSmrg DRI_CONF_SECTION_PERFORMANCE 5201e04c3fSmrg DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) 5301e04c3fSmrg DRI_CONF_SECTION_END 5401e04c3fSmrg DRI_CONF_SECTION_NINE 5501e04c3fSmrg DRI_CONF_NINE_OVERRIDEVENDOR(-1) 5601e04c3fSmrg DRI_CONF_NINE_THROTTLE(-2) 577ec681f3Smrg DRI_CONF_NINE_THREADSUBMIT(true) 587ec681f3Smrg DRI_CONF_NINE_ALLOWDISCARDDELAYEDRELEASE(true) 597ec681f3Smrg DRI_CONF_NINE_TEARFREEDISCARD(true) 6001e04c3fSmrg DRI_CONF_NINE_CSMT(-1) 617ec681f3Smrg DRI_CONF_NINE_DYNAMICTEXTUREWORKAROUND(true) 627ec681f3Smrg DRI_CONF_NINE_SHADERINLINECONSTANTS(false) 637ec681f3Smrg DRI_CONF_NINE_SHMEM_LIMIT() 647ec681f3Smrg DRI_CONF_NINE_FORCESWRENDERINGONCPU(false) 6501e04c3fSmrg DRI_CONF_SECTION_END 667ec681f3Smrg DRI_CONF_SECTION_DEBUG 677ec681f3Smrg DRI_CONF_OVERRIDE_VRAM_SIZE() 687ec681f3Smrg DRI_CONF_SECTION_END 697ec681f3Smrg}; 7001e04c3fSmrg 7101e04c3fSmrgstruct fallback_card_config { 7201e04c3fSmrg const char *name; 7301e04c3fSmrg unsigned vendor_id; 7401e04c3fSmrg unsigned device_id; 7501e04c3fSmrg} fallback_cards[] = { 7601e04c3fSmrg {"NV124", 0x10de, 0x13C2}, /* NVIDIA GeForce GTX 970 */ 7701e04c3fSmrg {"HAWAII", 0x1002, 0x67b1}, /* AMD Radeon R9 290 */ 7801e04c3fSmrg {"Haswell Mobile", 0x8086, 0x13C2}, /* Intel Haswell Mobile */ 7901e04c3fSmrg {"SVGA3D", 0x15ad, 0x0405}, /* VMware SVGA 3D */ 8001e04c3fSmrg}; 8101e04c3fSmrg 8201e04c3fSmrg/* prototypes */ 8301e04c3fSmrgvoid 8401e04c3fSmrgd3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, 8501e04c3fSmrg unsigned fallback_ven, 8601e04c3fSmrg unsigned fallback_dev, 8701e04c3fSmrg const char* fallback_name ); 8801e04c3fSmrg 8901e04c3fSmrgvoid d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid); 9001e04c3fSmrg 9101e04c3fSmrgvoid d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid); 9201e04c3fSmrg 9301e04c3fSmrgstruct d3dadapter9drm_context 9401e04c3fSmrg{ 9501e04c3fSmrg struct d3dadapter9_context base; 9601e04c3fSmrg struct pipe_loader_device *dev, *swdev; 9701e04c3fSmrg int fd; 9801e04c3fSmrg}; 9901e04c3fSmrg 10001e04c3fSmrgstatic void 10101e04c3fSmrgdrm_destroy( struct d3dadapter9_context *ctx ) 10201e04c3fSmrg{ 10301e04c3fSmrg struct d3dadapter9drm_context *drm = (struct d3dadapter9drm_context *)ctx; 10401e04c3fSmrg 1057ec681f3Smrg if (ctx->ref && ctx->hal != ctx->ref) 10601e04c3fSmrg ctx->ref->destroy(ctx->ref); 10701e04c3fSmrg /* because ref is a wrapper around hal, freeing ref frees hal too. */ 10801e04c3fSmrg else if (ctx->hal) 10901e04c3fSmrg ctx->hal->destroy(ctx->hal); 11001e04c3fSmrg 1117ec681f3Smrg if (drm->swdev && drm->swdev != drm->dev) 11201e04c3fSmrg pipe_loader_release(&drm->swdev, 1); 11301e04c3fSmrg if (drm->dev) 11401e04c3fSmrg pipe_loader_release(&drm->dev, 1); 11501e04c3fSmrg 11601e04c3fSmrg close(drm->fd); 11701e04c3fSmrg FREE(ctx); 11801e04c3fSmrg} 11901e04c3fSmrg 12001e04c3fSmrgstatic inline void 12101e04c3fSmrgget_bus_info( int fd, 12201e04c3fSmrg DWORD *vendorid, 12301e04c3fSmrg DWORD *deviceid, 12401e04c3fSmrg DWORD *subsysid, 12501e04c3fSmrg DWORD *revision ) 12601e04c3fSmrg{ 12701e04c3fSmrg int vid, did; 12801e04c3fSmrg 12901e04c3fSmrg if (loader_get_pci_id_for_fd(fd, &vid, &did)) { 13001e04c3fSmrg DBG("PCI info: vendor=0x%04x, device=0x%04x\n", 13101e04c3fSmrg vid, did); 13201e04c3fSmrg *vendorid = vid; 13301e04c3fSmrg *deviceid = did; 13401e04c3fSmrg *subsysid = 0; 13501e04c3fSmrg *revision = 0; 13601e04c3fSmrg } else { 13701e04c3fSmrg DBG("Unable to detect card. Faking %s\n", fallback_cards[0].name); 13801e04c3fSmrg *vendorid = fallback_cards[0].vendor_id; 13901e04c3fSmrg *deviceid = fallback_cards[0].device_id; 14001e04c3fSmrg *subsysid = 0; 14101e04c3fSmrg *revision = 0; 14201e04c3fSmrg } 14301e04c3fSmrg} 14401e04c3fSmrg 14501e04c3fSmrgstatic inline void 14601e04c3fSmrgread_descriptor( struct d3dadapter9_context *ctx, 14701e04c3fSmrg int fd, int override_vendorid ) 14801e04c3fSmrg{ 14901e04c3fSmrg unsigned i; 15001e04c3fSmrg BOOL found; 15101e04c3fSmrg D3DADAPTER_IDENTIFIER9 *drvid = &ctx->identifier; 15201e04c3fSmrg 15301e04c3fSmrg memset(drvid, 0, sizeof(*drvid)); 15401e04c3fSmrg get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId, 15501e04c3fSmrg &drvid->SubSysId, &drvid->Revision); 15601e04c3fSmrg snprintf(drvid->DeviceName, sizeof(drvid->DeviceName), 15701e04c3fSmrg "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal)); 1589f464c52Smaya snprintf(drvid->Description, sizeof(drvid->Description), 1599f464c52Smaya "%s", ctx->hal->get_name(ctx->hal)); 16001e04c3fSmrg 16101e04c3fSmrg if (override_vendorid > 0) { 16201e04c3fSmrg found = FALSE; 16301e04c3fSmrg /* fill in device_id and card name for fake vendor */ 16401e04c3fSmrg for (i = 0; i < sizeof(fallback_cards)/sizeof(fallback_cards[0]); i++) { 16501e04c3fSmrg if (fallback_cards[i].vendor_id == override_vendorid) { 16601e04c3fSmrg DBG("Faking card '%s' vendor 0x%04x, device 0x%04x\n", 16701e04c3fSmrg fallback_cards[i].name, 16801e04c3fSmrg fallback_cards[i].vendor_id, 16901e04c3fSmrg fallback_cards[i].device_id); 17001e04c3fSmrg drvid->VendorId = fallback_cards[i].vendor_id; 17101e04c3fSmrg drvid->DeviceId = fallback_cards[i].device_id; 1729f464c52Smaya snprintf(drvid->Description, sizeof(drvid->Description), 1739f464c52Smaya "%s", fallback_cards[i].name); 17401e04c3fSmrg found = TRUE; 17501e04c3fSmrg break; 17601e04c3fSmrg } 17701e04c3fSmrg } 17801e04c3fSmrg if (!found) { 17901e04c3fSmrg DBG("Unknown fake vendor 0x%04x! Using detected vendor !\n", override_vendorid); 18001e04c3fSmrg } 18101e04c3fSmrg } 18201e04c3fSmrg /* choose fall-back vendor if necessary to allow 18301e04c3fSmrg * the following functions to return sane results */ 18401e04c3fSmrg d3d_match_vendor_id(drvid, fallback_cards[0].vendor_id, fallback_cards[0].device_id, fallback_cards[0].name); 18501e04c3fSmrg /* fill in driver name and version info */ 18601e04c3fSmrg d3d_fill_driver_version(drvid); 18701e04c3fSmrg /* override Description field with Windows like names */ 18801e04c3fSmrg d3d_fill_cardname(drvid); 18901e04c3fSmrg 19001e04c3fSmrg /* this driver isn't WHQL certified */ 19101e04c3fSmrg drvid->WHQLLevel = 0; 19201e04c3fSmrg 19301e04c3fSmrg /* this value is fixed */ 19401e04c3fSmrg drvid->DeviceIdentifier.Data1 = 0xaeb2cdd4; 19501e04c3fSmrg drvid->DeviceIdentifier.Data2 = 0x6e41; 19601e04c3fSmrg drvid->DeviceIdentifier.Data3 = 0x43ea; 19701e04c3fSmrg drvid->DeviceIdentifier.Data4[0] = 0x94; 19801e04c3fSmrg drvid->DeviceIdentifier.Data4[1] = 0x1c; 19901e04c3fSmrg drvid->DeviceIdentifier.Data4[2] = 0x83; 20001e04c3fSmrg drvid->DeviceIdentifier.Data4[3] = 0x61; 20101e04c3fSmrg drvid->DeviceIdentifier.Data4[4] = 0xcc; 20201e04c3fSmrg drvid->DeviceIdentifier.Data4[5] = 0x76; 20301e04c3fSmrg drvid->DeviceIdentifier.Data4[6] = 0x07; 20401e04c3fSmrg drvid->DeviceIdentifier.Data4[7] = 0x81; 20501e04c3fSmrg} 20601e04c3fSmrg 20701e04c3fSmrgstatic HRESULT WINAPI 20801e04c3fSmrgdrm_create_adapter( int fd, 20901e04c3fSmrg ID3DAdapter9 **ppAdapter ) 21001e04c3fSmrg{ 21101e04c3fSmrg struct d3dadapter9drm_context *ctx = CALLOC_STRUCT(d3dadapter9drm_context); 21201e04c3fSmrg HRESULT hr; 21301e04c3fSmrg bool different_device; 21401e04c3fSmrg driOptionCache defaultInitOptions; 21501e04c3fSmrg driOptionCache userInitOptions; 21601e04c3fSmrg int throttling_value_user = -2; 21701e04c3fSmrg int override_vendorid = -1; 2187ec681f3Smrg bool sw_rendering; 21901e04c3fSmrg 22001e04c3fSmrg if (!ctx) { return E_OUTOFMEMORY; } 22101e04c3fSmrg 22201e04c3fSmrg ctx->base.destroy = drm_destroy; 22301e04c3fSmrg 22401e04c3fSmrg /* Although the fd is provided from external source, mesa/nine 22501e04c3fSmrg * takes ownership of it. */ 22601e04c3fSmrg fd = loader_get_user_preferred_fd(fd, &different_device); 22701e04c3fSmrg ctx->fd = fd; 22801e04c3fSmrg ctx->base.linear_framebuffer = different_device; 22901e04c3fSmrg 23001e04c3fSmrg if (!pipe_loader_drm_probe_fd(&ctx->dev, fd)) { 23101e04c3fSmrg ERR("Failed to probe drm fd %d.\n", fd); 23201e04c3fSmrg FREE(ctx); 23301e04c3fSmrg close(fd); 23401e04c3fSmrg return D3DERR_DRIVERINTERNALERROR; 23501e04c3fSmrg } 23601e04c3fSmrg 23701e04c3fSmrg ctx->base.hal = pipe_loader_create_screen(ctx->dev); 23801e04c3fSmrg if (!ctx->base.hal) { 23901e04c3fSmrg ERR("Unable to load requested driver.\n"); 24001e04c3fSmrg drm_destroy(&ctx->base); 24101e04c3fSmrg return D3DERR_DRIVERINTERNALERROR; 24201e04c3fSmrg } 24301e04c3fSmrg 2449f464c52Smaya if (!ctx->base.hal->get_param(ctx->base.hal, PIPE_CAP_DMABUF)) { 24501e04c3fSmrg ERR("The driver is not capable of dma-buf sharing." 24601e04c3fSmrg "Abandon to load nine state tracker\n"); 24701e04c3fSmrg drm_destroy(&ctx->base); 24801e04c3fSmrg return D3DERR_DRIVERINTERNALERROR; 24901e04c3fSmrg } 25001e04c3fSmrg 2519f464c52Smaya /* Previously was set to PIPE_CAP_MAX_FRAMES_IN_FLIGHT, 2529f464c52Smaya * but the change of value of this cap to 1 seems to cause 2539f464c52Smaya * regressions. */ 2549f464c52Smaya ctx->base.throttling_value = 2; 2559f464c52Smaya ctx->base.throttling = ctx->base.throttling_value > 0; 25601e04c3fSmrg 2577ec681f3Smrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsNine, 2587ec681f3Smrg ARRAY_SIZE(__driConfigOptionsNine)); 2597ec681f3Smrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, 2607ec681f3Smrg "nine", NULL, NULL, NULL, 0, NULL, 0); 26101e04c3fSmrg if (driCheckOption(&userInitOptions, "throttle_value", DRI_INT)) { 26201e04c3fSmrg throttling_value_user = driQueryOptioni(&userInitOptions, "throttle_value"); 26301e04c3fSmrg if (throttling_value_user == -1) 26401e04c3fSmrg ctx->base.throttling = FALSE; 26501e04c3fSmrg else if (throttling_value_user >= 0) { 26601e04c3fSmrg ctx->base.throttling = TRUE; 26701e04c3fSmrg ctx->base.throttling_value = throttling_value_user; 26801e04c3fSmrg } 26901e04c3fSmrg } 27001e04c3fSmrg 2717ec681f3Smrg ctx->base.vblank_mode = driQueryOptioni(&userInitOptions, "vblank_mode"); 2727ec681f3Smrg ctx->base.thread_submit = driQueryOptionb(&userInitOptions, "thread_submit"); /* TODO: default to TRUE if different_device */ 2737ec681f3Smrg override_vendorid = driQueryOptioni(&userInitOptions, "override_vendorid"); 27401e04c3fSmrg 2757ec681f3Smrg ctx->base.discard_delayed_release = driQueryOptionb(&userInitOptions, "discard_delayed_release"); 2767ec681f3Smrg ctx->base.tearfree_discard = driQueryOptionb(&userInitOptions, "tearfree_discard"); 27701e04c3fSmrg 27801e04c3fSmrg if (ctx->base.tearfree_discard && !ctx->base.discard_delayed_release) { 27901e04c3fSmrg ERR("tearfree_discard requires discard_delayed_release\n"); 28001e04c3fSmrg ctx->base.tearfree_discard = FALSE; 28101e04c3fSmrg } 28201e04c3fSmrg 2837ec681f3Smrg ctx->base.csmt_force = driQueryOptioni(&userInitOptions, "csmt_force"); 2847ec681f3Smrg ctx->base.dynamic_texture_workaround = driQueryOptionb(&userInitOptions, "dynamic_texture_workaround"); 2857ec681f3Smrg ctx->base.shader_inline_constants = driQueryOptionb(&userInitOptions, "shader_inline_constants"); 2867ec681f3Smrg ctx->base.memfd_virtualsizelimit = driQueryOptioni(&userInitOptions, "texture_memory_limit"); 2877ec681f3Smrg ctx->base.override_vram_size = driQueryOptioni(&userInitOptions, "override_vram_size"); 2887ec681f3Smrg sw_rendering = driQueryOptionb(&userInitOptions, "force_sw_rendering_on_cpu"); 2899f464c52Smaya 29001e04c3fSmrg driDestroyOptionCache(&userInitOptions); 29101e04c3fSmrg driDestroyOptionInfo(&defaultInitOptions); 29201e04c3fSmrg 29301e04c3fSmrg /* wrap it to create a software screen that can share resources */ 2947ec681f3Smrg if (sw_rendering && pipe_loader_sw_probe_wrapped(&ctx->swdev, ctx->base.hal)) 29501e04c3fSmrg ctx->base.ref = pipe_loader_create_screen(ctx->swdev); 2967ec681f3Smrg else { 2977ec681f3Smrg /* Use the hardware for sw rendering */ 2987ec681f3Smrg ctx->swdev = ctx->dev; 2997ec681f3Smrg ctx->base.ref = ctx->base.hal; 30001e04c3fSmrg } 30101e04c3fSmrg 30201e04c3fSmrg /* read out PCI info */ 30301e04c3fSmrg read_descriptor(&ctx->base, fd, override_vendorid); 30401e04c3fSmrg 30501e04c3fSmrg /* create and return new ID3DAdapter9 */ 30601e04c3fSmrg hr = NineAdapter9_new(&ctx->base, (struct NineAdapter9 **)ppAdapter); 30701e04c3fSmrg if (FAILED(hr)) { 30801e04c3fSmrg drm_destroy(&ctx->base); 30901e04c3fSmrg return hr; 31001e04c3fSmrg } 31101e04c3fSmrg 31201e04c3fSmrg return D3D_OK; 31301e04c3fSmrg} 31401e04c3fSmrg 31501e04c3fSmrgconst struct D3DAdapter9DRM drm9_desc = { 31601e04c3fSmrg .major_version = D3DADAPTER9DRM_MAJOR, 31701e04c3fSmrg .minor_version = D3DADAPTER9DRM_MINOR, 31801e04c3fSmrg .create_adapter = drm_create_adapter 31901e04c3fSmrg}; 320