diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2013-01-15 09:07:38 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2013-01-15 09:07:38 -0800 |
commit | 14d4490c83116c3b18d9ce51270403057c5bcee7 (patch) | |
tree | 974a85b42b6ad33a9b692815e604a60695854b33 | |
parent | 88f50388a0866128d4192196a14267916d1ea68f (diff) |
313.18313.18
27 files changed, 1709 insertions, 159 deletions
diff --git a/doc/version.mk b/doc/version.mk index f91d9f6..0203028 100644 --- a/doc/version.mk +++ b/doc/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 313.09 +NVIDIA_VERSION = 313.18 diff --git a/samples/Makefile b/samples/Makefile index ac7fb69..ee8777b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -70,7 +70,7 @@ SAMPLE_SOURCES += nv-control-targets.c SAMPLE_SOURCES += nv-control-framelock.c SAMPLE_SOURCES += nv-control-gvi.c SAMPLE_SOURCES += nv-control-3dvisionpro.c - +SAMPLE_SOURCES += nv-control-warpblend.c ############################################################################## # build rules diff --git a/samples/nv-control-warpblend.c b/samples/nv-control-warpblend.c new file mode 100644 index 0000000..d15c956 --- /dev/null +++ b/samples/nv-control-warpblend.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nv-control-warpblend.h" + +typedef struct __attribute__((packed)) { + float x, y; +} vertex2f; + +typedef struct __attribute__((packed)) { + vertex2f pos; + vertex2f tex; + vertex2f tex2; +} vertexDataRec; + +static inline float transformPoint(vertex2f *vec) +{ + float w, oneOverW; + float x_in, y_in; + + // Sample projection matrix generated from a trapezoid projection + static const float mat[3][3] = + { + { 0.153978257544863,-0.097906833257365,0.19921875 }, + { -0.227317623368679,0.222788944798964,0.25 }, + { -0.585236541598693,-0.135471643796181,1 } + }; + + x_in = vec->x; + y_in = vec->y; + + vec->x = x_in * mat[0][0] + y_in * mat[0][1] + mat[0][2]; + vec->y = x_in * mat[1][0] + y_in * mat[1][1] + mat[1][2]; + w = x_in * mat[2][0] + y_in * mat[2][1] + mat[2][2]; + + oneOverW = 1.0 / w; + + vec->x *= oneOverW; + vec->y *= oneOverW; + + return oneOverW; +} + +int main(int ac, char **av) +{ + Display *xDpy = XOpenDisplay(NULL); + int screenId; + GC gc; + XGCValues values; + Pixmap blendPixmap; + vertexDataRec warpData[6]; + int nvDpyId; + + if (!xDpy) { + fprintf (stderr, "Could not open X Display %s!\n", XDisplayName(NULL)); + return 1; + } + + screenId = XDefaultScreen(xDpy); + + if (ac != 2) { + fprintf (stderr, "Usage: ./nv-control-warpblend nvDpyId\n"); + fprintf (stderr, "See 'nvidia-settings -q CurrentMetaMode' for currently connected DPYs.\n"); + return 1; + } + + nvDpyId = atoi(av[1]); + + // Start with two screen-aligned triangles, and warp them using the sample + // keystone matrix in transformPoint. Make sure we save W for correct + // perspective and pass it through as the last texture coordinate component. + warpData[0].pos.x = 0.0f; + warpData[0].pos.y = 0.0f; + warpData[0].tex.x = 0.0f; + warpData[0].tex.y = 0.0f; + warpData[0].tex2.x = 0.0f; + warpData[0].tex2.y = transformPoint(&warpData[0].pos); + + warpData[1].pos.x = 1.0f; + warpData[1].pos.y = 0.0f; + warpData[1].tex.x = 1.0f; + warpData[1].tex.y = 0.0f; + warpData[1].tex2.x = 0.0f; + warpData[1].tex2.y = transformPoint(&warpData[1].pos); + + warpData[2].pos.x = 0.0f; + warpData[2].pos.y = 1.0f; + warpData[2].tex.x = 0.0f; + warpData[2].tex.y = 1.0f; + warpData[2].tex2.x = 0.0f; + warpData[2].tex2.y = transformPoint(&warpData[2].pos); + + warpData[3].pos.x = 1.0f; + warpData[3].pos.y = 0.0f; + warpData[3].tex.x = 1.0f; + warpData[3].tex.y = 0.0f; + warpData[3].tex2.x = 0.0f; + warpData[3].tex2.y = transformPoint(&warpData[3].pos); + + warpData[4].pos.x = 1.0f; + warpData[4].pos.y = 1.0f; + warpData[4].tex.x = 1.0f; + warpData[4].tex.y = 1.0f; + warpData[4].tex2.x = 0.0f; + warpData[4].tex2.y = transformPoint(&warpData[4].pos); + + warpData[5].pos.x = 0.0f; + warpData[5].pos.y = 1.0f; + warpData[5].tex.x = 0.0f; + warpData[5].tex.y = 1.0f; + warpData[5].tex2.x = 0.0f; + warpData[5].tex2.y = transformPoint(&warpData[5].pos); + + // Prime the random number generator, since the helper functions need it. + srand(time(NULL)); + + // Apply our transformed warp data to the chosen display. + XNVCTRLSetScanoutWarping(xDpy, + screenId, + nvDpyId, + NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLES_XYUVRQ, + 6, // 6 vertices for two triangles + (float *)warpData); + + // Create a sample blending pixmap; let's make it solid white with a grey + // border and rely on upscaling with filtering to feather the edges. + + // Start with a 32x32 pixmap. + blendPixmap = XCreatePixmap(xDpy, RootWindow(xDpy, screenId), 32, 32, DefaultDepth(xDpy, screenId)); + + values.foreground = 0x77777777; + gc = XCreateGC(xDpy, blendPixmap, GCForeground, &values); + + // Fill it fully with grey. + XFillRectangle(xDpy, blendPixmap, gc, 0, 0, 32, 32); + + values.foreground = 0xffffffff; + XChangeGC(xDpy, gc, GCForeground, &values); + + // Fill everything but a one-pixel border with white. + XFillRectangle(xDpy, blendPixmap, gc, 1, 1, 30, 30); + + // Apply it to the display. blendAfterWarp is FALSE, so the edges will be + // blended in warped space. + XNVCTRLSetScanoutIntensity(xDpy, + screenId, + nvDpyId, + blendPixmap, + False); + + return 0; +} diff --git a/samples/nv-control-warpblend.h b/samples/nv-control-warpblend.h new file mode 100644 index 0000000..36d36dc --- /dev/null +++ b/samples/nv-control-warpblend.h @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <ctype.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "NVCtrl.h" +#include "NVCtrlLib.h" + +/* + * The scanout composition pipeline provides infrastructure to: + * - Individually transform the output of each display device using a user- + * provided warping mesh, with perspective correction. + * - Perform per-pixel intensity and black level adjustment from two separate + * user-provided textures. This can be configured to apply before (desktop- + * space) or after (display-space) warping by setting the BlendOrder token + * to BlendAfterWarp or WarpAfterBlend. + * + * The composition equation is: + * Output = Input * blendTexture * (1 − offsetTexture) + offsetTexture + * + * The above functionality is exposed through binding Pixmaps to names through + * the XNVCTRLBindWarpPixmapName NV-CONTROL functionality, and passing these + * bound names to the "WarpMesh", "BlendTexture" and "OffsetTexture" attributes + * of the desired display in a MetaMode. + * + * The texture coordinates of the warping mesh indicate where to source from + * the desktop in normalized ViewPortIn space, meaning that 0,0 and 1,1 map to + * boundaries of the area that would otherwise be displayed if warping was + * disabled. Coordinates outside these boundaries are accepted. + * + * Likewise, the mesh coordinates are in normalized ViewPortOut space, 0,0 and + * 1,1 mapping to the boundaries of the visible region on the display device. + * + * Please also see the XNVCTRLBindWarpPixmapName documentation in NVCtrlLib.h. + * + * The below three wrappers are immediate interfaces to the same functionality. + * These functions will create Pixmaps to encapsulate the data provided to them, + * and leave them bound to the names generated from them, causing them to remain + * allocated for the lifetime of the server. This makes them ill-suited for use + * cases where the warp mesh data has to vary dynamically; accessing the + * XNVCTRLBindWarpPixmapName functionality directly is recommended in that case. + * + * Please make sure the standard random number generator is seeded with a call + * to srand() before using them. + * + * Refer to nv-control-warpblend.c for sample usage cases. + * + */ + +/* + * XNVCTRLSetScanoutWarping + * + * xDpy: valid X display connection + * screenId: X protocol screen number; typically 0 in "TwinView" or "Mosaic" + * nvDpyId: NV-CONTROL display target index; can be enumerated with the + * NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN request. + * warpDatatype: NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLESTRIP_XYUVRQ or + * NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLES_XYUVRQ. + * vertexCount: number of vertices in the passed data; must be a multiple of 3 + * if warpDataType is NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLES_XYUVRQ. + * warpData: array of floating-point values representing the warping mesh, + * with six components per vertice: + * - X, Y: position in normalized ViewPortOut space. + * - U, V: texture coordinate in normalized ViewPortIn space. + * - R: unused. + * - Q: perspective component for the position. + * If warpData is NULL, the WarpMesh attribute will be removed for + * the designated display device. + */ +static inline int +XNVCTRLSetScanoutWarping( + Display *xDpy, + int screenId, + int nvDpyId, + int warpDataType, + int vertexCount, + const float *warpData); + +/* + * XNVCTRLSetScanout[Intensity/Offset] + * + * xDpy: valid X display connection + * screenId: X protocol screen number; typically 0 in "TwinView" or "Mosaic" + * nvDpyId: NV-CONTROL display target index; can be enumerated with the + * NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN request. + * pixmap: XID naming a valid Pixmap to be used as Intensity/Offset data. + * The pixmap does not have any size restrictions and will be scaled + * to fit the ViewPortIn of the target display with filtering. + * If the pixmap has a depth of 8, it will be treated as a single + * color component replicated across all channels. + * blendAfterWarp: if True, sets BlendOrder to BlendAfterWarp to apply the + * composition in display-space; otherwise, it is applied in + * desktop-space before any warping. + */ +static inline int +XNVCTRLSetScanoutIntensity( + Display *xDpy, + int screenId, + int nvDpyId, + Pixmap intensityPixmap, + Bool blendAfterWarp); + +static inline int +XNVCTRLSetScanoutOffset( + Display *xDpy, + int screenId, + int nvDpyId, + Pixmap offsetPixmap, + Bool blendAfterWarp); + +static inline int +RemoveAttributeFromDisplayOfCurrentMetaMode( + Display *xDpy, + int screenId, + int nvDpyId, + const char *attribute) +{ + char *pOldCurrentMetaMode = NULL; + char *pCurrentMetaMode = NULL; + char displayName[512]; + char *pDisplay; + char *pNextDisplay; + char *pAttributeList; + char *pTargetAttribute; + char *newMetaMode = NULL; + int error = 1; + int attributeLen; + + if (!attribute) { + goto cleanup; + } + + attributeLen = strlen(attribute); + + XNVCTRLQueryStringAttribute(xDpy, + screenId, + 0, // displayMask + NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, + &pOldCurrentMetaMode); + + // Discard the metadata from the beginning of the MetaMode. + pCurrentMetaMode = strstr(pOldCurrentMetaMode, "::"); + pCurrentMetaMode += 2; + + // Keep a settable copy of this, to which we'll mirror the changes we want. + newMetaMode = strdup(pCurrentMetaMode); + + if (!newMetaMode) { + goto cleanup; + } + + sprintf(displayName, "DPY-%i", nvDpyId); + + pDisplay = strstr(pCurrentMetaMode, displayName); + + if (!pDisplay) { + // Requested Dpy not found in this MetaMode. + goto cleanup; + } + + // If there's another DPY after the one we want, finish the string there to + // limit the scope of our search. + pNextDisplay = strstr(pDisplay + 1, "DPY-"); + + if (pNextDisplay) { + *pNextDisplay = '\0'; + } + + // If it has an attribute list, start looking from there; if not, fail. + if (!(pAttributeList = strstr(pDisplay, "{"))) { + goto cleanup; + } + + pTargetAttribute = strstr(pAttributeList, attribute); + + if (!pTargetAttribute) { + goto cleanup; + } + + // Found it; use the offset we found against our good copy of the mode to + // mangle the attribute name. + while (attributeLen--) { + newMetaMode[pTargetAttribute - pCurrentMetaMode + attributeLen] = 'z'; + } + + XNVCTRLSetStringAttribute(xDpy, + screenId, + 0, // displayMask + NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, + newMetaMode); + XSync(xDpy, 0); + + error = 0; + +cleanup: + + if (newMetaMode) { + free(newMetaMode); + } + + if (pOldCurrentMetaMode) { + free(pOldCurrentMetaMode); + } + + return error; +} + +// Given a comma-separated, list of A=B tokens this helper appends them to the +// to the attribute list of the currently-set MetaMode. +static inline int +AddAttributesToDisplayOfCurrentMetaMode( + Display *xDpy, + int screenId, + int nvDpyId, + const char *attributes) +{ + char *pOldCurrentMetaMode = NULL; + char *pCurrentMetaMode = NULL; + char displayName[512]; + char *pDisplay; + char *newMetaMode = NULL; + int error = 1; + + XNVCTRLQueryStringAttribute(xDpy, + screenId, + 0, // displayMask + NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, + &pOldCurrentMetaMode); + + // Discard the metadata from the beginning of the MetaMode. + pCurrentMetaMode = strstr(pOldCurrentMetaMode, "::"); + pCurrentMetaMode += 2; + + sprintf(displayName, "DPY-%i", nvDpyId); + + pDisplay = strstr(pCurrentMetaMode, displayName); + + if (pDisplay) { + int foundBeginAttr = 0; + char newAttribute[256]; + int endOfString = 1; + int neededLength; + + while (*(++pDisplay)) { + if (*pDisplay == '{') { + foundBeginAttr = 1; + } + if (*pDisplay == '}') { + endOfString = 0; + break; + } + + if (*pDisplay == ',' && !foundBeginAttr) { + endOfString = 0; + break; + } + } + + if (!endOfString) { + *pDisplay = 0; + pDisplay++; + } + + if (endOfString) { + // no attributes, no mode after + sprintf(newAttribute, " {%s}", attributes); + } + if (foundBeginAttr) { + // pDisplay had to be at the }, append an attribute and add the } back + sprintf(newAttribute, ", %s}", attributes); + } else { + // No attributes for this Dpy, we need to add them and restore the , + sprintf(newAttribute, " {%s},", attributes); + } + + neededLength = strlen(pCurrentMetaMode) + + strlen(newAttribute) + + strlen(pDisplay); + + // Add potential null-terminators for each of the three components. + newMetaMode = malloc(neededLength + 3); + + if (!newMetaMode) { + goto cleanup; + } + + // Put it back together with the new stuff in the middle + sprintf(newMetaMode, "%s%s%s", + pCurrentMetaMode, + newAttribute, + pDisplay); + } else { + // Requested Dpy not found in this MetaMode. + goto cleanup; + } + + XNVCTRLSetStringAttribute(xDpy, + screenId, + 0, // displayMask + NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, + newMetaMode); + XSync(xDpy, 0); + + error = 0; + +cleanup: + + if (newMetaMode) { + free(newMetaMode); + } + + if (pOldCurrentMetaMode) { + free(pOldCurrentMetaMode); + } + + return error; +} + +// This creates a copy of a given target Pixmap. +static inline Pixmap +ClonePixmap( + Display *xDpy, + int screenId, + Pixmap targetPixmap) +{ + Pixmap newPixmap = None; + GC gc; + unsigned int width, height, depth; + // unneeded stuff below + Window parent; + int x, y; + unsigned int borderWidth; + + XGetGeometry(xDpy, targetPixmap, &parent, &x, &y, + &width, &height, &borderWidth, &depth); + + newPixmap = XCreatePixmap(xDpy, RootWindow(xDpy, screenId), + width, height, depth); + + if (newPixmap == None) { + return None; + } + + gc = XCreateGC(xDpy, newPixmap, 0, NULL); + + XCopyArea(xDpy, targetPixmap, newPixmap, gc, 0, 0, width, height, 0, 0); + + XFreeGC(xDpy, gc); + + return newPixmap; +} + +static inline int +SetPixmapDataToAttribute( + Display *xDpy, + int screenId, + int nvDpyId, + Pixmap pixmap, + Bool blendAfterWarp, + const char* attributeName) +{ + Bool ret = False; + char tempName[256]; + char newAttributes[256]; + + // Disable the attribute on that DPY + if (pixmap == None) { + return RemoveAttributeFromDisplayOfCurrentMetaMode(xDpy, + screenId, + nvDpyId, + attributeName); + } + + // Get our own copy of the immediate contents of this pixmap. + pixmap = ClonePixmap(xDpy, screenId, pixmap); + + if (pixmap == None) { + return 1; + } + + // Generate a throwaway random name to bind it to. + sprintf(tempName, "%d", rand()); + + if (blendAfterWarp) { + sprintf(newAttributes, "%s=%s, BlendOrder=BlendAfterWarp", + attributeName, tempName); + } else { + sprintf(newAttributes, "%s=%s, BlendOrder=WarpAfterBlend", + attributeName, tempName); + } + + ret = XNVCTRLBindWarpPixmapName(xDpy, + screenId, + pixmap, + tempName, + NV_CTRL_WARP_DATA_TYPE_BLEND_OR_OFFSET_TEXTURE, + 0); // vertexCount, unneeded for blend/off. + + // Removes the ClonePixmap() reference, but the name above still holds one. + XFreePixmap(xDpy, pixmap); + + if (!ret) { + return 1; + } + + if (AddAttributesToDisplayOfCurrentMetaMode(xDpy, screenId, nvDpyId, + newAttributes)) { + return 1; + } + + XSync(xDpy, 0); + + return 0; +} + +static inline int +XNVCTRLSetScanoutWarping( + Display *xDpy, + int screenId, + int nvDpyId, + int warpDataType, + int vertexCount, + const float *warpData) +{ + Pixmap pTempPix = 0; + int neededSize; + int rowSize; + int neededRows; + Bool ret = False; + XImage *pTempImage = NULL; + GC pGC = NULL; + char *paddedBuffer = NULL; + int error = 1; + char tempName[256]; + char newAttributes[256]; + + // Disable warping on that DPY + if (warpData == NULL) { + return RemoveAttributeFromDisplayOfCurrentMetaMode(xDpy, + screenId, + nvDpyId, + "WarpMesh"); + } + + // Generate a throwaway random name to bind the data we're going to upload. + sprintf(tempName, "%d", rand()); + + if (!xDpy || !vertexCount || !warpData) { + goto cleanup; + } + + // Let's use a 1024-wide Pixmap always; figure out how many rows we need. + neededSize = vertexCount * sizeof(float) * 6; + rowSize = 1024 * 4; + neededRows = (neededSize + (rowSize - 1)) / rowSize; + + // The spec mandates depth 32 for this type of data. + pTempPix = XCreatePixmap(xDpy, RootWindow(xDpy, screenId), + 1024, neededRows, 32); + + ret = XNVCTRLBindWarpPixmapName(xDpy, screenId, pTempPix, tempName, + warpDataType, vertexCount); + + if (!ret) { + goto cleanup; + } + + paddedBuffer = malloc(1024 * neededRows * 4); + + if (!paddedBuffer) { + goto cleanup; + } + + memcpy(paddedBuffer, warpData, neededSize); + + pTempImage = XCreateImage(xDpy, DefaultVisual(xDpy, screenId), 32, ZPixmap, + 0, paddedBuffer, 1024, neededRows, 32, 0); + + if (!pTempImage) { + goto cleanup; + } + + pGC = XCreateGC(xDpy, pTempPix, 0, NULL); + + XPutImage(xDpy, pTempPix, pGC, pTempImage, 0, 0, 0, 0, 1024, neededRows); + + // Data is now uploaded to named pixmap; set a mode with it + sprintf(newAttributes, "WarpMesh=%s", tempName); + + if (AddAttributesToDisplayOfCurrentMetaMode(xDpy, screenId, nvDpyId, newAttributes)) { + goto cleanup; + } + + error = 0; + +cleanup: + + if (pGC) { + XFreeGC(xDpy, pGC); + } + + if (pTempImage) { + XDestroyImage(pTempImage); + paddedBuffer = NULL; + } + + if (paddedBuffer) { + free(paddedBuffer); + } + + // The bound name still holds a reference to the Pixmap. + if (pTempPix) { + XFreePixmap(xDpy, pTempPix); + } + + XSync(xDpy, 0); + + return error; +} + +static inline int +XNVCTRLSetScanoutIntensity( + Display *xDpy, + int screenId, + int nvDpyId, + Pixmap intensityPixmap, + Bool blendAfterWarp) +{ + return SetPixmapDataToAttribute(xDpy, screenId, nvDpyId, intensityPixmap, + blendAfterWarp, "BlendTexture"); +} + +static inline int +XNVCTRLSetScanoutOffset( + Display *xDpy, + int screenId, + int nvDpyId, + Pixmap offsetPixmap, + Bool blendAfterWarp) +{ + return SetPixmapDataToAttribute(xDpy, screenId, nvDpyId, offsetPixmap, + blendAfterWarp, "OffsetTexture"); +} diff --git a/samples/src.mk b/samples/src.mk index 8bc8558..35743e8 100644 --- a/samples/src.mk +++ b/samples/src.mk @@ -13,6 +13,8 @@ SAMPLES_EXTRA_DIST += nv-control-events.c SAMPLES_EXTRA_DIST += nv-control-gvi.c SAMPLES_EXTRA_DIST += nv-control-targets.c SAMPLES_EXTRA_DIST += nv-control-framelock.c +SAMPLES_EXTRA_DIST += nv-control-warpblend.c +SAMPLES_EXTRA_DIST += nv-control-warpblend.h SAMPLES_EXTRA_DIST += nv-control-screen.h SAMPLES_EXTRA_DIST += src.mk diff --git a/samples/version.mk b/samples/version.mk index f91d9f6..0203028 100644 --- a/samples/version.mk +++ b/samples/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 313.09 +NVIDIA_VERSION = 313.18 diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.c b/src/gtk+-2.x/ctkdisplayconfig-utils.c index b2f1901..f4df85f 100644 --- a/src/gtk+-2.x/ctkdisplayconfig-utils.c +++ b/src/gtk+-2.x/ctkdisplayconfig-utils.c @@ -1069,31 +1069,71 @@ static gchar *display_pick_config_name(nvDisplayPtr display, int be_generic) * * A best match is: * - * - The modelines are the same. * - The modelines match in width & height. + * - Then, the modelines match the ViewPortIn. + * - Then, the modelines match the ViewPortOut. * **/ int display_find_closest_mode_matching_modeline(nvDisplayPtr display, nvModeLinePtr modeline) { - nvModePtr mode; + const int targetWidth = modeline->data.hdisplay; + const int targetHeight = modeline->data.vdisplay; + + nvModePtr mode, best_mode = NULL; int mode_idx; - int match_idx = -1; + int best_idx = -1; mode_idx = 0; for (mode = display->modes; mode; mode = mode->next) { if (!mode->modeline) { continue; + } else if (mode->modeline->data.hdisplay == targetWidth && + mode->modeline->data.vdisplay == targetHeight) { + nvModePtr tmp_mode = mode; + int tmp_idx = mode_idx; + + /* We already have a match. Let's figure out if the + * currently considered mode is the closer to what we + * want. + */ + if (best_mode) { + Bool current_match_vpin = + (mode->viewPortIn[W] == targetWidth && + mode->viewPortIn[H] == targetHeight); + Bool best_match_vpin = + (best_mode->viewPortIn[W] == targetWidth && + best_mode->viewPortIn[H] == targetHeight); + Bool best_match_vpout = + (best_mode->viewPortOut[W] == targetWidth && + best_mode->viewPortOut[H] == targetHeight); + + /* Try to find reasons why we should prefer the + * previous match over the currently considered + * mode. + * + * We first check which one has a matching ViewPortIn + * If it's the case for both of them, then we compare + * ViewPortOut. + * + * If both are equally close, we keep our previous + * match. + */ + if ((!current_match_vpin && best_match_vpin) || + (current_match_vpin && best_match_vpin && + best_match_vpout)) { + tmp_mode = best_mode; + tmp_idx = best_idx; + } + /* Fallthrough. */ + } + best_mode = tmp_mode; + best_idx = tmp_idx; } - if (mode->modeline->data.vdisplay == modeline->data.vdisplay && - mode->modeline->data.hdisplay == modeline->data.hdisplay) { - match_idx = mode_idx; - } - if (mode->modeline == modeline) break; mode_idx++; } - return match_idx; + return best_idx; } /* display_find_closest_mode_matching_modeline() */ @@ -2652,6 +2692,7 @@ static void gpu_free(nvGpuPtr gpu) gpu_remove_displays(gpu); XFree(gpu->name); + XFree(gpu->flags_memory); g_free(gpu->pci_bus_id); free(gpu->gvo_mode_data); @@ -2808,6 +2849,8 @@ static Bool layout_add_gpu_from_server(nvLayoutPtr layout, unsigned int gpu_id, ReturnStatus ret; Display *dpy; nvGpuPtr gpu = NULL; + unsigned int *pData; + int len; /* Create the GPU structure */ @@ -2876,6 +2919,21 @@ static Bool layout_add_gpu_from_server(nvLayoutPtr layout, unsigned int gpu_id, gpu->allow_depth_30 = FALSE; } + ret = NvCtrlGetBinaryAttribute(gpu->handle, + 0, + NV_CTRL_BINARY_DATA_GPU_FLAGS, + (unsigned char **)&pData, + &len); + if (ret != NvCtrlSuccess) { + gpu->num_flags = 0; + gpu->flags_memory = NULL; + gpu->flags = NULL; + } else { + gpu->flags_memory = pData; + gpu->num_flags = pData[0]; + gpu->flags = &pData[1]; + } + /* Add the display devices to the GPU */ if (!gpu_add_displays_from_server(gpu, err_str)) { nv_warning_msg("Failed to add displays to GPU-%d '%s'.", @@ -3072,6 +3130,14 @@ static Bool layout_add_screen_from_server(nvLayoutPtr layout, screen->stereo_supported = FALSE; } + /* Query the current overlay state */ + ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_OVERLAY, &val); + if (ret == NvCtrlSuccess) { + screen->overlay = val; + } else { + screen->overlay = NV_CTRL_OVERLAY_OFF; + } + /* See if the screen supports dynamic twinview */ ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_DYNAMIC_TWINVIEW, &val); if (ret != NvCtrlSuccess) { diff --git a/src/gtk+-2.x/ctkdisplayconfig.c b/src/gtk+-2.x/ctkdisplayconfig.c index 6437e26..7d3bb6d 100644 --- a/src/gtk+-2.x/ctkdisplayconfig.c +++ b/src/gtk+-2.x/ctkdisplayconfig.c @@ -3055,6 +3055,46 @@ static void setup_display_stereo_dropdown(CtkDisplayConfig *ctk_object) +/** are_display_composition_transformations_allowed() **************** + * + * Checks whether display composition transformations are allowed + * given the list of GPU flags. + * + **/ + +static Bool are_display_composition_transformations_allowed(nvScreenPtr screen) +{ + int i; + Bool ret = TRUE; + + if (!screen || !screen->gpu) { + return FALSE; + } + + for (i = 0; i < screen->gpu->num_flags; i++) + { + switch (screen->gpu->flags[i]) { + case NV_CTRL_BINARY_DATA_GPU_FLAGS_STEREO_DISPLAY_TRANSFORM_EXCLUSIVE: + if (screen->stereo != NV_CTRL_STEREO_OFF) { + ret = FALSE; + } + break; + case NV_CTRL_BINARY_DATA_GPU_FLAGS_OVERLAY_DISPLAY_TRANSFORM_EXCLUSIVE: + if (screen->overlay != NV_CTRL_OVERLAY_OFF) { + ret = FALSE; + } + break; + default: + /* We don't care about other flags */ + break; + } + } + + return ret; +} + + + /** setup_display_rotation_dropdown() ******************************** * * Configures the display rotation dropdown to reflect the current @@ -3074,11 +3114,12 @@ static void setup_display_rotation_dropdown(CtkDisplayConfig *ctk_object) } gtk_widget_show(ctk_object->box_display_orientation); - if (!display->cur_mode || !display->cur_mode->modeline) { - gtk_widget_set_sensitive(ctk_object->box_display_orientation, FALSE); + if (!display->cur_mode || !display->cur_mode->modeline || + !are_display_composition_transformations_allowed(display->screen)) { + gtk_widget_set_sensitive(ctk_object->mnu_display_rotation, FALSE); return; } - gtk_widget_set_sensitive(ctk_object->box_display_orientation, TRUE); + gtk_widget_set_sensitive(ctk_object->mnu_display_rotation, TRUE); /* Set the selected rotation */ g_signal_handlers_block_by_func @@ -3132,11 +3173,12 @@ static void setup_display_reflection_dropdown(CtkDisplayConfig *ctk_object) } gtk_widget_show(ctk_object->box_display_orientation); - if (!display->cur_mode || !display->cur_mode->modeline) { - gtk_widget_set_sensitive(ctk_object->box_display_orientation, FALSE); + if (!display->cur_mode || !display->cur_mode->modeline || + !are_display_composition_transformations_allowed(display->screen)) { + gtk_widget_set_sensitive(ctk_object->mnu_display_reflection, FALSE); return; } - gtk_widget_set_sensitive(ctk_object->box_display_orientation, TRUE); + gtk_widget_set_sensitive(ctk_object->mnu_display_reflection, TRUE); /* Set the selected reflection */ g_signal_handlers_block_by_func @@ -6457,7 +6499,8 @@ static gboolean do_display_confirm_countdown(gpointer data) **/ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, - nvScreenPtr screen) + nvScreenPtr screen, + const char *cur_metamode_str) { ReturnStatus ret; gint result; @@ -6470,6 +6513,7 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, GtkWidget *dlg; GtkWidget *parent; gchar *msg; + Bool modified_current_metamode; if (!screen->handle || !screen->cur_metamode) goto fail; @@ -6479,8 +6523,8 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, new_width = metamode->edim[W]; new_height = metamode->edim[H]; new_rate = metamode->id; - - + + /* Find the parent window for displaying dialogs */ parent = ctk_get_parent_window(GTK_WIDGET(ctk_object)); @@ -6500,16 +6544,33 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, } nv_info_msg(TAB, "Current mode (id: %d)", old_rate); - + nv_info_msg(TAB, "Current mode string: %s", cur_metamode_str); + /* Switch to the new mode */ - nv_info_msg(TAB, "Switching to mode: %dx%d (id: %d)...", - new_width, new_height, new_rate); + if (new_rate > 0 ) { + nv_info_msg(TAB, "Switching to mode: %dx%d (id: %d)...", + new_width, new_height, new_rate); + + ret = NvCtrlSetAttribute(screen->handle, + NV_CTRL_CURRENT_METAMODE_ID, + new_rate); + modified_current_metamode = FALSE; + } else { + nv_info_msg(TAB, "Modifying current MetaMode to: %s...", + metamode->string); + + ret = NvCtrlSetStringAttribute(screen->handle, + NV_CTRL_STRING_CURRENT_METAMODE, + metamode->string, + NULL); + if (ret == NvCtrlSuccess) { + metamode->id = old_rate; + } + modified_current_metamode = TRUE; + } - ret = NvCtrlSetDisplayAttributeWithReply(screen->handle, 0, - NV_CTRL_CURRENT_METAMODE_ID, - new_rate); if (ret != NvCtrlSuccess) { nv_warning_msg("Failed to set MetaMode (%d) '%s' " @@ -6606,12 +6667,28 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, case GTK_RESPONSE_REJECT: default: /* Fall back to previous settings */ - nv_info_msg(TAB, "Switching back to mode (id: %d)...", old_rate); + if (!modified_current_metamode) { + nv_info_msg(TAB, "Switching back to mode (id: %d)...", old_rate); + + ret = NvCtrlSetAttribute(screen->handle, + NV_CTRL_CURRENT_METAMODE_ID, + old_rate); + } else { + nv_info_msg(TAB, "Re-writing previous current MetaMode to: %s...", + cur_metamode_str); - ret = NvCtrlSetDisplayAttributeWithReply(screen->handle, 0, - NV_CTRL_CURRENT_METAMODE_ID, - old_rate); - /* Good luck! */ + ret = NvCtrlSetStringAttribute(screen->handle, + NV_CTRL_STRING_CURRENT_METAMODE, + cur_metamode_str, + NULL); + if (ret != NvCtrlSuccess) { + nv_warning_msg("Failed to re-write current MetaMode (%d) to " + "'%s' on X screen $d!", + old_rate, + cur_metamode_str, + NvCtrlGetTargetId(screen->handle)); + } + } goto fail; } @@ -6632,8 +6709,10 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, * **/ -static char *find_metamode_string_by_id(char *metamode_strs, int match_id) +static char *find_metamode_string_by_id(char *metamode_strs, int match_id, + int *match_idx) { + int idx = 0; char *m; for (m = metamode_strs; m && strlen(m); m += strlen(m) +1) { @@ -6641,9 +6720,13 @@ static char *find_metamode_string_by_id(char *metamode_strs, int match_id) if (str) { int id = atoi(str+3); if (id && (id == match_id)) { + if (match_idx) { + *match_idx = idx; + } return m; } } + idx++; } return NULL; @@ -6651,6 +6734,65 @@ static char *find_metamode_string_by_id(char *metamode_strs, int match_id) +/** add_cpl_metamode_to_X() ****************************************** + * + * Adds the given metamode to the given X screen. + * + **/ + +static Bool add_cpl_metamode_to_X(nvScreenPtr screen, nvMetaModePtr metamode, + int metamode_idx) +{ + ReturnStatus ret; + char *tokens; + + ret = NvCtrlStringOperation(screen->handle, 0, + NV_CTRL_STRING_OPERATION_ADD_METAMODE, + metamode->string, &tokens); + + /* Grab the metamode ID from the returned tokens */ + if ((ret != NvCtrlSuccess) || !tokens) { + nv_error_msg("Failed to add MetaMode '%s' to X for " + "screen %d (GPU:%s)", + metamode->string, + screen->scrnum, screen->gpu->name); + return FALSE; + } + + parse_token_value_pairs(tokens, apply_metamode_token, + metamode); + XFree(tokens); + + metamode->x_idx = metamode_idx; + + nv_info_msg(TAB, "Added MetaMode (# %d, ID: %d) > [%s]", + metamode_idx, + metamode->id, + metamode->string); + + return TRUE; +} + + + +/** stub_metamode_str() ********************************************** + * + * Stubs out a metamode string. + * + **/ + +static void stub_metamode_str(char *str) +{ + if (str) { + while (*str) { + *str = ' '; + str++; + } + } +} + + + /** preprocess_metamodes() ******************************************* * * Does preprocess work to the metamode strings: @@ -6659,20 +6801,23 @@ static char *find_metamode_string_by_id(char *metamode_strs, int match_id) * that will be used for creating the metamode list on the X * Server. * - * - Whites out each string in the metamode_strs list that should + * - Stubs out each string in the metamode_strs list that should * not be deleted (it has a matching metamode in "screen".) * * - Adds new metamodes to the X server screen that are specified - * in "screen". + * in "screen" but not found in metamode_strs. * **/ -static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs) +static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs, + char *cur_metamode_str, + int num_metamodes_in_X, + int cur_metamode_idx) { nvMetaModePtr metamode; ReturnStatus ret; char *str; - char *tokens; + char *tmp; int metamode_idx; @@ -6682,6 +6827,8 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs) /* Generate the metamode's string */ free(metamode->string); + metamode->id = -1; + metamode->x_idx = -1; metamode->string = screen_get_metamode_str(screen, metamode_idx, 0); if (!metamode->string) continue; @@ -6689,44 +6836,84 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs) ret = NvCtrlStringOperation(screen->handle, 0, NV_CTRL_STRING_OPERATION_PARSE_METAMODE, metamode->string, &str); - if (ret == NvCtrlSuccess) { - char *tmp; + if (ret != NvCtrlSuccess) { + /* XXX Something's wrong with the metamode, ignore it for now. */ + continue; + } - /* XXX Later, we'll ask X to parse this metamode on updates - * and already have an ID so we'll know already which metamodes - * need to be deleted/added/moved. - */ + /* XXX Later, we'll ask X to parse this metamode on updates + * and already have an ID so we'll know already which metamodes + * need to be deleted/added/moved. + */ - tmp = strstr(str, "id="); + tmp = strstr(str, "id="); + if (tmp) { + int id = atoi(tmp+3); + tmp = find_metamode_string_by_id(metamode_strs, id, + &(metamode->x_idx)); if (tmp) { - int id = atoi(tmp+3); - tmp = find_metamode_string_by_id(metamode_strs, id); - if (tmp) { - metamode->id = id; - while (*tmp) { - *tmp = ' '; - tmp++; - } - /* Process the next metamode */ - continue; - } + metamode->id = id; + + /* We matched a CPL metamode with an X metamode, so stub the + * metamode from the X list so we don't delete it later. + */ + stub_metamode_str(tmp); + + /* + nv_info_msg(TAB, "%3d - Matched MetaMode (ID:%3d, X idx:%3d) > [%s]", + metamode_idx, + metamode->id, + metamode->x_idx, + metamode->string); + */ + + /* Process the next metamode */ + continue; } } + /* If the CPL metamode did not match any of the metamodes in X, we + * should add it. Note, however, that since we have not yet gone + * through the whole list of CPL MetaModes (the currently active + * MetaMode in X may match a CPL MetaMode we have not yet encountered), + * we don't yet know if the current metamode should be modified via + * NV_CTRL_STRING_CURRENT_METAMODE, or added then swapped to, so ignore + * it for now and handle it once we've gone through all the CPL + * MetaModes. + */ + if (metamode == screen->cur_metamode) { + continue; + } + /* The metamode was not found, so add it to the X screen's list */ - tokens = NULL; - ret = NvCtrlStringOperation(screen->handle, 0, - NV_CTRL_STRING_OPERATION_ADD_METAMODE, - metamode->string, &tokens); + if (add_cpl_metamode_to_X(screen, metamode, num_metamodes_in_X)) { + num_metamodes_in_X++; + } + } - /* Grab the metamode ID from the returned tokens */ - if (ret == NvCtrlSuccess) { - if (tokens) { - parse_token_value_pairs(tokens, apply_metamode_token, - metamode); - free(tokens); + /* If the currently selected MetaMode in the CPL did not match any metamode + * in X, and the current active MetaMode (in X) was linked to another CPL + * MetaMode, then we will need to add the CPL's current MetaMode so we can + * switch to it later. + * + * Note: if a mode was matched above, then the current metamode pointer + * should now point to a stubbed out entry, and this is what we check for + * here. + */ + if ((screen->cur_metamode->id < 0)) { + const char *ctmp = parse_skip_whitespace(cur_metamode_str); + + if (!*ctmp) { + if (add_cpl_metamode_to_X(screen, screen->cur_metamode, + num_metamodes_in_X)) { + num_metamodes_in_X++; } - nv_info_msg(TAB, "Added > %s", metamode->string); + } else { + /* Current metamode will be overriden, so stub it here so that it + * does not get deleted later. + */ + stub_metamode_str(cur_metamode_str); + screen->cur_metamode->x_idx = cur_metamode_idx; } } @@ -6734,6 +6921,76 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs) +/** screen_move_metamode() ******************************************* + * + * Updates the X ordering of the given metamode so that it appears at + * 'metamode_idx'. + * + **/ + +static Bool screen_move_metamode(nvScreenPtr screen, nvMetaModePtr metamode, + int metamode_idx) +{ + char *update_str; + int len; + ReturnStatus ret; + + if (!metamode->string) { + goto fail; + } + + /* Append the index we want */ + len = 24 + strlen(metamode->string); + update_str = malloc(len); + snprintf(update_str, len, "index=%d :: %s", metamode_idx, + metamode->string); + + ret = NvCtrlSetStringAttribute(screen->handle, + NV_CTRL_STRING_MOVE_METAMODE, + update_str, NULL); + if (ret != NvCtrlSuccess) { + goto fail; + } + + nv_info_msg(TAB, "Moved MetaMode (id:%d from idx: %d to idx %d) > %s", + metamode->id, + metamode->x_idx, + metamode_idx, + metamode->string); + + /* We moved the metamode to position metamode_idx, so bump the + * index of all metamodes from the new position to the old one. + * This assumes that metamodes are always moved forward in the + * the list and not backwards. + */ + { + int from_idx = metamode_idx; // New position + int to_idx = metamode->x_idx; // Old position + nvMetaModePtr m; + + for (m = screen->metamodes; + m; + m = m->next) { + if ((m->x_idx >= from_idx) && + (m->x_idx < to_idx)) { + m->x_idx++; + } + } + /* Note the new location of the metamode */ + metamode->x_idx = metamode_idx; + } + return TRUE; + + fail: + nv_error_msg("Failed to move MetaMode (id:%d from idx: %d to idx %d) > %s", + metamode->id, + metamode->x_idx, + metamode_idx, + metamode->string ? metamode->string : "NULL"); + return FALSE; +} + + /** order_metamodes() ************************************************ * * Makes sure the metamodes are ordered properly by moving each @@ -6745,33 +7002,18 @@ static void order_metamodes(nvScreenPtr screen) { nvMetaModePtr metamode; int metamode_idx; - char *metamode_str; - char *update_str; - int len; - ReturnStatus ret; for (metamode = screen->metamodes, metamode_idx = 0; metamode; metamode = metamode->next, metamode_idx++) { - metamode_str = screen_get_metamode_str(screen, metamode_idx, - 0); - if (!metamode_str) continue; - - /* Append the index we want */ - len = 24 + strlen(metamode_str); - update_str = malloc(len); - snprintf(update_str, len, "index=%d :: %s", metamode_idx, - metamode_str); - - ret = NvCtrlSetStringAttribute(screen->handle, - NV_CTRL_STRING_MOVE_METAMODE, - update_str, NULL); - if (ret == NvCtrlSuccess) { - nv_info_msg(TAB, "Moved > %s", metamode_str); + /* MetaMode is already in correct spot */ + if (metamode_idx == metamode->x_idx) { + continue; } - free(metamode_str); + + screen_move_metamode(screen, metamode, metamode_idx); } } /* order_metamodes() */ @@ -6791,12 +7033,13 @@ static void postprocess_metamodes(nvScreenPtr screen, char *metamode_strs) char *metamode_str, *tmp; const char *str; ReturnStatus ret; + int idx; /* Delete metamodes that were not cleared out from the metamode_strs */ - for (metamode_str = metamode_strs; + for (metamode_str = metamode_strs, idx = 0; metamode_str && strlen(metamode_str); - metamode_str += strlen(metamode_str) +1) { + metamode_str += strlen(metamode_str) +1, idx++) { /* Skip tokens */ str = strstr(metamode_str, "::"); @@ -6811,7 +7054,20 @@ static void postprocess_metamodes(nvScreenPtr screen, char *metamode_strs) NV_CTRL_STRING_DELETE_METAMODE, tmp, NULL); if (ret == NvCtrlSuccess) { - nv_info_msg(TAB, "Removed > %s", str); + nvMetaModePtr metamode; + + nv_info_msg(TAB, "Removed MetaMode > %s", str); + + /* MetaModes after the one that was deleted will have + * moved up an index, so update the book keeping here. + */ + for (metamode = screen->metamodes; + metamode; + metamode = metamode->next) { + if (metamode->x_idx >= idx) { + metamode->x_idx--; + } + } } free(tmp); @@ -6834,8 +7090,13 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, nvScreenPtr screen) { char *metamode_strs = NULL; - char *cur_metamode_str = NULL; - const char *metamode_str; + char *cur_full_metamode_str = NULL; + char *cur_metamode_ptr = NULL; /* Pointer into metamode_strs */ + int cur_metamode_id; /* ID of current MetaMode on X screen */ + int cur_metamode_idx; + int num_metamodes_in_X; + char *str; + const char *cur_metamode_str; int len; int clear_apply = 0; /* Set if we should clear the apply button */ @@ -6862,7 +7123,7 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, * (postprocess) * - Delete any unused mode * - Move metamodes to the correct location - **/ + */ /* Get the list of the current metamodes */ @@ -6877,26 +7138,90 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, ret = NvCtrlGetStringAttribute(screen->handle, NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, - &cur_metamode_str); + &cur_full_metamode_str); + if (ret != NvCtrlSuccess) goto done; + + /* Get the current metamode index for the screen */ + + ret = NvCtrlGetAttribute(screen->handle, + NV_CTRL_CURRENT_METAMODE_ID, + &cur_metamode_id); if (ret != NvCtrlSuccess) goto done; /* Skip tokens */ - metamode_str = strstr(cur_metamode_str, "::"); - if (metamode_str) { - metamode_str = parse_skip_whitespace(metamode_str +2); + cur_metamode_str = strstr(cur_full_metamode_str, "::"); + if (cur_metamode_str) { + cur_metamode_str = parse_skip_whitespace(cur_metamode_str +2); } else { - metamode_str = cur_metamode_str; + cur_metamode_str = cur_full_metamode_str; + } + + /* Count the number of metamodes in X */ + num_metamodes_in_X = 0; + for (str = metamode_strs; + str && strlen(str); + str += strlen(str) +1) { + num_metamodes_in_X++; + } + + /* Find cur_metamode_str inside metamode_strs */ + cur_metamode_ptr = NULL; + cur_metamode_idx = 0; + for (str = metamode_strs; + str && strlen(str); + str += strlen(str) +1) { + const char *tmp; + + tmp = strstr(str, "::"); + if (!tmp) continue; + tmp = parse_skip_whitespace(tmp +2); + if (!tmp) continue; + + if (!strcasecmp(tmp, cur_metamode_str)) { + cur_metamode_ptr = str; + break; + } + cur_metamode_idx++; + } + + if (!cur_metamode_ptr) { + nv_error_msg("Failed to identify current MetaMode in X list of " + "MetaModes for screen %d (GPU:%s)", screen->scrnum, + screen->gpu->name); + return 1; } - /* Preprocess the new metamodes list */ + /* Add new metamodes and relate MetaModes from CPL to X */ - preprocess_metamodes(screen, metamode_strs); + preprocess_metamodes(screen, metamode_strs, cur_metamode_ptr, + num_metamodes_in_X, + cur_metamode_idx); - /* If we need to switch metamodes, do so now */ + /* Update the current metamode. + * + * At this point, the metamode we want to set as the current metamode should + * exist in the X server, or we will need to clobber the current X + * metamode with new data. + * + * - If the current CPL MetaMode is the same as the current X MetaMode, + * do nothing. + * + * - If the current CPL MetaMode is a different X MetaMode, switch to it. + * + * - If the current CPL MetaMode is not the same as the current X MetaMode. + * and both the CPL MetaMode is not some other X MetaMode, and the current + * X MetaMode is not some other CPL MetaMode, then we can modify the + * current X MetaMode to be the CPL MetaMode. + * + * - If the current CPL MetaMode is not the same as the current X MetaMode, + * and we matched the current X MetaMode to some other CPL MetaMode, then + * we should add the current CPL MetaMode to X and switch to it. + */ - if (strcmp(screen->cur_metamode->string, metamode_str)) { + if (screen->cur_metamode->id != cur_metamode_id) { - if (switch_to_current_metamode(ctk_object, screen)) { + if (switch_to_current_metamode(ctk_object, screen, + cur_metamode_str)) { ctk_config_statusbar_message(ctk_object->ctk_config, "Switched to MetaMode %dx%d.", @@ -6918,7 +7243,7 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, done: XFree(metamode_strs); - XFree(cur_metamode_str); + XFree(cur_full_metamode_str); return clear_apply; diff --git a/src/gtk+-2.x/ctkdisplaydevice.c b/src/gtk+-2.x/ctkdisplaydevice.c index 2249c11..31bce92 100644 --- a/src/gtk+-2.x/ctkdisplaydevice.c +++ b/src/gtk+-2.x/ctkdisplaydevice.c @@ -722,6 +722,7 @@ static gboolean update_refresh_rate(InfoEntry *entry) CtkDisplayDevice *ctk_object = entry->ctk_object; ReturnStatus ret; gint val; + gboolean hdmi3D; char *str; float fvalue; @@ -730,8 +731,18 @@ static gboolean update_refresh_rate(InfoEntry *entry) return FALSE; } + ret = NvCtrlGetAttribute(ctk_object->handle, NV_CTRL_DPY_HDMI_3D, &hdmi3D); + if (ret != NvCtrlSuccess) { + return FALSE; + } + fvalue = ((float)(val)) / 100.0f; - str = g_strdup_printf("%.2f Hz", fvalue); + + if (hdmi3D) { + fvalue /= 2; + } + + str = g_strdup_printf("%.2f Hz%s", fvalue, hdmi3D ? " (HDMI 3D)" : ""); gtk_label_set_text(GTK_LABEL(entry->txt), str); g_free(str); diff --git a/src/gtk+-2.x/ctkdisplaylayout.h b/src/gtk+-2.x/ctkdisplaylayout.h index b6e53c9..4bb68b3 100644 --- a/src/gtk+-2.x/ctkdisplaylayout.h +++ b/src/gtk+-2.x/ctkdisplaylayout.h @@ -244,6 +244,7 @@ typedef struct nvMetaModeRec { struct nvMetaModeRec *next; int id; /* Magic id */ + int x_idx; /* Used to re-order metamodes on apply */ MetaModeSource source; /* Source of the metamode */ Bool switchable; /* Can the metamode be accessed through Ctrl Alt +- */ @@ -283,6 +284,7 @@ typedef struct nvScreenRec { int depth; /* Depth of the screen */ int stereo; /* Stereo mode enabled on this screen */ + int overlay; /* Overlay enabled on this screen */ nvDisplayPtr displays; /* List of displays using this screen */ int num_displays; /* # of displays using this screen */ @@ -339,6 +341,10 @@ typedef struct nvGpuRec { GvoModeData *gvo_mode_data; /* Information about GVO modes available */ unsigned int num_gvo_modes; + unsigned int *flags_memory; /* Pointer to memory alloced for flags */ + unsigned int *flags; /* Array of flags queried from the X server */ + int num_flags; + nvDisplayPtr displays; /* Linked list of displays connected to GPU */ int num_displays; diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c index 6c77ec4..6238756 100644 --- a/src/gtk+-2.x/ctkevent.c +++ b/src/gtk+-2.x/ctkevent.c @@ -330,6 +330,9 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_SIGNAL(NV_CTRL_FRAMELOCK_DISPLAY_CONFIG); MAKE_SIGNAL(NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY); MAKE_SIGNAL(NV_CTRL_USED_DEDICATED_GPU_MEMORY); + MAKE_SIGNAL(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE); + MAKE_SIGNAL(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT); + MAKE_SIGNAL(NV_CTRL_DPY_HDMI_3D); #undef MAKE_SIGNAL /* @@ -339,7 +342,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) * knows about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_USED_DEDICATED_GPU_MEMORY +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_DPY_HDMI_3D #warning "There are attributes that do not emit signals!" #endif @@ -423,9 +426,10 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_METAMODES_VERSION_2); MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN); MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN); + MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_GPU_FLAGS); #undef MAKE_BINARY_SIGNAL -#if NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE != NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN +#if NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE != NV_CTRL_BINARY_DATA_GPU_FLAGS #warning "There are attributes that do not emit signals!" #endif diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c index 0496f13..39e6e95 100644 --- a/src/gtk+-2.x/ctkframelock.c +++ b/src/gtk+-2.x/ctkframelock.c @@ -181,6 +181,7 @@ struct _nvDisplayDataRec { /* Rate in milliHz */ guint rate_mHz; guint rate_precision; + gboolean hdmi3D; GtkWidget *stereo_label; GtkWidget *stereo_hbox; /* LED */ @@ -4020,7 +4021,13 @@ static void update_display_rate_txt(nvDisplayDataPtr data, data->rate_mHz = rate_mHz; fvalue = ((float)(data->rate_mHz)) / 1000.0f; - snprintf(str, 32, "%.*f Hz", precision, fvalue); + + if (data->hdmi3D) { + fvalue /= 2; + } + + snprintf(str, 32, "%.*f Hz%s", precision, fvalue, + data->hdmi3D ? " (Doubled for HDMI 3D)" : ""); gtk_label_set_text(GTK_LABEL(data->rate_text), str); } @@ -5171,6 +5178,7 @@ static void add_display_devices(CtkFramelock *ctk_framelock, while (display_mask) { int rate; int precision; + gboolean hdmi3D; if (display_mask & enabled_displays) { @@ -5223,6 +5231,12 @@ static void add_display_devices(CtkFramelock *ctk_framelock, /* Add display to GPU entry */ list_entry_add_child(gpu_entry, entry); + /* Determine if display is HDMI 3D */ + ret = NvCtrlGetDisplayAttribute(display_data->handle, + display_data->device_mask, + NV_CTRL_DPY_HDMI_3D, &hdmi3D); + + display_data->hdmi3D = hdmi3D; /* Refresh Rate */ ret = NvCtrlGetDisplayAttribute(display_data->handle, diff --git a/src/gtk+-2.x/ctkpowermizer.c b/src/gtk+-2.x/ctkpowermizer.c index da791ce..a25e7c7 100644 --- a/src/gtk+-2.x/ctkpowermizer.c +++ b/src/gtk+-2.x/ctkpowermizer.c @@ -41,6 +41,12 @@ static void powermizer_menu_changed(GtkOptionMenu*, gpointer); static void update_powermizer_menu_event(GtkObject *object, gpointer arg1, gpointer user_data); +static void dp_config_button_toggled(GtkWidget *, gpointer); +static void dp_set_config_status(CtkPowermizer *); +static void dp_update_config_status(CtkPowermizer *, gboolean); +static void dp_configuration_update_received(GtkObject *, gpointer, gpointer); +static void post_dp_configuration_update(CtkPowermizer *); +static void show_dp_toggle_warning_dlg(CtkPowermizer *ctk_powermizer); static const char *__adaptive_clock_help = "The Adaptive Clocking status describes if this feature " @@ -85,6 +91,13 @@ static const char *__powermizer_menu_help = "mode selected in nvidia-settings is what the system will be using; if two or " "more X servers are running, the behavior is undefined."; +static const char *__dp_configuration_button_help = +"CUDA - Double Precision lets you enable " +"increased double-precision calculations in CUDA applications. Available on " +"GPUs with the capability for increased double-precision performance." +" NOTE: Selecting a GPU reduces performance for non-CUDA applications, " +"including games. To increase game performance, disable this checkbox."; + GType ctk_powermizer_get_type(void) { static GType ctk_powermizer_type = 0; @@ -394,12 +407,14 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, CtkPowermizer *ctk_powermizer; GtkWidget *hbox, *hbox2, *vbox, *vbox2, *hsep, *table; GtkWidget *banner, *label, *menu, *menu_item; - ReturnStatus ret; + ReturnStatus ret, ret1; + gint attribute; gint val; gint row = 0; gchar *s = NULL; gint tmp; gboolean processor_clock_available = FALSE; + gboolean cuda_dp_ui = FALSE; /* make sure we have a handle */ @@ -695,6 +710,107 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, ctk_powermizer->powermizer_menu, FALSE, FALSE, 0); + /* + * check if CUDA - Double Precision Boost support available. + */ + + ret = NvCtrlGetAttribute(handle, + NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE, + &val); + if (ret == NvCtrlSuccess) { + attribute = NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE; + cuda_dp_ui = TRUE; + } else { + ret1 = NvCtrlGetAttribute(handle, + NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT, + &val); + if (ret1 == NvCtrlSuccess) { + attribute = NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT; + cuda_dp_ui = TRUE; + } + } + + if (cuda_dp_ui) { + ctk_powermizer->attribute = attribute; + ctk_powermizer->dp_toggle_warning_dlg_shown = FALSE; + + /* Query CUDA - Double Precision Boost Status */ + + dp_update_config_status(ctk_powermizer, val); + + /* CUDA - Double Precision Boost configuration settings */ + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("CUDA"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hsep, TRUE, TRUE, 5); + + hbox2 = gtk_hbox_new(FALSE, 0); + ctk_powermizer->configuration_button = + gtk_check_button_new_with_label("CUDA - Double precision"); + gtk_box_pack_start(GTK_BOX(hbox2), + ctk_powermizer->configuration_button, + FALSE, FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(hbox2), 0); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_powermizer->configuration_button), + ctk_powermizer->dp_enabled); + + /* Packing */ + + table = gtk_table_new(1, 1, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + gtk_table_attach(GTK_TABLE(table), hbox2, 0, 1, 0, 1, + GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + + if (attribute == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT) { + GtkWidget *separator; + + gtk_table_resize(GTK_TABLE(table), 1, 3); + /* V-bar */ + hbox2 = gtk_hbox_new(FALSE, 0); + separator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox2), separator, FALSE, FALSE, 0); + gtk_table_attach(GTK_TABLE(table), hbox2, 1, 2, 0, 1, + GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + + ctk_powermizer->status = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(ctk_powermizer->status), 0.0f, 0.5f); + hbox2 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox2), + ctk_powermizer->status, FALSE, FALSE, 0); + + gtk_table_attach(GTK_TABLE(table), hbox2, 2, 3, 0, 1, + GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + } + + ctk_config_set_tooltip(ctk_config, ctk_powermizer->configuration_button, + __dp_configuration_button_help); + g_signal_connect(G_OBJECT(ctk_powermizer->configuration_button), + "clicked", + G_CALLBACK(dp_config_button_toggled), + (gpointer) ctk_powermizer); + if (attribute == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE) { + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE), + G_CALLBACK(dp_configuration_update_received), + (gpointer) ctk_powermizer); + } else if (attribute == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT) { + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT), + G_CALLBACK(dp_configuration_update_received), + (gpointer) ctk_powermizer); + } + } + /* Updating the powermizer page */ update_powermizer_info(ctk_powermizer); @@ -785,6 +901,168 @@ static void powermizer_menu_changed(GtkOptionMenu *powermizer_menu, (gpointer) ctk_powermizer); } + + +static void show_dp_toggle_warning_dlg(CtkPowermizer *ctk_powermizer) +{ + GtkWidget *dlg, *parent; + + /* return early if message dialog already shown */ + if (ctk_powermizer->dp_toggle_warning_dlg_shown) { + return; + } + ctk_powermizer->dp_toggle_warning_dlg_shown = TRUE; + parent = ctk_get_parent_window(GTK_WIDGET(ctk_powermizer)); + + dlg = gtk_message_dialog_new (GTK_WINDOW(parent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + "Changes to the CUDA - Double precision " + "setting " + "require a system reboot before " + "taking effect."); + gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy (dlg); + +} /* show_dp_toggle_warning_dlg() */ + + + +/* + * post_dp_configuration_update() - this function updates status bar string. + */ + +static void post_dp_configuration_update(CtkPowermizer *ctk_powermizer) +{ + gboolean enabled = ctk_powermizer->dp_enabled; + + const char *conf_string = enabled ? "enabled" : "disabled"; + char message[128]; + + if (ctk_powermizer->attribute == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT) { + snprintf(message, sizeof(message), "CUDA - Double precision will " + "be %s after reboot.", + conf_string); + } else { + snprintf(message, sizeof(message), "CUDA - Double precision %s.", + conf_string); + } + + ctk_config_statusbar_message(ctk_powermizer->ctk_config, message); +} /* post_dp_configuration_update() */ + + + +/* + * dp_set_config_status() - set CUDA - Double Precision Boost configuration + * button status. + */ + +static void dp_set_config_status(CtkPowermizer *ctk_powermizer) +{ + GtkWidget *configuration_button = ctk_powermizer->configuration_button; + + g_signal_handlers_block_by_func(G_OBJECT(configuration_button), + G_CALLBACK(dp_config_button_toggled), + (gpointer) ctk_powermizer); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configuration_button), + ctk_powermizer->dp_enabled); + + g_signal_handlers_unblock_by_func(G_OBJECT(configuration_button), + G_CALLBACK(dp_config_button_toggled), + (gpointer) ctk_powermizer); +} /* dp_set_config_status() */ + + + +/* + * dp_update_config_status - get current CUDA - Double Precision Boost status. + */ + +static void dp_update_config_status(CtkPowermizer *ctk_powermizer, gboolean val) +{ + if ((ctk_powermizer->attribute == + NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE && + val == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE_DISABLED) || + (ctk_powermizer->attribute == + NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT && + val == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT_DISABLED)) { + ctk_powermizer->dp_enabled = FALSE; + } else { + ctk_powermizer->dp_enabled = TRUE; + } +} /* dp_update_config_status() */ + + + +/* + * dp_configuration_update_received() - this function is called when the + * NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE attribute is changed by another + * NV-CONTROL client. + */ + +static void dp_configuration_update_received(GtkObject *object, + gpointer arg1, gpointer user_data) +{ + CtkEventStruct *event_struct = (CtkEventStruct *) arg1; + CtkPowermizer *ctk_powermizer = CTK_POWERMIZER(user_data); + + ctk_powermizer->dp_enabled = event_struct->value; + + /* set CUDA - Double Precision Boost configuration buttion status */ + dp_set_config_status(ctk_powermizer); + + /* Update status bar message */ + post_dp_configuration_update(ctk_powermizer); +} /* dp_configuration_update_received() */ + + + +/* + * dp_config_button_toggled() - callback function for + * enable CUDA - Double Precision Boost checkbox. + */ + +static void dp_config_button_toggled(GtkWidget *widget, + gpointer user_data) +{ + gboolean enabled; + CtkPowermizer *ctk_powermizer = CTK_POWERMIZER(user_data); + ReturnStatus ret; + + enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + + /* show popup dialog when user first time click DP config */ + if (ctk_powermizer->attribute == NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT) { + show_dp_toggle_warning_dlg(ctk_powermizer); + } + + /* set the newly specified CUDA - Double Precision Boost value */ + ret = NvCtrlSetAttribute(ctk_powermizer->attribute_handle, + ctk_powermizer->attribute, + enabled); + if (ret != NvCtrlSuccess) { + ctk_config_statusbar_message(ctk_powermizer->ctk_config, + "Failed to set " + "CUDA - Double precision " + "configuration!"); + return; + } + + ctk_powermizer->dp_enabled = enabled; + dp_set_config_status(ctk_powermizer); + if (ctk_powermizer->status) { + gtk_label_set_text(GTK_LABEL(ctk_powermizer->status), + "pending reboot"); + } + + /* Update status bar message */ + post_dp_configuration_update(ctk_powermizer); +} /* dp_config_button_toggled() */ + + + GtkTextBuffer *ctk_powermizer_create_help(GtkTextTagTable *table, CtkPowermizer *ctk_powermizer) { @@ -832,6 +1110,12 @@ GtkTextBuffer *ctk_powermizer_create_help(GtkTextTagTable *table, ctk_help_heading(b, &i, "PowerMizer Settings"); ctk_help_para(b, &i, __powermizer_menu_help); + + if (ctk_powermizer->configuration_button) { + ctk_help_heading(b, &i, "CUDA - Double precision"); + ctk_help_para(b, &i, __dp_configuration_button_help); + } + ctk_help_finish(b); return b; diff --git a/src/gtk+-2.x/ctkpowermizer.h b/src/gtk+-2.x/ctkpowermizer.h index 09fd2ca..adb179f 100644 --- a/src/gtk+-2.x/ctkpowermizer.h +++ b/src/gtk+-2.x/ctkpowermizer.h @@ -64,6 +64,13 @@ struct _CtkPowermizer GtkWidget *powermizer_menu; GtkWidget *box_powermizer_menu; + GtkWidget *configuration_button; + gboolean dp_enabled; + gboolean dp_toggle_warning_dlg_shown; + gint attribute; + gchar *dp_enabled_string; + GtkWidget *status; + GtkWidget *link_width; GtkWidget *link_speed; gboolean pcie_gen_queriable; diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c index c3dd54b..8a6c418 100644 --- a/src/gtk+-2.x/ctkwindow.c +++ b/src/gtk+-2.x/ctkwindow.c @@ -69,6 +69,7 @@ #include "msg.h" #include "common-utils.h" +#include "query-assign.h" /* column enumeration */ @@ -1417,15 +1418,16 @@ static void add_display_devices(CtkWindow *ctk_window, GtkTreeIter *iter, CtkEvent *ctk_event; CtrlHandles *handles = ctk_window->ctk_config->pCtrlHandles; - /* + /* * Get the ctrl handle that was passed into ctk_main so that updated - * backend color slider values, cached in the handle itself, can be + * backend color slider values, cached in the handle itself, can be * saved to the RC file when the UI is closed. */ if (handles) { - display_handle = - handles->targets[NV_CTRL_TARGET_TYPE_DISPLAY].t[display_id].h; + display_handle = nv_get_target_handle(handles, + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id); } else { display_handle = NULL; } diff --git a/src/libXNVCtrl/NVCtrl.c b/src/libXNVCtrl/NVCtrl.c index 4db4533..edf7eff 100644 --- a/src/libXNVCtrl/NVCtrl.c +++ b/src/libXNVCtrl/NVCtrl.c @@ -514,14 +514,14 @@ Bool XNVCTRLSetTargetStringAttribute ( int target_id, unsigned int display_mask, unsigned int attribute, - char *ptr + const char *ptr ){ XExtDisplayInfo *info = find_display (dpy); xnvCtrlSetStringAttributeReq *req; xnvCtrlSetStringAttributeReply rep; int size; Bool success; - + if(!XextHasExtension(info)) return False; @@ -540,7 +540,7 @@ Bool XNVCTRLSetTargetStringAttribute ( req->length += ((size + 3) & ~3) >> 2; req->num_bytes = size; Data(dpy, ptr, size); - + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { UnlockDisplay (dpy); SyncHandle (); @@ -548,7 +548,7 @@ Bool XNVCTRLSetTargetStringAttribute ( } UnlockDisplay (dpy); SyncHandle (); - + success = rep.flags; return success; } @@ -558,7 +558,7 @@ Bool XNVCTRLSetStringAttribute ( int screen, unsigned int display_mask, unsigned int attribute, - char *ptr + const char *ptr ){ return XNVCTRLSetTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, display_mask, @@ -1059,7 +1059,7 @@ Bool XNVCTRLStringOperation ( int target_id, unsigned int display_mask, unsigned int attribute, - char *pIn, + const char *pIn, char **ppOut ) { XExtDisplayInfo *info = find_display(dpy); @@ -1070,24 +1070,24 @@ Bool XNVCTRLStringOperation ( if (!XextHasExtension(info)) return False; - + if (!ppOut) return False; *ppOut = NULL; - + XNVCTRLCheckExtension(dpy, info, False); XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); - + if (pIn) { inSize = strlen(pIn) + 1; } else { inSize = 0; } - + LockDisplay(dpy); GetReq(nvCtrlStringOperation, req); - + req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlStringOperation; req->target_type = target_type; @@ -1097,35 +1097,35 @@ Bool XNVCTRLStringOperation ( req->length += ((inSize + 3) & ~3) >> 2; req->num_bytes = inSize; - + if (pIn) { Data(dpy, pIn, inSize); } - + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { UnlockDisplay(dpy); SyncHandle(); return False; } - + length = rep.length; outSize = rep.num_bytes; slop = outSize & 3; if (outSize) *ppOut = (char *) Xmalloc(outSize); - + if (!*ppOut) { _XEatData(dpy, length); } else { _XRead(dpy, (char *) *ppOut, outSize); if (slop) _XEatData(dpy, 4-slop); } - + ret = rep.ret; - + UnlockDisplay(dpy); SyncHandle(); - + return ret; } diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h index 2b6a302..679cd01 100644 --- a/src/libXNVCtrl/NVCtrl.h +++ b/src/libXNVCtrl/NVCtrl.h @@ -3217,9 +3217,52 @@ */ #define NV_CTRL_USED_DEDICATED_GPU_MEMORY 394 /* R--G */ +/* + * NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE + * Some GPUs can make a tradeoff between double-precision floating-point + * performance and clock speed. Enabling double-precision floating point + * performance may benefit CUDA or OpenGL applications that require high + * bandwidth double-precision performance. Disabling this feature may benefit + * graphics applications that require higher clock speeds. + * + * This attribute is only available when toggling double precision boost + * can be done immediately (without need for a rebooot). + */ +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE 395 /* RW-G */ +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE_DISABLED 0 +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE_ENABLED 1 + +/* + * NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT + * Some GPUs can make a tradeoff between double-precision floating-point + * performance and clock speed. Enabling double-precision floating point + * performance may benefit CUDA or OpenGL applications that require high + * bandwidth double-precision performance. Disabling this feature may benefit + * graphics applications that require higher clock speeds. + * + * This attribute is only available when toggling double precision boost + * requires a reboot. + */ + +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT 396 /* RW-G */ +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT_DISABLED 0 +#define NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT_ENALED 1 + +/* + * NV_CTRL_DPY_HDMI_3D - Returns whether the specified display device is + * currently using HDMI 3D Frame Packed Stereo mode. Clients may use this + * to help interpret the refresh rate returned by NV_CTRL_REFRESH_RATE or + * NV_CTRL_REFRESH_RATE_3, which will be doubled when using HDMI 3D mode. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. + */ +#define NV_CTRL_DPY_HDMI_3D 397 /* R-DG */ +#define NV_CTRL_DPY_HDMI_3D_DISABLED 0 +#define NV_CTRL_DPY_HDMI_3D_ENABLED 1 -#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_USED_DEDICATED_GPU_MEMORY +#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_DPY_HDMI_3D /**************************************************************************/ @@ -4266,10 +4309,28 @@ #define NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN 18 /* R--- */ +/* + * NV_CTRL_BINARY_DATA_GPU_FLAGS - Returns a list of flags for the + * given GPU. A flag can, for instance, be a capability which enables + * of disables some features according to the GPU state. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPU flags + * 4 * n CARD32 GPU flag + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. + */ +#define NV_CTRL_BINARY_DATA_GPU_FLAGS 19 /* R--- */ + +/* Stereo and display composition transformations are mutually exclusive. */ +#define NV_CTRL_BINARY_DATA_GPU_FLAGS_STEREO_DISPLAY_TRANSFORM_EXCLUSIVE 0 +/* Overlay and display composition transformations are mutually exclusive. */ +#define NV_CTRL_BINARY_DATA_GPU_FLAGS_OVERLAY_DISPLAY_TRANSFORM_EXCLUSIVE 1 -#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE \ - NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN +#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE NV_CTRL_BINARY_DATA_GPU_FLAGS /**************************************************************************/ @@ -4620,5 +4681,4 @@ typedef struct _NVCTRLAttributePermissions { #define NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLESTRIP_XYUVRQ 1 #define NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLES_XYUVRQ 2 - #endif /* __NVCTRL_H */ diff --git a/src/libXNVCtrl/NVCtrlLib.h b/src/libXNVCtrl/NVCtrlLib.h index 0d6f910..8f12578 100644 --- a/src/libXNVCtrl/NVCtrlLib.h +++ b/src/libXNVCtrl/NVCtrlLib.h @@ -326,13 +326,13 @@ Bool XNVCTRLQueryTargetStringAttribute ( * BadMatch - The NVIDIA driver is not present on that screen. * BadAlloc - Insufficient resources to fulfill the request. */ - + Bool XNVCTRLSetStringAttribute ( Display *dpy, int screen, unsigned int display_mask, unsigned int attribute, - char *ptr + const char *ptr ); @@ -346,14 +346,14 @@ Bool XNVCTRLSetStringAttribute ( * BadMatch - The NVIDIA driver is not present on that screen. * BadAlloc - Insufficient resources to fulfill the request. */ - + Bool XNVCTRLSetTargetStringAttribute ( Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, - char *ptr + const char *ptr ); @@ -628,7 +628,7 @@ Bool XNVCTRLStringOperation ( int target_id, unsigned int display_mask, unsigned int attribute, - char *pIn, + const char *pIn, char **ppOut ); diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.c b/src/libXNVCtrlAttributes/NvCtrlAttributes.c index 6970a3f..e168a20 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.c @@ -516,7 +516,7 @@ ReturnStatus NvCtrlGetStringAttribute(NvCtrlAttributeHandle *handle, ReturnStatus NvCtrlSetStringAttribute(NvCtrlAttributeHandle *handle, - int attr, char *ptr, int *ret) + int attr, const char *ptr, int *ret) { if (!handle) return NvCtrlBadArgument; return NvCtrlSetStringDisplayAttribute(handle, 0, attr, ptr, ret); @@ -795,7 +795,7 @@ NvCtrlGetStringDisplayAttribute(NvCtrlAttributeHandle *handle, ReturnStatus NvCtrlSetStringDisplayAttribute(NvCtrlAttributeHandle *handle, unsigned int display_mask, - int attr, char *ptr, int *ret) + int attr, const char *ptr, int *ret) { NvCtrlAttributePrivateHandle *h; @@ -808,8 +808,7 @@ NvCtrlSetStringDisplayAttribute(NvCtrlAttributeHandle *handle, } return NvCtrlNoAttribute; - -} /* NvCtrlSetStringDisplayAttribute() */ +} ReturnStatus @@ -829,12 +828,12 @@ NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, ReturnStatus NvCtrlStringOperation(NvCtrlAttributeHandle *handle, unsigned int display_mask, int attr, - char *ptrIn, char **ptrOut) + const char *ptrIn, char **ptrOut) { NvCtrlAttributePrivateHandle *h; - + h = (NvCtrlAttributePrivateHandle *) handle; - + if ((attr >= 0) && (attr <= NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE)) { if (!h->nv) return NvCtrlMissingExtension; return NvCtrlNvControlStringOperation(h, display_mask, attr, ptrIn, @@ -842,8 +841,7 @@ NvCtrlStringOperation(NvCtrlAttributeHandle *handle, } return NvCtrlNoAttribute; - -} /* NvCtrlStringOperation() */ +} char *NvCtrlAttributesStrError(ReturnStatus status) diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.h b/src/libXNVCtrlAttributes/NvCtrlAttributes.h index bfb51d2..72c3c51 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.h +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.h @@ -393,7 +393,7 @@ ReturnStatus NvCtrlGetStringAttribute (NvCtrlAttributeHandle *handle, */ ReturnStatus NvCtrlSetStringAttribute (NvCtrlAttributeHandle *handle, - int attr, char *ptr, int *ret); + int attr, const char *ptr, int *ret); /* * The following four functions are identical to the above five, @@ -438,7 +438,7 @@ NvCtrlGetStringDisplayAttribute (NvCtrlAttributeHandle *handle, ReturnStatus NvCtrlSetStringDisplayAttribute (NvCtrlAttributeHandle *handle, unsigned int display_mask, - int attr, char *ptr, int *ret); + int attr, const char *ptr, int *ret); ReturnStatus NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, @@ -455,7 +455,7 @@ NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, ReturnStatus NvCtrlStringOperation(NvCtrlAttributeHandle *handle, unsigned int display_mask, int attr, - char *ptrIn, char **ptrOut); + const char *ptrIn, char **ptrOut); /* * NvCtrl[SG]etGvoColorConversion() - get and set the color conversion diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c index 1e75ce4..1695fd6 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c @@ -336,7 +336,7 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *h, ReturnStatus NvCtrlNvControlSetStringAttribute (NvCtrlAttributePrivateHandle *h, unsigned int display_mask, - int attr, char *ptr, int *ret) + int attr, const char *ptr, int *ret) { int tmp_int; /* Temp storage if ret is not specified */ @@ -357,7 +357,7 @@ NvCtrlNvControlSetStringAttribute (NvCtrlAttributePrivateHandle *h, return NvCtrlAttributeNotAvailable; } } - + return NvCtrlNoAttribute; } /* NvCtrlNvControlSetStringAttribute() */ @@ -393,7 +393,7 @@ NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, ReturnStatus NvCtrlNvControlStringOperation(NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, - char *ptrIn, char **ptrOut) + const char *ptrIn, char **ptrOut) { if (attr <= NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE) { if (XNVCTRLStringOperation (h->dpy, h->target_type, diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h index 538f6b2..3e9df16 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h @@ -268,7 +268,7 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *, ReturnStatus NvCtrlNvControlSetStringAttribute (NvCtrlAttributePrivateHandle *, - unsigned int, int, char *, int *); + unsigned int, int, const char *, int *); ReturnStatus NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, @@ -278,7 +278,7 @@ NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, ReturnStatus NvCtrlNvControlStringOperation (NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, - char *ptrIn, char **ptrOut); + const char *ptrIn, char **ptrOut); /* helper functions for XV86VidMode and RandR backends */ diff --git a/src/parse.c b/src/parse.c index 73eb006..4b480a2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -187,6 +187,9 @@ AttributeTableEntry attributeTable[] = { { "ThermalSensorReading", NV_CTRL_THERMAL_SENSOR_READING, N, "Returns the thermal sensor's current reading." }, { "ThermalSensorProvider", NV_CTRL_THERMAL_SENSOR_PROVIDER, N, "Returns the hardware device that provides the thermal sensor." }, { "ThermalSensorTarget", NV_CTRL_THERMAL_SENSOR_TARGET, N, "Returns what hardware component the thermal sensor is measuring." }, + { "GPUDoublePrecisionBoostImmediate", NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE, N, "Toggles GPU double precision; the change is applied immediately. Only available when the change can be made immediately." }, + { "GPUDoublePrecisionBoostReboot", NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT, N, "Toggles GPU double precision; the change is applied on the next reboot. Only available when the change requires a reboot." }, + /* Framelock */ { "FrameLockAvailable", NV_CTRL_FRAMELOCK, N|F|G, "Returns whether the underlying GPU supports Frame Lock. All of the other frame lock attributes are only applicable if this attribute is enabled (Supported)." }, { "FrameLockMaster", NV_CTRL_FRAMELOCK_MASTER, N|F|G|D, "Get/set which display device to use as the frame lock master for the entire sync group. Note that only one node in the sync group should be configured as the master." }, @@ -309,6 +312,7 @@ AttributeTableEntry attributeTable[] = { { "XineramaInfoOrder", NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER, S|N, "Controls the nvidiaXineramaInfoOrder." }, { "RandROutputID", NV_CTRL_DISPLAY_RANDR_OUTPUT_ID, N, "The RandR Output ID that corresponds to the display device." }, { "FrameLockDisplayConfig", NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, N, "Controls the FrameLock mode of operation for the display device." }, + { "Hdmi3D", NV_CTRL_DPY_HDMI_3D, N, "Returns whether the specified display device is currently using HDMI 3D Frame Packed Stereo mode. If so, the result of refresh rate queries will be doubled." }, /* TV */ { "TVOverScan", NV_CTRL_TV_OVERSCAN, 0, "Adjusts the amount of overscan on the specified display device." }, @@ -371,7 +375,7 @@ AttributeTableEntry attributeTable[] = { * about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_USED_DEDICATED_GPU_MEMORY +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_DPY_HDMI_3D #warning "Have you forgotten to add a new integer attribute to attributeTable?" #endif diff --git a/src/query-assign.c b/src/query-assign.c index f8fd0c0..3ac0931 100644 --- a/src/query-assign.c +++ b/src/query-assign.c @@ -106,6 +106,27 @@ static void query_display_target_names(CtrlHandleTarget *t) &(t->protoNames[NV_DPY_PROTO_NAME_RANDR])); } +NvCtrlAttributeHandle *nv_get_target_handle(CtrlHandles *handles, + int target_type, + int target_id) +{ + CtrlHandleTargets *targets; + int i; + + if (target_type < 0 || target_type >= MAX_TARGET_TYPES) { + return NULL; + } + + targets = handles->targets + target_type; + for (i = 0; i < targets->n; i++) { + CtrlHandleTarget *target = targets->t + i; + if (NvCtrlGetTargetId(target->h) == target_id) { + return target->h; + } + } + + return NULL; +} /* diff --git a/src/query-assign.h b/src/query-assign.h index d7209a8..bbc6dd3 100644 --- a/src/query-assign.h +++ b/src/query-assign.h @@ -73,6 +73,10 @@ int nv_process_assignments_and_queries(Options *op); CtrlHandles *nv_alloc_ctrl_handles(const char *display); void nv_free_ctrl_handles(CtrlHandles *h); +NvCtrlAttributeHandle *nv_get_target_handle(CtrlHandles *handles, + int target_type, + int target_id); + int nv_process_parsed_attribute(ParsedAttribute*, CtrlHandles *h, int, int, char*, ...); diff --git a/src/version.mk b/src/version.mk index f91d9f6..0203028 100644 --- a/src/version.mk +++ b/src/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 313.09 +NVIDIA_VERSION = 313.18 @@ -1 +1 @@ -NVIDIA_VERSION = 313.09 +NVIDIA_VERSION = 313.18 |