Как нарисовать текст на текстуре EGL, используя Skia SkBitmap?

Я ищу способ рисовать текст на EGLTexture с использованием библиотеки Skia в C / C ++. Я планирую запустить программу, которая делает это на платформе Android во время загрузки до появления SurfaceFlinger.

Пожалуйста, не указывайте мне примеры Java для Android, так как это не то, что я ищу. Я устраняю неполадки пользовательского интерфейса на уровне кадрового буфера. Я ищу способ сделать это в C / C ++, используя родные библиотеки Android (Skia и т. Д.).

У меня есть пример программы, которая может визуализировать изображение с помощью SkBitmap на EGLTexture. Я смог отобразить его на мониторе. Я последовал тому же примеру и придумал такую ​​стратегию. Но это не работает, хотя.

0) Очистить экран зеленым цветом
1) Создайте SkBitmap размером 640×480.
2) Создайте EGLTexture, поддерживаемую пиксельным буфером, возвращаемым SkBitmap.lockPixels ()
3) Нарисуйте текст на SkBitmap с помощью SkCanvas. Загрузите растровое изображение в вышеупомянутую текстуру.
4) Затем нарисуйте текстуру на текущей поверхности

В качестве отправной точки для этого я использовал загрузочную анимационную программу (Android).
Когда я запускал эту программу, я вижу только зеленый цвет. Я проверил на ошибки вызовов EGL. Кажется, все они преуспевают. Спасибо за вашу помощь

Разместил этот вопрос в гугл группах. Брайан из Google имеет несколько указателей здесь:
https://groups.google.com/d/topic/skia-discuss/aC5f6HB4gSU/discussion

Ниже приведен код, который реализует вышеуказанное.

#define EXPECT_NO_GL_ERROR(stmt)  \
do {  \
stmt;  \
const EGLint error_code = eglGetError();  \
if (EGL_SUCCESS != error_code){  \
LOGD("GLTest: GL error code %d at %s:%d", error_code, __FILE__, __LINE__); \
__android_log_assert("GLTest", "GLtest", "GlTest"); \
}\
} while(0)

struct Texture
{
GLint w;
GLint h;
GLuint id;
};
bool GLTest::frametest()
{
Texture texFrame;

// Paint screen with green color
glShadeModel (GL_FLAT);
glDisable (GL_DITHER);
glDisable (GL_SCISSOR_TEST);
glClearColor(0, 1, 0, 1);
glClear (GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);

SkGraphics::Init();
SkBitmap bitmap;

bitmap.setConfig(SkBitmap::kARGB_8888_Config, 640, 480);
bitmap.allocPixels();
if (NO_ERROR != initTexture(&texFrame, bitmap))
{
LOGD("GLTest: Unable to create a texture that is backed by SkBitmap");
return false;
}
SkCanvas canvas(bitmap);
SkPaint textAttribs;

textAttribs.setColor(0xFFFFFFFF);
textAttribs.setTextSize(SkIntToScalar(24));

const nsecs_t startTime = systemTime();
int frame_count = 0;
do
{
nsecs_t now = systemTime();
double time = now - startTime;

canvas.drawColor(0xFF0000FF);
canvas.drawText("Hello world", strlen("Hello world"), 200, 400,
textAttribs);
initTexture(&texFrame, bitmap); // Upload bitmap into canvas
glEnable (GL_BLEND);
EXPECT_NO_GL_ERROR(glBindTexture(GL_TEXTURE_2D, texFrame.id));
EXPECT_NO_GL_ERROR(glDrawTexiOES(0, 0, 0, texFrame.w, texFrame.h));
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
break;
frame_count++;
if (0 == (frame_count % 150))
LOGD("GLTest: Completed %d frames", frame_count);
// 12fps: don't animate too fast to preserve CPU
const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
if (sleepTime > 0)
usleep(sleepTime);
} while (!exitPending());

return false;
}

status_t GLTest::initTexture(Texture* texture, SkBitmap &bitmap)
{
bitmap.lockPixels();

const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();

GLint crop[4] =
{ 0, h, w, -h };
texture->w = w;
texture->h = h;

EXPECT_NO_GL_ERROR(glGenTextures(1, &(texture->id)));
EXPECT_NO_GL_ERROR(glBindTexture(GL_TEXTURE_2D, texture->id));

switch (bitmap.getConfig())
{
case SkBitmap::kA8_Config:
EXPECT_NO_GL_ERROR(
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, p));
break;
case SkBitmap::kARGB_4444_Config:
EXPECT_NO_GL_ERROR(
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p));
break;
case SkBitmap::kARGB_8888_Config:
EXPECT_NO_GL_ERROR(
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, p));
break;
case SkBitmap::kRGB_565_Config:
EXPECT_NO_GL_ERROR(
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p));
break;
default:
break;
}

EXPECT_NO_GL_ERROR(
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop));
EXPECT_NO_GL_ERROR(
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
EXPECT_NO_GL_ERROR(
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
EXPECT_NO_GL_ERROR(
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
EXPECT_NO_GL_ERROR(
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
return NO_ERROR;
}

0

Решение

Я нашел, почему мой код не работал. При создании текстур ширина и высота должны быть степенью 2. Например, если ширина равна 1920, то текстура должна быть создана с шириной 2048 (так как 2048 является следующей степенью 2).

Изменен initTexture на ниже. Теперь я могу нарисовать текст в SkBitmap, а затем загрузить растровое изображение в текстуру и нарисовать текстуру.

Ниже приведен новый initTexture, который загружает данное растровое изображение в текстуру.

bool initTexture(Texture* texture, const SkBitmap &bitmap)
{
bool result = true;
SkAutoLockPixels alp(bitmap);

const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();
int tw = 1 << (31 - __builtin_clz(w));
int th = 1 << (31 - __builtin_clz(h));
if (tw < w)
tw <<= 1;
if (th < h)
th <<= 1;

if (NULL == texture)
return false;
if (texture->id != 0)
{
glBindTexture(GL_TEXTURE_2D, texture->id);
switch (bitmap.getConfig())
{
case SkBitmap::kA8_Config:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kARGB_4444_Config:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
case SkBitmap::kARGB_8888_Config:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kRGB_565_Config:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
break;
default:
break;
}
return true;
}
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;

glEnable (GL_TEXTURE_2D);
glGenTextures(1, &(texture->id));
glBindTexture(GL_TEXTURE_2D, texture->id);

switch (bitmap.getConfig())
{
case SkBitmap::kA8_Config:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kARGB_4444_Config:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
case SkBitmap::kARGB_8888_Config:
if (tw != w || th != h)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA,
GL_UNSIGNED_BYTE, p);
}
else
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, p);
}
break;
case SkBitmap::kRGB_565_Config:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
break;
default:
break;
}

glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
return result;
}
0

Другие решения

Других решений пока нет …