Android上的帧缓冲区表面中不显示位图纹理

Android上的帧缓冲区表面中不显示位图纹理,android,opengl-es-2.0,effect,framebuffer,egl,Android,Opengl Es 2.0,Effect,Framebuffer,Egl,我正在尝试使用新的EffectFactory/Effect向屏幕外的图像(即帧缓冲区)添加效果。我已经查看了SDK中提供的功能,并进行了试用,效果良好。但它显然使用了GLSurfaceView,这不是我想要的 因此,我已经开始设置EGL的东西,我还从HelloEffects示例中获取了TextureRenderer.java和GLToolbox。把它们都混在一起,我得到了下面的代码 (另一方面,我还尝试了tests/media/src/android/media/cts/OutputSurfac

我正在尝试使用新的EffectFactory/Effect向屏幕外的图像(即帧缓冲区)添加效果。我已经查看了SDK中提供的功能,并进行了试用,效果良好。但它显然使用了GLSurfaceView,这不是我想要的

因此,我已经开始设置EGL的东西,我还从HelloEffects示例中获取了TextureRenderer.java和GLToolbox。把它们都混在一起,我得到了下面的代码

(另一方面,我还尝试了tests/media/src/android/media/cts/OutputSurface.java来设置EGL,得到了完全相同的结果。)

当我运行它时,我得到的图像是均匀的蓝色。这相当于我用蓝色做的glClear。这至少在某种程度上证明了像素正在被渲染到帧缓冲区,glReadPixels正在看到这些像素,并且位图输出正在工作

但是为什么纹理没有显示出来呢?原始纹理和应用的效果纹理均不显示。也未检测到总账错误

我已经将代码精简为一个可以复制/粘贴到Eclipse中并运行的单个文件工作示例。显然,根据需要修改输入和输出图像路径

在Nexus10/Android4.3和模拟器上测试。同样的结果

import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;


import android.media.effect.Effect;
import android.media.effect.EffectContext;
import android.media.effect.EffectFactory;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import android.opengl.GLES20;
import android.opengl.GLUtils;



public class MainActivity extends Activity 
{
    private int[] mTextures = new int[2];
    private EffectContext mEffectContext;
    private Effect mEffect;
    private TextureRenderer mTexRenderer = new TextureRenderer();
    private int mImageWidth;
    private int mImageHeight;


    final static String imageFileOut = "/data/local/out.png";
    final static String imageFileIn  = "/data/local/lol.png";

    private GLEnv mEnv;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        mEnv = new GLEnv();
        mEnv.makeCurrent();
        mEffectContext = EffectContext.createWithCurrentGlContext();
        mTexRenderer.init();
        loadTextures();
        initAndapplyEffect();
        renderResult();
        saveBitmap();
    }

    void saveBitmap() 
    {
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        ByteBuffer pixelBuffer = ByteBuffer.allocateDirect(mImageWidth * mImageHeight * 4).order(ByteOrder.nativeOrder());
        GLES20.glReadPixels(0, 0, mImageWidth, mImageHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        mEnv.checkForEGLErrors("store Pixels");

        Bitmap bitmap = Bitmap.createBitmap(mImageWidth, mImageHeight, Bitmap.Config.ARGB_8888);
        bitmap.copyPixelsFromBuffer(pixelBuffer);

        try 
        {
            FileOutputStream fos = new FileOutputStream(imageFileOut);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.close();
        } catch (Exception e) { e.printStackTrace();  }

    }

    private void initAndapplyEffect() 
    {
        EffectFactory effectFactory = mEffectContext.getFactory();
        if (mEffect != null) 
        {
            mEffect.release();
        }
        mEffect = effectFactory.createEffect(EffectFactory.EFFECT_BRIGHTNESS);
        mEffect.setParameter("brightness", 2.0f);
        mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);

     }

    private int loadTextures() 
    {
        // Generate textures
        GLES20.glGenTextures(2, mTextures, 0);

        // Load input bitmap
        Bitmap bitmap = BitmapFactory.decodeFile(imageFileIn);

        mImageWidth = bitmap.getWidth();
        mImageHeight = bitmap.getHeight();
        mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);

        // Upload to texture
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        // Set texture parameters
        GLToolbox.initTexParams();

        return mTextures[0];
    }

    private void renderResult() 
    { 
       mTexRenderer.renderTexture(mTextures[1]);
       //mTexRenderer.renderTexture(mTextures[0]);
    }


    public class GLEnv {

        private EGLContext mEGLContext;
        private EGLSurface mEGLSurface;
        private EGLDisplay mEGLDisplay;
        private EGLConfig  mEGLConfig;

        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
        private static final int EGL_OPENGL_ES2_BIT = 0x0004;

        public GLEnv() {
            EGL10 egl = (EGL10)EGLContext.getEGL();

            mEGLDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            checkForEGLErrors("eglGetDisplay");

            int[] version = new int[2];
            egl.eglInitialize(mEGLDisplay, version);
            int[] configSpec = {
                EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
                EGL10.EGL_RED_SIZE, 8,
                EGL10.EGL_GREEN_SIZE, 8,
                EGL10.EGL_BLUE_SIZE, 8,
                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                EGL10.EGL_NONE
            };
            EGLConfig[] configs = new EGLConfig[1];
            int[] num_config = new int[1];
            egl.eglChooseConfig(mEGLDisplay, configSpec, configs, 1, num_config);
            checkForEGLErrors("eglChooseConfig");
            if (num_config[0] < 1) {
                throw new RuntimeException("Could not find a suitable config for EGL context!");
            }
            mEGLConfig = configs[0];

            int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
            mEGLContext = egl.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, attribs);
            checkForEGLErrors("eglCreateContext");

            int[] surfaceSize = { EGL10.EGL_WIDTH, 1920, EGL10.EGL_HEIGHT, 1080, EGL10.EGL_NONE };
            mEGLSurface = egl.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, surfaceSize);
            checkForEGLErrors("eglCreatePbufferSurface");
        }

        public void makeCurrent() {
            EGL10 egl = (EGL10)EGLContext.getEGL();
            egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
            checkForEGLErrors("eglMakeCurrent");
        }


        public void checkForEGLErrors(String operation) {
            EGL10 egl = (EGL10)EGLContext.getEGL();
            int error = egl.eglGetError();
            if (error != EGL10.EGL_SUCCESS) {
                throw new RuntimeException("Operation '" + operation + "' caused EGL error: " + error);
            }
        }

    }

    private static final float[] TEX_VERTICES = {
        0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
    };

    private static final float[] POS_VERTICES = {
        -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f
    };

    public class TextureRenderer {

        private int mProgram;
        private int mTexSamplerHandle;
        private int mTexCoordHandle;
        private int mPosCoordHandle;

        private FloatBuffer mTexVertices;
        private FloatBuffer mPosVertices;

        private int mViewWidth;
        private int mViewHeight;

        private int mTexWidth;
        private int mTexHeight;

        private static final String VERTEX_SHADER =
            "attribute vec4 a_position;\n" +
            "attribute vec2 a_texcoord;\n" +
            "varying vec2 v_texcoord;\n" +
            "void main() {\n" +
            "  gl_Position = a_position;\n" +
            "  v_texcoord = a_texcoord;\n" +
            "}\n";

        private static final String FRAGMENT_SHADER =
            "precision mediump float;\n" +
            "uniform sampler2D tex_sampler;\n" +
            "varying vec2 v_texcoord;\n" +
            "void main() {\n" +
            "  gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
            "}\n";



        private static final int FLOAT_SIZE_BYTES = 4;

        public void init() {
            // Create program
            mProgram = GLToolbox.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);

            // Bind attributes and uniforms
            mTexSamplerHandle = GLES20.glGetUniformLocation(mProgram,
                    "tex_sampler");
            mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texcoord");
            mPosCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_position");

            // Setup coordinate buffers
            mTexVertices = ByteBuffer.allocateDirect(
                    TEX_VERTICES.length * FLOAT_SIZE_BYTES)
                    .order(ByteOrder.nativeOrder()).asFloatBuffer();
            mTexVertices.put(TEX_VERTICES).position(0);
            mPosVertices = ByteBuffer.allocateDirect(
                    POS_VERTICES.length * FLOAT_SIZE_BYTES)
                    .order(ByteOrder.nativeOrder()).asFloatBuffer();
            mPosVertices.put(POS_VERTICES).position(0);
        }

        public void tearDown() {
            GLES20.glDeleteProgram(mProgram);
        }

        public void updateTextureSize(int texWidth, int texHeight) {
            mTexWidth = texWidth;
            mTexHeight = texHeight;
            computeOutputVertices();
        }

        public void updateViewSize(int viewWidth, int viewHeight) {
            mViewWidth = viewWidth;
            mViewHeight = viewHeight;
            computeOutputVertices();
        }

        public void renderTexture(int texId) {
            // Bind default FBO
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

            // Use our shader program
            GLES20.glUseProgram(mProgram);
            GLToolbox.checkGlError("glUseProgram");

            // Set viewport
            GLES20.glViewport(0, 0, mViewWidth, mViewHeight);
            GLToolbox.checkGlError("glViewport");

            // Disable blending
            GLES20.glDisable(GLES20.GL_BLEND);

            // Set the vertex attributes
            GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false,
                    0, mTexVertices);
            GLES20.glEnableVertexAttribArray(mTexCoordHandle);
            GLES20.glVertexAttribPointer(mPosCoordHandle, 2, GLES20.GL_FLOAT, false,
                    0, mPosVertices);
            GLES20.glEnableVertexAttribArray(mPosCoordHandle);
            GLToolbox.checkGlError("vertex attribute setup");

            // Set the input texture
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLToolbox.checkGlError("glActiveTexture");
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
            GLToolbox.checkGlError("glBindTexture");
            GLES20.glUniform1i(mTexSamplerHandle, 0);

            // Draw
            GLES20.glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        }

        private void computeOutputVertices() {
            if (mPosVertices != null) {
                float imgAspectRatio = mTexWidth / (float)mTexHeight;
                float viewAspectRatio = mViewWidth / (float)mViewHeight;
                float relativeAspectRatio = viewAspectRatio / imgAspectRatio;
                float x0, y0, x1, y1;
                if (relativeAspectRatio > 1.0f) {
                    x0 = -1.0f / relativeAspectRatio;
                    y0 = -1.0f;
                    x1 = 1.0f / relativeAspectRatio;
                    y1 = 1.0f;
                } else {
                    x0 = -1.0f;
                    y0 = -relativeAspectRatio;
                    x1 = 1.0f;
                    y1 = relativeAspectRatio;
                }
                float[] coords = new float[] { x0, y0, x1, y0, x0, y1, x1, y1 };
                mPosVertices.put(coords).position(0);
            }
        }



    }

    public static class GLToolbox {

        public static int loadShader(int shaderType, String source) {
            int shader = GLES20.glCreateShader(shaderType);
            if (shader != 0) {
                GLES20.glShaderSource(shader, source);
                GLES20.glCompileShader(shader);
                int[] compiled = new int[1];
                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
                if (compiled[0] == 0) {
                    String info = GLES20.glGetShaderInfoLog(shader);
                    GLES20.glDeleteShader(shader);
                    shader = 0;
                    throw new RuntimeException("Could not compile shader " +
                    shaderType + ":" + info);
                }
            }
            return shader;
        }

        public static int createProgram(String vertexSource,
                String fragmentSource) {
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
            if (vertexShader == 0) {
                return 0;
            }
            int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
            if (pixelShader == 0) {
                return 0;
            }

            int program = GLES20.glCreateProgram();
            if (program != 0) {
                GLES20.glAttachShader(program, vertexShader);
                checkGlError("glAttachShader");
                GLES20.glAttachShader(program, pixelShader);
                checkGlError("glAttachShader");
                GLES20.glLinkProgram(program);
                int[] linkStatus = new int[1];
                GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus,
                        0);
                if (linkStatus[0] != GLES20.GL_TRUE) {
                    String info = GLES20.glGetProgramInfoLog(program);
                    GLES20.glDeleteProgram(program);
                    program = 0;
                    throw new RuntimeException("Could not link program: " + info);
                }
            }
            return program;
        }

        public static void checkGlError(String op) {
            int error;
            while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
                throw new RuntimeException(op + ": glError " + error);
            }
        }

        public static void initTexParams() {
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
                    GLES20.GL_CLAMP_TO_EDGE);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
                    GLES20.GL_CLAMP_TO_EDGE);
       }

    }
}
import java.io.FileOutputStream;
导入java.nio.ByteBuffer;
导入java.nio.ByteOrder;
导入java.nio.FloatBuffer;
导入javax.microedition.khronos.egl.EGL10;
导入javax.microedition.khronos.egl.EGLConfig;
导入javax.microedition.khronos.egl.EGLContext;
导入javax.microedition.khronos.egl.EGLDisplay;
导入javax.microedition.khronos.egl.EGLSurface;
导入android.media.effect.effect;
导入android.media.effect.EffectContext;
导入android.media.effect.EffectFactory;
导入android.os.Bundle;
导入android.app.Activity;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.opengl.GLES20;
导入android.opengl.GLUtils;
公共类MainActivity扩展了活动
{
私有int[]mTextures=newint[2];
私人效应语境;
私人效应;
私有TextureRenderer mTexRenderer=新TextureRenderer();
私有整数图像宽度;
私人内部图像高度;
最终静态字符串imageFileOut=“/data/local/out.png”;
最终静态字符串imageFileIn=“/data/local/lol.png”;
列兵格伦夫·门夫;
@凌驾
创建时受保护的void(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEnv=新格伦v();
mEnv.makeCurrent();
mEffectContext=EffectContext.createWithCurrentGlContext();
mTexRenderer.init();
加载纹理();
initAndapplyEffect();
renderResult();
保存位图();
}
void saveBitmap()
{
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
ByteBuffer pixelBuffer=ByteBuffer.allocateDirect(mImageWidth*mImageHeight*4).order(ByteOrder.nativeOrder());
GLES20.glReadPixels(0,0,mImageWidth,mImageHeight,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE,pixelBuffer);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
mEnv.checkforeglerors(“存储像素”);
位图Bitmap=Bitmap.createBitmap(mImageWidth、mImageHeight、Bitmap.Config.ARGB_8888);
copyPixelsFromBuffer(pixelBuffer);
尝试
{
FileOutputStream fos=新的FileOutputStream(imageFileOut);
compress(bitmap.CompressFormat.PNG,100,fos);
fos.close();
}catch(异常e){e.printStackTrace();}
}
私有void initAndapplyEffect()
{
EffectFactory EffectFactory=mEffectContext.getFactory();
if(mEffect!=null)
{
meeffect.release();
}
mEffect=effectFactory.createEffect(effectFactory.EFFECT\u亮度);
MEEffect.setParameter(“亮度”,2.0f);
MEEffect.apply(mTextures[0],mImageWidth,mImageHeight,mTextures[1]);
}
私有int loadTextures()
{
//生成纹理
GLES20.glGenTextures(2,mTextures,0);
//加载输入位图
位图位图=BitmapFactory.decodeFile(imageFileIn);
mImageWidth=bitmap.getWidth();
mImageHeight=bitmap.getHeight();
mTexRenderer.updateTextResize(mImageWidth、mImageHeight);
//上传到纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextures[0]);
GLUtils.texImage2D(GLES20.GL_纹理_2D,0,位图,0);
//设置纹理参数
GLToolbox.initTexParams();
返回mtexture[0];
}
私有void renderResult()
{ 
renderTexture(mTextures[1]);
//renderTexture(mTextures[0]);
}
公共课格伦夫{
私有EGLContext-mEGLContext;
私人EGLSurface MEGLSUFACE;
私人EGLDisplay mEGLDisplay;
私人EGLConfig MEGLonfig;
私有静态最终int EGL_上下文_客户端_版本=0x3098;
私有静态最终整数EGL\U OPENGL\U ES2\U位=0x0004;
公营部门{
EGL10 egl=(EGL10)EGLContext.getEGL();
mEGLDisplay=egl.eglGetDisplay(EGL10.egl\u默认显示);
CheckForegErrors(“eglGetDisplay”);
int[]版本=新int[2];
egl.eglinitalize(mEGLDisplay,版本);
int[]配置规范={
EGL10.EGL_表面类型,EGL10.EGL_缓冲位,
EGL10.EGL_红色_尺寸,8,
EGL10.EGL_绿色_尺寸,8,
EGL10.EGL_蓝色_尺寸,8,
EGL10.EGL_可渲染类型,EGL_OPENGL_ES2_位,
EGL10.EGL_无
};
EGLConfig[]configs=新的EGLConfig[1];
int[]num_config=new int[1];
egl.eglChooseConfig(mEGLDisplay,configSpec,configs,1,num_config);