Skip to content

Instantly share code, notes, and snippets.

@alicanalbayrak
Created June 12, 2015 13:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alicanalbayrak/c0b7ea3d023f9e7b0252 to your computer and use it in GitHub Desktop.
Save alicanalbayrak/c0b7ea3d023f9e7b0252 to your computer and use it in GitHub Desktop.
Jogl offscreen rendering (PBO2Texture)
package pbo;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.Random;
import javax.imageio.ImageIO;
import com.jogamp.opengl.DefaultGLCapabilitiesChooser;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLDrawableFactory;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
public class OffscreenPBO2Texture {
private static int width = 1024;
private static int height = 1024;
private static int CHANNEL_COUNT = 4;
private static int DATA_SIZE = width * height * CHANNEL_COUNT;
private static int PIXEL_FORMAT = GL2.GL_BGRA;
static Random r = new Random();
private static int imageNumber = 0;
private GLAutoDrawable drawable;
// vars
private int[] pboIds = new int[2];
private int[] textureId = new int[1];
int screenWidth;
int screenHeight;
boolean pboSupported;
int pboMode;
private static int index = 0;
private int nextIndex = 0;
static int color = 0;
// ===========================================================================
// Main
// ===========================================================================
public static void main(String[] args) {
OffscreenPBO2Texture offscreenPBO2Texture = new OffscreenPBO2Texture();
offscreenPBO2Texture.render();
}
// ===========================================================================
// Offscreen impl.
// ===========================================================================
public OffscreenPBO2Texture() {
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
caps.setHardwareAccelerated(true);
caps.setDoubleBuffered(false);
caps.setAlphaBits(8);
caps.setRedBits(8);
caps.setBlueBits(8);
caps.setGreenBits(8);
caps.setOnscreen(false);
caps.setPBuffer(true);
System.out.println("isPbBuffer " + caps.isPBuffer());
System.out.println("isFBO " + caps.isFBO());
System.out.println("isBitmap " + caps.isBitmap());
GLDrawableFactory factory = GLDrawableFactory.getFactory(glp);
drawable = factory.createOffscreenAutoDrawable(factory.getDefaultDevice(), caps,
new DefaultGLCapabilitiesChooser(), width, height);
drawable.display();
drawable.getContext().makeCurrent();
GL2 gl = drawable.getGL().getGL2();
generateTexture(gl);
pboSupported = checkForPBOSupport(gl);
if (pboSupported) {
generatePBOs(gl);
}
}
private void render() {
GL2 gl = drawable.getGL().getGL2();
renderPBO2Texture(gl);
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glViewport(0, 0, width, height);
// use pixel coordinates
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(0d, width, 0, height, -1d, 1d);
gl.glPointSize(4f);
gl.glColor3f(1f, 1f, 0f);
drawTexture2Screen(gl);
BufferedImage im = new AWTGLReadBufferUtil(drawable.getGLProfile(), true).readPixelsToBufferedImage(
drawable.getGL(), 0, 0, width, height, true);
try {
ImageIO.write(im, "png", new File("im" + imageNumber + ".png"));
imageNumber++;
} catch (IOException e) {
e.printStackTrace();
}
}
// ===========================================================================
// PBO Related Methods & Variables
// ===========================================================================
private boolean checkForPBOSupport(GL2 gl) {
boolean functionAvailability = gl.isFunctionAvailable("glGenBuffersARB")
&& gl.isFunctionAvailable("glBindBufferARB") && gl.isFunctionAvailable("glBufferDataARB")
&& gl.isFunctionAvailable("glBufferSubDataARB") && gl.isFunctionAvailable("glDeleteBuffersARB")
&& gl.isFunctionAvailable("glGetBufferParameterivARB") && gl.isFunctionAvailable("glMapBufferARB")
&& gl.isFunctionAvailable("glUnmapBufferARB");
boolean wglExtSwapAvailability = gl.isExtensionAvailable("WGL_EXT_swap_control");
boolean glArbPBOAvailability = gl.isExtensionAvailable("GL_ARB_pixel_buffer_object");
if (functionAvailability && wglExtSwapAvailability && glArbPBOAvailability) {
System.out.println("Video card seems ok!");
pboMode = 2;
return true;
} else {
pboMode = 0;
}
return false;
}
private void generateTexture(GL2 gl) {
gl.glGenTextures(1, textureId, 0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureId[0]);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP);
gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGBA8, width, height, 0, PIXEL_FORMAT, GL2.GL_UNSIGNED_BYTE, null);
gl.glBindTexture(GL2.GL_TEXTURE_2D, 0);
}
private void generatePBOs(GL2 gl) {
gl.glGenBuffers(2, pboIds, 0);
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, pboIds[0]);
gl.glBufferData(GL2.GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, null, GL2.GL_STREAM_DRAW);
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, pboIds[1]);
gl.glBufferData(GL2.GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, null, GL2.GL_STREAM_DRAW);
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, 0);
}
private void renderPBO2Texture(GL2 gl) {
if (pboMode == 1) {
index = nextIndex = 0;
} else if (pboMode == 2) {
index = (index + 1) % 2;
nextIndex = (index + 1) % 2;
}
// start to copy from PBO to texture object
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureId[0]);
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
// copy pixels from PBO to texture object
// Use offset instead of ponter.
gl.glTexSubImage2D(GL2.GL_TEXTURE_2D, 0, 0, 0, width, height, PIXEL_FORMAT, GL2.GL_UNSIGNED_BYTE, 0);
// bind PBO to update pixel values
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, pboIds[nextIndex]);
// map the buffer object into client's memory
// Note that glMapBufferARB() causes sync issue.
// If GPU is working with this buffer, glMapBufferARB() will wait(stall)
// for GPU to finish its job. To avoid waiting (stall), you can call
// first glBufferDataARB() with NULL pointer before glMapBufferARB().
// If you do that, the previous data in PBO will be discarded and
// glMapBufferARB() returns a new allocated pointer immediately
// even if GPU is still working with the previous data.
gl.glBufferData(GL2.GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, null, GL2.GL_STREAM_DRAW);
IntBuffer intBuffer = gl.glMapBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, GL2.GL_WRITE_ONLY).asIntBuffer();
if (intBuffer != null) {
updatePixels(intBuffer);
gl.glUnmapBuffer(GL2.GL_PIXEL_UNPACK_BUFFER);
}
// it is good idea to release PBOs with ID 0 after use.
// Once bound with 0, all pixel operations behave normal ways.
gl.glBindBuffer(GL2.GL_PIXEL_UNPACK_BUFFER, 0);
}
private void updatePixels(IntBuffer intBuffer) {
// copy 4 bytes at once
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
intBuffer.put(color);
}
color += 257; // add an arbitary number (no meaning)
}
++color; // scroll down
}
private void drawTexture2Screen(GL2 gl) {
gl.glTranslatef(0.0f, 0.0f, -3.0f);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureId[0]);
gl.glColor4f(1, 1, 1, 1);
gl.glBegin(GL2.GL_QUADS);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 0.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(1f, -1.0f, 0.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 0.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, 0.0f);
gl.glEnd();
gl.glBindTexture(GL2.GL_TEXTURE_2D, 0);
gl.glDisable(GL.GL_TEXTURE_2D);
}
private void deletePBORelatedBuffers(GL2 gl) {
// Delete generated texture
gl.glDeleteBuffers(1, textureId, 0);
// Delete pixel buffer objects
gl.glDeleteBuffers(2, pboIds, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment