renderer-egl: Add function to render AVFrames
parent
3e652be8d6
commit
c4ffd8eef6
|
@ -2,10 +2,13 @@
|
|||
|
||||
struct buffer;
|
||||
struct image;
|
||||
struct vnc_av_frame;
|
||||
|
||||
int egl_init(void);
|
||||
void egl_finish(void);
|
||||
|
||||
void render_image_egl(struct buffer* dst, const struct image* src, double scale,
|
||||
int pos_x, int pos_y);
|
||||
void render_av_frames_egl(struct buffer* dst, struct vnc_av_frame** src,
|
||||
int n_av_frames, double scale, int x_pos, int y_pos);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "buffer.h"
|
||||
#include "renderer.h"
|
||||
#include "renderer-egl.h"
|
||||
#include "vnc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -33,6 +34,9 @@
|
|||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/hwcontext_drm.h>
|
||||
|
||||
#define XSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
|
||||
|
@ -42,6 +46,7 @@ X(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR) \
|
|||
X(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR) \
|
||||
|
||||
#define GL_EXTENSION_LIST \
|
||||
X(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC, glEGLImageTargetTexture2DOES) \
|
||||
X(PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC, glEGLImageTargetRenderbufferStorageOES) \
|
||||
|
||||
#define X(t, n) static t n;
|
||||
|
@ -64,6 +69,7 @@ static EGLDisplay egl_display = EGL_NO_DISPLAY;
|
|||
static EGLContext egl_context = EGL_NO_CONTEXT;
|
||||
|
||||
static GLuint shader_program = 0;
|
||||
static GLuint shader_program_ext = 0;
|
||||
static GLuint texture = 0;
|
||||
|
||||
static const char *vertex_shader_src =
|
||||
|
@ -83,6 +89,15 @@ static const char *fragment_shader_src =
|
|||
" gl_FragColor = texture2D(u_tex, v_texture);\n"
|
||||
"}\n";
|
||||
|
||||
static const char *fragment_shader_ext_src =
|
||||
"#extension GL_OES_EGL_image_external: require\n\n"
|
||||
"precision mediump float;\n"
|
||||
"uniform samplerExternalOES u_tex;\n"
|
||||
"varying vec2 v_texture;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = texture2D(u_tex, v_texture);\n"
|
||||
"}\n";
|
||||
|
||||
struct {
|
||||
GLuint u_tex;
|
||||
} uniforms;
|
||||
|
@ -113,10 +128,10 @@ static int egl_load_gl_ext(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void compile_shaders()
|
||||
static int compile_shaders(const char* vert_src, const char* frag_src)
|
||||
{
|
||||
GLuint vert = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert, 1, &vertex_shader_src, NULL);
|
||||
glShaderSource(vert, 1, &vert_src, NULL);
|
||||
glCompileShader(vert);
|
||||
|
||||
GLint is_compiled = 0;
|
||||
|
@ -124,29 +139,31 @@ static void compile_shaders()
|
|||
assert(is_compiled);
|
||||
|
||||
GLuint frag = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag, 1, &fragment_shader_src, NULL);
|
||||
glShaderSource(frag, 1, &frag_src, NULL);
|
||||
glCompileShader(frag);
|
||||
glGetShaderiv(frag, GL_COMPILE_STATUS, &is_compiled);
|
||||
assert(is_compiled);
|
||||
|
||||
shader_program = glCreateProgram();
|
||||
int prog = glCreateProgram();
|
||||
|
||||
glAttachShader(shader_program, vert);
|
||||
glAttachShader(shader_program, frag);
|
||||
glAttachShader(prog, vert);
|
||||
glAttachShader(prog, frag);
|
||||
|
||||
glBindAttribLocation(shader_program, ATTR_INDEX_POS, "pos");
|
||||
glBindAttribLocation(shader_program, ATTR_INDEX_TEXTURE, "texture");
|
||||
glBindAttribLocation(prog, ATTR_INDEX_POS, "pos");
|
||||
glBindAttribLocation(prog, ATTR_INDEX_TEXTURE, "texture");
|
||||
|
||||
glLinkProgram(shader_program);
|
||||
glLinkProgram(prog);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
|
||||
GLint is_linked = 0;
|
||||
glGetProgramiv(shader_program, GL_LINK_STATUS, &is_linked);
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &is_linked);
|
||||
assert(is_linked);
|
||||
|
||||
uniforms.u_tex = glGetUniformLocation(shader_program, "u_tex");
|
||||
uniforms.u_tex = glGetUniformLocation(prog, "u_tex");
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
int egl_init(void)
|
||||
|
@ -185,7 +202,10 @@ int egl_init(void)
|
|||
if (egl_load_gl_ext() < 0)
|
||||
goto failure;
|
||||
|
||||
compile_shaders();
|
||||
shader_program = compile_shaders(vertex_shader_src,
|
||||
fragment_shader_src);
|
||||
shader_program_ext = compile_shaders(vertex_shader_src,
|
||||
fragment_shader_ext_src);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -198,6 +218,8 @@ void egl_finish(void)
|
|||
{
|
||||
if (texture)
|
||||
glDeleteTextures(1, &texture);
|
||||
if (shader_program_ext)
|
||||
glDeleteProgram(shader_program_ext);
|
||||
if (shader_program)
|
||||
glDeleteProgram(shader_program);
|
||||
eglDestroyContext(egl_display, egl_context);
|
||||
|
@ -276,6 +298,78 @@ static void fbo_from_gbm_bo(struct fbo_info* dst, struct gbm_bo* bo)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
#define X(lc, uc) \
|
||||
static EGLint plane_ ## lc ## _key(int plane) \
|
||||
{ \
|
||||
switch (plane) { \
|
||||
case 0: return EGL_DMA_BUF_PLANE0_ ## uc ## _EXT; \
|
||||
case 1: return EGL_DMA_BUF_PLANE1_ ## uc ## _EXT; \
|
||||
case 2: return EGL_DMA_BUF_PLANE2_ ## uc ## _EXT; \
|
||||
case 3: return EGL_DMA_BUF_PLANE3_ ## uc ## _EXT; \
|
||||
} \
|
||||
return EGL_NONE; \
|
||||
}
|
||||
|
||||
X(fd, FD);
|
||||
X(offset, OFFSET);
|
||||
X(pitch, PITCH);
|
||||
X(modifier_lo, MODIFIER_LO);
|
||||
X(modifier_hi, MODIFIER_HI);
|
||||
#undef X
|
||||
|
||||
static void dmabuf_attr_append_planes(EGLint* dst, int* index,
|
||||
struct AVDRMFrameDescriptor* desc)
|
||||
{
|
||||
struct AVDRMPlaneDescriptor *plane;
|
||||
struct AVDRMObjectDescriptor *obj;
|
||||
|
||||
for (int i = 0; i < desc->nb_layers; ++i) {
|
||||
assert(desc->layers[i].nb_planes == 1);
|
||||
|
||||
plane = &desc->layers[i].planes[0];
|
||||
obj = &desc->objects[plane->object_index];
|
||||
|
||||
append_attr(dst, index, plane_fd_key(i), obj->fd);
|
||||
append_attr(dst, index, plane_offset_key(i), plane->offset);
|
||||
append_attr(dst, index, plane_pitch_key(i), plane->pitch);
|
||||
append_attr(dst, index, plane_modifier_lo_key(i),
|
||||
obj->format_modifier);
|
||||
append_attr(dst, index, plane_modifier_hi_key(i),
|
||||
obj->format_modifier >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
static GLuint texture_from_av_frame(const struct AVFrame* frame)
|
||||
{
|
||||
int index = 0;
|
||||
EGLint attr[128];
|
||||
|
||||
AVDRMFrameDescriptor *desc = (void*)frame->data[0];
|
||||
|
||||
append_attr(attr, &index, EGL_WIDTH, frame->width);
|
||||
append_attr(attr, &index, EGL_HEIGHT, frame->height);
|
||||
append_attr(attr, &index, EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_NV12);
|
||||
append_attr(attr, &index, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE);
|
||||
dmabuf_attr_append_planes(attr, &index, desc);
|
||||
attr[index++] = EGL_NONE;
|
||||
|
||||
EGLImageKHR image = eglCreateImageKHR(egl_display, EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT, NULL, attr);
|
||||
assert(image != EGL_NO_IMAGE_KHR);
|
||||
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
|
||||
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
|
||||
|
||||
eglDestroyImageKHR(egl_display, image);
|
||||
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
return tex;
|
||||
}
|
||||
|
||||
void gl_draw(void)
|
||||
{
|
||||
static const GLfloat s_vertices[4][2] = {
|
||||
|
@ -405,3 +499,44 @@ void render_image_egl(struct buffer* dst, const struct image* src,
|
|||
glDeleteFramebuffers(1, &fbo.fbo);
|
||||
glDeleteRenderbuffers(1, &fbo.rbo);
|
||||
}
|
||||
|
||||
void render_av_frames_egl(struct buffer* dst, struct vnc_av_frame** src,
|
||||
int n_av_frames, double scale, int x_pos, int y_pos)
|
||||
{
|
||||
struct fbo_info fbo;
|
||||
fbo_from_gbm_bo(&fbo, dst->bo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
struct pixman_box16* ext = pixman_region_extents(&dst->damage);
|
||||
glScissor(ext->x1, ext->y1, ext->x2 - ext->x1, ext->y2 - ext->y1);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glUseProgram(shader_program_ext);
|
||||
|
||||
for (int i = 0; i < n_av_frames; ++i) {
|
||||
const struct vnc_av_frame* frame = src[i];
|
||||
|
||||
int width = round((double)frame->width * scale);
|
||||
int height = round((double)frame->height * scale);
|
||||
glViewport(x_pos + frame->x, y_pos + frame->y, width, height);
|
||||
|
||||
GLuint tex = texture_from_av_frame(frame->frame);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
|
||||
|
||||
gl_draw();
|
||||
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
}
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
glFinish();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo.fbo);
|
||||
glDeleteRenderbuffers(1, &fbo.rbo);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue