diff options
author | Sven Gothel <[email protected]> | 2014-06-08 08:11:57 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-08 08:11:57 +0200 |
commit | 2571ed0b5ef14155d204540d38b564a7d4cd47b6 (patch) | |
tree | 8aaf1171af1b95f1cb1ebe706771a4aff3752c2f /src/nativewindow/classes/jogamp | |
parent | ff7bf3122fd2007bbe70cfadca9f0f978ee96456 (diff) |
Bug 741 HiDPI: Add ScalableSurface interface to get/set pixelScale w/ full OSX impl.
Add ScalableSurface interface
- To set pixelScale before and after realization
- To get pixelScale
- Implemented on:
- NEWT Window
- Generic impl. in WindowImpl
- OSX WindowDriver impl.
- Also propagetes pixelScale to parent JAWTWindow if offscreen (NewtCanvasAWT)
- AWT WindowDriver impl.
- JAWTWindow / OSXCalayer
- AWT GLCanvas
- AWT GLJPanel
- NEWTCanvasAWT:
- Propagates NEWT Window's pixelScale to underlying JAWTWindow
- WrappedSurface for pixelScale propagation
using offscreen drawables, i.e. GLJPanel
- Generic helper in SurfaceScaleUtils (nativewindow package)
- Fully implemented on OSX
- Capable to switch pixelScale before realization,
i.e. native-creation, as well as on-the-fly.
- Impl. uses int[2] for pixelScale to support
non-uniform scale.
Test cases:
- com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT
- Press 'x' to toggle HiDPI
- Commandline '-pixelScale <value>'
- Added basic auto unit test (setting pre-realization)
Diffstat (limited to 'src/nativewindow/classes/jogamp')
4 files changed, 272 insertions, 6 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java new file mode 100644 index 000000000..22e67ecff --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java @@ -0,0 +1,175 @@ +/** + * Copyright 2014 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ScalableSurface; + +/** + * Basic {@link ScalableSurface} utility to validate and compute pixel-scale values. + */ +public class SurfaceScaleUtils { + + private static final int[] PlatformMaxPixelScale; + private static final boolean PlatformUniformPixelScale; + private static final boolean PlatformPixelScaleSupported; + + static { + if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true) ) { + PlatformMaxPixelScale = new int[] { jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE, jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE }; + PlatformUniformPixelScale = true; + PlatformPixelScaleSupported = true; + } else { + PlatformMaxPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + PlatformUniformPixelScale = false; + PlatformPixelScaleSupported = false; + } + } + + /** + * Compute a new valid pixelScale to be used by {@link NativeSurface} implementations, + * based on the given request and surface's pixelScale + * + * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place + * @param prePixelScale previous pixelScale + * @param reqPixelScale requested pixelScale, validated via {@link #validateReqPixelScale(int[], int, String)}. + * @param surfPixelScaleRaw raw surface pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + * @return true if pixelScale has changed, otherwise false + */ + public static boolean computePixelScale(int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] surfPixelScaleRaw, final String DEBUG_PREFIX) { + final int surfPixelScaleSafeX = 0 < surfPixelScaleRaw[0] ? surfPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE; + final int surfPixelScaleSafeY = 0 < surfPixelScaleRaw[1] ? surfPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE; + final boolean useHiDPI = ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[0] || ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[1]; + final int prePixelScaleX = prePixelScale[0]; + final int prePixelScaleY = prePixelScale[1]; + + if( useHiDPI ) { + result[0] = surfPixelScaleSafeX; + result[1] = surfPixelScaleSafeY; + } else { + result[0] = ScalableSurface.IDENTITY_PIXELSCALE; + result[1] = ScalableSurface.IDENTITY_PIXELSCALE; + } + + if( result[0] != prePixelScaleX || result[1] != prePixelScaleY ) { + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+ + reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+ + surfPixelScaleRaw[0]+"x"+surfPixelScaleRaw[1]+" (raw) -> "+ + surfPixelScaleSafeX+"x"+surfPixelScaleSafeY+" (safe) -> "+ + result[0]+"x"+result[1]+" (use)"); + } + return true; + } else { + return false; + } + } + + /** + * Validate the given requested pixelScale value pair, i.e. clip it to the + * limits of {@link ScalableSurface#AUTOMAX_PIXELSCALE} and {@link #getPlatformMaxPixelScale(int[])} + * <p> + * To be used by {@link ScalableSurface#setSurfaceScale(int[])} implementations. + * </p> + * + * @param result int[2] storage for result + * @param reqPixelScale requested pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + */ + public static void validateReqPixelScale(final int[] result, final int[] reqPixelScale, final String DEBUG_PREFIX) { + final int minPS = Math.min(reqPixelScale[0], reqPixelScale[1]); + if( ScalableSurface.AUTOMAX_PIXELSCALE >= minPS ) { + result[0] = ScalableSurface.AUTOMAX_PIXELSCALE; + result[1] = ScalableSurface.AUTOMAX_PIXELSCALE; + } else if( PlatformUniformPixelScale ) { + final int maxPS = Math.max(reqPixelScale[0], reqPixelScale[1]); + if( maxPS >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + result[1] = PlatformMaxPixelScale[1]; + } else { + result[0] = maxPS; + result[1] = maxPS; + } + } else { + if( reqPixelScale[0] >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + } else { + result[0] = reqPixelScale[0]; + } + if( reqPixelScale[1] >= PlatformMaxPixelScale[1] ) { + result[1] = PlatformMaxPixelScale[1]; + } else { + result[1] = reqPixelScale[1]; + } + } + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".validateReqPixelScale: ["+reqPixelScale[0]+"x"+reqPixelScale[1]+" (req), "+ + PlatformMaxPixelScale[0]+"x"+PlatformMaxPixelScale[1]+" (max)] -> "+ + result[0]+"x"+result[1]+" (valid)"); + } + } + + /** + * Replaces {@link ScalableSurface#AUTOMAX_PIXELSCALE} with {@link #getPlatformMaxPixelScale(int[])}, + * for each component. + * + * @param pixelScale int[2] value array to be tested and replaced + */ + public static void replaceAutoMaxWithPlatformMax(final int[] pixelScale) { + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[0] ) { + pixelScale[0] = PlatformMaxPixelScale[0]; + } + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[1] ) { + pixelScale[1] = PlatformMaxPixelScale[1]; + } + } + + /** + * Returns the maximum platform pixelScale + */ + public static int[] getPlatformMaxPixelScale(final int[] result) { + System.arraycopy(PlatformMaxPixelScale, 0, result, 0, 2); + return result; + } + + /** + * Returns true if platform pixelScale is uniform, i.e. same scale factor for x- and y-direction, otherwise false. + */ + public static boolean isPlatformPixelScaleUniform() { + return PlatformUniformPixelScale; + } + + /** + * Returns whether the platform supports pixelScale + */ + public static boolean isPlatformPixelScaleSupported() { + return PlatformPixelScaleSupported; + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index 902223c80..1a8772988 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -31,6 +31,7 @@ package jogamp.nativewindow; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.UpstreamSurfaceHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; @@ -40,8 +41,9 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; * * @see ProxySurface */ -public class WrappedSurface extends ProxySurfaceImpl { - protected long surfaceHandle; +public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface { + private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private long surfaceHandle; /** * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information, @@ -76,6 +78,8 @@ public class WrappedSurface extends ProxySurfaceImpl { @Override protected void invalidateImpl() { surfaceHandle = 0; + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } @Override @@ -97,14 +101,61 @@ public class WrappedSurface extends ProxySurfaceImpl { protected final void unlockSurfaceImpl() { } + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ @Override public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { - return pixelUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + pixelUnitsAndResult[0] /= hasPixelScale[0]; + pixelUnitsAndResult[1] /= hasPixelScale[1]; + return pixelUnitsAndResult; } + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ @Override public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { - return windowUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + windowUnitsAndResult[0] *= hasPixelScale[0]; + windowUnitsAndResult[1] *= hasPixelScale[1]; + return windowUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation is to simply pass the given pixelScale + * from the caller <i>down</i> to this instance without validation to be applied in the {@link #convertToPixelUnits(int[]) conversion} {@link #convertToWindowUnits(int[]) methods} <b>only</b>.<br/> + * This allows the caller to pass down knowledge about window- and pixel-unit conversion and utilize mentioned conversion methods. + * </p> + * <p> + * The given pixelScale will not impact the actual {@link #getSurfaceWidth()} and {@link #getSurfaceHeight()}, + * which is determinated by this instances {@link #getUpstreamSurface() upstream surface}. + * </p> + * <p> + * Implementation uses the default pixelScale {@link ScalableSurface#IDENTITY_PIXELSCALE} + * and resets to default values on {@link #invalidateImpl()}, i.e. {@link #destroyNotify()}. + * </p> + * <p> + * Implementation returns the given pixelScale array. + * </p> + */ + @Override + public final void setSurfaceScale(final int[] pixelScale) { + hasPixelScale[0] = pixelScale[0]; + hasPixelScale[1] = pixelScale[1]; + } + + @Override + public final int[] getSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; } }
\ No newline at end of file diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 3b91fc8ab..3d88049b2 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -114,6 +114,27 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } @Override + public void setSurfaceScale(final int[] pixelScale) { + super.setSurfaceScale(pixelScale); + if( 0 != drawable ) { // locked at least once ! + final int hadPixelScaleX = getPixelScaleX(); + updatePixelScale(); + + if( hadPixelScaleX != getPixelScaleX() && 0 != getAttachedSurfaceLayer() ) { + OSXUtil.RunOnMainThread(false, new Runnable() { + @Override + public void run() { + final long osl = getAttachedSurfaceLayer(); + if( 0 != osl ) { + OSXUtil.SetCALayerPixelScale(rootSurfaceLayer, osl, getPixelScaleX()); + } + } + }); + } + } + } + + @Override protected void attachSurfaceLayerImpl(final long layerHandle) { OSXUtil.RunOnMainThread(false, new Runnable() { @Override @@ -143,7 +164,8 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } else if( DEBUG ) { System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); } - OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScale(), JAWTUtil.getOSXCALayerQuirks()); + // HiDPI: uniform pixel scale + OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScaleX(), JAWTUtil.getOSXCALayerQuirks()); } } ); } @@ -309,7 +331,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { public void run() { String errMsg = null; if(0 == rootSurfaceLayer && 0 != jawtSurfaceLayersHandle) { - rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScale()); + rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScaleX()); // HiDPI: uniform pixel scale if(0 == rootSurfaceLayer) { errMsg = "Could not create root CALayer"; } else { diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 12e574ced..a91698f62 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -44,6 +44,9 @@ public class OSXUtil implements ToolkitProperties { private static boolean isInit = false; private static final boolean DEBUG = Debug.debug("OSXUtil"); + /** FIXME HiDPI: OSX unique and maximum value {@value} */ + public static final int MAX_PIXELSCALE = 2; + /** * Called by {@link NativeWindowFactory#initSingleton()} * @see ToolkitProperties @@ -201,6 +204,20 @@ public class OSXUtil implements ToolkitProperties { } /** + * Set root and sub CALayer pixelScale / contentScale for HiDPI + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetCALayerPixelScale(final long rootCALayer, final long subCALayer, final float contentsScale) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + SetCALayerPixelScale0(rootCALayer, subCALayer, contentsScale); + } + + /** * Detach a sub CALayer from the root CALayer. */ public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) { @@ -364,6 +381,7 @@ public class OSXUtil implements ToolkitProperties { private static native long CreateCALayer0(int width, int height, float contentsScale); private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, float contentsScale, int caLayerQuirks); private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks); + private static native void SetCALayerPixelScale0(long rootCALayer, long subCALayer, float contentsScale); private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(Runnable runnable); |