Created
June 12, 2015 13:00
-
-
Save alicanalbayrak/c0b7ea3d023f9e7b0252 to your computer and use it in GitHub Desktop.
Jogl offscreen rendering (PBO2Texture)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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