[vlc-devel] [PATCH 3/3] direct3d11: add support for I420 picture pools
Steve Lhomme
robux4 at gmail.com
Mon Jul 3 13:26:12 CEST 2017
On Sun, Jul 2, 2017 at 11:38 AM, Steve Lhomme <robux4 at videolabs.io> wrote:
> 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.
> ---
> 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 9b6a879ef5..c0bd23ed03 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_x_offset;
> unsigned int i_y_offset;
> unsigned int i_width;
> @@ -405,6 +406,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)
> {
> @@ -580,7 +622,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;
> @@ -588,31 +631,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_width_aligned + 15 ) & ~15;
typo, it should be the height
> + }
> +
> + 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( (p->i_pitch % 16) == 0 );
sub-planes don't need to be aligned to 16 bytes.
> + }
> + }
> +
> + 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
> @@ -623,10 +728,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);
> @@ -677,7 +780,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
> }
>
> if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures,
> - true))
> + sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN))
> goto error;
>
> if (!vd->info.is_slow) {
> @@ -740,6 +843,8 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
> sys->picQuad.i_width = staging_fmt.i_width;
> sys->picQuad.i_height = staging_fmt.i_height;
>
> + sys->picQuad.p_chroma_sampling = vlc_fourcc_GetChromaDescription( staging_fmt.i_chroma );
> +
> for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
> sys->stagingSys.texture[plane] = textures[plane];
>
> @@ -768,7 +873,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;
> }
> @@ -1106,7 +1216,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);
> @@ -1745,6 +1886,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();
> }
> @@ -2108,7 +2256,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))
> --
> 2.13.0
>
More information about the vlc-devel
mailing list