summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/decode/d3d11va.c26
-rw-r--r--video/out/opengl/header_fixes.h5
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c239
-rw-r--r--video/out/opengl/utils.c1
4 files changed, 251 insertions, 20 deletions
diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c
index 1626626767..9e300b1620 100644
--- a/video/decode/d3d11va.c
+++ b/video/decode/d3d11va.c
@@ -187,6 +187,29 @@ static const struct d3d_decoded_format d3d11_formats[] = {
};
#undef DFMT
+// Update hw_subfmt to the underlying format. Needed because AVFrame does not
+// have such an attribute, so it can't be passed through, and is updated here
+// instead. (But in the future, AVHWFramesContext could be used.)
+static struct mp_image *d3d11va_update_image_attribs(struct lavc_ctx *s,
+ struct mp_image *img)
+{
+ ID3D11Texture2D *texture = (void *)img->planes[1];
+
+ if (!texture)
+ return img;
+
+ D3D11_TEXTURE2D_DESC texture_desc;
+ ID3D11Texture2D_GetDesc(texture, &texture_desc);
+ for (int n = 0; n < MP_ARRAY_SIZE(d3d11_formats); n++) {
+ if (d3d11_formats[n].dxfmt == texture_desc.Format) {
+ img->params.hw_subfmt = d3d11_formats[n].mpfmt;
+ break;
+ }
+ }
+
+ return img;
+}
+
static bool d3d11_format_supported(struct lavc_ctx *s, const GUID *guid,
const struct d3d_decoded_format *format)
{
@@ -274,7 +297,7 @@ static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h)
.MiscFlags = 0,
.ArraySize = n_surfaces,
.Usage = D3D11_USAGE_DEFAULT,
- .BindFlags = D3D11_BIND_DECODER,
+ .BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE,
.CPUAccessFlags = 0,
};
hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL, &texture);
@@ -555,6 +578,7 @@ const struct vd_lavc_hwdec mp_vd_lavc_d3d11va = {
.uninit = d3d11va_uninit,
.init_decoder = d3d11va_init_decoder,
.allocate_image = d3d11va_allocate_image,
+ .process_image = d3d11va_update_image_attribs,
};
const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy = {
diff --git a/video/out/opengl/header_fixes.h b/video/out/opengl/header_fixes.h
index 9f9b58f8d3..494658a64b 100644
--- a/video/out/opengl/header_fixes.h
+++ b/video/out/opengl/header_fixes.h
@@ -88,6 +88,11 @@
#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
#endif
+// GL_OES_EGL_image_external, GL_NV_EGL_stream_consumer_external
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
+
#undef MP_GET_GL_WORKAROUNDS
#endif // MP_GET_GL_WORKAROUNDS
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,
};
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index 40f1beba5f..d93db76869 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -664,6 +664,7 @@ const char* mp_sampler_type(GLenum texture_target)
case GL_TEXTURE_1D: return "sampler1D";
case GL_TEXTURE_2D: return "sampler2D";
case GL_TEXTURE_RECTANGLE: return "sampler2DRect";
+ case GL_TEXTURE_EXTERNAL_OES: return "samplerExternalOES";
case GL_TEXTURE_3D: return "sampler3D";
default: abort();
}