d3d12: Use lower size estimations for compressed output bitstream sizes

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37565>
This commit is contained in:
Silvio Vilerino 2025-09-24 15:05:23 -04:00 committed by Marge Bot
parent 0395dca6d6
commit b2b009fc29
3 changed files with 66 additions and 4 deletions

View file

@ -2402,6 +2402,55 @@ d3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc
return true;
}
// Helper function to calculate the max output bitstream size based on width, height, and format
// This function uses an approach based on common video formats and their typical compression ratios
inline
UINT d3d12_video_encoder_calculate_max_output_compressed_bitstream_size(
UINT uiWidth,
UINT uiHeight,
DXGI_FORMAT format
)
{
assert((uiHeight > 16) &&
(uiWidth > 16) &&
(format != DXGI_FORMAT_UNKNOWN));
const UINT MIN_BUFFER_SIZE = 128 * 128 * 2; // Minimum buffer size for very small frames: 128x128 pixels at 2 bytes/pixel
const UINT MAX_BUFFER_SIZE = 20 * 1024 * 1024; // Maximum buffer size of 20MB
const float EXPECTED_COMPRESSION_FACTOR = 2.0f; // Assume 50% of calculated size after compression of raw pixel sizes
UINT alignedWidth = (uiWidth + 15) & ~15;
UINT alignedHeight = (uiHeight + 15) & ~15;
UINT bufferSize = 0;
switch (format) {
case DXGI_FORMAT_NV12:
// NV12: Y plane (1 byte/pixel) + UV plane (1/2 byte/pixel) = 1.5 bytes/pixel
bufferSize = alignedWidth * alignedHeight * 3 / 2;
break;
case DXGI_FORMAT_P010:
// P010: Y plane (2 bytes/pixel) + UV plane (1 byte/pixel) = 3 bytes/pixel
bufferSize = alignedWidth * alignedHeight * 3;
break;
case DXGI_FORMAT_AYUV:
// AYUV: 4 bytes/pixel
bufferSize = alignedWidth * alignedHeight * 4;
break;
default:
// Fallback formula for other formats: assume 15 bits/pixel (1.875 bytes/pixel)
bufferSize = (((alignedHeight) * (alignedWidth) * 15) >> 3);
break;
}
// Apply EXPECTED_COMPRESSION_FACTOR constant (% of calculated size)
bufferSize = static_cast<UINT>(std::ceil(bufferSize / EXPECTED_COMPRESSION_FACTOR));
// Clamp buffer size between minimum and maximum limits
bufferSize = std::max(MIN_BUFFER_SIZE, std::min(bufferSize, MAX_BUFFER_SIZE));
return bufferSize;
}
struct pipe_video_codec *
d3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pipe_video_codec *codec)
{
@ -2445,6 +2494,20 @@ d3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pi
goto failed;
}
pD3D12Enc->m_MaxOutputBitstreamSize = d3d12_video_encoder_calculate_max_output_compressed_bitstream_size(
codec->width,
codec->height,
d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile)
);
debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_encoder - Calculated max output bitstream size: %u bytes (%u Kb, %u Mb) for %ux%u DXGI_FORMAT %u\n",
pD3D12Enc->m_MaxOutputBitstreamSize,
pD3D12Enc->m_MaxOutputBitstreamSize / 1024,
pD3D12Enc->m_MaxOutputBitstreamSize / (1024 * 1024),
codec->width,
codec->height,
static_cast<UINT>(d3d12_convert_pipe_video_profile_to_dxgi_format(pD3D12Enc->base.profile)));
if (!d3d12_video_encoder_create_command_objects(pD3D12Enc)) {
debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_encoder - Failure on "
"d3d12_video_encoder_create_command_objects\n");
@ -3225,7 +3288,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec,
pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstreams[0/*first slice*/];
} else if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstreams[slice_idx] == nullptr) {
D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(D3D12_DEFAULT_COMPBIT_STAGING_SIZE);
CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(pD3D12Enc->m_MaxOutputBitstreamSize);
HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
&Properties,
D3D12_HEAP_FLAG_NONE,
@ -4356,7 +4419,7 @@ d3d12_video_encoder_get_feedback(struct pipe_video_codec *codec,
templ.target = PIPE_BUFFER;
templ.usage = PIPE_USAGE_DEFAULT;
templ.format = PIPE_FORMAT_R8_UINT;
templ.width0 = D3D12_DEFAULT_COMPBIT_STAGING_SIZE;
templ.width0 = pD3D12Enc->m_MaxOutputBitstreamSize;
templ.height0 = 1;
templ.depth0 = 1;
templ.array_size = 1;

View file

@ -574,6 +574,7 @@ struct d3d12_video_encoder
const uint m_NodeMask = 0u;
const uint m_NodeIndex = 0u;
UINT m_MaxOutputBitstreamSize = 0;
ComPtr<ID3D12Fence> m_spFence;
uint64_t m_fenceValue = 1u;

View file

@ -75,8 +75,6 @@ const size_t D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT = static_cast<size_t>(debug_
constexpr unsigned int D3D12_VIDEO_H264_MB_IN_PIXELS = 16;
constexpr size_t D3D12_DEFAULT_COMPBIT_STAGING_SIZE = (1024 /*1K*/ * 1024/*1MB*/) * 8/*8 MB*/; // 8MB
/* If enabled, the D3D12 AV1 encoder will use always ...CONFIGURABLE_GRID_PARTITION mode */
/* If disabled, the D3D12 AV1 encoder will try to use ...UNIFORM_GRID_PARTITION first and then fallback to ...CONFIGURABLE_GRID_PARTITION if not possible */
const bool D3D12_VIDEO_FORCE_TILE_MODE = debug_get_bool_option("D3D12_VIDEO_FORCE_TILE_MODE", false);