summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/hwdec_d3d11egl.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl/hwdec_d3d11egl.c')
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c239
1 files changed, 220 insertions, 19 deletions
diff --git a/video/out/opengl/hwdec_d3d11egl.c b/video/out/opengl/hwdec_d3d11egl.c
index ae7e35f953..28c5f27bf6 100644
--- a/video/out/opengl/hwdec_d3d11egl.c
+++ b/video/out/opengl/hwdec_d3d11egl.c
@@ -29,6 +29,10 @@
#include "hwdec.h"
#include "video/hwdec.h"
+#ifndef EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE
+#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x3AAB
+#endif
+
struct priv {
struct mp_hwdec_ctx hwctx;
@@ -44,9 +48,36 @@ struct priv {
ID3D11VideoProcessor *video_proc;
ID3D11VideoProcessorEnumerator *vp_enum;
ID3D11VideoProcessorOutputView *out_view;
+
+ struct mp_image_params image_params;
int c_w, c_h;
- GLuint gl_texture;
+ EGLStreamKHR egl_stream;
+
+ GLuint gl_textures[3];
+
+ // EGL_KHR_stream
+ EGLStreamKHR (EGLAPIENTRY *CreateStreamKHR)(EGLDisplay dpy,
+ const EGLint *attrib_list);
+ EGLBoolean (EGLAPIENTRY *DestroyStreamKHR)(EGLDisplay dpy,
+ EGLStreamKHR stream);
+
+ // EGL_KHR_stream_consumer_gltexture
+ EGLBoolean (EGLAPIENTRY *StreamConsumerAcquireKHR)
+ (EGLDisplay dpy, EGLStreamKHR stream);
+ EGLBoolean (EGLAPIENTRY *StreamConsumerReleaseKHR)
+ (EGLDisplay dpy, EGLStreamKHR stream);
+
+ // EGL_NV_stream_consumer_gltexture_yuv
+ EGLBoolean (EGLAPIENTRY *StreamConsumerGLTextureExternalAttribsNV)
+ (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list);
+
+ // EGL_ANGLE_stream_producer_d3d_texture_nv12
+ EGLBoolean (EGLAPIENTRY *CreateStreamProducerD3DTextureNV12ANGLE)
+ (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+ EGLBoolean (EGLAPIENTRY *StreamPostD3DTextureNV12ANGLE)
+ (EGLDisplay dpy, EGLStreamKHR stream, void *texture,
+ const EGLAttrib *attrib_list);
};
static void destroy_video_proc(struct gl_hwdec *hw)
@@ -71,8 +102,14 @@ static void destroy_objects(struct gl_hwdec *hw)
struct priv *p = hw->priv;
GL *gl = hw->gl;
- gl->DeleteTextures(1, &p->gl_texture);
- p->gl_texture = 0;
+ if (p->egl_stream)
+ p->DestroyStreamKHR(p->egl_display, p->egl_stream);
+ p->egl_stream = 0;
+
+ for (int n = 0; n < 3; n++) {
+ gl->DeleteTextures(1, &p->gl_textures[n]);
+ p->gl_textures[n] = 0;
+ }
if (p->egl_display && p->egl_surface) {
eglReleaseTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER);
@@ -135,6 +172,38 @@ static int create(struct gl_hwdec *hw)
p->egl_display = egl_display;
+ // Optional EGLStream stuff for working without video processor.
+ // Note that as long as GL_OES_EGL_image_external_essl3 is not available,
+ // this won't work in ES 3.x mode due to missing GLSL mechanisms.
+ if (strstr(exts, "EGL_ANGLE_stream_producer_d3d_texture_nv12") &&
+ hw->gl->es == 200)
+ {
+ MP_VERBOSE(hw, "Loading EGL_ANGLE_stream_producer_d3d_texture_nv12\n");
+
+ p->CreateStreamKHR = (void *)eglGetProcAddress("eglCreateStreamKHR");
+ p->DestroyStreamKHR = (void *)eglGetProcAddress("eglDestroyStreamKHR");
+ p->StreamConsumerAcquireKHR =
+ (void *)eglGetProcAddress("eglStreamConsumerAcquireKHR");
+ p->StreamConsumerReleaseKHR =
+ (void *)eglGetProcAddress("eglStreamConsumerReleaseKHR");
+ p->StreamConsumerGLTextureExternalAttribsNV =
+ (void *)eglGetProcAddress("eglStreamConsumerGLTextureExternalAttribsNV");
+ p->CreateStreamProducerD3DTextureNV12ANGLE =
+ (void *)eglGetProcAddress("eglCreateStreamProducerD3DTextureNV12ANGLE");
+ p->StreamPostD3DTextureNV12ANGLE =
+ (void *)eglGetProcAddress("eglStreamPostD3DTextureNV12ANGLE");
+
+ if (!p->CreateStreamKHR || !p->DestroyStreamKHR ||
+ !p->StreamConsumerAcquireKHR || !p->StreamConsumerReleaseKHR ||
+ !p->StreamConsumerGLTextureExternalAttribsNV ||
+ !p->CreateStreamProducerD3DTextureNV12ANGLE ||
+ !p->StreamPostD3DTextureNV12ANGLE)
+ {
+ MP_ERR(hw, "Failed to load some EGLStream functions.\n");
+ goto fail;
+ }
+ }
+
EGLAttrib device = 0;
if (!p_eglQueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &device))
goto fail;
@@ -208,6 +277,73 @@ fail:
return -1;
}
+static int create_egl_stream(struct gl_hwdec *hw, struct mp_image_params *params)
+{
+ struct priv *p = hw->priv;
+ GL *gl = hw->gl;
+
+ if (params->hw_subfmt != IMGFMT_NV12)
+ return -1;
+
+ if (!p->CreateStreamKHR)
+ return -1; // extensions not available
+
+ MP_VERBOSE(hw, "Using EGL_KHR_stream path.\n");
+
+ // Hope that the given texture unit range is not "in use" by anything.
+ // The texture units need to be bound during init only, and are free for
+ // use again after the initialization here is done.
+ int texunits = 0; // [texunits, texunits + num_planes)
+ int num_planes = 2;
+ int gl_target = GL_TEXTURE_EXTERNAL_OES;
+
+ p->egl_stream = p->CreateStreamKHR(p->egl_display, (EGLint[]){EGL_NONE});
+ if (!p->egl_stream)
+ goto fail;
+
+ for (int n = 0; n < num_planes; n++) {
+ gl->ActiveTexture(GL_TEXTURE0 + texunits + n);
+ gl->GenTextures(1, &p->gl_textures[n]);
+ gl->BindTexture(gl_target, p->gl_textures[n]);
+ gl->TexParameteri(gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameteri(gl_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+
+ EGLAttrib attrs[] = {
+ EGL_COLOR_BUFFER_TYPE, EGL_YUV_BUFFER_EXT,
+ EGL_YUV_NUMBER_OF_PLANES_EXT, num_planes,
+ EGL_YUV_PLANE0_TEXTURE_UNIT_NV, texunits + 0,
+ EGL_YUV_PLANE1_TEXTURE_UNIT_NV, texunits + 1,
+ EGL_NONE,
+ };
+
+ if (!p->StreamConsumerGLTextureExternalAttribsNV(p->egl_display, p->egl_stream,
+ attrs))
+ goto fail;
+
+ if (!p->CreateStreamProducerD3DTextureNV12ANGLE(p->egl_display, p->egl_stream,
+ (EGLAttrib[]){EGL_NONE}))
+ goto fail;
+
+ params->imgfmt = params->hw_subfmt;
+
+ for (int n = 0; n < num_planes; n++) {
+ gl->ActiveTexture(GL_TEXTURE0 + texunits + n);
+ gl->BindTexture(gl_target, 0);
+ }
+ gl->ActiveTexture(GL_TEXTURE0);
+ return 0;
+fail:
+ MP_ERR(hw, "Failed to create EGLStream\n");
+ if (p->egl_stream)
+ p->DestroyStreamKHR(p->egl_display, p->egl_stream);
+ p->egl_stream = 0;
+ gl->ActiveTexture(GL_TEXTURE0);
+ return -1;
+}
+
static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
{
struct priv *p = hw->priv;
@@ -216,6 +352,14 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
destroy_objects(hw);
+ p->image_params = *params;
+
+ // If this does not work, use the video process instead.
+ if (create_egl_stream(hw, params) >= 0)
+ return 0;
+
+ MP_VERBOSE(hw, "Using ID3D11VideoProcessor path.\n");
+
D3D11_TEXTURE2D_DESC texdesc = {
.Width = params->w,
.Height = params->h,
@@ -264,8 +408,8 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
goto fail;
}
- gl->GenTextures(1, &p->gl_texture);
- gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
+ gl->GenTextures(1, &p->gl_textures[0]);
+ gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[0]);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -355,27 +499,19 @@ fail:
return -1;
}
-static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
- struct gl_hwdec_frame *out_frame)
+static int map_frame_video_proc(struct gl_hwdec *hw, ID3D11Texture2D *d3d_tex,
+ int d3d_subindex, struct gl_hwdec_frame *out_frame)
{
struct priv *p = hw->priv;
HRESULT hr;
ID3D11VideoProcessorInputView *in_view = NULL;
- if (!p->gl_texture)
- return -1;
-
- ID3D11Texture2D *d3d_tex = (void *)hw_image->planes[1];
- int d3d_subindex = (intptr_t)hw_image->planes[2];
- if (!d3d_tex)
- return -1;
-
D3D11_TEXTURE2D_DESC texdesc;
ID3D11Texture2D_GetDesc(d3d_tex, &texdesc);
if (!p->video_proc || p->c_w != texdesc.Width || p->c_h != texdesc.Height) {
p->c_w = texdesc.Width;
p->c_h = texdesc.Height;
- if (create_video_proc(hw, &hw_image->params) < 0)
+ if (create_video_proc(hw, &p->image_params) < 0)
return -1;
}
@@ -410,16 +546,80 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
*out_frame = (struct gl_hwdec_frame){
.planes = {
{
- .gl_texture = p->gl_texture,
+ .gl_texture = p->gl_textures[0],
.gl_target = GL_TEXTURE_2D,
- .tex_w = hw_image->w,
- .tex_h = hw_image->h,
+ .tex_w = p->image_params.w,
+ .tex_h = p->image_params.h,
},
},
};
return 0;
}
+static int map_frame_egl_stream(struct gl_hwdec *hw, ID3D11Texture2D *d3d_tex,
+ int d3d_subindex, struct gl_hwdec_frame *out_frame)
+{
+ struct priv *p = hw->priv;
+
+ EGLAttrib attrs[] = {
+ EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, d3d_subindex,
+ EGL_NONE,
+ };
+ if (!p->StreamPostD3DTextureNV12ANGLE(p->egl_display, p->egl_stream,
+ (void *)d3d_tex, attrs))
+ return -1;
+
+ if (!p->StreamConsumerAcquireKHR(p->egl_display, p->egl_stream))
+ return -1;
+
+ D3D11_TEXTURE2D_DESC texdesc;
+ ID3D11Texture2D_GetDesc(d3d_tex, &texdesc);
+
+ *out_frame = (struct gl_hwdec_frame){
+ .planes = {
+ {
+ .gl_texture = p->gl_textures[0],
+ .gl_target = GL_TEXTURE_EXTERNAL_OES,
+ .tex_w = texdesc.Width,
+ .tex_h = texdesc.Height,
+ },
+ {
+ .gl_texture = p->gl_textures[1],
+ .gl_target = GL_TEXTURE_EXTERNAL_OES,
+ .tex_w = texdesc.Width / 2,
+ .tex_h = texdesc.Height / 2,
+ .swizzle = "rgba", // even in ES2 mode (no LUMINANCE_ALPHA)
+ },
+ },
+ };
+ return 0;
+}
+
+static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
+ struct gl_hwdec_frame *out_frame)
+{
+ struct priv *p = hw->priv;
+
+ if (!p->gl_textures[0])
+ return -1;
+
+ ID3D11Texture2D *d3d_tex = (void *)hw_image->planes[1];
+ int d3d_subindex = (intptr_t)hw_image->planes[2];
+ if (!d3d_tex)
+ return -1;
+
+ return p->egl_stream
+ ? map_frame_egl_stream(hw, d3d_tex, d3d_subindex, out_frame)
+ : map_frame_video_proc(hw, d3d_tex, d3d_subindex, out_frame);
+}
+
+static void unmap(struct gl_hwdec *hw)
+{
+ struct priv *p = hw->priv;
+ if (p->egl_stream)
+ p->StreamConsumerReleaseKHR(p->egl_display, p->egl_stream);
+}
+
const struct gl_hwdec_driver gl_hwdec_d3d11egl = {
.name = "d3d11-egl",
.api = HWDEC_D3D11VA,
@@ -427,5 +627,6 @@ const struct gl_hwdec_driver gl_hwdec_d3d11egl = {
.create = create,
.reinit = reinit,
.map_frame = map_frame,
+ .unmap = unmap,
.destroy = destroy,
};