mro*_*avy 11 c++ android opengl-es skia android-camera2
我的 OpenGL/Skia Android Camera2 应用程序遇到奇怪的问题。
我的相机将帧渲染为SurfaceTexture,这是GL_TEXTURE_EXTERNAL_OESOpenGL 中的纹理。
然后,我可以使用简单的直通着色器简单地将这个 OpenGL 纹理渲染到所有输出(1920x1080 Preview EGLSurface、4000x2000 Video Recorder )。EGLSurface
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Video Recorder Output EGLSurface
Run Code Online (Sandbox Code Playgroud)
现在我想将 Skia 引入其中,它允许我在将其传递到输出之前渲染到相机框架上(例如,在框架上绘制一个红色框)。由于我无法GL_TEXTURE_EXTERNAL_OES再次直接渲染到相同的对象上,因此我创建了一个单独的离屏纹理 ( GL_TEXTURE_2D) 和一个单独的离屏帧缓冲区 (FBO1) 并附加了它们。
现在,当我渲染到 FBO1 时,屏幕外纹理GL_TEXTURE_2D会更新,然后我想将其传递GL_TEXTURE_2D到我的输出:
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> Skia to FBO1 + drawing a red box --> GL_TEXTURE_2D
GL_TEXTURE_2D --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_2D --> PassThroughShader --> Video Recorder Output EGLSurface
Run Code Online (Sandbox Code Playgroud)
但由于某种原因,这只绘制了第一帧,然后卡住并在屏幕上呈现奇怪的故障伪像。请参阅此处的视频演示: https://github.com/mrousavy/react-native-vision-camera/assets/15199031/254a5455-b9cf-4c1e-9cb9-85f9b60d0cd5
相关文件是:
_inputTexture( GL_TEXTURE_EXTERNAL_OES) 后调用。
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Video Recorder Output EGLSurface
Run Code Online (Sandbox Code Playgroud)
GL_TEXTURE_2D) 上并添加一些额外的 Skia 命令(绘制红色矩形)。
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> Skia to FBO1 + drawing a red box --> GL_TEXTURE_2D
GL_TEXTURE_2D --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_2D --> PassThroughShader --> Video Recorder Output EGLSurface
Run Code Online (Sandbox Code Playgroud)
GL_TEXTURE_2D包含帧和红色矩形的离屏纹理 ( ) 进行调用。这会将框架渲染到输出 EGLSurface。
// Camera texture
OpenGLTexture& cameraTexture = _inputTexture.value();
// Render to new texture using Skia
auto newTexture = skia->renderFrame(_glContext, cameraTexture);
// Reset the bindings
glBindTexture(GL_TEXTURE_2D, newTexture.id);
glBindFramebuffer(GL_FRAMEBUFFER, DEFAULT_FRAMEBUFFER);
// Render to all outputs
if (_previewOutput) {
_previewOutput->renderTextureToSurface(newTexture, transformMatrix);
}
if (_recordingSessionOutput) {
_recordingSessionOutput->renderTextureToSurface(newTexture, transformMatrix);
}
Run Code Online (Sandbox Code Playgroud)
sampler2D而不是samplerExternalOES,对吧?)
if (_skiaContext == nullptr) {
_skiaContext = GrDirectContext::MakeGL();
}
if (_offscreenSurface == nullptr) {
GrBackendTexture skiaTex = _skiaContext->createBackendTexture(cameraTexture.width,
cameraTexture.height,
SkColorType::kN32_SkColorType,
GrMipMapped::kNo,
GrRenderable::kYes);
GrGLTextureInfo info;
skiaTex.getGLTextureInfo(&info);
_offscreenSurfaceTextureId = info.fID;
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
_offscreenSurface = SkSurfaces::WrapBackendTexture(_skiaContext.get(),
skiaTex,
kBottomLeft_GrSurfaceOrigin,
0,
SkColorType::kN32_SkColorType,
nullptr,
&props,
// TODO: Delete texture!
nullptr);
}
GrGLTextureInfo textureInfo {
// OpenGL will automatically convert YUV -> RGB because it's an EXTERNAL texture
.fTarget = GL_TEXTURE_EXTERNAL_OES,
.fID = cameraTexture.id,
.fFormat = GR_GL_RGBA8,
.fProtected = skgpu::Protected::kNo,
};
GrBackendTexture skiaTexture(cameraTexture.width,
cameraTexture.height,
GrMipMapped::kNo,
textureInfo);
sk_sp<SkImage> frame = SkImages::BorrowTextureFrom(_skiaContext.get(),
skiaTexture,
kBottomLeft_GrSurfaceOrigin,
kN32_SkColorType,
kOpaque_SkAlphaType,
nullptr,
nullptr);
SkCanvas* canvas = _offscreenSurface->getCanvas();
canvas->clear(SkColors::kCyan);
canvas->drawImage(frame, 0, 0);
SkRect rect = SkRect::MakeXYWH(150, 250, random() * 200, random() * 400);
SkPaint paint;
paint.setColor(SkColors::kGreen);
canvas->drawRect(rect, paint);
_offscreenSurface->flushAndSubmit();
Run Code Online (Sandbox Code Playgroud)
着色器在这里:
if (_surface == EGL_NO_SURFACE) {
_context->makeCurrent();
_surface = eglCreateWindowSurface(_context->display, _context->config, _outputSurface, nullptr);
}
// 1. Activate the OpenGL context for this surface
_context->makeCurrent(_surface);
// 2. Set the viewport for rendering
glViewport(0, 0, _width, _height);
glDisable(GL_BLEND);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // <-- red for debug
glClear(GL_COLOR_BUFFER_BIT);
// 3. Bind the input texture
glBindTexture(GL_TEXTURE_2D, newTexture.id);
// 4. Draw it using the pass-through shader which also applies transforms
_passThroughShader.draw(newTexture, transformMatrix);
// 5. Swap buffers to pass it to the window surface
_context->flush();
Run Code Online (Sandbox Code Playgroud)
OpenGL 设置在这里,我基本上有一个 1x1 pbuffer 用于创建我的纹理,然后我在输出 EGLSurfaces 之间切换以进行渲染。当我渲染到离屏帧缓冲区 (TEXTURE_2D) 时,1x1 pbuffer 处于活动状态。
我不确定 Skia 是否正在执行一些我应该撤消的纹理/缓冲区绑定,是否存在内存问题,是否直通着色器错误,或者变换矩阵是否也需要应用于 Skia 着色器。
如果你想看一下这个;
yarn && cd example && yarnexample/android在 Android Studio 中打开任何帮助表示赞赏!