Оригинал взят у
droids_life в
Жук в Canvas.drawBitmap на андроиде. Занятный жук всплыл при переработке кода
шашек. Там был алгоритм рендеринга подсветки полей, куда может ходить шашечка. Использовалась т.н. «off-screen» битовая карта для промежуточных результатов. Схема несложная:
for (клетка in поля для хода)
{
отрисовать клетку в битовую карту;
canvas.drawBitmap(...);}
Сия свистопляска нужна для случая, когда шашечка может прийти в конечную клетку несколькими путями. Тогда мы красим метку окончания хода в несколько цветов. Эта покраска делается равными (по углу) сегментами окружности, маскированными картинкой от нашего дизайнера.
Маска (зелёное - нулевая альфа):
Сегменты без маскирования:
Итоговый выхлоп:
В игре:
Если б разноцветности не было, то можно просто рисовать чёрно-белую картинку с матричным преобразованием цвета (см.
ColorMatrixColorFilter). После переработки кода по какой-то причине вышеозначенный схематоз сломался: все клетки стали рисоваться, как последняя в цикле. Как будто содержимое битовой карты на каждый вызов
drawBitmap было одним и тем же. Как выяснилось, причина проблемы появилась ещё в 2011 и не исправлена до сих пор.
Начиная с версии
андроида 3.0 все приложения, которые в своём манифесте в
targetSdkVersion ставят 14, автоматом получают
рендеринг пользовательского интерфейса через видеокарту. Про трансляцию методов класса
Canvas в соотв. OpenGL ES вызовы очень интересно
рассказывал Romain Guy на Google IO 2011.
Создавать на каждый кадр, а уж тем более на каждую клетку, по битовой карте - непозволительное расточительство. Поэтому в памяти была одна картинка, в которую всё и рисовалось. Кроме флагов в манифесте есть ещё условия неполучения аппаратного ускорения. И они были соблюдены в шашках. А после переработки кода получилось так, что включилось аппаратное ускорение, и рендеринг через объект класса
Canvas переставал быть моментальным (т.н. immediate mode) - все команды на отрисовку начали идти в буфер, который потом выполняла нить рендеринга. Соответственно каждый вызов
drawBitmap запоминал в качестве своего аргумента ссылку на одну и ту же битовую карту, содержимое которой менялось (кстати, тоже через
Canvas,
созданный с ней в качестве аргумента конструктора).
Простейшее решение, явно запретить аппаратный рендеринг пользовательского интерфейса, не сработало на аппаратах с большим экраном - анимации лютейшим образом тормозили. Что интересно, на старичках с андроидом версии
2.3 и экраном 320x480 всё было замечательно. Видимо, в гугле таким же образом пришли к реализации рисования UI через OpenGL (упёрлись в пропускную способность памяти?): экраны телефонов расли, да и планшеты надо было окучивать.
В итоге переписал алгоритм на рендеринг без промежуточного буфера - запользовал класс
BitmapShader при отрисовке сегментов окружности.