ПРЕДПОСЫЛКА:рендеринг рендеринга рендеринга намного медленнее, чем рендеринг OpenGL на Android
Я хочу добавить живой фильтр на основе кода приложения для Android-камеры. Но архитектура приложения для Android-камер основана на OpenGL ES 1.x. Мне нужно использовать шейдер для настройки нашей фильтрации. Тем не менее, слишком сложно обновить приложение камеры до OpenGL ES 2.0. Затем мне нужно найти другие методы для реализации фильтра Live вместо OpenGL. После некоторых исследований я решил использовать сценарий рендеринга.
ПРОБЛЕМА:
Я написал демо простой фильтр по визуализации сценария. Это показывает, что fps намного ниже, чем реализация OpenGL. Около 5 кадров в секунду против 15 кадров в секунду.
ВОПРОСЫ:
Официальный внеплощадочный Android говорит: среда Renderscript будет распараллелить работу всех процессоров, доступных на устройстве, такие как многоядерные процессоры, графические процессоры, или ЦСП, позволяя Вам сосредоточиться на выражая алгоритмы, а не планируя работу или балансировку нагрузки. Тогда почему рендеринг скрипта выполняется медленнее?
Если сценарий рендеринга не может удовлетворить мои требования, есть ли лучший способ?
КОД ДЕТАЛИ:
Привет Я нахожусь в одной команде с спрашивающего. Мы хотим написать камеру live-filter на основе рендеринга. В нашем тестовом демо-проекте мы используем простой фильтр: IntrinsicScript YuvToRGB добавлен с сценарием ScriptC наложения-фильтра. В версии OpenGL мы устанавливаем данные камеры как текстуры и выполняем процесс image-filter-procss с шейдером. Как это:
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureYHandle);
GLES20.glUniform1i(shader.uniforms.get("uTextureY"), 0);
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mTextureWidth,
mTextureHeight, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
mPixelsYBuffer.position(0));
В версии Renderscript мы устанавливаем данные камеры, как выделение и сделать изображение-фильтр-procss с скрипт-kernals. Как это:
// The belowing code is from onPreviewFrame(byte[] data, Camera camera) which gives the camera frame data
byte[] imageData = datas[0];
long timeBegin = System.currentTimeMillis();
mYUVInAllocation.copyFrom(imageData);
mYuv.setInput(mYUVInAllocation);
mYuv.forEach(mRGBAAllocationA);
// To make sure the process of YUVtoRGBA has finished!
mRGBAAllocationA.copyTo(mOutBitmap);
Log.e(TAG, "RS time: YUV to RGBA : " + String.valueOf((System.currentTimeMillis() - timeBegin)));
mLayerScript.forEach_overlay(mRGBAAllocationA, mRGBAAllocationB);
mRGBAAllocationB.copyTo(mOutBitmap);
Log.e(TAG, "RS time: overlay : " + String.valueOf((System.currentTimeMillis() - timeBegin)));
mCameraSurPreview.refresh(mOutBitmap, mCameraDisplayOrientation, timeBegin);
две проблемы: (1) Renderscript процесс кажется медленнее, чем процесс OpenGL. (2) Согласно нашему журналу времени, процесс YUV для RGBA, который использует встроенный скрипт, очень быстрый, занимает около 6 мс; но процесс наложения, который использует scriptC, очень медленный, занимает около 180 мс. Как это произошло?
Вот RS-Kernal код ScriptC мы используем (mLayerScript):
#pragma version(1)
#pragma rs java_package_name(**.renderscript)
#pragma stateFragment(parent)
#include "rs_graphics.rsh"
static rs_allocation layer;
static uint32_t dimX;
static uint32_t dimY;
void setLayer(rs_allocation layer1) {
layer = layer1;
}
void setBitmapDim(uint32_t dimX1, uint32_t dimY1) {
dimX = dimX1;
dimY = dimY1;
}
static float BlendOverlayf(float base, float blend) {
return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));
}
static float3 BlendOverlay(float3 base, float3 blend) {
float3 blendOverLayPixel = {BlendOverlayf(base.r, blend.r), BlendOverlayf(base.g, blend.g), BlendOverlayf(base.b, blend.b)};
return blendOverLayPixel;
}
uchar4 __attribute__((kernel)) overlay(uchar4 in, uint32_t x, uint32_t y) {
float4 inPixel = rsUnpackColor8888(in);
uint32_t layerDimX = rsAllocationGetDimX(layer);
uint32_t layerDimY = rsAllocationGetDimY(layer);
uint32_t layerX = x * layerDimX/dimX;
uint32_t layerY = y * layerDimY/dimY;
uchar4* p = (uchar4*)rsGetElementAt(layer, layerX, layerY);
float4 layerPixel = rsUnpackColor8888(*p);
float3 color = BlendOverlay(inPixel.rgb, layerPixel.rgb);
float4 outf = {color.r, color.g, color.b, inPixel.a};
uchar4 outc = rsPackColorTo8888(outf.r, outf.g, outf.b, outf.a);
return outc;
}
Можете ли вы рассказать, как код отличается между двумя версиями? Я подозреваю, что проблема заключается в получении данных с камеры в RS. –
@ R.JasonSams Спасибо за ваш ответ. Я отредактировал мой вопрос. И добавил код. –
1. Не используйте rsAllocationGetDimX. передайте их как глобальные (например, dimX и dimY). 2. Не забудьте суффикс f на ваших константах. вы используете двойную точность прямо сейчас. 3. Используйте rsGetElementAt_uchar4, а не rsGetElementAt. 4. Не включайте rs_graphics.rsh, это не нужно. 5. рассмотрите кэширование layerDimX/DimX как глобального (то же, что и Y). 6. попробуйте #pragma rs_fp_relaxed, включите некоторые дополнительные оптимизации, если вам не подходит строгое соответствие IEEE-754 (NEON и некоторые графические процессоры требуют расслабления). Это основные моменты. –