我有一个应用程序正在运行一个带有闪烁火焰的蜡烛的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;
}
非常感谢!