diff options
author | Sven Gothel <[email protected]> | 2014-07-27 04:00:26 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-07-27 04:00:26 +0200 |
commit | 007f120cd8d33e4231ef4d207b85ed156d1e0c82 (patch) | |
tree | d04584098e9ded5144030054ec5f978d5998abd4 /src/jogl | |
parent | c77b8f586cb2553582a42f5b90aeee5ef85f1efe (diff) |
Fixed and Changed NVidia Windows Driver Threaded optimization bug workaround of commit 5166d6a6b617ccb15c40fcb8d4eac2800527aa7b
Commit 5166d6a6b617ccb15c40fcb8d4eac2800527aa7b added a workaround
for the NVidia driver 260.99 for Window from 2010-12-11 issue.
[1] The workaround sets a process affinity while JOGL initialization
to mitigate NVidia driver's 'Threaded optimization := On' race conditions.
The process affinity is reset reset after initialization.
[2] The process affinity reset code had a bug, i.e. instead to restore the
original process's affinity mask, we restored the system's default affinity mask.
[3] Further more, there seem to be issues with changing a process affinity mask
regarding the process group.
This patch:
- Solves issue [2] by using the original process affinity mask
- Solves issue [3] by allowing a custom
affinity mode via the property 'jogl.debug.windows.cpu_affinity_mode':
- 0 - none (default, no affinity required for Windows NV driver >= 266.58 from 2011-01-24)
- 1 - process affinity (was required w/ Windows NV driver 260.99 from 2010-12-11, see commit 5166d6a6b617ccb15c40fcb8d4eac2800527aa7b)
- 2 - thread affinity (experimental)
Hence the workaround is disabled by default,
since the crash as dicumented in commit 5166d6a6b617ccb15c40fcb8d4eac2800527aa7b
could not be reproduced with NV driver 266.58 from 2011-01-24.
Diffstat (limited to 'src/jogl')
-rw-r--r-- | src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java | 197 |
1 files changed, 169 insertions, 28 deletions
diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 4d8c85137..42e802a95 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -68,6 +68,7 @@ import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.GDIDummyUpstreamSurfaceHook; import jogamp.nativewindow.windows.GDISurface; import jogamp.nativewindow.windows.RegisteredClassFactory; +import jogamp.opengl.Debug; import jogamp.opengl.DesktopGLDynamicLookupHelper; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -83,11 +84,35 @@ import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.GLRendererQuirks; public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { + /** + * Property integer value <code>jogl.debug.windows.cpu_affinity_mode</code>: + * <ul> + * <li>0 - none (default, no affinity required for Windows NV driver >= 266.58 from 2011-01-24)</li> + * <li>1 - process affinity (was required w/ Windows NV driver 260.99 from 2010-12-11, see commit 5166d6a6b617ccb15c40fcb8d4eac2800527aa7b)</li> + * <li>2 - thread affinity (experimental)</li> + * </ul> + */ + private static final int CPU_AFFINITY_MODE = Debug.getIntProperty("jogl.debug.windows.cpu_affinity_mode", true, 0); + private static DesktopGLDynamicLookupHelper windowsWGLDynamicLookupHelper = null; + private final CPUAffinity cpuAffinity; + public WindowsWGLDrawableFactory() { super(); + switch( CPU_AFFINITY_MODE ) { + case 1: + cpuAffinity = new WindowsProcessAffinity(); + break; + case 2: + cpuAffinity = new WindowsThreadAffinity(); + break; + default: + cpuAffinity = new NopCPUAffinity(); + break; + } + synchronized(WindowsWGLDrawableFactory.class) { if( null == windowsWGLDynamicLookupHelper ) { windowsWGLDynamicLookupHelper = AccessController.doPrivileged(new PrivilegedAction<DesktopGLDynamicLookupHelper>() { @@ -168,45 +193,23 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { return windowsWGLDynamicLookupHelper; } + /* pp */ static String toHexString(final long l) { return "0x"+Long.toHexString(l); } + private WindowsGraphicsDevice defaultDevice; private SharedResourceRunner sharedResourceRunner; private HashMap<String /*connection*/, SharedResourceRunner.Resource> sharedMap; - private long processAffinityChanges = 0; - private final PointerBuffer procMask = PointerBuffer.allocateDirect(1); - private final PointerBuffer sysMask = PointerBuffer.allocateDirect(1); - @Override protected void enterThreadCriticalZone() { - synchronized (sysMask) { - if( 0 == processAffinityChanges) { - final long pid = GDI.GetCurrentProcess(); - if ( GDI.GetProcessAffinityMask(pid, procMask, sysMask) ) { - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.enterThreadCriticalZone() - 0x" + Long.toHexString(pid) + " - " + getThreadName()); - // Thread.dumpStack(); - } - processAffinityChanges = pid; - GDI.SetProcessAffinityMask(pid, 1); - } - } + synchronized (cpuAffinity) { + cpuAffinity.set(1); } } @Override protected void leaveThreadCriticalZone() { - synchronized (sysMask) { - if( 0 != processAffinityChanges) { - final long pid = GDI.GetCurrentProcess(); - if( pid != processAffinityChanges) { - throw new GLException("PID doesn't match: set PID 0x" + Long.toHexString(processAffinityChanges) + - " this PID 0x" + Long.toHexString(pid) ); - } - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.leaveThreadCriticalZone() - 0x" + Long.toHexString(pid) + " - " + getThreadName()); - } - GDI.SetProcessAffinityMask(pid, sysMask.get(0)); - } + synchronized (cpuAffinity) { + cpuAffinity.reset(); } } @@ -598,4 +601,142 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { GDI.SetDeviceGammaRamp(screenDC, originalGammaRamp); GDI.ReleaseDC(0, screenDC); } + + static interface CPUAffinity { + boolean set(final int newAffinity); + boolean reset(); + } + static final class WindowsThreadAffinity implements CPUAffinity { + private long threadHandle; + private long threadOrigAffinity; + private long threadNewAffinity; + public WindowsThreadAffinity() { + threadHandle = 0; + threadOrigAffinity = 0; + threadNewAffinity = 0; + } + @Override + public boolean set(final int newAffinity) { + final long tid = GDI.GetCurrentThread(); + if( 0 != threadHandle ) { + throw new IllegalStateException("Affinity already set"); + } + final long threadLastAffinity = GDI.SetThreadAffinityMask(tid, newAffinity); + final int werr = GDI.GetLastError(); + final boolean res; + if( 0 != threadLastAffinity ) { + res = true; + this.threadHandle = tid; + this.threadNewAffinity = newAffinity; + this.threadOrigAffinity = threadLastAffinity; + } else { + res = false; + } + if(DEBUG) { + System.err.println("WindowsThreadAffinity.set() - tid " + toHexString(tid) + " - " + getThreadName() + + ": OK "+res+" (werr "+werr+"), Affinity: "+toHexString(threadOrigAffinity) + " -> " + toHexString(newAffinity)); + } + return res; + } + @Override + public boolean reset() { + if( 0 == threadHandle ) { + return true; + } + final long tid = GDI.GetCurrentThread(); + if( tid != threadHandle) { + throw new IllegalStateException("TID doesn't match: set TID " + toHexString(threadHandle) + + " this TID " + toHexString(tid) ); + } + final long preThreadAffinity = GDI.SetThreadAffinityMask(threadHandle, threadOrigAffinity); + final boolean res = 0 != preThreadAffinity; + if(DEBUG) { + System.err.println("WindowsThreadAffinity.reset() - tid " + toHexString(threadHandle) + " - " + getThreadName() + + ": OK "+res+" (werr "+GDI.GetLastError()+"), Affinity: "+toHexString(threadNewAffinity)+" -> orig "+ toHexString(threadOrigAffinity)); + } + this.threadHandle = 0; + this.threadNewAffinity = this.threadOrigAffinity; + return res; + } + } + static final class WindowsProcessAffinity implements CPUAffinity { + private long processHandle; + private long newAffinity; + private final PointerBuffer procMask; + private final PointerBuffer sysMask; + + public WindowsProcessAffinity() { + processHandle = 0; + newAffinity = 0; + procMask = PointerBuffer.allocateDirect(1); + sysMask = PointerBuffer.allocateDirect(1); + } + @Override + public boolean set(final int newAffinity) { + if( 0 != processHandle ) { + throw new IllegalStateException("Affinity already set"); + } + final long pid = GDI.GetCurrentProcess(); + final boolean res; + if ( GDI.GetProcessAffinityMask(pid, procMask, sysMask) ) { + if( GDI.SetProcessAffinityMask(pid, newAffinity) ) { + this.processHandle = pid; + this.newAffinity = newAffinity; + res = true; + } else { + res = false; + } + if(DEBUG) { + System.err.println("WindowsProcessAffinity.set() - pid " + toHexString(pid) + " - " + getThreadName() + + ": OK "+res+" (werr "+GDI.GetLastError()+"), Affinity: procMask "+ toHexString(procMask.get(0)) + ", sysMask "+ toHexString(sysMask.get(0)) + + " -> "+toHexString(newAffinity)); + } + } else { + if(DEBUG) { + System.err.println("WindowsProcessAffinity.set() - pid " + toHexString(pid) + " - " + getThreadName() + + ": Error, could not GetProcessAffinityMask, werr "+GDI.GetLastError()); + } + res = false; + } + return res; + } + @Override + public boolean reset() { + if( 0 == processHandle ) { + return true; + } + final long pid = GDI.GetCurrentProcess(); + if( pid != processHandle) { + throw new IllegalStateException("PID doesn't match: set PID " + toHexString(processHandle) + + " this PID " + toHexString(pid) ); + } + final long origProcAffinity = procMask.get(0); + final boolean res = GDI.SetProcessAffinityMask(processHandle, origProcAffinity); + if(DEBUG) { + final int werr = GDI.GetLastError(); + System.err.println("WindowsProcessAffinity.reset() - pid " + toHexString(processHandle) + " - " + getThreadName() + + ": OK "+res+" (werr "+werr+"), Affinity: "+toHexString(newAffinity)+" -> procMask "+ toHexString(origProcAffinity)); + } + this.processHandle = 0; + this.newAffinity = origProcAffinity; + return res; + } + } + static final class NopCPUAffinity implements CPUAffinity { + public NopCPUAffinity() { } + @Override + public boolean set(final int newAffinity) { + if(DEBUG) { + System.err.println("NopCPUAffinity.set() - " + getThreadName()); + } + return false; + } + @Override + public boolean reset() { + if(DEBUG) { + System.err.println("NopCPUAffinity.reset() - " + getThreadName()); + } + return false; + } + } } |