Probing videoram using ATIFGLEXTENSION

Fabian Bieler der.fabe at gmx.net
Thu Oct 5 18:05:43 CDT 2006


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
-------------- next part --------------
From c1b2f368aa4580faef68cc0eaff0c5387e3eb8bf Mon Sep 17 00:00:00 2001
From: Fabian Bieler <der.fabe at 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
-- 
1.4.1.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: getvram.tar.gz
Type: application/x-tgz
Size: 2018 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20061006/32346707/getvram.tar-0001.bin


More information about the wine-devel mailing list