Skip to content

Commit

Permalink
iOS: Clean up promotion of EAGLLayer use down to FBObject
Browse files Browse the repository at this point in the history
Initial commit bba73bc hacked
its path using a context global EGLLayer instance attachement.
The hack was good for the first demo, however, it forbid using
other FBObjects etc on the way.

Properly specifying FBObject.Attachment.StorageDefinition,
allowing the user to inject code for selected FBO attachements
to define their storage. This might be useful for different
platforms as well - however, it is OS agnostic and instance specific now.

In this sense, GLFBODrawableImpl, hosting FBObject,
has a more specific instance of FBObject.Attachment.StorageDefinition
for color-renderbuffer. It is passed along newly created color renderbuffer.

GLDrawableFactoryImpl.createGLDrawable uses a derived interface,
OnscreenFBOColorbufferStorageDefinition which is defined in
IOSEAGLDrawableFactory and return by its getter.
GLDrawableFactoryImpl.createGLDrawable is therefor platform agnostic again.

Bottom line is, as more platforms will be added, these semi-public interfaces
have to adapt to suit them all ..

All this due to iOS architecture for 'onscreen rendering' using a FBO
which shares its color renderbuffer storage with the EAGLLayer,
associated with the UIView. A bit weird maybe in first sight,
but efficient for creating cheap hardware design ;-)
Only criticism here is that Apple didn't bother using EGL and an extension.
  • Loading branch information
sgothel committed Jun 24, 2019
1 parent bba73bc commit 203f795
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 150 deletions.
24 changes: 16 additions & 8 deletions src/demos/com/jogamp/opengl/demos/ios/Hello.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import com.jogamp.common.GlueGenVersion;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.demos.es2.RedSquareES2;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.AnimatorBase;

import jogamp.nativewindow.WrappedWindow;
import jogamp.nativewindow.ios.IOSUtil;
Expand All @@ -61,9 +63,9 @@ private static int parseInt(final String s, final int def) {

public static void main(final String[] args) {
int width = 832, height = 480; // ipad pro 11: 2388x1668 px (scale: 2)
int fboDepthBits = 0; // CAEAGLLayer fails with depth 16 + 24 in Simulation
int fboDepthBits = -1; // CAEAGLLayer fails with depth 16 + 24 in Simulation; -1 means don't change
boolean exitJVM = false;
String demoName = "com.jogamp.opengl.demos.es2.LandscapeES2";
String demoName = "com.jogamp.opengl.demos.es2.GearsES2";
for(int i=0; i<args.length; i++) {
if(args[i].equals("-exit")) {
exitJVM = true;
Expand Down Expand Up @@ -119,9 +121,9 @@ public static void main(final String[] args) {
// 1) Config ..
final GLProfile glp = GLProfile.getGL2ES2();
final GLCapabilities reqCaps = new GLCapabilities(glp);
reqCaps.setOnscreen(true);
reqCaps.setDoubleBuffered(false);
reqCaps.setDepthBits(fboDepthBits);
if( 0 <= fboDepthBits) {
reqCaps.setDepthBits(fboDepthBits);
}
System.out.println("Requested GL Caps: "+reqCaps);
final GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactory(glp);

Expand Down Expand Up @@ -170,14 +172,20 @@ protected void destroyImplInLock() {
System.out.println("Choosen demo "+demo.getClass().getName());
glad.addGLEventListener(demo);

for(int i=0; i<60*10; i++) { // 10s w/ 60fps
glad.display(); // force native context creation
final Animator animator = new Animator();
// animator.setExclusiveContext(exclusiveContext);
animator.setUpdateFPSFrames(60, System.err);
animator.add(glad);
animator.start();

for(int i=0; i<10; i++) { // 10s
try {
Thread.sleep(16);
Thread.sleep(1000);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
animator.stop();

} finally {
if( null != glad ) {
Expand Down
112 changes: 61 additions & 51 deletions src/jogl/classes/com/jogamp/opengl/FBObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import com.jogamp.opengl.GLProfile;

import jogamp.opengl.Debug;
import jogamp.opengl.ios.eagl.EAGL;

import com.jogamp.common.ExceptionUtils;
import com.jogamp.common.util.PropertyAccess;
Expand Down Expand Up @@ -165,6 +164,32 @@ public static Type determine(final int format) throws IllegalArgumentException {
}
}
};
/**
* Interface abstraction to allow custom definitions of {@link Attachment}'s storage.
* <p>
* Please see {@link #setStorage(GL, Attachment)} for details.
* </p>
*/
public static interface StorageDefinition {
/**
* Set or create the {@link Attachment}'s storage after generating its name and binding it to the target.
* Typical examples for standard definitions as implemented in {@link Attachment} specializations are:
* <pre>
* // Renderbuffer (Color, Debt, Stencil, ..) storage definition w/o multisamples
* gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, a.format, a.getWidth(), a.getHeight());
* // Renderbuffer (Color, Debt, Stencil, ..) storage definition with multisamples
* gl.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, a.format, a.getWidth(), a.getHeight());
* // TextureAttachment
* gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, format, getWidth(), getHeight(), 0, dataFormat, dataType, null);
* </pre>
* The storage is setup within {@link Attachment#initialize(GL)} and hence the {@link Attachment}
* instance's {@link Attachment#setStorageDefinition(StorageDefinition)}.
*
* @param gl current {@link GL} instance
* @param a instance of the {@link Attachment} this {@link StorageDefinition} has been assigned to via {@link Attachment#setStorageDefinition(StorageDefinition)}.
*/
public void setStorage(final GL gl, final Attachment a);
}

/** immutable type [{@link #COLOR}, {@link #DEPTH}, {@link #STENCIL}, {@link #COLOR_TEXTURE}, {@link #DEPTH_TEXTURE}, {@link #STENCIL_TEXTURE} ] */
public final Type type;
Expand All @@ -176,6 +201,9 @@ public static Type determine(final int format) throws IllegalArgumentException {

private int name;

/** Every implementation needs to have set their default instance via {@link #setStorageDefinition(StorageDefinition). */
private StorageDefinition storageDefinition;

protected Attachment(final Type type, final int iFormat, final int width, final int height, final int name) {
this.type = type;
this.format = iFormat;
Expand All @@ -184,6 +212,17 @@ protected Attachment(final Type type, final int iFormat, final int width, final
this.name = name;
}

/**
* Override implementation default {@link StorageDefinition}
* @see {@link StorageDefinition#setStorage(GL, Attachment)}
*/
public void setStorageDefinition(final StorageDefinition sd) { this.storageDefinition = sd; }

/**
* Accessor to call {@link StorageDefinition#setStorage(GL, Attachment)} within {@link #initialize(GL)} for implementations of {@link Attachment}.
*/
protected final void setStorage(final GL gl) { storageDefinition.setStorage(gl, this); }

/**
* Writes the internal format to the given GLCapabilities object.
* @param caps the destination for format bits
Expand Down Expand Up @@ -372,6 +411,7 @@ public static class RenderAttachment extends Attachment {
*/
public RenderAttachment(final Type type, final int iFormat, final int samples, final int width, final int height, final int name) {
super(validateType(type), iFormat, width, height, name);
this.setStorageDefinition(defStorageDefinition);
this.samples = samples;
}

Expand Down Expand Up @@ -432,11 +472,7 @@ public boolean initialize(final GL gl) throws GLException {
setName(name[0]);

gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, getName());
if( samples > 0 ) {
((GL2ES3)gl).glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, format, getWidth(), getHeight());
} else {
gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, getWidth(), getHeight());
}
setStorage(gl);
if( checkError ) {
final int glerr = gl.glGetError();
if(GL.GL_NO_ERROR != glerr) {
Expand All @@ -451,6 +487,16 @@ public boolean initialize(final GL gl) throws GLException {
}
return init;
}
private final StorageDefinition defStorageDefinition = new StorageDefinition() {
@Override
public void setStorage(final GL gl, final Attachment a) {
// a == this.super for this instance
if( samples > 0 ) {
gl.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, format, getWidth(), getHeight());
} else {
gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, getWidth(), getHeight());
}
} };

@Override
public void free(final GL gl) {
Expand Down Expand Up @@ -482,49 +528,6 @@ public ColorAttachment(final int iFormat, final int samples, final int width, fi
public final TextureAttachment getTextureAttachment() { throw new GLException("Not a TextureAttachment, but ColorAttachment"); }
@Override
public final ColorAttachment getColorAttachment() { return this; }

@Override
public boolean initialize(final GL gl) throws GLException {
final boolean init = 0 == getName();
if( init ) {
final boolean checkError = DEBUG || GLContext.DEBUG_GL;
if( checkError ) {
checkPreGLError(gl);
}
final int[] name = new int[] { -1 };
gl.glGenRenderbuffers(1, name, 0);
setName(name[0]);

gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, getName());
if( getSamples() > 0 ) {
((GL2ES3)gl).glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, getSamples(), format, getWidth(), getHeight());
} else {
// FIXME: Need better way to inject the IOS EAGL Layer into FBObject
// FIXME: May want to implement optional injection of a BufferStorage SPI?
final GLContext ctx = gl.getContext();
final Long iosEAGLLayer = (Long) ctx.getAttachedObject("IOS_EAGL_LAYER");
if( null != iosEAGLLayer ) {
EAGL.eaglBindDrawableStorageToRenderbuffer(gl.getContext().contextHandle, GL.GL_RENDERBUFFER, iosEAGLLayer.longValue());
} else {
gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, getWidth(), getHeight());
}
}
if( checkError ) {
final int glerr = gl.glGetError();
if(GL.GL_NO_ERROR != glerr) {
gl.glDeleteRenderbuffers(1, name, 0);
setName(0);
throw new GLException("GL Error "+toHexString(glerr)+" while creating "+this);
}
}
if(DEBUG) {
System.err.println("Attachment.init.X: "+this);
}
}
return init;
}


}

/** Texture FBO attachment */
Expand All @@ -548,6 +551,7 @@ public static class TextureAttachment extends Attachment implements Colorbuffer
public TextureAttachment(final Type type, final int iFormat, final int width, final int height, final int dataFormat, final int dataType,
final int magFilter, final int minFilter, final int wrapS, final int wrapT, final int name) {
super(validateType(type), iFormat, width, height, name);
this.setStorageDefinition(defStorageDefinition);
this.dataFormat = dataFormat;
this.dataType = dataType;
this.magFilter = magFilter;
Expand Down Expand Up @@ -604,7 +608,7 @@ public boolean initialize(final GL gl) throws GLException {
int glerr = gl.glGetError();
if(GL.GL_NO_ERROR == glerr) {
preTexImage2D = false;
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, format, getWidth(), getHeight(), 0, dataFormat, dataType, null);
setStorage(gl);
glerr = gl.glGetError();
}
if(GL.GL_NO_ERROR != glerr) {
Expand All @@ -613,14 +617,20 @@ public boolean initialize(final GL gl) throws GLException {
throw new GLException("GL Error "+toHexString(glerr)+" while creating (pre TexImage2D "+preTexImage2D+") "+this);
}
} else {
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, format, getWidth(), getHeight(), 0, dataFormat, dataType, null);
setStorage(gl);
}
if(DEBUG) {
System.err.println("Attachment.init.X: "+this);
}
}
return init;
}
private final StorageDefinition defStorageDefinition = new StorageDefinition() {
@Override
public void setStorage(final GL gl, final Attachment a) {
// a == this.super for this instance
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, format, getWidth(), getHeight(), 0, dataFormat, dataType, null);
} };

@Override
public void free(final GL gl) {
Expand Down
Loading

0 comments on commit 203f795

Please sign in to comment.