aboutsummaryrefslogtreecommitdiffstats
path: root/src/nativewindow
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-06-08 08:11:57 +0200
committerSven Gothel <[email protected]>2014-06-08 08:11:57 +0200
commit2571ed0b5ef14155d204540d38b564a7d4cd47b6 (patch)
tree8aaf1171af1b95f1cb1ebe706771a4aff3752c2f /src/nativewindow
parentff7bf3122fd2007bbe70cfadca9f0f978ee96456 (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')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java104
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java80
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java175
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java59
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java26
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java18
-rw-r--r--src/nativewindow/native/macosx/OSXmisc.m41
7 files changed, 452 insertions, 51 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
index 690d77901..efe9409ac 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
@@ -61,6 +61,7 @@ import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.OffscreenLayerOption;
import javax.media.nativewindow.OffscreenLayerSurface;
+import javax.media.nativewindow.ScalableSurface;
import javax.media.nativewindow.SurfaceUpdatedListener;
import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
@@ -70,13 +71,14 @@ import javax.media.nativewindow.util.PointImmutable;
import javax.media.nativewindow.util.Rectangle;
import javax.media.nativewindow.util.RectangleImmutable;
+import jogamp.nativewindow.SurfaceScaleUtils;
import jogamp.nativewindow.SurfaceUpdatedHelper;
import jogamp.nativewindow.awt.AWTMisc;
import jogamp.nativewindow.jawt.JAWT;
import jogamp.nativewindow.jawt.JAWTUtil;
import jogamp.nativewindow.jawt.JAWT_Rectangle;
-public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption {
+public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption, ScalableSurface {
protected static final boolean DEBUG = JAWTUtil.DEBUG;
// user properties
@@ -98,7 +100,10 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
protected Rectangle bounds;
protected Insets insets;
private volatile long offscreenSurfaceLayer;
- private volatile int pixelScale;
+
+ private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+
private long drawable_old;
/**
@@ -122,7 +127,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
invalidate();
this.isApplet = false;
this.offscreenSurfaceLayer = 0;
- this.pixelScale = 1;
}
private static String id(Object obj) { return ( null!=obj ? toHexString(obj.hashCode()) : "nil" ); }
private String jawtStr() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; }
@@ -260,22 +264,37 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
drawable_old = 0;
bounds = new Rectangle();
insets = new Insets();
- pixelScale = 1;
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
}
protected abstract void invalidateNative();
/**
+ * {@inheritDoc}
+ * <p>
+ * Per default impl. only works for not yet {@link #isRealized() realized} instances,
+ * current exception OSX.
+ * </p>
+ */
+ @Override
+ public void setSurfaceScale(final int[] pixelScale) {
+ SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null);
+ }
+
+ @Override
+ public final int[] getSurfaceScale(final int[] result) {
+ // 0 != drawable -> locked at least once !
+ System.arraycopy(0 != drawable ? hasPixelScale : reqPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ /**
* Updates bounds and pixelScale
+ * @return true if bounds or pixelScale has changed, otherwise false
*/
protected final boolean updateLockedData(JAWT_Rectangle jawtBounds) {
final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
- final int newPixelScale;
- {
- final int s = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
- newPixelScale = 0 < s ? s : 1;
- }
final boolean changedBounds = !bounds.equals(jb);
- final boolean changedPixelScale = newPixelScale != pixelScale;
if( changedBounds ) {
if( DEBUG ) {
@@ -288,20 +307,31 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
}
}
- if( changedPixelScale ) {
- if( DEBUG ) {
- System.err.println("JAWTWindow.updatePixelScale: "+pixelScale+" -> "+newPixelScale);
- }
- pixelScale = newPixelScale;
+
+ return updatePixelScale() || changedBounds;
+ }
+
+ /**
+ * Update pixelScale
+ * @return true if pixelScale has changed, otherwise false
+ */
+ protected final boolean updatePixelScale() {
+ final int[] pixelScaleInt;
+ {
+ final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
+ pixelScaleInt = new int[] { ps, ps };
}
- return changedBounds || changedPixelScale;
+ return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
}
/** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */
public final RectangleImmutable getBounds() { return bounds; }
- /** @return the safe pixelScale value, i.e. never negative or zero. Updated with lock. */
- public final int getPixelScale() { return pixelScale; }
+ /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */
+ protected final int getPixelScaleX() { return hasPixelScale[0]; }
+
+ /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */
+ protected final int getPixelScaleY() { return hasPixelScale[1]; }
@Override
public final InsetsImmutable getInsets() { return insets; }
@@ -625,12 +655,26 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
@Override
public final int getSurfaceWidth() {
- return getWidth() * getPixelScale();
+ return getWidth() * getPixelScaleX();
}
@Override
public final int getSurfaceHeight() {
- return getHeight() * getPixelScale();
+ return getHeight() * getPixelScaleY();
+ }
+
+ @Override
+ public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
+ pixelUnitsAndResult[0] /= getPixelScaleX();
+ pixelUnitsAndResult[1] /= getPixelScaleY();
+ return pixelUnitsAndResult;
+ }
+
+ @Override
+ public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
+ windowUnitsAndResult[0] *= getPixelScaleX();
+ windowUnitsAndResult[1] *= getPixelScaleY();
+ return windowUnitsAndResult;
}
@Override
@@ -651,22 +695,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
@Override
- public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
- final int scale = getPixelScale();
- pixelUnitsAndResult[0] /= scale;
- pixelUnitsAndResult[1] /= scale;
- return pixelUnitsAndResult;
- }
-
- @Override
- public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
- final int scale = getPixelScale();
- windowUnitsAndResult[0] *= scale;
- windowUnitsAndResult[1] *= scale;
- return windowUnitsAndResult;
- }
-
- @Override
public void destroy() {
surfaceLock.lock();
try {
@@ -810,7 +838,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)).
append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()).
append(", bounds ").append(bounds).append(", insets ").append(insets).
- append(", pixelScale ").append(getPixelScale());
+ append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY());
} else {
sb.append("JAWT n/a, bounds ").append(bounds).append(", insets ").append(insets);
}
@@ -830,7 +858,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
", bounds "+bounds+", insets "+insets
);
sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
- "], pixels[x"+getPixelScale()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
+ "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
", visible "+component.isVisible());
sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+
",\n\tconfig "+config+
diff --git a/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java
new file mode 100644
index 000000000..024f22bc9
--- /dev/null
+++ b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java
@@ -0,0 +1,80 @@
+/**
+ * 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 javax.media.nativewindow;
+
+/**
+ * Adding mutable surface pixel scale property to implementing class, usually to a {@link NativeSurface} implementation,
+ * see {@link #setSurfaceScale(int[])}.
+ */
+public interface ScalableSurface {
+ /** Setting surface-pixel-scale of {@value}, results in same pixel- and window-units. */
+ public static final int IDENTITY_PIXELSCALE = 1;
+ /** Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale, i.e. pixel-units >> window-units where available. */
+ public static final int AUTOMAX_PIXELSCALE = 0;
+
+ /**
+ * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}.
+ * <p>
+ * Default pixel scale request for both directions is {@link #AUTOMAX_PIXELSCALE}.
+ * </p>
+ * <p>
+ * In case platform only supports uniform pixel scale, i.e. one scale for both directions,
+ * either {@link #AUTOMAX_PIXELSCALE} or the maximum requested pixel scale component is used.
+ * </p>
+ * <p>
+ * The <i>requested</i> pixel scale will be validated against platform limits before native scale-setup,
+ * i.e. clipped to {@link #IDENTITY_PIXELSCALE} if not supported or the platform maximum.
+ * </p>
+ * <p>
+ * The actual <i>realized</i> pixel scale values of the {@link NativeSurface}
+ * can be queried via {@link #getSurfaceScale(int[])} or
+ * computed via <code>surface.{@link NativeSurface#convertToPixelUnits(int[]) convertToPixelUnits}(new int[] { 1, 1 })</code>
+ * </p>
+ *
+ * @param pixelScale <i>requested</i> surface pixel scale int[2] values for x- and y-direction.
+ */
+ public void setSurfaceScale(final int[] pixelScale);
+
+ /**
+ * Returns the pixel scale of the associated {@link NativeSurface}.
+ * <p>
+ * In case the {@link NativeSurface} is not yet realized, method returns the
+ * requested pixel scale as validated via {@link #setSurfaceScale(int[])}
+ * if called earlier or the implementation default, usually {@link #AUTOMAX_PIXELSCALE}.
+ * </p>
+ * <p>
+ * In case the {@link NativeSurface} is already realized, method returns the
+ * actual used pixel scale.
+ * </p>
+ * @param result int[2] storage for the result
+ * @return the passed storage for chaining
+ */
+ public int[] getSurfaceScale(final int[] result);
+}
+
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);
diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m
index 62d3d67bb..fa3bf026a 100644
--- a/src/nativewindow/native/macosx/OSXmisc.m
+++ b/src/nativewindow/native/macosx/OSXmisc.m
@@ -639,13 +639,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0
if(0 == width) { width = 32; }
if(0 == height) { height = 32; }
- if( 1.0 != contentsScale ) {
NS_DURING
- // Available >= 10.7
- [layer setContentsScale: (CGFloat)contentsScale];
+ // Available >= 10.7
+ [layer setContentsScale: (CGFloat)contentsScale];
NS_HANDLER
NS_ENDHANDLER
- }
// initial dummy size !
CGRect lFrame = [layer frame];
@@ -692,12 +690,10 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0
caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount],
lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (float)contentsScale);
- if( 1.0 != contentsScale ) {
NS_DURING
- [subLayer setContentsScale: (CGFloat)contentsScale];
+ [subLayer setContentsScale: (CGFloat)contentsScale];
NS_HANDLER
NS_ENDHANDLER
- }
[subLayer setFrame:lRectRoot];
[rootLayer addSublayer:subLayer];
@@ -753,6 +749,37 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0
/*
* Class: Java_jogamp_nativewindow_macosx_OSXUtil
+ * Method: SetCALayerPixelScale0
+ * Signature: (JJF)V
+ */
+JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_SetCALayerPixelScale0
+ (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer);
+ if( NULL == rootLayer ) {
+ NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null");
+ }
+ CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer);
+
+ [CATransaction begin];
+ [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+
+NS_DURING
+ [rootLayer setContentsScale: (CGFloat)contentsScale];
+ if( NULL != subLayer ) {
+ [subLayer setContentsScale: (CGFloat)contentsScale];
+ }
+NS_HANDLER
+NS_ENDHANDLER
+
+ [CATransaction commit];
+
+ [pool release];
+}
+
+/*
+ * Class: Java_jogamp_nativewindow_macosx_OSXUtil
* Method: RemoveCASublayer0
* Signature: (JJ)V
*/