You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Skia渲染结果在外部OpenGL环境绘制显示黑屏求助

Skia渲染到FBO后外部OpenGL绘制黑屏排查

我尝试将Skia的渲染结果绘制到FBO而非直接绘制到窗口帧缓冲,步骤如下:

  • 创建关联FBO的纹理
  • 使用SkSurfaces::WrapBackendRenderTarget,基于已创建的FBO创建SkSurface
  • 通过Skia的Canvas进行绘制
  • 在外部OpenGL环境中将步骤1创建的纹理绘制到屏幕,但显示黑屏

完成步骤3后导出该纹理,确认其内容是正确的,相关代码片段如下:

//initialize in render thread:
glfwMakeContextCurrent(native_window_);
int width = 800, height = 600;
sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
GrDirectContext* grDirectContext_ = GrDirectContexts::MakeGL(GrGLMakeNativeInterface(), GrContextOptions()).release();
shared_ptr<TextureData> g_texture = CITextureUtils::createTextureWithFBO(CIGLContext::getInstance(), width, height);
sk_sp<SkSurface> g_surface = SkSurfaces::WrapBackendRenderTarget(
        grDirectContext_,
        GrBackendRenderTargets::MakeGL(width,
                                        height,
                                        1,
                                        8,
                                        GrGLFramebufferInfo{(GrGLuint)g_texture->fbo, GL_RGBA8}),
        kBottomLeft_GrSurfaceOrigin,
        kRGBA_8888_SkColorType,
        nullptr,
        nullptr);

//the draw loop in render thread:

SkCanvas *canvas = g_surface->getCanvas();
canvas->clear(kClearColor);
canvas->save();
canvas->translate(SkIntToScalar(128), SkIntToScalar(128));
canvas->rotate(SkIntToScalar(45));
SkRect rect = SkRect::MakeXYWH(-90.5f, -90.5f, 181.0f, 181.0f);
SkPaint paint;
paint.setColor(SK_ColorBLUE);
canvas->drawRect(rect, paint);
canvas->restore();
grDirectContext_->flush();
grDirectContext_->resetContext();
// here dump the created texture, the texture has right context
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lOldFbo);
glBindFramebuffer(GL_FRAMEBUFFER, texture->fbo);
glReadPixels(0, 0, bitmap->width, bitmap->height, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->plane[0]);
glBindFramebuffer(GL_FRAMEBUFFER, lOldFbo);

// draw in outside opengl environment in render thread:

glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, g_texture->textureID);
GLint currProgram;
glGetIntegerv(GL_CURRENT_PROGRAM, &currProgram);
shader_.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glfwSwapBuffers((GLFWwindow*)window_);

排查方向:

  1. Y轴方向不匹配
    Skia使用kBottomLeft_GrSurfaceOrigin,纹理原点在左下角;而OpenGL默认纹理原点在右上角。若着色器未处理Y轴翻转,会导致内容显示异常甚至黑屏。可在片段着色器中修改纹理坐标:
vec4 color = texture(u_texture, vec2(texCoord.x, 1.0 - texCoord.y));
  1. Skia上下文状态残留
    即使调用了flush()和resetContext(),Skia可能仍占用部分OpenGL状态。建议在Skia绘制完成后:
  • 明确绑定默认帧缓冲:glBindFramebuffer(GL_FRAMEBUFFER, 0);
  • 重置纹理绑定状态,确保后续绘制使用正确的纹理单元
  1. 纹理采样参数未正确设置
    若纹理未设置合理的过滤和环绕参数,会导致采样失败。创建纹理后添加:
glBindTexture(GL_TEXTURE_2D, g_texture->textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1. GPU命令未同步
    glReadPixels会等待GPU完成,但后续绘制可能未等待Skia的渲染命令执行完毕。在grDirectContext_->flush()后添加glFinish(),确保FBO渲染完成后再进行屏幕绘制。

  2. 着色器纹理绑定错误
    检查着色器中纹理变量的绑定:

  • 激活对应纹理单元:glActiveTexture(GL_TEXTURE0);
  • 在使用着色器后设置纹理单元索引:glUniform1i(glGetUniformLocation(shader_.ID, "u_texture"), 0);

内容的提问来源于stack exchange,提问作者xiaoming wang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:35:06