Android: Canvas.DrawBitmap VS Drawable.Draw - Огромное повышение производительности

Я только что кое-что узнал, и мне было интересно, как и почему. Я разрабатываю небольшую аркадную игру для Android. Я решил игнорировать OpenGL и использовать стандартные SurfaceView и Drawables, чтобы сделать это, так как он предположительно будет светлым (10 спрайтов или около того). У меня есть drawables, которые я загружаю, и использую метод Draw и передавая им свой холст. Это как каждый спрайт обращается к экрану. Хорошо получается, что рисунок 4-5 больших спрайтов (200X400 или около того) занимает много времени на менее чем новых моделях телефонов. Достаточно долго, чтобы моя игра была неиграбельной. Мы говорим о 50-60 миллисекундах для создания одного кадра с использованием этого метода. И я действительно ничего не делаю, кроме рисунка, и нигде я не могу сократить расходы. Поэтому я решил попробовать использовать Bitmaps. Здесь, однако, мне нужно предварительно задать размер, так как в растровом виде нет метода setBounds. Нет проблем, я изменяю их размер, чтобы соответствовать моему текущему экрану при загрузке, проблема решена.

OK. Поэтому у меня есть растровые изображения. Теперь я использую Canvas.DrawBitmap для рисования. Я скачу новый метод рисования.. и я получаю повышение эффективности 400%!. Вместо 50-60 мс весь цикл рисования теперь занимает 8-12 мс. Какого черта??? Чтобы исключить это, я тоже приурочил setBounds, он занимает < 1ms, чтобы он не виноват. Это фактический Drawable.Draw, который замедляет работу.

Для меня это отличная новость, так как я действительно не хотел изучать OpenGL, чтобы сделать игру более доступной, но я не могу перестать думать об этом - все в порядке? есть ли проблемы с моим методом? Почему он нигде не упоминается?

Ответы

Ответ 1

SurfaceView SurfaceView предназначен для использования при постоянном повторении и Drawable не для этой цели.

Ответ 2

Canvas.drawBitmap работает намного меньше, чем Drawable.draw, поэтому он быстрее.

Drawable.draw

Поскольку Drawable является абстрактным классом, рассмотрим BitmapDrawable:

BitmapDrawable.draw(холст)

public void draw(Canvas canvas) {
    final Bitmap bitmap = mBitmapState.mBitmap;
    if (bitmap == null) {
        return;
    }
    final BitmapState state = mBitmapState;
    final Paint paint = state.mPaint;
    if (state.mRebuildShader) {
        final Shader.TileMode tmx = state.mTileModeX;
        final Shader.TileMode tmy = state.mTileModeY;
        if (tmx == null && tmy == null) {
            paint.setShader(null);
        } else {
            paint.setShader(new BitmapShader(bitmap,
                    tmx == null ? Shader.TileMode.CLAMP : tmx,
                    tmy == null ? Shader.TileMode.CLAMP : tmy));
        }
        state.mRebuildShader = false;
    }
    final int restoreAlpha;
    if (state.mBaseAlpha != 1.0f) {
        final Paint p = getPaint();
        restoreAlpha = p.getAlpha();
        p.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
    } else {
        restoreAlpha = -1;
    }
    final boolean clearColorFilter;
    if (mTintFilter != null && paint.getColorFilter() == null) {
        paint.setColorFilter(mTintFilter);
        clearColorFilter = true;
    } else {
        clearColorFilter = false;
    }
    updateDstRectAndInsetsIfDirty();
    final Shader shader = paint.getShader();
    final boolean needMirroring = needMirroring();
    if (shader == null) {
        if (needMirroring) {
            canvas.save();
            // Mirror the bitmap
            canvas.translate(mDstRect.right - mDstRect.left, 0);
            canvas.scale(-1.0f, 1.0f);
        }
        canvas.drawBitmap(bitmap, null, mDstRect, paint);
        if (needMirroring) {
            canvas.restore();
        }
    } else {
        updateShaderMatrix(bitmap, paint, shader, needMirroring);
        canvas.drawRect(mDstRect, paint);
    }
    if (clearColorFilter) {
        paint.setColorFilter(null);
    }
    if (restoreAlpha >= 0) {
        paint.setAlpha(restoreAlpha);
    }
}

Вы можете видеть, что он даже вызывает Canvas.drawBitmap внутренне.

Canvas.drawBitmap

Сравните это с Canvas.drawBitmap. Это намного короче.

Canvas.drawBitmap

public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
    throwIfCannotDraw(bitmap);
    native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top,
            paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
}

Существует несколько различных методов drawBitmap, но все они короче метода Drawable.draw. Остерегайтесь ловушек как это, чтобы быстро сохранить рисунок растрового изображения.