Add helpers for FBOs in GlUtil.

FBOs will be used in follow-up CLs to chain multiple GL
shader programs in Transformer.

PiperOrigin-RevId: 428016050
This commit is contained in:
hschlueter 2022-02-11 17:07:26 +00:00 committed by Ian Baker
parent a72f04f9b0
commit 40a5c01275
3 changed files with 96 additions and 26 deletions

View File

@ -35,7 +35,6 @@ import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.microedition.khronos.egl.EGL10;
/** OpenGL ES utilities. */
@ -224,13 +223,29 @@ public final class GlUtil {
}
/**
* Makes the specified {@code surface} the render target, using a viewport of {@code width} by
* Makes the specified {@code eglSurface} the render target, using a viewport of {@code width} by
* {@code height} pixels.
*/
@RequiresApi(17)
public static void focusSurface(
EGLDisplay eglDisplay, EGLContext eglContext, EGLSurface surface, int width, int height) {
Api17.focusSurface(eglDisplay, eglContext, surface, width, height);
public static void focusEglSurface(
EGLDisplay eglDisplay, EGLContext eglContext, EGLSurface eglSurface, int width, int height) {
Api17.focusRenderTarget(
eglDisplay, eglContext, eglSurface, /* framebuffer= */ 0, width, height);
}
/**
* Makes the specified {@code framebuffer} the render target, using a viewport of {@code width} by
* {@code height} pixels.
*/
@RequiresApi(17)
public static void focusFramebuffer(
EGLDisplay eglDisplay,
EGLContext eglContext,
EGLSurface eglSurface,
int framebuffer,
int width,
int height) {
Api17.focusRenderTarget(eglDisplay, eglContext, eglSurface, framebuffer, width, height);
}
/**
@ -295,21 +310,72 @@ public final class GlUtil {
* GL_CLAMP_TO_EDGE wrapping.
*/
public static int createExternalTexture() {
return generateAndBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
}
/**
* Returns the texture identifier for a newly-allocated texture with the specified dimensions.
*
* @param width of the new texture in pixels
* @param height of the new texture in pixels
*/
public static int createTexture(int width, int height) {
int texId = generateAndBindTexture(GLES20.GL_TEXTURE_2D);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(width * height * 4);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
/* level= */ 0,
GLES20.GL_RGBA,
width,
height,
/* border= */ 0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
byteBuffer);
checkGlError();
return texId;
}
/**
* Returns a GL texture identifier of a newly generated and bound texture of the requested type
* with default configuration of GL_LINEAR filtering and GL_CLAMP_TO_EDGE wrapping.
*
* @param textureTarget The target to which the texture is bound, e.g. {@link
* GLES20#GL_TEXTURE_2D} for a two-dimensional texture or {@link
* GLES11Ext#GL_TEXTURE_EXTERNAL_OES} for an external texture.
*/
private static int generateAndBindTexture(int textureTarget) {
int[] texId = new int[1];
GLES20.glGenTextures(/* n= */ 1, IntBuffer.wrap(texId));
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texId[0]);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glGenTextures(/* n= */ 1, texId, /* offset= */ 0);
checkGlError();
GLES20.glBindTexture(textureTarget, texId[0]);
checkGlError();
GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
checkGlError();
GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
checkGlError();
GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
checkGlError();
return texId[0];
}
/**
* Returns a new framebuffer for the texture.
*
* @param texId The identifier of the texture to attach to the framebuffer.
*/
public static int createFboForTexture(int texId) {
int[] fboId = new int[1];
GLES20.glGenFramebuffers(/* n= */ 1, fboId, /* offset= */ 0);
checkGlError();
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]);
checkGlError();
GLES20.glFramebufferTexture2D(
GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texId, 0);
checkGlError();
return fboId[0];
}
/* package */ static void throwGlException(String errorMsg) {
Log.e(TAG, errorMsg);
if (glAssertionsEnabled) {
@ -380,15 +446,19 @@ public final class GlUtil {
}
@DoNotInline
public static void focusSurface(
EGLDisplay eglDisplay, EGLContext eglContext, EGLSurface surface, int width, int height) {
int[] boundFrameBuffer = new int[1];
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, boundFrameBuffer, /* offset= */ 0);
int defaultFrameBuffer = 0;
if (boundFrameBuffer[0] != defaultFrameBuffer) {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, defaultFrameBuffer);
public static void focusRenderTarget(
EGLDisplay eglDisplay,
EGLContext eglContext,
EGLSurface eglSurface,
int framebuffer,
int width,
int height) {
int[] boundFramebuffer = new int[1];
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, boundFramebuffer, /* offset= */ 0);
if (boundFramebuffer[0] != framebuffer) {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer);
}
EGL14.eglMakeCurrent(eglDisplay, surface, surface, eglContext);
EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
GLES20.glViewport(/* x= */ 0, /* y= */ 0, width, height);
}

View File

@ -109,7 +109,7 @@ import java.util.concurrent.atomic.AtomicInteger;
}
}
GlUtil.focusSurface(eglDisplay, eglContext, eglSurface, outputWidth, outputHeight);
GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, outputWidth, outputHeight);
textureId = GlUtil.createExternalTexture();
glProgram =
configureGlProgram(
@ -351,7 +351,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/** Focuses the specified surface with the specified width and height, then draws a quad. */
private void focusAndDrawQuad(EGLSurface eglSurface, int width, int height) {
GlUtil.focusSurface(eglDisplay, eglContext, eglSurface, width, height);
GlUtil.focusEglSurface(eglDisplay, eglContext, eglSurface, width, height);
// The four-vertex triangle strip forms a quad.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
}

View File

@ -152,7 +152,7 @@ import org.checkerframework.dataflow.qual.Pure;
fallbackListener.onTransformationRequestFinalized(
createFallbackTransformationRequest(
transformationRequest,
!swapEncodingDimensions,
/* resolutionIsHeight= */ !swapEncodingDimensions,
requestedEncoderFormat,
encoderSupportedFormat));