2014-02-14 2 views
7

ПРЕДПОСЫЛКА:рендеринг рендеринга рендеринга намного медленнее, чем рендеринг OpenGL на Android

Я хочу добавить живой фильтр на основе кода приложения для Android-камеры. Но архитектура приложения для Android-камер основана на OpenGL ES 1.x. Мне нужно использовать шейдер для настройки нашей фильтрации. Тем не менее, слишком сложно обновить приложение камеры до OpenGL ES 2.0. Затем мне нужно найти другие методы для реализации фильтра Live вместо OpenGL. После некоторых исследований я решил использовать сценарий рендеринга.

ПРОБЛЕМА:

Я написал демо простой фильтр по визуализации сценария. Это показывает, что fps намного ниже, чем реализация OpenGL. Около 5 кадров в секунду против 15 кадров в секунду.

ВОПРОСЫ:

  1. Официальный внеплощадочный Android говорит: среда Renderscript будет распараллелить работу всех процессоров, доступных на устройстве, такие как многоядерные процессоры, графические процессоры, или ЦСП, позволяя Вам сосредоточиться на выражая алгоритмы, а не планируя работу или балансировку нагрузки. Тогда почему рендеринг скрипта выполняется медленнее?

  2. Если сценарий рендеринга не может удовлетворить мои требования, есть ли лучший способ?

КОД ДЕТАЛИ:

Привет Я нахожусь в одной команде с спрашивающего. Мы хотим написать камеру 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; 
} 
+0

Можете ли вы рассказать, как код отличается между двумя версиями? Я подозреваю, что проблема заключается в получении данных с камеры в RS. –

+0

@ R.JasonSams Спасибо за ваш ответ. Я отредактировал мой вопрос. И добавил код. –

+3

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 и некоторые графические процессоры требуют расслабления). Это основные моменты. –

ответ

3

Renderscript не использует GPU или ЦСП ядер. Это распространенное заблуждение, поощряемое преднамеренно расплывчатой ​​документацией Google. У Renderscript был интерфейс с OpenGL ES, но он был устаревшим и никогда не использовался за пределами анимированных обоев. Renderscript будет использовать несколько ядер процессора, если они доступны, но я подозреваю, что Renderscript будет заменен OpenCL.

Взгляните на класс «Эффекты» и демо-версию эффектов в Android SDK. В нем показано, как использовать шейдеры OpenGL ES 2.0 для применения эффектов к изображениям без написания кода OpenGL ES.

http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1

UPDATE:

Это замечательно, когда я узнаю больше, отвечая на вопрос, чем спрашивать одно и то в данном случае. Из-за отсутствия ответов видно, что Renderscript вряд ли используется вне Google из-за своей странной архитектуры, которая игнорирует отраслевые стандарты, такие как OpenCL, и почти несуществующую документацию о том, как она работает. Тем не менее, мой ответ действительно вызывает редкий ответ от команды разработчиков Renderscrpt, которая включает в себя только один ссылку, которая на самом деле содержит никакой полезной информацию о Renderscript - эта статья Александра Voica в IMG, поставщик PowerVR GPU:

http://withimagination.imgtec.com/index.php/powervr/running-renderscript-efficiently-with-powervr-gpus-on-android

В этой статье есть хорошая информация, которая была для меня новой. Есть комментарии, размещенные там от большего числа людей, у которых возникают проблемы с получением кода Renderscript для фактического запуска на GPU.

Но я ошибался, полагая, что Renderscript больше не разрабатывается в Google. Хотя мое утверждение о том, что «RendersScript не использует ядра GPU или DSPs». был прав до недавнего времени, я узнал, что это изменилось как один из выпусков Jelly Bean. Было бы здорово, если бы один из разработчиков Renderscript мог это объяснить. Или даже если у них была общедоступная веб-страница, которая объясняет, что или что содержит , какие GPU действительно поддерживаются и как вы можете определить, действительно ли ваш код запускается на графическом процессоре.

Мое мнение, что Google заменит Renderscript OpenCL в конце концов, и я бы не стал инвестировать время в разработку с ним.

+5

«Отсутствие поддержки GPU» абсолютно неверно, каждое устройство Nexus, находящееся на рынке (и множество других устройств), отправляется с драйверами RS GPU. –

+0

Для этого им нужно будет предоставить компилятор шейдеров GLSL для каждого типа и версии графического процессора, используемого в Nexus, и даже тогда код Renderscript не будет переносимым на устройства Android с разными графическими процессорами, что нарушит гарантию Google портативность. – ClayMontgomery

+4

, что совершенно неверно. RS и GLSL не имеют ничего общего друг с другом; они являются полностью отдельными стеками драйверов пользовательского режима. RS-код может быть запущен на CPU для устройств без поддержки графического процессора или на GPU, когда присутствует соответствующий графический процессор. разработчику не нужно предоставлять несколько исходных файлов или что-то в этом роде. (источник: я работаю над временем выполнения RS, моделью драйверов и API) –

Смежные вопросы