Skip to content

Commit

Permalink
New hint for depth reading (see processing#2771)
Browse files Browse the repository at this point in the history
Use hint(ENABLE_DEPTH_READING) to enable depth reading while using
multisampling.
  • Loading branch information
JakubValtar committed Sep 15, 2014
1 parent bd8cf86 commit 87f1e3b
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 52 deletions.
5 changes: 4 additions & 1 deletion core/src/processing/core/PConstants.java
Expand Up @@ -493,7 +493,10 @@ public interface PConstants {
static final int ENABLE_RETINA_PIXELS = 10;
static final int DISABLE_RETINA_PIXELS = -10;

static final int HINT_COUNT = 11;
static final int ENABLE_DEPTH_READING = 11;
static final int DISABLE_DEPTH_READING = -11;

static final int HINT_COUNT = 12;

// error messages

Expand Down
144 changes: 99 additions & 45 deletions core/src/processing/opengl/PGL.java
Expand Up @@ -140,20 +140,28 @@ public abstract class PGL {
protected boolean firstFrame = true;
protected int reqNumSamples;
protected int numSamples;

protected IntBuffer glColorFbo;
protected IntBuffer glMultiFbo;
protected IntBuffer glColorBuf;
protected IntBuffer glColorTex;
protected IntBuffer glDepthStencil;
protected IntBuffer glDepth;
protected IntBuffer glStencil;

protected IntBuffer glMultiFbo;
protected IntBuffer glMultiColor;
protected IntBuffer glMultiDepthStencil;
protected IntBuffer glMultiDepth;
protected IntBuffer glMultiStencil;

protected int fboWidth, fboHeight;
protected int backTex, frontTex;

/** Flags used to handle the creation of a separate front texture */
protected boolean usingFrontTex = false;
protected boolean needSepFrontTex = false;

protected boolean depthReadingEnabled;

// ........................................................

// Texture rendering
Expand Down Expand Up @@ -281,6 +289,11 @@ public abstract class PGL {
"if using any of the built-in OpenGL renderers. If you are using a contributed " +
"library, contact the library's developers.";

protected static final String DEPTH_READING_NOT_ENABLED_ERROR =
"Reading depth and stencil values from this multisampled buffer is not enabled. " +
"You can enable it by calling hint(ENABLE_DEPTH_READING) once. " +
"If your sketch becomes too slow, disable multisampling with noSmooth() instead.";

// ........................................................

// Constants
Expand Down Expand Up @@ -327,13 +340,18 @@ public PGL(PGraphicsOpenGL pg) {
this.pg = pg;
if (glColorTex == null) {
glColorTex = allocateIntBuffer(2);

glColorFbo = allocateIntBuffer(1);
glMultiFbo = allocateIntBuffer(1);
glColorBuf = allocateIntBuffer(1);
glDepthStencil = allocateIntBuffer(1);
glDepth = allocateIntBuffer(1);
glStencil = allocateIntBuffer(1);

glMultiFbo = allocateIntBuffer(1);
glMultiColor = allocateIntBuffer(1);
glMultiDepthStencil = allocateIntBuffer(1);
glMultiDepth = allocateIntBuffer(1);
glMultiStencil = allocateIntBuffer(1);

fboLayerCreated = false;
fboLayerInUse = false;
firstFrame = false;
Expand All @@ -349,6 +367,10 @@ public void setPrimary(boolean primary) {
primaryPGL = primary;
}

public void setDepthReadingEnabled(boolean enabled) {
depthReadingEnabled = enabled;
}


/**
* Return the native canvas the OpenGL context associated to this PGL object
Expand All @@ -372,12 +394,17 @@ public void setPrimary(boolean primary) {
protected void deleteSurface() {
if (threadIsCurrent() && fboLayerCreated) {
deleteTextures(2, glColorTex);

deleteFramebuffers(1, glColorFbo);
deleteFramebuffers(1, glMultiFbo);
deleteRenderbuffers(1, glColorBuf);
deleteRenderbuffers(1, glDepthStencil);
deleteRenderbuffers(1, glDepth);
deleteRenderbuffers(1, glStencil);

deleteFramebuffers(1, glMultiFbo);
deleteRenderbuffers(1, glMultiColor);
deleteRenderbuffers(1, glMultiDepthStencil);
deleteRenderbuffers(1, glMultiDepth);
deleteRenderbuffers(1, glMultiStencil);
}

fboLayerCreated = false;
Expand Down Expand Up @@ -513,9 +540,11 @@ protected void syncBackTexture() {
if (1 < numSamples) {
bindFramebufferImpl(READ_FRAMEBUFFER, glMultiFbo.get(0));
bindFramebufferImpl(DRAW_FRAMEBUFFER, glColorFbo.get(0));
int mask = COLOR_BUFFER_BIT;
if (depthReadingEnabled) mask |= DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT;
blitFramebuffer(0, 0, fboWidth, fboHeight,
0, 0, fboWidth, fboHeight,
COLOR_BUFFER_BIT, NEAREST);
mask, NEAREST);
}
}

Expand Down Expand Up @@ -676,36 +705,68 @@ private void createFBOLayer() {
framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D,
glColorTex.get(backTex), 0);

if (!multisample || depthReadingEnabled) {
// If not multisampled, this is the only depth and stencil buffer.
// If multisampled and depth reading enabled, these are going to
// hold downsampled depth and stencil buffers.
createDepthAndStencilBuffer(false, depthBits, stencilBits, packed);
}

if (multisample) {
// Creating multisampled FBO
genFramebuffers(1, glMultiFbo);
bindFramebufferImpl(FRAMEBUFFER, glMultiFbo.get(0));

// color render buffer...
genRenderbuffers(1, glColorBuf);
bindRenderbuffer(RENDERBUFFER, glColorBuf.get(0));
genRenderbuffers(1, glMultiColor);
bindRenderbuffer(RENDERBUFFER, glMultiColor.get(0));
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
RGBA8, fboWidth, fboHeight);
framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0,
RENDERBUFFER, glColorBuf.get(0));
RENDERBUFFER, glMultiColor.get(0));

// Creating multisampled depth and stencil buffers
createDepthAndStencilBuffer(true, depthBits, stencilBits, packed);
}

validateFramebuffer();

// Clear all buffers.
clearDepth(1);
clearStencil(0);
int argb = pg.backgroundColor;
float a = ((argb >> 24) & 0xff) / 255.0f;
float r = ((argb >> 16) & 0xff) / 255.0f;
float g = ((argb >> 8) & 0xff) / 255.0f;
float b = ((argb) & 0xff) / 255.0f;
clearColor(r, g, b, a);
clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT);

bindFramebufferImpl(FRAMEBUFFER, 0);

fboLayerCreated = true;
}

private void createDepthAndStencilBuffer(boolean multisampled, int depthBits,
int stencilBits, boolean packed) {
// Creating depth and stencil buffers
if (packed && depthBits == 24 && stencilBits == 8) {
// packed depth+stencil buffer
genRenderbuffers(1, glDepthStencil);
bindRenderbuffer(RENDERBUFFER, glDepthStencil.get(0));
if (multisample) {
IntBuffer depthStencilBuf =
multisampled ? glMultiDepthStencil : glDepthStencil;
genRenderbuffers(1, depthStencilBuf);
bindRenderbuffer(RENDERBUFFER, depthStencilBuf.get(0));
if (multisampled) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
DEPTH24_STENCIL8, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER,
glDepthStencil.get(0));
depthStencilBuf.get(0));
framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER,
glDepthStencil.get(0));
depthStencilBuf.get(0));
} else {
// separate depth and stencil buffers
if (0 < depthBits) {
Expand All @@ -718,17 +779,18 @@ private void createFBOLayer() {
depthComponent = DEPTH_COMPONENT16;
}

genRenderbuffers(1, glDepth);
bindRenderbuffer(RENDERBUFFER, glDepth.get(0));
if (multisample) {
IntBuffer depthBuf = multisampled ? glMultiDepth : glDepth;
genRenderbuffers(1, depthBuf);
bindRenderbuffer(RENDERBUFFER, depthBuf.get(0));
if (multisampled) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
depthComponent, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, depthComponent,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT,
RENDERBUFFER, glDepth.get(0));
RENDERBUFFER, depthBuf.get(0));
}

if (0 < stencilBits) {
Expand All @@ -741,36 +803,20 @@ private void createFBOLayer() {
stencilIndex = STENCIL_INDEX1;
}

genRenderbuffers(1, glStencil);
bindRenderbuffer(RENDERBUFFER, glStencil.get(0));
if (multisample) {
IntBuffer stencilBuf = multisampled ? glMultiStencil : glStencil;
genRenderbuffers(1, stencilBuf);
bindRenderbuffer(RENDERBUFFER, stencilBuf.get(0));
if (multisampled) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
stencilIndex, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, stencilIndex,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT,
RENDERBUFFER, glStencil.get(0));
RENDERBUFFER, stencilBuf.get(0));
}
}

validateFramebuffer();

// Clear all buffers.
clearDepth(1);
clearStencil(0);
int argb = pg.backgroundColor;
float a = ((argb >> 24) & 0xff) / 255.0f;
float r = ((argb >> 16) & 0xff) / 255.0f;
float g = ((argb >> 8) & 0xff) / 255.0f;
float b = ((argb) & 0xff) / 255.0f;
clearColor(r, g, b, a);
clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT);

bindFramebufferImpl(FRAMEBUFFER, 0);

fboLayerCreated = true;
}


Expand Down Expand Up @@ -1168,7 +1214,7 @@ protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH,
}


protected int getColorValue(int scrX, int scrY) {
public int getColorValue(int scrX, int scrY) {
if (colorBuffer == null) {
colorBuffer = IntBuffer.allocate(1);
}
Expand All @@ -1179,7 +1225,7 @@ protected int getColorValue(int scrX, int scrY) {
}


protected float getDepthValue(int scrX, int scrY) {
public float getDepthValue(int scrX, int scrY) {
if (depthBuffer == null) {
depthBuffer = FloatBuffer.allocate(1);
}
Expand All @@ -1190,10 +1236,11 @@ protected float getDepthValue(int scrX, int scrY) {
}


protected byte getStencilValue(int scrX, int scrY) {
public byte getStencilValue(int scrX, int scrY) {
if (stencilBuffer == null) {
stencilBuffer = ByteBuffer.allocate(1);
}
stencilBuffer.rewind();
readPixels(scrX, pg.height - scrY - 1, 1, 1, STENCIL_INDEX,
UNSIGNED_BYTE, stencilBuffer);
return stencilBuffer.get(0);
Expand Down Expand Up @@ -2559,8 +2606,15 @@ protected interface FontOutline {
// to glReadPixels() should be done in readPixelsImpl().

public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer){
boolean pgCall = format != STENCIL_INDEX &&
format != DEPTH_COMPONENT && format != DEPTH_STENCIL;
boolean multisampled = (primaryPGL && 1 < numSamples) || (!primaryPGL && 1 < pg.quality);

if (!depthReadingEnabled && multisampled &&
(format == STENCIL_INDEX || format == DEPTH_COMPONENT || format == DEPTH_STENCIL)) {
PGraphics.showWarning(DEPTH_READING_NOT_ENABLED_ERROR);
return;
}
boolean pgCall = multisampled ||
(format != STENCIL_INDEX && format != DEPTH_COMPONENT && format != DEPTH_STENCIL);
if (pgCall) pg.beginReadPixels();
readPixelsImpl(x, y, width, height, format, type, buffer);
if (pgCall) pg.endReadPixels();
Expand Down
36 changes: 30 additions & 6 deletions core/src/processing/opengl/PGraphicsOpenGL.java
Expand Up @@ -64,6 +64,12 @@ public class PGraphicsOpenGL extends PGraphics {
/** Current flush mode. */
protected int flushMode = FLUSH_WHEN_FULL;

/** True if user wants to use PGL#readPixels with STENCIL_INDEX,
* DEPTH_COMPONENT or DEPTH_STENCIL.
* If true and multisampling is enabled, depth and stencil buffers
* will be downsampled along with color buffer to allow reading. */
protected boolean depthReadingEnabled;

// ........................................................

// VBOs for immediate rendering:
Expand Down Expand Up @@ -1888,7 +1894,11 @@ protected void beginPixelsOp(int op) {
if (op == OP_READ) {
if (offscreenMultisample) {
// Making sure the offscreen FBO is up-to-date
multisampleFramebuffer.copyColor(offscreenFramebuffer);
int mask = PGL.COLOR_BUFFER_BIT;
if (depthReadingEnabled) {
mask |= PGL.DEPTH_BUFFER_BIT | PGL.STENCIL_BUFFER_BIT;
}
multisampleFramebuffer.copy(offscreenFramebuffer, mask);
}
// We always read the screen pixels from the color FBO.
pixfb = offscreenFramebuffer;
Expand Down Expand Up @@ -2115,6 +2125,14 @@ public void hint(int which) {
// We flush the geometry using the previous line setting.
flush();
}
} else if (which == ENABLE_DEPTH_READING) {
depthReadingEnabled = true;
pgl.setDepthReadingEnabled(true);
restartPGL();
} else if (which == DISABLE_DEPTH_READING) {
depthReadingEnabled = false;
pgl.setDepthReadingEnabled(false);
restartPGL();
}
}

Expand Down Expand Up @@ -6382,11 +6400,17 @@ protected void initOffscreen() {
offscreenMultisample = true;

// The offscreen framebuffer where the multisampled image is finally drawn
// to doesn't need depth and stencil buffers since they are part of the
// multisampled framebuffer.
offscreenFramebuffer =
new FrameBuffer(this, texture.glWidth, texture.glHeight, 1, 1, 0, 0,
false, false);
// to. If depth reading is disabled it doesn't need depth and stencil buffers
// since they are part of the multisampled framebuffer.
if (depthReadingEnabled) {
offscreenFramebuffer =
new FrameBuffer(this, texture.glWidth, texture.glHeight, 1, 1,
depthBits, stencilBits, packed, false);
} else {
offscreenFramebuffer =
new FrameBuffer(this, texture.glWidth, texture.glHeight, 1, 1,
0, 0, false, false);
}

} else {
quality = 0;
Expand Down

0 comments on commit 87f1e3b

Please sign in to comment.