0

我正在寻找一种使用 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 调用的错误。他们似乎都成功了。谢谢你的帮助

在谷歌群组上发布了这个问题。来自谷歌的布赖恩在这里有一些建议: 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;
}
4

1 回答 1

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;
}
于 2014-02-05T19:09:52.720 回答