d3d12: Add HEVC Decode/Encode

Reviewed-by: Giancarlo Devich <gdevich@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18328>
This commit is contained in:
Sil Vilerino 2022-09-14 16:13:55 -04:00
parent f2d172a8be
commit da11684e9d
27 changed files with 4601 additions and 98 deletions

View file

@ -467,8 +467,10 @@ d3d12_convert_pipe_video_profile_to_dxgi_format(enum pipe_video_profile profile)
case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED: case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
return DXGI_FORMAT_NV12; return DXGI_FORMAT_NV12;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
return DXGI_FORMAT_P010; return DXGI_FORMAT_P010;
default: default:
{ {

View file

@ -28,6 +28,7 @@
#include "d3d12_surface.h" #include "d3d12_surface.h"
#include "d3d12_video_dec.h" #include "d3d12_video_dec.h"
#include "d3d12_video_dec_h264.h" #include "d3d12_video_dec_h264.h"
#include "d3d12_video_dec_hevc.h"
#include "d3d12_video_buffer.h" #include "d3d12_video_buffer.h"
#include "d3d12_residency.h" #include "d3d12_residency.h"
@ -298,14 +299,20 @@ d3d12_video_decoder_store_upper_layer_references(struct d3d12_video_decoder *pD3
struct pipe_video_buffer *target, struct pipe_video_buffer *target,
struct pipe_picture_desc *picture) struct pipe_picture_desc *picture)
{ {
pD3D12Dec->m_pCurrentDecodeTarget = target;
switch (pD3D12Dec->m_d3d12DecProfileType) { switch (pD3D12Dec->m_d3d12DecProfileType) {
case d3d12_video_decode_profile_type_h264: case d3d12_video_decode_profile_type_h264:
{ {
pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture; pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture;
pD3D12Dec->m_pCurrentDecodeTarget = target;
pD3D12Dec->m_pCurrentReferenceTargets = pPicControlH264->ref; pD3D12Dec->m_pCurrentReferenceTargets = pPicControlH264->ref;
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
pipe_h265_picture_desc *pPicControlHevc = (pipe_h265_picture_desc *) picture;
pD3D12Dec->m_pCurrentReferenceTargets = pPicControlHevc->ref;
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -493,7 +500,7 @@ d3d12_video_decoder_end_frame(struct pipe_video_codec *codec,
}; };
} }
if (pD3D12Dec->m_InverseQuantMatrixBuffer.size() > 0) { if (pD3D12Dec->qp_matrix_frame_argument_enabled && (pD3D12Dec->m_InverseQuantMatrixBuffer.size() > 0)) {
d3d12InputArguments.NumFrameArguments++; d3d12InputArguments.NumFrameArguments++;
d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = { d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = {
D3D12_VIDEO_DECODE_ARGUMENT_TYPE_INVERSE_QUANTIZATION_MATRIX, D3D12_VIDEO_DECODE_ARGUMENT_TYPE_INVERSE_QUANTIZATION_MATRIX,
@ -992,6 +999,13 @@ d3d12_video_decoder_prepare_for_decode_frame(struct d3d12_video_decoder *pD3D12D
currentFrameDPBEntrySubresource); currentFrameDPBEntrySubresource);
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
d3d12_video_decoder_prepare_current_frame_references_hevc(pD3D12Dec,
pCurrentFrameDPBEntry,
currentFrameDPBEntrySubresource);
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -1024,7 +1038,7 @@ d3d12_video_decoder_reconfigure_dpb(struct d3d12_video_decoder *pD3D12Dec,
D3D12_VIDEO_DECODER_DESC decoderDesc = pD3D12Dec->m_decoderDesc; D3D12_VIDEO_DECODER_DESC decoderDesc = pD3D12Dec->m_decoderDesc;
decoderDesc.Configuration.InterlaceType = interlaceTypeRequested; decoderDesc.Configuration.InterlaceType = interlaceTypeRequested;
decoderDesc.Configuration.DecodeProfile = decoderDesc.Configuration.DecodeProfile =
d3d12_video_decoder_resolve_profile(pD3D12Dec->m_d3d12DecProfileType); d3d12_video_decoder_resolve_profile(pD3D12Dec->m_d3d12DecProfileType, pD3D12Dec->m_decodeFormat);
pD3D12Dec->m_spVideoDecoder.Reset(); pD3D12Dec->m_spVideoDecoder.Reset();
HRESULT hr = HRESULT hr =
pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&decoderDesc, pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&decoderDesc,
@ -1105,6 +1119,11 @@ d3d12_video_decoder_refresh_dpb_active_references(struct d3d12_video_decoder *pD
d3d12_video_decoder_refresh_dpb_active_references_h264(pD3D12Dec); d3d12_video_decoder_refresh_dpb_active_references_h264(pD3D12Dec);
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
d3d12_video_decoder_refresh_dpb_active_references_hevc(pD3D12Dec);
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -1127,6 +1146,11 @@ d3d12_video_decoder_get_frame_info(
d3d12_video_decoder_get_frame_info_h264(pD3D12Dec, pWidth, pHeight, pMaxDPB, isInterlaced); d3d12_video_decoder_get_frame_info_h264(pD3D12Dec, pWidth, pHeight, pMaxDPB, isInterlaced);
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
d3d12_video_decoder_get_frame_info_hevc(pD3D12Dec, pWidth, pHeight, pMaxDPB, isInterlaced);
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -1183,13 +1207,14 @@ d3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input(
d3d12_video_decode_profile_type profileType = d3d12_video_decode_profile_type profileType =
d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->base.profile); d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->base.profile);
ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture);
D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource);
pD3D12Dec->qp_matrix_frame_argument_enabled = false;
switch (profileType) { switch (profileType) {
case d3d12_video_decode_profile_type_h264: case d3d12_video_decode_profile_type_h264:
{ {
size_t dxvaPicParamsBufferSize = sizeof(DXVA_PicParams_H264); size_t dxvaPicParamsBufferSize = sizeof(DXVA_PicParams_H264);
pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture; pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture;
ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture);
D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource);
DXVA_PicParams_H264 dxvaPicParamsH264 = DXVA_PicParams_H264 dxvaPicParamsH264 =
d3d12_video_decoder_dxva_picparams_from_pipe_picparams_h264(pD3D12Dec->m_fenceValue, d3d12_video_decoder_dxva_picparams_from_pipe_picparams_h264(pD3D12Dec->m_fenceValue,
codec->base.profile, codec->base.profile,
@ -1205,8 +1230,32 @@ d3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input(
DXVA_Qmatrix_H264 dxvaQmatrixH264 = {}; DXVA_Qmatrix_H264 dxvaQmatrixH264 = {};
d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_h264((pipe_h264_picture_desc *) picture, d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_h264((pipe_h264_picture_desc *) picture,
dxvaQmatrixH264); dxvaQmatrixH264);
pD3D12Dec->qp_matrix_frame_argument_enabled = true; // We don't have a way of knowing from the pipe params so send always
d3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(codec, &dxvaQmatrixH264, dxvaQMatrixBufferSize); d3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(codec, &dxvaQmatrixH264, dxvaQMatrixBufferSize);
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
size_t dxvaPicParamsBufferSize = sizeof(DXVA_PicParams_HEVC);
pipe_h265_picture_desc *pPicControlHEVC = (pipe_h265_picture_desc *) picture;
DXVA_PicParams_HEVC dxvaPicParamsHEVC =
d3d12_video_decoder_dxva_picparams_from_pipe_picparams_hevc(pD3D12Dec->m_fenceValue,
codec->base.profile,
pPicControlHEVC);
d3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(codec,
&dxvaPicParamsHEVC,
dxvaPicParamsBufferSize);
size_t dxvaQMatrixBufferSize = sizeof(DXVA_Qmatrix_HEVC);
DXVA_Qmatrix_HEVC dxvaQmatrixHEVC = {};
pD3D12Dec->qp_matrix_frame_argument_enabled = false;
d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_hevc((pipe_h265_picture_desc *) picture,
dxvaQmatrixHEVC,
pD3D12Dec->qp_matrix_frame_argument_enabled);
d3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(codec, &dxvaQmatrixHEVC, dxvaQMatrixBufferSize);
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -1238,6 +1287,22 @@ d3d12_video_decoder_prepare_dxva_slices_control(
DXVAStructSize); DXVAStructSize);
assert(pD3D12Dec->m_SliceControlBuffer.size() == DXVAStructSize); assert(pD3D12Dec->m_SliceControlBuffer.size() == DXVAStructSize);
} break; } break;
case d3d12_video_decode_profile_type_hevc:
{
std::vector<DXVA_Slice_HEVC_Short> pOutSliceControlBuffers;
struct pipe_h265_picture_desc* picture_hevc = (struct pipe_h265_picture_desc*) picture;
d3d12_video_decoder_prepare_dxva_slices_control_hevc(pD3D12Dec, pOutSliceControlBuffers, picture_hevc);
assert(sizeof(pOutSliceControlBuffers.front()) == sizeof(DXVA_Slice_HEVC_Short));
uint64_t DXVAStructSize = pOutSliceControlBuffers.size() * sizeof((pOutSliceControlBuffers.front()));
assert((DXVAStructSize % sizeof(DXVA_Slice_HEVC_Short)) == 0);
d3d12_video_decoder_store_dxva_slicecontrol_in_slicecontrol_buffer(pD3D12Dec,
pOutSliceControlBuffers.data(),
DXVAStructSize);
assert(pD3D12Dec->m_SliceControlBuffer.size() == DXVAStructSize);
} break;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");
@ -1291,6 +1356,7 @@ d3d12_video_decoder_supports_aot_dpb(D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT dec
bool supportedProfile = false; bool supportedProfile = false;
switch (profileType) { switch (profileType) {
case d3d12_video_decode_profile_type_h264: case d3d12_video_decode_profile_type_h264:
case d3d12_video_decode_profile_type_hevc:
supportedProfile = true; supportedProfile = true;
break; break;
default: default:
@ -1312,6 +1378,9 @@ d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(enum pipe_video_p
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
return d3d12_video_decode_profile_type_h264; return d3d12_video_decode_profile_type_h264;
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
return d3d12_video_decode_profile_type_hevc;
default: default:
{ {
unreachable("Unsupported pipe video profile"); unreachable("Unsupported pipe video profile");
@ -1330,18 +1399,23 @@ d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(enum pipe_video_
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
return D3D12_VIDEO_DECODE_PROFILE_H264; return D3D12_VIDEO_DECODE_PROFILE_H264;
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
return D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
return D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10;
default: default:
return {}; return {};
} }
} }
GUID GUID
d3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType) d3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType, DXGI_FORMAT decode_format)
{ {
switch (profileType) { switch (profileType) {
case d3d12_video_decode_profile_type_h264: case d3d12_video_decode_profile_type_h264:
return D3D12_VIDEO_DECODE_PROFILE_H264; return D3D12_VIDEO_DECODE_PROFILE_H264;
break; case d3d12_video_decode_profile_type_hevc:
return (decode_format == DXGI_FORMAT_NV12) ? D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN : D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10;
default: default:
{ {
unreachable("Unsupported d3d12_video_decode_profile_type"); unreachable("Unsupported d3d12_video_decode_profile_type");

View file

@ -147,6 +147,9 @@ struct d3d12_video_decoder
std::vector<uint8_t> m_picParamsBuffer; // size() has the byte size of the currently held picparams ; capacity() std::vector<uint8_t> m_picParamsBuffer; // size() has the byte size of the currently held picparams ; capacity()
// has the underlying container allocation size // has the underlying container allocation size
// Set for each frame indicating whether to send VIDEO_DECODE_BUFFER_TYPE_INVERSE_QUANTIZATION_MATRIX
bool qp_matrix_frame_argument_enabled = false;
// Holds a buffer for the DXVA struct layout of the VIDEO_DECODE_BUFFER_TYPE_INVERSE_QUANTIZATION_MATRIX of the // Holds a buffer for the DXVA struct layout of the VIDEO_DECODE_BUFFER_TYPE_INVERSE_QUANTIZATION_MATRIX of the
// current frame m_InverseQuantMatrixBuffer.size() == 0 means no quantization matrix buffer is set for current frame // current frame m_InverseQuantMatrixBuffer.size() == 0 means no quantization matrix buffer is set for current frame
std::vector<uint8_t> m_InverseQuantMatrixBuffer; // size() has the byte size of the currently held std::vector<uint8_t> m_InverseQuantMatrixBuffer; // size() has the byte size of the currently held
@ -214,7 +217,7 @@ d3d12_video_decoder_supports_aot_dpb(D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT dec
d3d12_video_decode_profile_type d3d12_video_decode_profile_type
d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(enum pipe_video_profile profile); d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(enum pipe_video_profile profile);
GUID GUID
d3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType); d3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType, DXGI_FORMAT decode_format);
void void
d3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(struct d3d12_video_decoder *codec, d3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(struct d3d12_video_decoder *codec,
void * pDXVABuffer, void * pDXVABuffer,

View file

@ -23,6 +23,7 @@
#include "d3d12_video_dec.h" #include "d3d12_video_dec.h"
#include "d3d12_video_dec_h264.h" #include "d3d12_video_dec_h264.h"
#include "vl/vl_zscan.h"
#include <cmath> #include <cmath>
@ -594,11 +595,11 @@ d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_h264(pipe_h264_picture_desc
unsigned i, j; unsigned i, j;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++) {
outMatrixBuffer.bScalingLists4x4[i][j] = pPipeDesc->pps->ScalingList4x4[i][d3d12_video_zigzag_scan[j]]; outMatrixBuffer.bScalingLists4x4[i][j] = pPipeDesc->pps->ScalingList4x4[i][vl_zscan_normal_16[j]];
} }
} }
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
outMatrixBuffer.bScalingLists8x8[0][i] = pPipeDesc->pps->ScalingList8x8[0][d3d12_video_zigzag_direct[i]]; outMatrixBuffer.bScalingLists8x8[0][i] = pPipeDesc->pps->ScalingList8x8[0][vl_zscan_normal[i]];
outMatrixBuffer.bScalingLists8x8[1][i] = pPipeDesc->pps->ScalingList8x8[1][d3d12_video_zigzag_direct[i]]; outMatrixBuffer.bScalingLists8x8[1][i] = pPipeDesc->pps->ScalingList8x8[1][vl_zscan_normal[i]];
} }
} }

View file

@ -184,26 +184,6 @@ typedef struct _DXVA_Qmatrix_H264
} DXVA_Qmatrix_H264, *LPDXVA_Qmatrix_H264; } DXVA_Qmatrix_H264, *LPDXVA_Qmatrix_H264;
#pragma pack(pop, BeforeDXVApacking) #pragma pack(pop, BeforeDXVApacking)
// For translating the QP matrices from VA to DXVA
const uint8_t d3d12_video_zigzag_direct[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
// For translating the QP matrices from VA to DXVA
const uint8_t d3d12_video_zigzag_scan[16+1] = {
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4,
3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
};
/* H.264/AVC slice control data structure - short form */ /* H.264/AVC slice control data structure - short form */
/* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */ /* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */
#pragma pack(push, BeforeDXVApacking, 1) #pragma pack(push, BeforeDXVApacking, 1)

View file

@ -0,0 +1,546 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_video_dec.h"
#include "d3d12_video_dec_hevc.h"
#include "d3d12_resource.h"
#include "d3d12_video_buffer.h"
#include <cmath>
void
d3d12_video_decoder_refresh_dpb_active_references_hevc(struct d3d12_video_decoder *pD3D12Dec)
{
// Method overview
// 1. Codec specific strategy in switch statement regarding reference frames eviction policy. Should only mark active
// DPB references, leaving evicted ones as unused
// 2. Call release_unused_references_texture_memory(); at the end of this method. Any references (and texture
// allocations associated)
// that were left not marked as used in m_spDPBManager by step (2) are lost.
// Assign DXVA original Index7Bits indices to current frame and references
DXVA_PicParams_HEVC *pCurrPicParams = d3d12_video_decoder_get_current_dxva_picparams<DXVA_PicParams_HEVC>(pD3D12Dec);
for (uint8_t i = 0; i < _countof(pCurrPicParams->RefPicList); i++) {
// From HEVC DXVA spec:
// Index7Bits
// An index that identifies an uncompressed surface for the CurrPic or RefPicList member of the picture parameters structure (section 4.0).
// When Index7Bits is used in the CurrPic and RefPicList members of the picture parameters structure, the value directly specifies the DXVA index of an uncompressed surface.
// When Index7Bits is 127 (0x7F), this indicates that it does not contain a valid index.
// AssociatedFlag
// Optional 1-bit flag associated with the surface. It specifies whether the reference picture is a long-term reference or a short-term reference for RefPicList, and it has no meaning when used for CurrPic.
// bPicEntry
// Accesses the entire 8 bits of the union.
if (pCurrPicParams->RefPicList[i].bPicEntry != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE) {
pCurrPicParams->RefPicList[i].Index7Bits =
pD3D12Dec->m_spDPBManager->get_index7bits(pD3D12Dec->m_pCurrentReferenceTargets[i]);
}
}
pD3D12Dec->m_spDPBManager->mark_all_references_as_unused();
pD3D12Dec->m_spDPBManager->mark_references_in_use(pCurrPicParams->RefPicList);
// Releases the underlying reference picture texture objects of all references that were not marked as used in this
// method.
pD3D12Dec->m_spDPBManager->release_unused_references_texture_memory();
pCurrPicParams->CurrPic.Index7Bits = pD3D12Dec->m_spDPBManager->get_index7bits(pD3D12Dec->m_pCurrentDecodeTarget);
}
inline int
LengthFromMinCb(int length, int cbsize)
{
return length * (1 << cbsize);
}
void
d3d12_video_decoder_get_frame_info_hevc(
struct d3d12_video_decoder *pD3D12Dec, uint32_t *pWidth, uint32_t *pHeight, uint16_t *pMaxDPB, bool &isInterlaced)
{
auto pPicParams = d3d12_video_decoder_get_current_dxva_picparams<DXVA_PicParams_HEVC>(pD3D12Dec);
UINT log2_min_luma_coding_block_size = pPicParams->log2_min_luma_coding_block_size_minus3 + 3;
*pWidth = LengthFromMinCb(pPicParams->PicWidthInMinCbsY, log2_min_luma_coding_block_size);
*pHeight = LengthFromMinCb(pPicParams->PicHeightInMinCbsY, log2_min_luma_coding_block_size);
*pMaxDPB = pPicParams->sps_max_dec_pic_buffering_minus1 + 1;
isInterlaced = false;
}
///
/// Pushes the current frame as next reference, updates the DXVA HEVC structure with the indices of the DPB and
/// transitions the references
///
void
d3d12_video_decoder_prepare_current_frame_references_hevc(struct d3d12_video_decoder *pD3D12Dec,
ID3D12Resource *pTexture2D,
uint32_t subresourceIndex)
{
DXVA_PicParams_HEVC *pPicParams = d3d12_video_decoder_get_current_dxva_picparams<DXVA_PicParams_HEVC>(pD3D12Dec);
pPicParams->CurrPic.Index7Bits = pD3D12Dec->m_spDPBManager->store_future_reference(pPicParams->CurrPic.Index7Bits,
pD3D12Dec->m_spVideoDecoderHeap,
pTexture2D,
subresourceIndex);
// From HEVC DXVA spec:
// Index7Bits
// An index that identifies an uncompressed surface for the CurrPic or RefPicList member of the picture parameters structure (section 4.0).
// When Index7Bits is used in the CurrPic and RefPicList members of the picture parameters structure, the value directly specifies the DXVA index of an uncompressed surface.
// When Index7Bits is 127 (0x7F), this indicates that it does not contain a valid index.
std::vector<D3D12_RESOURCE_BARRIER>
neededStateTransitions; // Returned by update_entries to perform by the method caller
pD3D12Dec->m_spDPBManager->update_entries(
d3d12_video_decoder_get_current_dxva_picparams<DXVA_PicParams_HEVC>(pD3D12Dec)->RefPicList,
neededStateTransitions);
pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(neededStateTransitions.size(), neededStateTransitions.data());
// Schedule reverse (back to common) transitions before command list closes for current frame
for (auto BarrierDesc : neededStateTransitions) {
std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back(BarrierDesc);
}
debug_printf(
"[d3d12_video_decoder_prepare_current_frame_references_hevc] DXVA_PicParams_HEVC after index remapping)\n");
d3d12_video_decoder_log_pic_params_hevc(
d3d12_video_decoder_get_current_dxva_picparams<DXVA_PicParams_HEVC>(pD3D12Dec));
}
void
d3d12_video_decoder_prepare_dxva_slices_control_hevc(struct d3d12_video_decoder *pD3D12Dec,
std::vector<DXVA_Slice_HEVC_Short> &pOutSliceControlBuffers,
struct pipe_h265_picture_desc *picture_hevc)
{
if(!picture_hevc->slice_parameter.slice_info_present)
{
unreachable("Unsupported - need pipe_h265_picture_desc.slice_parameter.slice_info_present");
}
debug_printf("[d3d12_video_decoder_hevc] Upper layer reported %d slices for this frame, parsing them below...\n",
picture_hevc->slice_parameter.slice_count);
for (uint32_t sliceIdx = 0; sliceIdx < picture_hevc->slice_parameter.slice_count; sliceIdx++)
{
DXVA_Slice_HEVC_Short currentSliceEntry = {};
// From HEVC DXVA Spec
// wBadSliceChopping
// 0 All bits for the slice are located within the corresponding bitstream data buffer.
// 1 The bitstream data buffer contains the start of the slice, but not the entire slice, because the buffer is full.
// 2 The bitstream data buffer contains the end of the slice. It does not contain the start of the slice, because the start of the slice was located in the previous bitstream data buffer.
// 3 The bitstream data buffer does not contain the start of the slice (because the start of the slice was located in the previous bitstream data buffer),
// and it does not contain the end of the slice (because the current bitstream data buffer is also full).
switch (picture_hevc->slice_parameter.slice_data_flag[sliceIdx]) {
/* whole slice is in the buffer */
case PIPE_SLICE_BUFFER_PLACEMENT_TYPE_WHOLE:
currentSliceEntry.wBadSliceChopping = 0u;
break;
/* The beginning of the slice is in the buffer but the end is not */
case PIPE_SLICE_BUFFER_PLACEMENT_TYPE_BEGIN:
currentSliceEntry.wBadSliceChopping = 1u;
break;
/* Neither beginning nor end of the slice is in the buffer */
case PIPE_SLICE_BUFFER_PLACEMENT_TYPE_MIDDLE:
currentSliceEntry.wBadSliceChopping = 3u;
break;
/* end of the slice is in the buffer */
case PIPE_SLICE_BUFFER_PLACEMENT_TYPE_END:
currentSliceEntry.wBadSliceChopping = 2u;
break;
default:
{
unreachable("Unsupported pipe_slice_buffer_placement_type");
} break;
}
currentSliceEntry.SliceBytesInBuffer = picture_hevc->slice_parameter.slice_data_size[sliceIdx];
currentSliceEntry.BSNALunitDataLocation = picture_hevc->slice_parameter.slice_data_offset[sliceIdx];
debug_printf("[d3d12_video_decoder_hevc] Detected slice index %" PRIu32 " with SliceBytesInBuffer %d - BSNALunitDataLocation %d - wBadSliceChopping: %" PRIu16
" for frame with "
"fenceValue: %d\n",
sliceIdx,
currentSliceEntry.SliceBytesInBuffer,
currentSliceEntry.BSNALunitDataLocation,
currentSliceEntry.wBadSliceChopping,
pD3D12Dec->m_fenceValue);
pOutSliceControlBuffers.push_back(currentSliceEntry);
}
assert(pOutSliceControlBuffers.size() == picture_hevc->slice_parameter.slice_count);
}
static void
d3d12_video_decoder_log_pic_entry_hevc(DXVA_PicEntry_HEVC &picEntry)
{
debug_printf("\t\tIndex7Bits: %d\n"
"\t\tAssociatedFlag: %d\n"
"\t\tbPicEntry: %d\n",
picEntry.Index7Bits,
picEntry.AssociatedFlag,
picEntry.bPicEntry);
}
void
d3d12_video_decoder_log_pic_params_hevc(DXVA_PicParams_HEVC *pPicParams)
{
debug_printf("\n=============================================\n");
debug_printf("PicWidthInMinCbsY = %d\n", pPicParams->PicWidthInMinCbsY);
debug_printf("PicHeightInMinCbsY = %d\n", pPicParams->PicHeightInMinCbsY);
debug_printf("chroma_format_idc = %d\n", pPicParams->chroma_format_idc);
debug_printf("separate_colour_plane_flag = %d\n", pPicParams->separate_colour_plane_flag);
debug_printf("bit_depth_luma_minus8 = %d\n", pPicParams->bit_depth_luma_minus8);
debug_printf("bit_depth_chroma_minus8 = %d\n", pPicParams->bit_depth_chroma_minus8);
debug_printf("log2_max_pic_order_cnt_lsb_minus4 = %d\n", pPicParams->log2_max_pic_order_cnt_lsb_minus4);
debug_printf("NoPicReorderingFlag = %d\n", pPicParams->NoPicReorderingFlag);
debug_printf("NoBiPredFlag = %d\n", pPicParams->NoBiPredFlag);
debug_printf("ReservedBits1 = %d\n", pPicParams->ReservedBits1);
debug_printf("wFormatAndSequenceInfoFlags = %d\n", pPicParams->wFormatAndSequenceInfoFlags);
debug_printf("CurrPic.Index7Bits = %d\n", pPicParams->CurrPic.Index7Bits);
debug_printf("CurrPic.AssociatedFlag = %d\n", pPicParams->CurrPic.AssociatedFlag);
debug_printf("sps_max_dec_pic_buffering_minus1 = %d\n", pPicParams->sps_max_dec_pic_buffering_minus1);
debug_printf("log2_min_luma_coding_block_size_minus3 = %d\n", pPicParams->log2_min_luma_coding_block_size_minus3);
debug_printf("log2_diff_max_min_luma_coding_block_size = %d\n", pPicParams->log2_diff_max_min_luma_coding_block_size);
debug_printf("log2_min_transform_block_size_minus2 = %d\n", pPicParams->log2_min_transform_block_size_minus2);
debug_printf("log2_diff_max_min_transform_block_size = %d\n", pPicParams->log2_diff_max_min_transform_block_size);
debug_printf("max_transform_hierarchy_depth_inter = %d\n", pPicParams->max_transform_hierarchy_depth_inter);
debug_printf("max_transform_hierarchy_depth_intra = %d\n", pPicParams->max_transform_hierarchy_depth_intra);
debug_printf("num_short_term_ref_pic_sets = %d\n", pPicParams->num_short_term_ref_pic_sets);
debug_printf("num_long_term_ref_pics_sps = %d\n", pPicParams->num_long_term_ref_pics_sps);
debug_printf("num_ref_idx_l0_default_active_minus1 = %d\n", pPicParams->num_ref_idx_l0_default_active_minus1);
debug_printf("num_ref_idx_l1_default_active_minus1 = %d\n", pPicParams->num_ref_idx_l1_default_active_minus1);
debug_printf("init_qp_minus26 = %d\n", pPicParams->init_qp_minus26);
debug_printf("ucNumDeltaPocsOfRefRpsIdx = %d\n", pPicParams->ucNumDeltaPocsOfRefRpsIdx);
debug_printf("wNumBitsForShortTermRPSInSlice = %d\n", pPicParams->wNumBitsForShortTermRPSInSlice);
debug_printf("ReservedBits2 = %d\n", pPicParams->ReservedBits2);
debug_printf("scaling_list_enabled_flag = %d\n", pPicParams->scaling_list_enabled_flag);
debug_printf("amp_enabled_flag = %d\n", pPicParams->amp_enabled_flag);
debug_printf("sample_adaptive_offset_enabled_flag = %d\n", pPicParams->sample_adaptive_offset_enabled_flag);
debug_printf("pcm_enabled_flag = %d\n", pPicParams->pcm_enabled_flag);
debug_printf("pcm_sample_bit_depth_luma_minus1 = %d\n", pPicParams->pcm_sample_bit_depth_luma_minus1);
debug_printf("pcm_sample_bit_depth_chroma_minus1 = %d\n", pPicParams->pcm_sample_bit_depth_chroma_minus1);
debug_printf("log2_min_pcm_luma_coding_block_size_minus3 = %d\n", pPicParams->log2_min_pcm_luma_coding_block_size_minus3);
debug_printf("log2_diff_max_min_pcm_luma_coding_block_size = %d\n", pPicParams->log2_diff_max_min_pcm_luma_coding_block_size);
debug_printf("pcm_loop_filter_disabled_flag = %d\n", pPicParams->pcm_loop_filter_disabled_flag);
debug_printf("long_term_ref_pics_present_flag = %d\n", pPicParams->long_term_ref_pics_present_flag);
debug_printf("sps_temporal_mvp_enabled_flag = %d\n", pPicParams->sps_temporal_mvp_enabled_flag);
debug_printf("strong_intra_smoothing_enabled_flag = %d\n", pPicParams->strong_intra_smoothing_enabled_flag);
debug_printf("dependent_slice_segments_enabled_flag = %d\n", pPicParams->dependent_slice_segments_enabled_flag);
debug_printf("output_flag_present_flag = %d\n", pPicParams->output_flag_present_flag);
debug_printf("num_extra_slice_header_bits = %d\n", pPicParams->num_extra_slice_header_bits);
debug_printf("sign_data_hiding_enabled_flag = %d\n", pPicParams->sign_data_hiding_enabled_flag);
debug_printf("cabac_init_present_flag = %d\n", pPicParams->cabac_init_present_flag);
debug_printf("ReservedBits3 = %d\n", pPicParams->ReservedBits3);
debug_printf("dwCodingParamToolFlags = %d\n", pPicParams->dwCodingParamToolFlags);
debug_printf("constrained_intra_pred_flag = %d\n", pPicParams->constrained_intra_pred_flag);
debug_printf("transform_skip_enabled_flag = %d\n", pPicParams->transform_skip_enabled_flag);
debug_printf("cu_qp_delta_enabled_flag = %d\n", pPicParams->cu_qp_delta_enabled_flag);
debug_printf("pps_slice_chroma_qp_offsets_present_flag = %d\n", pPicParams->pps_slice_chroma_qp_offsets_present_flag);
debug_printf("weighted_pred_flag = %d\n", pPicParams->weighted_pred_flag);
debug_printf("weighted_bipred_flag = %d\n", pPicParams->weighted_bipred_flag);
debug_printf("transquant_bypass_enabled_flag = %d\n", pPicParams->transquant_bypass_enabled_flag);
debug_printf("tiles_enabled_flag = %d\n", pPicParams->tiles_enabled_flag);
debug_printf("entropy_coding_sync_enabled_flag = %d\n", pPicParams->entropy_coding_sync_enabled_flag);
debug_printf("uniform_spacing_flag = %d\n", pPicParams->uniform_spacing_flag);
debug_printf("loop_filter_across_tiles_enabled_flag = %d\n", pPicParams->loop_filter_across_tiles_enabled_flag);
debug_printf("pps_loop_filter_across_slices_enabled_flag = %d\n", pPicParams->pps_loop_filter_across_slices_enabled_flag);
debug_printf("deblocking_filter_override_enabled_flag = %d\n", pPicParams->deblocking_filter_override_enabled_flag);
debug_printf("pps_deblocking_filter_disabled_flag = %d\n", pPicParams->pps_deblocking_filter_disabled_flag);
debug_printf("lists_modification_present_flag = %d\n", pPicParams->lists_modification_present_flag);
debug_printf("slice_segment_header_extension_present_flag = %d\n", pPicParams->slice_segment_header_extension_present_flag);
debug_printf("IrapPicFlag = %d\n", pPicParams->IrapPicFlag);
debug_printf("IdrPicFlag = %d\n", pPicParams->IdrPicFlag);
debug_printf("IntraPicFlag = %d\n", pPicParams->IntraPicFlag);
debug_printf("ReservedBits4 = %d\n", pPicParams->ReservedBits4);
debug_printf("dwCodingSettingPicturePropertyFlags = %d\n", pPicParams->dwCodingSettingPicturePropertyFlags);
debug_printf("pps_cb_qp_offset = %d\n", pPicParams->pps_cb_qp_offset);
debug_printf("pps_cr_qp_offset = %d\n", pPicParams->pps_cr_qp_offset);
debug_printf("num_tile_columns_minus1 = %d\n", pPicParams->num_tile_columns_minus1);
debug_printf("num_tile_rows_minus1 = %d\n", pPicParams->num_tile_rows_minus1);
for (uint32_t i = 0; i < std::min((unsigned) pPicParams->num_tile_columns_minus1 + 1u, (unsigned) _countof(DXVA_PicParams_HEVC::column_width_minus1)); i++) {
debug_printf("column_width_minus1[%d]; = %d\n", i, pPicParams->column_width_minus1[i]);
}
for (uint32_t i = 0; i < std::min((unsigned) pPicParams->num_tile_rows_minus1 + 1u, (unsigned) _countof(DXVA_PicParams_HEVC::row_height_minus1)); i++) {
debug_printf("row_height_minus1[%d]; = %d\n", i, pPicParams->row_height_minus1[i]);
}
debug_printf("diff_cu_qp_delta_depth = %d\n", pPicParams->diff_cu_qp_delta_depth);
debug_printf("pps_beta_offset_div2 = %d\n", pPicParams->pps_beta_offset_div2);
debug_printf("pps_tc_offset_div2 = %d\n", pPicParams->pps_tc_offset_div2);
debug_printf("log2_parallel_merge_level_minus2 = %d\n", pPicParams->log2_parallel_merge_level_minus2);
debug_printf("CurrPicOrderCntVal = %d\n", pPicParams->CurrPicOrderCntVal);
debug_printf("ReservedBits5 = %d\n", pPicParams->ReservedBits5);
debug_printf("ReservedBits6 = %d\n", pPicParams->ReservedBits6);
debug_printf("ReservedBits7 = %d\n", pPicParams->ReservedBits7);
debug_printf("StatusReportFeedbackNumber = %d\n", pPicParams->StatusReportFeedbackNumber);
debug_printf("[D3D12 Video Decoder HEVC DXVA PicParams info]\n"
"\t[Current Picture Entry]\n");
d3d12_video_decoder_log_pic_entry_hevc(pPicParams->CurrPic);
debug_printf("[D3D12 Video Decoder HEVC DXVA PicParams info]\n"
"\t[Current Picture Reference sets, hiding entries with bPicEntry 0xFF]\n");
for (uint32_t refIdx = 0; refIdx < _countof(DXVA_PicParams_HEVC::RefPicSetStCurrBefore); refIdx++) {
if(pPicParams->RefPicSetStCurrBefore[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE) {
debug_printf("\tRefPicSetStCurrBefore[%d] = %d \n PicEntry RefPicList[%d]\n", refIdx, pPicParams->RefPicSetStCurrBefore[refIdx], pPicParams->RefPicSetStCurrBefore[refIdx]);
d3d12_video_decoder_log_pic_entry_hevc(pPicParams->RefPicList[pPicParams->RefPicSetStCurrBefore[refIdx]]);
debug_printf("\t\tPicOrderCntValList: %d\n",
pPicParams->PicOrderCntValList[pPicParams->RefPicSetStCurrBefore[refIdx]]);
}
}
for (uint32_t refIdx = 0; refIdx < _countof(DXVA_PicParams_HEVC::RefPicSetStCurrAfter); refIdx++) {
if(pPicParams->RefPicSetStCurrAfter[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE) {
debug_printf("\tRefPicSetStCurrAfter[%d] = %d \n PicEntry RefPicList[%d]\n", refIdx, pPicParams->RefPicSetStCurrAfter[refIdx], pPicParams->RefPicSetStCurrAfter[refIdx]);
d3d12_video_decoder_log_pic_entry_hevc(pPicParams->RefPicList[pPicParams->RefPicSetStCurrAfter[refIdx]]);
debug_printf("\t\tPicOrderCntValList: %d\n",
pPicParams->PicOrderCntValList[pPicParams->RefPicSetStCurrAfter[refIdx]]);
}
}
for (uint32_t refIdx = 0; refIdx < _countof(DXVA_PicParams_HEVC::RefPicSetLtCurr); refIdx++) {
if(pPicParams->RefPicSetLtCurr[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE) {
debug_printf("\tRefPicSetLtCurr[%d] = %d \n PicEntry RefPicList[%d]\n", refIdx, pPicParams->RefPicSetLtCurr[refIdx], pPicParams->RefPicSetLtCurr[refIdx]);
d3d12_video_decoder_log_pic_entry_hevc(pPicParams->RefPicList[pPicParams->RefPicSetLtCurr[refIdx]]);
debug_printf("\t\tPicOrderCntValList: %d\n",
pPicParams->PicOrderCntValList[pPicParams->RefPicSetLtCurr[refIdx]]);
}
}
}
void
d3d12_video_decoder_sort_rps_lists_by_refpoc(DXVA_PicParams_HEVC* pDXVAStruct, pipe_h265_picture_desc *pPipeDesc)
{
// Sort the RPS lists in pDXVAStruct in order by pPipeDesc->PicOrderCntVal for DXVA expectations.
// Both arrays have parallel indices
struct RPSEntryWithPOC {
uint8_t refpicset_index;
int32_t poc_value;
};
std::vector<RPSEntryWithPOC> tmpVec;
for (uint8_t i = 0; i < pPipeDesc->NumPocStCurrBefore; i++)
tmpVec.push_back({ pDXVAStruct->RefPicSetStCurrBefore[i], pPipeDesc->PicOrderCntVal[pDXVAStruct->RefPicSetStCurrBefore[i]] });
std::sort(std::begin(tmpVec), std::end(tmpVec), [](RPSEntryWithPOC entryI, RPSEntryWithPOC entryJ)
{ return entryI.poc_value /*desc order*/ > entryJ.poc_value; });
for (uint8_t i = 0; i < pPipeDesc->NumPocStCurrBefore; i++)
pDXVAStruct->RefPicSetStCurrBefore[i] = tmpVec[i].refpicset_index;
tmpVec.clear();
for (uint8_t i = 0; i < pPipeDesc->NumPocStCurrAfter; i++)
tmpVec.push_back({ pDXVAStruct->RefPicSetStCurrAfter[i], pPipeDesc->PicOrderCntVal[pDXVAStruct->RefPicSetStCurrAfter[i]] });
std::sort(std::begin(tmpVec), std::end(tmpVec), [](RPSEntryWithPOC entryI, RPSEntryWithPOC entryJ)
{ return entryI.poc_value /*ascending order*/ < entryJ.poc_value; });
for (uint8_t i = 0; i < pPipeDesc->NumPocStCurrAfter; i++)
pDXVAStruct->RefPicSetStCurrAfter[i] = tmpVec[i].refpicset_index;
tmpVec.clear();
for (uint8_t i = 0; i < pPipeDesc->NumPocLtCurr; i++)
tmpVec.push_back({ pDXVAStruct->RefPicSetLtCurr[i], pPipeDesc->PicOrderCntVal[pDXVAStruct->RefPicSetLtCurr[i]] });
// The ordering of RefPicSetLtCurr is unclear from the DXVA spec, might need to be changed
std::sort(std::begin(tmpVec), std::end(tmpVec), [](RPSEntryWithPOC entryI, RPSEntryWithPOC entryJ)
{ return entryI.poc_value /*ascending order*/ < entryJ.poc_value; });
for (uint8_t i = 0; i < pPipeDesc->NumPocLtCurr; i++)
pDXVAStruct->RefPicSetLtCurr[i] = tmpVec[i].refpicset_index;
}
DXVA_PicParams_HEVC
d3d12_video_decoder_dxva_picparams_from_pipe_picparams_hevc(
uint32_t frameNum,
pipe_video_profile profile,
pipe_h265_picture_desc *pPipeDesc)
{
pipe_h265_pps *pps = pPipeDesc->pps;
pipe_h265_sps *sps = pPipeDesc->pps->sps;
DXVA_PicParams_HEVC dxvaStructure;
memset(&dxvaStructure, 0, sizeof(dxvaStructure));
uint8_t log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
dxvaStructure.PicWidthInMinCbsY = sps->pic_width_in_luma_samples >> log2_min_cb_size;
dxvaStructure.PicHeightInMinCbsY = sps->pic_height_in_luma_samples >> log2_min_cb_size;
dxvaStructure.chroma_format_idc = sps->chroma_format_idc;
dxvaStructure.separate_colour_plane_flag = sps->separate_colour_plane_flag;
dxvaStructure.bit_depth_luma_minus8 = sps->bit_depth_luma_minus8;
dxvaStructure.bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8;
dxvaStructure.log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4;
dxvaStructure.NoPicReorderingFlag = sps->no_pic_reordering_flag;
dxvaStructure.NoBiPredFlag = sps->no_bi_pred_flag;
dxvaStructure.CurrPic.bPicEntry = 0; // No semantic for this flag in HEVC DXVA spec
// CurrPic.Index7Bits is handled by d3d12_video_decoder_refresh_dpb_active_references_hevc
dxvaStructure.sps_max_dec_pic_buffering_minus1 = sps->sps_max_dec_pic_buffering_minus1;
dxvaStructure.log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3;
dxvaStructure.log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size;
dxvaStructure.log2_min_transform_block_size_minus2 = sps->log2_min_transform_block_size_minus2;
dxvaStructure.log2_diff_max_min_transform_block_size = sps->log2_diff_max_min_transform_block_size;
dxvaStructure.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
dxvaStructure.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
dxvaStructure.num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets;
dxvaStructure.num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps;
dxvaStructure.num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1;
dxvaStructure.num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1;
dxvaStructure.init_qp_minus26 = pps->init_qp_minus26;
// NumDeltaPocsOfRefRpsIdx is not passed from VA to pipe, and VA doesn't have it defined in their va_dec_hevc header.
// DXVA drivers should use wNumBitsForShortTermRPSInSlice (st_rps_bits in VA) to derive the slice header info instead
dxvaStructure.ucNumDeltaPocsOfRefRpsIdx = pPipeDesc->NumDeltaPocsOfRefRpsIdx;
dxvaStructure.wNumBitsForShortTermRPSInSlice = pps->st_rps_bits;
dxvaStructure.scaling_list_enabled_flag = sps->scaling_list_enabled_flag;
dxvaStructure.amp_enabled_flag = sps->amp_enabled_flag;
dxvaStructure.sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag;
dxvaStructure.pcm_enabled_flag = sps->pcm_enabled_flag;
dxvaStructure.pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1;
dxvaStructure.pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1;
dxvaStructure.log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3;
dxvaStructure.log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size;
dxvaStructure.pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag;
dxvaStructure.long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag;
dxvaStructure.sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag;
dxvaStructure.strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag;
dxvaStructure.dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag;
dxvaStructure.output_flag_present_flag = pps->output_flag_present_flag;
dxvaStructure.num_extra_slice_header_bits = pps->num_extra_slice_header_bits;
dxvaStructure.sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag;
dxvaStructure.cabac_init_present_flag = pps->cabac_init_present_flag;
dxvaStructure.ReservedBits3 = 0;
dxvaStructure.constrained_intra_pred_flag = pps->constrained_intra_pred_flag;
dxvaStructure.transform_skip_enabled_flag = pps->transform_skip_enabled_flag;
dxvaStructure.cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag;
dxvaStructure.pps_slice_chroma_qp_offsets_present_flag = pps->pps_slice_chroma_qp_offsets_present_flag;
dxvaStructure.weighted_pred_flag = pps->weighted_pred_flag;
dxvaStructure.weighted_bipred_flag = pps->weighted_bipred_flag;
dxvaStructure.transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag;
dxvaStructure.tiles_enabled_flag = pps->tiles_enabled_flag;
dxvaStructure.entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag;
dxvaStructure.uniform_spacing_flag = pps->uniform_spacing_flag;
dxvaStructure.loop_filter_across_tiles_enabled_flag = (pps->tiles_enabled_flag ? pps->loop_filter_across_tiles_enabled_flag : 0);
dxvaStructure.pps_loop_filter_across_slices_enabled_flag = pps->pps_loop_filter_across_slices_enabled_flag;
dxvaStructure.deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag;
dxvaStructure.pps_deblocking_filter_disabled_flag = pps->pps_deblocking_filter_disabled_flag;
dxvaStructure.lists_modification_present_flag = pps->lists_modification_present_flag;
dxvaStructure.slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag;
dxvaStructure.IrapPicFlag = pPipeDesc->RAPPicFlag;
dxvaStructure.IdrPicFlag = pPipeDesc->IDRPicFlag;
dxvaStructure.IntraPicFlag = pPipeDesc->IntraPicFlag;
dxvaStructure.pps_cb_qp_offset = pps->pps_cb_qp_offset;
dxvaStructure.pps_cr_qp_offset = pps->pps_cr_qp_offset;
if (pps->tiles_enabled_flag) {
dxvaStructure.num_tile_columns_minus1 = pps->num_tile_columns_minus1;
dxvaStructure.num_tile_rows_minus1 = pps->num_tile_rows_minus1;
if (!pps->uniform_spacing_flag) {
for (uint8_t i = 0; i < _countof(dxvaStructure.column_width_minus1); i++)
dxvaStructure.column_width_minus1[i] = pps->column_width_minus1[i];
for (uint8_t i = 0; i < _countof(dxvaStructure.row_height_minus1); i++)
dxvaStructure.row_height_minus1[i] = pps->row_height_minus1[i];
}
}
dxvaStructure.diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth;
dxvaStructure.pps_beta_offset_div2 = pps->pps_beta_offset_div2;
dxvaStructure.pps_tc_offset_div2 = pps->pps_tc_offset_div2;
dxvaStructure.log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2;
dxvaStructure.CurrPicOrderCntVal = pPipeDesc->CurrPicOrderCntVal;
// Update RefPicList with the DPB pictures to be kept alive for current or future frames
for (uint8_t refIdx = 0; refIdx < _countof(DXVA_PicParams_HEVC::PicOrderCntValList); refIdx++)
{
if (pPipeDesc->ref[refIdx] != nullptr) {
// Mark as used so d3d12_video_decoder_refresh_dpb_active_references_hevc will assign the correct Index7Bits
dxvaStructure.RefPicList[refIdx].Index7Bits = 0;
// Mark refpic as LTR if necessary.
dxvaStructure.RefPicList[refIdx].AssociatedFlag = pPipeDesc->IsLongTerm[refIdx] ? 1u : 0u;
}
else
{
dxvaStructure.RefPicList[refIdx].bPicEntry = DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE;
}
}
// Copy POC values for the references
memcpy(dxvaStructure.PicOrderCntValList, pPipeDesc->PicOrderCntVal, sizeof(dxvaStructure.PicOrderCntValList));
// Copy RPS Sets to DXVA or mark them as 0xFF if unused in current frame
for (uint8_t i = 0; i < DXVA_RPS_COUNT; i++) {
dxvaStructure.RefPicSetStCurrBefore[i] = (i < pPipeDesc->NumPocStCurrBefore) ? pPipeDesc->RefPicSetStCurrBefore[i] : DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE;
dxvaStructure.RefPicSetStCurrAfter[i] = (i < pPipeDesc->NumPocStCurrAfter) ? pPipeDesc->RefPicSetStCurrAfter[i] : DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE;
dxvaStructure.RefPicSetLtCurr[i] = (i < pPipeDesc->NumPocLtCurr) ? pPipeDesc->RefPicSetLtCurr[i] : DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE;
}
// DXVA drivers expect these in POC order, VA/pipe sends them out of order.
d3d12_video_decoder_sort_rps_lists_by_refpoc(&dxvaStructure, pPipeDesc);
for (uint32_t refIdx = 0; refIdx < DXVA_RPS_COUNT; refIdx++) {
if ((refIdx < pPipeDesc->NumPocStCurrBefore) && (pPipeDesc->RefPicSetStCurrBefore[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE)) {
debug_printf("pPipeDesc->RefPicSetStCurrBefore[%d]: %d (index into RefPicList) Refs[%d] pipe buffer ptr = %p - d3d12 resource %p POC: %d\n",
refIdx, pPipeDesc->RefPicSetStCurrBefore[refIdx], pPipeDesc->RefPicSetStCurrBefore[refIdx], pPipeDesc->ref[pPipeDesc->RefPicSetStCurrBefore[refIdx]],
d3d12_resource_resource(((struct d3d12_video_buffer *)(pPipeDesc->ref[pPipeDesc->RefPicSetStCurrBefore[refIdx]]))->texture),
dxvaStructure.PicOrderCntValList[pPipeDesc->RefPicSetStCurrBefore[refIdx]]);
}
if ((refIdx < pPipeDesc->NumPocStCurrAfter) && (pPipeDesc->RefPicSetStCurrAfter[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE)) {
debug_printf("pPipeDesc->RefPicSetStCurrAfter[%d]: %d (index into RefPicList) Refs[%d] pipe buffer ptr = %p - d3d12 resource %p POC: %d\n",
refIdx, pPipeDesc->RefPicSetStCurrAfter[refIdx], pPipeDesc->RefPicSetStCurrAfter[refIdx], pPipeDesc->ref[pPipeDesc->RefPicSetStCurrAfter[refIdx]],
d3d12_resource_resource(((struct d3d12_video_buffer *)(pPipeDesc->ref[pPipeDesc->RefPicSetStCurrAfter[refIdx]]))->texture),
dxvaStructure.PicOrderCntValList[pPipeDesc->RefPicSetStCurrAfter[refIdx]]);
}
if ((refIdx < pPipeDesc->NumPocLtCurr) && (pPipeDesc->RefPicSetLtCurr[refIdx] != DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE)) {
debug_printf("pPipeDesc->RefPicSetLtCurr[%d]: %d (index into RefPicList) Refs[%d] pipe buffer ptr = %p - d3d12 resource %p POC: %d\n",
refIdx, pPipeDesc->RefPicSetLtCurr[refIdx], pPipeDesc->RefPicSetLtCurr[refIdx], pPipeDesc->ref[pPipeDesc->RefPicSetLtCurr[refIdx]],
d3d12_resource_resource(((struct d3d12_video_buffer *)(pPipeDesc->ref[pPipeDesc->RefPicSetLtCurr[refIdx]]))->texture),
dxvaStructure.PicOrderCntValList[pPipeDesc->RefPicSetLtCurr[refIdx]]);
}
}
// DXVA spec: Arbitrary number set by the host decoder to use as a tag in the status report
// feedback data. The value should not equal 0, and should be different in each call to
// Execute. For more information, see section 12.0, Status Report Data Structure.
dxvaStructure.StatusReportFeedbackNumber = frameNum;
assert(dxvaStructure.StatusReportFeedbackNumber > 0);
return dxvaStructure;
}
void
d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_hevc(pipe_h265_picture_desc *pPipeDesc,
DXVA_Qmatrix_HEVC &outMatrixBuffer,
bool &outScalingListEnabled)
{
// VA is already converting hevc scaling lists to zigzag order
// https://gitlab.freedesktop.org/mesa/mesa/-/commit/63dcfed81f011dae5ca68af3369433be28135415
outScalingListEnabled = (pPipeDesc->pps->sps->scaling_list_enabled_flag != 0);
if (outScalingListEnabled) {
memcpy(outMatrixBuffer.ucScalingLists0, pPipeDesc->pps->sps->ScalingList4x4, 6 * 16);
memcpy(outMatrixBuffer.ucScalingLists1, pPipeDesc->pps->sps->ScalingList8x8, 6 * 64);
memcpy(outMatrixBuffer.ucScalingLists2, pPipeDesc->pps->sps->ScalingList16x16, 6 * 64);
memcpy(outMatrixBuffer.ucScalingLists3, pPipeDesc->pps->sps->ScalingList32x32, 2 * 64);
memcpy(outMatrixBuffer.ucScalingListDCCoefSizeID2, pPipeDesc->pps->sps->ScalingListDCCoeff16x16, 6);
memcpy(outMatrixBuffer.ucScalingListDCCoefSizeID3, pPipeDesc->pps->sps->ScalingListDCCoeff32x32, 2);
} else {
memset(&outMatrixBuffer, 0, sizeof(outMatrixBuffer));
}
}

View file

@ -0,0 +1,247 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of uint8_tge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_DEC_HEVC_H
#define D3D12_VIDEO_DEC_HEVC_H
#include "d3d12_video_types.h"
// From DXVA spec regarding DXVA_PicEntry_HEVC entries:
// Entries that will not be used for decoding the current picture, or any subsequent pictures,
// are indicated by setting bPicEntry to 0xFF.
// If bPicEntry is not 0xFF, the entry may be used as a reference surface for decoding the current picture or
// a subsequent picture (in decoding order).
constexpr uint16_t DXVA_HEVC_INVALID_PICTURE_INDEX =
0x7F; // This corresponds to DXVA_PicEntry_HEVC.Index7Bits ; Not to be confused with the invalid value for
// DXVA_PicEntry_HEVC.bPicEntry full uint8_t value
constexpr uint16_t DXVA_HEVC_INVALID_PICTURE_ENTRY_VALUE = 0xFF; // This corresponds to DXVA_PicEntry_HEVC.bPicEntry
constexpr unsigned int DXVA_HEVC_START_CODE = 0x000001; // 3 byte start code
constexpr unsigned int DXVA_HEVC_START_CODE_LEN_BITS = 24; // 3 byte start code
#define DXVA_RPS_COUNT 8
/* HEVC picture entry data structure */
/* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */
#pragma pack(push, BeforeDXVApacking, 1)
typedef struct _DXVA_PicEntry_HEVC
{
union
{
struct
{
uint8_t Index7Bits : 7;
uint8_t AssociatedFlag : 1;
};
uint8_t bPicEntry;
};
} DXVA_PicEntry_HEVC, *LPDXVA_PicEntry_HEVC; /* 1 byte */
#pragma pack(pop, BeforeDXVApacking)
/* HEVC picture parameters structure */
/* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */
#pragma pack(push, BeforeDXVApacking, 1)
/* HEVC Picture Parameter structure */
typedef struct _DXVA_PicParams_HEVC {
uint16_t PicWidthInMinCbsY;
uint16_t PicHeightInMinCbsY;
union {
struct {
uint16_t chroma_format_idc : 2;
uint16_t separate_colour_plane_flag : 1;
uint16_t bit_depth_luma_minus8 : 3;
uint16_t bit_depth_chroma_minus8 : 3;
uint16_t log2_max_pic_order_cnt_lsb_minus4 : 4;
uint16_t NoPicReorderingFlag : 1;
uint16_t NoBiPredFlag : 1;
uint16_t ReservedBits1 : 1;
};
uint16_t wFormatAndSequenceInfoFlags;
};
DXVA_PicEntry_HEVC CurrPic;
uint8_t sps_max_dec_pic_buffering_minus1;
uint8_t log2_min_luma_coding_block_size_minus3;
uint8_t log2_diff_max_min_luma_coding_block_size;
uint8_t log2_min_transform_block_size_minus2;
uint8_t log2_diff_max_min_transform_block_size;
uint8_t max_transform_hierarchy_depth_inter;
uint8_t max_transform_hierarchy_depth_intra;
uint8_t num_short_term_ref_pic_sets;
uint8_t num_long_term_ref_pics_sps;
uint8_t num_ref_idx_l0_default_active_minus1;
uint8_t num_ref_idx_l1_default_active_minus1;
uint8_t init_qp_minus26;
uint8_t ucNumDeltaPocsOfRefRpsIdx;
uint16_t wNumBitsForShortTermRPSInSlice;
uint16_t ReservedBits2;
union {
struct {
uint32_t scaling_list_enabled_flag : 1;
uint32_t amp_enabled_flag : 1;
uint32_t sample_adaptive_offset_enabled_flag : 1;
uint32_t pcm_enabled_flag : 1;
uint32_t pcm_sample_bit_depth_luma_minus1 : 4;
uint32_t pcm_sample_bit_depth_chroma_minus1 : 4;
uint32_t log2_min_pcm_luma_coding_block_size_minus3 : 2;
uint32_t log2_diff_max_min_pcm_luma_coding_block_size : 2;
uint32_t pcm_loop_filter_disabled_flag : 1;
uint32_t long_term_ref_pics_present_flag : 1;
uint32_t sps_temporal_mvp_enabled_flag : 1;
uint32_t strong_intra_smoothing_enabled_flag : 1;
uint32_t dependent_slice_segments_enabled_flag : 1;
uint32_t output_flag_present_flag : 1;
uint32_t num_extra_slice_header_bits : 3;
uint32_t sign_data_hiding_enabled_flag : 1;
uint32_t cabac_init_present_flag : 1;
uint32_t ReservedBits3 : 5;
};
uint32_t dwCodingParamToolFlags;
};
union {
struct {
uint32_t constrained_intra_pred_flag : 1;
uint32_t transform_skip_enabled_flag : 1;
uint32_t cu_qp_delta_enabled_flag : 1;
uint32_t pps_slice_chroma_qp_offsets_present_flag : 1;
uint32_t weighted_pred_flag : 1;
uint32_t weighted_bipred_flag : 1;
uint32_t transquant_bypass_enabled_flag : 1;
uint32_t tiles_enabled_flag : 1;
uint32_t entropy_coding_sync_enabled_flag : 1;
uint32_t uniform_spacing_flag : 1;
uint32_t loop_filter_across_tiles_enabled_flag : 1;
uint32_t pps_loop_filter_across_slices_enabled_flag : 1;
uint32_t deblocking_filter_override_enabled_flag : 1;
uint32_t pps_deblocking_filter_disabled_flag : 1;
uint32_t lists_modification_present_flag : 1;
uint32_t slice_segment_header_extension_present_flag : 1;
uint32_t IrapPicFlag : 1;
uint32_t IdrPicFlag : 1;
uint32_t IntraPicFlag : 1;
uint32_t ReservedBits4 : 13;
};
uint32_t dwCodingSettingPicturePropertyFlags;
};
uint8_t pps_cb_qp_offset;
uint8_t pps_cr_qp_offset;
uint8_t num_tile_columns_minus1;
uint8_t num_tile_rows_minus1;
uint16_t column_width_minus1[19];
uint16_t row_height_minus1[21];
uint8_t diff_cu_qp_delta_depth;
uint8_t pps_beta_offset_div2;
uint8_t pps_tc_offset_div2;
uint8_t log2_parallel_merge_level_minus2;
int32_t CurrPicOrderCntVal;
DXVA_PicEntry_HEVC RefPicList[15];
uint8_t ReservedBits5;
int32_t PicOrderCntValList[15];
uint8_t RefPicSetStCurrBefore[8];
uint8_t RefPicSetStCurrAfter[8];
uint8_t RefPicSetLtCurr[8];
uint16_t ReservedBits6;
uint16_t ReservedBits7;
uint32_t StatusReportFeedbackNumber;
} DXVA_PicParams_HEVC, *LPDXVA_PicParams_HEVC;
#pragma pack(pop, BeforeDXVApacking)
static_assert(_countof(DXVA_PicParams_HEVC::RefPicSetStCurrBefore) == DXVA_RPS_COUNT,
"DXVA_PicParams_HEVC::RefPicSetStCurrBefore must have DXVA_RPS_COUNT elements");
static_assert(_countof(DXVA_PicParams_HEVC::RefPicSetStCurrAfter) == DXVA_RPS_COUNT,
"DXVA_PicParams_HEVC::RefPicSetStCurrAfter must have DXVA_RPS_COUNT elements");
static_assert(_countof(DXVA_PicParams_HEVC::RefPicSetLtCurr) == DXVA_RPS_COUNT,
"DXVA_PicParams_HEVC::RefPicSetLtCurr must have DXVA_RPS_COUNT elements");
/* HEVC Quantization Matrix structure */
/* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */
#pragma pack(push, BeforeDXVApacking, 1)
typedef struct _DXVA_Qmatrix_HEVC
{
uint8_t ucScalingLists0[6][16];
uint8_t ucScalingLists1[6][64];
uint8_t ucScalingLists2[6][64];
uint8_t ucScalingLists3[2][64];
uint8_t ucScalingListDCCoefSizeID2[6];
uint8_t ucScalingListDCCoefSizeID3[2];
} DXVA_Qmatrix_HEVC, *LPDXVA_Qmatrix_HEVC;
#pragma pack(pop, BeforeDXVApacking)
/* HEVC slice control data structure - short form */
/* If including new DXVA structs in this header, check the byte-alignment packing pragma declarations that need to be included with them */
#pragma pack(push, BeforeDXVApacking, 1)
typedef struct _DXVA_Slice_HEVC_Short
{
uint32_t BSNALunitDataLocation; /* type 1..5 */
uint32_t SliceBytesInBuffer; /* for off-host parse */
uint16_t wBadSliceChopping; /* for off-host parse */
} DXVA_Slice_HEVC_Short, *LPDXVA_Slice_HEVC_Short;
#pragma pack(pop, BeforeDXVApacking)
#pragma pack(push, BeforeDXVApacking, 1)
typedef struct _DXVA_Status_HEVC {
uint16_t StatusReportFeedbackNumber;
DXVA_PicEntry_HEVC CurrPic;
uint8_t bBufType;
uint8_t bStatus;
uint8_t bReserved8Bits;
uint16_t wNumMbsAffected;
} DXVA_Status_HEVC, *LPDXVA_Status_HEVC;
#pragma pack(pop, BeforeDXVApacking)
DXVA_PicParams_HEVC
d3d12_video_decoder_dxva_picparams_from_pipe_picparams_hevc(uint32_t frameNum,
pipe_video_profile profile,
pipe_h265_picture_desc *pipeDesc);
void
d3d12_video_decoder_get_frame_info_hevc(
struct d3d12_video_decoder *pD3D12Dec, uint32_t *pWidth, uint32_t *pHeight, uint16_t *pMaxDPB, bool &isInterlaced);
void
d3d12_video_decoder_prepare_current_frame_references_hevc(struct d3d12_video_decoder *pD3D12Dec,
ID3D12Resource * pTexture2D,
uint32_t subresourceIndex);
void
d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_hevc(pipe_h265_picture_desc *pPipeDesc,
DXVA_Qmatrix_HEVC & outMatrixBuffer,
bool &outScalingListEnabled);
void
d3d12_video_decoder_refresh_dpb_active_references_hevc(struct d3d12_video_decoder *pD3D12Dec);
bool
d3d12_video_decoder_get_next_slice_size_and_offset_hevc(std::vector<uint8_t> &buf,
unsigned int bufferOffset,
uint32_t & outSliceSize,
uint32_t & outSliceOffset);
uint
d3d12_video_decoder_get_slice_count_hevc(std::vector<uint8_t> &buf);
void
d3d12_video_decoder_prepare_dxva_slices_control_hevc(struct d3d12_video_decoder * pD3D12Dec,
std::vector<DXVA_Slice_HEVC_Short> &pOutSliceControlBuffers,
struct pipe_h265_picture_desc* picture_hevc);
void
d3d12_video_decoder_log_pic_params_hevc(DXVA_PicParams_HEVC * pPicParams);
#endif

View file

@ -23,6 +23,7 @@
#include "d3d12_video_dec_references_mgr.h" #include "d3d12_video_dec_references_mgr.h"
#include "d3d12_video_dec_h264.h" #include "d3d12_video_dec_h264.h"
#include "d3d12_video_dec_hevc.h"
#include "d3d12_video_texture_array_dpb_manager.h" #include "d3d12_video_texture_array_dpb_manager.h"
#include "d3d12_video_array_of_textures_dpb_manager.h" #include "d3d12_video_array_of_textures_dpb_manager.h"
#include "d3d12_screen.h" #include "d3d12_screen.h"
@ -40,6 +41,8 @@ GetInvalidReferenceIndex(d3d12_video_decode_profile_type DecodeProfileType)
switch (DecodeProfileType) { switch (DecodeProfileType) {
case d3d12_video_decode_profile_type_h264: case d3d12_video_decode_profile_type_h264:
return DXVA_H264_INVALID_PICTURE_INDEX; return DXVA_H264_INVALID_PICTURE_INDEX;
case d3d12_video_decode_profile_type_hevc:
return DXVA_HEVC_INVALID_PICTURE_INDEX;
default: default:
return 0; return 0;
}; };

View file

@ -31,10 +31,12 @@
#include "d3d12_surface.h" #include "d3d12_surface.h"
#include "d3d12_video_enc.h" #include "d3d12_video_enc.h"
#include "d3d12_video_enc_h264.h" #include "d3d12_video_enc_h264.h"
#include "d3d12_video_enc_hevc.h"
#include "d3d12_video_buffer.h" #include "d3d12_video_buffer.h"
#include "d3d12_video_texture_array_dpb_manager.h" #include "d3d12_video_texture_array_dpb_manager.h"
#include "d3d12_video_array_of_textures_dpb_manager.h" #include "d3d12_video_array_of_textures_dpb_manager.h"
#include "d3d12_video_encoder_references_manager_h264.h" #include "d3d12_video_encoder_references_manager_h264.h"
#include "d3d12_video_encoder_references_manager_hevc.h"
#include "d3d12_residency.h" #include "d3d12_residency.h"
#include "vl/vl_video_buffer.h" #include "vl/vl_video_buffer.h"
@ -183,13 +185,18 @@ d3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12
d3d12_video_encoder_update_current_frame_pic_params_info_h264(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference); d3d12_video_encoder_update_current_frame_pic_params_info_h264(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
d3d12_video_encoder_update_current_frame_pic_params_info_hevc(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
} break; } break;
} }
pD3D12Enc->m_upDPBManager->begin_frame(currentPicParams, bUsedAsReference); pD3D12Enc->m_upDPBManager->begin_frame(currentPicParams, bUsedAsReference, picture);
} }
bool bool
@ -415,6 +422,24 @@ d3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder
pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>(); pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>();
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
bool gopHasPFrames =
(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod > 0) &&
((pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.GOPLength == 0) ||
(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod <
pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.GOPLength));
pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_hevc>(
gopHasPFrames,
*pD3D12Enc->m_upDPBStorageManager,
// Max number of frames to be used as a reference, without counting the current recon picture
d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc)
);
pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_hevc>();
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -439,6 +464,18 @@ d3d12_video_encoder_get_current_slice_param_settings(struct d3d12_video_encoder
return subregionData; return subregionData;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {};
if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode !=
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) {
subregionData.pSlicesPartition_HEVC =
&pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC;
subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES);
}
return subregionData;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -459,6 +496,14 @@ d3d12_video_encoder_get_current_picture_param_settings(struct d3d12_video_encode
return curPicParamsData; return curPicParamsData;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
curPicParamsData.pHEVCPicData = &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_HEVCPicData;
curPicParamsData.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_HEVCPicData);
return curPicParamsData;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -530,6 +575,14 @@ d3d12_video_encoder_get_current_level_desc(struct d3d12_video_encoder *pD3D12Enc
return curLevelDesc; return curLevelDesc;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {};
curLevelDesc.pHEVCLevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting;
curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting);
return curLevelDesc;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -548,6 +601,12 @@ d3d12_video_encoder_build_codec_headers(struct d3d12_video_encoder *pD3D12Enc)
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
return d3d12_video_encoder_build_codec_headers_hevc(pD3D12Enc);
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -570,6 +629,15 @@ d3d12_video_encoder_get_current_gop_desc(struct d3d12_video_encoder *pD3D12Enc)
return curGOPDesc; return curGOPDesc;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {};
curGOPDesc.pHEVCGroupOfPictures =
&pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures);
return curGOPDesc;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -591,6 +659,15 @@ d3d12_video_encoder_get_current_codec_config_desc(struct d3d12_video_encoder *pD
return codecConfigDesc; return codecConfigDesc;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {};
codecConfigDesc.pHEVCConfig = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig;
codecConfigDesc.DataSize =
sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig);
return codecConfigDesc;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -607,6 +684,10 @@ d3d12_video_encoder_get_current_codec(struct d3d12_video_encoder *pD3D12Enc)
{ {
return D3D12_VIDEO_ENCODER_CODEC_H264; return D3D12_VIDEO_ENCODER_CODEC_H264;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
return D3D12_VIDEO_ENCODER_CODEC_HEVC;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -750,6 +831,18 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3
sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting); sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
capEncoderSupportData.SuggestedProfile.pHEVCProfile =
&pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile;
capEncoderSupportData.SuggestedProfile.DataSize =
sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
capEncoderSupportData.SuggestedLevel.pHEVCLevelSetting =
&pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting;
capEncoderSupportData.SuggestedLevel.DataSize =
sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting);
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -803,6 +896,14 @@ d3d12_video_encoder_get_current_profile_desc(struct d3d12_video_encoder *pD3D12E
return curProfDesc; return curProfDesc;
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {};
curProfDesc.pHEVCProfile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile;
curProfDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile);
return curProfDesc;
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");
@ -828,6 +929,11 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod
return d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTexture, picture); return d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTexture, picture);
} break; } break;
case PIPE_VIDEO_FORMAT_HEVC:
{
return d3d12_video_encoder_update_current_encoder_config_state_hevc(pD3D12Enc, srcTexture, picture);
} break;
default: default:
{ {
unreachable("Unsupported pipe_video_format"); unreachable("Unsupported pipe_video_format");

View file

@ -28,6 +28,7 @@
#include "d3d12_video_encoder_references_manager.h" #include "d3d12_video_encoder_references_manager.h"
#include "d3d12_video_dpb_storage_manager.h" #include "d3d12_video_dpb_storage_manager.h"
#include "d3d12_video_encoder_bitstream_builder_h264.h" #include "d3d12_video_encoder_bitstream_builder_h264.h"
#include "d3d12_video_encoder_bitstream_builder_hevc.h"
/// ///
/// Pipe video interface starts /// Pipe video interface starts
@ -161,6 +162,12 @@ struct d3d12_video_encoder
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC m_HEVCLevelSetting; D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC m_HEVCLevelSetting;
} m_encoderLevelSuggestedDesc = {}; } m_encoderLevelSuggestedDesc = {};
union
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 m_H264CodecCaps;
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC m_HEVCCodecCaps;
} m_encoderCodecSpecificConfigCaps = {};
// Required size for the layout-resolved metadata buffer of current frame to be encoded // Required size for the layout-resolved metadata buffer of current frame to be encoded
size_t m_resolvedLayoutMetadataBufferRequiredSize; size_t m_resolvedLayoutMetadataBufferRequiredSize;

View file

@ -120,7 +120,7 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps_id(); picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps_id();
picParams.pH264PicData->idr_pic_id = h264Pic->idr_pic_id; picParams.pH264PicData->idr_pic_id = h264Pic->idr_pic_id;
picParams.pH264PicData->FrameType = d3d12_video_encoder_convert_frame_type(h264Pic->picture_type); picParams.pH264PicData->FrameType = d3d12_video_encoder_convert_frame_type_h264(h264Pic->picture_type);
picParams.pH264PicData->PictureOrderCountNumber = h264Pic->pic_order_cnt; picParams.pH264PicData->PictureOrderCountNumber = h264Pic->pic_order_cnt;
picParams.pH264PicData->FrameDecodingOrderNumber = h264Pic->frame_num; picParams.pH264PicData->FrameDecodingOrderNumber = h264Pic->frame_num;
@ -141,7 +141,7 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
} }
D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type(enum pipe_h2645_enc_picture_type picType) d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)
{ {
switch (picType) { switch (picType) {
case PIPE_H2645_ENC_PICTURE_TYPE_P: case PIPE_H2645_ENC_PICTURE_TYPE_P:
@ -518,8 +518,10 @@ d3d12_video_encoder_update_h264_gop_configuration(struct d3d12_video_encoder *pD
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264
d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc, d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h264_enc_picture_desc *picture) pipe_h264_enc_picture_desc *picture,
bool &is_supported)
{ {
is_supported = true;
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 config = { D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 config = {
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE, D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_DIRECT_MODES_DISABLED, D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_DIRECT_MODES_DISABLED,
@ -530,6 +532,41 @@ d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING; config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
} }
pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps =
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_SLICES_DEBLOCKING_MODE_FLAG_NONE
};
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
D3D12_VIDEO_ENCODER_PROFILE_H264 prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(pD3D12Enc->base.profile);
capCodecConfigData.Profile.pH264Profile = &prof;
capCodecConfigData.Profile.DataSize = sizeof(prof);
capCodecConfigData.CodecSupportLimits.pH264Support = &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps;
capCodecConfigData.CodecSupportLimits.DataSize = sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_H264CodecCaps);
if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData))
|| !capCodecConfigData.IsSupported))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments not supported - DisableDeblockingFilterConfig (value %d) "
"not allowed by DisableDeblockingFilterSupportedModes 0x%x cap reporting.",
config.DisableDeblockingFilterConfig,
capCodecConfigData.CodecSupportLimits.pH264Support->DisableDeblockingFilterSupportedModes);
is_supported = false;
return config;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING) != 0)
&& ((capCodecConfigData.CodecSupportLimits.pH264Support->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264_FLAG_CABAC_ENCODING_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - CABAC encoding mode not supported."
" Ignoring the request for this feature flag on this encode session");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264_FLAG_ENABLE_CABAC_ENCODING;
}
return config; return config;
} }
@ -603,7 +640,12 @@ d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_
pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting = targetLevel; pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting = targetLevel;
// Set codec config // Set codec config
auto targetCodecConfig = d3d12_video_encoder_convert_h264_codec_configuration(pD3D12Enc, h264Pic); bool is_supported = false;
auto targetCodecConfig = d3d12_video_encoder_convert_h264_codec_configuration(pD3D12Enc, h264Pic, is_supported);
if (!is_supported) {
return false;
}
if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config, if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config,
&targetCodecConfig, &targetCodecConfig,
sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264)) != 0) { sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264)) != 0) {

View file

@ -46,7 +46,8 @@ D3D12_VIDEO_ENCODER_LEVELS_H264
d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel); d3d12_video_encoder_convert_level_h264(uint32_t h264SpecLevel);
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264
d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc, d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h264_enc_picture_desc *picture); pipe_h264_enc_picture_desc *picture,
bool &is_supported);
void void
d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder *pD3D12Enc, d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer * srcTexture, struct pipe_video_buffer * srcTexture,
@ -54,7 +55,7 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams, D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
bool &bUsedAsReference); bool &bUsedAsReference);
D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type(enum pipe_h2645_enc_picture_type picType); d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType);
uint32_t uint32_t
d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc); d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc);
bool bool

View file

@ -0,0 +1,768 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_video_enc.h"
#include "d3d12_video_enc_hevc.h"
#include "util/u_video.h"
#include "d3d12_screen.h"
#include "d3d12_format.h"
#include <cmath>
void
d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture)
{
auto previousConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc = {};
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Numerator =
picture->rc.frame_rate_num;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Denominator =
picture->rc.frame_rate_den;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
switch (picture->rc.rate_ctrl_method) {
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
{
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.TargetAvgBitRate =
picture->rc.target_bitrate;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.PeakBitRate =
picture->rc.peak_bitrate;
} break;
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
{
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate =
picture->rc.target_bitrate;
/* For CBR mode, to guarantee bitrate of generated stream complies with
* target bitrate (e.g. no over +/-10%), vbv_buffer_size should be same
* as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
*/
if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
", forcing VBV Size = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate/2);
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate/2;
}
} break;
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
{
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_FullIntracodedFrame = picture->rc.quant_i_frames;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_InterPredictedFrame_PrevRefOnly = picture->rc.quant_p_frames;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_InterPredictedFrame_BiDirectionalRef = picture->rc.quant_b_frames;
} break;
default:
{
debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc invalid RC "
"config, using default RC CQP mode\n");
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_FullIntracodedFrame = 30;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
.ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
} break;
}
if (memcmp(&previousConfig,
&pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc,
sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc)) != 0) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_rate_control;
}
}
void
d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer *srcTexture,
struct pipe_picture_desc *picture,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
bool &bUsedAsReference)
{
struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
assert(pHEVCBitstreamBuilder != nullptr);
bUsedAsReference = !hevcPic->not_referenced;
picParams.pHEVCPicData->slice_pic_parameter_set_id = pHEVCBitstreamBuilder->get_active_pps_id();
picParams.pHEVCPicData->FrameType = d3d12_video_encoder_convert_frame_type_hevc(hevcPic->picture_type);
picParams.pHEVCPicData->PictureOrderCountNumber = hevcPic->pic_order_cnt;
picParams.pHEVCPicData->List0ReferenceFramesCount = 0;
picParams.pHEVCPicData->pList0ReferenceFrames = nullptr;
picParams.pHEVCPicData->List1ReferenceFramesCount = 0;
picParams.pHEVCPicData->pList1ReferenceFrames = nullptr;
if (picParams.pHEVCPicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) {
picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
picParams.pHEVCPicData->pList0ReferenceFrames = hevcPic->ref_idx_l0_list;
} else if (picParams.pHEVCPicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME) {
picParams.pHEVCPicData->List0ReferenceFramesCount = hevcPic->num_ref_idx_l0_active_minus1 + 1;
picParams.pHEVCPicData->pList0ReferenceFrames = hevcPic->ref_idx_l0_list;
picParams.pHEVCPicData->List1ReferenceFramesCount = hevcPic->num_ref_idx_l1_active_minus1 + 1;
picParams.pHEVCPicData->pList1ReferenceFrames = hevcPic->ref_idx_l1_list;
}
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.ConfigurationFlags
& D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES;
}
D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC
d3d12_video_encoder_convert_frame_type_hevc(enum pipe_h2645_enc_picture_type picType)
{
switch (picType) {
case PIPE_H2645_ENC_PICTURE_TYPE_P:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_B:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_I:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_I_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME;
} break;
default:
{
unreachable("Unsupported pipe_h2645_enc_picture_type");
} break;
}
}
///
/// Tries to configurate the encoder using the requested slice configuration
/// or falls back to single slice encoding.
///
bool
d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture)
{
///
/// Initialize single slice by default
///
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES requestedSlicesConfig = {};
requestedSlicesConfig.NumberOfSlicesPerFrame = 1;
///
/// Try to see if can accomodate for multi-slice request by user
///
if (picture->num_slice_descriptors > 1) {
/* Last slice can be less for rounding frame size and leave some error for mb rounding */
bool bUniformSizeSlices = true;
const double rounding_delta = 1.0;
for (uint32_t sliceIdx = 1; (sliceIdx < picture->num_slice_descriptors - 1) && bUniformSizeSlices; sliceIdx++) {
int64_t curSlice = picture->slices_descriptors[sliceIdx].num_ctu_in_slice;
int64_t prevSlice = picture->slices_descriptors[sliceIdx - 1].num_ctu_in_slice;
bUniformSizeSlices = bUniformSizeSlices && (std::abs(curSlice - prevSlice) <= rounding_delta);
}
uint32_t subregion_block_pixel_size = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize;
uint32_t num_subregions_per_scanline =
pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width / subregion_block_pixel_size;
/* m_currentResolutionSupportCaps.SubregionBlockPixelsSize can be a multiple of MinCUSize to accomodate for HW requirements
So, if the allowed subregion (slice) pixel size partition is bigger (a multiple) than the CTU size, we have to adjust
num_subregions_per_slice by this factor respect from slices_descriptors[X].num_ctu_in_slice
*/
/* This assert should always be true according to the spec
https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#3150-struct-d3d12_feature_data_video_encoder_resolution_support_limits
*/
uint8_t minCUSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig.MinLumaCodingUnitSize);
assert((pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize
% minCUSize) == 0);
uint32_t subregionsize_to_ctu_factor = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize /
minCUSize;
uint32_t num_subregions_per_slice = picture->slices_descriptors[0].num_ctu_in_slice / (subregionsize_to_ctu_factor*subregionsize_to_ctu_factor);
bool bSliceAligned = ((num_subregions_per_slice % num_subregions_per_scanline) == 0);
if (!bUniformSizeSlices &&
d3d12_video_encoder_check_subregion_mode_support(
pD3D12Enc,
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
if (D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG) { // Check if fallback mode is enabled, or we should just fail
// without support
// Not supported to have custom slice sizes in D3D12 Video Encode fallback to uniform multi-slice
debug_printf(
"[d3d12_video_encoder_hevc] WARNING: Requested slice control mode is not supported: All slices must "
"have the same number of macroblocks. Falling back to encoding uniform %d slices per frame.\n",
picture->num_slice_descriptors);
requestedSlicesMode =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
"D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
"with %d slices per frame.\n",
requestedSlicesConfig.NumberOfSlicesPerFrame);
} else {
debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
"have the same number of macroblocks. To continue with uniform slices as a fallback, must "
"enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG");
return false;
}
} else if (bUniformSizeSlices && bSliceAligned &&
d3d12_video_encoder_check_subregion_mode_support(
pD3D12Enc,
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION)) {
// Number of subregion block per slice is aligned to a scanline width, in which case we can
// use D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION
requestedSlicesMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
requestedSlicesConfig.NumberOfRowsPerSlice = (num_subregions_per_slice / num_subregions_per_scanline);
debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
"D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION with "
"%d subregion block rows (%d pix scanlines) per slice.\n",
requestedSlicesConfig.NumberOfRowsPerSlice,
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
} else if (bUniformSizeSlices &&
d3d12_video_encoder_check_subregion_mode_support(
pD3D12Enc,
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME)) {
requestedSlicesMode =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
requestedSlicesConfig.NumberOfSlicesPerFrame = picture->num_slice_descriptors;
debug_printf("[d3d12_video_encoder_hevc] Using multi slice encoding mode: "
"D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME "
"with %d slices per frame.\n",
requestedSlicesConfig.NumberOfSlicesPerFrame);
} else if (D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG) { // Check if fallback mode is enabled, or we should just fail
// without support
// Fallback to single slice encoding (assigned by default when initializing variables requestedSlicesMode,
// requestedSlicesConfig)
debug_printf(
"[d3d12_video_encoder_hevc] WARNING: Slice mode for %d slices with bUniformSizeSlices: %d - bSliceAligned "
"%d not supported by the D3D12 driver, falling back to encoding a single slice per frame.\n",
picture->num_slice_descriptors,
bUniformSizeSlices,
bSliceAligned);
} else {
debug_printf("[d3d12_video_encoder_hevc] Requested slice control mode is not supported: All slices must "
"have the same number of macroblocks. To continue with uniform slices as a fallback, must "
"enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_SLICE_CONFIG\n");
return false;
}
}
if (!d3d12_video_encoder_isequal_slice_config_hevc(
pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
requestedSlicesMode,
requestedSlicesConfig)) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC = requestedSlicesConfig;
pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedSlicesMode;
return true;
}
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture)
{
return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
}
bool
d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture)
{
// Only update GOP when it begins
// This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
if (picture->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) {
uint32_t GOPLength = picture->seq.intra_period;
uint32_t PPicturePeriod = picture->seq.ip_period;
const uint32_t max_pic_order_cnt_lsb = MAX2(16, util_next_power_of_two(GOPLength));
double log2_max_pic_order_cnt_lsb_minus4 = std::max(0.0, std::ceil(std::log2(max_pic_order_cnt_lsb)) - 4);
assert(log2_max_pic_order_cnt_lsb_minus4 < UCHAR_MAX);
// Set dirty flag if m_HEVCGroupOfPictures changed
auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures = {
GOPLength,
PPicturePeriod,
static_cast<uint8_t>(log2_max_pic_order_cnt_lsb_minus4)
};
if (memcmp(&previousGOPConfig,
&pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC)) != 0) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
}
}
return true;
}
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC
d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture,
bool&is_supported)
{
is_supported = true;
uint32_t min_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3));
uint32_t max_cu_size = (1 << (picture->seq.log2_min_luma_coding_block_size_minus3 + 3 + picture->seq.log2_diff_max_min_luma_coding_block_size));
uint32_t min_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2));
uint32_t max_tu_size = (1 << (picture->seq.log2_min_transform_block_size_minus2 + 2 + picture->seq.log2_diff_max_min_transform_block_size));
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC config = {
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE,
d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(min_cu_size),
d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(max_cu_size),
d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(min_tu_size),
d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(max_tu_size),
picture->seq.max_transform_hierarchy_depth_inter,
picture->seq.max_transform_hierarchy_depth_intra,
};
pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps =
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
config.MinLumaCodingUnitSize,
config.MaxLumaCodingUnitSize,
config.MinLumaTransformUnitSize,
config.MaxLumaTransformUnitSize,
config.max_transform_hierarchy_depth_inter,
config.max_transform_hierarchy_depth_intra
};
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
D3D12_VIDEO_ENCODER_PROFILE_HEVC prof = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
capCodecConfigData.Profile.pHEVCProfile = &prof;
capCodecConfigData.Profile.DataSize = sizeof(prof);
capCodecConfigData.CodecSupportLimits.pHEVCSupport = &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps;
capCodecConfigData.CodecSupportLimits.DataSize = sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps);
if(FAILED(pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData))
|| !capCodecConfigData.IsSupported))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - "
"Call to CheckFeatureCaps (D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, ...) returned failure "
"or not supported for Codec HEVC - MinLumaSize %d - MaxLumaSize %d - MinTransformSize %d - "
"MaxTransformSize %d - Depth_inter %d - Depth intra %d\n",
config.MinLumaCodingUnitSize,
config.MaxLumaCodingUnitSize,
config.MinLumaTransformUnitSize,
config.MaxLumaTransformUnitSize,
config.max_transform_hierarchy_depth_inter,
config.max_transform_hierarchy_depth_intra);
is_supported = false;
return config;
}
if (picture->seq.amp_enabled_flag)
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
if (picture->seq.sample_adaptive_offset_enabled_flag)
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
if (picture->pic.pps_loop_filter_across_slices_enabled_flag)
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
if (picture->pic.transform_skip_enabled_flag)
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
if (picture->pic.constrained_intra_pred_flag)
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_DISABLING_LOOP_FILTER_ACROSS_SLICES_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Disable deblocking across slice boundary mode not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_INTRA_SLICE_CONSTRAINED_ENCODING_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Intra slice constrained mode not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - SAO Filter mode not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) == 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Asymetric motion partition is required to be set."
" Enabling this HW required feature flag on this encode session\n");
// HW doesn't support otherwise, so set it
config.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Allow transform skipping is not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING;
}
if(((config.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0)
&& ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) == 0))
{
debug_printf("D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION arguments are not supported - Constrained intra-prediction use is not supported."
" Ignoring the request for this feature flag on this encode session\n");
// Disable it and keep going with a warning
config.ConfigurationFlags &= ~D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION;
}
return config;
}
bool
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer *srcTexture,
struct pipe_picture_desc *picture)
{
struct pipe_h265_enc_picture_desc *hevcPic = (struct pipe_h265_enc_picture_desc *) picture;
// Reset reconfig dirty flags
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
// Reset sequence changes flags
pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
// Set codec
if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_HEVC) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_HEVC;
// Set input format
DXGI_FORMAT targetFmt = d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile);
if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
}
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
&pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
if (FAILED(hr)) {
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
return false;
}
// Set resolution
if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTexture->width) ||
(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTexture->height)) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
}
pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTexture->width;
pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTexture->height;
// Set resolution codec dimensions (ie. cropping)
memset(&pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig, 0,
sizeof(pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig));
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.front = hevcPic->seq.pic_width_in_luma_samples;
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.back = hevcPic->seq.pic_height_in_luma_samples;
if (hevcPic->seq.conformance_window_flag) {
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.left = hevcPic->seq.conf_win_left_offset;
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = hevcPic->seq.conf_win_right_offset;
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.top = hevcPic->seq.conf_win_top_offset;
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom = hevcPic->seq.conf_win_bottom_offset;
}
// Set profile
auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(pD3D12Enc->base.profile);
if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile != targetProfile) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile = targetProfile;
// Set level
auto targetLevel = d3d12_video_encoder_convert_level_hevc(hevcPic->seq.general_level_idc);
auto targetTier = (hevcPic->seq.general_tier_flag == 0) ? D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH;
if ( (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level != targetLevel)
|| (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier != targetTier)) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier = targetTier;
pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level = targetLevel;
// Set codec config
bool is_supported = true;
auto targetCodecConfig = d3d12_video_encoder_convert_hevc_codec_configuration(pD3D12Enc, hevcPic, is_supported);
if(!is_supported) {
return false;
}
if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig,
&targetCodecConfig,
sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC)) != 0) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig = targetCodecConfig;
// Set rate control
d3d12_video_encoder_update_current_rate_control_hevc(pD3D12Enc, hevcPic);
///
/// Check for video encode support detailed capabilities
///
// Will call for d3d12 driver support based on the initial requested features, then
// try to fallback if any of them is not supported and return the negotiated d3d12 settings
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData)) {
debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT "
"arguments are not supported - "
"ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
capEncoderSupportData.ValidationFlags,
capEncoderSupportData.SupportFlags);
return false;
}
///
// Calculate current settings based on the returned values from the caps query
//
pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput =
d3d12_video_encoder_calculate_max_slices_count_in_output(
pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
&pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC,
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize);
// Set slices config
if(!d3d12_video_encoder_negotiate_current_hevc_slices_configuration(pD3D12Enc, hevcPic)) {
debug_printf("d3d12_video_encoder_negotiate_current_hevc_slices_configuration failed!\n");
return false;
}
// Set GOP config
if(!d3d12_video_encoder_update_hevc_gop_configuration(pD3D12Enc, hevcPic)) {
debug_printf("d3d12_video_encoder_update_hevc_gop_configuration failed!\n");
return false;
}
// m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
// after re-allocating objects if needed
// Set motion estimation config
auto targetMotionLimit = d3d12_video_encoder_convert_hevc_motion_configuration(pD3D12Enc, hevcPic);
if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
}
pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
//
// Validate caps support returned values against current settings
//
if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile !=
pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile) {
debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_HEVC by upper layer: %d "
"mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_HEVC: %d\n",
pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile,
pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
}
if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier !=
pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier) {
debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier by upper layer: %d "
"mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Tier: %d\n",
pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Tier,
pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Tier);
}
if (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level !=
pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level) {
debug_printf("[d3d12_video_encoder_hevc] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level by upper layer: %d "
"mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_HEVC.Level: %d\n",
pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting.Level,
pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting.Level);
}
if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
debug_printf("[d3d12_video_encoder_hevc] Desired number of subregions is not supported (higher than max "
"reported slice number in query caps)\n.");
return false;
}
return true;
}
D3D12_VIDEO_ENCODER_PROFILE_HEVC
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile)
{
switch (profile) {
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
{
return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
} break;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
{
return D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10;
} break;
default:
{
unreachable("Unsupported pipe_video_profile");
} break;
}
}
bool
d3d12_video_encoder_isequal_slice_config_hevc(
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig)
{
return (targetMode == otherMode) &&
(memcmp(&targetConfig,
&otherConfig,
sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES)) == 0);
}
uint32_t
d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder *pD3D12Enc)
{
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
auto profDesc = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
auto levelDesc = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
auto codecConfigDesc = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
auto MaxDPBCapacity = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
size_t writtenSPSBytesCount = 0;
size_t writtenVPSBytesCount = 0;
bool isFirstFrame = (pD3D12Enc->m_fenceValue == 1);
bool writeNewSPS = isFirstFrame // on first frame
|| ((pD3D12Enc->m_currentEncodeConfig.m_seqFlags & // also on resolution change
D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0);
d3d12_video_bitstream_builder_hevc *pHEVCBitstreamBuilder =
static_cast<d3d12_video_bitstream_builder_hevc *>(pD3D12Enc->m_upBitstreamBuilder.get());
assert(pHEVCBitstreamBuilder);
uint32_t active_seq_parameter_set_id = pHEVCBitstreamBuilder->get_active_sps_id();
uint32_t active_video_parameter_set_id = pHEVCBitstreamBuilder->get_active_vps_id();
bool writeNewVPS = isFirstFrame;
if (writeNewVPS) {
bool gopHasBFrames = (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures.PPicturePeriod > 1);
pHEVCBitstreamBuilder->build_vps(*profDesc.pHEVCProfile,
*levelDesc.pHEVCLevelSetting,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
MaxDPBCapacity, // max_num_ref_frames
gopHasBFrames,
active_video_parameter_set_id,
pD3D12Enc->m_BitstreamHeadersBuffer,
pD3D12Enc->m_BitstreamHeadersBuffer.begin(),
writtenVPSBytesCount);
}
if (writeNewSPS) {
// For every new SPS for reconfiguration, increase the active_sps_id
if (!isFirstFrame) {
active_seq_parameter_set_id++;
pHEVCBitstreamBuilder->set_active_sps_id(active_seq_parameter_set_id);
}
pHEVCBitstreamBuilder->build_sps(
pHEVCBitstreamBuilder->get_latest_vps(),
active_seq_parameter_set_id,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig,
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.SubregionBlockPixelsSize,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
*codecConfigDesc.pHEVCConfig,
pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures,
pD3D12Enc->m_BitstreamHeadersBuffer,
pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenVPSBytesCount,
writtenSPSBytesCount);
}
size_t writtenPPSBytesCount = 0;
pHEVCBitstreamBuilder->build_pps(pHEVCBitstreamBuilder->get_latest_sps(),
currentPicParams.pHEVCPicData->slice_pic_parameter_set_id,
*codecConfigDesc.pHEVCConfig,
*currentPicParams.pHEVCPicData,
pD3D12Enc->m_BitstreamHeadersBuffer,
pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenSPSBytesCount + writtenVPSBytesCount,
writtenPPSBytesCount);
// Shrink buffer to fit the headers
if (pD3D12Enc->m_BitstreamHeadersBuffer.size() > (writtenPPSBytesCount + writtenSPSBytesCount + writtenVPSBytesCount)) {
pD3D12Enc->m_BitstreamHeadersBuffer.resize(writtenPPSBytesCount + writtenSPSBytesCount + writtenVPSBytesCount);
}
return pD3D12Enc->m_BitstreamHeadersBuffer.size();
}

View file

@ -0,0 +1,68 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_ENC_HEVC_H
#define D3D12_VIDEO_ENC_HEVC_H
#include "d3d12_video_types.h"
bool
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer * srcTexture,
struct pipe_picture_desc * picture);
void
d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture);
bool
d3d12_video_encoder_negotiate_current_hevc_slices_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture);
bool
d3d12_video_encoder_update_hevc_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture);
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
d3d12_video_encoder_convert_hevc_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture);
D3D12_VIDEO_ENCODER_LEVELS_HEVC
d3d12_video_encoder_convert_level_hevc(uint32_t hevcSpecLevel);
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC
d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
pipe_h265_enc_picture_desc *picture,
bool &is_supported);
void
d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer * srcTexture,
struct pipe_picture_desc * picture,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
bool &bUsedAsReference);
D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC
d3d12_video_encoder_convert_frame_type_hevc(enum pipe_h2645_enc_picture_type picType);
uint32_t
d3d12_video_encoder_build_codec_headers_hevc(struct d3d12_video_encoder *pD3D12Enc);
bool
d3d12_video_encoder_isequal_slice_config_hevc(
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE targetMode,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES targetConfig,
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE otherMode,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES otherConfig);
#endif

View file

@ -0,0 +1,732 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_video_encoder_bitstream_builder_hevc.h"
#include <cmath>
static uint8_t
convert_profile12_to_stdprofile(D3D12_VIDEO_ENCODER_PROFILE_HEVC profile)
{
// Main is 1, Main10 is 2, one more than the D3D12 enum definition
return static_cast<uint8_t>(profile) + 1u;
}
void
d3d12_video_bitstream_builder_hevc::init_profile_tier_level(HEVCProfileTierLevel *ptl,
uint8_t HEVCProfileIdc,
uint8_t HEVCLevelIdc,
bool isHighTier)
{
memset(ptl, 0, sizeof(HEVCProfileTierLevel));
ptl->general_profile_space = 0; // must be 0
ptl->general_tier_flag = isHighTier ? 1 : 0;
ptl->general_profile_idc = HEVCProfileIdc;
memset(ptl->general_profile_compatibility_flag, 0, sizeof(ptl->general_profile_compatibility_flag));
ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1;
ptl->general_progressive_source_flag = 1; // yes
ptl->general_interlaced_source_flag = 0; // no
ptl->general_non_packed_constraint_flag = 1; // no frame packing arrangement SEI messages
ptl->general_frame_only_constraint_flag = 1;
ptl->general_level_idc = HEVCLevelIdc;
}
void
d3d12_video_encoder_convert_from_d3d12_level_hevc(D3D12_VIDEO_ENCODER_LEVELS_HEVC level12,
uint32_t &specLevel)
{
specLevel = 3u;
switch(level12)
{
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_1:
{
specLevel *= 10;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_2:
{
specLevel *= 20;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_21:
{
specLevel *= 21;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_3:
{
specLevel *= 30;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_31:
{
specLevel *= 31;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_4:
{
specLevel *= 40;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_41:
{
specLevel *= 41;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_5:
{
specLevel *= 50;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_51:
{
specLevel *= 51;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_52:
{
specLevel *= 52;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_6 :
{
specLevel *= 60;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_61 :
{
specLevel *= 61;
} break;
case D3D12_VIDEO_ENCODER_LEVELS_HEVC_62 :
{
specLevel *= 62;
} break;
default:
{
unreachable("Unsupported D3D12_VIDEO_ENCODER_LEVELS_HEVC value");
} break;
}
}
D3D12_VIDEO_ENCODER_LEVELS_HEVC
d3d12_video_encoder_convert_level_hevc(uint32_t hevcSpecLevel)
{
hevcSpecLevel = hevcSpecLevel / 3u;
switch(hevcSpecLevel)
{
case 10:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_1;
} break;
case 20:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_2;
} break;
case 21:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_21;
} break;
case 30:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_3;
} break;
case 31:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_31;
} break;
case 40:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_4;
} break;
case 41:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_41;
} break;
case 50:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_5;
} break;
case 51:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_51;
} break;
case 52:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_52;
} break;
case 60:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_6;
} break;
case 61:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_61;
} break;
case 62:
{
return D3D12_VIDEO_ENCODER_LEVELS_HEVC_62;
} break;
default:
{
unreachable("Unsupported D3D12_VIDEO_ENCODER_LEVELS_HEVC value");
} break;
}
}
uint8_t
d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE& cuSize)
{
switch(cuSize)
{
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8:
{
return 8u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_16x16:
{
return 16u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32:
{
return 32u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64:
{
return 64u;
} break;
default:
{
unreachable(L"Not a supported cu size");
return 0u;
} break;
}
}
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE
d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(const uint32_t& cuSize)
{
switch(cuSize)
{
case 8u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8;
} break;
case 16u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_16x16;
} break;
case 32u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32;
} break;
case 64u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64;
} break;
default:
{
unreachable(L"Not a supported cu size");
} break;
}
}
uint8_t
d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE& TUSize)
{
switch(TUSize)
{
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4:
{
return 4u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_8x8:
{
return 8u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_16x16:
{
return 16u;
} break;
case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32:
{
return 32u;
} break;
default:
{
unreachable(L"Not a supported TU size");
} break;
}
}
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE
d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(const uint32_t& TUSize)
{
switch(TUSize)
{
case 4u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4;
} break;
case 8u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_8x8;
} break;
case 16u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_16x16;
} break;
case 32u:
{
return D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32;
} break;
default:
{
unreachable(L"Not a supported TU size");
} break;
}
}
void
d3d12_video_bitstream_builder_hevc::build_vps(const D3D12_VIDEO_ENCODER_PROFILE_HEVC& profile,
const D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC& level,
const DXGI_FORMAT inputFmt,
uint8_t maxRefFrames,
bool gopHasBFrames,
uint8_t vps_video_parameter_set_id,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcVideoParameterSet* pVPSStruct)
{
uint8_t HEVCProfileIdc = convert_profile12_to_stdprofile(profile);
uint32_t HEVCLevelIdc = 0u;
d3d12_video_encoder_convert_from_d3d12_level_hevc(level.Level, HEVCLevelIdc);
bool isHighTier = (level.Tier == D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH);
memset(&m_latest_vps, 0, sizeof(HevcVideoParameterSet));
m_latest_vps.nalu = {
// forbidden_zero_bit
0u,
// nal_unit_type
HEVC_NALU_VPS_NUT,
// nuh_layer_id
0u,
// nuh_temporal_id_plus1
1u
};
m_latest_vps.vps_video_parameter_set_id = vps_video_parameter_set_id,
m_latest_vps.vps_reserved_three_2bits = 3u;
m_latest_vps.vps_max_layers_minus1 = 0u;
m_latest_vps.vps_max_sub_layers_minus1 = 0u;
m_latest_vps.vps_temporal_id_nesting_flag = 1u;
m_latest_vps.vps_reserved_0xffff_16bits = 0xFFFF;
init_profile_tier_level(&m_latest_vps.ptl, HEVCProfileIdc, HEVCLevelIdc, isHighTier);
m_latest_vps.vps_sub_layer_ordering_info_present_flag = 0u;
for (int i = (m_latest_vps.vps_sub_layer_ordering_info_present_flag ? 0 : m_latest_vps.vps_max_sub_layers_minus1); i <= m_latest_vps.vps_max_sub_layers_minus1; i++) {
m_latest_vps.vps_max_dec_pic_buffering_minus1[i] = (maxRefFrames/*previous reference frames*/ + 1 /*additional current frame recon pic*/) - 1/**minus1 for header*/;
m_latest_vps.vps_max_num_reorder_pics[i] = gopHasBFrames ? m_latest_vps.vps_max_dec_pic_buffering_minus1[i] : 0;
m_latest_vps.vps_max_latency_increase_plus1[i] = 0; // When vps_max_latency_increase_plus1[ i ] is equal to 0, no corresponding limit is expressed.
}
// Print built VPS structure
debug_printf("[HEVCBitstreamBuilder] HevcVideoParameterSet Structure generated before writing to bitstream:\n");
print_vps(m_latest_vps);
m_hevcEncoder.vps_to_nalu_bytes(&m_latest_vps, headerBitstream, placingPositionStart, writtenBytes);
if(pVPSStruct != nullptr)
{
*pVPSStruct = m_latest_vps;
}
}
void
d3d12_video_bitstream_builder_hevc::build_sps(const HevcVideoParameterSet& parentVPS,
uint8_t seq_parameter_set_id,
const D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& encodeResolution,
const D3D12_BOX& crop_window_upper_layer,
const UINT picDimensionMultipleRequirement,
const DXGI_FORMAT& inputFmt,
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC& codecConfig,
const D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC& hevcGOP,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcSeqParameterSet* outputSPS)
{
memset(&m_latest_sps, 0, sizeof(HevcSeqParameterSet));
// In case is 420 10 bits
if(inputFmt == DXGI_FORMAT_P010)
{
m_latest_sps.bit_depth_luma_minus8 = 2;
m_latest_sps.bit_depth_chroma_minus8 = 2;
}
uint8_t minCuSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(codecConfig.MinLumaCodingUnitSize);
uint8_t maxCuSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(codecConfig.MaxLumaCodingUnitSize);
uint8_t minTuSize = d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(codecConfig.MinLumaTransformUnitSize);
uint8_t maxTuSize = d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(codecConfig.MaxLumaTransformUnitSize);
m_latest_sps.nalu.nal_unit_type = HEVC_NALU_SPS_NUT;
m_latest_sps.nalu.nuh_temporal_id_plus1 = 1;
m_latest_sps.sps_seq_parameter_set_id = seq_parameter_set_id;
m_latest_sps.sps_max_sub_layers_minus1 = parentVPS.vps_max_sub_layers_minus1;
m_latest_sps.sps_temporal_id_nesting_flag = parentVPS.vps_temporal_id_nesting_flag;
// inherit PTL from parentVPS fully
m_latest_sps.ptl = parentVPS.ptl;
m_latest_sps.chroma_format_idc = 1; // 420
// Codec spec dictates pic_width/height_in_luma_samples must be divisible by minCuSize but HW might have higher req pow 2 multiples
assert((picDimensionMultipleRequirement % minCuSize) == 0u);
// upper layer passes the viewport, can calculate the difference between it and pic_width_in_luma_samples
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC viewport = { };
viewport.Width = crop_window_upper_layer.front /* passes height */ - ((crop_window_upper_layer.left + crop_window_upper_layer.right) << 1);
viewport.Height = crop_window_upper_layer.back /* passes width */- ((crop_window_upper_layer.top + crop_window_upper_layer.bottom) << 1);
m_latest_sps.pic_width_in_luma_samples = ALIGN(encodeResolution.Width, picDimensionMultipleRequirement);
m_latest_sps.pic_height_in_luma_samples = ALIGN(encodeResolution.Height, picDimensionMultipleRequirement);
m_latest_sps.conf_win_right_offset = (m_latest_sps.pic_width_in_luma_samples - viewport.Width) >> 1;
m_latest_sps.conf_win_bottom_offset = (m_latest_sps.pic_height_in_luma_samples - viewport.Height) >> 1;
m_latest_sps.conformance_window_flag = m_latest_sps.conf_win_left_offset || m_latest_sps.conf_win_right_offset || m_latest_sps.conf_win_top_offset || m_latest_sps.conf_win_bottom_offset;
m_latest_sps.log2_max_pic_order_cnt_lsb_minus4 = hevcGOP.log2_max_pic_order_cnt_lsb_minus4;
m_latest_sps.maxPicOrderCntLsb = 1 << (m_latest_sps.log2_max_pic_order_cnt_lsb_minus4 + 4);
m_latest_sps.sps_sub_layer_ordering_info_present_flag = parentVPS.vps_sub_layer_ordering_info_present_flag;
for (int i = (m_latest_sps.sps_sub_layer_ordering_info_present_flag ? 0 : m_latest_sps.sps_max_sub_layers_minus1); i <= m_latest_sps.sps_max_sub_layers_minus1; i++) {
m_latest_sps.sps_max_dec_pic_buffering_minus1[i] = parentVPS.vps_max_dec_pic_buffering_minus1[i];
m_latest_sps.sps_max_num_reorder_pics[i] = parentVPS.vps_max_num_reorder_pics[i];
m_latest_sps.sps_max_latency_increase_plus1[i] = parentVPS.vps_max_latency_increase_plus1[i];
}
m_latest_sps.log2_min_luma_coding_block_size_minus3 = static_cast<uint8_t>(std::log2(minCuSize) - 3);
m_latest_sps.log2_diff_max_min_luma_coding_block_size = static_cast<uint8_t>(std::log2(maxCuSize) - std::log2(minCuSize));
m_latest_sps.log2_min_transform_block_size_minus2 = static_cast<uint8_t>(std::log2(minTuSize) - 2);
m_latest_sps.log2_diff_max_min_transform_block_size = static_cast<uint8_t>(std::log2(maxTuSize) - std::log2(minTuSize));
m_latest_sps.max_transform_hierarchy_depth_inter = codecConfig.max_transform_hierarchy_depth_inter;
m_latest_sps.max_transform_hierarchy_depth_intra = codecConfig.max_transform_hierarchy_depth_intra;
m_latest_sps.scaling_list_enabled_flag = 0;
m_latest_sps.amp_enabled_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION) != 0) ? 1u : 0u;
m_latest_sps.sample_adaptive_offset_enabled_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER) != 0) ? 1u : 0u;
m_latest_sps.pcm_enabled_flag = 0;
m_latest_sps.num_short_term_ref_pic_sets = 0;
m_latest_sps.long_term_ref_pics_present_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_LONG_TERM_REFERENCES) != 0) ? 1u : 0u;
m_latest_sps.num_long_term_ref_pics_sps = 0; // signal through slice header for now
m_latest_sps.sps_temporal_mvp_enabled_flag = 0;
m_latest_sps.strong_intra_smoothing_enabled_flag = 0;
m_latest_sps.vui_parameters_present_flag = 0;
m_latest_sps.sps_extension_flag = 0;
// Print built SPS structure
debug_printf("[HEVCBitstreamBuilder] HevcSeqParameterSet Structure generated before writing to bitstream:\n");
print_sps(m_latest_sps);
m_hevcEncoder.sps_to_nalu_bytes(&m_latest_sps, headerBitstream, placingPositionStart, writtenBytes);
if(outputSPS != nullptr)
{
*outputSPS = m_latest_sps;
}
}
void
d3d12_video_bitstream_builder_hevc::build_pps(const HevcSeqParameterSet& parentSPS,
uint8_t pic_parameter_set_id,
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC& codecConfig,
const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC& pictureControl,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcPicParameterSet* outputPPS)
{
memset(&m_latest_pps, 0, sizeof(HevcPicParameterSet));
m_latest_pps.nalu.nal_unit_type = HEVC_NALU_PPS_NUT;
m_latest_pps.nalu.nuh_temporal_id_plus1 = 1;
m_latest_pps.pps_pic_parameter_set_id = pic_parameter_set_id;
m_latest_pps.pps_seq_parameter_set_id = parentSPS.sps_seq_parameter_set_id;
m_latest_pps.weighted_pred_flag = 0u; // no weighted prediction in D3D12
m_latest_pps.num_ref_idx_lx_default_active_minus1[0] = static_cast<uint8_t>(std::max(static_cast<INT>(pictureControl.List0ReferenceFramesCount) - 1, 0));
m_latest_pps.num_ref_idx_lx_default_active_minus1[1] = static_cast<uint8_t>(std::max(static_cast<INT>(pictureControl.List1ReferenceFramesCount) - 1, 0));
m_latest_pps.num_tile_columns_minus1 = 0u; // no tiling in D3D12
m_latest_pps.num_tile_rows_minus1 = 0u; // no tiling in D3D12
m_latest_pps.tiles_enabled_flag = 0u; // no tiling in D3D12
m_latest_pps.loop_filter_across_tiles_enabled_flag = 0;
m_latest_pps.lists_modification_present_flag = 0;
m_latest_pps.log2_parallel_merge_level_minus2 = 0;
m_latest_pps.deblocking_filter_control_present_flag = 1;
m_latest_pps.deblocking_filter_override_enabled_flag = 0;
m_latest_pps.pps_deblocking_filter_disabled_flag = 0;
m_latest_pps.pps_scaling_list_data_present_flag = 0;
m_latest_pps.pps_beta_offset_div2 = 0;
m_latest_pps.pps_tc_offset_div2 = 0;
m_latest_pps.pps_loop_filter_across_slices_enabled_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES) != 0) ? 0 : 1;
m_latest_pps.transform_skip_enabled_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING) != 0) ? 1 : 0;
m_latest_pps.constrained_intra_pred_flag = ((codecConfig.ConfigurationFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_CONSTRAINED_INTRAPREDICTION) != 0) ? 1 : 0;
m_latest_pps.cabac_init_present_flag = 1;
m_latest_pps.pps_slice_chroma_qp_offsets_present_flag = 1;
m_latest_pps.cu_qp_delta_enabled_flag = 1;
// Print built PPS structure
debug_printf("[HEVCBitstreamBuilder] HevcPicParameterSet Structure generated before writing to bitstream:\n");
print_pps(m_latest_pps);
m_hevcEncoder.pps_to_nalu_bytes(&m_latest_pps, headerBitstream, placingPositionStart, writtenBytes);
if(outputPPS != nullptr)
{
*outputPPS = m_latest_pps;
}
}
void
d3d12_video_bitstream_builder_hevc::write_end_of_stream_nalu(std::vector<uint8_t> & headerBitstream,
std::vector<uint8_t>::iterator placingPositionStart,
size_t & writtenBytes)
{
m_hevcEncoder.write_end_of_stream_nalu(headerBitstream, placingPositionStart, writtenBytes);
}
void
d3d12_video_bitstream_builder_hevc::write_end_of_sequence_nalu(std::vector<uint8_t> & headerBitstream,
std::vector<uint8_t>::iterator placingPositionStart,
size_t & writtenBytes)
{
m_hevcEncoder.write_end_of_sequence_nalu(headerBitstream, placingPositionStart, writtenBytes);
}
void
d3d12_video_bitstream_builder_hevc::print_vps(const HevcVideoParameterSet& VPS)
{
debug_printf("--------------------------------------\nHevcVideoParameterSet values below:\n");
debug_printf("vps_video_parameter_set_id: %d\n", VPS.vps_video_parameter_set_id);
debug_printf("vps_reserved_three_2bits: %d\n", VPS.vps_reserved_three_2bits);
debug_printf("vps_max_layers_minus1: %d\n", VPS.vps_max_layers_minus1);
debug_printf("vps_max_sub_layers_minus1: %d\n", VPS.vps_max_sub_layers_minus1);
debug_printf("vps_temporal_id_nesting_flag: %d\n", VPS.vps_temporal_id_nesting_flag);
debug_printf("general_profile_space: %d\n", VPS.ptl.general_profile_space);
debug_printf("general_tier_flag: %d\n", VPS.ptl.general_tier_flag);
debug_printf("general_profile_idc: %d\n", VPS.ptl.general_profile_idc);
debug_printf("general_progressive_source_flag: %d\n", VPS.ptl.general_progressive_source_flag);
debug_printf("general_interlaced_source_flag: %d\n", VPS.ptl.general_interlaced_source_flag);
debug_printf("general_non_packed_constraint_flag: %d\n", VPS.ptl.general_non_packed_constraint_flag);
debug_printf("general_frame_only_constraint_flag: %d\n", VPS.ptl.general_frame_only_constraint_flag);
debug_printf("general_level_idc: %d\n", VPS.ptl.general_level_idc);
debug_printf("vps_sub_layer_ordering_info_present_flag: %d\n", VPS.vps_sub_layer_ordering_info_present_flag);
debug_printf("vps_max_dec_pic_buffering_minus1[%d]: %d\n", (0u), VPS.vps_max_dec_pic_buffering_minus1[0u]);
debug_printf("vps_max_num_reorder_pics[%d]: %d\n", (0u), VPS.vps_max_num_reorder_pics[0u]);
debug_printf("vps_max_latency_increase_plus1[%d]: %d\n", (0u), VPS.vps_max_latency_increase_plus1[0u]);
debug_printf("vps_max_layer_id: %d\n", VPS.vps_max_layer_id);
debug_printf("vps_num_layer_sets_minus1: %d\n", VPS.vps_num_layer_sets_minus1);
debug_printf("vps_timing_info_present_flag: %d\n", VPS.vps_timing_info_present_flag);
debug_printf("vps_num_units_in_tick: %d\n", VPS.vps_num_units_in_tick);
debug_printf("vps_time_scale: %d\n", VPS.vps_time_scale);
debug_printf("vps_poc_proportional_to_timing_flag: %d\n", VPS.vps_poc_proportional_to_timing_flag);
debug_printf("vps_num_ticks_poc_diff_one_minus1: %d\n", VPS.vps_num_ticks_poc_diff_one_minus1);
debug_printf("vps_num_hrd_parameters: %d\n", VPS.vps_num_hrd_parameters);
debug_printf("vps_extension_flag: %d\n", VPS.vps_extension_flag);
debug_printf("vps_extension_data_flag: %d\n", VPS.vps_extension_data_flag);
debug_printf("HevcVideoParameterSet values end\n--------------------------------------\n");
}
void
d3d12_video_bitstream_builder_hevc::print_sps(const HevcSeqParameterSet& SPS)
{
debug_printf("--------------------------------------\nHevcSeqParameterSet values below:\n");
debug_printf("sps_video_parameter_set_id: %d\n", SPS.sps_video_parameter_set_id);
debug_printf("sps_max_sub_layers_minus1: %d\n", SPS.sps_max_sub_layers_minus1);
debug_printf("sps_temporal_id_nesting_flag: %d\n", SPS.sps_temporal_id_nesting_flag);
debug_printf("general_profile_space: %d\n", SPS.ptl.general_profile_space);
debug_printf("general_tier_flag: %d\n", SPS.ptl.general_tier_flag);
debug_printf("general_profile_idc: %d\n", SPS.ptl.general_profile_idc);
debug_printf("general_progressive_source_flag: %d\n", SPS.ptl.general_progressive_source_flag);
debug_printf("general_interlaced_source_flag: %d\n", SPS.ptl.general_interlaced_source_flag);
debug_printf("general_non_packed_constraint_flag: %d\n", SPS.ptl.general_non_packed_constraint_flag);
debug_printf("general_frame_only_constraint_flag: %d\n", SPS.ptl.general_frame_only_constraint_flag);
debug_printf("general_level_idc: %d\n", SPS.ptl.general_level_idc);
debug_printf("sps_seq_parameter_set_id: %d\n", SPS.sps_seq_parameter_set_id);
debug_printf("chroma_format_idc: %d\n", SPS.chroma_format_idc);
debug_printf("separate_colour_plane_flag: %d\n", SPS.separate_colour_plane_flag);
debug_printf("pic_width_in_luma_samples: %d\n", SPS.pic_width_in_luma_samples);
debug_printf("pic_height_in_luma_samples: %d\n", SPS.pic_height_in_luma_samples);
debug_printf("conformance_window_flag: %d\n", SPS.conformance_window_flag);
debug_printf("conf_win_left_offset: %d\n", SPS.conf_win_left_offset);
debug_printf("conf_win_right_offset: %d\n", SPS.conf_win_right_offset);
debug_printf("conf_win_top_offset: %d\n", SPS.conf_win_top_offset);
debug_printf("conf_win_bottom_offset: %d\n", SPS.conf_win_bottom_offset);
debug_printf("bit_depth_luma_minus8: %d\n", SPS.bit_depth_luma_minus8);
debug_printf("bit_depth_chroma_minus8: %d\n", SPS.bit_depth_chroma_minus8);
debug_printf("log2_max_pic_order_cnt_lsb_minus4: %d\n", SPS.log2_max_pic_order_cnt_lsb_minus4);
debug_printf("maxPicOrderCntLsb: %d\n", SPS.maxPicOrderCntLsb);
debug_printf("sps_sub_layer_ordering_info_present_flag: %d\n", SPS.sps_sub_layer_ordering_info_present_flag);
debug_printf("sps_max_dec_pic_buffering_minus1[%d]: %d\n", (0u), SPS.sps_max_dec_pic_buffering_minus1[0u]);
debug_printf("sps_max_num_reorder_pics[%d]: %d\n", (0u), SPS.sps_max_num_reorder_pics[0u]);
debug_printf("sps_max_latency_increase_plus1[%d]: %d\n", (0u), SPS.sps_max_latency_increase_plus1[0u]);
debug_printf("log2_min_luma_coding_block_size_minus3: %d\n", SPS.log2_min_luma_coding_block_size_minus3);
debug_printf("log2_diff_max_min_luma_coding_block_size: %d\n", SPS.log2_diff_max_min_luma_coding_block_size);
debug_printf("log2_min_transform_block_size_minus2: %d\n", SPS.log2_min_transform_block_size_minus2);
debug_printf("log2_diff_max_min_transform_block_size: %d\n", SPS.log2_diff_max_min_transform_block_size);
debug_printf("max_transform_hierarchy_depth_inter: %d\n", SPS.max_transform_hierarchy_depth_inter);
debug_printf("max_transform_hierarchy_depth_intra: %d\n", SPS.max_transform_hierarchy_depth_intra);
debug_printf("scaling_list_enabled_flag: %d\n", SPS.scaling_list_enabled_flag);
debug_printf("sps_scaling_list_data_present_flag: %d\n", SPS.sps_scaling_list_data_present_flag);
debug_printf("amp_enabled_flag: %d\n", SPS.amp_enabled_flag);
debug_printf("sample_adaptive_offset_enabled_flag: %d\n", SPS.sample_adaptive_offset_enabled_flag);
debug_printf("pcm_enabled_flag: %d\n", SPS.pcm_enabled_flag);
debug_printf("pcm_sample_bit_depth_luma_minus1: %d\n", SPS.pcm_sample_bit_depth_luma_minus1);
debug_printf("pcm_sample_bit_depth_chroma_minus1: %d\n", SPS.pcm_sample_bit_depth_chroma_minus1);
debug_printf("log2_min_pcm_luma_coding_block_size_minus3: %d\n", SPS.log2_min_pcm_luma_coding_block_size_minus3);
debug_printf("log2_diff_max_min_pcm_luma_coding_block_size: %d\n", SPS.log2_diff_max_min_pcm_luma_coding_block_size);
debug_printf("pcm_loop_filter_disabled_flag: %d\n", SPS.pcm_loop_filter_disabled_flag);
debug_printf("num_short_term_ref_pic_sets: %d\n", SPS.num_short_term_ref_pic_sets);
for(UINT idx = 0; idx < SPS.num_short_term_ref_pic_sets ; idx++)
{
print_rps(&SPS, idx);
}
debug_printf("long_term_ref_pics_present_flag: %d\n", SPS.long_term_ref_pics_present_flag);
debug_printf("num_long_term_ref_pics_sps: %d\n", SPS.num_long_term_ref_pics_sps);
for(UINT idx = 0; idx < SPS.num_long_term_ref_pics_sps ; idx++)
{
debug_printf("lt_ref_pic_poc_lsb_sps[%d]: %d\n", idx, SPS.lt_ref_pic_poc_lsb_sps[idx]);
debug_printf("used_by_curr_pic_lt_sps_flag[%d]: %d\n", idx, SPS.used_by_curr_pic_lt_sps_flag[idx]);
}
debug_printf("sps_temporal_mvp_enabled_flag: %d\n", SPS.sps_temporal_mvp_enabled_flag);
debug_printf("strong_intra_smoothing_enabled_flag: %d\n", SPS.strong_intra_smoothing_enabled_flag);
debug_printf("vui_parameters_present_flag: %d\n", SPS.vui_parameters_present_flag);
debug_printf("sps_extension_flag: %d\n", SPS.sps_extension_flag);
debug_printf("sps_extension_data_flag: %d\n", SPS.sps_extension_data_flag);
debug_printf("HevcSeqParameterSet values end\n--------------------------------------\n");
}
void
d3d12_video_bitstream_builder_hevc::print_pps(const HevcPicParameterSet& PPS)
{
debug_printf("--------------------------------------\nHevcPicParameterSet values below:\n");
debug_printf("pps_pic_parameter_set_id: %d\n", PPS.pps_pic_parameter_set_id);
debug_printf("pps_seq_parameter_set_id: %d\n", PPS.pps_seq_parameter_set_id);
debug_printf("dependent_slice_segments_enabled_flag: %d\n", PPS.dependent_slice_segments_enabled_flag);
debug_printf("output_flag_present_flag: %d\n", PPS.output_flag_present_flag);
debug_printf("num_extra_slice_header_bits: %d\n", PPS.num_extra_slice_header_bits);
debug_printf("sign_data_hiding_enabled_flag: %d\n", PPS.sign_data_hiding_enabled_flag);
debug_printf("cabac_init_present_flag: %d\n", PPS.cabac_init_present_flag);
debug_printf("num_ref_idx_l0_default_active_minus1: %d\n", PPS.num_ref_idx_lx_default_active_minus1[0]);
debug_printf("num_ref_idx_l1_default_active_minus1: %d\n", PPS.num_ref_idx_lx_default_active_minus1[1]);
debug_printf("init_qp_minus26: %d\n", PPS.init_qp_minus26);
debug_printf("constrained_intra_pred_flag: %d\n", PPS.constrained_intra_pred_flag);
debug_printf("transform_skip_enabled_flag: %d\n", PPS.transform_skip_enabled_flag);
debug_printf("cu_qp_delta_enabled_flag: %d\n", PPS.cu_qp_delta_enabled_flag);
debug_printf("diff_cu_qp_delta_depth: %d\n", PPS.diff_cu_qp_delta_depth);
debug_printf("pps_cb_qp_offset: %d\n", PPS.pps_cb_qp_offset);
debug_printf("pps_cr_qp_offset: %d\n", PPS.pps_cr_qp_offset);
debug_printf("pps_slice_chroma_qp_offsets_present_flag: %d\n", PPS.pps_slice_chroma_qp_offsets_present_flag);
debug_printf("weighted_pred_flag: %d\n", PPS.weighted_pred_flag);
debug_printf("weighted_bipred_flag: %d\n", PPS.weighted_bipred_flag);
debug_printf("transquant_bypass_enabled_flag: %d\n", PPS.transquant_bypass_enabled_flag);
debug_printf("tiles_enabled_flag: %d\n", PPS.tiles_enabled_flag);
debug_printf("entropy_coding_sync_enabled_flag: %d\n", PPS.entropy_coding_sync_enabled_flag);
debug_printf("num_tile_columns_minus1: %d\n", PPS.num_tile_columns_minus1);
debug_printf("num_tile_rows_minus1: %d\n", PPS.num_tile_rows_minus1);
debug_printf("uniform_spacing_flag: %d\n", PPS.uniform_spacing_flag);
debug_printf("column_width_minus1[0]: %d\n", PPS.column_width_minus1[0]); // no tiles in D3D12)
debug_printf("row_height_minus1[0]: %d\n", PPS.row_height_minus1[0]); // no tiles in D3D12)
debug_printf("loop_filter_across_tiles_enabled_flag: %d\n", PPS.loop_filter_across_tiles_enabled_flag);
debug_printf("pps_loop_filter_across_slices_enabled_flag: %d\n", PPS.pps_loop_filter_across_slices_enabled_flag);
debug_printf("deblocking_filter_control_present_flag: %d\n", PPS.deblocking_filter_control_present_flag);
debug_printf("deblocking_filter_override_enabled_flag: %d\n", PPS.deblocking_filter_override_enabled_flag);
debug_printf("pps_deblocking_filter_disabled_flag: %d\n", PPS.pps_deblocking_filter_disabled_flag);
debug_printf("pps_beta_offset_div2: %d\n", PPS.pps_beta_offset_div2);
debug_printf("pps_tc_offset_div2: %d\n", PPS.pps_tc_offset_div2);
debug_printf("pps_scaling_list_data_present_flag: %d\n", PPS.pps_scaling_list_data_present_flag);
debug_printf("lists_modification_present_flag: %d\n", PPS.lists_modification_present_flag);
debug_printf("log2_parallel_merge_level_minus2: %d\n", PPS.log2_parallel_merge_level_minus2);
debug_printf("slice_segment_header_extension_present_flag: %d\n", PPS.slice_segment_header_extension_present_flag);
debug_printf("pps_extension_flag: %d\n", PPS.pps_extension_flag);
debug_printf("pps_extension_data_flag: %d\n", PPS.pps_extension_data_flag);
debug_printf("HevcPicParameterSet values end\n--------------------------------------\n");
}
void
d3d12_video_bitstream_builder_hevc::print_rps(const HevcSeqParameterSet* sps, UINT stRpsIdx)
{
const HEVCReferencePictureSet* rps = &(sps->rpsShortTerm[stRpsIdx]);
debug_printf("--------------------------------------\nHEVCReferencePictureSet[%d] values below:\n", stRpsIdx);
debug_printf("inter_ref_pic_set_prediction_flag: %d\n", rps->inter_ref_pic_set_prediction_flag);
if(rps->inter_ref_pic_set_prediction_flag)
{
debug_printf("delta_idx_minus1: %d\n", rps->delta_idx_minus1);
debug_printf("delta_rps_sign: %d\n", rps->delta_rps_sign);
debug_printf("abs_delta_rps_minus1: %d\n", rps->abs_delta_rps_minus1);
debug_printf("num_negative_pics: %d\n", rps->num_negative_pics);
debug_printf("num_positive_pics: %d\n", rps->num_positive_pics);
int32_t RefRpsIdx = stRpsIdx - 1 - rps->delta_idx_minus1;
const HEVCReferencePictureSet* rpsRef = &(sps->rpsShortTerm[RefRpsIdx]);
auto numberOfPictures = rpsRef->num_negative_pics + rpsRef->num_positive_pics;
for (uint8_t j = 0; j <= numberOfPictures; j++) {
debug_printf("used_by_curr_pic_flag[%d]: %d\n", j, rps->used_by_curr_pic_flag[j]);
if (!rps->used_by_curr_pic_flag[j]) {
debug_printf("use_delta_flag[%d]: %d\n", j, rps->use_delta_flag[j]);
}
}
}
else
{
debug_printf("num_negative_pics: %d\n", rps->num_negative_pics);
for (uint8_t i = 0; i < rps->num_negative_pics; i++) {
debug_printf("delta_poc_s0_minus1[%d]: %d\n", i, rps->delta_poc_s0_minus1[i]);
debug_printf("used_by_curr_pic_s0_flag[%d]: %d\n", i, rps->used_by_curr_pic_s0_flag[i]);
}
debug_printf("num_positive_pics: %d\n", rps->num_positive_pics);
for (int32_t i = 0; i < rps->num_positive_pics; i++) {
debug_printf("delta_poc_s1_minus1[%d]: %d\n", i, rps->delta_poc_s1_minus1[i]);
debug_printf("used_by_curr_pic_s1_flag[%d]: %d\n", i, rps->used_by_curr_pic_s1_flag[i]);
}
}
debug_printf("HEVCReferencePictureSet values end\n--------------------------------------\n");
}

View file

@ -0,0 +1,140 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_ENC_BITSTREAM_BUILDER_HEVC_H
#define D3D12_VIDEO_ENC_BITSTREAM_BUILDER_HEVC_H
#include "d3d12_video_encoder_nalu_writer_hevc.h"
#include "d3d12_video_encoder_bitstream_builder.h"
class d3d12_video_bitstream_builder_hevc : public d3d12_video_bitstream_builder_interface
{
public:
d3d12_video_bitstream_builder_hevc() {};
~d3d12_video_bitstream_builder_hevc() {};
void build_vps(const D3D12_VIDEO_ENCODER_PROFILE_HEVC& profile,
const D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC& level,
const DXGI_FORMAT inputFmt,
uint8_t maxRefFrames,
bool gopHasBFrames,
uint8_t vps_video_parameter_set_id,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcVideoParameterSet* pVPSStruct = nullptr);
void build_sps(const HevcVideoParameterSet& parentVPS,
uint8_t seq_parameter_set_id,
const D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& encodeResolution,
const D3D12_BOX& crop_window_upper_layer,
const UINT picDimensionMultipleRequirement,
const DXGI_FORMAT& inputFmt,
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC& codecConfig,
const D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC& hevcGOP,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcSeqParameterSet* outputSPS = nullptr);
void build_pps(const HevcSeqParameterSet& parentSPS,
uint8_t pic_parameter_set_id,
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC& codecConfig,
const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC& pictureControl,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
HevcPicParameterSet* outputPPS = nullptr);
void write_end_of_stream_nalu(std::vector<uint8_t> & headerBitstream,
std::vector<uint8_t>::iterator placingPositionStart,
size_t & writtenBytes);
void write_end_of_sequence_nalu(std::vector<uint8_t> & headerBitstream,
std::vector<uint8_t>::iterator placingPositionStart,
size_t & writtenBytes);
void print_vps(const HevcVideoParameterSet& vps);
void print_sps(const HevcSeqParameterSet& sps);
void print_pps(const HevcPicParameterSet& pps);
void print_rps(const HevcSeqParameterSet* sps, UINT stRpsIdx);
uint32_t m_activeVPSIndex = 0;
uint32_t m_activeSPSIndex = 0;
uint32_t m_activePPSIndex = 0;
HevcVideoParameterSet m_latest_vps = {};
HevcSeqParameterSet m_latest_sps = {};
HevcPicParameterSet m_latest_pps = {};
HevcVideoParameterSet get_latest_vps()
{
return m_latest_vps;
}
HevcSeqParameterSet get_latest_sps()
{
return m_latest_sps;
}
HevcPicParameterSet get_latest_pps()
{
return m_latest_pps;
}
uint32_t get_active_vps_id()
{
return m_activeVPSIndex;
};
uint32_t get_active_sps_id()
{
return m_activeSPSIndex;
};
uint32_t get_active_pps_id()
{
return m_activePPSIndex;
};
void set_active_vps_id(uint32_t active_vps_id)
{
m_activeVPSIndex = active_vps_id;
debug_printf("[d3d12_video_bitstream_builder_hevc] Setting new active VPS ID: %d ", m_activeVPSIndex);
};
void set_active_sps_id(uint32_t active_sps_id)
{
m_activeSPSIndex = active_sps_id;
debug_printf("[d3d12_video_bitstream_builder_hevc] Setting new active SPS ID: %d ", m_activeSPSIndex);
};
void set_active_pps_id(uint32_t active_pps_id)
{
m_activePPSIndex = active_pps_id;
debug_printf("[d3d12_video_bitstream_builder_hevc] Setting new active PPS ID: %d ", m_activePPSIndex);
};
private:
d3d12_video_nalu_writer_hevc m_hevcEncoder;
void init_profile_tier_level(HEVCProfileTierLevel *ptl, uint8_t HEVCProfileIdc, uint8_t HEVCLevelIdc, bool isHighTier);
};
#endif

View file

@ -0,0 +1,520 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_video_encoder_nalu_writer_hevc.h"
#include <algorithm>
// Writes the HEVC VPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void
d3d12_video_nalu_writer_hevc::vps_to_nalu_bytes(HevcVideoParameterSet *pVPS,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes) {
generic_write_bytes(headerBitstream, placingPositionStart, writtenBytes, pVPS);
}
// Writes the HEVC pSPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void
d3d12_video_nalu_writer_hevc::sps_to_nalu_bytes(HevcSeqParameterSet *pSPS,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes) {
generic_write_bytes(headerBitstream, placingPositionStart, writtenBytes, pSPS);
}
// Writes the HEVC PPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void
d3d12_video_nalu_writer_hevc::pps_to_nalu_bytes(HevcPicParameterSet *pPPS,
std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes) {
generic_write_bytes(headerBitstream, placingPositionStart, writtenBytes, pPPS);
}
void
d3d12_video_nalu_writer_hevc::write_end_of_stream_nalu(std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes) {
HEVCNaluHeader endOfStreamNALU =
{
// uint8_t forbidden_zero_bit;
static_cast<uint8_t>(0u),
// uint8_t nal_unit_type
static_cast<uint8_t>(HEVC_NALU_EOB_NUT),
// uint8_t nuh_layer_id
static_cast<uint8_t>(0u),
// uint8_t nuh_temporal_id_plus1
static_cast<uint8_t>(1u)
};
generic_write_bytes(headerBitstream, placingPositionStart, writtenBytes, &endOfStreamNALU);
}
void
d3d12_video_nalu_writer_hevc::write_end_of_sequence_nalu(std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes) {
HEVCNaluHeader endOfSeqNALU =
{
// uint8_t forbidden_zero_bit;
static_cast<uint8_t>(0u),
// uint8_t nal_unit_type
static_cast<uint8_t>(HEVC_NALU_EOS_NUT),
// uint8_t nuh_layer_id
static_cast<uint8_t>(0u),
// uint8_t nuh_temporal_id_plus1
static_cast<uint8_t>(1u)
};
generic_write_bytes(headerBitstream, placingPositionStart, writtenBytes, &endOfSeqNALU);
}
void
d3d12_video_nalu_writer_hevc::generic_write_bytes( std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
void *pStructure)
{
// Wrap pSPS into NALU and copy full NALU into output byte array
d3d12_video_encoder_bitstream rbsp, nalu;
/*HEVCNaluHeader nalu is in all Hevc*ParameterSet structures at the beggining*/
HEVCNaluHeader* nal_header = ((HEVCNaluHeader *) pStructure);
if (!rbsp.create_bitstream(MAX_COMPRESSED_NALU)) {
debug_printf("rbsp.create_bitstream(MAX_COMPRESSED_NALU) failed\n");
assert(false);
}
if (!nalu.create_bitstream(2 * MAX_COMPRESSED_NALU)) {
debug_printf("nalu.create_bitstream(2 * MAX_COMPRESSED_NALU) failed\n");
assert(false);
}
rbsp.set_start_code_prevention(TRUE);
if (write_bytes_from_struct(&rbsp, pStructure, nal_header->nal_unit_type) <= 0u) {
debug_printf("write_bytes_from_struct(&rbsp, pStructure, nal_header->nal_unit_type) didn't write any bytes.\n");
assert(false);
}
if (wrap_rbsp_into_nalu(&nalu, &rbsp, nal_header) <= 0u) {
debug_printf("wrap_rbsp_into_nalu(&nalu, &rbsp, nal_header) didn't write any bytes.\n");
assert(false);
}
// Deep copy nalu into headerBitstream, nalu gets out of scope here and its destructor frees the nalu object buffer
// memory.
uint8_t *naluBytes = nalu.get_bitstream_buffer();
size_t naluByteSize = nalu.get_byte_count();
auto startDstIndex = std::distance(headerBitstream.begin(), placingPositionStart);
if (headerBitstream.size() < (startDstIndex + naluByteSize)) {
headerBitstream.resize(startDstIndex + naluByteSize);
}
std::copy_n(&naluBytes[0], naluByteSize, &headerBitstream.data()[startDstIndex]);
writtenBytes = naluByteSize;
}
uint32_t
d3d12_video_nalu_writer_hevc::write_bytes_from_struct(d3d12_video_encoder_bitstream *pBitstream, void *pData, uint8_t nal_unit_type)
{
switch(nal_unit_type)
{
case HEVC_NALU_VPS_NUT:
{
return write_vps_bytes(pBitstream, (HevcVideoParameterSet *) pData);
} break;
case HEVC_NALU_SPS_NUT:
{
return write_sps_bytes(pBitstream, (HevcSeqParameterSet *) pData);
} break;
case HEVC_NALU_PPS_NUT:
{
return write_pps_bytes(pBitstream, (HevcPicParameterSet *) pData);
} break;
case HEVC_NALU_EOS_NUT:
case HEVC_NALU_EOB_NUT:
{
// Do nothing for these two, just the header suffices
return 1;
} break;
default:
{
unreachable("Unsupported NALU value");
} break;
}
}
uint32_t
d3d12_video_nalu_writer_hevc::write_vps_bytes(d3d12_video_encoder_bitstream *pBitstream, HevcVideoParameterSet *vps)
{
int32_t iBytesWritten = pBitstream->get_byte_count();
pBitstream->put_bits(4, vps->vps_video_parameter_set_id);
pBitstream->put_bits(2, 3); //vps_reserved_three_2bits
pBitstream->put_bits(6, vps->vps_max_layers_minus1);
pBitstream->put_bits(3, vps->vps_max_sub_layers_minus1);
pBitstream->put_bits(1, vps->vps_temporal_id_nesting_flag);
pBitstream->put_bits(16, 0xffff); //vps_reserved_ffff_16bits
write_profile_tier_level(pBitstream, &vps->ptl);
pBitstream->put_bits(1,vps->vps_sub_layer_ordering_info_present_flag);
for (int i = 0; i <= vps->vps_max_sub_layers_minus1; i++) {
pBitstream->exp_Golomb_ue(vps->vps_max_dec_pic_buffering_minus1[i]);
pBitstream->exp_Golomb_ue(vps->vps_max_num_reorder_pics[i]);
pBitstream->exp_Golomb_ue(vps->vps_max_latency_increase_plus1[i]);
}
pBitstream->put_bits(6, vps->vps_max_layer_id);
pBitstream->exp_Golomb_ue(vps->vps_num_layer_sets_minus1);
pBitstream->put_bits(1, vps->vps_timing_info_present_flag);
pBitstream->put_bits(1, 0); // vps_extension_flag
rbsp_trailing(pBitstream);
pBitstream->flush();
iBytesWritten = pBitstream->get_byte_count() - iBytesWritten;
return (uint32_t) iBytesWritten;
}
uint32_t
d3d12_video_nalu_writer_hevc::write_sps_bytes(d3d12_video_encoder_bitstream *pBitstream,
HevcSeqParameterSet *pSPS)
{
int32_t iBytesWritten = pBitstream->get_byte_count();
pBitstream->put_bits(4, pSPS->sps_video_parameter_set_id);
pBitstream->put_bits(3, pSPS->sps_max_sub_layers_minus1);
pBitstream->put_bits(1, pSPS->sps_temporal_id_nesting_flag);
write_profile_tier_level(pBitstream, &pSPS->ptl);
pBitstream->exp_Golomb_ue(pSPS->sps_seq_parameter_set_id);
pBitstream->exp_Golomb_ue(pSPS->chroma_format_idc);
pBitstream->exp_Golomb_ue(pSPS->pic_width_in_luma_samples);
pBitstream->exp_Golomb_ue(pSPS->pic_height_in_luma_samples);
pBitstream->put_bits(1, pSPS->conformance_window_flag);
if (pSPS->conformance_window_flag) {
pBitstream->exp_Golomb_ue(pSPS->conf_win_left_offset);
pBitstream->exp_Golomb_ue(pSPS->conf_win_right_offset);
pBitstream->exp_Golomb_ue(pSPS->conf_win_top_offset);
pBitstream->exp_Golomb_ue(pSPS->conf_win_bottom_offset);
}
pBitstream->exp_Golomb_ue(pSPS->bit_depth_luma_minus8);
pBitstream->exp_Golomb_ue(pSPS->bit_depth_chroma_minus8);
pBitstream->exp_Golomb_ue(pSPS->log2_max_pic_order_cnt_lsb_minus4);
pBitstream->put_bits(1, pSPS->sps_sub_layer_ordering_info_present_flag);
for (int i = 0; i <= pSPS->sps_max_sub_layers_minus1; i++) {
pBitstream->exp_Golomb_ue(pSPS->sps_max_dec_pic_buffering_minus1[i]);
pBitstream->exp_Golomb_ue(pSPS->sps_max_num_reorder_pics[i]);
pBitstream->exp_Golomb_ue(pSPS->sps_max_latency_increase_plus1[i]);
}
pBitstream->exp_Golomb_ue(pSPS->log2_min_luma_coding_block_size_minus3);
pBitstream->exp_Golomb_ue(pSPS->log2_diff_max_min_luma_coding_block_size);
pBitstream->exp_Golomb_ue(pSPS->log2_min_transform_block_size_minus2);
pBitstream->exp_Golomb_ue(pSPS->log2_diff_max_min_transform_block_size);
pBitstream->exp_Golomb_ue(pSPS->max_transform_hierarchy_depth_inter);
pBitstream->exp_Golomb_ue(pSPS->max_transform_hierarchy_depth_intra);
pBitstream->put_bits(1, pSPS->scaling_list_enabled_flag);
pBitstream->put_bits(1, pSPS->amp_enabled_flag);
pBitstream->put_bits(1, pSPS->sample_adaptive_offset_enabled_flag);
pBitstream->put_bits(1, pSPS->pcm_enabled_flag);
if (pSPS->pcm_enabled_flag) {
pBitstream->put_bits(4, pSPS->bit_depth_luma_minus8 + 7);
pBitstream->put_bits(4, pSPS->bit_depth_chroma_minus8 + 7);
pBitstream->exp_Golomb_ue(pSPS->log2_min_luma_coding_block_size_minus3);
pBitstream->exp_Golomb_ue(pSPS->log2_diff_max_min_luma_coding_block_size);
pBitstream->put_bits(1, pSPS->pcm_loop_filter_disabled_flag);
}
pBitstream->exp_Golomb_ue(pSPS->num_short_term_ref_pic_sets);
for (int i = 0; i < pSPS->num_short_term_ref_pic_sets; i++) {
write_rps(pBitstream, pSPS, i, false);
}
pBitstream->put_bits(1, pSPS->long_term_ref_pics_present_flag);
if (pSPS->long_term_ref_pics_present_flag) {
pBitstream->exp_Golomb_ue(pSPS->num_long_term_ref_pics_sps);
for (int i = 0; i < pSPS->num_long_term_ref_pics_sps; i++) {
pBitstream->put_bits(pSPS->log2_max_pic_order_cnt_lsb_minus4 + 4, pSPS->lt_ref_pic_poc_lsb_sps[i]);
pBitstream->put_bits(1, pSPS->used_by_curr_pic_lt_sps_flag[i]);
}
}
pBitstream->put_bits(1, pSPS->sps_temporal_mvp_enabled_flag);
pBitstream->put_bits(1, pSPS->strong_intra_smoothing_enabled_flag);
pBitstream->put_bits(1, pSPS->vui_parameters_present_flag);
assert (pSPS->vui_parameters_present_flag == 0);
// pSps_extension_flag
pBitstream->put_bits(1, 0);
rbsp_trailing(pBitstream);
pBitstream->flush();
iBytesWritten = pBitstream->get_byte_count() - iBytesWritten;
return (uint32_t) iBytesWritten;
}
uint32_t
d3d12_video_nalu_writer_hevc::write_pps_bytes(d3d12_video_encoder_bitstream *pBitstream,
HevcPicParameterSet *pPPS)
{
int32_t iBytesWritten = pBitstream->get_byte_count();
pBitstream->exp_Golomb_ue(pPPS->pps_pic_parameter_set_id);
pBitstream->exp_Golomb_ue(pPPS->pps_seq_parameter_set_id);
pBitstream->put_bits(1, pPPS->dependent_slice_segments_enabled_flag);
pBitstream->put_bits(1, pPPS->output_flag_present_flag);
pBitstream->put_bits(3, pPPS->num_extra_slice_header_bits);
pBitstream->put_bits(1, pPPS->sign_data_hiding_enabled_flag);
pBitstream->put_bits(1, pPPS->cabac_init_present_flag);
pBitstream->exp_Golomb_ue(pPPS->num_ref_idx_lx_default_active_minus1[0]);
pBitstream->exp_Golomb_ue(pPPS->num_ref_idx_lx_default_active_minus1[1]);
pBitstream->exp_Golomb_se(pPPS->init_qp_minus26);
pBitstream->put_bits(1, pPPS->constrained_intra_pred_flag);
pBitstream->put_bits(1, pPPS->transform_skip_enabled_flag);
pBitstream->put_bits(1, pPPS->cu_qp_delta_enabled_flag);
if (pPPS->cu_qp_delta_enabled_flag) {
pBitstream->exp_Golomb_se(pPPS->diff_cu_qp_delta_depth);
}
pBitstream->exp_Golomb_se(pPPS->pps_cb_qp_offset);
pBitstream->exp_Golomb_se(pPPS->pps_cr_qp_offset);
pBitstream->put_bits(1, pPPS->pps_slice_chroma_qp_offsets_present_flag);
pBitstream->put_bits(1, pPPS->weighted_pred_flag);
pBitstream->put_bits(1, pPPS->weighted_bipred_flag);
pBitstream->put_bits(1, pPPS->transquant_bypass_enabled_flag);
pBitstream->put_bits(1, pPPS->tiles_enabled_flag);
pBitstream->put_bits(1, pPPS->entropy_coding_sync_enabled_flag);
if (pPPS->tiles_enabled_flag) {
pBitstream->exp_Golomb_ue(pPPS->num_tile_columns_minus1);
pBitstream->exp_Golomb_ue(pPPS->num_tile_rows_minus1);
pBitstream->put_bits(1, pPPS->uniform_spacing_flag);
if (!pPPS->uniform_spacing_flag) {
for (int i = 0; i < pPPS->num_tile_columns_minus1; i++) {
pBitstream->exp_Golomb_ue(pPPS->column_width_minus1[i]);
}
for (int i = 0; i < pPPS->num_tile_rows_minus1; i++) {
pBitstream->exp_Golomb_ue(pPPS->row_height_minus1[i]);
}
}
pBitstream->put_bits(1, pPPS->loop_filter_across_tiles_enabled_flag);
}
pBitstream->put_bits(1, pPPS->pps_loop_filter_across_slices_enabled_flag);
pBitstream->put_bits(1, pPPS->deblocking_filter_control_present_flag);
if (pPPS->deblocking_filter_control_present_flag) {
pBitstream->put_bits(1, pPPS->deblocking_filter_override_enabled_flag);
pBitstream->put_bits(1, pPPS->pps_deblocking_filter_disabled_flag);
if (!pPPS->pps_deblocking_filter_disabled_flag) {
pBitstream->exp_Golomb_se(pPPS->pps_beta_offset_div2);
pBitstream->exp_Golomb_se(pPPS->pps_tc_offset_div2);
}
}
pBitstream->put_bits(1, pPPS->pps_scaling_list_data_present_flag);
if (pPPS->pps_scaling_list_data_present_flag) {
assert(0); //, "scaling list syntax is not implemented yet");
}
pBitstream->put_bits(1, pPPS->lists_modification_present_flag);
pBitstream->exp_Golomb_ue(pPPS->log2_parallel_merge_level_minus2);
pBitstream->put_bits(1, pPPS->slice_segment_header_extension_present_flag);
//pps_extension_flag
pBitstream->put_bits(1, 0);
rbsp_trailing(pBitstream);
pBitstream->flush();
iBytesWritten = pBitstream->get_byte_count() - iBytesWritten;
return (uint32_t) iBytesWritten;
}
uint32_t
d3d12_video_nalu_writer_hevc::wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream *pNALU,
d3d12_video_encoder_bitstream *pRBSP,
HEVCNaluHeader *pHeader)
{
bool isAligned = pRBSP->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
int32_t iBytesWritten = pNALU->get_byte_count();
pNALU->set_start_code_prevention(FALSE);
// NAL start code
pNALU->put_bits(24, 0);
pNALU->put_bits(8, 1);
// NAL header
pNALU->put_bits(1, pHeader->forbidden_zero_bit);
pNALU->put_bits(6, pHeader->nal_unit_type);
pNALU->put_bits(6, pHeader->nuh_layer_id);
pNALU->put_bits(3, pHeader->nuh_temporal_id_plus1);
pNALU->flush();
// NAL body
pRBSP->flush();
if (pRBSP->get_start_code_prevention_status()) {
// Direct copying.
pNALU->append_byte_stream(pRBSP);
} else {
// Copy with start code prevention.
pNALU->set_start_code_prevention(TRUE);
int32_t iLength = pRBSP->get_byte_count();
uint8_t *pBuffer = pRBSP->get_bitstream_buffer();
for (int32_t i = 0; i < iLength; i++) {
pNALU->put_bits(8, pBuffer[i]);
}
}
isAligned = pNALU->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
write_nalu_end(pNALU);
pNALU->flush();
iBytesWritten = pNALU->get_byte_count() - iBytesWritten;
return (uint32_t) iBytesWritten;
}
void
d3d12_video_nalu_writer_hevc::write_nalu_end(d3d12_video_encoder_bitstream *pNALU)
{
pNALU->flush();
pNALU->set_start_code_prevention(FALSE);
int32_t iNALUnitLen = pNALU->get_byte_count();
if (FALSE == pNALU->m_bBufferOverflow && 0x00 == pNALU->get_bitstream_buffer()[iNALUnitLen - 1]) {
pNALU->put_bits(8, 0x03);
pNALU->flush();
}
}
void
d3d12_video_nalu_writer_hevc::rbsp_trailing(d3d12_video_encoder_bitstream *pBitstream)
{
pBitstream->put_bits(1, 1);
int32_t iLeft = pBitstream->get_num_bits_for_byte_align();
if (iLeft) {
pBitstream->put_bits(iLeft, 0);
}
bool isAligned = pBitstream->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
}
void
d3d12_video_nalu_writer_hevc::write_profile_tier_level(d3d12_video_encoder_bitstream* rbsp, HEVCProfileTierLevel* ptl)
{
rbsp->put_bits(2, ptl->general_profile_space);
rbsp->put_bits(1, ptl->general_tier_flag);
rbsp->put_bits(5, ptl->general_profile_idc);
for (int j = 0; j < 32; j++) {
rbsp->put_bits(1, ptl->general_profile_compatibility_flag[j]);
}
rbsp->put_bits(1, ptl->general_progressive_source_flag);
rbsp->put_bits(1, ptl->general_interlaced_source_flag);
rbsp->put_bits(1, ptl->general_non_packed_constraint_flag);
rbsp->put_bits(1, ptl->general_frame_only_constraint_flag);
rbsp->put_bits(31, 0); //first 31 bits of general_reserved_zero_44bits
rbsp->put_bits(13, 0); //last 13 bits of general_reserved_zero_44bits
rbsp->put_bits(8, ptl->general_level_idc);
}
void
d3d12_video_nalu_writer_hevc::write_rps(d3d12_video_encoder_bitstream* rbsp, HevcSeqParameterSet* pSPS, int stRpsIdx, bool sliceRPS)
{
HEVCReferencePictureSet* rps = &(pSPS->rpsShortTerm[stRpsIdx]);
if (stRpsIdx != 0) {
rbsp->put_bits(1, rps->inter_ref_pic_set_prediction_flag);
}
if (rps->inter_ref_pic_set_prediction_flag) {
if (sliceRPS) {
rbsp->exp_Golomb_ue(rps->delta_idx_minus1);
}
int RefRpsIdx = stRpsIdx - (rps->delta_idx_minus1 + 1);
rbsp->put_bits(1, rps->delta_rps_sign);
rbsp->exp_Golomb_ue(rps->abs_delta_rps_minus1);
HEVCReferencePictureSet* rpsRef = &(pSPS->rpsShortTerm[RefRpsIdx]);
auto numDeltaPocs = rpsRef->num_negative_pics + rpsRef->num_positive_pics;
for (int j = 0; j <= numDeltaPocs; j++) {
rbsp->put_bits(1, rps->used_by_curr_pic_flag[j]);
if (!rps->used_by_curr_pic_flag[j]) {
rbsp->put_bits(1, rps->use_delta_flag[j]);
}
}
} else {
rbsp->exp_Golomb_ue(rps->num_negative_pics);
rbsp->exp_Golomb_ue(rps->num_positive_pics);
for (int i = 0; i < rps->num_negative_pics; i++) {
rbsp->exp_Golomb_ue(rps->delta_poc_s0_minus1[i]);
rbsp->put_bits(1, rps->used_by_curr_pic_s0_flag[i]);
}
for (int i = 0; i < rps->num_positive_pics; i++) {
rbsp->exp_Golomb_ue(rps->delta_poc_s1_minus1[i]);
rbsp->put_bits(1, rps->used_by_curr_pic_s1_flag[i]);
}
}
}

View file

@ -0,0 +1,347 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_ENC_NALU_WRITER_HEVC_H
#define D3D12_VIDEO_ENC_NALU_WRITER_HEVC_H
#include "d3d12_video_encoder_bitstream.h"
#define HEVC_MAX_REF_PICS 16
#define HEVC_MAX_SUB_LAYERS_NUM 7
#define HEVC_MAX_TILE_NUM 64
#define MAX_COMPRESSED_NALU (10*1024)
enum HEVCNaluType {
HEVC_NALU_TRAIL_N = 0,
HEVC_NALU_TRAIL_R = 1,
HEVC_NALU_TSA_N = 2,
HEVC_NALU_TSA_R = 3,
HEVC_NALU_STSA_N = 4,
HEVC_NALU_STSA_R = 5,
HEVC_NALU_RADL_N = 6,
HEVC_NALU_RADL_R = 7,
HEVC_NALU_RASL_N = 8,
HEVC_NALU_RASL_R = 9,
HEVC_NALU_RSV_VCL_N10 = 10,
HEVC_NALU_RSV_VCL_N12 = 12,
HEVC_NALU_RSV_VCL_N14 = 14,
HEVC_NALU_RSV_VCL_R11 = 11,
HEVC_NALU_RSV_VCL_R13 = 13,
HEVC_NALU_RSV_VCL_R15 = 15,
HEVC_NALU_BLA_W_LP = 16,
HEVC_NALU_BLA_W_RADL = 17,
HEVC_NALU_BLA_N_LP = 18,
HEVC_NALU_IDR_W_RADL = 19,
HEVC_NALU_IDR_N_LP = 20,
HEVC_NALU_CRA_NUT = 21,
HEVC_NALU_RSV_IRAP_VCL22 = 22,
HEVC_NALU_RSV_IRAP_VCL23 = 23,
HEVC_NALU_RSV_VCL_24 = 24,
HEVC_NALU_RSV_VCL_25 = 25,
HEVC_NALU_RSV_VCL_26 = 26,
HEVC_NALU_RSV_VCL_27 = 27,
HEVC_NALU_RSV_VCL_28 = 28,
HEVC_NALU_RSV_VCL_29 = 29,
HEVC_NALU_RSV_VCL_30 = 30,
HEVC_NALU_RSV_VCL_31 = 31,
HEVC_NALU_VPS_NUT = 32,
HEVC_NALU_SPS_NUT = 33,
HEVC_NALU_PPS_NUT = 34,
HEVC_NALU_AUD_NUT = 35,
HEVC_NALU_EOS_NUT = 36,
HEVC_NALU_EOB_NUT = 37,
HEVC_NALU_FD_NUT = 38,
HEVC_NALU_PREFIX_SEI_NUT = 39,
HEVC_NALU_SUFFIX_SEI_NUT = 40,
};
struct HEVCNaluHeader {
uint8_t forbidden_zero_bit;
uint8_t nal_unit_type;
uint8_t nuh_layer_id;
uint8_t nuh_temporal_id_plus1;
};
struct HEVCProfileTierLevel {
uint8_t general_profile_space;
uint8_t general_tier_flag;
uint8_t general_profile_idc;
uint8_t general_profile_compatibility_flag[32];
uint8_t general_progressive_source_flag;
uint8_t general_interlaced_source_flag;
uint8_t general_non_packed_constraint_flag;
uint8_t general_frame_only_constraint_flag;
uint8_t general_level_idc;
uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_profile_space[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_tier_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_profile_idc[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_profile_compatibility_flag[HEVC_MAX_SUB_LAYERS_NUM - 1][32];
uint8_t sub_layer_progressive_source_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_interlaced_source_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_non_packed_constraint_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
uint8_t sub_layer_frame_only_constraint_flag[HEVC_MAX_SUB_LAYERS_NUM - 1];
int32_t sub_layer_level_idc[HEVC_MAX_SUB_LAYERS_NUM - 1];
};
struct ReferencePictureSet {
int32_t numberOfPictures;
int32_t numberOfNegativePictures;
int32_t numberOfPositivePictures;
int32_t numberOfLongtermPictures;
int32_t deltaPOC[HEVC_MAX_REF_PICS];
int32_t POC[HEVC_MAX_REF_PICS];
uint8_t used[HEVC_MAX_REF_PICS];
uint8_t interRPSPrediction;
int32_t deltaRIdxMinus1;
int32_t deltaRPS;
int32_t numRefIdc;
int32_t refIdc[HEVC_MAX_REF_PICS + 1];
uint8_t bCheckLTMSB[HEVC_MAX_REF_PICS];
int32_t pocLSBLT[HEVC_MAX_REF_PICS];
int32_t deltaPOCMSBCycleLT[HEVC_MAX_REF_PICS];
uint8_t deltaPocMSBPresentFlag[HEVC_MAX_REF_PICS];
};
struct HEVCReferencePictureSet {
uint8_t inter_ref_pic_set_prediction_flag;
union {
struct {
uint32_t delta_idx_minus1;
uint8_t delta_rps_sign;
uint32_t abs_delta_rps_minus1;
uint8_t used_by_curr_pic_flag[HEVC_MAX_REF_PICS];
uint8_t use_delta_flag[HEVC_MAX_REF_PICS];
};
struct {
int32_t num_negative_pics;
int32_t num_positive_pics;
int32_t delta_poc_s0_minus1[HEVC_MAX_REF_PICS];
uint8_t used_by_curr_pic_s0_flag[HEVC_MAX_REF_PICS];
int32_t delta_poc_s1_minus1[HEVC_MAX_REF_PICS];
uint8_t used_by_curr_pic_s1_flag[HEVC_MAX_REF_PICS];
};
};
};
struct HevcSeqParameterSet {
HEVCNaluHeader nalu;
uint8_t sps_video_parameter_set_id;
uint8_t sps_max_sub_layers_minus1;
uint8_t sps_temporal_id_nesting_flag;
HEVCProfileTierLevel ptl;
uint8_t sps_seq_parameter_set_id;
uint8_t chroma_format_idc;
uint8_t separate_colour_plane_flag;
int32_t pic_width_in_luma_samples;
int32_t pic_height_in_luma_samples;
uint8_t conformance_window_flag;
int32_t conf_win_left_offset;
int32_t conf_win_right_offset;
int32_t conf_win_top_offset;
int32_t conf_win_bottom_offset;
uint8_t bit_depth_luma_minus8;
uint8_t bit_depth_chroma_minus8;
uint8_t log2_max_pic_order_cnt_lsb_minus4;
int maxPicOrderCntLsb;
uint8_t sps_sub_layer_ordering_info_present_flag;
int32_t sps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS_NUM];
int32_t sps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS_NUM];
int32_t sps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS_NUM];
uint8_t log2_min_luma_coding_block_size_minus3;
uint8_t log2_diff_max_min_luma_coding_block_size;
uint8_t log2_min_transform_block_size_minus2;
uint8_t log2_diff_max_min_transform_block_size;
uint8_t max_transform_hierarchy_depth_inter;
uint8_t max_transform_hierarchy_depth_intra;
uint8_t scaling_list_enabled_flag;
uint8_t sps_scaling_list_data_present_flag;
uint8_t scaling_list_pred_mode_flag[4][6];
uint32_t scaling_list_pred_matrix_id_delta[4][6];
int32_t scaling_list_dc_coef_minus8[2][6];
int32_t scaling_list_delta_coef;
int32_t ScalingList[4][6][64];
uint8_t amp_enabled_flag;
uint8_t sample_adaptive_offset_enabled_flag;
uint8_t pcm_enabled_flag;
uint8_t pcm_sample_bit_depth_luma_minus1;
uint8_t pcm_sample_bit_depth_chroma_minus1;
int32_t log2_min_pcm_luma_coding_block_size_minus3;
int32_t log2_diff_max_min_pcm_luma_coding_block_size;
uint8_t pcm_loop_filter_disabled_flag;
uint8_t num_short_term_ref_pic_sets;
HEVCReferencePictureSet rpsShortTerm[64];
uint8_t long_term_ref_pics_present_flag;
uint8_t num_long_term_ref_pics_sps;
int32_t lt_ref_pic_poc_lsb_sps[32];
uint8_t used_by_curr_pic_lt_sps_flag[32];
uint8_t sps_temporal_mvp_enabled_flag;
uint8_t strong_intra_smoothing_enabled_flag;
uint8_t vui_parameters_present_flag;
uint8_t sps_extension_flag;
uint8_t sps_extension_data_flag;
};
struct HevcPicParameterSet {
HEVCNaluHeader nalu;
uint8_t pps_pic_parameter_set_id;
uint8_t pps_seq_parameter_set_id;
uint8_t dependent_slice_segments_enabled_flag;
uint8_t output_flag_present_flag;
uint8_t num_extra_slice_header_bits;
uint8_t sign_data_hiding_enabled_flag;
uint8_t cabac_init_present_flag;
uint8_t num_ref_idx_lx_default_active_minus1[2];
int8_t init_qp_minus26;
uint8_t constrained_intra_pred_flag;
uint8_t transform_skip_enabled_flag;
uint8_t cu_qp_delta_enabled_flag;
uint8_t diff_cu_qp_delta_depth;
int8_t pps_cb_qp_offset;
int8_t pps_cr_qp_offset;
uint8_t pps_slice_chroma_qp_offsets_present_flag;
uint8_t weighted_pred_flag;
uint8_t weighted_bipred_flag;
uint8_t transquant_bypass_enabled_flag;
uint8_t tiles_enabled_flag;
uint8_t entropy_coding_sync_enabled_flag;
int32_t num_tile_columns_minus1;
int32_t num_tile_rows_minus1;
uint8_t uniform_spacing_flag;
int32_t column_width_minus1[HEVC_MAX_TILE_NUM];
int32_t row_height_minus1[HEVC_MAX_TILE_NUM];
uint8_t loop_filter_across_tiles_enabled_flag;
uint8_t pps_loop_filter_across_slices_enabled_flag;
uint8_t deblocking_filter_control_present_flag;
uint8_t deblocking_filter_override_enabled_flag;
uint8_t pps_deblocking_filter_disabled_flag;
int8_t pps_beta_offset_div2;
int8_t pps_tc_offset_div2;
uint8_t pps_scaling_list_data_present_flag;
uint8_t lists_modification_present_flag;
uint8_t log2_parallel_merge_level_minus2;
uint8_t slice_segment_header_extension_present_flag;
uint8_t pps_extension_flag;
uint8_t pps_extension_data_flag;
};
struct HevcVideoParameterSet {
HEVCNaluHeader nalu;
uint8_t vps_video_parameter_set_id;
uint8_t vps_reserved_three_2bits;
uint8_t vps_max_layers_minus1;
uint8_t vps_max_sub_layers_minus1;
uint8_t vps_temporal_id_nesting_flag;
int32_t vps_reserved_0xffff_16bits;
HEVCProfileTierLevel ptl;
uint8_t vps_sub_layer_ordering_info_present_flag;
uint8_t vps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS_NUM];
uint8_t vps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS_NUM];
uint8_t vps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS_NUM];
uint8_t vps_max_layer_id;
uint8_t vps_num_layer_sets_minus1;
uint8_t layer_id_included_flag[1024][1];
uint8_t vps_timing_info_present_flag;
uint32_t vps_num_units_in_tick;
uint32_t vps_time_scale;
uint8_t vps_poc_proportional_to_timing_flag;
uint32_t vps_num_ticks_poc_diff_one_minus1;
uint32_t vps_num_hrd_parameters;
uint32_t hrd_layer_set_idx[1024];
uint8_t cprms_present_flag[1024];
uint8_t vps_extension_flag;
uint8_t vps_extension_data_flag;
};
class d3d12_video_nalu_writer_hevc
{
public:
d3d12_video_nalu_writer_hevc() { }
~d3d12_video_nalu_writer_hevc() { }
// Writes the HEVC VPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void vps_to_nalu_bytes(HevcVideoParameterSet *pVPS,
std::vector<BYTE>
&headerBitstream,
std::vector<BYTE>::iterator
placingPositionStart,
size_t &writtenBytes);
// Writes the HEVC SPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void sps_to_nalu_bytes(HevcSeqParameterSet *pSPS,
std::vector<BYTE>
&headerBitstream,
std::vector<BYTE>::iterator
placingPositionStart,
size_t &writtenBytes);
// Writes the HEVC PPS structure into a bitstream passed in headerBitstream
// Function resizes bitstream accordingly and puts result in byte vector
void pps_to_nalu_bytes(HevcPicParameterSet *pPPS,
std::vector<BYTE>
&headerBitstream,
std::vector<BYTE>::iterator
placingPositionStart,
size_t &writtenBytes);
void write_end_of_stream_nalu(std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator
placingPositionStart,
size_t
&writtenBytes);
void write_end_of_sequence_nalu(std::vector<BYTE>
&headerBitstream,
std::vector<BYTE>::iterator
placingPositionStart,
size_t &writtenBytes);
private:
// Writes from structure into bitstream with RBSP trailing but WITHOUT NAL unit wrap (eg. nal_idc_type, etc)
uint32_t write_vps_bytes(d3d12_video_encoder_bitstream *pBitstream, HevcVideoParameterSet *pSPS);
uint32_t write_sps_bytes(d3d12_video_encoder_bitstream *pBitstream, HevcSeqParameterSet *pSPS);
uint32_t write_pps_bytes(d3d12_video_encoder_bitstream *pBitstream, HevcPicParameterSet *pPPS);
// Adds NALU wrapping into structures and ending NALU control bits
uint32_t wrap_rbsp_into_nalu(d3d12_video_encoder_bitstream *pNALU, d3d12_video_encoder_bitstream *pRBSP, HEVCNaluHeader *pHeader);
// Helpers
void write_nalu_end(d3d12_video_encoder_bitstream *pNALU);
void rbsp_trailing(d3d12_video_encoder_bitstream *pBitstream);
void write_profile_tier_level(d3d12_video_encoder_bitstream* rbsp, HEVCProfileTierLevel* ptl);
void generic_write_bytes(std::vector<BYTE> &headerBitstream,
std::vector<BYTE>::iterator placingPositionStart,
size_t &writtenBytes,
void *pStructure);
uint32_t
write_bytes_from_struct(d3d12_video_encoder_bitstream *pBitstream, void *pData, uint8_t nal_unit_type);
void write_rps(d3d12_video_encoder_bitstream* rbsp, HevcSeqParameterSet* sps, int stRpsIdx, bool sliceRPS);
};
#endif

View file

@ -30,7 +30,7 @@
class d3d12_video_encoder_references_manager_interface class d3d12_video_encoder_references_manager_interface
{ {
public: public:
virtual void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA, bool bUsedAsReference) = 0; virtual void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA, bool bUsedAsReference, struct pipe_picture_desc* picture) = 0;
virtual void end_frame() = 0; virtual void end_frame() = 0;
virtual D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation() = 0; virtual D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation() = 0;
virtual void virtual void

View file

@ -398,11 +398,12 @@ d3d12_video_encoder_references_manager_h264::is_current_frame_used_as_reference(
void void
d3d12_video_encoder_references_manager_h264::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData, d3d12_video_encoder_references_manager_h264::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
bool bUsedAsReference) bool bUsedAsReference, struct pipe_picture_desc* picture)
{ {
m_curFrameState = *curFrameData.pH264PicData; m_curFrameState = *curFrameData.pH264PicData;
m_isCurrentFrameUsedAsReference = bUsedAsReference; m_isCurrentFrameUsedAsReference = bUsedAsReference;
debug_printf("Marking frame_num %d (POC %d) as reference ? %d\n", debug_printf("[Entrypoint: %d] - Marking frame_num %d (POC %d) as reference ? %d\n",
picture->entry_point,
curFrameData.pH264PicData->FrameDecodingOrderNumber, curFrameData.pH264PicData->FrameDecodingOrderNumber,
curFrameData.pH264PicData->PictureOrderCountNumber, curFrameData.pH264PicData->PictureOrderCountNumber,
bUsedAsReference); bUsedAsReference);

View file

@ -32,7 +32,7 @@ class d3d12_video_encoder_references_manager_h264 : public d3d12_video_encoder_r
{ {
public: public:
void end_frame(); void end_frame();
void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData, bool bUsedAsReference); void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData, bool bUsedAsReference, struct pipe_picture_desc* picture);
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation(); D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation();
void get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation); void get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation);
bool is_current_frame_used_as_reference(); bool is_current_frame_used_as_reference();

View file

@ -0,0 +1,463 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_video_encoder_references_manager_hevc.h"
#include <algorithm>
#include <string>
#include "d3d12_screen.h"
using namespace std;
d3d12_video_encoder_references_manager_hevc::d3d12_video_encoder_references_manager_hevc(
bool gopHasIorPFrames, d3d12_video_dpb_storage_manager_interface &rDpbStorageManager, uint32_t MaxDPBCapacity)
: m_MaxDPBCapacity(MaxDPBCapacity),
m_rDPBStorageManager(rDpbStorageManager),
m_CurrentFrameReferencesData({}),
m_gopHasInterFrames(gopHasIorPFrames)
{
assert((m_MaxDPBCapacity + 1 /*extra for cur frame output recon pic*/) ==
m_rDPBStorageManager.get_number_of_tracked_allocations());
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] Completed construction of "
"d3d12_video_encoder_references_manager_hevc instance, settings are\n");
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] m_MaxDPBCapacity: %d\n", m_MaxDPBCapacity);
}
void
d3d12_video_encoder_references_manager_hevc::reset_gop_tracking_and_dpb()
{
// Reset m_CurrentFrameReferencesData tracking
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.clear();
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.reserve(m_MaxDPBCapacity);
m_curFrameStateDescriptorStorage.reserve(m_MaxDPBCapacity);
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
// Reset DPB storage
uint32_t numPicsBeforeClearInDPB = m_rDPBStorageManager.get_number_of_pics_in_dpb();
uint32_t cFreedResources = m_rDPBStorageManager.clear_decode_picture_buffer();
assert(numPicsBeforeClearInDPB == cFreedResources);
// Initialize if needed the reconstructed picture allocation for the first IDR picture in the GOP
// This needs to be done after initializing the GOP tracking state above since it makes decisions based on the
// current picture type.
prepare_current_frame_recon_pic_allocation();
// After clearing the DPB, outstanding used allocations should be 1u only for the first allocation for the
// reconstructed picture of the initial IDR in the GOP
assert(m_rDPBStorageManager.get_number_of_in_use_allocations() == (m_gopHasInterFrames ? 1u : 0u));
assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <=
(m_MaxDPBCapacity + 1)); // pool is not extended beyond maximum expected usage
}
// Calculates the picture control structure for the current frame
void
d3d12_video_encoder_references_manager_hevc::get_current_frame_picture_control_data(
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
{
// Update reference picture control structures (L0/L1 and DPB descriptors lists based on current frame and next frame
// in GOP) for next frame
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] %d resources IN USE out of a total of %d ALLOCATED "
"resources at frame with POC: %d\n",
m_rDPBStorageManager.get_number_of_in_use_allocations(),
m_rDPBStorageManager.get_number_of_tracked_allocations(),
m_curFrameState.PictureOrderCountNumber);
// See casts below
assert(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() < UINT32_MAX);
bool needsL0List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) ||
(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME);
bool needsL1List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME);
// (in HEVC I pics might contain following pics, ref not used in curr)
bool needsRefPicDescriptors = (m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME);
assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC));
// See D3D12 Encode spec below
// pList0ReferenceFrames
// List of past frame reference frames to be used for this frame. Each integer value in this array indices into
// pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
// pList1ReferenceFrames
// List of future frame reference frames to be used for this frame. Each integer value in this array indices into
// pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
// Need to map from frame_num in the receiving ref_idx_l0_list/ref_idx_l1_list to the position with that
// reference_lists_frame_idx in the DPB descriptor
// L0 and L1 need to be ordered by POC (ie. different RefPicSets). The upper layers building the lists should but might not be following this
// Set all in the DPB as unused for the current frame, then below just mark as used the ones references by L0 and L1
for(UINT idx = 0 ; idx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() ; idx++)
{
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[idx].base.IsRefUsedByCurrentPic = false;
}
if (needsL0List && (m_curFrameState.List0ReferenceFramesCount > 0)) {
std::vector<uint32_t> tmpL0(m_curFrameState.List0ReferenceFramesCount, 0);
memcpy(tmpL0.data(),
m_curFrameState.pList0ReferenceFrames,
m_curFrameState.List0ReferenceFramesCount * sizeof(m_curFrameState.pList0ReferenceFrames[0]));
for (size_t l0Idx = 0; l0Idx < m_curFrameState.List0ReferenceFramesCount; l0Idx++) {
// tmpL0[l0Idx] has frame_num's (reference_lists_frame_idx)
// m_curFrameState.pList0ReferenceFrames[l0Idx] needs to have the index j of
// pReferenceFramesReconPictureDescriptors where
// pReferenceFramesReconPictureDescriptors[j].reference_lists_frame_idx == tmpL0[l0Idx]
auto value = tmpL0[l0Idx];
auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
[&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX &p) {
return p.reference_lists_frame_idx == value;
});
assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
m_curFrameState.pList0ReferenceFrames[l0Idx] =
std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[m_curFrameState.pList0ReferenceFrames[l0Idx]].base.IsRefUsedByCurrentPic = true;
}
}
if (needsL1List && (m_curFrameState.List1ReferenceFramesCount > 0)) {
std::vector<uint32_t> tmpL1(m_curFrameState.List1ReferenceFramesCount, 0);
memcpy(tmpL1.data(),
m_curFrameState.pList1ReferenceFrames,
m_curFrameState.List1ReferenceFramesCount * sizeof(m_curFrameState.pList1ReferenceFrames[0]));
for (size_t l1Idx = 0; l1Idx < m_curFrameState.List1ReferenceFramesCount; l1Idx++) {
// tmpL1[l1Idx] has frame_num's (reference_lists_frame_idx)
// m_curFrameState.pList1ReferenceFrames[l1Idx] needs to have the index j of
// pReferenceFramesReconPictureDescriptors where
// pReferenceFramesReconPictureDescriptors[j].reference_lists_frame_idx == tmpL1[l1Idx]
auto value = tmpL1[l1Idx];
auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
[&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX &p) {
return p.reference_lists_frame_idx == value;
});
assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
m_curFrameState.pList1ReferenceFrames[l1Idx] =
std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[m_curFrameState.pList1ReferenceFrames[l1Idx]].base.IsRefUsedByCurrentPic = true;
}
}
m_curFrameState.List0ReferenceFramesCount = needsL0List ? m_curFrameState.List0ReferenceFramesCount : 0;
m_curFrameState.pList0ReferenceFrames = needsL0List ? m_curFrameState.pList0ReferenceFrames : nullptr,
m_curFrameState.List1ReferenceFramesCount = needsL1List ? m_curFrameState.List1ReferenceFramesCount : 0,
m_curFrameState.pList1ReferenceFrames = needsL1List ? m_curFrameState.pList1ReferenceFrames : nullptr;
if (!needsRefPicDescriptors) {
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = 0;
m_curFrameState.pReferenceFramesReconPictureDescriptors = nullptr;
} else {
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size());
m_curFrameStateDescriptorStorage.resize(m_curFrameState.ReferenceFramesReconPictureDescriptorsCount);
for(uint32_t idx = 0; idx < m_curFrameState.ReferenceFramesReconPictureDescriptorsCount ; idx++) {
m_curFrameStateDescriptorStorage[idx] = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[idx].base;
}
m_curFrameState.pReferenceFramesReconPictureDescriptors = m_curFrameStateDescriptorStorage.data();
}
*codecAllocation.pHEVCPicData = m_curFrameState;
print_l0_l1_lists();
print_dpb();
}
// Returns the resource allocation for a reconstructed picture output for the current frame
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
d3d12_video_encoder_references_manager_hevc::get_current_frame_recon_pic_output_allocation()
{
return m_CurrentFrameReferencesData.ReconstructedPicTexture;
}
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
d3d12_video_encoder_references_manager_hevc::get_current_reference_frames()
{
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES retVal = { 0,
// ppTexture2Ds
nullptr,
// pSubresources
nullptr };
// Return nullptr for fully intra frames (eg IDR)
// and return references information for inter frames (eg.P/B) and I frame that doesn't flush DPB
if ((m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME) && m_gopHasInterFrames) {
auto curRef = m_rDPBStorageManager.get_current_reference_frames();
retVal.NumTexture2Ds = curRef.NumTexture2Ds;
retVal.ppTexture2Ds = curRef.ppTexture2Ds;
retVal.pSubresources = curRef.pSubresources;
}
return retVal;
}
void
d3d12_video_encoder_references_manager_hevc::prepare_current_frame_recon_pic_allocation()
{
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
// If all GOP are intra frames, no point in doing reference pic allocations
if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
auto reconPic = m_rDPBStorageManager.get_new_tracked_picture_allocation();
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture = reconPic.pReconstructedPicture;
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
reconPic.ReconstructedPictureSubresource;
}
}
void
d3d12_video_encoder_references_manager_hevc::update_fifo_dpb_push_front_cur_recon_pic()
{
// Keep the order of the dpb storage and dpb descriptors in a circular buffer
// order such that the DPB array consists of a sequence of frames in DECREASING encoding order
// eg. last frame encoded at first, followed by one to last frames encoded, and at the end
// the most distant frame encoded (currentFrameEncodeOrderNumber - MaxDPBSize)
// If current pic was not used as reference, current reconstructed picture resource is empty,
// No need to to anything in that case.
// Otherwise extract the reconstructed picture result and add it to the DPB
// If GOP are all intra frames, do nothing also.
if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] MaxDPBCapacity is %d - Number of pics in DPB is %d "
"when trying to put frame with POC %d (frame_num %d) at front of the DPB\n",
m_MaxDPBCapacity,
m_rDPBStorageManager.get_number_of_pics_in_dpb(),
m_curFrameState.PictureOrderCountNumber,
m_current_frame_idx);
// Release least recently used in DPB if we filled the m_MaxDPBCapacity allowed
if (m_rDPBStorageManager.get_number_of_pics_in_dpb() == m_MaxDPBCapacity) {
bool untrackedRes = false;
m_rDPBStorageManager.remove_reference_frame(m_rDPBStorageManager.get_number_of_pics_in_dpb() - 1,
&untrackedRes); // Remove last entry
// Verify that resource was untracked since this class is using the pool completely for allocations
assert(untrackedRes);
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.pop_back(); // Remove last entry
}
// Add new dpb to front of DPB
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE recAlloc = get_current_frame_recon_pic_output_allocation();
d3d12_video_reconstructed_picture refFrameDesc = {};
refFrameDesc.pReconstructedPicture = recAlloc.pReconstructedPicture;
refFrameDesc.ReconstructedPictureSubresource = recAlloc.ReconstructedPictureSubresource;
refFrameDesc.pVideoHeap = nullptr; // D3D12 Video Encode does not need the D3D12VideoEncoderHeap struct for HEVC
// (used for no-key-frame resolution change in VC1, AV1, etc)
m_rDPBStorageManager.insert_reference_frame(refFrameDesc, 0);
// Prepare D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX for added DPB member
D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX newDPBDescriptor =
{
// D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC
{
// UINT ReconstructedPictureResourceIndex;
0, // the associated reconstructed picture is also being pushed_front in m_rDPBStorageManager
// BOOL IsRefUsedByCurrentPic;
false, // usage is determined in method AdvanceFrame according to picture type to be encoded
// BOOL IsLongTermReference
false, // not implemented - neither FFMPEG or GSTREAMER use LTR for HEVC VAAPI
// UINT PictureOrderCountNumber;
m_curFrameState.PictureOrderCountNumber,
// UINT TemporalLayerIndex;
0
},
// reference_lists_frame_idx
m_current_frame_idx,
};
// Add DPB entry
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.insert(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
newDPBDescriptor);
// Update the indices for ReconstructedPictureResourceIndex in pReferenceFramesReconPictureDescriptors
// to be in identity mapping with m_rDPBStorageManager indices
// after pushing the elements to the right in the push_front operation
for (uint32_t dpbResIdx = 1;
dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
dpbResIdx++) {
auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
dpbDesc.base.ReconstructedPictureResourceIndex = dpbResIdx;
}
}
// Number of allocations, disregarding if they are used or not, should not exceed this limit due to reuse policies on
// DPB items removal.
assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <= (m_MaxDPBCapacity + 1));
}
void
d3d12_video_encoder_references_manager_hevc::print_l0_l1_lists()
{
if ((D3D12_DEBUG_VERBOSE & d3d12_debug) &&
((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) ||
(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME))) {
std::string list0ContentsString;
for (uint32_t idx = 0; idx < m_curFrameState.List0ReferenceFramesCount; idx++) {
uint32_t value = m_curFrameState.pList0ReferenceFrames[idx];
list0ContentsString += "{ DPBidx: ";
list0ContentsString += std::to_string(value);
list0ContentsString += " - POC: ";
list0ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.PictureOrderCountNumber);
list0ContentsString += " - IsRefUsedByCurrentPic: ";
list0ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsRefUsedByCurrentPic);
list0ContentsString += " - IsLongTermReference: ";
list0ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsLongTermReference);
list0ContentsString += " - reference_lists_frame_idx: ";
list0ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].reference_lists_frame_idx);
list0ContentsString += "}\n";
}
debug_printf(
"[D3D12 Video Encoder Picture Manager HEVC] L0 list for frame with POC %d (frame_num %d) is: \n %s \n",
m_curFrameState.PictureOrderCountNumber,
m_current_frame_idx,
list0ContentsString.c_str());
std::string list1ContentsString;
for (uint32_t idx = 0; idx < m_curFrameState.List1ReferenceFramesCount; idx++) {
uint32_t value = m_curFrameState.pList1ReferenceFrames[idx];
list1ContentsString += "{ DPBidx: ";
list1ContentsString += std::to_string(value);
list1ContentsString += " - POC: ";
list1ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.PictureOrderCountNumber);
list1ContentsString += " - IsRefUsedByCurrentPic: ";
list1ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsRefUsedByCurrentPic);
list1ContentsString += " - IsLongTermReference: ";
list1ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsLongTermReference);
list1ContentsString += " - reference_lists_frame_idx: ";
list1ContentsString += std::to_string(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].reference_lists_frame_idx);
list1ContentsString += "}\n";
}
debug_printf(
"[D3D12 Video Encoder Picture Manager HEVC] L1 list for frame with POC %d (frame_num %d) is: \n %s \n",
m_curFrameState.PictureOrderCountNumber,
m_current_frame_idx,
list1ContentsString.c_str());
}
}
void
d3d12_video_encoder_references_manager_hevc::print_dpb()
{
if (D3D12_DEBUG_VERBOSE & d3d12_debug) {
std::string dpbContents;
for (uint32_t dpbResIdx = 0;
dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
dpbResIdx++) {
auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
auto dpbEntry = m_rDPBStorageManager.get_reference_frame(dpbDesc.base.ReconstructedPictureResourceIndex);
dpbContents += "{ DPBidx: ";
dpbContents += std::to_string(dpbResIdx);
dpbContents += " - POC: ";
dpbContents += std::to_string(dpbDesc.base.PictureOrderCountNumber);
dpbContents += " - IsRefUsedByCurrentPic: ";
dpbContents += std::to_string(dpbDesc.base.IsRefUsedByCurrentPic);
dpbContents += " - DPBStorageIdx: ";
dpbContents += std::to_string(dpbDesc.base.ReconstructedPictureResourceIndex);
dpbContents += " - reference_lists_frame_idx: ";
dpbContents += std::to_string(dpbDesc.reference_lists_frame_idx);
dpbContents += " - DPBStorageResourcePtr: ";
char strBuf[256];
memset(&strBuf, '\0', 256);
sprintf(strBuf, "%p", dpbEntry.pReconstructedPicture);
dpbContents += std::string(strBuf);
dpbContents += " - DPBStorageSubresource: ";
dpbContents += std::to_string(dpbEntry.ReconstructedPictureSubresource);
dpbContents += "}\n";
}
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] DPB has %d frames - DPB references for frame with POC "
"%d are: \n %s \n",
m_rDPBStorageManager.get_number_of_pics_in_dpb(),
m_curFrameState.PictureOrderCountNumber,
dpbContents.c_str());
}
}
// Advances state to next frame in GOP; subsequent calls to GetCurrentFrame* point to the advanced frame status
void
d3d12_video_encoder_references_manager_hevc::end_frame()
{
debug_printf("[D3D12 Video Encoder Picture Manager HEVC] %d resources IN USE out of a total of %d ALLOCATED "
"resources at end_frame for frame with POC: %d\n",
m_rDPBStorageManager.get_number_of_in_use_allocations(),
m_rDPBStorageManager.get_number_of_tracked_allocations(),
m_curFrameState.PictureOrderCountNumber);
// Adds last used (if not null) get_current_frame_recon_pic_output_allocation to DPB for next EncodeFrame if
// necessary updates pReferenceFramesReconPictureDescriptors and updates the dpb storage
update_fifo_dpb_push_front_cur_recon_pic();
}
bool
d3d12_video_encoder_references_manager_hevc::is_current_frame_used_as_reference()
{
return m_isCurrentFrameUsedAsReference;
}
void
d3d12_video_encoder_references_manager_hevc::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
bool bUsedAsReference, struct pipe_picture_desc* picture)
{
pipe_h265_enc_picture_desc * pPipeDesc = (pipe_h265_enc_picture_desc*) picture;
m_curFrameState = *curFrameData.pHEVCPicData;
m_isCurrentFrameUsedAsReference = bUsedAsReference;
m_current_frame_idx = pPipeDesc->frame_num;
debug_printf("Marking POC %d (frame_num %d) as reference ? %d\n",
curFrameData.pHEVCPicData->PictureOrderCountNumber,
m_current_frame_idx,
bUsedAsReference);
// Advance the GOP tracking state
bool isDPBFlushNeeded = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME);
if (isDPBFlushNeeded) {
reset_gop_tracking_and_dpb();
} else {
// Get new allocation from DPB storage for reconstructed picture
// This is only necessary for the frames that come after an IDR
// since in the initial state already has this initialized
// and re-initialized by reset_gop_tracking_and_dpb above
prepare_current_frame_recon_pic_allocation();
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_HEVC_H
#define D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_HEVC_H
#include "d3d12_video_types.h"
#include "d3d12_video_encoder_references_manager.h"
#include "d3d12_video_dpb_storage_manager.h"
class d3d12_video_encoder_references_manager_hevc : public d3d12_video_encoder_references_manager_interface
{
public:
void end_frame();
void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData, bool bUsedAsReference, struct pipe_picture_desc* picture);
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation();
void get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation);
bool is_current_frame_used_as_reference();
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES get_current_reference_frames();
d3d12_video_encoder_references_manager_hevc(bool gopHasInterCodedFrames,
d3d12_video_dpb_storage_manager_interface &rDpbStorageManager,
uint32_t MaxDPBCapacity);
~d3d12_video_encoder_references_manager_hevc()
{ }
private:
// Class helpers
void prepare_current_frame_recon_pic_allocation();
void reset_gop_tracking_and_dpb();
void update_fifo_dpb_push_front_cur_recon_pic();
void print_dpb();
void print_l0_l1_lists();
// Class members
uint32_t m_MaxDPBCapacity = 0;
struct D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX {
D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC base;
/* the upper layer uses pipe_h265_enc_picture_desc.frame_num to identify frames
in the L0 and L1 reference lists. This frame_num is different than POC
so let's save it in this variable to be able to reverse-map the L0/L1 lists from
these indices into POCs */
unsigned int reference_lists_frame_idx;
};
struct current_frame_references_data
{
std::vector<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX> pReferenceFramesReconPictureDescriptors;
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE ReconstructedPicTexture;
};
d3d12_video_dpb_storage_manager_interface &m_rDPBStorageManager;
current_frame_references_data m_CurrentFrameReferencesData;
bool m_gopHasInterFrames = false;
bool m_isCurrentFrameUsedAsReference = false;
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC m_curFrameState = {};
std::vector<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC> m_curFrameStateDescriptorStorage;
unsigned int m_current_frame_idx;
};
#endif

View file

@ -26,12 +26,29 @@
#include "d3d12_format.h" #include "d3d12_format.h"
#include "util/u_video.h" #include "util/u_video.h"
#include <directx/d3d12video.h> #include <directx/d3d12video.h>
#include <cmath>
#include <wrl/client.h> #include <wrl/client.h>
using Microsoft::WRL::ComPtr; using Microsoft::WRL::ComPtr;
#include "d3d12_video_types.h" #include "d3d12_video_types.h"
struct d3d12_encode_codec_support {
enum pipe_video_profile profile;
union {
struct {
enum pipe_h265_enc_pred_direction prediction_direction;
union pipe_h265_enc_cap_features hevc_features;
union pipe_h265_enc_cap_block_sizes hevc_block_sizes;
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC d3d12_caps;
} hevc_support;
// Can add more codecs for each codec specific caps here, for example:
// struct {
// D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264;
// } h264_support;
};
};
static bool static bool
d3d12_video_buffer_is_format_supported(struct pipe_screen *screen, d3d12_video_buffer_is_format_supported(struct pipe_screen *screen,
enum pipe_format format, enum pipe_format format,
@ -134,6 +151,8 @@ d3d12_has_video_decode_support(struct pipe_screen *pscreen, enum pipe_video_prof
case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
{ {
supportsProfile = true; supportsProfile = true;
} break; } break;
@ -207,39 +226,65 @@ d3d12_video_encode_max_supported_resolution(const D3D12_VIDEO_ENCODER_CODEC &arg
static uint32_t static uint32_t
d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_ENCODER_CODEC &codec, d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
D3D12_VIDEO_ENCODER_PROFILE_H264 profile, D3D12_VIDEO_ENCODER_PROFILE_DESC profile,
D3D12_VIDEO_ENCODER_LEVELS_H264 level,
ID3D12VideoDevice3 *pD3D12VideoDevice) ID3D12VideoDevice3 *pD3D12VideoDevice)
{ {
uint32_t supportedMaxRefFrames = 0u; uint32_t supportedMaxRefFrames = 0u;
D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264PictureControl = {};
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT capPictureControlData = {}; D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT capPictureControlData = {};
capPictureControlData.NodeIndex = 0; capPictureControlData.NodeIndex = 0;
capPictureControlData.Codec = codec; capPictureControlData.Codec = codec;
capPictureControlData.Profile.pH264Profile = &profile;
capPictureControlData.Profile.DataSize = sizeof(profile);
capPictureControlData.PictureSupport.pH264Support = &h264PictureControl;
capPictureControlData.PictureSupport.DataSize = sizeof(h264PictureControl);
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
&capPictureControlData,
sizeof(capPictureControlData));
if (FAILED(hr)) {
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
}
if (capPictureControlData.IsSupported) { if(codec == D3D12_VIDEO_ENCODER_CODEC_H264) {
/* This attribute determines the maximum number of reference D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264PictureControl = {};
* frames supported for encoding. capPictureControlData.Profile = profile;
* capPictureControlData.PictureSupport.pH264Support = &h264PictureControl;
* Note: for H.264 encoding, the value represents the maximum number capPictureControlData.PictureSupport.DataSize = sizeof(h264PictureControl);
* of reference frames for both the reference picture list 0 (bottom HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
* 16 bits) and the reference picture list 1 (top 16 bits). &capPictureControlData,
*/ sizeof(capPictureControlData));
uint32_t maxRefForL0 = std::min(capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForP, if (FAILED(hr)) {
capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForB); debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
uint32_t maxRefForL1 = capPictureControlData.PictureSupport.pH264Support->MaxL1ReferencesForB; }
supportedMaxRefFrames = (maxRefForL0 & 0xffff) | ((maxRefForL1 & 0xffff) << 16);
if (capPictureControlData.IsSupported) {
/* This attribute determines the maximum number of reference
* frames supported for encoding.
*
* Note: for H.264 encoding, the value represents the maximum number
* of reference frames for both the reference picture list 0 (bottom
* 16 bits) and the reference picture list 1 (top 16 bits).
*/
uint32_t maxRefForL0 = std::min(capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForP,
capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForB);
uint32_t maxRefForL1 = capPictureControlData.PictureSupport.pH264Support->MaxL1ReferencesForB;
supportedMaxRefFrames = (maxRefForL0 & 0xffff) | ((maxRefForL1 & 0xffff) << 16);
}
} else if(codec == D3D12_VIDEO_ENCODER_CODEC_HEVC) {
D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevcPictureControl = {};
capPictureControlData.Profile = profile;
capPictureControlData.PictureSupport.pHEVCSupport = &hevcPictureControl;
capPictureControlData.PictureSupport.DataSize = sizeof(hevcPictureControl);
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
&capPictureControlData,
sizeof(capPictureControlData));
if (FAILED(hr)) {
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
}
if (capPictureControlData.IsSupported) {
/* This attribute determines the maximum number of reference
* frames supported for encoding.
*
* Note: for H.265 encoding, the value represents the maximum number
* of reference frames for both the reference picture list 0 (bottom
* 16 bits) and the reference picture list 1 (top 16 bits).
*/
uint32_t maxRefForL0 = std::min(capPictureControlData.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
capPictureControlData.PictureSupport.pHEVCSupport->MaxL0ReferencesForB);
uint32_t maxRefForL1 = capPictureControlData.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
supportedMaxRefFrames = (maxRefForL0 & 0xffff) | ((maxRefForL1 & 0xffff) << 16);
}
} }
return supportedMaxRefFrames; return supportedMaxRefFrames;
@ -247,8 +292,8 @@ d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_E
static uint32_t static uint32_t
d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &codec, d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
D3D12_VIDEO_ENCODER_PROFILE_H264 profile, D3D12_VIDEO_ENCODER_PROFILE_DESC profile,
D3D12_VIDEO_ENCODER_LEVELS_H264 level, D3D12_VIDEO_ENCODER_LEVEL_SETTING level,
ID3D12VideoDevice3 *pD3D12VideoDevice) ID3D12VideoDevice3 *pD3D12VideoDevice)
{ {
uint32_t supportedSliceStructuresBitMask = PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE; uint32_t supportedSliceStructuresBitMask = PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE;
@ -256,10 +301,8 @@ d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &c
D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = {}; D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = {};
capDataSubregionLayout.NodeIndex = 0; capDataSubregionLayout.NodeIndex = 0;
capDataSubregionLayout.Codec = codec; capDataSubregionLayout.Codec = codec;
capDataSubregionLayout.Profile.pH264Profile = &profile; capDataSubregionLayout.Profile = profile;
capDataSubregionLayout.Profile.DataSize = sizeof(profile); capDataSubregionLayout.Level = level;
capDataSubregionLayout.Level.pH264LevelSetting = &level;
capDataSubregionLayout.Level.DataSize = sizeof(level);
/** /**
* pipe_video_cap_slice_structure * pipe_video_cap_slice_structure
@ -273,6 +316,10 @@ d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &c
* determines the range of accepted values to * determines the range of accepted values to
* h264_slice_descriptor::macroblock_address and * h264_slice_descriptor::macroblock_address and
* h264_slice_descriptor::num_macroblocks. * h264_slice_descriptor::num_macroblocks.
*
* For HEVC, similarly determines the ranges for
* slice_segment_address
* num_ctu_in_slice
*/ */
capDataSubregionLayout.SubregionMode = capDataSubregionLayout.SubregionMode =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME; D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
@ -331,7 +378,8 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution, D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution,
DXGI_FORMAT encodeFormat, DXGI_FORMAT encodeFormat,
uint32_t &outMaxSlices, uint32_t &outMaxSlices,
ID3D12VideoDevice3 *pD3D12VideoDevice) ID3D12VideoDevice3 *pD3D12VideoDevice,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codecSupport)
{ {
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {}; D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
capEncoderSupportData.NodeIndex = 0; capEncoderSupportData.NodeIndex = 0;
@ -351,13 +399,22 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
capEncoderSupportData.SubregionFrameEncoding = capEncoderSupportData.SubregionFrameEncoding =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME; D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
/*
All codec structures must be declared outside the switch statement to be
present in memory (stack scope) when calling CheckFeatureSupport below
*/
D3D12_VIDEO_ENCODER_PROFILE_H264 h264prof = {}; D3D12_VIDEO_ENCODER_PROFILE_H264 h264prof = {};
D3D12_VIDEO_ENCODER_LEVELS_H264 h264lvl = {}; D3D12_VIDEO_ENCODER_LEVELS_H264 h264lvl = {};
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 h264Gop = { 1, 0, 0, 0, 0 }; D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 h264Gop = { 1, 0, 0, 0, 0 };
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 h264Config = {}; D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 h264Config = {};
D3D12_VIDEO_ENCODER_PROFILE_HEVC hevcprof = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevcLvl = { D3D12_VIDEO_ENCODER_LEVELS_HEVC_62, D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH };
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC hevcGop = { 1, 0, 0 };
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC hevcConfig = {};
switch (argTargetCodec) { switch (argTargetCodec) {
case D3D12_VIDEO_ENCODER_CODEC_H264: case D3D12_VIDEO_ENCODER_CODEC_H264:
{ {
// assert(codecSupport.pH264Support); // Fill this in caller if ever used
capEncoderSupportData.SuggestedProfile.pH264Profile = &h264prof; capEncoderSupportData.SuggestedProfile.pH264Profile = &h264prof;
capEncoderSupportData.SuggestedProfile.DataSize = sizeof(h264prof); capEncoderSupportData.SuggestedProfile.DataSize = sizeof(h264prof);
capEncoderSupportData.SuggestedLevel.pH264LevelSetting = &h264lvl; capEncoderSupportData.SuggestedLevel.pH264LevelSetting = &h264lvl;
@ -368,6 +425,29 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
capEncoderSupportData.CodecConfiguration.pH264Config = &h264Config; capEncoderSupportData.CodecConfiguration.pH264Config = &h264Config;
} break; } break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
{
/* Only read from codecSupport.pHEVCSupport in this case (union of pointers definition) */
assert(codecSupport.pHEVCSupport);
hevcConfig = {
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE,
codecSupport.pHEVCSupport->MinLumaCodingUnitSize,
codecSupport.pHEVCSupport->MaxLumaCodingUnitSize,
codecSupport.pHEVCSupport->MinLumaTransformUnitSize,
codecSupport.pHEVCSupport->MaxLumaTransformUnitSize,
codecSupport.pHEVCSupport->max_transform_hierarchy_depth_inter,
codecSupport.pHEVCSupport->max_transform_hierarchy_depth_intra,
};
capEncoderSupportData.SuggestedProfile.pHEVCProfile = &hevcprof;
capEncoderSupportData.SuggestedProfile.DataSize = sizeof(hevcprof);
capEncoderSupportData.SuggestedLevel.pHEVCLevelSetting = &hevcLvl;
capEncoderSupportData.SuggestedLevel.DataSize = sizeof(hevcLvl);
capEncoderSupportData.CodecGopSequence.pHEVCGroupOfPictures = &hevcGop;
capEncoderSupportData.CodecGopSequence.DataSize = sizeof(hevcGop);
capEncoderSupportData.CodecConfiguration.DataSize = sizeof(hevcConfig);
capEncoderSupportData.CodecConfiguration.pHEVCConfig = &hevcConfig;
} break;
default: default:
{ {
unreachable("Unsupported D3D12_VIDEO_ENCODER_CODEC"); unreachable("Unsupported D3D12_VIDEO_ENCODER_CODEC");
@ -394,6 +474,86 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
} }
} }
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC
static d3d12_video_encode_get_hevc_codec_support ( const D3D12_VIDEO_ENCODER_CODEC &argCodec,
const D3D12_VIDEO_ENCODER_PROFILE_DESC &argTargetProfile,
ID3D12VideoDevice3 *pD3D12VideoDevice)
{
constexpr unsigned c_hevcConfigurationSets = 5u;
const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC hevcConfigurationSets[c_hevcConfigurationSets] =
{
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32,
3u,
3u,
},
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32,
0u,
0u,
},
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32,
2u,
2u,
},
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32,
2u,
2u,
},
{
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4,
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32,
4u,
4u,
},
};
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC hevcCodecCaps = { };
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
capCodecConfigData.NodeIndex = 0;
capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
capCodecConfigData.Profile = argTargetProfile;
capCodecConfigData.CodecSupportLimits.pHEVCSupport = &hevcCodecCaps;
capCodecConfigData.CodecSupportLimits.DataSize = sizeof(hevcCodecCaps);
for (auto hevc_config : hevcConfigurationSets) {
hevcCodecCaps = hevc_config;
if(SUCCEEDED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData))
&& capCodecConfigData.IsSupported)) {
hevc_config.SupportFlags = hevcCodecCaps.SupportFlags;
return hevc_config;
}
}
/* If we reach this point, the underlying HW/Driver might need a new configuration
added to the table and be iterated above */
unreachable("D3D12: Couldn't find HEVC supported configuration arguments.");
return hevcCodecCaps;
}
static bool static bool
d3d12_has_video_encode_support(struct pipe_screen *pscreen, d3d12_has_video_encode_support(struct pipe_screen *pscreen,
enum pipe_video_profile profile, enum pipe_video_profile profile,
@ -401,7 +561,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC &maxRes, D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC &maxRes,
uint32_t &maxSlices, uint32_t &maxSlices,
uint32_t &supportedSliceStructures, uint32_t &supportedSliceStructures,
uint32_t &maxReferencesPerFrame) uint32_t &maxReferencesPerFrame,
struct d3d12_encode_codec_support& codecSupport)
{ {
ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice; ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
@ -416,7 +577,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
sizeof(VideoFeatureAreaSupport)))) { sizeof(VideoFeatureAreaSupport)))) {
return false; return false;
} }
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT d3d12_codec_support = { };
bool supportsProfile = false; bool supportsProfile = false;
switch (profile) { switch (profile) {
case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE: case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
@ -458,18 +619,174 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
maxRes, maxRes,
encodeFormat, encodeFormat,
maxSlices, maxSlices,
spD3D12VideoDevice.Get()); spD3D12VideoDevice.Get(),
d3d12_codec_support);
D3D12_VIDEO_ENCODER_PROFILE_DESC profile;
profile.pH264Profile = &profH264;
profile.DataSize = sizeof(profH264);
D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
level.pH264LevelSetting = &maxLvlSettingH264;
level.DataSize = sizeof(maxLvlSettingH264);
supportedSliceStructures = d3d12_video_encode_supported_slice_structures(codecDesc, supportedSliceStructures = d3d12_video_encode_supported_slice_structures(codecDesc,
profH264, profile,
maxLvlSettingH264, level,
spD3D12VideoDevice.Get()); spD3D12VideoDevice.Get());
maxReferencesPerFrame = maxReferencesPerFrame =
d3d12_video_encode_supported_references_per_frame_structures(codecDesc, d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
profH264, profile,
maxLvlSettingH264,
spD3D12VideoDevice.Get()); spD3D12VideoDevice.Get());
} }
} break; } break;
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
{
supportsProfile = true;
D3D12_VIDEO_ENCODER_PROFILE_DESC profDesc = {};
D3D12_VIDEO_ENCODER_PROFILE_HEVC profHEVC =
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(profile);
profDesc.DataSize = sizeof(profHEVC);
profDesc.pHEVCProfile = &profHEVC;
D3D12_VIDEO_ENCODER_CODEC codecDesc = d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(profile);
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC minLvlSettingHEVC = { };
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC maxLvlSettingHEVC = { };
D3D12_VIDEO_ENCODER_LEVEL_SETTING minLvl = {};
D3D12_VIDEO_ENCODER_LEVEL_SETTING maxLvl = {};
minLvl.pHEVCLevelSetting = &minLvlSettingHEVC;
minLvl.DataSize = sizeof(minLvlSettingHEVC);
maxLvl.pHEVCLevelSetting = &maxLvlSettingHEVC;
maxLvl.DataSize = sizeof(maxLvlSettingHEVC);
if (d3d12_video_encode_max_supported_level_for_profile(codecDesc,
profDesc,
minLvl,
maxLvl,
spD3D12VideoDevice.Get())) {
d3d12_video_encoder_convert_from_d3d12_level_hevc(maxLvlSettingHEVC.Level, maxLvlSpec);
supportsProfile = true;
}
if (supportsProfile) {
D3D12_VIDEO_ENCODER_PROFILE_DESC d3d12_profile;
d3d12_profile.pHEVCProfile = &profHEVC;
d3d12_profile.DataSize = sizeof(profHEVC);
D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
level.pHEVCLevelSetting = &maxLvlSettingHEVC;
level.DataSize = sizeof(maxLvlSettingHEVC);
supportedSliceStructures = d3d12_video_encode_supported_slice_structures(codecDesc,
d3d12_profile,
level,
spD3D12VideoDevice.Get());
maxReferencesPerFrame =
d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
d3d12_profile,
spD3D12VideoDevice.Get());
codecSupport.hevc_support.d3d12_caps = d3d12_video_encode_get_hevc_codec_support(codecDesc,
profDesc,
spD3D12VideoDevice.Get());
d3d12_codec_support.DataSize = sizeof(codecSupport.hevc_support.d3d12_caps);
d3d12_codec_support.pHEVCSupport = &codecSupport.hevc_support.d3d12_caps;
/* get_video_param sets pipe_features.bits.config_supported = 1
to distinguish between supported cap with all bits off and unsupported by driver
with value = 0
*/
codecSupport.hevc_support.hevc_block_sizes.bits.config_supported = 1;
codecSupport.hevc_support.hevc_features.bits.config_supported = 1;
// Fill codecSupport.hevc_support
uint8_t minCuSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(codecSupport.hevc_support.d3d12_caps.MinLumaCodingUnitSize);
uint8_t maxCuSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(codecSupport.hevc_support.d3d12_caps.MaxLumaCodingUnitSize);
uint8_t MinCbLog2SizeY = std::log2(minCuSize);
uint8_t CtbLog2SizeY = std::log2(maxCuSize);
uint8_t minTuSize = d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(codecSupport.hevc_support.d3d12_caps.MinLumaTransformUnitSize);
uint8_t maxTuSize = d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(codecSupport.hevc_support.d3d12_caps.MaxLumaTransformUnitSize);
codecSupport.hevc_support.hevc_block_sizes.bits.log2_max_coding_tree_block_size_minus3
= static_cast<uint8_t>(CtbLog2SizeY - 3);
codecSupport.hevc_support.hevc_block_sizes.bits.log2_min_coding_tree_block_size_minus3
= static_cast<uint8_t>(CtbLog2SizeY - 3);
codecSupport.hevc_support.hevc_block_sizes.bits.log2_min_luma_coding_block_size_minus3
= static_cast<uint8_t>(MinCbLog2SizeY - 3);
codecSupport.hevc_support.hevc_block_sizes.bits.log2_max_luma_transform_block_size_minus2
= static_cast<uint8_t>(std::log2(maxTuSize) - 2);
codecSupport.hevc_support.hevc_block_sizes.bits.log2_min_luma_transform_block_size_minus2
= static_cast<uint8_t>(std::log2(minTuSize) - 2);
codecSupport.hevc_support.hevc_block_sizes.bits.max_max_transform_hierarchy_depth_inter
= codecSupport.hevc_support.d3d12_caps.max_transform_hierarchy_depth_inter;
codecSupport.hevc_support.hevc_block_sizes.bits.min_max_transform_hierarchy_depth_inter
= codecSupport.hevc_support.d3d12_caps.max_transform_hierarchy_depth_inter;
codecSupport.hevc_support.hevc_block_sizes.bits.max_max_transform_hierarchy_depth_intra
= codecSupport.hevc_support.d3d12_caps.max_transform_hierarchy_depth_intra;
codecSupport.hevc_support.hevc_block_sizes.bits.min_max_transform_hierarchy_depth_intra
= codecSupport.hevc_support.d3d12_caps.max_transform_hierarchy_depth_intra;
codecSupport.hevc_support.hevc_block_sizes.bits.log2_max_pcm_coding_block_size_minus3 = 0; // No PCM Supported
codecSupport.hevc_support.hevc_block_sizes.bits.log2_min_pcm_coding_block_size_minus3 = 0; // No PCM Supported
// Feature flags
uint32_t ref_l0 = maxReferencesPerFrame & 0xffff;
uint32_t ref_l1 = maxReferencesPerFrame >> 16 & 0xffff;
codecSupport.hevc_support.prediction_direction = PIPE_H265_PRED_DIRECTION_ALL;
if(ref_l0)
codecSupport.hevc_support.prediction_direction |= PIPE_H265_PRED_DIRECTION_PREVIOUS;
if(ref_l1)
codecSupport.hevc_support.prediction_direction |= PIPE_H265_PRED_DIRECTION_FUTURE;
codecSupport.hevc_support.hevc_features.bits.separate_colour_planes = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.scaling_lists = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.pcm = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.temporal_mvp = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.strong_intra_smoothing = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.dependent_slices = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.sign_data_hiding = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.weighted_prediction = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.transquant_bypass = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
codecSupport.hevc_support.hevc_features.bits.deblocking_filter_disable = PIPE_H265_ENC_FEATURE_NOT_SUPPORTED;
/* cu_qp_delta always required to be 1 in https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md */
codecSupport.hevc_support.hevc_features.bits.cu_qp_delta = (PIPE_H265_ENC_FEATURE_SUPPORTED | PIPE_H265_ENC_FEATURE_REQUIRED);
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_P_FRAMES_IMPLEMENTED_AS_LOW_DELAY_B_FRAMES) != 0)
codecSupport.hevc_support.prediction_direction |= PIPE_H265_PRED_DIRECTION_BI_NOT_EMPTY;
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT) != 0)
codecSupport.hevc_support.hevc_features.bits.amp = PIPE_H265_ENC_FEATURE_SUPPORTED;
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0)
codecSupport.hevc_support.hevc_features.bits.amp = (PIPE_H265_ENC_FEATURE_SUPPORTED | PIPE_H265_ENC_FEATURE_REQUIRED);
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) != 0)
codecSupport.hevc_support.hevc_features.bits.sao = PIPE_H265_ENC_FEATURE_SUPPORTED;
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_CONSTRAINED_INTRAPREDICTION_SUPPORT) != 0)
codecSupport.hevc_support.hevc_features.bits.constrained_intra_pred = PIPE_H265_ENC_FEATURE_SUPPORTED;
if ((codecSupport.hevc_support.d3d12_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) != 0)
codecSupport.hevc_support.hevc_features.bits.transform_skip = PIPE_H265_ENC_FEATURE_SUPPORTED;
DXGI_FORMAT encodeFormat = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
supportsProfile = supportsProfile &&
d3d12_video_encode_max_supported_resolution(codecDesc, maxRes, spD3D12VideoDevice.Get());
supportsProfile = supportsProfile && d3d12_video_encode_max_supported_slices(codecDesc,
maxRes,
encodeFormat,
maxSlices,
spD3D12VideoDevice.Get(),
d3d12_codec_support);
}
} break;
default: default:
supportsProfile = false; supportsProfile = false;
} }
@ -716,6 +1033,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
uint32_t maxSlices = 0u; uint32_t maxSlices = 0u;
uint32_t supportedSliceStructures = 0u; uint32_t supportedSliceStructures = 0u;
uint32_t maxReferencesPerFrame = 0u; uint32_t maxReferencesPerFrame = 0u;
struct d3d12_encode_codec_support codec_specific_support;
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
switch (param) { switch (param) {
case PIPE_VIDEO_CAP_NPOT_TEXTURES: case PIPE_VIDEO_CAP_NPOT_TEXTURES:
return 1; return 1;
@ -726,6 +1045,9 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
case PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME: case PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME:
case PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE: case PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE:
case PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME: case PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME:
case PIPE_VIDEO_CAP_ENC_HEVC_FEATURE_FLAGS:
case PIPE_VIDEO_CAP_ENC_HEVC_BLOCK_SIZES:
case PIPE_VIDEO_CAP_ENC_HEVC_PREDICTION_DIRECTION:
{ {
if (d3d12_has_video_encode_support(pscreen, if (d3d12_has_video_encode_support(pscreen,
profile, profile,
@ -733,21 +1055,42 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
maxResEncode, maxResEncode,
maxSlices, maxSlices,
supportedSliceStructures, supportedSliceStructures,
maxReferencesPerFrame)) { maxReferencesPerFrame,
if (param == PIPE_VIDEO_CAP_MAX_WIDTH) { codec_specific_support)) {
return maxResEncode.Width;
} else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) { DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
return maxResEncode.Height; auto pipeFmt = d3d12_get_pipe_format(format);
} else if (param == PIPE_VIDEO_CAP_MAX_LEVEL) { bool formatSupported = pscreen->is_video_format_supported(pscreen, pipeFmt, profile, entrypoint);
return maxLvlEncode; if (formatSupported) {
} else if (param == PIPE_VIDEO_CAP_SUPPORTED) { if (param == PIPE_VIDEO_CAP_MAX_WIDTH) {
return 1; return maxResEncode.Width;
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME) { } else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) {
return maxSlices; return maxResEncode.Height;
} else if (param == PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE) { } else if (param == PIPE_VIDEO_CAP_MAX_LEVEL) {
return supportedSliceStructures; return maxLvlEncode;
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME) { } else if (param == PIPE_VIDEO_CAP_SUPPORTED) {
return maxReferencesPerFrame; return 1;
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME) {
return maxSlices;
} else if (param == PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE) {
return supportedSliceStructures;
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME) {
return maxReferencesPerFrame;
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_FEATURE_FLAGS) {
/* get_video_param sets hevc_features.bits.config_supported = 1
to distinguish between supported cap with all bits off and unsupported by driver
with value = 0
*/
return codec_specific_support.hevc_support.hevc_features.value;
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_BLOCK_SIZES) {
/* get_video_param sets hevc_block_sizes.bits.config_supported = 1
to distinguish between supported cap with all bits off and unsupported by driver
with value = 0
*/
return codec_specific_support.hevc_support.hevc_block_sizes.value;
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_PREDICTION_DIRECTION) {
return codec_specific_support.hevc_support.prediction_direction;
}
} }
} }
return 0; return 0;

View file

@ -99,6 +99,7 @@ enum d3d12_video_decode_profile_type
{ {
d3d12_video_decode_profile_type_none, d3d12_video_decode_profile_type_none,
d3d12_video_decode_profile_type_h264, d3d12_video_decode_profile_type_h264,
d3d12_video_decode_profile_type_hevc,
d3d12_video_decode_profile_type_max_valid d3d12_video_decode_profile_type_max_valid
}; };
@ -125,11 +126,27 @@ void
d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12, d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H264 level12,
uint32_t & specLevel, uint32_t & specLevel,
uint32_t & constraint_set3_flag); uint32_t & constraint_set3_flag);
void
d3d12_video_encoder_convert_from_d3d12_level_hevc(D3D12_VIDEO_ENCODER_LEVELS_HEVC level12,
uint32_t & specLevel);
D3D12_VIDEO_ENCODER_PROFILE_H264 D3D12_VIDEO_ENCODER_PROFILE_H264
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile); d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile);
D3D12_VIDEO_ENCODER_PROFILE_HEVC
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile);
D3D12_VIDEO_ENCODER_CODEC D3D12_VIDEO_ENCODER_CODEC
d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile); d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile);
GUID GUID
d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(enum pipe_video_profile profile); d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(enum pipe_video_profile profile);
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE
d3d12_video_encoder_convert_pixel_size_hevc_to_12tusize(const uint32_t& TUSize);
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE
d3d12_video_encoder_convert_pixel_size_hevc_to_12cusize(const uint32_t& cuSize);
uint8_t
d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE& cuSize);
uint8_t
d3d12_video_encoder_convert_12tusize_to_pixel_size_hevc(const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE& TUSize);
DEFINE_ENUM_FLAG_OPERATORS(pipe_h265_enc_feature);
DEFINE_ENUM_FLAG_OPERATORS(pipe_h265_enc_pred_direction);
#endif #endif

View file

@ -63,6 +63,11 @@ if with_gallium_d3d12_video
'd3d12_video_array_of_textures_dpb_manager.cpp', 'd3d12_video_array_of_textures_dpb_manager.cpp',
'd3d12_video_screen.cpp', 'd3d12_video_screen.cpp',
'd3d12_video_proc.cpp', 'd3d12_video_proc.cpp',
'd3d12_video_dec_hevc.cpp',
'd3d12_video_enc_hevc.cpp',
'd3d12_video_encoder_bitstream_builder_hevc.cpp',
'd3d12_video_encoder_nalu_writer_hevc.cpp',
'd3d12_video_encoder_references_manager_hevc.cpp',
] ]
endif endif
@ -80,5 +85,5 @@ libd3d12 = static_library(
driver_d3d12 = declare_dependency( driver_d3d12 = declare_dependency(
compile_args : '-DGALLIUM_D3D12', compile_args : '-DGALLIUM_D3D12',
link_with : [libd3d12], link_with : [libd3d12, libgalliumvl],
) )

View file

@ -40,7 +40,7 @@ libgallium_wgl = shared_library(
], ],
link_whole : [libwgl], link_whole : [libwgl],
link_with : [ link_with : [
libgallium, libglsl, libmesa, libwsgdi, libglapi_static, libglapi libgallium, libglsl, libmesa, libwsgdi, libglapi_static, libglapi, libgalliumvl
], ],
dependencies : [ dependencies : [
dep_ws2_32, idep_nir, idep_mesautil, driver_swrast, dep_ws2_32, idep_nir, idep_mesautil, driver_swrast,