Updating GL context reference in offscreen surfaces

This commit is contained in:
codeanticode
2011-07-04 08:24:04 +00:00
parent 3f10ae3a8d
commit 7f4b1ef45b
5 changed files with 244 additions and 110 deletions
@@ -70,7 +70,7 @@ class PFontTexture implements PConstants {
// contains any native OpenGL resources, it does contains a list of textures
// that don't depend on any PImage, so it is registered so in the case of a refresh
// event the textures are re-initialized with the correct data.
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
initTexture(maxw, maxh);
}
@@ -80,7 +80,7 @@ class PFontTexture implements PConstants {
for (int i = 0; i < textures.length; i++) {
textures[i].delete();
}
ogl.unregisterGLObject(this);
ogl.unregisterPGLObject(this);
}
@@ -73,7 +73,7 @@ public class PFramebuffer implements PConstants {
this(parent, w, h, 1, 1, 0, 0, false, false);
}
PFramebuffer(PApplet parent, int w, int h, boolean screen) {
PFramebuffer(PApplet parent, int w, int h, boolean screen) {
this(parent, w, h, 1, 1, 0, 0, false, screen);
}
@@ -82,7 +82,7 @@ public class PFramebuffer implements PConstants {
boolean screen) {
this.parent = parent;
ogl = (PGraphicsOpenGL)parent.g;
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
glFboID = 0;
glDepthBufferID = 0;
@@ -92,6 +92,13 @@ public class PFramebuffer implements PConstants {
fboMode = PGraphicsOpenGL.fboSupported;
if (screen) {
// If this framebuffer is used to represent a on-screen buffer,
// then it doesn't make it sense for it to have multisampling,
// color, depth or stencil buffers.
depthBits = stencilBits = samples = colorBuffers = 0;
}
width = w;
height = h;
@@ -150,7 +157,7 @@ public class PFramebuffer implements PConstants {
for (int i = 0; i < numColorBuffers; i++) {
colorBufferTex[i] = null;
}
ogl.unregisterGLObject(this);
ogl.unregisterPGLObject(this);
}
public void backup() {
@@ -230,7 +237,8 @@ public class PFramebuffer implements PConstants {
// Saves content of the screen into the backup texture.
public void backupScreen() {
if (pixelBuffer == null) createPixelBuffer();
if (pixelBuffer == null) createPixelBuffer();
pixelBuffer.rewind();
getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer);
copyToTexture(pixelBuffer, backupTexture.glID, backupTexture.glTarget);
}
@@ -243,6 +251,7 @@ public class PFramebuffer implements PConstants {
// Copies current content of screen to color buffers.
public void copyToColorBuffers() {
if (pixelBuffer == null) createPixelBuffer();
pixelBuffer.rewind();
getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer);
for (int i = 0; i < numColorBuffers; i++) {
copyToTexture(pixelBuffer, colorBufferTex[i].glID, colorBufferTex[i].glTarget);
@@ -251,6 +260,7 @@ public class PFramebuffer implements PConstants {
public void readPixels() {
if (pixelBuffer == null) createPixelBuffer();
pixelBuffer.rewind();
getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer);
}
@@ -311,10 +321,7 @@ public class PFramebuffer implements PConstants {
colorBufferTex[i].glTarget, colorBufferTex[i].glID, 0);
}
if (validFbo() && textures != null && 0 < textures.length) {
width = textures[0].glWidth;
height = textures[0].glHeight;
}
validateFbo();
ogl.popFramebuffer();
}
@@ -542,7 +549,7 @@ public class PFramebuffer implements PConstants {
getGl().glDisable(gltarget);
}
public boolean validFbo() {
public boolean validateFbo() {
int status = getGl().glCheckFramebufferStatus(GL.GL_FRAMEBUFFER);
if (status == GL.GL_FRAMEBUFFER_COMPLETE) {
return true;
@@ -160,7 +160,11 @@ public class PGraphicsOpenGL extends PGraphics {
static protected final int GL_FRAME_BUFFER = 2;
static protected final int GL_RENDER_BUFFER = 3;
static protected Set<Object> glObjects = new HashSet<Object>();
static protected Set<PGraphicsOpenGL> pGraphicsOpenGLObjects = new HashSet<PGraphicsOpenGL>();
static protected Set<PTexture> pTextureObjects = new HashSet<PTexture>();
static protected Set<PFramebuffer> pFramebufferObjects = new HashSet<PFramebuffer>();
static protected Set<PShape3D> pShape3DObjects = new HashSet<PShape3D>();
static protected Set<PFontTexture> pFontTextureObjects = new HashSet<PFontTexture>();
static protected Set<Integer> glTextureObjects = new HashSet<Integer>();
static protected Set<Integer> glVertexBuffers = new HashSet<Integer>();
static protected Set<Integer> glFrameBuffers = new HashSet<Integer>();
@@ -680,7 +684,8 @@ public class PGraphicsOpenGL extends PGraphics {
// that the context has been re-created, so we need to re-allocate them in
// order to be able to keep using them. This step doesn't refresh their data, this
// is, they are empty after re-allocation.
allocateGLObjects();
//getGLObjects();
//allocateGLObjects();
} else {
reapplySettings();
}
@@ -689,6 +694,9 @@ public class PGraphicsOpenGL extends PGraphics {
if (context == null) {
initOffscreen();
} else {
// Updating OpenGL context associated to this offscreen
// surface, to take into account a context recreation situation.
updateOffscreenContext();
reapplySettings();
}
}
@@ -702,7 +710,13 @@ public class PGraphicsOpenGL extends PGraphics {
super.delete();
if (offscreenFramebuffer != null) {
offscreenFramebuffer.delete();
offscreenFramebuffer = null;
}
if (offscreenFramebufferMultisample != null) {
offscreenFramebufferMultisample.delete();
offscreenFramebufferMultisample = null;
}
unregisterPGLObject(this);
}
}
@@ -719,74 +733,160 @@ public class PGraphicsOpenGL extends PGraphics {
// RESOURCE HANDLING
protected void allocateGLObjects() {
if (!glObjects.isEmpty()) {
Object[] globjs = glObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
if (globjs[i] instanceof PTexture) {
((PTexture)globjs[i]).allocate();
} else if (globjs[i] instanceof PShape3D) {
((PShape3D)globjs[i]).allocate();
} else if (globjs[i] instanceof PFramebuffer) {
((PFramebuffer)globjs[i]).allocate();
} else if (globjs[i] instanceof PFontTexture) {
((PFontTexture)globjs[i]).allocate();
}
}
}
protected void allocatePGLObjects() {
// Note: it is important that allocation / backup / restoration are don
// in the order below (0: PGraphicsOpenGL, 1: PTexture objects, 2: PFramebuffer
// objects, etc.) since both PFramebuffers and PShape3Ds might need a valid PTexture
// for their re-allocation.
// The case of PGraphicsOpenGL is special, the list is only stores offscreen surfaces
// in order to call allocate() upon context re-creation. allocate() for non-primary
// surfaces ends up just updating the context associated to them.
if (!pGraphicsOpenGLObjects.isEmpty()) {
Object[] globjs = pGraphicsOpenGLObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PGraphicsOpenGL obj = (PGraphicsOpenGL)globjs[i];
obj.allocate();
}
}
if (!pTextureObjects.isEmpty()) {
Object[] globjs = pTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PTexture obj = (PTexture)globjs[i];
obj.allocate();
}
}
if (!pFramebufferObjects.isEmpty()) {
Object[] globjs = pFramebufferObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFramebuffer obj = (PFramebuffer)globjs[i];
obj.allocate();
}
}
if (!pShape3DObjects.isEmpty()) {
Object[] globjs = pShape3DObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PShape3D obj = (PShape3D)globjs[i];
obj.allocate();
}
}
if (!pFontTextureObjects.isEmpty()) {
Object[] globjs = pFontTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFontTexture obj = (PFontTexture)globjs[i];
obj.allocate();
}
}
}
protected void backupGLObjects() {
if (!glObjects.isEmpty()) {
Object[] globjs = glObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
if (globjs[i] instanceof PTexture) {
((PTexture)globjs[i]).backup();
} else if (globjs[i] instanceof PShape3D) {
((PShape3D)globjs[i]).backup();
} else if (globjs[i] instanceof PFramebuffer) {
((PFramebuffer)globjs[i]).backup();
} else if (globjs[i] instanceof PFontTexture) {
((PFontTexture)globjs[i]).backup();
}
}
}
protected void backupPGLObjects() {
if (!pTextureObjects.isEmpty()) {
Object[] globjs = pTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PTexture obj = (PTexture)globjs[i];
obj.backup();
}
}
if (!pFramebufferObjects.isEmpty()) {
Object[] globjs = pFramebufferObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFramebuffer obj = (PFramebuffer)globjs[i];
obj.backup();
}
}
if (!pShape3DObjects.isEmpty()) {
Object[] globjs = pShape3DObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PShape3D obj = (PShape3D)globjs[i];
obj.backup();
}
}
if (!pFontTextureObjects.isEmpty()) {
Object[] globjs = pFontTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFontTexture obj = (PFontTexture)globjs[i];
obj.backup();
}
}
}
protected void clearGLFramebuffers() {
if (!glObjects.isEmpty()) {
Object[] globjs = glObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
if (globjs[i] instanceof PFramebuffer) {
((PFramebuffer)globjs[i]).clear();
}
}
}
protected void clearPGLFramebuffers() {
if (!pFramebufferObjects.isEmpty()) {
Object[] globjs = pFramebufferObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFramebuffer obj = (PFramebuffer)globjs[i];
obj.clear();
}
}
}
protected void restoreGLObjects() {
if (!glObjects.isEmpty()) {
Object[] globjs = glObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
if (globjs[i] instanceof PTexture) {
((PTexture)globjs[i]).restore();
} else if (globjs[i] instanceof PShape3D) {
((PShape3D)globjs[i]).restore();
} else if (globjs[i] instanceof PFramebuffer) {
((PFramebuffer)globjs[i]).restore();
} else if (globjs[i] instanceof PFontTexture) {
((PFontTexture)globjs[i]).restore();
}
}
protected void restorePGLObjects() {
if (!pTextureObjects.isEmpty()) {
Object[] globjs = pTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PTexture obj = (PTexture)globjs[i];
obj.restore();
}
}
if (!pFramebufferObjects.isEmpty()) {
Object[] globjs = pFramebufferObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFramebuffer obj = (PFramebuffer)globjs[i];
obj.restore();
}
}
if (!pShape3DObjects.isEmpty()) {
Object[] globjs = pShape3DObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PShape3D obj = (PShape3D)globjs[i];
obj.restore();
}
}
if (!pFontTextureObjects.isEmpty()) {
Object[] globjs = pFontTextureObjects.toArray();
for (int i = 0; i < globjs.length; i++) {
PFontTexture obj = (PFontTexture)globjs[i];
obj.restore();
}
}
}
protected void registerPGLObject(Object obj) {
if (obj instanceof PGraphicsOpenGL) {
pGraphicsOpenGLObjects.add((PGraphicsOpenGL)obj);
} else if (obj instanceof PTexture) {
pTextureObjects.add((PTexture)obj);
} else if (obj instanceof PFramebuffer) {
pFramebufferObjects.add((PFramebuffer)obj);
} else if (obj instanceof PShape3D) {
pShape3DObjects.add((PShape3D)obj);
} else if (obj instanceof PFontTexture) {
pFontTextureObjects.add((PFontTexture)obj);
}
}
protected void registerGLObject(Object obj) {
glObjects.add(obj);
}
protected void unregisterGLObject(Object obj) {
glTextureObjects.remove(obj);
protected void unregisterPGLObject(Object obj) {
if (obj instanceof PGraphicsOpenGL) {
pGraphicsOpenGLObjects.remove(obj);
} else if (obj instanceof PTexture) {
pTextureObjects.remove(obj);
} else if (obj instanceof PFramebuffer) {
pFramebufferObjects.remove(obj);
} else if (obj instanceof PShape3D) {
pShape3DObjects.remove(obj);
} else if (obj instanceof PFontTexture) {
pFontTextureObjects.remove(obj);
}
}
protected int createGLResource(int type) {
@@ -966,7 +1066,27 @@ public class PGraphicsOpenGL extends PGraphics {
context.release();
}
/**
* Destroys current OpenGL context and creates a new one, making sure that all
* the current OpenGL objects remain valid afterward.
*/
public void restartContext() {
backupPGLObjects();
releaseContext();
context.destroy();
context = null;
allocate();
detainContext();
getGLProfiles();
allocatePGLObjects();
clearPGLFramebuffers();
restorePGLObjects();
}
/**
* OpenGL cannot draw until a proper native peer is available, so this
* returns the value of PApplet.isDisplayable() (inherited from Component).
@@ -988,7 +1108,7 @@ public class PGraphicsOpenGL extends PGraphics {
detainContext();
}
getGLObjects();
getGLProfiles();
if (!glParamsRead) {
getGLParameters();
@@ -1171,16 +1291,16 @@ public class PGraphicsOpenGL extends PGraphics {
public void allocateGL() {
allocateGLObjects();
allocatePGLObjects();
}
public void backupGL() {
backupGLObjects();
backupPGLObjects();
}
public void restoreGL() {
clearGLFramebuffers();
restoreGLObjects();
clearPGLFramebuffers();
restorePGLObjects();
}
protected void saveGLState() {
@@ -1370,12 +1490,7 @@ public class PGraphicsOpenGL extends PGraphics {
} else if (which == DISABLE_OPENGL_2X_SMOOTH) {
if (opengl2X) {
if (primarySurface) {
backupGL();
releaseContext();
context.destroy();
context = null;
allocate();
restoreGL();
restartContext();
throw new PApplet.RendererChangeException();
} else {
initOffscreen();
@@ -1383,17 +1498,19 @@ public class PGraphicsOpenGL extends PGraphics {
}
} else if (which == ENABLE_OPENGL_2X_SMOOTH) {
// do nothing, this is the default in release 0158 and later
if (!opengl2X) {
if (primarySurface) {
restartContext();
throw new PApplet.RendererChangeException();
} else {
initOffscreen();
}
}
} else if (which == ENABLE_OPENGL_4X_SMOOTH) {
if (!opengl4X) {
if (primarySurface) {
backupGL();
releaseContext();
context.destroy();
context = null;
allocate();
restoreGL();
restartContext();
throw new PApplet.RendererChangeException();
} else {
initOffscreen();
@@ -1402,6 +1519,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
//////////////////////////////////////////////////////////////
@@ -5757,8 +5875,7 @@ return width * (1 + ox) / 2.0f;
public void loadPixels() {
if ((pixels == null) || (pixels.length != width * height)) {
pixels = new int[width * height];
pixelBuffer = IntBuffer.allocate(pixels.length);
pixelBuffer.rewind();
pixelBuffer = IntBuffer.allocate(pixels.length);
}
boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer;
@@ -5767,14 +5884,14 @@ return width * (1 + ox) / 2.0f;
setFramebuffer(offscreenFramebuffer);
}
pixelBuffer.rewind();
gl.glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer);
if (notCurrent) {
popFramebuffer();
}
}
pixelBuffer.get(pixels);
pixelBuffer.rewind();
// flip vertically (opengl stores images upside down),
// and swap RGBA components to ARGB (big endian)
@@ -6154,8 +6271,7 @@ return width * (1 + ox) / 2.0f;
public int get(int x, int y) {
if (getsetBuffer == null) {
getsetBuffer = IntBuffer.allocate(1);
getsetBuffer.rewind();
getsetBuffer = IntBuffer.allocate(1);
}
boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer;
@@ -6168,6 +6284,7 @@ return width * (1 + ox) / 2.0f;
setFramebuffer(offscreenFramebuffer);
}
getsetBuffer.rewind();
gl.glReadPixels(x, height - y - 1, 1, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, getsetBuffer);
if (notCurrent) {
@@ -6199,6 +6316,7 @@ return width * (1 + ox) / 2.0f;
setFramebuffer(offscreenFramebuffer);
}
newbieBuffer.rewind();
gl.glReadPixels(x, height - y - h, w, h, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, newbieBuffer);
if (notCurrent) {
@@ -7105,7 +7223,6 @@ return width * (1 + ox) / 2.0f;
context = drawable.createContext(null);
}
protected void initOffscreen() {
// Getting the context and capabilities from the main renderer.
ogl = (PGraphicsOpenGL)parent.g;
@@ -7114,7 +7231,9 @@ return width * (1 + ox) / 2.0f;
capabilities = ogl.getCapabilities();
drawable = null;
getGLObjects();
registerPGLObject(this);
getGLProfiles();
loadTextureImpl(BILINEAR);
// In case of reinitialization (for example, when the smooth level
@@ -7163,7 +7282,15 @@ return width * (1 + ox) / 2.0f;
offscreenFramebuffer.clear();
}
protected void getGLObjects() {
protected void updateOffscreenContext() {
context = ogl.getContext();
capabilities = ogl.getCapabilities();
drawable = null;
getGLProfiles();
}
protected void getGLProfiles() {
gl = context.getGL();
if (pipeline == PROG_GL4) {
@@ -7232,7 +7359,7 @@ return width * (1 + ox) / 2.0f;
fboSupported = true;
}
if (-1 < OPENGL_EXTENSIONS.indexOf("framebuffer_multisample")) {
fboMultisampleSupported = true;
//fboMultisampleSupported = true;
}
blendEqSupported = true;
@@ -176,7 +176,7 @@ public class PShape3D extends PShape {
this();
this.papplet = parent;
ogl = (PGraphicsOpenGL)parent.g;
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
this.family = PShape.GROUP;
this.name = "root";
@@ -190,7 +190,7 @@ public class PShape3D extends PShape {
public PShape3D(PApplet parent, String filename, Parameters params) {
this.papplet = parent;
ogl = (PGraphicsOpenGL)parent.g;
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
this.family = PShape.GROUP;
this.name = "root";
@@ -209,7 +209,7 @@ public class PShape3D extends PShape {
public PShape3D(PApplet parent, int size, Parameters params) {
this.papplet = parent;
ogl = (PGraphicsOpenGL)parent.g;
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
this.family = PShape.GROUP;
this.name = "root";
@@ -228,7 +228,7 @@ public class PShape3D extends PShape {
public void delete() {
if (root != this) return; // Can be done only from the root shape.
release();
ogl.unregisterGLObject(this);
ogl.unregisterPGLObject(this);
}
@@ -91,7 +91,7 @@ public class PTexture implements PConstants {
this.parent = parent;
ogl = (PGraphicsOpenGL)parent.g;
ogl.registerGLObject(this);
ogl.registerPGLObject(this);
glID = 0;
@@ -134,7 +134,7 @@ public class PTexture implements PConstants {
public void delete() {
release();
img = null;
ogl.unregisterGLObject(this);
ogl.unregisterPGLObject(this);
}
@@ -147,14 +147,14 @@ public class PTexture implements PConstants {
// to the pixels array.
get(img.pixels);
}
}
}
}
public void restore() {
public void restore() {
if (img != null && img.pixels != null) {
set(img.pixels);
}
}
}
////////////////////////////////////////////////////////////