如何使用Skia SkBitmap在EGL纹理上绘制文本?

时间:2014-01-21 17:35:01

标签: c++ opengl-es android-ndk android-source skia

我正在寻找一种在C / C ++中使用Skia库在EGLTexture上绘制文本的方法。我打算在启动SurfaceFlinger之前运行一个在启动时在Android平台上运行的程序。

请不要指向Android Java示例,因为这不是我想要的。我在帧缓冲级别解决UI问题。我正在寻找一种使用Android原生库(Skia等)在C / C ++中完成此操作的方法。

我有一个示例程序可以使用SkBitmap将图像渲染到EGLTexture上。我能够在显示器上显示它。我按照同样的例子提出了这样的策略。但它不起作用。

0)用绿色清除屏幕
1)创建大小为640x480的SkBitmap 2)创建由SkBitmap.lockPixels()返回的像素缓冲区支持的EGLTexture 3)使用SkCanvas在SkBitmap上绘制文本。将位图上传到上面的纹理中。 4)然后在当前表面上绘制纹理

我使用启动动画程序(android)作为我的起点。 当我运行这个程序时,我看到的只是绿色。我检查了EGL调用的错误。他们似乎都成功了。谢谢你的帮助

在google群组上发布此问题。谷歌的Brian在这里有一些指示: 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;
}

1 个答案:

答案 0 :(得分: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;
}