diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java index c12a3751ad..99f88a38f0 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/GlRectDrawerTest.java @@ -28,22 +28,25 @@ package org.webrtc; import android.test.ActivityTestCase; import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; import java.nio.ByteBuffer; import java.util.Random; +import android.graphics.SurfaceTexture; import android.opengl.EGL14; -import android.opengl.Matrix; +import android.opengl.EGLContext; import android.opengl.GLES20; +import android.opengl.Matrix; -public class GlRectDrawerTest extends ActivityTestCase { +public final class GlRectDrawerTest extends ActivityTestCase { // Resolution of the test image. private static final int WIDTH = 16; private static final int HEIGHT = 16; // Seed for random pixel creation. private static final int SEED = 42; // When comparing pixels, allow some slack for float arithmetic and integer rounding. - final float MAX_DIFF = 1.0f; + private static final float MAX_DIFF = 1.0f; private static float normalizedByte(byte b) { return (b & 0xFF) / 255.0f; @@ -95,7 +98,7 @@ public class GlRectDrawerTest extends ActivityTestCase { } @SmallTest - public void testRgbRendering() throws Exception { + public void testRgbRendering() { // Create EGL base with a pixel buffer as display output. final EglBase eglBase = new EglBase(EGL14.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); eglBase.createPbufferSurface(WIDTH, HEIGHT); @@ -134,7 +137,7 @@ public class GlRectDrawerTest extends ActivityTestCase { } @SmallTest - public void testYuvRendering() throws Exception { + public void testYuvRendering() { // Create EGL base with a pixel buffer as display output. EglBase eglBase = new EglBase(EGL14.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); eglBase.createPbufferSurface(WIDTH, HEIGHT); @@ -206,4 +209,108 @@ public class GlRectDrawerTest extends ActivityTestCase { GLES20.glDeleteTextures(3, yuvTextures, 0); eglBase.release(); } + + /** + * The purpose here is to test GlRectDrawer.oesDraw(). Unfortunately, there is no easy way to + * create an OES texture, which is needed for input to oesDraw(). Most of the test is concerned + * with creating OES textures in the following way: + * - Create SurfaceTexture with help from SurfaceTextureHelper. + * - Create an EglBase with the SurfaceTexture as EGLSurface. + * - Upload RGB texture with known content. + * - Draw the RGB texture onto the EglBase with the SurfaceTexture as target. + * - Wait for an OES texture to be produced. + * The actual oesDraw() test is this: + * - Create an EglBase with a pixel buffer as target. + * - Render the OES texture onto the pixel buffer. + * - Read back the pixel buffer and compare it with the known RGB data. + */ + @MediumTest + public void testOesRendering() throws InterruptedException { + /** + * Stub class to convert RGB ByteBuffers to OES textures by drawing onto a SurfaceTexture. + */ + class StubOesTextureProducer { + private final EglBase eglBase; + private final GlRectDrawer drawer; + private final int rgbTexture; + + public StubOesTextureProducer( + EGLContext sharedContext, SurfaceTexture surfaceTexture, int width, int height) { + eglBase = new EglBase(sharedContext, EglBase.ConfigType.PLAIN); + surfaceTexture.setDefaultBufferSize(width, height); + eglBase.createSurface(surfaceTexture); + assertEquals(eglBase.surfaceWidth(), width); + assertEquals(eglBase.surfaceHeight(), height); + + drawer = new GlRectDrawer(); + + eglBase.makeCurrent(); + rgbTexture = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); + } + + public void draw(ByteBuffer rgbPlane) { + eglBase.makeCurrent(); + + // Upload RGB data to texture. + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, rgbTexture); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, WIDTH, + HEIGHT, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, rgbPlane); + // Draw the RGB data onto the SurfaceTexture. + final float[] identityMatrix = new float[16]; + Matrix.setIdentityM(identityMatrix, 0); + drawer.drawRgb(rgbTexture, identityMatrix); + eglBase.swapBuffers(); + } + + public void release() { + eglBase.makeCurrent(); + drawer.release(); + GLES20.glDeleteTextures(1, new int[] {rgbTexture}, 0); + eglBase.release(); + } + } + + // Create EGL base with a pixel buffer as display output. + final EglBase eglBase = new EglBase(EGL14.EGL_NO_CONTEXT, EglBase.ConfigType.PIXEL_BUFFER); + eglBase.createPbufferSurface(WIDTH, HEIGHT); + + // Create resources for generating OES textures. + final SurfaceTextureHelper surfaceTextureHelper = + new SurfaceTextureHelper(eglBase.getContext()); + final StubOesTextureProducer oesProducer = new StubOesTextureProducer( + eglBase.getContext(), surfaceTextureHelper.getSurfaceTexture(), WIDTH, HEIGHT); + final SurfaceTextureHelperTest.MockTextureListener listener = + new SurfaceTextureHelperTest.MockTextureListener(); + surfaceTextureHelper.setListener(listener); + + // Create RGB byte buffer plane with random content. + final ByteBuffer rgbPlane = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 3); + final Random random = new Random(SEED); + random.nextBytes(rgbPlane.array()); + + // Draw the frame and block until an OES texture is delivered. + oesProducer.draw(rgbPlane); + listener.waitForNewFrame(); + + // Real test starts here. + // Draw the OES texture on the pixel buffer. + eglBase.makeCurrent(); + final GlRectDrawer drawer = new GlRectDrawer(); + drawer.drawOes(listener.oesTextureId, listener.transformMatrix); + + // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. + final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4); + GLES20.glReadPixels(0, 0, WIDTH, HEIGHT, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, rgbaData); + GlUtil.checkNoGLES2Error("glReadPixels"); + + // Assert rendered image is pixel perfect to source RGB. + assertEquals(WIDTH, HEIGHT, stripAlphaChannel(rgbaData), rgbPlane); + + drawer.release(); + surfaceTextureHelper.returnTextureFrame(); + oesProducer.release(); + surfaceTextureHelper.disconnect(); + eglBase.release(); + } }