OpenGLES - 无法为adreno_pool_allocator分配内存页面

时间:2014-10-14 15:39:16

标签: android opengl-es opengl-es-2.0

我有一个应用程序正在运行一个带有闪烁火焰的蜡烛的2D动画。它由一个矩形组成,烛台图像为纹理(512 * 512px,158 KB),矢量火焰用着色器着色。

应用程序运行绝对正常一个小时左右,然后退出。虽然设备上没有错误,但如果您正在调试(简要),请参阅:

10-13 16:05:46.420    8373-8418/org.projectcede.flame.app E/Adreno-SC﹕ <allocate:384>: Could not allocate a memory page for the adreno_pool_allocator.
10-13 16:05:46.420    8373-8418/org.projectcede.flame.app A/libc﹕ Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 8418 (Thread-262)

基于一些测试(频率为......

GC_FOR_ALLOC freed 536K, 14% free 9672K/11204K, paused 20ms, total 20ms

...在调试日志中)我认为这是闪烁的火焰而不是纹理。

我试过谷歌搜索错误,已经阅读了几本书,但我完全不知道该怎么做。

我认为它是某种类型的内存泄漏,并且可能是由于我没有解除OpenGLES方面的问题,但我不知道是什么。

我尝试在每次抽奖后调用GLES20.glDeleteProgram(mProgram);,但这没有效果。

任何想法都会感激不尽!

以下是绘制闪烁火焰的类:

import android.content.Context;
import android.content.res.Resources;
import android.opengl.GLES20;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Random;

/**
 * Creates a flickering leaf constructed from two bezier curves
 *
 * @author jonnyhuck
 * @version 0.1
 */
public class FlickeringFlame {

    // finals
    private static final Random r = new Random();
    private static final String A_POSITION = "aPosition";
    private static final String A_COLOR = "aColor";
    private static final String U_MATRIX = "uMVPMatrix";
    // vertex values
    private static final int COORDS_PER_VERTEX = 2;
    private static final int COLOURS_PER_VERTEX = 4;
    private static final int COMPONENTS_PER_VERTEX = COORDS_PER_VERTEX + COLOURS_PER_VERTEX;
    private static final int VERTEX_STRIDE = COMPONENTS_PER_VERTEX * 4;
    // curve values
    private static final int VERTICES_PER_CURVE = 22;
    private static final int COORDS_PER_CURVE = COORDS_PER_VERTEX * VERTICES_PER_CURVE;
    // leaf values
    private static final int VERTICES_PER_LEAF = VERTICES_PER_CURVE * 2;
    private static final int COORDS_PER_LEAF = COORDS_PER_VERTEX * VERTICES_PER_LEAF;
    // centroid once, inner twice, mid twice, outer once...
    private static final ByteBuffer bb = ByteBuffer.allocateDirect(((VERTICES_PER_LEAF * 5) + 1) * VERTEX_STRIDE);
    // variables
    private static final String LOGTAG = "JONNY!";
    // shaders
    private static String vertexShaderCode;
    private static String fragmentShaderCode;
    private static int vertexShader;
    private static int fragmentShader;
    private float[] bezierCoords;
    private FloatBuffer vertexBuffer;
    private int mProgram;
    private int mPositionHandle;
    private int mMVPMatrixHandle;
    private int aColorLocation;

    /**
     * Build the shaders
     */
    public FlickeringFlame(Context context) {

        // build and compile vertex shader
        vertexShaderCode = readTextFileFromResource(context,
                R.raw.vertex_shader);
        // vertexShaderCode = readTextFileFromResource(context, R.raw.test);
        vertexShader = MyRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        // build and compile fragment shader
        fragmentShaderCode = readTextFileFromResource(context,
                R.raw.fragment_shader);
        fragmentShader = MyRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);
    }

    /**
     * Read a text file fro the resources (used to read in the vertex shader)
     *
     * @param context
     * @param resourceId
     * @return
     */
    public static String readTextFileFromResource(Context context,
                                                  int resourceId) {
        StringBuilder body = new StringBuilder();
        try {
            InputStream inputStream = context.getResources().openRawResource(
                    resourceId);
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream);
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);
            String nextLine;
            while ((nextLine = bufferedReader.readLine()) != null) {
                body.append(nextLine);
                body.append("\n");
            }
        } catch (IOException e) {
            Log.e(LOGTAG, e.getMessage());
            throw new RuntimeException(
                    "Could not open resource: " + resourceId, e);
        } catch (Resources.NotFoundException nfe) {
            Log.e(LOGTAG, nfe.getMessage());
            throw new RuntimeException("Resource not found: " + resourceId, nfe);
        }
        // Log.i(LOGTAG, body.toString());
        return body.toString();
    }

    /**
     * draw the object
     * <p/>
     * TODO: Throw exception if the mProgram does not link
     */
    public void draw(float[] mMVPMatrix) {

        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // build the OpenGL 'program'
        mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
        GLES20.glAttachShader(mProgram, vertexShader); // add vertex shader
        GLES20.glAttachShader(mProgram, fragmentShader); // add fragment shader
        GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
        int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0); // 6
        if (linkStatus[0] != GLES20.GL_TRUE) {
            Log.e(LOGTAG, "Could not link program: ");
            Log.e(LOGTAG, GLES20.glGetProgramInfoLog(mProgram));
            GLES20.glDeleteProgram(mProgram);
        }
        GLES20.glUseProgram(mProgram); // Add program to OpenGL environment

        // create the leaf shape
        bezierCoords = createFlame( //
//              0f, -0.25f, //
//              0.125f, -0.25f, //
//              0.05f, 0.15f, //
//              0f, 0.25f, //
//              // 0f, 0f); //this keeps it still
//              0.075f, 0.025f);
                0f, -0.13f, //
                0.07f, -0.08f, //
                0.025f, 0.08f, //
                0f, 0.13f, //
                // 0f, 0f); //this keeps it still
                0.038f, 0.013f);

        // create a floating point buffer
        vertexBuffer = bb.asFloatBuffer();

        // add the coordinates to the FloatBuffer
        vertexBuffer.put(bezierCoords);

        // get handle to vertex shader's position data
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, A_POSITION);

        // get handle to fragment shader's colour data
        aColorLocation = GLES20.glGetAttribLocation(mProgram, A_COLOR);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, U_MATRIX);
        MyRenderer.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
        MyRenderer.checkGlError("glUniformMatrix4fv");

        // Prepare the coordinate data
        vertexBuffer.position(0); // set the buffer to read the first coordinate
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VERTEX_STRIDE, vertexBuffer);
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the colour data
        vertexBuffer.position(COORDS_PER_VERTEX); // skip the coordinates - start reading at the start of the colours
        GLES20.glVertexAttribPointer(aColorLocation, COLOURS_PER_VERTEX, GLES20.GL_FLOAT, false, VERTEX_STRIDE, vertexBuffer);
        GLES20.glEnableVertexAttribArray(aColorLocation);

        //enable transparency
        GLES20.glDisable(GLES20.GL_CULL_FACE);
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

        // Draw the 3 sections
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 1 + VERTICES_PER_LEAF); // INNER
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 2 + VERTICES_PER_LEAF, VERTICES_PER_LEAF * 2); // MIDDLE
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 2 + (3 * VERTICES_PER_LEAF), VERTICES_PER_LEAF * 2); // OUTER

        //disable transparency
        GLES20.glDisable(GLES20.GL_BLEND);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

    /**
     * Build a flame
     *
     * @return
     */
    private float[] createFlame(float p0x, float p0y, float p1x, float p1y,
                                float p2x, float p2y, float p3x, float p3y, float ctrlOffset,
                                float tipOffset) {

        /* INNER FLAME */

        // get the leaf shape
        float[] inner = createLeaf(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y,
                ctrlOffset * 0.6f, tipOffset * 0.3f);

        // create an array to take it and a centre point
//      float[] coords = new float[(COMPONENTS_PER_LEAF * COMPONENTS_PER_VERTEX)
//              + COMPONENTS_PER_VERTEX];
        float[] coords = new float[((VERTICES_PER_LEAF * 5) + 1) * COMPONENTS_PER_VERTEX];

        // load the screen centroid
        coords[0] = 0f; // x
        coords[1] = 0f; // y
        coords[2] = 0.15f; // r
        coords[3] = 0f; // g
        coords[4] = 0f; // b
        coords[5] = 1f; // a

        // load in the leaf, applying colours
        int j;
        for (int i = 0; i < inner.length; i += COORDS_PER_VERTEX) {

            // calculate next position
            j = (i / 2) * COMPONENTS_PER_VERTEX + COMPONENTS_PER_VERTEX;

            // populate array with coords and colour
            coords[j] = inner[i]; // x
            coords[j + 1] = inner[i + 1]; // y
            coords[j + 2] = 1f; // r
            coords[j + 3] = 0f; // g
            coords[j + 4] = 0f; // b
            coords[j + 5] = 1f; // a
        }

//      /* MID FLAME */
//
//      // build the mid section of the flame
        float multiplier = 3f;
        float[] mid = createLeaf(p0x, p0y, p1x * multiplier, p1y, p2x
                * multiplier, p2y * multiplier, p3x * multiplier, p3y
                * multiplier, ctrlOffset * 0.8f, tipOffset * 0.6f);

        int k;
        for (int i = 0; i < inner.length / COORDS_PER_VERTEX; i++) {

            // calculate array positions
            j = (COMPONENTS_PER_VERTEX * VERTICES_PER_LEAF) + COMPONENTS_PER_VERTEX + (i * COMPONENTS_PER_VERTEX * 2);
            k = i * COORDS_PER_VERTEX;

            // populate mid
            coords[j] = mid[k]; // x
            coords[j + 1] = mid[k + 1]; // y
            coords[j + 2] = 1f; // r
            coords[j + 3] = 1f; // g
            coords[j + 4] = 0f; // b
            coords[j + 5] = 0.95f; // a

            // populate inner
            coords[j + 6] = inner[k]; // x
            coords[j + 7] = inner[k + 1]; // y
            coords[j + 8] = 1f; // r
            coords[j + 9] = 0f; // g
            coords[j + 10] = 0f; // b
            coords[j + 11] = 1f; // a
        }

        /* OUTER FLAME */

        // build the outer section of the flame
        multiplier = 4f;
        //(p0y - ctrlOffset just stops the mid from overlapping the outer at the base of the flame)
        float[] outer = createLeaf(p0x, p0y - ctrlOffset, p1x * multiplier, p1y, p2x
                * multiplier, p2y * multiplier, p3x * multiplier, p3y
                * multiplier, ctrlOffset, tipOffset);

        for (int i = 0; i < (inner.length / COORDS_PER_VERTEX); i++) {

            // calculate array positions
            j = ((COMPONENTS_PER_VERTEX * VERTICES_PER_LEAF) * 3) + COMPONENTS_PER_VERTEX + (i * COMPONENTS_PER_VERTEX * 2);
            k = i * COORDS_PER_VERTEX;

            // populate outer
            coords[j] = outer[k]; // x
            coords[j + 1] = outer[k + 1]; // y
            coords[j + 2] = 1f; // r
            coords[j + 3] = 1f; // g
            coords[j + 4] = 0f; // b
            coords[j + 5] = 0f; // a

            // populate mid
            coords[j + 6] = mid[k]; // x
            coords[j + 7] = mid[k + 1]; // y
            coords[j + 8] = 1f; // r
            coords[j + 9] = 1f; // g
            coords[j + 10] = 0f; // b
            coords[j + 11] = 0.95f; // a
        }

//        String out = "";
//        for (int z = 0; z < coords.length; z++){
//            out += coords[z] + ", ";
//        }
//        Log.w(LOGTAG, out);
        return coords;
    }

    /**
     * Build the 'leaf' shape
     *
     * @return
     */
    private float[] createLeaf(float p0x, float p0y, float p1x, float p1y,
                               float p2x, float p2y, float p3x, float p3y, float ctrlOffset,
                               float tipOffset) {

        // get new top
        float[] flameTop = {p3x + rand(-ctrlOffset, ctrlOffset),
                p3y + rand(-ctrlOffset, ctrlOffset)};

        // load in the bezier curves
        final float[] left = create2DBezierCurve(p0x, //
                p0y, //
                p1x + rand(-ctrlOffset, ctrlOffset), //
                p1y + rand(-ctrlOffset, ctrlOffset), //
                p2x + rand(-ctrlOffset, ctrlOffset), //
                p2y + rand(-ctrlOffset, ctrlOffset), //
                flameTop[0], //
                flameTop[1]);
        final float[] right = create2DBezierCurve(flameTop[0], //
                flameTop[1], //
                p2x * -1f + rand(-ctrlOffset, ctrlOffset), //
                p2y + rand(-ctrlOffset, ctrlOffset), //
                p1x * -1f + rand(-ctrlOffset, ctrlOffset), //
                p1y + rand(-ctrlOffset, ctrlOffset), //
                p0x, //
                p0y);

        // load into output array & return
        float[] coords = new float[COORDS_PER_LEAF];
        for (int i = 0; i < COORDS_PER_CURVE; i++) {
            coords[i] = left[i];
            coords[i + COORDS_PER_CURVE] = right[i];
        }
        return coords;
    }

    /**
     * Create a 2D cubic bezier curve
     * <p/>
     * {http://en.wikipedia.org/wiki/B%C3%A9zier_curve}
     * p0
     * The start anchor point for the Bezier curve
     * p1
     * The first control point for the Bezier curve
     * p2
     * The second control point for the Bezier curve
     * p3
     * The end anchor point for the Bezier curve
     *
     * @return Float array of 3D coordinates for a Bezier Curve
     */
    private float[] create2DBezierCurve(float p0x, float p0y, float p1x,
                                        float p1y, float p2x, float p2y, float p3x, float p3y) {

        // loop through 11 points along the curve
        float t2;
        int t3;
        float[] coords = new float[COORDS_PER_CURVE];
        for (int t = 0; t < VERTICES_PER_CURVE; t++) {

            // scale t down
            t2 = t * (1f / (VERTICES_PER_CURVE - 1)); // value between 0-1
            t3 = t * 2; // the array position to write to

            // get coords along the curve for x & y
            coords[t3] = create1DBezierCurve(p0x, p1x, p2x, p3x, t2);
            coords[t3 + 1] = create1DBezierCurve(p0y, p1y, p2y, p3y, t2);
        }
        return coords;
    }

    /**
     * Create a 1D cubic bezier curve
     * <p/>
     * {http://en.wikipedia.org/wiki/B%C3%A9zier_curve}
     *
     * @param p0 The start anchor point for the Bezier curve
     * @param p1 The first control point for the Bezier curve
     * @param p2 The second control point for the Bezier curve
     * @param p3 The end anchor point for the Bezier curve
     * @param t  The distance along the curve on a scale of 0-1
     * @return
     */
    private float create1DBezierCurve(float p0, float p1, float p2, float p3,
                                      float t) {
        return (1 - t) * (1 - t) * (1 - t) * p0 + (3 * ((1 - t) * (1 - t))) * t
                * p1 + (3 * (1 - t)) * (t * t) * p2 + (t * t * t) * p3;
    }

    /**
     * Returns a random float between two specified values
     *
     * @param hi The upper limit of the random number range
     * @param lo The lower limit of the random number range
     * @return
     */
    private float rand(float hi, float lo) {
        return r.nextFloat() * (hi - lo) / 1 + lo;
    }
}

顶点着色器是:

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec4 aColor;
varying vec4 vColor;
void main() {
    vColor = aColor;
    gl_Position = uMVPMatrix * aPosition;
}

片段着色器是:

precision mediump float;
varying vec4 vColor;
void main() {
    gl_FragColor = vColor;
}

非常感谢!

0 个答案:

没有答案