[vlc-commits] direct3d11: add support for I420 picture pools
Steve Lhomme
git at videolan.org
Thu Aug 10 14:34:43 CEST 2017
vlc | branch: master | Steve Lhomme <robux4 at videolabs.io> | Thu Jun 8 17:37:04 2017 +0200| [e6fd647e938259eda622b5ce77cf1c9f89f00673] | committer: Jean-Baptiste Kempf
direct3d11: add support for I420 picture pools
Allow direct rendering to I420 textures directly in the GPU memory mapped to CPU
The texture to display is copied to the staging texture just before rendering.
Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e6fd647e938259eda622b5ce77cf1c9f89f00673
---
modules/video_chroma/d3d11_fmt.h | 1 +
modules/video_chroma/dxgi_fmt.c | 1 +
modules/video_output/win32/direct3d11.c | 204 +++++++++++++++++++++++++++-----
3 files changed, 178 insertions(+), 28 deletions(-)
diff --git a/modules/video_chroma/d3d11_fmt.h b/modules/video_chroma/d3d11_fmt.h
index 3b461cb1bf..f1651ffa73 100644
--- a/modules/video_chroma/d3d11_fmt.h
+++ b/modules/video_chroma/d3d11_fmt.h
@@ -47,6 +47,7 @@ struct picture_sys_t
ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW];
DXGI_FORMAT decoderFormat;
DXGI_FORMAT formatTexture;
+ bool mapped;
};
#include "../codec/avcodec/va_surface.h"
diff --git a/modules/video_chroma/dxgi_fmt.c b/modules/video_chroma/dxgi_fmt.c
index bc462919ca..bacf329cac 100644
--- a/modules/video_chroma/dxgi_fmt.c
+++ b/modules/video_chroma/dxgi_fmt.c
@@ -80,6 +80,7 @@ static const d3d_format_t d3d_formats[] = {
{ "Y410", DXGI_FORMAT_Y410, VLC_CODEC_I444, 10, 1, 1, { DXGI_FORMAT_R10G10B10A2_UNORM } },
{ "NV11", DXGI_FORMAT_NV11, VLC_CODEC_I411, 8, 4, 1, { DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM} },
#endif
+ { "I420", DXGI_FORMAT_UNKNOWN, VLC_CODEC_I420, 8, 2, 2, { DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM } },
{ "R8G8B8A8", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_RGBA, 8, 1, 1, { DXGI_FORMAT_R8G8B8A8_UNORM } },
{ "VA_RGBA", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_D3D11_OPAQUE, 8, 1, 1, { DXGI_FORMAT_R8G8B8A8_UNORM } },
{ "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA, 8, 1, 1, { DXGI_FORMAT_B8G8R8A8_UNORM } },
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index a7db3960cb..cb0d0a302b 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -99,6 +99,7 @@ typedef struct
UINT PSConstantsCount;
ID3D11PixelShader *d3dpixelShader;
D3D11_VIEWPORT cropViewport;
+ const vlc_chroma_description_t *p_chroma_sampling;
unsigned int i_width;
unsigned int i_height;
} d3d_quad_t;
@@ -408,6 +409,47 @@ static void Direct3D11UnmapPoolTexture(picture_t *picture)
ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[KNOWN_DXGI_INDEX], 0);
}
+static int Direct3D11LockDirectTexture(picture_t *picture)
+{
+ picture_sys_t *p_sys = picture->p_sys;
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT hr;
+ D3D11_TEXTURE2D_DESC texDesc;
+ int i;
+
+ for (i = 0; i < picture->i_planes; i++) {
+ hr = ID3D11DeviceContext_Map(p_sys->context, p_sys->resource[i], 0, D3D11_MAP_WRITE, 0, &mappedResource);
+ if( FAILED(hr) )
+ break;
+ ID3D11Texture2D_GetDesc(p_sys->texture[i], &texDesc);
+ picture->p[i].p_pixels = mappedResource.pData;
+ picture->p[i].i_pitch = mappedResource.RowPitch;
+ picture->p[i].i_lines = texDesc.Height;
+ assert(picture->p[i].i_visible_pitch <= picture->p[i].i_pitch);
+ assert(picture->p[i].i_visible_lines <= picture->p[i].i_lines);
+ }
+
+ if( FAILED(hr) )
+ {
+ while (i-- > 0)
+ ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[i+1], 0);
+ return VLC_EGENERIC;
+ }
+
+ p_sys->mapped = true;
+ return VLC_SUCCESS;
+}
+
+static void Direct3D11UnlockDirectTexture(picture_t *picture)
+{
+ picture_sys_t *p_sys = picture->p_sys;
+ if (p_sys->mapped) {
+ for (int i = 0; i < picture->i_planes; i++)
+ ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[i], 0);
+ p_sys->mapped = false;
+ }
+}
+
#if !VLC_WINSTORE_APP
static int OpenHwnd(vout_display_t *vd)
{
@@ -583,7 +625,8 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
bool pool_type_display)
{
vout_display_sys_t *sys = vd->sys;
- int plane;
+ plane_t planes[PICTURE_PLANE_MAX];
+ int plane, plane_count;
HRESULT hr;
ID3D11Texture2D *slicedTexture = NULL;
D3D11_TEXTURE2D_DESC texDesc;
@@ -591,31 +634,93 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
texDesc.MipLevels = 1;
texDesc.SampleDesc.Count = 1;
texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
- texDesc.Format = cfg->formatTexture;
- texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
- if (is_d3d11_opaque(fmt->i_chroma)) {
- texDesc.BindFlags |= D3D11_BIND_DECODER;
- texDesc.Usage = D3D11_USAGE_DEFAULT;
- texDesc.CPUAccessFlags = 0;
+ const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
+ if( !p_chroma_desc )
+ return VLC_EGENERIC;
+
+ if (cfg->formatTexture == DXGI_FORMAT_UNKNOWN) {
+ int i_width_aligned = fmt->i_width;
+ int i_height_aligned = fmt->i_height;
+ if (p_chroma_desc->plane_count == 0)
+ {
+ msg_Dbg(vd, "failed to get the pixel format planes for %4.4s", (char *)&fmt->i_chroma);
+ return VLC_EGENERIC;
+ }
+ assert(p_chroma_desc->plane_count <= D3D11_MAX_SHADER_VIEW);
+ plane_count = p_chroma_desc->plane_count;
+
+ texDesc.Format = cfg->resourceFormat[0];
+ assert(cfg->resourceFormat[1] == cfg->resourceFormat[0]);
+ assert(cfg->resourceFormat[2] == cfg->resourceFormat[0]);
+
+ if (pool_type_display) {
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+ } else {
+ texDesc.Usage = D3D11_USAGE_STAGING;
+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ /* align on 16 pixel boundaries */
+ i_width_aligned = ( i_width_aligned + 15 ) & ~15;
+ i_height_aligned = ( i_height_aligned + 15 ) & ~15;
+ }
+
+ for( int i = 0; i < plane_count; i++ )
+ {
+ plane_t *p = &planes[i];
+
+ p->i_lines = i_height_aligned * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
+ p->i_visible_lines = fmt->i_visible_height * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
+ p->i_pitch = i_width_aligned * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
+ p->i_visible_pitch = fmt->i_visible_width * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
+ p->i_pixel_pitch = p_chroma_desc->pixel_size;
+ }
+
+ if (!pool_type_display) {
+ assert( (planes[0].i_pitch % 16) == 0 );
+ }
+
+ texDesc.ArraySize = 1;
} else {
- texDesc.Usage = D3D11_USAGE_DYNAMIC;
- texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- }
- texDesc.ArraySize = pool_size;
- texDesc.Height = fmt->i_height;
- texDesc.Width = fmt->i_width;
+ plane_count = 1;
+ texDesc.Format = cfg->formatTexture;
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ if (is_d3d11_opaque(fmt->i_chroma)) {
+ texDesc.BindFlags |= D3D11_BIND_DECODER;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+ texDesc.CPUAccessFlags = 0;
+ } else {
+ texDesc.Usage = D3D11_USAGE_DYNAMIC;
+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ }
+ texDesc.ArraySize = pool_size;
+ texDesc.Height = fmt->i_height;
+ texDesc.Width = fmt->i_width;
- hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
- if (FAILED(hr)) {
- msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
- goto error;
+ hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
+ if (FAILED(hr)) {
+ msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
+ goto error;
+ }
}
for (unsigned picture_count = 0; picture_count < pool_size; picture_count++) {
- textures[picture_count * D3D11_MAX_SHADER_VIEW] = slicedTexture;
- ID3D11Texture2D_AddRef(slicedTexture);
-
- for (plane = 1; plane < D3D11_MAX_SHADER_VIEW; plane++) {
+ for (plane = 0; plane < plane_count; plane++)
+ {
+ if (slicedTexture) {
+ textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = slicedTexture;
+ ID3D11Texture2D_AddRef(slicedTexture);
+ } else {
+ texDesc.Height = planes[plane].i_lines;
+ texDesc.Width = planes[plane].i_pitch;
+ hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] );
+ if (FAILED(hr)) {
+ msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
+ goto error;
+ }
+ }
+ }
+ for (; plane < D3D11_MAX_SHADER_VIEW; plane++) {
if (!cfg->resourceFormat[plane])
textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = NULL;
else
@@ -626,10 +731,8 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
}
}
- if (!is_d3d11_opaque(fmt->i_chroma)) {
+ if (!is_d3d11_opaque(fmt->i_chroma) && cfg->formatTexture != DXGI_FORMAT_UNKNOWN) {
D3D11_MAPPED_SUBRESOURCE mappedResource;
- const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
-
hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource*)textures[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if( FAILED(hr) ) {
msg_Err(vd, "The texture cannot be mapped. (hr=0x%lX)", hr);
@@ -676,7 +779,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
surface_fmt.i_height = sys->picQuad.i_height;
if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures,
- true))
+ sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN))
goto error;
if (!vd->info.is_slow) {
@@ -730,6 +833,8 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, 1, textures, true))
goto error;
+ sys->picQuad.p_chroma_sampling = vlc_fourcc_GetChromaDescription( surface_fmt.i_chroma );
+
for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
sys->stagingSys.texture[plane] = textures[plane];
@@ -754,7 +859,12 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
return NULL;
}
- if (vd->info.is_slow) {
+ if (sys->picQuadConfig->formatTexture == DXGI_FORMAT_UNKNOWN)
+ {
+ pool_cfg.lock = Direct3D11LockDirectTexture;
+ pool_cfg.unlock = Direct3D11UnlockDirectTexture;
+ }
+ else if (vd->info.is_slow) {
pool_cfg.lock = Direct3D11MapPoolTexture;
//pool_cfg.unlock = Direct3D11UnmapPoolTexture;
}
@@ -1121,7 +1231,38 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
#endif
picture_sys_t *p_sys = ActivePictureSys(picture);
- if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
+ if (picture->p_sys->formatTexture == DXGI_FORMAT_UNKNOWN)
+ {
+ Direct3D11UnlockDirectTexture(picture);
+ for (int plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
+ {
+ if (!p_sys->resource[plane])
+ continue;
+
+ unsigned int width = sys->picQuad.i_width;
+ unsigned int height = sys->picQuad.i_height;
+ unsigned int x_offset = picture->format.i_x_offset;
+ unsigned int y_offset = picture->format.i_y_offset;
+ x_offset = x_offset * sys->picQuad.p_chroma_sampling->p[plane].h.num / sys->picQuad.p_chroma_sampling->p[plane].h.den;
+ y_offset = y_offset * sys->picQuad.p_chroma_sampling->p[plane].w.num / sys->picQuad.p_chroma_sampling->p[plane].w.den;
+ width = width * sys->picQuad.p_chroma_sampling->p[plane].h.num / sys->picQuad.p_chroma_sampling->p[plane].h.den;
+ height = height * sys->picQuad.p_chroma_sampling->p[plane].w.num / sys->picQuad.p_chroma_sampling->p[plane].w.den;
+
+ D3D11_BOX box = {
+ .top = y_offset,
+ .bottom = y_offset + height,
+ .left = x_offset,
+ .right = x_offset + width,
+ .back = 1,
+ };
+ ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
+ sys->stagingSys.resource[plane],
+ 0, 0, 0, 0,
+ p_sys->resource[plane],
+ 0, &box);
+ }
+ }
+ else if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
D3D11_TEXTURE2D_DESC texDesc;
if (!is_d3d11_opaque(picture->format.i_chroma))
Direct3D11UnmapPoolTexture(picture);
@@ -1802,6 +1943,13 @@ static HRESULT CompilePixelShader(vout_display_t *vd, const d3d_format_t *format
psz_sampler =
"sample = shaderTexture[0].Sample(SampleType, In.Texture);";
break;
+ case DXGI_FORMAT_UNKNOWN:
+ psz_sampler =
+ "sample.x = shaderTexture[0].Sample(SampleType, In.Texture).x;\
+ sample.y = shaderTexture[1].Sample(SampleType, In.Texture).x;\
+ sample.z = shaderTexture[2].Sample(SampleType, In.Texture).x;\
+ sample.a = 1;";
+ break;
default:
vlc_assert_unreachable();
}
@@ -2165,7 +2313,7 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
}
sys->legacy_shader = !CanUseTextureArray(vd);
- vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma);
+ vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma) && sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN;
hr = CompilePixelShader(vd, sys->picQuadConfig, fmt->transfer, fmt->b_color_range_full, &sys->picQuadPixelShader);
if (FAILED(hr))
More information about the vlc-commits
mailing list