/* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ package jogamp.opengl.windows.wgl; import java.nio.Buffer; import java.nio.ShortBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; import java.util.HashMap; import java.util.List; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import jogamp.nativewindow.WrappedSurface; 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; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.GLRendererQuirks; public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { /** * Bug 1036: NVidia Windows Driver 'Threaded optimization' workaround. *

* https://jogamp.org/bugzilla/show_bug.cgi?id=1036 *

*

* Since NV driver 260.99 from 2010-12-11 a 'Threaded optimization' feature has been introduced. * The driver spawns off a dedicated thread to off-load certain OpenGL tasks from the calling thread * to perform them async and off-thread. *

*

* If 'Threaded optimization' is manually enabled 'on', the driver may crash with JOGL's consistent * multi-threaded usage - this is a driver bug. *

*

* If 'Threaded optimization' is manually disabled 'off', the driver always works correctly. *

*

* 'Threaded optimization' default setting is 'auto' and the driver may crash without this workaround. *

*

* If setting the process affinity to '1' (1st CPU) while initialization and launching * the {@link SharedResourceRunner}, the driver does not crash anymore in 'auto' mode. * This might be either because the driver does not enable 'Threaded optimization' * or because the driver's worker thread is bound to the same CPU. *

*

* Property integer value jogl.windows.cpu_affinity_mode: *

*

*

* Test case reproducing the crash reliable is: com.jogamp.opengl.test.junit.jogl.caps.TestTranslucencyNEWT
* (don't ask why ..) *

*/ private static final int CPU_AFFINITY_MODE; static { Debug.initSingleton(); CPU_AFFINITY_MODE = PropertyAccess.getIntProperty("jogl.windows.cpu_affinity_mode", true, 1); } private static DesktopGLDynamicLookupHelper windowsWGLDynamicLookupHelper = null; private final CPUAffinity cpuAffinity; public WindowsWGLDrawableFactory() { super(); switch( CPU_AFFINITY_MODE ) { case 0: cpuAffinity = new NopCPUAffinity(); break; /** * Doesn't work ! case 2: cpuAffinity = new WindowsThreadAffinity(); break; */ default: cpuAffinity = new WindowsProcessAffinity(); break; } synchronized(WindowsWGLDrawableFactory.class) { if( null == windowsWGLDynamicLookupHelper ) { windowsWGLDynamicLookupHelper = AccessController.doPrivileged(new PrivilegedAction() { @Override public DesktopGLDynamicLookupHelper run() { DesktopGLDynamicLookupHelper tmp; try { tmp = new DesktopGLDynamicLookupHelper(new WindowsWGLDynamicLibraryBundleInfo()); if(null!=tmp && tmp.isLibComplete()) { WGL.getWGLProcAddressTable().reset(tmp); } } catch (final Exception ex) { tmp = null; if(DEBUG) { ex.printStackTrace(); } } return tmp; } } ); } } defaultDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); if(null!=windowsWGLDynamicLookupHelper) { // Register our GraphicsConfigurationFactory implementations // The act of constructing them causes them to be registered WindowsWGLGraphicsConfigurationFactory.registerFactory(); if(GLProfile.isAWTAvailable()) { try { ReflectionUtil.callStaticMethod("jogamp.opengl.windows.wgl.awt.WindowsAWTWGLGraphicsConfigurationFactory", "registerFactory", null, null, getClass().getClassLoader()); } catch (final Exception jre) { /* n/a .. */ } } sharedMap = new HashMap(); // Init shared resources off thread // Will be released via ShutdownHook sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); sharedResourceRunner.start(); } } @Override protected final boolean isComplete() { return null != windowsWGLDynamicLookupHelper; } @Override protected final void shutdownImpl() { if( DEBUG ) { System.err.println("WindowsWGLDrawableFactory.shutdown"); } if(null != sharedResourceRunner) { sharedResourceRunner.stop(); sharedResourceRunner = null; } if(null != sharedMap) { sharedMap.clear(); sharedMap = null; } defaultDevice = null; /** * Pulling away the native library may cause havoc .. * windowsWGLDynamicLookupHelper.destroy(); */ windowsWGLDynamicLookupHelper = null; RegisteredClassFactory.shutdownSharedClasses(); } @Override public GLDynamicLookupHelper getGLDynamicLookupHelper(final int profile) { return windowsWGLDynamicLookupHelper; } /* pp */ static String toHexString(final long l) { return "0x"+Long.toHexString(l); } private WindowsGraphicsDevice defaultDevice; private SharedResourceRunner sharedResourceRunner; private HashMap sharedMap; @Override protected void enterThreadCriticalZone() { synchronized (cpuAffinity) { cpuAffinity.set(1); } } @Override protected void leaveThreadCriticalZone() { synchronized (cpuAffinity) { cpuAffinity.reset(); } } static class SharedResource implements SharedResourceRunner.Resource { private final boolean hasARBPixelFormat; private final boolean hasARBMultisample; private final boolean hasARBPBuffer; private final boolean hasARBReadDrawable; private WindowsGraphicsDevice device; private AbstractGraphicsScreen screen; private GLDrawableImpl drawable; private GLContextImpl context; SharedResource(final WindowsGraphicsDevice dev, final AbstractGraphicsScreen scrn, final GLDrawableImpl draw, final GLContextImpl ctx, final boolean arbPixelFormat, final boolean arbMultisample, final boolean arbPBuffer, final boolean arbReadDrawable) { device = dev; screen = scrn; drawable = draw; context = ctx; hasARBPixelFormat = arbPixelFormat; hasARBMultisample = arbMultisample; hasARBPBuffer = arbPBuffer; hasARBReadDrawable = arbReadDrawable; } @Override public final boolean isValid() { return null != context; } @Override final public AbstractGraphicsDevice getDevice() { return device; } @Override final public AbstractGraphicsScreen getScreen() { return screen; } @Override final public GLDrawableImpl getDrawable() { return drawable; } @Override final public GLContextImpl getContext() { return context; } @Override public GLRendererQuirks getRendererQuirks() { return null != context ? context.getRendererQuirks() : null; } final boolean hasARBPixelFormat() { return hasARBPixelFormat; } final boolean hasARBMultisample() { return hasARBMultisample; } final boolean hasARBPBuffer() { return hasARBPBuffer; } final boolean hasReadDrawable() { return hasARBReadDrawable; } } class SharedResourceImplementation implements SharedResourceRunner.Implementation { @Override public void clear() { sharedMap.clear(); } @Override public SharedResourceRunner.Resource mapPut(final String connection, final SharedResourceRunner.Resource resource) { return sharedMap.put(connection, resource); } @Override public SharedResourceRunner.Resource mapGet(final String connection) { return sharedMap.get(connection); } @Override public Collection mapValues() { synchronized(sharedMap) { return sharedMap.values(); } } @Override public boolean isDeviceSupported(final String connection) { return true; } @Override public SharedResourceRunner.Resource createSharedResource(final String connection) { final WindowsGraphicsDevice sharedDevice = new WindowsGraphicsDevice(connection, AbstractGraphicsDevice.DEFAULT_UNIT); sharedDevice.lock(); try { final AbstractGraphicsScreen absScreen = new DefaultGraphicsScreen(sharedDevice, 0); final GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP, false); if (null == glp) { throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); } final GLCapabilitiesImmutable caps = new GLCapabilities(glp); final GLDrawableImpl sharedDrawable = createOnscreenDrawableImpl(createDummySurfaceImpl(sharedDevice, false, caps, caps, null, 64, 64)); sharedDrawable.setRealized(true); final GLContextImpl sharedContext = (GLContextImpl) sharedDrawable.createContext(null); if (null == sharedContext) { throw new GLException("Couldn't create shared context for drawable: "+sharedDrawable); } boolean hasARBPixelFormat; boolean hasARBMultisample; boolean hasARBPBuffer; boolean hasARBReadDrawableAvailable; sharedContext.makeCurrent(); try { hasARBPixelFormat = sharedContext.isExtensionAvailable(WGL_ARB_pixel_format); hasARBMultisample = sharedContext.isExtensionAvailable(WGL_ARB_multisample); hasARBPBuffer = sharedContext.isExtensionAvailable(GLExtensions.ARB_pbuffer); hasARBReadDrawableAvailable = sharedContext.isExtensionAvailable(WGL_ARB_make_current_read) && sharedContext.isFunctionAvailable(wglMakeContextCurrent); } finally { sharedContext.release(); } if (DEBUG) { System.err.println("SharedDevice: " + sharedDevice); System.err.println("SharedScreen: " + absScreen); System.err.println("SharedContext: " + sharedContext); System.err.println("pixelformat: " + hasARBPixelFormat); System.err.println("multisample: " + hasARBMultisample); System.err.println("pbuffer: " + hasARBPBuffer); System.err.println("readDrawable: " + hasARBReadDrawableAvailable); } return new SharedResource(sharedDevice, absScreen, sharedDrawable, sharedContext, hasARBPixelFormat, hasARBMultisample, hasARBPBuffer, hasARBReadDrawableAvailable); } catch (final Throwable t) { throw new GLException("WindowsWGLDrawableFactory - Could not initialize shared resources for "+connection, t); } finally { sharedDevice.unlock(); } } @Override public void releaseSharedResource(final SharedResourceRunner.Resource shared) { final SharedResource sr = (SharedResource) shared; if (DEBUG) { System.err.println("Shutdown Shared:"); System.err.println("Device : " + sr.device); System.err.println("Screen : " + sr.screen); System.err.println("Drawable: " + sr.drawable); System.err.println("CTX : " + sr.context); } if (null != sr.context) { // may cause JVM SIGSEGV: sharedContext.destroy(); sr.context.destroy(); // will also pull the dummy MutableSurface sr.context = null; } if (null != sr.drawable) { sr.drawable.setRealized(false); sr.drawable = null; } if (null != sr.screen) { sr.screen = null; } if (null != sr.device) { sr.device.close(); sr.device = null; } } } @Override public final AbstractGraphicsDevice getDefaultDevice() { return defaultDevice; } @Override public final boolean getIsDeviceCompatible(final AbstractGraphicsDevice device) { if(null!=windowsWGLDynamicLookupHelper && device instanceof WindowsGraphicsDevice) { return true; } return false; } final static String WGL_ARB_pbuffer = "WGL_ARB_pbuffer"; final static String WGL_ARB_pixel_format = "WGL_ARB_pixel_format"; final static String WGL_ARB_multisample = "WGL_ARB_multisample"; final static String WGL_NV_float_buffer = "WGL_NV_float_buffer"; final static String WGL_ARB_make_current_read = "WGL_ARB_make_current_read"; final static String wglMakeContextCurrent = "wglMakeContextCurrent"; @Override protected final Thread getSharedResourceThread() { return sharedResourceRunner.start(); } @Override protected final SharedResource getOrCreateSharedResourceImpl(final AbstractGraphicsDevice device) { return (SharedResource) sharedResourceRunner.getOrCreateShared(device); } protected final WindowsWGLDrawable getOrCreateSharedDrawable(final AbstractGraphicsDevice device) { final SharedResourceRunner.Resource sr = getOrCreateSharedResourceImpl(device); if(null!=sr) { return (WindowsWGLDrawable) sr.getDrawable(); } return null; } @Override protected List getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return WindowsWGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); } @Override protected final GLDrawableImpl createOnscreenDrawableImpl(final NativeSurface target) { if (target == null) { throw new IllegalArgumentException("Null target"); } return new WindowsOnscreenWGLDrawable(this, target); } @Override protected final GLDrawableImpl createOffscreenDrawableImpl(final NativeSurface target) { if (target == null) { throw new IllegalArgumentException("Null target"); } final AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!chosenCaps.isPBuffer()) { return WindowsBitmapWGLDrawable.create(this, target); } // PBuffer GLDrawable Creation GLDrawableImpl pbufferDrawable; final AbstractGraphicsDevice device = config.getScreen().getDevice(); /** * Similar to ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, * we need to have a context current on the same Display to create a PBuffer. */ final SharedResource sr = getOrCreateSharedResourceImpl(device); if(null!=sr) { final GLContext lastContext = GLContext.getCurrent(); if (lastContext != null) { lastContext.release(); } sr.context.makeCurrent(); try { pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); } finally { sr.context.release(); if (lastContext != null) { lastContext.makeCurrent(); } } } else { pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); } return pbufferDrawable; } /** * @return 1 if read drawable extension is available, 0 if not * and -1 if undefined yet, ie no shared device exist at this point. */ public final int isReadDrawableAvailable(final AbstractGraphicsDevice device) { final SharedResource sr = getOrCreateSharedResourceImpl( ( null != device ) ? device : defaultDevice ); if(null!=sr) { return sr.hasReadDrawable() ? 1 : 0 ; } return -1; // undefined } @Override public final boolean canCreateGLPbuffer(final AbstractGraphicsDevice device, final GLProfile glp) { final SharedResource sr = getOrCreateSharedResourceImpl( ( null != device ) ? device : defaultDevice ); if(null!=sr) { return sr.hasARBPBuffer(); } return false; } @Override protected final ProxySurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstreamHook) { final WindowsGraphicsDevice device; if(createNewDevice || !(deviceReq instanceof WindowsGraphicsDevice)) { device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); } else { device = (WindowsGraphicsDevice)deviceReq; } final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, 0); final WindowsWGLGraphicsConfiguration config = WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen); if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } return new WrappedSurface(config, 0, upstreamHook, createNewDevice); } @Override public final ProxySurface createDummySurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { final WindowsGraphicsDevice device; if( createNewDevice || !(deviceReq instanceof WindowsGraphicsDevice) ) { device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); } else { device = (WindowsGraphicsDevice)deviceReq; } final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, 0); chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); final WindowsWGLGraphicsConfiguration config = WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(chosenCaps, requestedCaps, chooser, screen); if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+chosenCaps+" on "+screen); } return new GDISurface(config, 0, new GDIDummyUpstreamSurfaceHook(width, height), createNewDevice); } @Override protected final ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { final WindowsGraphicsDevice device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen); return new GDISurface(cfg, windowHandle, upstream, true); } @Override protected final GLContext createExternalGLContextImpl() { return WindowsExternalWGLContext.create(this, null); } @Override public final boolean canCreateExternalGLDrawable(final AbstractGraphicsDevice device) { return true; } @Override protected final GLDrawable createExternalGLDrawableImpl() { return WindowsExternalWGLDrawable.create(this, null); } static String wglGetLastError() { final long err = GDI.GetLastError(); String detail = null; switch ((int) err) { case GDI.ERROR_SUCCESS: detail = "ERROR_SUCCESS"; break; case GDI.ERROR_INVALID_PIXEL_FORMAT: detail = "ERROR_INVALID_PIXEL_FORMAT"; break; case GDI.ERROR_NO_SYSTEM_RESOURCES: detail = "ERROR_NO_SYSTEM_RESOURCES"; break; case GDI.ERROR_INVALID_DATA: detail = "ERROR_INVALID_DATA"; break; case GDI.ERROR_PROC_NOT_FOUND: detail = "ERROR_PROC_NOT_FOUND"; break; case GDI.ERROR_INVALID_WINDOW_HANDLE:detail = "ERROR_INVALID_WINDOW_HANDLE"; break; default: detail = "(Unknown error code " + err + ")"; break; } return detail; } //------------------------------------------------------ // Gamma-related functionality // private static final int GAMMA_RAMP_LENGTH = 256; @Override protected final int getGammaRampLength(final NativeSurface surface) { return GAMMA_RAMP_LENGTH; } @Override protected final boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { final short[] rampData = new short[3 * GAMMA_RAMP_LENGTH]; for (int i = 0; i < GAMMA_RAMP_LENGTH; i++) { final short scaledValue = (short) (ramp[i] * 65535); rampData[i] = scaledValue; rampData[i + GAMMA_RAMP_LENGTH] = scaledValue; rampData[i + 2 * GAMMA_RAMP_LENGTH] = scaledValue; } final long hDC = surface.getSurfaceHandle(); if( 0 == hDC ) { return false; } // final long screenDC = GDI.GetDC(0); final boolean res = GDI.SetDeviceGammaRamp(hDC, ShortBuffer.wrap(rampData)); // GDI.ReleaseDC(0, screenDC); return res; } @Override protected final Buffer getGammaRamp(final NativeSurface surface) { final ShortBuffer rampData = ShortBuffer.wrap(new short[3 * GAMMA_RAMP_LENGTH]); final long hDC = surface.getSurfaceHandle(); if( 0 == hDC ) { return null; } // final long screenDC = GDI.GetDC(0); final boolean res = GDI.GetDeviceGammaRamp(hDC, rampData); // GDI.ReleaseDC(0, screenDC); if (!res) { return null; } return rampData; } @Override protected final void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { if (originalGammaRamp == null) { // getGammaRamp failed earlier return; } final long hDC = surface.getSurfaceHandle(); if( 0 == hDC ) { return; } // final long screenDC = GDI.GetDC(0); GDI.SetDeviceGammaRamp(hDC, originalGammaRamp); // GDI.ReleaseDC(0, hDC); } @Override protected final void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { if (originalGammaRamp == null) { // getGammaRamp failed earlier return; } final long screenDC = GDI.GetDC(0); 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; } } }