Hello! I wrote a patch to query the amount of videoram via the NV-CONTROL and ATIFGLEXTENSION Xserver extensions. The problem is: I have no access to a box with an ATI adapter to test it. Therefore, I'm sending the patch to wine-devel rather than to wine-patches. Perhaps somebody with an ATI card could test the patch. Alternatively, I attached a small test program which just prints the amount of videoram to stdout and uses the same code as the patch.
Fabian
From c1b2f368aa4580faef68cc0eaff0c5387e3eb8bf Mon Sep 17 00:00:00 2001 From: Fabian Bieler der.fabe@gmx.net Date: Fri, 6 Oct 2006 00:07:00 +0200 Subject: [PATCH] use NV-CONTROL and ATIFGLEXTENSION Xserver extensions to query amount of videoram --- dlls/wined3d/device.c | 26 +--- dlls/wined3d/directx.c | 36 +++++ dlls/wined3d/wined3d_private.h | 1 dlls/winex11.drv/Makefile.in | 1 dlls/winex11.drv/init.c | 7 + dlls/winex11.drv/opengl.c | 17 +++ dlls/winex11.drv/vendor_specific.c | 242 ++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 6 + 8 files changed, 312 insertions(+), 24 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 82c8044..3358111 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1061,7 +1061,7 @@ static HRESULT WINAPI IWineD3DDeviceImp
/** TODO: change this into a texture transform matrix so that it's processed in hardware **/
- TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM); + TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
/** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly * this function is too deap to need to care about things like this. @@ -2305,24 +2305,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl }
static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) { - /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever) - * Into the video ram as possible and seeing how many fit - * you can also get the correct initial value from nvidia and ATI's driver via X - * texture memory is video memory + AGP memory - *******************/ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - static BOOL showfixmes = TRUE; - if (showfixmes) { - FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This, - (wined3d_settings.emulated_textureram/(1024*1024)), - ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); - showfixmes = FALSE; - } - TRACE("(%p) : simulating %dMB, returning %dMB left\n", This, - (wined3d_settings.emulated_textureram/(1024*1024)), - ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); - /* return simulated texture memory left */ - return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram); + + TRACE("(%p) : emulating %dMib, returning %dMib\n", This, (This->videoRam/1024), + ((This->videoRam*1024 - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); + /* videomemory is simulated videomemory + AGP memory left */ + return (This->videoRam*1024 - wineD3DGlobalStatistics->glsurfaceram); }
@@ -5909,7 +5897,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl IWineD3DStateBlockImpl *object; HRESULT temp_result;
- TRACE("(%p)\n", This); + TRACE("(%p)", This);
if (This->isRecordingState) { return WINED3DERR_INVALIDCALL; diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 33b4fb5..4205986 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -42,9 +42,17 @@ #define GLINFO_LOCATION This->gl_info #define X11DRV_ESCAPE 6789 enum x11drv_escape_codes { - X11DRV_GET_DISPLAY, /* get X11 display for a DC */ - X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ - X11DRV_GET_FONT, /* get current X font for a DC */ + X11DRV_GET_DISPLAY, /* get X11 display for a DC */ + X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ + X11DRV_GET_FONT, /* get current X font for a DC */ + X11DRV_SET_DRAWABLE, /* set current drawable for a DC */ + X11DRV_START_EXPOSURES, /* start graphics exposures */ + X11DRV_END_EXPOSURES, /* end graphics exposures */ + X11DRV_GET_DCE, /* get the DCE pointer */ + X11DRV_SET_DCE, /* set the DCE pointer */ + X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */ + X11DRV_SYNC_PIXMAP, /* sync the dibsection to its pixmap */ + X11DRV_GET_VIDEORAM /* get videoram in kBytes */ };
/* retrieve the X display to use on a given DC */ @@ -158,6 +166,25 @@ static void WineD3D_ReleaseFakeGLContext } }
+/* returns videoRam in kBytes */ +static unsigned int IWineD3DImpl_GetVideoRam( HDC hdc ) +{ + unsigned int videoRam; + enum x11drv_escape_codes escape = X11DRV_GET_VIDEORAM; + + if (ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, + sizeof(videoRam), (LPSTR)&videoRam )) + { + TRACE("Using %u kByte\n", videoRam); + return videoRam; + } + else + { + TRACE("Using default of %u kByte\n", wined3d_settings.emulated_textureram); + return wined3d_settings.emulated_textureram; + } +} + /********************************************************** * IUnknown parts follows **********************************************************/ @@ -1589,7 +1616,7 @@ static HRESULT WINAPI IWineD3DImpl_Check static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DFORMAT AdapterFormat, DWORD Usage, WINED3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat) { IWineD3DImpl *This = (IWineD3DImpl *)iface; - TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), AdptFmt:(%u,%s), Use:(%u,%s,%s), ResTyp:(%x,%s), CheckFmt:(%u,%s))\n", + TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), AdptFmt:(%u,%s), Use:(%u,%s,%s), ResTyp:(%x,%s), CheckFmt:(%u,%s)) ", This, Adapter, DeviceType, debug_d3ddevicetype(DeviceType), @@ -2396,6 +2423,7 @@ static HRESULT WINAPI IWineD3DImpl_Crea /* Initialize other useful values */ object->adapterNo = Adapter; object->devType = DeviceType; + object->videoRam = IWineD3DImpl_GetVideoRam(GetDC(0));
TRACE("(%p) : Creating stateblock\n", This); /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index b859ade..8563bac 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -527,6 +527,7 @@ #define NEEDS_DI WINED3DDEVICE_CREATION_PARAMETERS createParms; UINT adapterNo; D3DDEVTYPE devType; + UINT videoRam; /* emulated videoram in kByte */
IWineD3DSwapChain **swapchains; uint NumberOfSwapChains; diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 200bec6..cc8439a 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -32,6 +32,7 @@ C_SRCS = \ scroll.c \ settings.c \ text.c \ + vendor_specific.c \ window.c \ winpos.c \ wintab.c \ diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index b3ee171..987826c 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -422,6 +422,13 @@ INT X11DRV_ExtEscape( X11DRV_PDEVICE *ph } return FALSE; break; + case X11DRV_GET_VIDEORAM: + if (out_count >= sizeof(unsigned int)) + { + *(unsigned int *)out_data = get_videoram(gdi_display); + return TRUE; + } + break; } } break; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 64b1166..f1f623b 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2648,6 +2648,16 @@ BOOL destroy_glxpixmap(XID glxpixmap) return TRUE; }
+const char *get_glversion() +{ + if (!has_opengl()) { + ERR("No libGL on this box - disabling OpenGL support !\n"); + return NULL; + } + + return WineGLInfo.glVersion; +} + /** * X11DRV_SwapBuffers * @@ -2863,4 +2873,11 @@ BOOL destroy_glxpixmap(XID glxpixmap) return FALSE; }
+const char *get_glversion() +{ + ERR_(opengl)("No OpenGL support compiled in.\n"); + return NULL; +} + + #endif /* defined(HAVE_OPENGL) */ diff --git a/dlls/winex11.drv/vendor_specific.c b/dlls/winex11.drv/vendor_specific.c new file mode 100644 index 0000000..350c659 --- /dev/null +++ b/dlls/winex11.drv/vendor_specific.c @@ -0,0 +1,242 @@ +/* + * X11DRV vendor specific Xserver extensions + * + * Copyright 2006 Fabian Bieler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include "x11drv.h" +#include "wine/debug.h" + +#include <X11/Xlibint.h> + +WINE_DEFAULT_DEBUG_CHANNEL(x11drv); + +/* from "NVCtrl.h" */ +#define NV_CTRL_VIDEO_RAM 6 + +/* from "nv_control.h" */ +#define NV_CONTROL_NAME "NV-CONTROL" +#define NV_CONTROL_EVENTS 1 +typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; + CARD32 display_mask B32; + CARD32 attribute B32; +} xnvCtrlQueryAttributeReq; +#define sz_xnvCtrlQueryAttributeReq sizeof(xnvCtrlQueryAttributeReq) +typedef struct { + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + INT32 value B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlQueryAttributeReply; +//#define sz_xnvCtrlQueryAttributeReply 32 +#define X_nvCtrlQueryAttribute 2 + +/* from "R200_extensions.h" "atiddx_extensions.h" respectively */ +#define ATIFGL_EXTENSION_NAME "ATIFGLEXTENSION" +#define ATIFGL_EXTENSION_EVENTS 0 +typedef struct _FGLGetDriverData { + CARD8 reqType; + CARD8 fireglReqType; + CARD16 length B16; + CARD32 screen B32; + CARD16 size B16; + CARD16 pad1; +} xFGLGetDriverDataReq; +#define sz_xFGLGetDriverDataReq sizeof(xFGLGetDriverDataReq) +typedef union { +struct { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD8 majorVersion; + CARD8 minorVersion; + CARD8 patchlevel B16; + CARD8 BIOSVersionMajor; + CARD8 BIOSVersionMinor; + CARD8 HasSecondary; + CARD16 pad3 B16; + CARD16 usBoardType B16; + CARD16 usChipType B16; + CARD16 usVideoRam B16; + CARD8 ATiRevID; + CARD8 AGPTransferMode; + CARD32 AGPCapPtr; + CARD32 AGPStatus; + CARD32 AGPCommand; + CARD32 ulGamma1 B32; + CARD32 ulGamma2 B32; + CARD32 ulDriverType B32; + CARD32 ulDesktopSetup B32; + CARD32 ulPrimary B32; +} v0; +struct { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD8 majorVersion; + CARD8 minorVersion; + CARD8 patchlevel B16; + CARD8 BIOSVersionMajor; + CARD8 BIOSVersionMinor; + CARD8 HasSecondary; + CARD16 pad3 B16; + CARD16 usBoardType B16; + CARD16 usChipType B16; + CARD16 usVideoRam B16; + CARD8 sATiRevID[17]; + CARD8 AGPTransferMode; + CARD32 AGPCapPtr; + CARD32 AGPStatus; + CARD32 AGPCommand; + CARD32 ulGamma1 B32; + CARD32 ulGamma2 B32; + CARD32 ulDriverType B32; + CARD32 ulDesktopSetup B32; + CARD32 ulPrimary B32; +} v3_7; +struct { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD8 majorVersion; + CARD8 minorVersion; + CARD8 patchlevel B16; + CARD8 BIOSVersionMajor; + CARD8 BIOSVersionMinor; + CARD8 HasSecondary; + CARD16 pad3 B16; + CARD16 usBoardType B16; + CARD16 usChipType B16; + CARD32 ulVideoRam B32; + CARD8 sATiRevID[17]; + CARD8 AGPTransferMode; + CARD32 AGPCapPtr; + CARD32 AGPStatus; + CARD32 AGPCommand; + CARD32 ulGamma1 B32; + CARD32 ulGamma2 B32; + CARD32 ulDriverType B32; + CARD32 ulDesktopSetup B32; + CARD32 ulPrimary B32; + CARD8 sBoardName[96]; +} v8_24; +} xFGLGetDriverDataReply; +#define X_FGLGetDriverData 0 + +unsigned int get_videoram(Display *dpy) +{ + int major_opcode, first_event, first_error; + unsigned int vram=0; + + TRACE("Probing videoram...\n"); + + /* Try the NV-CONTROL x-server extension: */ + if(XQueryExtension(dpy, NV_CONTROL_NAME, &major_opcode, &first_event, &first_error)) { + xnvCtrlQueryAttributeReply rep; + xnvCtrlQueryAttributeReq *req; + + wine_tsx11_lock(); + GetReq(nvCtrlQueryAttribute, req); + req->reqType = major_opcode; + req->nvReqType = X_nvCtrlQueryAttribute; + req->screen = DefaultScreen(dpy); + req->display_mask = 0; + req->attribute = NV_CTRL_VIDEO_RAM; + if(_XReply(dpy, (xReply *)&rep, 0, xTrue)) { + if(rep.flags) { + vram=rep.value; + TRACE("Got %u kByte from NV-CONTROL\n", vram); + } + } + wine_tsx11_unlock(); + SyncHandle(); + } + + /* Try the ATIFGLEXTENSION x-server extension: */ + if(XQueryExtension(dpy, ATIFGL_EXTENSION_NAME, &major_opcode, &first_event, &first_error)) { + xFGLGetDriverDataReq *req; + xFGLGetDriverDataReply rep; + + char *v; + unsigned short version; + int size; + + /* This extension was altered a few times, so we need to get the driver version. + * ATI OpenGL version strings are of the form + * "<OGLmajor>.<OGLminor>.<OGLpatchlevel> ([XFree86-version-]<DRIVERmajor>.<DRIVERminor>.<DRIVERpatchlevel>)" */ + v=(char *)get_glversion(); + v=strchr(v, '('); + if(!v) { + ERR("Failed to parse ATI OpenGL version string '%s'", get_glversion()); + } + else + { + v=max(strchr(v, '-'),v); + if(*v)v++; + version=strtol(v, &v, 10)<<8; + if(*v)v++; + version+=strtol(v, NULL, 10); + if(version<0x0307) + size=(sizeof(rep.v0) - 32) >> 2; + else if(version<0x0818) + size=(sizeof(rep.v3_7) - 32) >> 2; + else + size=(sizeof(rep.v8_24) - 32) >> 2; + TRACE("Found ATI driver version %hhu.%hhu\n", (version&0xff00)>>8, version&0x00ff); + + wine_tsx11_lock(); + GetReq(FGLGetDriverData, req); + req->reqType = major_opcode; + req->fireglReqType = X_FGLGetDriverData; + req->screen = DefaultScreen(dpy); + if(_XReply(dpy, (xReply *)&rep, size, xTrue)) + { + if(version<0x0307) { + if(rep.v0.usVideoRam==0x200 || rep.v0.usVideoRam==0x400 || rep.v0.usVideoRam==0x800 || rep.v0.usVideoRam==0x1000) + vram=rep.v0.usVideoRam<<6; + } + else if(version<0x0818) { + if(rep.v3_7.usVideoRam==0x200 || rep.v3_7.usVideoRam==0x400 || rep.v3_7.usVideoRam==0x800 || rep.v3_7.usVideoRam==0x1000) + vram=rep.v3_7.usVideoRam<<6; + } + else { + vram=rep.v8_24.ulVideoRam; + } + } + TRACE("Got %u kByte from ATIFGLEXTENSION\n", vram); + wine_tsx11_unlock(); + SyncHandle(); + } + } + + return vram; +} diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a4eb516..5fb918a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -271,6 +271,9 @@ extern void X11DRV_XRender_UpdateDrawabl extern XVisualInfo *X11DRV_setup_opengl_visual(Display *display); extern Drawable get_glxdrawable(X11DRV_PDEVICE *physDev); extern BOOL destroy_glxpixmap(XID glxpixmap); +extern const char *get_glversion(); + +extern unsigned int get_videoram(Display *dpy);
/* XIM support */ extern XIC X11DRV_CreateIC(XIM xim, Display *display, Window win); @@ -474,7 +477,8 @@ enum x11drv_escape_codes X11DRV_GET_DCE, /* get the DCE pointer */ X11DRV_SET_DCE, /* set the DCE pointer */ X11DRV_GET_GLX_DRAWABLE, /* get current glx drawable for a DC */ - X11DRV_SYNC_PIXMAP /* sync the dibsection to its pixmap */ + X11DRV_SYNC_PIXMAP, /* sync the dibsection to its pixmap */ + X11DRV_GET_VIDEORAM /* get videoram in kBytes */ };
struct x11drv_escape_set_drawable