Android - RenderScript - Падение производительности в SDK 21
Я разрабатываю проект, который требует сложных эффектов наложения типа Photoshop. Я использую кастом RenderScript
сценарии, чтобы решить это.
Я проверял это на Samsung Galaxy S4
На устройстве работает Kitkat, и все работает отлично и очень быстро.
Затем я попытался протестировать его на Nexus 5 под управлением Lollipop, и я заметил внезапное падение производительности.
Я начал синхронизировать отдельные разделы в коде, чтобы увидеть, какие части замедляются, и придумал следующее:
Allocation.createFromBitmap
- Runtime on Kitkat - ~5-10 millisec
- Runtime on Lollipop - ~100-150 millisec
mRenderScript.destory()
- Runtime on Kitkat - ~1-3 millisec
- Runtime on Lollipop - ~60-100 millisec
Мне любопытно, почему происходит внезапное падение производительности при создании Allocation
объекты и уничтожение RenderScript
объекты на устройстве, которое должно быть сильнее, и на ОС, которая должна быть более продвинутой.
Могу ли я что-нибудь сделать для ОС API 21, чтобы эти методы работали быстрее?
Кто-нибудь вообще сталкивался с этой проблемой или может ее воспроизвести?
Я должен отметить, что фактическое выполнение скрипта (т.е. ScriptC.forEach
метод) работает очень быстро на обоих устройствах / ОС. Также я пользуюсь родным RenderScript
API, а не какие-либо библиотеки поддержки.
Любой вклад будет оценен.
Редактировать:
Я скопировал соответствующую строку из исходного кода Android-релиза Lollipop в Github of Allocation.java
static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
}
return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
USAGE_GRAPHICS_TEXTURE);
}
Обратите внимание, что когда целевой SDK выше 17, распределение создается по умолчанию с USAGE_SHARED
флаг. Может ли быть, что эти дополнительные флаги вызывают проблему? Должен ли я использовать USAGE_GRAPHICS_TEXTURE
флаг вместо?
Редактировать 2
Следуя совету Р. Джейсона Сэма, я запустил следующий скрипт, когда Nexus 5 был подключен к моему компьютеру:
adb shell setprop debug.rs.default-CPU-driver 1
После этого время выполнения указанных функций значительно быстрее (~30-40 миллисекунд и 20-50 миллисекунд соответственно). Все еще не так быстро, как устройства перед леденцом на палочке, но в пределах допустимого диапазона производительности.
Моя единственная проблема с этим решением - то, что, если я чего-то не понимаю, не может считаться решением, так как это потребовало бы от меня вызова этого скрипта на каждом проблемном устройстве перед запуском приложения на нем.
Что-нибудь, что я могу сделать в своем коде, который может симулировать этот вызов adb?
Окончательное редактирование
Итак, похоже, что проблема возникла из-за того, что я создавал новый объект RenderScript каждый раз, когда вызывал функцию, которая выполняла эффект наложения с использованием RenderScript.
Я провел некоторый рефакторинг кода, и теперь вместо создания нового объекта RenderScript при каждом вызове метода эффекта я снова использую один и тот же объект каждый раз. Первое создание объекта RenderScript по-прежнему занимает гораздо больше времени для создания на устройствах Lollipop, но теперь проблема устранена, поскольку я продолжаю повторно использовать один и тот же объект в течение нескольких вызовов метода.
Я добавлю это как ответ.
2 ответа
Кажется, проблема возникла из-за того, что я создавал новый RenderScript
объект каждый раз, когда я вызывал функцию, которая выполняла эффект наложения, используя RenderScript
,
Я сделал некоторый рефакторинг кода и теперь вместо создания нового RenderScript
объект при каждом вызове метода эффекта, я использую один и тот же каждый раз. 1-е создание RenderScript
Создание объекта по-прежнему занимает гораздо больше времени на устройствах Lollipop, но теперь проблема устранена, поскольку я продолжаю повторно использовать один и тот же объект в течение нескольких вызовов методов.
Я обязательно позвоню destory()
на общем RenderScript
если я уверен, что он мне больше не нужен, чтобы не было утечек памяти.
Согласно этому посту, кажется, что повторное использование является честной практикой RenderScript
объекты, а не создание нового каждый раз, но я был бы рад услышать мнение других людей относительно их опыта в этом вопросе. Жаль, что в Интернете не так много документации по этой теме, но пока все работает хорошо на разных устройствах.
В Api 18 был добавлен тип распределения (USAGE_SHARED). Если вы заставляете Renderscript копировать резервную копию растрового изображения (вместо того, чтобы использовать ее на месте), это может объяснить разницу.
Allocation tmpOut = Allocation.createFromBitmap(mRenderContext, result, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SHARED);