SurfaceView 游戏线程上的 drawBitmap 性能低下 (android)
drawBitmap low performance on SurfaceView game thread (android)
我正在 SurfaceView 上绘制一组图像 canvas。 doDraw 在获取 surfaceHolder 后由游戏循环线程调用。问题是当在 canvas 上绘制的图像数量很大时,每秒帧数 (FPS) 确实很低。这是因为 drawBitmap 很慢。
测试设置
clusters arraylist 有 400 个小图像 (cluster.Picture)。时间差是 运行 drawBitmap 循环的测量参数。为了进行比较,我用 drawRect 替换了 drawBitmap,并且还注释掉了 drawBitmap,使循环体为空。
用于测试的设备
https://www.optus.com.au/shop/prepaidmobile/lg/leon
测试结果(毫秒)
- drawBitmap 400 循环 - 平均值:25.5,最小值:14,最大值:37
- drawRect 400 循环 - 平均值:8.6,最小值:5,最大值:21
- 无 400 循环 - 平均值:1.3,最小值:0,最大值:10
以上时间只测了部分逻辑。整个游戏循环需要将近 40 毫秒。这意味着 FPS 真的很低。即使是 100 次循环,仅绘制位图也需要 18 毫秒。
我尝试设置 getHolder().setFormat(PixelFormat.RGBA_8888)、setFixedSize(screenSize.x , screenSize.y) 和 zorder 以及将位图配置设置为 RGBA_8888.此外,我尝试使用游戏线程的 setPriority 设置高优先级。
我不确定我还能做什么。如何提高游戏循环和 FPS 的性能。
public List<PCluster> clusters = new ArrayList<PCluster>();
public void doDraw(Canvas canvas) {
try {
if (canvas == null) {
return;
}
super.draw(canvas);
canvas.drawColor(backColor);
if (waitTillLoad) {
return;
}
} catch (Exception ex) {
}
final int savedState = canvas.save();
try {
minX = (int) (((viewWidth / mScaleFactor) - Gen.screenSizeWidth) / 2) * Utils.VIEW_SIZE;
minY = (int) (((viewHeight / mScaleFactor) - Gen.screenSizeHeight) / 2) * Utils.VIEW_SIZE;
if (mPosX > maxX) {
mPosX = maxX;
}
if (mPosX < minX) {
mPosX = minX;
}
if (mPosY > maxY) {
mPosY = maxY;
}
if (mPosY < minY) {
mPosY = minY;
}
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(mPosX, mPosY);
long startTime = System.currentTimeMillis();
if (!showBackground) {
for (PCluster cluster : clusters) {
if (cluster.isVisible) {
canvas.drawBitmap(cluster.Picture, cluster.BoardLocation.left,
cluster.BoardLocation.top, null);
}
}
Log.d("myApp", " " + (System.currentTimeMillis() - startTime));
}
} catch (Exception ex) {
} finally {
canvas.restoreToCount(savedState);
}
}
我能够使用 PorterDuff SRC_OVER 绘制对象来提高性能。这可能是因为透明图像相互重叠绘制时计算较少。还要确保为绘画添加抖动和抗锯齿。
canvasPaint = new Paint();
canvasPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER ));
canvas.drawBitmap(cluster.Picture, cluster.BoardLocation.left,
cluster.BoardLocation.top, canvasPaint );
我正在 SurfaceView 上绘制一组图像 canvas。 doDraw 在获取 surfaceHolder 后由游戏循环线程调用。问题是当在 canvas 上绘制的图像数量很大时,每秒帧数 (FPS) 确实很低。这是因为 drawBitmap 很慢。
测试设置
clusters arraylist 有 400 个小图像 (cluster.Picture)。时间差是 运行 drawBitmap 循环的测量参数。为了进行比较,我用 drawRect 替换了 drawBitmap,并且还注释掉了 drawBitmap,使循环体为空。 用于测试的设备 https://www.optus.com.au/shop/prepaidmobile/lg/leon
测试结果(毫秒)
- drawBitmap 400 循环 - 平均值:25.5,最小值:14,最大值:37
- drawRect 400 循环 - 平均值:8.6,最小值:5,最大值:21
- 无 400 循环 - 平均值:1.3,最小值:0,最大值:10
以上时间只测了部分逻辑。整个游戏循环需要将近 40 毫秒。这意味着 FPS 真的很低。即使是 100 次循环,仅绘制位图也需要 18 毫秒。
我尝试设置 getHolder().setFormat(PixelFormat.RGBA_8888)、setFixedSize(screenSize.x , screenSize.y) 和 zorder 以及将位图配置设置为 RGBA_8888.此外,我尝试使用游戏线程的 setPriority 设置高优先级。
我不确定我还能做什么。如何提高游戏循环和 FPS 的性能。
public List<PCluster> clusters = new ArrayList<PCluster>();
public void doDraw(Canvas canvas) {
try {
if (canvas == null) {
return;
}
super.draw(canvas);
canvas.drawColor(backColor);
if (waitTillLoad) {
return;
}
} catch (Exception ex) {
}
final int savedState = canvas.save();
try {
minX = (int) (((viewWidth / mScaleFactor) - Gen.screenSizeWidth) / 2) * Utils.VIEW_SIZE;
minY = (int) (((viewHeight / mScaleFactor) - Gen.screenSizeHeight) / 2) * Utils.VIEW_SIZE;
if (mPosX > maxX) {
mPosX = maxX;
}
if (mPosX < minX) {
mPosX = minX;
}
if (mPosY > maxY) {
mPosY = maxY;
}
if (mPosY < minY) {
mPosY = minY;
}
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(mPosX, mPosY);
long startTime = System.currentTimeMillis();
if (!showBackground) {
for (PCluster cluster : clusters) {
if (cluster.isVisible) {
canvas.drawBitmap(cluster.Picture, cluster.BoardLocation.left,
cluster.BoardLocation.top, null);
}
}
Log.d("myApp", " " + (System.currentTimeMillis() - startTime));
}
} catch (Exception ex) {
} finally {
canvas.restoreToCount(savedState);
}
}
我能够使用 PorterDuff SRC_OVER 绘制对象来提高性能。这可能是因为透明图像相互重叠绘制时计算较少。还要确保为绘画添加抖动和抗锯齿。
canvasPaint = new Paint();
canvasPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER ));
canvas.drawBitmap(cluster.Picture, cluster.BoardLocation.left,
cluster.BoardLocation.top, canvasPaint );