blob: c70334ac557f6baca8334c6d53f42dcb7f98f64c [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Video Decoding Base Classe Functionality
*//*--------------------------------------------------------------------*/
/*
* Copyright 2020 NVIDIA Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "vktVideoBaseDecodeUtils.hpp"
#include "tcuPlatform.hpp"
#include "vkDefs.hpp"
#include "vkQueryUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkStrUtil.hpp"
#include "deRandom.hpp"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <random>
namespace vkt
{
namespace video
{
using namespace vk;
using namespace std;
using de::MovePtr;
using de::SharedPtr;
static const deUint32 topFieldShift = 0;
static const deUint32 topFieldMask = (1 << topFieldShift);
static const deUint32 bottomFieldShift = 1;
static const deUint32 bottomFieldMask = (1 << bottomFieldShift);
static const deUint32 fieldIsReferenceMask = (topFieldMask | bottomFieldMask);
#define HEVC_MAX_DPB_SLOTS 16
#define AVC_MAX_DPB_SLOTS 17
inline vkPicBuffBase *GetPic(VkPicIf *pPicBuf)
{
return (vkPicBuffBase *) pPicBuf;
}
inline VkVideoChromaSubsamplingFlagBitsKHR ConvertStdH264ChromaFormatToVulkan(StdVideoH264ChromaFormatIdc stdFormat)
{
switch (stdFormat)
{
case STD_VIDEO_H264_CHROMA_FORMAT_IDC_420:
return VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
case STD_VIDEO_H264_CHROMA_FORMAT_IDC_422:
return VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
case STD_VIDEO_H264_CHROMA_FORMAT_IDC_444:
return VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
default:
TCU_THROW(InternalError, "Invalid chroma sub-sampling format");
}
}
VkFormat codecGetVkFormat(VkVideoChromaSubsamplingFlagBitsKHR chromaFormatIdc,
int bitDepthLuma,
bool isSemiPlanar)
{
switch (chromaFormatIdc)
{
case VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR:
{
switch (bitDepthLuma)
{
case VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR:
return VK_FORMAT_R8_UNORM;
case VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR:
return VK_FORMAT_R10X6_UNORM_PACK16;
case VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR:
return VK_FORMAT_R12X4_UNORM_PACK16;
default:
TCU_THROW(InternalError, "Cannot map monochrome format to VkFormat");
}
}
case VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR:
{
switch (bitDepthLuma)
{
case VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G8_B8R8_2PLANE_420_UNORM : VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
case VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 : VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16);
case VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 : VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16);
default:
TCU_THROW(InternalError, "Cannot map 420 format to VkFormat");
}
}
case VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR:
{
switch (bitDepthLuma)
{
case VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G8_B8R8_2PLANE_422_UNORM : VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM);
case VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 : VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16);
case VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 : VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16);
default:
TCU_THROW(InternalError, "Cannot map 422 format to VkFormat");
}
}
case VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR:
{
switch (bitDepthLuma)
{
case VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT : VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM);
case VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT : VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16);
case VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR:
return (isSemiPlanar ? VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT : VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16);
default:
TCU_THROW(InternalError, "Cannot map 444 format to VkFormat");
}
}
default:
TCU_THROW(InternalError, "Unknown input idc format");
}
}
VkVideoComponentBitDepthFlagsKHR getLumaBitDepth(deUint8 lumaBitDepthMinus8)
{
switch (lumaBitDepthMinus8)
{
case 0:
return VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
case 2:
return VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
case 4:
return VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
default:
TCU_THROW(InternalError, "Unhandler lumaBitDepthMinus8");
}
}
VkVideoComponentBitDepthFlagsKHR getChromaBitDepth(deUint8 chromaBitDepthMinus8)
{
switch (chromaBitDepthMinus8)
{
case 0:
return VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
case 2:
return VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
case 4:
return VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
default:
TCU_THROW(InternalError, "Unhandler chromaBitDepthMinus8");
}
}
void setImageLayout(const DeviceInterface &vkd,
VkCommandBuffer cmdBuffer,
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags2KHR srcStages,
VkPipelineStageFlags2KHR dstStages,
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT)
{
VkAccessFlags2KHR srcAccessMask = 0;
VkAccessFlags2KHR dstAccessMask = 0;
switch (static_cast<VkImageLayout>(oldImageLayout))
{
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR:
srcAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR;
break;
default:
srcAccessMask = 0;
break;
}
switch (static_cast<VkImageLayout>(newImageLayout))
{
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR:
dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR;
break;
case VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR:
dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR;
break;
case VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR:
dstAccessMask = VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR;
break;
case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR:
dstAccessMask = VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR | VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR;
break;
case VK_IMAGE_LAYOUT_GENERAL:
dstAccessMask = VK_ACCESS_HOST_WRITE_BIT;
break;
default:
dstAccessMask = 0;
break;
}
const VkImageMemoryBarrier2KHR imageMemoryBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
srcStages, // VkPipelineStageFlags2KHR srcStageMask;
srcAccessMask, // VkAccessFlags2KHR srcAccessMask;
dstStages, // VkPipelineStageFlags2KHR dstStageMask;
dstAccessMask, // VkAccessFlags2KHR dstAccessMask;
oldImageLayout, // VkImageLayout oldLayout;
newImageLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
image, // VkImage image;
{aspectMask, 0, 1, 0, 1}, // VkImageSubresourceRange subresourceRange;
};
const VkDependencyInfoKHR dependencyInfo =
{
VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
0, // deUint32 memoryBarrierCount;
DE_NULL, // const VkMemoryBarrier2KHR* pMemoryBarriers;
0, // deUint32 bufferMemoryBarrierCount;
DE_NULL, // const VkBufferMemoryBarrier2KHR* pBufferMemoryBarriers;
1, // deUint32 imageMemoryBarrierCount;
&imageMemoryBarrier, // const VkImageMemoryBarrier2KHR* pImageMemoryBarriers;
};
vkd.cmdPipelineBarrier2(cmdBuffer, &dependencyInfo);
}
typedef struct dpbH264Entry {
int8_t dpbSlot;
// bit0(used_for_reference)=1: top field used for reference,
// bit1(used_for_reference)=1: bottom field used for reference
deUint32 used_for_reference : 2;
deUint32 is_long_term : 1; // 0 = short-term, 1 = long-term
deUint32 is_non_existing : 1; // 1 = marked as non-existing
deUint32 is_field_ref : 1; // set if unpaired field or complementary field pair
union {
int16_t FieldOrderCnt[2]; // h.264 : 2*32 [top/bottom].
int32_t PicOrderCnt; // HEVC PicOrderCnt
};
union {
int16_t FrameIdx; // : 16 short-term: FrameNum (16 bits), long-term:
// LongTermFrameIdx (4 bits)
int8_t originalDpbIndex; // Original Dpb source Index.
};
vkPicBuffBase* m_picBuff; // internal picture reference
void setReferenceAndTopBottomField(
bool isReference, bool nonExisting, bool isLongTerm, bool isFieldRef,
bool topFieldIsReference, bool bottomFieldIsReference, int16_t frameIdx,
const int16_t fieldOrderCntList[2], vkPicBuffBase* picBuff)
{
is_non_existing = nonExisting;
is_long_term = isLongTerm;
is_field_ref = isFieldRef;
if (isReference && isFieldRef) {
used_for_reference = (bottomFieldIsReference << bottomFieldShift) | (topFieldIsReference << topFieldShift);
} else {
used_for_reference = isReference ? 3 : 0;
}
FrameIdx = frameIdx;
FieldOrderCnt[0] = fieldOrderCntList[used_for_reference == 2]; // 0: for progressive and top reference; 1: for
// bottom reference only.
FieldOrderCnt[1] = fieldOrderCntList[used_for_reference != 1]; // 0: for top reference only; 1: for bottom
// reference and progressive.
dpbSlot = -1;
m_picBuff = picBuff;
}
void setReference(bool isLongTerm, int32_t picOrderCnt,
vkPicBuffBase* picBuff)
{
is_non_existing = (picBuff == NULL);
is_long_term = isLongTerm;
is_field_ref = false;
used_for_reference = (picBuff != NULL) ? 3 : 0;
PicOrderCnt = picOrderCnt;
dpbSlot = -1;
m_picBuff = picBuff;
originalDpbIndex = -1;
}
bool isRef() { return (used_for_reference != 0); }
StdVideoDecodeH264ReferenceInfoFlags getPictureFlag(bool currentPictureIsProgressive)
{
StdVideoDecodeH264ReferenceInfoFlags picFlags = StdVideoDecodeH264ReferenceInfoFlags();
if (videoLoggingEnabled())
std::cout << "\t\t Flags: ";
if (used_for_reference) {
if (videoLoggingEnabled())
std::cout << "FRAME_IS_REFERENCE ";
// picFlags.is_reference = true;
}
if (is_long_term) {
if (videoLoggingEnabled())
std::cout << "IS_LONG_TERM ";
picFlags.used_for_long_term_reference = true;
}
if (is_non_existing) {
if (videoLoggingEnabled())
std::cout << "IS_NON_EXISTING ";
picFlags.is_non_existing = true;
}
if (is_field_ref) {
if (videoLoggingEnabled())
std::cout << "IS_FIELD ";
// picFlags.field_pic_flag = true;
}
if (!currentPictureIsProgressive && (used_for_reference & topFieldMask)) {
if (videoLoggingEnabled())
std::cout << "TOP_FIELD_IS_REF ";
picFlags.top_field_flag = true;
}
if (!currentPictureIsProgressive && (used_for_reference & bottomFieldMask)) {
if (videoLoggingEnabled())
std::cout << "BOTTOM_FIELD_IS_REF ";
picFlags.bottom_field_flag = true;
}
return picFlags;
}
void setH264PictureData(nvVideoDecodeH264DpbSlotInfo* pDpbRefList,
VkVideoReferenceSlotInfoKHR* pReferenceSlots,
deUint32 dpbEntryIdx, deUint32 dpbSlotIndex,
bool currentPictureIsProgressive)
{
DE_ASSERT(dpbEntryIdx < AVC_MAX_DPB_SLOTS);
DE_ASSERT(dpbSlotIndex < AVC_MAX_DPB_SLOTS);
DE_ASSERT((dpbSlotIndex == (deUint32)dpbSlot) || is_non_existing);
pReferenceSlots[dpbEntryIdx].sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
pReferenceSlots[dpbEntryIdx].slotIndex = dpbSlotIndex;
pReferenceSlots[dpbEntryIdx].pNext = pDpbRefList[dpbEntryIdx].Init(dpbSlotIndex);
StdVideoDecodeH264ReferenceInfo* pRefPicInfo = &pDpbRefList[dpbEntryIdx].stdReferenceInfo;
pRefPicInfo->FrameNum = FrameIdx;
if (videoLoggingEnabled()) {
std::cout << "\tdpbEntryIdx: " << dpbEntryIdx
<< "dpbSlotIndex: " << dpbSlotIndex
<< " FrameIdx: " << (int32_t)FrameIdx;
}
pRefPicInfo->flags = getPictureFlag(currentPictureIsProgressive);
pRefPicInfo->PicOrderCnt[0] = FieldOrderCnt[0];
pRefPicInfo->PicOrderCnt[1] = FieldOrderCnt[1];
if (videoLoggingEnabled())
std::cout << " fieldOrderCnt[0]: " << pRefPicInfo->PicOrderCnt[0]
<< " fieldOrderCnt[1]: " << pRefPicInfo->PicOrderCnt[1]
<< std::endl;
}
void setH265PictureData(nvVideoDecodeH265DpbSlotInfo* pDpbSlotInfo,
VkVideoReferenceSlotInfoKHR* pReferenceSlots,
deUint32 dpbEntryIdx, deUint32 dpbSlotIndex)
{
DE_ASSERT(dpbEntryIdx < HEVC_MAX_DPB_SLOTS);
DE_ASSERT(dpbSlotIndex < HEVC_MAX_DPB_SLOTS);
DE_ASSERT(isRef());
DE_ASSERT((dpbSlotIndex == (deUint32)dpbSlot) || is_non_existing);
pReferenceSlots[dpbEntryIdx].sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
pReferenceSlots[dpbEntryIdx].slotIndex = dpbSlotIndex;
pReferenceSlots[dpbEntryIdx].pNext = pDpbSlotInfo[dpbEntryIdx].Init(dpbSlotIndex);
StdVideoDecodeH265ReferenceInfo* pRefPicInfo = &pDpbSlotInfo[dpbEntryIdx].stdReferenceInfo;
pRefPicInfo->PicOrderCntVal = PicOrderCnt;
pRefPicInfo->flags.used_for_long_term_reference = is_long_term;
if (videoLoggingEnabled()) {
std::cout << "\tdpbIndex: " << dpbSlotIndex
<< " picOrderCntValList: " << PicOrderCnt;
std::cout << "\t\t Flags: ";
std::cout << "FRAME IS REFERENCE ";
if (pRefPicInfo->flags.used_for_long_term_reference) {
std::cout << "IS LONG TERM ";
}
std::cout << std::endl;
}
}
} dpbH264Entry;
int8_t VideoBaseDecoder::GetPicIdx(vkPicBuffBase *pPicBuf)
{
if (pPicBuf)
{
int32_t picIndex = pPicBuf->m_picIdx;
if ((picIndex >= 0) && ((deUint32) picIndex < m_maxNumDecodeSurfaces))
{
return (int8_t) picIndex;
}
}
return -1;
}
int8_t VideoBaseDecoder::GetPicIdx(VkPicIf *pPicBuf)
{
return GetPicIdx(GetPic(pPicBuf));
}
int8_t VideoBaseDecoder::GetPicDpbSlot(int8_t picIndex)
{
return m_pictureToDpbSlotMap[picIndex];
}
bool VideoBaseDecoder::GetFieldPicFlag(int8_t picIndex)
{
DE_ASSERT((picIndex >= 0) && ((deUint32) picIndex < m_maxNumDecodeSurfaces));
return !!(m_fieldPicFlagMask & (1 << (deUint32) picIndex));
}
bool VideoBaseDecoder::SetFieldPicFlag(int8_t picIndex, bool fieldPicFlag)
{
DE_ASSERT((picIndex >= 0) && ((deUint32) picIndex < m_maxNumDecodeSurfaces));
bool oldFieldPicFlag = GetFieldPicFlag(picIndex);
if (fieldPicFlag)
{
m_fieldPicFlagMask |= (1 << (deUint32) picIndex);
}
else
{
m_fieldPicFlagMask &= ~(1 << (deUint32) picIndex);
}
return oldFieldPicFlag;
}
int8_t VideoBaseDecoder::SetPicDpbSlot(int8_t picIndex, int8_t dpbSlot)
{
int8_t oldDpbSlot = m_pictureToDpbSlotMap[picIndex];
m_pictureToDpbSlotMap[picIndex] = dpbSlot;
if (dpbSlot >= 0)
{
m_dpbSlotsMask |= (1 << picIndex);
}
else
{
m_dpbSlotsMask &= ~(1 << picIndex);
if (oldDpbSlot >= 0)
{
m_dpb.FreeSlot(oldDpbSlot);
}
}
return oldDpbSlot;
}
deUint32 VideoBaseDecoder::ResetPicDpbSlots(deUint32 picIndexSlotValidMask)
{
deUint32 resetSlotsMask = ~(picIndexSlotValidMask | ~m_dpbSlotsMask);
for (deUint32 picIdx = 0; (picIdx < m_maxNumDecodeSurfaces) && resetSlotsMask; picIdx++)
{
if (resetSlotsMask & (1 << picIdx))
{
resetSlotsMask &= ~(1 << picIdx);
SetPicDpbSlot((int8_t) picIdx, -1);
}
}
return m_dpbSlotsMask;
}
VideoBaseDecoder::VideoBaseDecoder(Parameters&& params)
: m_deviceContext(params.context)
, m_profile(*params.profile)
, m_framesToCheck(params.framesToCheck)
, m_dpb(3)
, m_videoFrameBuffer(params.framebuffer)
// TODO: interface cleanup
, m_decodeFramesData(params.context->getDeviceDriver(), params.context->device, params.context->decodeQueueFamilyIdx())
, m_resetPictureParametersFrameTriggerHack(params.pictureParameterUpdateTriggerHack)
, m_queryResultWithStatus(params.queryDecodeStatus)
, m_outOfOrderDecoding(params.outOfOrderDecoding)
, m_alwaysRecreateDPB(params.alwaysRecreateDPB)
{
std::fill(m_pictureToDpbSlotMap.begin(), m_pictureToDpbSlotMap.end(), -1);
VK_CHECK(util::getVideoDecodeCapabilities(*m_deviceContext, *params.profile, m_videoCaps, m_decodeCaps));
VK_CHECK(util::getSupportedVideoFormats(*m_deviceContext, m_profile, m_decodeCaps.flags,
m_outImageFormat,
m_dpbImageFormat));
m_supportedVideoCodecs = util::getSupportedCodecs(*m_deviceContext,
m_deviceContext->decodeQueueFamilyIdx(),
VK_QUEUE_VIDEO_DECODE_BIT_KHR,
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR | VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR);
DE_ASSERT(m_supportedVideoCodecs != VK_VIDEO_CODEC_OPERATION_NONE_KHR);
}
void VideoBaseDecoder::Deinitialize()
{
const DeviceInterface& vkd = m_deviceContext->getDeviceDriver();
VkDevice device = m_deviceContext->device;
VkQueue queueDecode = m_deviceContext->decodeQueue;
VkQueue queueTransfer = m_deviceContext->transferQueue;
if (queueDecode)
vkd.queueWaitIdle(queueDecode);
if (queueTransfer)
vkd.queueWaitIdle(queueTransfer);
vkd.deviceWaitIdle(device);
m_dpb.Deinit();
m_videoFrameBuffer = nullptr;
m_decodeFramesData.deinit();
m_videoSession = nullptr;
}
int32_t VideoBaseDecoder::StartVideoSequence (const VkParserDetectedVideoFormat* pVideoFormat)
{
VkExtent2D codedExtent = { pVideoFormat->coded_width, pVideoFormat->coded_height };
// Width and height of the image surface
VkExtent2D imageExtent = VkExtent2D { std::max((deUint32)(pVideoFormat->display_area.right - pVideoFormat->display_area.left), pVideoFormat->coded_width),
std::max((deUint32)(pVideoFormat->display_area.bottom - pVideoFormat->display_area.top), pVideoFormat->coded_height) };
// REVIEW: There is some inflexibility in the parser regarding this parameter. For the Jellyfish content, it continues wanting to allocate buffers
// well past what is advertises here. The tangential problem with that content is that the second GOP doesn't start with an IDR frame like all the
// other test content. Should look more ino this problem, but for now cheese it by always allocating the total number of frames we might need
// to allocate, even if many of them could be recycled if the parser output pictures earlier (which would be legal but isn't happening for some
// reason)
m_numDecodeSurfaces = std::max(4u, m_framesToCheck); // N.B. pVideoFormat->minNumDecodeSurfaces is NOT advertised correctly!
VkResult result = VK_SUCCESS;
if (videoLoggingEnabled()) {
std::cout << "\t" << std::hex << m_supportedVideoCodecs << " HW codec types are available: " << std::dec << std::endl;
}
VkVideoCodecOperationFlagBitsKHR detectedVideoCodec = pVideoFormat->codec;
VkVideoCoreProfile videoProfile(detectedVideoCodec, pVideoFormat->chromaSubsampling, pVideoFormat->lumaBitDepth, pVideoFormat->chromaBitDepth,
pVideoFormat->codecProfile);
DE_ASSERT(videoProfile == m_profile);
// Check the detected profile is the same as the specified test profile.
DE_ASSERT(m_profile == videoProfile);
DE_ASSERT(((detectedVideoCodec & m_supportedVideoCodecs) != 0) && (detectedVideoCodec == m_profile.GetCodecType()));
if (m_videoFormat.coded_width && m_videoFormat.coded_height) {
// CreateDecoder() has been called before, and now there's possible config change
m_deviceContext->waitDecodeQueue();
m_deviceContext->deviceWaitIdle();
}
deUint32 maxDpbSlotCount = pVideoFormat->maxNumDpbSlots;
if (videoLoggingEnabled())
{
// TODO: Tidy up all the logging stuff copied from NVIDIA...
std::cout << std::dec << "Video Input Information" << std::endl
<< "\tCodec : " << util::getVideoCodecString(pVideoFormat->codec) << std::endl
<< "\tFrame rate : " << pVideoFormat->frame_rate.numerator << "/" << pVideoFormat->frame_rate.denominator << " = " << ((pVideoFormat->frame_rate.denominator != 0) ? (1.0 * pVideoFormat->frame_rate.numerator / pVideoFormat->frame_rate.denominator) : 0.0) << " fps" << std::endl
<< "\tSequence : " << (pVideoFormat->progressive_sequence ? "Progressive" : "Interlaced") << std::endl
<< "\tCoded size : [" << codedExtent.width << ", " << codedExtent.height << "]" << std::endl
<< "\tDisplay area : [" << pVideoFormat->display_area.left << ", " << pVideoFormat->display_area.top << ", " << pVideoFormat->display_area.right << ", " << pVideoFormat->display_area.bottom << "]" << std::endl
<< "\tChroma : " << util::getVideoChromaFormatString(pVideoFormat->chromaSubsampling) << std::endl
<< "\tBit depth : " << pVideoFormat->bit_depth_luma_minus8 + 8 << std::endl
<< "\tCodec : " << VkVideoCoreProfile::CodecToName(detectedVideoCodec) << std::endl
<< "\t#Decode surf : " << m_numDecodeSurfaces << std::endl
<< "\tCoded extent : " << codedExtent.width << " x " << codedExtent.height << std::endl
<< "\tMax DPB slots : " << maxDpbSlotCount << std::endl;
}
DE_ASSERT(VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR == pVideoFormat->chromaSubsampling ||
VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR == pVideoFormat->chromaSubsampling ||
VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR == pVideoFormat->chromaSubsampling ||
VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR == pVideoFormat->chromaSubsampling);
DE_ASSERT(pVideoFormat->chromaSubsampling == m_profile.GetColorSubsampling());
imageExtent.width = std::max(imageExtent.width, m_videoCaps.minCodedExtent.width);
imageExtent.height = std::max(imageExtent.height, m_videoCaps.minCodedExtent.height);
imageExtent.width = deAlign32(imageExtent.width, m_videoCaps.pictureAccessGranularity.width);
imageExtent.height = deAlign32(imageExtent.height, m_videoCaps.pictureAccessGranularity.height);
if (!m_videoSession ||
!m_videoSession->IsCompatible(m_deviceContext->device,
m_deviceContext->decodeQueueFamilyIdx(),
&videoProfile,
m_outImageFormat,
imageExtent,
m_dpbImageFormat,
maxDpbSlotCount,
maxDpbSlotCount) ||
m_alwaysRecreateDPB)
{
VK_CHECK(VulkanVideoSession::Create(*m_deviceContext,
m_deviceContext->decodeQueueFamilyIdx(),
&videoProfile,
m_outImageFormat,
imageExtent,
m_dpbImageFormat,
maxDpbSlotCount,
std::min<deUint32>(maxDpbSlotCount, m_videoCaps.maxActiveReferencePictures),
m_videoSession));
// after creating a new video session, we need codec reset.
m_resetDecoder = true;
DE_ASSERT(result == VK_SUCCESS);
}
if (m_currentPictureParameters)
{
m_currentPictureParameters->FlushPictureParametersQueue(m_videoSession);
}
VkImageUsageFlags outImageUsage = (VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT);
VkImageUsageFlags dpbImageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
if (dpbAndOutputCoincide()) {
dpbImageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
} else {
// The implementation does not support dpbAndOutputCoincide
m_useSeparateOutputImages = true;
}
if(!(m_videoCaps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR)) {
// The implementation does not support individual images for DPB and so must use arrays
m_useImageArray = true;
m_useImageViewArray = true;
}
bool useLinearOutput = false;
int32_t ret = m_videoFrameBuffer->InitImagePool(videoProfile.GetProfile(),
m_numDecodeSurfaces,
m_dpbImageFormat,
m_outImageFormat,
codedExtent,
imageExtent,
dpbImageUsage,
outImageUsage,
m_deviceContext->decodeQueueFamilyIdx(),
m_useImageArray, m_useImageViewArray,
m_useSeparateOutputImages, useLinearOutput);
DE_ASSERT((deUint32)ret >= m_numDecodeSurfaces);
if ((deUint32)ret != m_numDecodeSurfaces) {
fprintf(stderr, "\nERROR: InitImagePool() ret(%d) != m_numDecodeSurfaces(%d)\n", ret, m_numDecodeSurfaces);
}
if (videoLoggingEnabled()) {
std::cout << "Allocating Video Device Memory" << std::endl
<< "Allocating " << m_numDecodeSurfaces << " Num Decode Surfaces and "
<< maxDpbSlotCount << " Video Device Memory Images for DPB " << std::endl
<< imageExtent.width << " x " << imageExtent.height << std::endl;
}
// There will be no more than 32 frames in the queue.
m_decodeFramesData.resize(m_numDecodeSurfaces);
int32_t availableBuffers = (int32_t)m_decodeFramesData.GetBitstreamBuffersQueue().GetAvailableNodesNumber();
if (availableBuffers < m_numBitstreamBuffersToPreallocate) {
deUint32 allocateNumBuffers = std::min<deUint32>(
m_decodeFramesData.GetBitstreamBuffersQueue().GetMaxNodes(),
(m_numBitstreamBuffersToPreallocate - availableBuffers));
allocateNumBuffers = std::min<deUint32>(allocateNumBuffers,
m_decodeFramesData.GetBitstreamBuffersQueue().GetFreeNodesNumber());
for (deUint32 i = 0; i < 1; i++) {
VkSharedBaseObj<BitstreamBufferImpl> bitstreamBuffer;
VkDeviceSize allocSize = 2 * 1024 * 1024;
result = BitstreamBufferImpl::Create(m_deviceContext,
m_deviceContext->decodeQueueFamilyIdx(),
allocSize,
m_videoCaps.minBitstreamBufferOffsetAlignment,
m_videoCaps.minBitstreamBufferSizeAlignment,
bitstreamBuffer,
m_profile.GetProfileListInfo());
DE_ASSERT(result == VK_SUCCESS);
if (result != VK_SUCCESS) {
fprintf(stderr, "\nERROR: CreateVideoBitstreamBuffer() result: 0x%x\n", result);
break;
}
int32_t nodeAddedWithIndex = m_decodeFramesData.GetBitstreamBuffersQueue().
AddNodeToPool(bitstreamBuffer, false);
if (nodeAddedWithIndex < 0) {
DE_ASSERT("Could not add the new node to the pool");
break;
}
}
}
// Save the original config
m_videoFormat = *pVideoFormat;
return m_numDecodeSurfaces;
}
int32_t VideoBaseDecoder::BeginSequence (const VkParserSequenceInfo* pnvsi)
{
bool sequenceUpdate = m_nvsi.nMaxWidth != 0 && m_nvsi.nMaxHeight != 0;
const deUint32 maxDpbSlots = (pnvsi->eCodec == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) ? VkParserPerFrameDecodeParameters::MAX_DPB_REF_AND_SETUP_SLOTS : VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS;
deUint32 configDpbSlots = (pnvsi->nMinNumDpbSlots > 0) ? pnvsi->nMinNumDpbSlots : maxDpbSlots;
configDpbSlots = std::min<deUint32>(configDpbSlots, maxDpbSlots);
bool sequenceReconfigureFormat = false;
bool sequenceReconfigureCodedExtent = false;
if (sequenceUpdate) {
if ((pnvsi->eCodec != m_nvsi.eCodec) ||
(pnvsi->nChromaFormat != m_nvsi.nChromaFormat) || (pnvsi->uBitDepthLumaMinus8 != m_nvsi.uBitDepthLumaMinus8) ||
(pnvsi->uBitDepthChromaMinus8 != m_nvsi.uBitDepthChromaMinus8) ||
(pnvsi->bProgSeq != m_nvsi.bProgSeq)) {
sequenceReconfigureFormat = true;
}
if ((pnvsi->nCodedWidth != m_nvsi.nCodedWidth) || (pnvsi->nCodedHeight != m_nvsi.nCodedHeight)) {
sequenceReconfigureCodedExtent = true;
}
}
m_nvsi = *pnvsi;
m_nvsi.nMaxWidth = pnvsi->nCodedWidth;
m_nvsi.nMaxHeight = pnvsi->nCodedHeight;
m_maxNumDecodeSurfaces = pnvsi->nMinNumDecodeSurfaces;
VkParserDetectedVideoFormat detectedFormat;
deUint8 raw_seqhdr_data[1024]; /* Output the sequence header data, currently
not used */
memset(&detectedFormat, 0, sizeof(detectedFormat));
detectedFormat.sequenceUpdate = sequenceUpdate;
detectedFormat.sequenceReconfigureFormat = sequenceReconfigureFormat;
detectedFormat.sequenceReconfigureCodedExtent = sequenceReconfigureCodedExtent;
detectedFormat.codec = pnvsi->eCodec;
detectedFormat.frame_rate.numerator = NV_FRAME_RATE_NUM(pnvsi->frameRate);
detectedFormat.frame_rate.denominator = NV_FRAME_RATE_DEN(pnvsi->frameRate);
detectedFormat.progressive_sequence = pnvsi->bProgSeq;
detectedFormat.coded_width = pnvsi->nCodedWidth;
detectedFormat.coded_height = pnvsi->nCodedHeight;
detectedFormat.display_area.right = pnvsi->nDisplayWidth;
detectedFormat.display_area.bottom = pnvsi->nDisplayHeight;
if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_420) {
detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
} else if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_422) {
detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
} else if ((StdChromaFormatIdc)pnvsi->nChromaFormat == chroma_format_idc_444) {
detectedFormat.chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
} else {
DE_ASSERT(!"Invalid chroma sub-sampling format");
}
switch (pnvsi->uBitDepthLumaMinus8) {
case 0:
detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
break;
case 2:
detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
break;
case 4:
detectedFormat.lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
break;
default:
DE_ASSERT(false);
}
switch (pnvsi->uBitDepthChromaMinus8) {
case 0:
detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
break;
case 2:
detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
break;
case 4:
detectedFormat.chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
break;
default:
DE_ASSERT(false);
}
detectedFormat.bit_depth_luma_minus8 = pnvsi->uBitDepthLumaMinus8;
detectedFormat.bit_depth_chroma_minus8 = pnvsi->uBitDepthChromaMinus8;
detectedFormat.bitrate = pnvsi->lBitrate;
detectedFormat.display_aspect_ratio.x = pnvsi->lDARWidth;
detectedFormat.display_aspect_ratio.y = pnvsi->lDARHeight;
detectedFormat.video_signal_description.video_format = pnvsi->lVideoFormat;
detectedFormat.video_signal_description.video_full_range_flag = pnvsi->uVideoFullRange;
detectedFormat.video_signal_description.color_primaries = pnvsi->lColorPrimaries;
detectedFormat.video_signal_description.transfer_characteristics = pnvsi->lTransferCharacteristics;
detectedFormat.video_signal_description.matrix_coefficients = pnvsi->lMatrixCoefficients;
detectedFormat.seqhdr_data_length = (deUint32)std::min((size_t)pnvsi->cbSequenceHeader, sizeof(raw_seqhdr_data));
detectedFormat.minNumDecodeSurfaces = pnvsi->nMinNumDecodeSurfaces;
detectedFormat.maxNumDpbSlots = configDpbSlots;
detectedFormat.codecProfile = pnvsi->codecProfile;
if (detectedFormat.seqhdr_data_length > 0) {
memcpy(raw_seqhdr_data, pnvsi->SequenceHeaderData,
detectedFormat.seqhdr_data_length);
}
int32_t maxDecodeRTs = StartVideoSequence(&detectedFormat);
// nDecodeRTs <= 0 means SequenceCallback failed
// nDecodeRTs = 1 means SequenceCallback succeeded
// nDecodeRTs > 1 means we need to overwrite the MaxNumDecodeSurfaces
if (maxDecodeRTs <= 0) {
return 0;
}
// MaxNumDecodeSurface may not be correctly calculated by the client while
// parser creation so overwrite it with NumDecodeSurface. (only if nDecodeRT
// > 1)
if (maxDecodeRTs > 1) {
m_maxNumDecodeSurfaces = maxDecodeRTs;
}
// Always deinit the DPB between sequences. The optimization path does not work for resolution change cases.
m_maxNumDpbSlots = m_dpb.Init(configDpbSlots, false /* reconfigure the DPB size if true */);
// Ensure the picture map is empited, so that DPB slot management doesn't get confused in-between sequences.
m_pictureToDpbSlotMap.fill(-1);
return m_maxNumDecodeSurfaces;
}
bool VideoBaseDecoder::AllocPictureBuffer (VkPicIf** ppNvidiaVulkanPicture)
{
DEBUGLOG(std::cout << "VideoBaseDecoder::AllocPictureBuffer" << std::endl);
bool result = false;
*ppNvidiaVulkanPicture = m_videoFrameBuffer->ReservePictureBuffer();
if (*ppNvidiaVulkanPicture)
{
result = true;
DEBUGLOG(std::cout << "\tVideoBaseDecoder::AllocPictureBuffer " << (void*)*ppNvidiaVulkanPicture << std::endl);
}
if (!result)
{
*ppNvidiaVulkanPicture = (VkPicIf*)nullptr;
}
return result;
}
bool VideoBaseDecoder::DecodePicture (VkParserPictureData* pd)
{
DEBUGLOG(std::cout << "VideoBaseDecoder::DecodePicture" << std::endl);
bool result = false;
if (!pd->pCurrPic)
{
return result;
}
vkPicBuffBase* pVkPicBuff = GetPic(pd->pCurrPic);
const int32_t picIdx = pVkPicBuff ? pVkPicBuff->m_picIdx : -1;
if (videoLoggingEnabled())
std::cout
<< "\t ==> VulkanVideoParser::DecodePicture " << picIdx << std::endl
<< "\t\t progressive: " << (bool)pd->progressive_frame
<< // Frame is progressive
"\t\t field: " << (bool)pd->field_pic_flag << std::endl
<< // 0 = frame picture, 1 = field picture
"\t\t\t bottom_field: " << (bool)pd->bottom_field_flag
<< // 0 = top field, 1 = bottom field (ignored if field_pic_flag=0)
"\t\t\t second_field: " << (bool)pd->second_field
<< // Second field of a complementary field pair
"\t\t\t top_field: " << (bool)pd->top_field_first << std::endl
<< // Frame pictures only
"\t\t repeat_first: " << pd->repeat_first_field
<< // For 3:2 pulldown (number of additional fields, 2 = frame
// doubling, 4 = frame tripling)
"\t\t ref_pic: " << (bool)pd->ref_pic_flag
<< std::endl; // Frame is a reference frame
DE_ASSERT(picIdx < MAX_FRM_CNT);
VkParserDecodePictureInfo decodePictureInfo = VkParserDecodePictureInfo();
decodePictureInfo.pictureIndex = picIdx;
decodePictureInfo.flags.progressiveFrame = pd->progressive_frame;
decodePictureInfo.flags.fieldPic = pd->field_pic_flag; // 0 = frame picture, 1 = field picture
decodePictureInfo.flags.repeatFirstField = pd->repeat_first_field; // For 3:2 pulldown (number of additional fields, 2 = frame doubling, 4 = frame tripling)
decodePictureInfo.flags.refPic = pd->ref_pic_flag; // Frame is a reference frame
// Mark the first field as unpaired Detect unpaired fields
if (pd->field_pic_flag)
{
decodePictureInfo.flags.bottomField = pd->bottom_field_flag; // 0 = top field, 1 = bottom field (ignored if field_pic_flag=0)
decodePictureInfo.flags.secondField = pd->second_field; // Second field of a complementary field pair
decodePictureInfo.flags.topFieldFirst = pd->top_field_first; // Frame pictures only
if (!pd->second_field)
{
decodePictureInfo.flags.unpairedField = true; // Incomplete (half) frame.
}
else
{
if (decodePictureInfo.flags.unpairedField)
{
decodePictureInfo.flags.syncToFirstField = true;
decodePictureInfo.flags.unpairedField = false;
}
}
}
decodePictureInfo.frameSyncinfo.unpairedField = decodePictureInfo.flags.unpairedField;
decodePictureInfo.frameSyncinfo.syncToFirstField = decodePictureInfo.flags.syncToFirstField;
return DecodePicture(pd, pVkPicBuff, &decodePictureInfo);
}
bool VideoBaseDecoder::DecodePicture (VkParserPictureData* pd,
vkPicBuffBase* /*pVkPicBuff*/,
VkParserDecodePictureInfo* pDecodePictureInfo)
{
DEBUGLOG(std::cout << "\tDecodePicture sps_sid:" << (deUint32)pNvidiaVulkanParserPictureData->CodecSpecific.h264.pStdSps->seq_parameter_set_id << " pps_sid:" << (deUint32)pNvidiaVulkanParserPictureData->CodecSpecific.h264.pStdPps->seq_parameter_set_id << " pps_pid:" << (deUint32)pNvidiaVulkanParserPictureData->CodecSpecific.h264.pStdPps->pic_parameter_set_id << std::endl);
if (!pd->pCurrPic)
{
return false;
}
const deUint32 PicIdx = GetPicIdx(pd->pCurrPic);
TCU_CHECK (PicIdx < MAX_FRM_CNT);
m_cachedDecodeParams.emplace_back(new CachedDecodeParameters);
auto& cachedParameters = m_cachedDecodeParams.back();
bool bRet = false;
if (m_resetDecoder)
{
cachedParameters->performCodecReset = true;
m_resetDecoder = false;
}
else
{
cachedParameters->performCodecReset = false;
}
// Copy the picture data over, taking care to memcpy the heap resources that might get freed on the parser side (we have no guarantees about those pointers)
cachedParameters->pd = *pd;
if (pd->sideDataLen > 0)
{
cachedParameters->pd.pSideData = new deUint8[pd->sideDataLen];
deMemcpy(cachedParameters->pd.pSideData, pd->pSideData, pd->sideDataLen);
}
// And again for the decoded picture information, these are all POD types for now.
cachedParameters->decodedPictureInfo = *pDecodePictureInfo;
pDecodePictureInfo = &cachedParameters->decodedPictureInfo;
// Now build up the frame's decode parameters and store it in the cache
cachedParameters->pictureParams = VkParserPerFrameDecodeParameters();
VkParserPerFrameDecodeParameters* pCurrFrameDecParams = &cachedParameters->pictureParams;
pCurrFrameDecParams->currPicIdx = PicIdx;
pCurrFrameDecParams->numSlices = pd->numSlices;
pCurrFrameDecParams->firstSliceIndex = pd->firstSliceIndex;
pCurrFrameDecParams->bitstreamDataOffset = pd->bitstreamDataOffset;
pCurrFrameDecParams->bitstreamDataLen = pd->bitstreamDataLen;
pCurrFrameDecParams->bitstreamData = pd->bitstreamData;
auto& referenceSlots = cachedParameters->referenceSlots;
auto& setupReferenceSlot = cachedParameters->setupReferenceSlot;
setupReferenceSlot.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
setupReferenceSlot.pPictureResource = nullptr;
setupReferenceSlot.slotIndex = -1;
pCurrFrameDecParams->decodeFrameInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR;
pCurrFrameDecParams->decodeFrameInfo.dstPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
pCurrFrameDecParams->dpbSetupPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR)
{
const VkParserH264PictureData* const pin = &pd->CodecSpecific.h264;
cachedParameters->h264PicParams = nvVideoH264PicParameters();
VkVideoDecodeH264PictureInfoKHR* h264PictureInfo = &cachedParameters->h264PicParams.pictureInfo;
nvVideoDecodeH264DpbSlotInfo* h264DpbReferenceList = cachedParameters->h264PicParams.dpbRefList;
StdVideoDecodeH264PictureInfo* h264StandardPictureInfo = &cachedParameters->h264PicParams.stdPictureInfo;
pCurrFrameDecParams->pStdPps = pin->pStdPps;
pCurrFrameDecParams->pStdSps = pin->pStdSps;
pCurrFrameDecParams->pStdVps = nullptr;
cachedParameters->decodedPictureInfo.videoFrameType = 0; // pd->CodecSpecific.h264.slice_type;
// FIXME: If mvcext is enabled.
cachedParameters->decodedPictureInfo.viewId = pd->CodecSpecific.h264.mvcext.view_id;
h264PictureInfo->pStdPictureInfo = &cachedParameters->h264PicParams.stdPictureInfo;
h264PictureInfo->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR;
h264PictureInfo->pNext = nullptr;
pCurrFrameDecParams->decodeFrameInfo.pNext = h264PictureInfo;
h264StandardPictureInfo->pic_parameter_set_id = pin->pic_parameter_set_id; // PPS ID
h264StandardPictureInfo->seq_parameter_set_id = pin->seq_parameter_set_id; // SPS ID;
h264StandardPictureInfo->frame_num = (deUint16)pin->frame_num;
h264PictureInfo->sliceCount = pd->numSlices;
deUint32 maxSliceCount = 0;
DE_ASSERT(pd->firstSliceIndex == 0); // No slice and MV modes are supported yet
h264PictureInfo->pSliceOffsets = pd->bitstreamData->GetStreamMarkersPtr(pd->firstSliceIndex, maxSliceCount);
DE_ASSERT(maxSliceCount == pd->numSlices);
StdVideoDecodeH264PictureInfoFlags currPicFlags = StdVideoDecodeH264PictureInfoFlags();
currPicFlags.is_intra = (pd->intra_pic_flag != 0);
// 0 = frame picture, 1 = field picture
if (pd->field_pic_flag) {
// 0 = top field, 1 = bottom field (ignored if field_pic_flag = 0)
currPicFlags.field_pic_flag = true;
if (pd->bottom_field_flag) {
currPicFlags.bottom_field_flag = true;
}
}
// Second field of a complementary field pair
if (pd->second_field) {
currPicFlags.complementary_field_pair = true;
}
// Frame is a reference frame
if (pd->ref_pic_flag) {
currPicFlags.is_reference = true;
}
h264StandardPictureInfo->flags = currPicFlags;
if (!pd->field_pic_flag) {
h264StandardPictureInfo->PicOrderCnt[0] = pin->CurrFieldOrderCnt[0];
h264StandardPictureInfo->PicOrderCnt[1] = pin->CurrFieldOrderCnt[1];
} else {
h264StandardPictureInfo->PicOrderCnt[pd->bottom_field_flag] = pin->CurrFieldOrderCnt[pd->bottom_field_flag];
}
const deUint32 maxDpbInputSlots = sizeof(pin->dpb) / sizeof(pin->dpb[0]);
pCurrFrameDecParams->numGopReferenceSlots = FillDpbH264State(
pd, pin->dpb, maxDpbInputSlots, h264DpbReferenceList,
VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS, // 16 reference pictures
referenceSlots, pCurrFrameDecParams->pGopReferenceImagesIndexes,
h264StandardPictureInfo->flags, &setupReferenceSlot.slotIndex);
DE_ASSERT(!pd->ref_pic_flag || (setupReferenceSlot.slotIndex >= 0));
// TODO: Dummy struct to silence validation. The root problem is that the dpb map doesn't take account of the setup slot,
// for some reason... So we can't use the existing logic to setup the picture flags and frame number from the dpbEntry
// class.
cachedParameters->h264SlotInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR;
cachedParameters->h264SlotInfo.pNext = nullptr;
cachedParameters->h264SlotInfo.pStdReferenceInfo = &cachedParameters->h264RefInfo;
if (setupReferenceSlot.slotIndex >= 0) {
setupReferenceSlot.pPictureResource = &pCurrFrameDecParams->dpbSetupPictureResource;
setupReferenceSlot.pNext = &cachedParameters->h264SlotInfo;
pCurrFrameDecParams->decodeFrameInfo.pSetupReferenceSlot = &setupReferenceSlot;
}
if (pCurrFrameDecParams->numGopReferenceSlots) {
DE_ASSERT(pCurrFrameDecParams->numGopReferenceSlots <= (int32_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS);
for (deUint32 dpbEntryIdx = 0; dpbEntryIdx < (deUint32)pCurrFrameDecParams->numGopReferenceSlots;
dpbEntryIdx++) {
pCurrFrameDecParams->pictureResources[dpbEntryIdx].sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
referenceSlots[dpbEntryIdx].pPictureResource = &pCurrFrameDecParams->pictureResources[dpbEntryIdx];
DE_ASSERT(h264DpbReferenceList[dpbEntryIdx].IsReference());
}
pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots = referenceSlots;
pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = pCurrFrameDecParams->numGopReferenceSlots;
} else {
pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots = NULL;
pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = 0;
}
}
else if (m_profile.GetCodecType() == VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR)
{
const VkParserHevcPictureData* const pin = &pd->CodecSpecific.hevc;
cachedParameters->h265PicParams = nvVideoH265PicParameters();
VkVideoDecodeH265PictureInfoKHR* pPictureInfo = &cachedParameters->h265PicParams.pictureInfo;
StdVideoDecodeH265PictureInfo* pStdPictureInfo = &cachedParameters->h265PicParams.stdPictureInfo;
nvVideoDecodeH265DpbSlotInfo* pDpbRefList = cachedParameters->h265PicParams.dpbRefList;
pCurrFrameDecParams->pStdPps = pin->pStdPps;
pCurrFrameDecParams->pStdSps = pin->pStdSps;
pCurrFrameDecParams->pStdVps = pin->pStdVps;
if (videoLoggingEnabled()) {
std::cout << "\n\tCurrent h.265 Picture VPS update : "
<< pin->pStdVps->GetUpdateSequenceCount() << std::endl;
std::cout << "\n\tCurrent h.265 Picture SPS update : "
<< pin->pStdSps->GetUpdateSequenceCount() << std::endl;
std::cout << "\tCurrent h.265 Picture PPS update : "
<< pin->pStdPps->GetUpdateSequenceCount() << std::endl;
}
pPictureInfo->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR;
pPictureInfo->pNext = nullptr;
pPictureInfo->pStdPictureInfo = &cachedParameters->h265PicParams.stdPictureInfo;
pCurrFrameDecParams->decodeFrameInfo.pNext = &cachedParameters->h265PicParams.pictureInfo;
pDecodePictureInfo->videoFrameType = 0; // pd->CodecSpecific.hevc.SliceType;
if (pd->CodecSpecific.hevc.mv_hevc_enable) {
pDecodePictureInfo->viewId = pd->CodecSpecific.hevc.nuh_layer_id;
} else {
pDecodePictureInfo->viewId = 0;
}
pPictureInfo->sliceSegmentCount = pd->numSlices;
deUint32 maxSliceCount = 0;
DE_ASSERT(pd->firstSliceIndex == 0); // No slice and MV modes are supported yet
pPictureInfo->pSliceSegmentOffsets = pd->bitstreamData->GetStreamMarkersPtr(pd->firstSliceIndex, maxSliceCount);
DE_ASSERT(maxSliceCount == pd->numSlices);
pStdPictureInfo->pps_pic_parameter_set_id = pin->pic_parameter_set_id; // PPS ID
pStdPictureInfo->pps_seq_parameter_set_id = pin->seq_parameter_set_id; // SPS ID
pStdPictureInfo->sps_video_parameter_set_id = pin->vps_video_parameter_set_id; // VPS ID
// hevc->irapPicFlag = m_slh.nal_unit_type >= NUT_BLA_W_LP &&
// m_slh.nal_unit_type <= NUT_CRA_NUT;
pStdPictureInfo->flags.IrapPicFlag = pin->IrapPicFlag; // Intra Random Access Point for current picture.
// hevc->idrPicFlag = m_slh.nal_unit_type == NUT_IDR_W_RADL ||
// m_slh.nal_unit_type == NUT_IDR_N_LP;
pStdPictureInfo->flags.IdrPicFlag = pin->IdrPicFlag; // Instantaneous Decoding Refresh for current picture.
// NumBitsForShortTermRPSInSlice = s->sh.short_term_rps ?
// s->sh.short_term_ref_pic_set_size : 0
pStdPictureInfo->NumBitsForSTRefPicSetInSlice = pin->NumBitsForShortTermRPSInSlice;
// NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ?
// s->sh.short_term_rps->rps_idx_num_delta_pocs : 0
pStdPictureInfo->NumDeltaPocsOfRefRpsIdx = pin->NumDeltaPocsOfRefRpsIdx;
pStdPictureInfo->PicOrderCntVal = pin->CurrPicOrderCntVal;
if (videoLoggingEnabled())
std::cout << "\tnumPocStCurrBefore: " << (int32_t)pin->NumPocStCurrBefore
<< " numPocStCurrAfter: " << (int32_t)pin->NumPocStCurrAfter
<< " numPocLtCurr: " << (int32_t)pin->NumPocLtCurr << std::endl;
pCurrFrameDecParams->numGopReferenceSlots = FillDpbH265State(pd, pin, pDpbRefList, pStdPictureInfo,
VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS, // max 16 reference pictures
referenceSlots, pCurrFrameDecParams->pGopReferenceImagesIndexes,
&setupReferenceSlot.slotIndex);
DE_ASSERT(!pd->ref_pic_flag || (setupReferenceSlot.slotIndex >= 0));
// TODO: Dummy struct to silence validation. The root problem is that the dpb map doesn't take account of the setup slot,
// for some reason... So we can't use the existing logic to setup the picture flags and frame number from the dpbEntry
// class.
cachedParameters->h265SlotInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR;
cachedParameters->h265SlotInfo.pNext = nullptr;
cachedParameters->h265SlotInfo.pStdReferenceInfo = &cachedParameters->h265RefInfo;
if (setupReferenceSlot.slotIndex >= 0) {
setupReferenceSlot.pPictureResource = &pCurrFrameDecParams->dpbSetupPictureResource;
setupReferenceSlot.pNext = &cachedParameters->h265SlotInfo;
pCurrFrameDecParams->decodeFrameInfo.pSetupReferenceSlot = &setupReferenceSlot;
}
if (pCurrFrameDecParams->numGopReferenceSlots) {
DE_ASSERT(pCurrFrameDecParams->numGopReferenceSlots <= (int32_t)VkParserPerFrameDecodeParameters::MAX_DPB_REF_SLOTS);
for (deUint32 dpbEntryIdx = 0; dpbEntryIdx < (deUint32)pCurrFrameDecParams->numGopReferenceSlots;
dpbEntryIdx++) {
pCurrFrameDecParams->pictureResources[dpbEntryIdx].sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
referenceSlots[dpbEntryIdx].pPictureResource = &pCurrFrameDecParams->pictureResources[dpbEntryIdx];
DE_ASSERT(pDpbRefList[dpbEntryIdx].IsReference());
}
pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots = referenceSlots;
pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = pCurrFrameDecParams->numGopReferenceSlots;
} else {
pCurrFrameDecParams->decodeFrameInfo.pReferenceSlots = nullptr;
pCurrFrameDecParams->decodeFrameInfo.referenceSlotCount = 0;
}
if (videoLoggingEnabled()) {
for (int32_t i = 0; i < HEVC_MAX_DPB_SLOTS; i++) {
std::cout << "\tdpbIndex: " << i;
if (pDpbRefList[i]) {
std::cout << " REFERENCE FRAME";
std::cout << " picOrderCntValList: "
<< (int32_t)pDpbRefList[i]
.dpbSlotInfo.pStdReferenceInfo->PicOrderCntVal;
std::cout << "\t\t Flags: ";
if (pDpbRefList[i]
.dpbSlotInfo.pStdReferenceInfo->flags.used_for_long_term_reference) {
std::cout << "IS LONG TERM ";
}
} else {
std::cout << " NOT A REFERENCE ";
}
std::cout << std::endl;
}
}
}
pDecodePictureInfo->displayWidth = m_nvsi.nDisplayWidth;
pDecodePictureInfo->displayHeight = m_nvsi.nDisplayHeight;
bRet = DecodePictureWithParameters(cachedParameters) >= 0;
DE_ASSERT(bRet);
m_nCurrentPictureID++;
return bRet;
}
int32_t VideoBaseDecoder::DecodePictureWithParameters(MovePtr<CachedDecodeParameters>& cachedParameters)
{
TCU_CHECK_MSG(m_videoSession, "Video session has not been initialized!");
auto *pPicParams = &cachedParameters->pictureParams;
int32_t currPicIdx = pPicParams->currPicIdx;
DE_ASSERT((deUint32) currPicIdx < m_numDecodeSurfaces);
cachedParameters->picNumInDecodeOrder = m_decodePicCount++;
m_videoFrameBuffer->SetPicNumInDecodeOrder(currPicIdx, cachedParameters->picNumInDecodeOrder);
DE_ASSERT(pPicParams->bitstreamData->GetMaxSize() >= pPicParams->bitstreamDataLen);
pPicParams->decodeFrameInfo.srcBuffer = pPicParams->bitstreamData->GetBuffer();
DE_ASSERT(pPicParams->bitstreamDataOffset == 0);
DE_ASSERT(pPicParams->firstSliceIndex == 0);
pPicParams->decodeFrameInfo.srcBufferOffset = pPicParams->bitstreamDataOffset;
pPicParams->decodeFrameInfo.srcBufferRange = deAlign64(pPicParams->bitstreamDataLen, m_videoCaps.minBitstreamBufferSizeAlignment);
int32_t retPicIdx = GetCurrentFrameData((deUint32) currPicIdx, cachedParameters->frameDataSlot);
DE_ASSERT(retPicIdx == currPicIdx);
if (retPicIdx != currPicIdx)
{
fprintf(stderr, "\nERROR: DecodePictureWithParameters() retPicIdx(%d) != currPicIdx(%d)\n", retPicIdx, currPicIdx);
}
auto &decodeBeginInfo = cachedParameters->decodeBeginInfo;
decodeBeginInfo.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR;
// CmdResetQueryPool are NOT Supported yet.
decodeBeginInfo.pNext = pPicParams->beginCodingInfoPictureParametersExt;
decodeBeginInfo.videoSession = m_videoSession->GetVideoSession();
cachedParameters->currentPictureParameterObject = m_currentPictureParameters;
DE_ASSERT(!!pPicParams->decodeFrameInfo.srcBuffer);
cachedParameters->bitstreamBufferMemoryBarrier = {
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR,
nullptr,
VK_PIPELINE_STAGE_2_NONE_KHR,
0, // VK_ACCESS_2_HOST_WRITE_BIT_KHR,
VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR,
(deUint32) m_deviceContext->decodeQueueFamilyIdx(),
(deUint32) m_deviceContext->decodeQueueFamilyIdx(),
pPicParams->decodeFrameInfo.srcBuffer,
pPicParams->decodeFrameInfo.srcBufferOffset,
pPicParams->decodeFrameInfo.srcBufferRange
};
deUint32 baseArrayLayer = (m_useImageArray || m_useImageViewArray) ? pPicParams->currPicIdx : 0;
const VkImageMemoryBarrier2KHR dpbBarrierTemplate = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR, // VkStructureType sType
nullptr, // const void* pNext
VK_PIPELINE_STAGE_2_NONE_KHR, // VkPipelineStageFlags2KHR srcStageMask
0, // VkAccessFlags2KHR srcAccessMask
VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, // VkPipelineStageFlags2KHR dstStageMask;
VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR, // VkAccessFlags dstAccessMask
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout
VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, // VkImageLayout newLayout
(deUint32) m_deviceContext->decodeQueueFamilyIdx(), // deUint32 srcQueueFamilyIndex
(deUint32) m_deviceContext->decodeQueueFamilyIdx(), // deUint32 dstQueueFamilyIndex
VK_NULL_HANDLE, // VkImage image;
{
// VkImageSubresourceRange subresourceRange
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask
0, // deUint32 baseMipLevel
1, // deUint32 levelCount
baseArrayLayer, // deUint32 baseArrayLayer
1, // deUint32 layerCount;
},
};
cachedParameters->currentDpbPictureResourceInfo = VulkanVideoFrameBuffer::PictureResourceInfo();
cachedParameters->currentOutputPictureResourceInfo = VulkanVideoFrameBuffer::PictureResourceInfo();
deMemset(&cachedParameters->currentOutputPictureResource, 0, sizeof(VkVideoPictureResourceInfoKHR));
cachedParameters->currentOutputPictureResource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
auto *pOutputPictureResource = cachedParameters->pOutputPictureResource;
auto *pOutputPictureResourceInfo = cachedParameters->pOutputPictureResourceInfo;
if (!dpbAndOutputCoincide())
{
// Output Distinct will use the decodeFrameInfo.dstPictureResource directly.
pOutputPictureResource = &pPicParams->decodeFrameInfo.dstPictureResource;
}
else if (true) // TODO: Tidying
{
// Output Coincide needs the output only if we are processing linear images that we need to copy to below.
pOutputPictureResource = &cachedParameters->currentOutputPictureResource;
}
if (pOutputPictureResource)
{
// if the pOutputPictureResource is set then we also need the pOutputPictureResourceInfo.
pOutputPictureResourceInfo = &cachedParameters->currentOutputPictureResourceInfo;
}
if (pPicParams->currPicIdx !=
m_videoFrameBuffer->GetCurrentImageResourceByIndex(pPicParams->currPicIdx,
&pPicParams->dpbSetupPictureResource,
&cachedParameters->currentDpbPictureResourceInfo,
VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
pOutputPictureResource,
pOutputPictureResourceInfo,
VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR))
{
DE_ASSERT(!"GetImageResourcesByIndex has failed");
}
if (dpbAndOutputCoincide())
{
// For the Output Coincide, the DPB and destination output resources are the same.
pPicParams->decodeFrameInfo.dstPictureResource = pPicParams->dpbSetupPictureResource;
// Also, when we are copying the output we need to know which layer is used for the current frame.
// This is if a multi-layered image is used for the DPB and the output (since they coincide).
cachedParameters->decodedPictureInfo.imageLayerIndex = pPicParams->dpbSetupPictureResource.baseArrayLayer;
}
else if (pOutputPictureResourceInfo)
{
// For Output Distinct transition the image to DECODE_DST
if (pOutputPictureResourceInfo->currentImageLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
VkImageMemoryBarrier2KHR barrier = dpbBarrierTemplate;
barrier.oldLayout = pOutputPictureResourceInfo->currentImageLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR;
barrier.image = pOutputPictureResourceInfo->image;
barrier.dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR;
cachedParameters->imageBarriers.push_back(barrier);
DE_ASSERT(!!cachedParameters->imageBarriers.back().image);
}
}
if (cachedParameters->currentDpbPictureResourceInfo.currentImageLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
VkImageMemoryBarrier2KHR barrier = dpbBarrierTemplate;
barrier.oldLayout = cachedParameters->currentDpbPictureResourceInfo.currentImageLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
barrier.image = cachedParameters->currentDpbPictureResourceInfo.image;
barrier.dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR;
cachedParameters->imageBarriers.push_back(barrier);
DE_ASSERT(!!cachedParameters->imageBarriers.back().image);
}
// Transition all the DPB images to DECODE_DPB layout, if necessary.
deMemset(cachedParameters->pictureResourcesInfo, 0, DE_LENGTH_OF_ARRAY(cachedParameters->pictureResourcesInfo) * sizeof(cachedParameters->pictureResourcesInfo[0]));
const int8_t *pGopReferenceImagesIndexes = pPicParams->pGopReferenceImagesIndexes;
if (pPicParams->numGopReferenceSlots)
{
if (pPicParams->numGopReferenceSlots != m_videoFrameBuffer->GetDpbImageResourcesByIndex(
pPicParams->numGopReferenceSlots,
pGopReferenceImagesIndexes,
pPicParams->pictureResources,
cachedParameters->pictureResourcesInfo,
VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR))
{
DE_ASSERT(!"GetImageResourcesByIndex has failed");
}
for (int32_t resId = 0; resId < pPicParams->numGopReferenceSlots; resId++)
{
// slotLayer requires NVIDIA specific extension VK_KHR_video_layers, not enabled, just yet.
// pGopReferenceSlots[resId].slotLayerIndex = 0;
// pictureResourcesInfo[resId].image can be a nullptr handle if the picture is not-existent.
if (!!cachedParameters->pictureResourcesInfo[resId].image &&
(cachedParameters->pictureResourcesInfo[resId].currentImageLayout != VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR) &&
(cachedParameters->pictureResourcesInfo[resId].currentImageLayout != VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR))
{
VkImageMemoryBarrier2KHR barrier = dpbBarrierTemplate;
barrier.oldLayout = cachedParameters->currentDpbPictureResourceInfo.currentImageLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
barrier.image = cachedParameters->pictureResourcesInfo[resId].image;
barrier.dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR;
cachedParameters->imageBarriers.push_back(barrier);
DE_ASSERT(!!cachedParameters->imageBarriers.back().image);
}
}
}
decodeBeginInfo.referenceSlotCount = pPicParams->decodeFrameInfo.referenceSlotCount;
decodeBeginInfo.pReferenceSlots = pPicParams->decodeFrameInfo.pReferenceSlots;
// Ensure the resource for the resources associated with the
// reference slot (if it exists) are in the bound picture
// resources set. See VUID-vkCmdDecodeVideoKHR-pDecodeInfo-07149.
if (pPicParams->decodeFrameInfo.pSetupReferenceSlot != nullptr)
{
cachedParameters->fullReferenceSlots.clear();
for (deUint32 i = 0; i < decodeBeginInfo.referenceSlotCount; i++)
cachedParameters->fullReferenceSlots.push_back(decodeBeginInfo.pReferenceSlots[i]);
VkVideoReferenceSlotInfoKHR setupActivationSlot = {};
setupActivationSlot.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR;
setupActivationSlot.slotIndex = -1;
setupActivationSlot.pPictureResource = &pPicParams->dpbSetupPictureResource; //dpbAndOutputCoincide() ? &pPicParams->decodeFrameInfo.dstPictureResource : &pPicParams->pictureResources[pPicParams->numGopReferenceSlots];
cachedParameters->fullReferenceSlots.push_back(setupActivationSlot);
decodeBeginInfo.referenceSlotCount++;
decodeBeginInfo.pReferenceSlots = cachedParameters->fullReferenceSlots.data();
}
if (cachedParameters->decodedPictureInfo.flags.unpairedField)
{
// DE_ASSERT(pFrameSyncinfo->frameCompleteSemaphore == VK_NULL_HANDLE);
cachedParameters->decodedPictureInfo.flags.syncFirstReady = true;
}
// FIXME: the below sequence for interlaced synchronization.
cachedParameters->decodedPictureInfo.flags.syncToFirstField = false;
cachedParameters->frameSynchronizationInfo = VulkanVideoFrameBuffer::FrameSynchronizationInfo();
cachedParameters->frameSynchronizationInfo.hasFrameCompleteSignalFence = true;
cachedParameters->frameSynchronizationInfo.hasFrameCompleteSignalSemaphore = true;
VulkanVideoFrameBuffer::ReferencedObjectsInfo referencedObjectsInfo(pPicParams->bitstreamData,
pPicParams->pStdPps,
pPicParams->pStdSps,
pPicParams->pStdVps);
int picIdx = m_videoFrameBuffer->QueuePictureForDecode(currPicIdx, &cachedParameters->decodedPictureInfo, &referencedObjectsInfo,
&cachedParameters->frameSynchronizationInfo);
DE_ASSERT(picIdx == currPicIdx);
DE_UNREF(picIdx);
if (m_outOfOrderDecoding)
return currPicIdx;
WaitForFrameFences(cachedParameters);
ApplyPictureParameters(cachedParameters);
RecordCommandBuffer(cachedParameters);
SubmitQueue(cachedParameters);
if (m_queryResultWithStatus)
{
QueryDecodeResults(cachedParameters);
}
return currPicIdx;
}
void VideoBaseDecoder::ApplyPictureParameters(de::MovePtr<CachedDecodeParameters> &cachedParameters)
{
auto* pPicParams = &cachedParameters->pictureParams;
VkSharedBaseObj<VkVideoRefCountBase> currentVkPictureParameters;
bool valid = pPicParams->pStdPps->GetClientObject(currentVkPictureParameters);
DE_ASSERT(currentVkPictureParameters && valid);
VkParserVideoPictureParameters *pOwnerPictureParameters =
VkParserVideoPictureParameters::VideoPictureParametersFromBase(currentVkPictureParameters);
DE_ASSERT(pOwnerPictureParameters);
int32_t ret = pOwnerPictureParameters->FlushPictureParametersQueue(m_videoSession);
DE_ASSERT(ret >= 0);
DE_UNREF(ret);
bool isSps = false;
int32_t spsId = pPicParams->pStdPps->GetSpsId(isSps);
DE_ASSERT(!isSps);
DE_ASSERT(spsId >= 0);
DE_ASSERT(pOwnerPictureParameters->HasSpsId(spsId));
bool isPps = false;
int32_t ppsId = pPicParams->pStdPps->GetPpsId(isPps);
DE_ASSERT(isPps);
DE_ASSERT(ppsId >= 0);
DE_ASSERT(pOwnerPictureParameters->HasPpsId(ppsId));
DE_UNREF(valid);
cachedParameters->decodeBeginInfo.videoSessionParameters = *pOwnerPictureParameters;
if (videoLoggingEnabled())
{
std::cout << "ApplyPictureParameters object " << cachedParameters->decodeBeginInfo.videoSessionParameters << " with ID: (" << pOwnerPictureParameters->GetId() << ")"
<< " for SPS: " << spsId << ", PPS: " << ppsId << std::endl;
}
}
void VideoBaseDecoder::WaitForFrameFences(de::MovePtr<CachedDecodeParameters> &cachedParameters)
{
// Check here that the frame for this entry (for this command buffer) has already completed decoding.
// Otherwise we may step over a hot command buffer by starting a new recording.
// This fence wait should be NOP in 99.9% of the cases, because the decode queue is deep enough to
// ensure the frame has already been completed.
VK_CHECK(m_deviceContext->getDeviceDriver().waitForFences(m_deviceContext->device, 1, &cachedParameters->frameSynchronizationInfo.frameCompleteFence, true, TIMEOUT_100ms));
VkResult result = m_deviceContext->getDeviceDriver().getFenceStatus(m_deviceContext->device, cachedParameters->frameSynchronizationInfo.frameCompleteFence);
TCU_CHECK_MSG(result == VK_SUCCESS || result == VK_NOT_READY, "Bad fence status");
}
void VideoBaseDecoder::RecordCommandBuffer(de::MovePtr<CachedDecodeParameters> &cachedParameters)
{
auto &vk = m_deviceContext->getDeviceDriver();
VkCommandBuffer commandBuffer = cachedParameters->frameDataSlot.commandBuffer;
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr;
vk.beginCommandBuffer(commandBuffer, &beginInfo);
if (m_queryResultWithStatus)
{
vk.cmdResetQueryPool(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool, cachedParameters->frameSynchronizationInfo.startQueryId,
cachedParameters->frameSynchronizationInfo.numQueries);
}
vk.cmdBeginVideoCodingKHR(commandBuffer, &cachedParameters->decodeBeginInfo);
if (cachedParameters->performCodecReset)
{
VkVideoCodingControlInfoKHR codingControlInfo = {VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR,
nullptr,
VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR};
vk.cmdControlVideoCodingKHR(commandBuffer, &codingControlInfo);
}
const VkDependencyInfoKHR dependencyInfo = {
VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
nullptr,
VK_DEPENDENCY_BY_REGION_BIT,
0,
nullptr,
1,
&cachedParameters->bitstreamBufferMemoryBarrier,
static_cast<deUint32>(cachedParameters->imageBarriers.size()),
cachedParameters->imageBarriers.data(),
};
vk.cmdPipelineBarrier2(commandBuffer, &dependencyInfo);
if (m_queryResultWithStatus)
{
vk.cmdBeginQuery(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool, cachedParameters->frameSynchronizationInfo.startQueryId, VkQueryControlFlags());
}
vk.cmdDecodeVideoKHR(commandBuffer, &cachedParameters->pictureParams.decodeFrameInfo);
if (m_queryResultWithStatus)
{
vk.cmdEndQuery(commandBuffer, cachedParameters->frameSynchronizationInfo.queryPool, cachedParameters->frameSynchronizationInfo.startQueryId);
}
VkVideoEndCodingInfoKHR decodeEndInfo{};
decodeEndInfo.sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR;
vk.cmdEndVideoCodingKHR(commandBuffer, &decodeEndInfo);
m_deviceContext->getDeviceDriver().endCommandBuffer(commandBuffer);
}
void VideoBaseDecoder::SubmitQueue(de::MovePtr<CachedDecodeParameters> &cachedParameters)
{
auto& vk = m_deviceContext->getDeviceDriver();
auto device = m_deviceContext->device;
VkCommandBuffer commandBuffer = cachedParameters->frameDataSlot.commandBuffer;
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = (cachedParameters->frameSynchronizationInfo.frameConsumerDoneSemaphore == VK_NULL_HANDLE) ? 0 : 1;
submitInfo.pWaitSemaphores = &cachedParameters->frameSynchronizationInfo.frameConsumerDoneSemaphore;
VkPipelineStageFlags videoDecodeSubmitWaitStages = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR;
submitInfo.pWaitDstStageMask = &videoDecodeSubmitWaitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &cachedParameters->frameSynchronizationInfo.frameCompleteSemaphore;
if ((cachedParameters->frameSynchronizationInfo.frameConsumerDoneSemaphore == VK_NULL_HANDLE) &&
(cachedParameters->frameSynchronizationInfo.frameConsumerDoneFence != VK_NULL_HANDLE))
{
VK_CHECK(vk.waitForFences(device, 1, &cachedParameters->frameSynchronizationInfo.frameConsumerDoneFence, true, TIMEOUT_100ms));
VkResult result = vk.getFenceStatus(device, cachedParameters->frameSynchronizationInfo.frameCompleteFence);
TCU_CHECK_MSG(result == VK_SUCCESS || result == VK_NOT_READY, "Bad fence status");
}
VK_CHECK(vk.resetFences(device, 1, &cachedParameters->frameSynchronizationInfo.frameCompleteFence));
VkResult result = vk.getFenceStatus(device, cachedParameters->frameSynchronizationInfo.frameCompleteFence);
TCU_CHECK_MSG(result == VK_SUCCESS || result == VK_NOT_READY, "Bad fence status");
VK_CHECK(vk.queueSubmit(m_deviceContext->decodeQueue, 1, &submitInfo, cachedParameters->frameSynchronizationInfo.frameCompleteFence));
if (videoLoggingEnabled())
{
std::cout << "\t +++++++++++++++++++++++++++< " << cachedParameters->pictureParams.currPicIdx << " >++++++++++++++++++++++++++++++" << std::endl;
std::cout << std::dec << "\t => Decode Submitted for CurrPicIdx: " << cachedParameters->pictureParams.currPicIdx << std::endl
<< "\t\tm_nPicNumInDecodeOrder: " << cachedParameters->picNumInDecodeOrder << "\t\tframeCompleteFence " << cachedParameters->frameSynchronizationInfo.frameCompleteFence
<< "\t\tframeCompleteSemaphore " << cachedParameters->frameSynchronizationInfo.frameCompleteSemaphore << "\t\tdstImageView "
<< cachedParameters->pictureParams.decodeFrameInfo.dstPictureResource.imageViewBinding << std::endl;
}
const bool checkDecodeIdleSync = false; // For fence/sync/idle debugging
if (checkDecodeIdleSync)
{ // For fence/sync debugging
if (cachedParameters->frameSynchronizationInfo.frameCompleteFence == VK_NULL_HANDLE)
{
VK_CHECK(vk.queueWaitIdle(m_deviceContext->decodeQueue));
}
else
{
if (cachedParameters->frameSynchronizationInfo.frameCompleteSemaphore == VK_NULL_HANDLE)
{
VK_CHECK(vk.waitForFences(device, 1, &cachedParameters->frameSynchronizationInfo.frameCompleteFence, true, TIMEOUT_100ms));
result = vk.getFenceStatus(device, cachedParameters->frameSynchronizationInfo.frameCompleteFence);
TCU_CHECK_MSG(result == VK_SUCCESS || result == VK_NOT_READY, "Bad fence status");
}
}
}
}
void VideoBaseDecoder::QueryDecodeResults(de::MovePtr<CachedDecodeParameters> &cachedParameters)
{
auto& vk = m_deviceContext->getDeviceDriver();
auto device = m_deviceContext->device;
VkQueryResultStatusKHR decodeStatus;
VkResult result = vk.getQueryPoolResults(device,
cachedParameters->frameSynchronizationInfo.queryPool,
cachedParameters->frameSynchronizationInfo.startQueryId,
1,
sizeof(decodeStatus),
&decodeStatus,
sizeof(decodeStatus),
VK_QUERY_RESULT_WITH_STATUS_BIT_KHR | VK_QUERY_RESULT_WAIT_BIT);
if (videoLoggingEnabled())
{
std::cout << "\t +++++++++++++++++++++++++++< " << cachedParameters->pictureParams.currPicIdx << " >++++++++++++++++++++++++++++++" << std::endl;
std::cout << "\t => Decode Status for CurrPicIdx: " << cachedParameters->pictureParams.currPicIdx << std::endl
<< "\t\tdecodeStatus: " << decodeStatus << std::endl;
}
TCU_CHECK_AND_THROW(TestError, result == VK_SUCCESS || result == VK_ERROR_DEVICE_LOST, "Driver has returned an invalid query result");
TCU_CHECK_AND_THROW(TestError, decodeStatus != VK_QUERY_RESULT_STATUS_ERROR_KHR, "Decode query returned an unexpected error");
}
void VideoBaseDecoder::decodeFramesOutOfOrder()
{
std::vector<int> ordering(m_cachedDecodeParams.size());
std::iota(ordering.begin(), ordering.end(), 0);
if (ordering.size() == 2)
std::swap(ordering[0], ordering[1]);
else // TODO: test seeding
std::shuffle(ordering.begin(), ordering.end(), std::mt19937{std::random_device{}()});
DE_ASSERT(m_cachedDecodeParams.size() > 1);
// Record out of order
for (int recordOrderIdx : ordering)
{
auto &cachedParams = m_cachedDecodeParams[recordOrderIdx];
WaitForFrameFences(cachedParams);
ApplyPictureParameters(cachedParams);
RecordCommandBuffer(cachedParams);
}
// Submit in order
for (int i = 0; i < m_cachedDecodeParams.size(); i++)
{
auto& cachedParams = m_cachedDecodeParams[i];
SubmitQueue(cachedParams);
if (m_queryResultWithStatus)
{
QueryDecodeResults(cachedParams);
}
}
}
bool VideoBaseDecoder::UpdatePictureParameters(VkSharedBaseObj<StdVideoPictureParametersSet>& pictureParametersObject, /* in */
VkSharedBaseObj<VkVideoRefCountBase>& client)
{
triggerPictureParameterSequenceCount();
VkResult result = VkParserVideoPictureParameters::AddPictureParameters(*m_deviceContext,
m_videoSession,
pictureParametersObject,
m_currentPictureParameters);
client = m_currentPictureParameters;
return (result == VK_SUCCESS);
}
bool VideoBaseDecoder::DisplayPicture (VkPicIf* pNvidiaVulkanPicture,
int64_t /*llPTS*/)
{
vkPicBuffBase* pVkPicBuff = GetPic(pNvidiaVulkanPicture);
DE_ASSERT(pVkPicBuff != DE_NULL);
int32_t picIdx = pVkPicBuff ? pVkPicBuff->m_picIdx : -1;
DE_ASSERT(picIdx != -1);
DE_ASSERT(m_videoFrameBuffer != nullptr);
if (videoLoggingEnabled())
{
std::cout << "\t ======================< " << picIdx << " >============================" << std::endl;
std::cout << "\t ==> VulkanVideoParser::DisplayPicture " << picIdx << std::endl;
}
VulkanVideoDisplayPictureInfo dispInfo = VulkanVideoDisplayPictureInfo();
dispInfo.timestamp = 0; // NOTE: we ignore PTS in the CTS
const int32_t retVal = m_videoFrameBuffer->QueueDecodedPictureForDisplay((int8_t)picIdx, &dispInfo);
DE_ASSERT(picIdx == retVal);
DE_UNREF(retVal);
return true;
}
int32_t VideoBaseDecoder::ReleaseDisplayedFrame(DecodedFrame* pDisplayedFrame)
{
if (pDisplayedFrame->pictureIndex == -1)
return -1;
DecodedFrameRelease decodedFramesRelease = {pDisplayedFrame->pictureIndex, 0, 0, 0, 0, 0};
DecodedFrameRelease* decodedFramesReleasePtr = &decodedFramesRelease;
pDisplayedFrame->pictureIndex = -1;
decodedFramesRelease.decodeOrder = pDisplayedFrame->decodeOrder;
decodedFramesRelease.displayOrder = pDisplayedFrame->displayOrder;
decodedFramesRelease.hasConsummerSignalFence = pDisplayedFrame->hasConsummerSignalFence;
decodedFramesRelease.hasConsummerSignalSemaphore = pDisplayedFrame->hasConsummerSignalSemaphore;
decodedFramesRelease.timestamp = 0;
return m_videoFrameBuffer->ReleaseDisplayedPicture(&decodedFramesReleasePtr, 1);
}
VkDeviceSize VideoBaseDecoder::GetBitstreamBuffer(VkDeviceSize size, VkDeviceSize minBitstreamBufferOffsetAlignment, VkDeviceSize minBitstreamBufferSizeAlignment, const deUint8* pInitializeBufferMemory, VkDeviceSize initializeBufferMemorySize, VkSharedBaseObj<VulkanBitstreamBuffer>& bitstreamBuffer)
{
DE_ASSERT(initializeBufferMemorySize <= size);
VkDeviceSize newSize = size;
VkSharedBaseObj<BitstreamBufferImpl> newBitstreamBuffer;
VK_CHECK(BitstreamBufferImpl::Create(m_deviceContext,
m_deviceContext->decodeQueueFamilyIdx(),
newSize,
minBitstreamBufferOffsetAlignment,
minBitstreamBufferSizeAlignment,
newBitstreamBuffer,
m_profile.GetProfileListInfo()));
if (videoLoggingEnabled())
{
std::cout << "\tAllocated bitstream buffer with size " << newSize << " B, " << newSize / 1024 << " KB, " << newSize / 1024 / 1024 << " MB" << std::endl;
}
DE_ASSERT(newBitstreamBuffer);
newSize = newBitstreamBuffer->GetMaxSize();
DE_ASSERT(initializeBufferMemorySize <= newSize);
size_t bytesToCopy = std::min(initializeBufferMemorySize, newSize);
size_t bytesCopied = newBitstreamBuffer->CopyDataFromBuffer((const deUint8*)pInitializeBufferMemory, 0, 0, bytesToCopy);
DE_ASSERT(bytesToCopy == bytesCopied);
DE_UNREF(bytesCopied);
newBitstreamBuffer->MemsetData(0x0, bytesToCopy, newSize - bytesToCopy);
if (videoLoggingEnabled())
{
std::cout << "\t\tFrom bitstream buffer pool with size " << newSize << " B, " << newSize / 1024 << " KB, " << newSize / 1024 / 1024 << " MB" << std::endl;
std::cout << "\t\t\t FreeNodes " << m_decodeFramesData.GetBitstreamBuffersQueue().GetFreeNodesNumber();
std::cout << " of MaxNodes " << m_decodeFramesData.GetBitstreamBuffersQueue().GetMaxNodes();
std::cout << ", AvailableNodes " << m_decodeFramesData.GetBitstreamBuffersQueue().GetAvailableNodesNumber();
std::cout << std::endl;
}
bitstreamBuffer = newBitstreamBuffer;
if (videoLoggingEnabled() && newSize > m_maxStreamBufferSize)
{
std::cout << "\tAllocated bitstream buffer with size " << newSize << " B, " << newSize / 1024 << " KB, " << newSize / 1024 / 1024 << " MB" << std::endl;
m_maxStreamBufferSize = newSize;
}
return bitstreamBuffer->GetMaxSize();
}
void VideoBaseDecoder::UnhandledNALU (const deUint8* pbData,
size_t cbData)
{
const vector<deUint8> data (pbData, pbData + cbData);
ostringstream css;
css << "UnhandledNALU=";
for (const auto& i: data)
css << std::hex << std::setw(2) << std::setfill('0') << (deUint32)i << ' ';
TCU_THROW(InternalError, css.str());
}
deUint32 VideoBaseDecoder::FillDpbH264State (const VkParserPictureData * pd,
const VkParserH264DpbEntry* dpbIn,
deUint32 maxDpbInSlotsInUse,
nvVideoDecodeH264DpbSlotInfo* pDpbRefList,
deUint32 /*maxRefPictures*/,
VkVideoReferenceSlotInfoKHR* pReferenceSlots,
int8_t* pGopReferenceImagesIndexes,
StdVideoDecodeH264PictureInfoFlags currPicFlags,
int32_t* pCurrAllocatedSlotIndex)
{
// #### Update m_dpb based on dpb parameters ####
// Create unordered DPB and generate a bitmask of all render targets present
// in DPB
deUint32 num_ref_frames = pd->CodecSpecific.h264.pStdSps->GetStdH264Sps()->max_num_ref_frames;
DE_ASSERT(num_ref_frames <= HEVC_MAX_DPB_SLOTS);
DE_ASSERT(num_ref_frames <= m_maxNumDpbSlots);
dpbH264Entry refOnlyDpbIn[AVC_MAX_DPB_SLOTS]; // max number of Dpb
// surfaces
memset(&refOnlyDpbIn, 0, m_maxNumDpbSlots * sizeof(refOnlyDpbIn[0]));
deUint32 refDpbUsedAndValidMask = 0;
deUint32 numUsedRef = 0;
for (int32_t inIdx = 0; (deUint32)inIdx < maxDpbInSlotsInUse; inIdx++) {
// used_for_reference: 0 = unused, 1 = top_field, 2 = bottom_field, 3 =
// both_fields
const deUint32 used_for_reference = dpbIn[inIdx].used_for_reference & fieldIsReferenceMask;
if (used_for_reference) {
int8_t picIdx = (!dpbIn[inIdx].not_existing && dpbIn[inIdx].pPicBuf)
? GetPicIdx(dpbIn[inIdx].pPicBuf)
: -1;
const bool isFieldRef = (picIdx >= 0) ? GetFieldPicFlag(picIdx)
: (used_for_reference && (used_for_reference != fieldIsReferenceMask));
const int16_t fieldOrderCntList[2] = {
(int16_t)dpbIn[inIdx].FieldOrderCnt[0],
(int16_t)dpbIn[inIdx].FieldOrderCnt[1]
};
refOnlyDpbIn[numUsedRef].setReferenceAndTopBottomField(
!!used_for_reference,
(picIdx < 0), /* not_existing is frame inferred by the decoding
process for gaps in frame_num */
!!dpbIn[inIdx].is_long_term, isFieldRef,
!!(used_for_reference & topFieldMask),
!!(used_for_reference & bottomFieldMask), dpbIn[inIdx].FrameIdx,
fieldOrderCntList, GetPic(dpbIn[inIdx].pPicBuf));
if (picIdx >= 0) {
refDpbUsedAndValidMask |= (1 << picIdx);
}
numUsedRef++;
}
// Invalidate all slots.
pReferenceSlots[inIdx].slotIndex = -1;
pGopReferenceImagesIndexes[inIdx] = -1;
}
DE_ASSERT(numUsedRef <= HEVC_MAX_DPB_SLOTS);
DE_ASSERT(numUsedRef <= m_maxNumDpbSlots);
DE_ASSERT(numUsedRef <= num_ref_frames);
if (videoLoggingEnabled()) {
std::cout << " =>>> ********************* picIdx: "
<< (int32_t)GetPicIdx(pd->pCurrPic)
<< " *************************" << std::endl;
std::cout << "\tRef frames data in for picIdx: "
<< (int32_t)GetPicIdx(pd->pCurrPic) << std::endl
<< "\tSlot Index:\t\t";
if (numUsedRef == 0)
std::cout << "(none)" << std::endl;
else
{
for (deUint32 slot = 0; slot < numUsedRef; slot++)
{
if (!refOnlyDpbIn[slot].is_non_existing)
{
std::cout << slot << ",\t";
}
else
{
std::cout << 'X' << ",\t";
}
}
std::cout << std::endl;
}
std::cout << "\tPict Index:\t\t";
if (numUsedRef == 0)
std::cout << "(none)" << std::endl;
else
{
for (deUint32 slot = 0; slot < numUsedRef; slot++)
{
if (!refOnlyDpbIn[slot].is_non_existing)
{
std::cout << refOnlyDpbIn[slot].m_picBuff->m_picIdx << ",\t";
}
else
{
std::cout << 'X' << ",\t";
}
}
}
std::cout << "\n\tTotal Ref frames for picIdx: "
<< (int32_t)GetPicIdx(pd->pCurrPic) << " : " << numUsedRef
<< " out of " << num_ref_frames << " MAX(" << m_maxNumDpbSlots
<< ")" << std::endl
<< std::endl;
std::cout << std::flush;
}
// Map all frames not present in DPB as non-reference, and generate a mask of
// all used DPB entries
/* deUint32 destUsedDpbMask = */ ResetPicDpbSlots(refDpbUsedAndValidMask);
// Now, map DPB render target indices to internal frame buffer index,
// assign each reference a unique DPB entry, and create the ordered DPB
// This is an undocumented MV restriction: the position in the DPB is stored
// along with the co-located data, so once a reference frame is assigned a DPB
// entry, it can no longer change.
// Find or allocate slots for existing dpb items.
// Take into account the reference picture now.
int8_t currPicIdx = GetPicIdx(pd->pCurrPic);
DE_ASSERT(currPicIdx >= 0);
int8_t bestNonExistingPicIdx = currPicIdx;
if (refDpbUsedAndValidMask) {
int32_t minFrameNumDiff = 0x10000;
for (int32_t dpbIdx = 0; (deUint32)dpbIdx < numUsedRef; dpbIdx++) {
if (!refOnlyDpbIn[dpbIdx].is_non_existing) {
vkPicBuffBase* picBuff = refOnlyDpbIn[dpbIdx].m_picBuff;
int8_t picIdx = GetPicIdx(picBuff); // should always be valid at this point
DE_ASSERT(picIdx >= 0);
// We have up to 17 internal frame buffers, but only MAX_DPB_SIZE dpb
// entries, so we need to re-map the index from the [0..MAX_DPB_SIZE]
// range to [0..15]
int8_t dpbSlot = GetPicDpbSlot(picIdx);
if (dpbSlot < 0) {
dpbSlot = m_dpb.AllocateSlot();
DE_ASSERT((dpbSlot >= 0) && ((deUint32)dpbSlot < m_maxNumDpbSlots));
SetPicDpbSlot(picIdx, dpbSlot);
m_dpb[dpbSlot].setPictureResource(picBuff, m_nCurrentPictureID);
}
m_dpb[dpbSlot].MarkInUse(m_nCurrentPictureID);
DE_ASSERT(dpbSlot >= 0);
if (dpbSlot >= 0) {
refOnlyDpbIn[dpbIdx].dpbSlot = dpbSlot;
} else {
// This should never happen
printf("DPB mapping logic broken!\n");
DE_ASSERT(0);
}
int32_t frameNumDiff = ((int32_t)pd->CodecSpecific.h264.frame_num - refOnlyDpbIn[dpbIdx].FrameIdx);
if (frameNumDiff <= 0) {
frameNumDiff = 0xffff;
}
if (frameNumDiff < minFrameNumDiff) {
bestNonExistingPicIdx = picIdx;
minFrameNumDiff = frameNumDiff;
} else if (bestNonExistingPicIdx == currPicIdx) {
bestNonExistingPicIdx = picIdx;
}
}
}
}
// In Vulkan, we always allocate a Dbp slot for the current picture,
// regardless if it is going to become a reference or not. Non-reference slots
// get freed right after usage. if (pd->ref_pic_flag) {
int8_t currPicDpbSlot = AllocateDpbSlotForCurrentH264(GetPic(pd->pCurrPic),
currPicFlags, pd->current_dpb_id);
DE_ASSERT(currPicDpbSlot >= 0);
*pCurrAllocatedSlotIndex = currPicDpbSlot;
if (refDpbUsedAndValidMask) {
// Find or allocate slots for non existing dpb items and populate the slots.
deUint32 dpbInUseMask = m_dpb.getSlotInUseMask();
int8_t firstNonExistingDpbSlot = 0;
for (deUint32 dpbIdx = 0; dpbIdx < numUsedRef; dpbIdx++) {
int8_t dpbSlot = -1;
int8_t picIdx = -1;
if (refOnlyDpbIn[dpbIdx].is_non_existing) {
DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff == NULL);
while (((deUint32)firstNonExistingDpbSlot < m_maxNumDpbSlots) && (dpbSlot == -1)) {
if (!(dpbInUseMask & (1 << firstNonExistingDpbSlot))) {
dpbSlot = firstNonExistingDpbSlot;
}
firstNonExistingDpbSlot++;
}
DE_ASSERT((dpbSlot >= 0) && ((deUint32)dpbSlot < m_maxNumDpbSlots));
picIdx = bestNonExistingPicIdx;
// Find the closest valid refpic already in the DPB
deUint32 minDiffPOC = 0x7fff;
for (deUint32 j = 0; j < numUsedRef; j++) {
if (!refOnlyDpbIn[j].is_non_existing && (refOnlyDpbIn[j].used_for_reference & refOnlyDpbIn[dpbIdx].used_for_reference) == refOnlyDpbIn[dpbIdx].used_for_reference) {
deUint32 diffPOC = abs((int32_t)(refOnlyDpbIn[j].FieldOrderCnt[0] - refOnlyDpbIn[dpbIdx].FieldOrderCnt[0]));
if (diffPOC <= minDiffPOC) {
minDiffPOC = diffPOC;
picIdx = GetPicIdx(refOnlyDpbIn[j].m_picBuff);
}
}
}
} else {
DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff != NULL);
dpbSlot = refOnlyDpbIn[dpbIdx].dpbSlot;
picIdx = GetPicIdx(refOnlyDpbIn[dpbIdx].m_picBuff);
}
DE_ASSERT((dpbSlot >= 0) && ((deUint32)dpbSlot < m_maxNumDpbSlots));
refOnlyDpbIn[dpbIdx].setH264PictureData(pDpbRefList, pReferenceSlots,
dpbIdx, dpbSlot, pd->progressive_frame);
pGopReferenceImagesIndexes[dpbIdx] = picIdx;
}
}
if (videoLoggingEnabled()) {
deUint32 slotInUseMask = m_dpb.getSlotInUseMask();
deUint32 slotsInUseCount = 0;
std::cout << "\tAllocated DPB slot " << (int32_t)currPicDpbSlot << " for "
<< (pd->ref_pic_flag ? "REFERENCE" : "NON-REFERENCE")
<< " picIdx: " << (int32_t)currPicIdx << std::endl;
std::cout << "\tDPB frames map for picIdx: " << (int32_t)currPicIdx
<< std::endl
<< "\tSlot Index:\t\t";
for (deUint32 slot = 0; slot < m_dpb.getMaxSize(); slot++) {
if (slotInUseMask & (1 << slot)) {
std::cout << slot << ",\t";
slotsInUseCount++;
} else {
std::cout << 'X' << ",\t";
}
}
std::cout << std::endl
<< "\tPict Index:\t\t";
for (deUint32 slot = 0; slot < m_dpb.getMaxSize(); slot++) {
if (slotInUseMask & (1 << slot)) {
if (m_dpb[slot].getPictureResource()) {
std::cout << m_dpb[slot].getPictureResource()->m_picIdx << ",\t";
} else {
std::cout << "non existent"
<< ",\t";
}
} else {
std::cout << 'X' << ",\t";
}
}
std::cout << "\n\tTotal slots in use for picIdx: " << (int32_t)currPicIdx
<< " : " << slotsInUseCount << " out of " << m_dpb.getMaxSize()
<< std::endl;
std::cout << " <<<= ********************* picIdx: "
<< (int32_t)GetPicIdx(pd->pCurrPic)
<< " *************************" << std::endl
<< std::endl;
std::cout << std::flush;
}
return refDpbUsedAndValidMask ? numUsedRef : 0;}
deUint32 VideoBaseDecoder::FillDpbH265State (const VkParserPictureData* pd,
const VkParserHevcPictureData* pin,
nvVideoDecodeH265DpbSlotInfo* pDpbSlotInfo,
StdVideoDecodeH265PictureInfo* pStdPictureInfo,
deUint32 /*maxRefPictures*/,
VkVideoReferenceSlotInfoKHR* pReferenceSlots,
int8_t* pGopReferenceImagesIndexes,
int32_t* pCurrAllocatedSlotIndex)
{
// #### Update m_dpb based on dpb parameters ####
// Create unordered DPB and generate a bitmask of all render targets present
// in DPB
dpbH264Entry refOnlyDpbIn[HEVC_MAX_DPB_SLOTS];
DE_ASSERT(m_maxNumDpbSlots <= HEVC_MAX_DPB_SLOTS);
memset(&refOnlyDpbIn, 0, m_maxNumDpbSlots * sizeof(refOnlyDpbIn[0]));
deUint32 refDpbUsedAndValidMask = 0;
deUint32 numUsedRef = 0;
if (videoLoggingEnabled())
std::cout << "Ref frames data: " << std::endl;
for (int32_t inIdx = 0; inIdx < HEVC_MAX_DPB_SLOTS; inIdx++) {
// used_for_reference: 0 = unused, 1 = top_field, 2 = bottom_field, 3 =
// both_fields
int8_t picIdx = GetPicIdx(pin->RefPics[inIdx]);
if (picIdx >= 0) {
DE_ASSERT(numUsedRef < HEVC_MAX_DPB_SLOTS);
refOnlyDpbIn[numUsedRef].setReference((pin->IsLongTerm[inIdx] == 1),
pin->PicOrderCntVal[inIdx],
GetPic(pin->RefPics[inIdx]));
if (picIdx >= 0) {
refDpbUsedAndValidMask |= (1 << picIdx);
}
refOnlyDpbIn[numUsedRef].originalDpbIndex = inIdx;
numUsedRef++;
}
// Invalidate all slots.
pReferenceSlots[inIdx].slotIndex = -1;
pGopReferenceImagesIndexes[inIdx] = -1;
}
if (videoLoggingEnabled())
std::cout << "Total Ref frames: " << numUsedRef << std::endl;
DE_ASSERT(numUsedRef <= m_maxNumDpbSlots);
DE_ASSERT(numUsedRef <= HEVC_MAX_DPB_SLOTS);
// Take into account the reference picture now.
int8_t currPicIdx = GetPicIdx(pd->pCurrPic);
DE_ASSERT(currPicIdx >= 0);
if (currPicIdx >= 0) {
refDpbUsedAndValidMask |= (1 << currPicIdx);
}
// Map all frames not present in DPB as non-reference, and generate a mask of
// all used DPB entries
/* deUint32 destUsedDpbMask = */ ResetPicDpbSlots(refDpbUsedAndValidMask);
// Now, map DPB render target indices to internal frame buffer index,
// assign each reference a unique DPB entry, and create the ordered DPB
// This is an undocumented MV restriction: the position in the DPB is stored
// along with the co-located data, so once a reference frame is assigned a DPB
// entry, it can no longer change.
int8_t frmListToDpb[HEVC_MAX_DPB_SLOTS];
// TODO change to -1 for invalid indexes.
memset(&frmListToDpb, 0, sizeof(frmListToDpb));
// Find or allocate slots for existing dpb items.
for (int32_t dpbIdx = 0; (deUint32)dpbIdx < numUsedRef; dpbIdx++) {
if (!refOnlyDpbIn[dpbIdx].is_non_existing) {
vkPicBuffBase* picBuff = refOnlyDpbIn[dpbIdx].m_picBuff;
int32_t picIdx = GetPicIdx(picBuff); // should always be valid at this point
DE_ASSERT(picIdx >= 0);
// We have up to 17 internal frame buffers, but only HEVC_MAX_DPB_SLOTS
// dpb entries, so we need to re-map the index from the
// [0..HEVC_MAX_DPB_SLOTS] range to [0..15]
int8_t dpbSlot = GetPicDpbSlot(picIdx);
if (dpbSlot < 0) {
dpbSlot = m_dpb.AllocateSlot();
DE_ASSERT(dpbSlot >= 0);
SetPicDpbSlot(picIdx, dpbSlot);
m_dpb[dpbSlot].setPictureResource(picBuff, m_nCurrentPictureID);
}
m_dpb[dpbSlot].MarkInUse(m_nCurrentPictureID);
DE_ASSERT(dpbSlot >= 0);
if (dpbSlot >= 0) {
refOnlyDpbIn[dpbIdx].dpbSlot = dpbSlot;
deUint32 originalDpbIndex = refOnlyDpbIn[dpbIdx].originalDpbIndex;
DE_ASSERT(originalDpbIndex < HEVC_MAX_DPB_SLOTS);
frmListToDpb[originalDpbIndex] = dpbSlot;
} else {
// This should never happen
printf("DPB mapping logic broken!\n");
DE_ASSERT(0);
}
}
}
// Find or allocate slots for non existing dpb items and populate the slots.
deUint32 dpbInUseMask = m_dpb.getSlotInUseMask();
int8_t firstNonExistingDpbSlot = 0;
for (deUint32 dpbIdx = 0; dpbIdx < numUsedRef; dpbIdx++) {
int8_t dpbSlot = -1;
if (refOnlyDpbIn[dpbIdx].is_non_existing) {
// There shouldn't be not_existing in h.265
DE_ASSERT(0);
DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff == NULL);
while (((deUint32)firstNonExistingDpbSlot < m_maxNumDpbSlots) && (dpbSlot == -1)) {
if (!(dpbInUseMask & (1 << firstNonExistingDpbSlot))) {
dpbSlot = firstNonExistingDpbSlot;
}
firstNonExistingDpbSlot++;
}
DE_ASSERT((dpbSlot >= 0) && ((deUint32)dpbSlot < m_maxNumDpbSlots));
} else {
DE_ASSERT(refOnlyDpbIn[dpbIdx].m_picBuff != NULL);
dpbSlot = refOnlyDpbIn[dpbIdx].dpbSlot;
}
DE_ASSERT((dpbSlot >= 0) && (dpbSlot < HEVC_MAX_DPB_SLOTS));
refOnlyDpbIn[dpbIdx].setH265PictureData(pDpbSlotInfo, pReferenceSlots,
dpbIdx, dpbSlot);
pGopReferenceImagesIndexes[dpbIdx] = GetPicIdx(refOnlyDpbIn[dpbIdx].m_picBuff);
}
if (videoLoggingEnabled()) {
std::cout << "frmListToDpb:" << std::endl;
for (int8_t dpbResIdx = 0; dpbResIdx < HEVC_MAX_DPB_SLOTS; dpbResIdx++) {
std::cout << "\tfrmListToDpb[" << (int32_t)dpbResIdx << "] is "
<< (int32_t)frmListToDpb[dpbResIdx] << std::endl;
}
}
int32_t numPocStCurrBefore = 0;
const size_t maxNumPocStCurrBefore = sizeof(pStdPictureInfo->RefPicSetStCurrBefore) / sizeof(pStdPictureInfo->RefPicSetStCurrBefore[0]);
DE_ASSERT((size_t)pin->NumPocStCurrBefore <= maxNumPocStCurrBefore);
if ((size_t)pin->NumPocStCurrBefore > maxNumPocStCurrBefore) {
tcu::print("\nERROR: FillDpbH265State() pin->NumPocStCurrBefore(%d) must be smaller than maxNumPocStCurrBefore(%zd)\n", pin->NumPocStCurrBefore, maxNumPocStCurrBefore);
}
for (int32_t i = 0; i < pin->NumPocStCurrBefore; i++) {
deUint8 idx = (deUint8)pin->RefPicSetStCurrBefore[i];
if (idx < HEVC_MAX_DPB_SLOTS) {
if (videoLoggingEnabled())
std::cout << "\trefPicSetStCurrBefore[" << i << "] is " << (int32_t)idx
<< " -> " << (int32_t)frmListToDpb[idx] << std::endl;
pStdPictureInfo->RefPicSetStCurrBefore[numPocStCurrBefore++] = frmListToDpb[idx] & 0xf;
}
}
while (numPocStCurrBefore < 8) {
pStdPictureInfo->RefPicSetStCurrBefore[numPocStCurrBefore++] = 0xff;
}
int32_t numPocStCurrAfter = 0;
const size_t maxNumPocStCurrAfter = sizeof(pStdPictureInfo->RefPicSetStCurrAfter) / sizeof(pStdPictureInfo->RefPicSetStCurrAfter[0]);
DE_ASSERT((size_t)pin->NumPocStCurrAfter <= maxNumPocStCurrAfter);
if ((size_t)pin->NumPocStCurrAfter > maxNumPocStCurrAfter) {
fprintf(stderr, "\nERROR: FillDpbH265State() pin->NumPocStCurrAfter(%d) must be smaller than maxNumPocStCurrAfter(%zd)\n", pin->NumPocStCurrAfter, maxNumPocStCurrAfter);
}
for (int32_t i = 0; i < pin->NumPocStCurrAfter; i++) {
deUint8 idx = (deUint8)pin->RefPicSetStCurrAfter[i];
if (idx < HEVC_MAX_DPB_SLOTS) {
if (videoLoggingEnabled())
std::cout << "\trefPicSetStCurrAfter[" << i << "] is " << (int32_t)idx
<< " -> " << (int32_t)frmListToDpb[idx] << std::endl;
pStdPictureInfo->RefPicSetStCurrAfter[numPocStCurrAfter++] = frmListToDpb[idx] & 0xf;
}
}
while (numPocStCurrAfter < 8) {
pStdPictureInfo->RefPicSetStCurrAfter[numPocStCurrAfter++] = 0xff;
}
int32_t numPocLtCurr = 0;
const size_t maxNumPocLtCurr = sizeof(pStdPictureInfo->RefPicSetLtCurr) / sizeof(pStdPictureInfo->RefPicSetLtCurr[0]);
DE_ASSERT((size_t)pin->NumPocLtCurr <= maxNumPocLtCurr);
if ((size_t)pin->NumPocLtCurr > maxNumPocLtCurr) {
fprintf(stderr, "\nERROR: FillDpbH265State() pin->NumPocLtCurr(%d) must be smaller than maxNumPocLtCurr(%zd)\n", pin->NumPocLtCurr, maxNumPocLtCurr);
}
for (int32_t i = 0; i < pin->NumPocLtCurr; i++) {
deUint8 idx = (deUint8)pin->RefPicSetLtCurr[i];
if (idx < HEVC_MAX_DPB_SLOTS) {
if (videoLoggingEnabled())
std::cout << "\trefPicSetLtCurr[" << i << "] is " << (int32_t)idx
<< " -> " << (int32_t)frmListToDpb[idx] << std::endl;
pStdPictureInfo->RefPicSetLtCurr[numPocLtCurr++] = frmListToDpb[idx] & 0xf;
}
}
while (numPocLtCurr < 8) {
pStdPictureInfo->RefPicSetLtCurr[numPocLtCurr++] = 0xff;
}
for (int32_t i = 0; i < 8; i++) {
if (videoLoggingEnabled())
std::cout << "\tlist indx " << i << ": "
<< " refPicSetStCurrBefore: "
<< (int32_t)pStdPictureInfo->RefPicSetStCurrBefore[i]
<< " refPicSetStCurrAfter: "
<< (int32_t)pStdPictureInfo->RefPicSetStCurrAfter[i]
<< " refPicSetLtCurr: "
<< (int32_t)pStdPictureInfo->RefPicSetLtCurr[i] << std::endl;
}
int8_t dpbSlot = AllocateDpbSlotForCurrentH265(GetPic(pd->pCurrPic),
true /* isReference */, pd->current_dpb_id);
*pCurrAllocatedSlotIndex = dpbSlot;
DE_ASSERT(!(dpbSlot < 0));
if (dpbSlot >= 0) {
DE_ASSERT(pd->ref_pic_flag);
}
return numUsedRef;
}
int8_t VideoBaseDecoder::AllocateDpbSlotForCurrentH264 (vkPicBuffBase* pPic, StdVideoDecodeH264PictureInfoFlags currPicFlags,
int8_t /*presetDpbSlot*/)
{
// Now, map the current render target
int8_t dpbSlot = -1;
int8_t currPicIdx = GetPicIdx(pPic);
DE_ASSERT(currPicIdx >= 0);
SetFieldPicFlag(currPicIdx, currPicFlags.field_pic_flag);
// In Vulkan we always allocate reference slot for the current picture.
if (true /* currPicFlags.is_reference */) {
dpbSlot = GetPicDpbSlot(currPicIdx);
if (dpbSlot < 0) {
dpbSlot = m_dpb.AllocateSlot();
DE_ASSERT(dpbSlot >= 0);
SetPicDpbSlot(currPicIdx, dpbSlot);
m_dpb[dpbSlot].setPictureResource(pPic, m_nCurrentPictureID);
}
DE_ASSERT(dpbSlot >= 0);
}
return dpbSlot;
}
int8_t VideoBaseDecoder::AllocateDpbSlotForCurrentH265 (vkPicBuffBase* pPic,
bool isReference, int8_t /*presetDpbSlot*/)
{
// Now, map the current render target
int8_t dpbSlot = -1;
int8_t currPicIdx = GetPicIdx(pPic);
DE_ASSERT(currPicIdx >= 0);
DE_ASSERT(isReference);
if (isReference) {
dpbSlot = GetPicDpbSlot(currPicIdx);
if (dpbSlot < 0) {
dpbSlot = m_dpb.AllocateSlot();
DE_ASSERT(dpbSlot >= 0);
SetPicDpbSlot(currPicIdx, dpbSlot);
m_dpb[dpbSlot].setPictureResource(pPic, m_nCurrentPictureID);
}
DE_ASSERT(dpbSlot >= 0);
}
return dpbSlot;
}
VkFormat getRecommendedFormat (const vector<VkFormat>& formats, VkFormat recommendedFormat)
{
if (formats.empty())
return VK_FORMAT_UNDEFINED;
else if (recommendedFormat != VK_FORMAT_UNDEFINED && std::find(formats.begin(), formats.end(), recommendedFormat) != formats.end())
return recommendedFormat;
else
return formats[0];
}
VkResult VulkanVideoSession::Create(DeviceContext& vkDevCtx,
deUint32 videoQueueFamily,
VkVideoCoreProfile* pVideoProfile,
VkFormat pictureFormat,
const VkExtent2D& maxCodedExtent,
VkFormat referencePicturesFormat,
deUint32 maxDpbSlots,
deUint32 maxActiveReferencePictures,
VkSharedBaseObj<VulkanVideoSession>& videoSession)
{
auto& vk = vkDevCtx.getDeviceDriver();
auto device = vkDevCtx.device;
VulkanVideoSession* pNewVideoSession = new VulkanVideoSession(vkDevCtx, pVideoProfile);
static const VkExtensionProperties h264DecodeStdExtensionVersion = { VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION };
static const VkExtensionProperties h265DecodeStdExtensionVersion = { VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION };
static const VkExtensionProperties h264EncodeStdExtensionVersion = { VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION };
static const VkExtensionProperties h265EncodeStdExtensionVersion = { VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME, VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION };
VkVideoSessionCreateInfoKHR& createInfo = pNewVideoSession->m_createInfo;
createInfo.flags = 0;
createInfo.pVideoProfile = pVideoProfile->GetProfile();
createInfo.queueFamilyIndex = videoQueueFamily;
createInfo.pictureFormat = pictureFormat;
createInfo.maxCodedExtent = maxCodedExtent;
createInfo.maxDpbSlots = maxDpbSlots;
createInfo.maxActiveReferencePictures = maxActiveReferencePictures;
createInfo.referencePictureFormat = referencePicturesFormat;
switch ((int32_t)pVideoProfile->GetCodecType()) {
case VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
createInfo.pStdHeaderVersion = &h264DecodeStdExtensionVersion;
break;
case VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
createInfo.pStdHeaderVersion = &h265DecodeStdExtensionVersion;
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT:
createInfo.pStdHeaderVersion = &h264EncodeStdExtensionVersion;
break;
case VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_EXT:
createInfo.pStdHeaderVersion = &h265EncodeStdExtensionVersion;
break;
default:
DE_ASSERT(0);
}
VkResult result = vk.createVideoSessionKHR(device, &createInfo, NULL, &pNewVideoSession->m_videoSession);
if (result != VK_SUCCESS) {
return result;
}
deUint32 videoSessionMemoryRequirementsCount = 0;
VkVideoSessionMemoryRequirementsKHR decodeSessionMemoryRequirements[MAX_BOUND_MEMORY];
// Get the count first
result = vk.getVideoSessionMemoryRequirementsKHR(device, pNewVideoSession->m_videoSession,
&videoSessionMemoryRequirementsCount, NULL);
DE_ASSERT(result == VK_SUCCESS);
DE_ASSERT(videoSessionMemoryRequirementsCount <= MAX_BOUND_MEMORY);
memset(decodeSessionMemoryRequirements, 0x00, sizeof(decodeSessionMemoryRequirements));
for (deUint32 i = 0; i < videoSessionMemoryRequirementsCount; i++) {
decodeSessionMemoryRequirements[i].sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR;
}
result = vk.getVideoSessionMemoryRequirementsKHR(device, pNewVideoSession->m_videoSession,
&videoSessionMemoryRequirementsCount,
decodeSessionMemoryRequirements);
if (result != VK_SUCCESS) {
return result;
}
deUint32 decodeSessionBindMemoryCount = videoSessionMemoryRequirementsCount;
VkBindVideoSessionMemoryInfoKHR decodeSessionBindMemory[MAX_BOUND_MEMORY];
for (deUint32 memIdx = 0; memIdx < decodeSessionBindMemoryCount; memIdx++) {
deUint32 memoryTypeIndex = 0;
deUint32 memoryTypeBits = decodeSessionMemoryRequirements[memIdx].memoryRequirements.memoryTypeBits;
if (memoryTypeBits == 0) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Find an available memory type that satisfies the requested properties.
for (; !(memoryTypeBits & 1); memoryTypeIndex++ ) {
memoryTypeBits >>= 1;
}
VkMemoryAllocateInfo memInfo = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType
NULL, // pNext
decodeSessionMemoryRequirements[memIdx].memoryRequirements.size, // allocationSize
memoryTypeIndex, // memoryTypeIndex
};
result = vk.allocateMemory(device, &memInfo, 0,
&pNewVideoSession->m_memoryBound[memIdx]);
if (result != VK_SUCCESS) {
return result;
}
DE_ASSERT(result == VK_SUCCESS);
decodeSessionBindMemory[memIdx].pNext = NULL;
decodeSessionBindMemory[memIdx].sType = VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR;
decodeSessionBindMemory[memIdx].memory = pNewVideoSession->m_memoryBound[memIdx];
decodeSessionBindMemory[memIdx].memoryBindIndex = decodeSessionMemoryRequirements[memIdx].memoryBindIndex;
decodeSessionBindMemory[memIdx].memoryOffset = 0;
decodeSessionBindMemory[memIdx].memorySize = decodeSessionMemoryRequirements[memIdx].memoryRequirements.size;
}
result = vk.bindVideoSessionMemoryKHR(device, pNewVideoSession->m_videoSession, decodeSessionBindMemoryCount,
decodeSessionBindMemory);
DE_ASSERT(result == VK_SUCCESS);
videoSession = pNewVideoSession;
// Make sure we do not use dangling (on the stack) pointers
createInfo.pNext = nullptr;
return result;
}
VkResult VkImageResource::Create(DeviceContext& vkDevCtx,
const VkImageCreateInfo* pImageCreateInfo,
VkSharedBaseObj<VkImageResource>& imageResource)
{
imageResource = new VkImageResource(vkDevCtx,
pImageCreateInfo);
return VK_SUCCESS;
}
VkResult VkImageResourceView::Create(DeviceContext& vkDevCtx,
VkSharedBaseObj<VkImageResource>& imageResource,
VkImageSubresourceRange &imageSubresourceRange,
VkSharedBaseObj<VkImageResourceView>& imageResourceView)
{
auto& vk = vkDevCtx.getDeviceDriver();
VkDevice device = vkDevCtx.device;
VkImageView imageView;
VkImageViewCreateInfo viewInfo = VkImageViewCreateInfo();
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.pNext = nullptr;
viewInfo.image = imageResource->GetImage();
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = imageResource->GetImageCreateInfo().format;
viewInfo.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
viewInfo.subresourceRange = imageSubresourceRange;
viewInfo.flags = 0;
VkResult result = vk.createImageView(device, &viewInfo, nullptr, &imageView);
if (result != VK_SUCCESS) {
return result;
}
imageResourceView = new VkImageResourceView(vkDevCtx, imageResource,
imageView, imageSubresourceRange);
return result;
}
VkImageResourceView::~VkImageResourceView()
{
auto& vk = m_vkDevCtx.getDeviceDriver();
auto device = m_vkDevCtx.device;
if (m_imageView != VK_NULL_HANDLE) {
vk.destroyImageView(device, m_imageView, nullptr);
m_imageView = VK_NULL_HANDLE;
}
m_imageResource = nullptr;
}
const char* VkParserVideoPictureParameters::m_refClassId = "VkParserVideoPictureParameters";
int32_t VkParserVideoPictureParameters::m_currentId = 0;
int32_t VkParserVideoPictureParameters::PopulateH264UpdateFields(const StdVideoPictureParametersSet* pStdPictureParametersSet,
VkVideoDecodeH264SessionParametersAddInfoKHR& h264SessionParametersAddInfo)
{
int32_t currentId = -1;
if (pStdPictureParametersSet == nullptr) {
return currentId;
}
DE_ASSERT( (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_SPS) ||
(pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_PPS));
DE_ASSERT(h264SessionParametersAddInfo.sType == VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR);
if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_SPS) {
h264SessionParametersAddInfo.stdSPSCount = 1;
h264SessionParametersAddInfo.pStdSPSs = pStdPictureParametersSet->GetStdH264Sps();
bool isSps = false;
currentId = pStdPictureParametersSet->GetSpsId(isSps);
DE_ASSERT(isSps);
} else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H264_PPS ) {
h264SessionParametersAddInfo.stdPPSCount = 1;
h264SessionParametersAddInfo.pStdPPSs = pStdPictureParametersSet->GetStdH264Pps();
bool isPps = false;
currentId = pStdPictureParametersSet->GetPpsId(isPps);
DE_ASSERT(isPps);
} else {
DE_ASSERT(!"Incorrect h.264 type");
}
return currentId;
}
int32_t VkParserVideoPictureParameters::PopulateH265UpdateFields(const StdVideoPictureParametersSet* pStdPictureParametersSet,
VkVideoDecodeH265SessionParametersAddInfoKHR& h265SessionParametersAddInfo)
{
int32_t currentId = -1;
if (pStdPictureParametersSet == nullptr) {
return currentId;
}
DE_ASSERT( (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_VPS) ||
(pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_SPS) ||
(pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_PPS));
DE_ASSERT(h265SessionParametersAddInfo.sType == VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR);
if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_VPS) {
h265SessionParametersAddInfo.stdVPSCount = 1;
h265SessionParametersAddInfo.pStdVPSs = pStdPictureParametersSet->GetStdH265Vps();
bool isVps = false;
currentId = pStdPictureParametersSet->GetVpsId(isVps);
DE_ASSERT(isVps);
} else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_SPS) {
h265SessionParametersAddInfo.stdSPSCount = 1;
h265SessionParametersAddInfo.pStdSPSs = pStdPictureParametersSet->GetStdH265Sps();
bool isSps = false;
currentId = pStdPictureParametersSet->GetSpsId(isSps);
DE_ASSERT(isSps);
} else if (pStdPictureParametersSet->GetStdType() == StdVideoPictureParametersSet::TYPE_H265_PPS) {
h265SessionParametersAddInfo.stdPPSCount = 1;
h265SessionParametersAddInfo.pStdPPSs = pStdPictureParametersSet->GetStdH265Pps();
bool isPps = false;
currentId = pStdPictureParametersSet->GetPpsId(isPps);
DE_ASSERT(isPps);
} else {
DE_ASSERT(!"Incorrect h.265 type");
}
return currentId;
}
VkResult
VkParserVideoPictureParameters::Create(DeviceContext& deviceContext,
VkSharedBaseObj<VkParserVideoPictureParameters>& templatePictureParameters,
VkSharedBaseObj<VkParserVideoPictureParameters>& videoPictureParameters)
{
VkSharedBaseObj<VkParserVideoPictureParameters> newVideoPictureParameters(
new VkParserVideoPictureParameters(deviceContext, templatePictureParameters));
if (!newVideoPictureParameters) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
videoPictureParameters = newVideoPictureParameters;
return VK_SUCCESS;
}
VkResult VkParserVideoPictureParameters::CreateParametersObject(VkSharedBaseObj<VulkanVideoSession>& videoSession,
const StdVideoPictureParametersSet* pStdVideoPictureParametersSet,
VkParserVideoPictureParameters* pTemplatePictureParameters)
{
int32_t currentId = -1;
VkVideoSessionParametersCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR;
VkVideoDecodeH264SessionParametersCreateInfoKHR h264SessionParametersCreateInfo{};
h264SessionParametersCreateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR;
VkVideoDecodeH264SessionParametersAddInfoKHR h264SessionParametersAddInfo{};
h264SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR;
VkVideoDecodeH265SessionParametersCreateInfoKHR h265SessionParametersCreateInfo{};
h265SessionParametersCreateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR;
VkVideoDecodeH265SessionParametersAddInfoKHR h265SessionParametersAddInfo{};
h265SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR;
StdVideoPictureParametersSet::StdType updateType = pStdVideoPictureParametersSet->GetStdType();
switch (updateType)
{
case StdVideoPictureParametersSet::TYPE_H264_SPS:
case StdVideoPictureParametersSet::TYPE_H264_PPS:
{
createInfo.pNext = &h264SessionParametersCreateInfo;
h264SessionParametersCreateInfo.maxStdSPSCount = MAX_SPS_IDS;
h264SessionParametersCreateInfo.maxStdPPSCount = MAX_PPS_IDS;
h264SessionParametersCreateInfo.pParametersAddInfo = &h264SessionParametersAddInfo;
currentId = PopulateH264UpdateFields(pStdVideoPictureParametersSet, h264SessionParametersAddInfo);
}
break;
case StdVideoPictureParametersSet::TYPE_H265_VPS:
case StdVideoPictureParametersSet::TYPE_H265_SPS:
case StdVideoPictureParametersSet::TYPE_H265_PPS:
{
createInfo.pNext = &h265SessionParametersCreateInfo;
h265SessionParametersCreateInfo.maxStdVPSCount = MAX_VPS_IDS;
h265SessionParametersCreateInfo.maxStdSPSCount = MAX_SPS_IDS;
h265SessionParametersCreateInfo.maxStdPPSCount = MAX_PPS_IDS;
h265SessionParametersCreateInfo.pParametersAddInfo = &h265SessionParametersAddInfo;
currentId = PopulateH265UpdateFields(pStdVideoPictureParametersSet, h265SessionParametersAddInfo);
}
break;
default:
DE_ASSERT(!"Invalid Parser format");
return VK_ERROR_INITIALIZATION_FAILED;
}
createInfo.videoSessionParametersTemplate = pTemplatePictureParameters ? VkVideoSessionParametersKHR(*pTemplatePictureParameters) : VK_NULL_HANDLE;
createInfo.videoSession = videoSession->GetVideoSession();
VkResult result = m_deviceContext.getDeviceDriver().createVideoSessionParametersKHR(m_deviceContext.device,
&createInfo,
nullptr,
&m_sessionParameters);
if (result != VK_SUCCESS) {
DE_ASSERT(!"Could not create Session Parameters Object");
return result;
} else {
m_videoSession = videoSession;
if (pTemplatePictureParameters) {
m_vpsIdsUsed = pTemplatePictureParameters->m_vpsIdsUsed;
m_spsIdsUsed = pTemplatePictureParameters->m_spsIdsUsed;
m_ppsIdsUsed = pTemplatePictureParameters->m_ppsIdsUsed;
}
assert (currentId >= 0);
switch (pStdVideoPictureParametersSet->GetParameterType()) {
case StdVideoPictureParametersSet::PPS_TYPE:
m_ppsIdsUsed.set(currentId, true);
break;
case StdVideoPictureParametersSet::SPS_TYPE:
m_spsIdsUsed.set(currentId, true);
break;
case StdVideoPictureParametersSet::VPS_TYPE:
m_vpsIdsUsed.set(currentId, true);
break;
default:
DE_ASSERT(!"Invalid StdVideoPictureParametersSet Parameter Type!");
}
m_Id = ++m_currentId;
}
return result;
}
VkResult VkParserVideoPictureParameters::UpdateParametersObject(StdVideoPictureParametersSet* pStdVideoPictureParametersSet)
{
if (pStdVideoPictureParametersSet == nullptr) {
return VK_SUCCESS;
}
int32_t currentId = -1;
VkVideoSessionParametersUpdateInfoKHR updateInfo{};
updateInfo.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR;
VkVideoDecodeH264SessionParametersAddInfoKHR h264SessionParametersAddInfo{};
h264SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR;
VkVideoDecodeH265SessionParametersAddInfoKHR h265SessionParametersAddInfo{};
h265SessionParametersAddInfo.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR;
StdVideoPictureParametersSet::StdType updateType = pStdVideoPictureParametersSet->GetStdType();
switch (updateType)
{
case StdVideoPictureParametersSet::TYPE_H264_SPS:
case StdVideoPictureParametersSet::TYPE_H264_PPS:
{
updateInfo.pNext = &h264SessionParametersAddInfo;
currentId = PopulateH264UpdateFields(pStdVideoPictureParametersSet, h264SessionParametersAddInfo);
}
break;
case StdVideoPictureParametersSet::TYPE_H265_VPS:
case StdVideoPictureParametersSet::TYPE_H265_SPS:
case StdVideoPictureParametersSet::TYPE_H265_PPS:
{
updateInfo.pNext = &h265SessionParametersAddInfo;
currentId = PopulateH265UpdateFields(pStdVideoPictureParametersSet, h265SessionParametersAddInfo);
}
break;
default:
DE_ASSERT(!"Invalid Parser format");
return VK_ERROR_INITIALIZATION_FAILED;
}
updateInfo.updateSequenceCount = ++m_updateCount;
VK_CHECK(m_deviceContext.getDeviceDriver().updateVideoSessionParametersKHR(m_deviceContext.device,
m_sessionParameters,
&updateInfo));
DE_ASSERT(currentId >= 0);
switch (pStdVideoPictureParametersSet->GetParameterType()) {
case StdVideoPictureParametersSet::PPS_TYPE:
m_ppsIdsUsed.set(currentId, true);
break;
case StdVideoPictureParametersSet::SPS_TYPE:
m_spsIdsUsed.set(currentId, true);
break;
case StdVideoPictureParametersSet::VPS_TYPE:
m_vpsIdsUsed.set(currentId, true);
break;
default:
DE_ASSERT(!"Invalid StdVideoPictureParametersSet Parameter Type!");
}
return VK_SUCCESS;
}
VkParserVideoPictureParameters::~VkParserVideoPictureParameters()
{
if (!!m_sessionParameters) {
m_deviceContext.getDeviceDriver().destroyVideoSessionParametersKHR(m_deviceContext.device, m_sessionParameters, nullptr);
m_sessionParameters = VK_NULL_HANDLE;
}
m_videoSession = nullptr;
}
bool VkParserVideoPictureParameters::UpdatePictureParametersHierarchy(
VkSharedBaseObj<StdVideoPictureParametersSet>& pictureParametersObject)
{
int32_t nodeId = -1;
bool isNodeId = false;
StdVideoPictureParametersSet::ParameterType nodeParent = StdVideoPictureParametersSet::INVALID_TYPE;
StdVideoPictureParametersSet::ParameterType nodeChild = StdVideoPictureParametersSet::INVALID_TYPE;
switch (pictureParametersObject->GetParameterType()) {
case StdVideoPictureParametersSet::PPS_TYPE:
nodeParent = StdVideoPictureParametersSet::SPS_TYPE;
nodeId = pictureParametersObject->GetPpsId(isNodeId);
if (!((deUint32)nodeId < VkParserVideoPictureParameters::MAX_PPS_IDS)) {
DE_ASSERT(!"PPS ID is out of bounds");
return false;
}
DE_ASSERT(isNodeId);
if (m_lastPictParamsQueue[nodeParent]) {
bool isParentId = false;
const int32_t spsParentId = pictureParametersObject->GetSpsId(isParentId);
DE_ASSERT(!isParentId);
if (spsParentId == m_lastPictParamsQueue[nodeParent]->GetSpsId(isParentId)) {
DE_ASSERT(isParentId);
pictureParametersObject->m_parent = m_lastPictParamsQueue[nodeParent];
}
}
break;
case StdVideoPictureParametersSet::SPS_TYPE:
nodeParent = StdVideoPictureParametersSet::VPS_TYPE;
nodeChild = StdVideoPictureParametersSet::PPS_TYPE;
nodeId = pictureParametersObject->GetSpsId(isNodeId);
if (!((deUint32)nodeId < VkParserVideoPictureParameters::MAX_SPS_IDS)) {
DE_ASSERT(!"SPS ID is out of bounds");
return false;
}
DE_ASSERT(isNodeId);
if (m_lastPictParamsQueue[nodeChild]) {
const int32_t spsChildId = m_lastPictParamsQueue[nodeChild]->GetSpsId(isNodeId);
DE_ASSERT(!isNodeId);
if (spsChildId == nodeId) {
m_lastPictParamsQueue[nodeChild]->m_parent = pictureParametersObject;
}
}
if (m_lastPictParamsQueue[nodeParent]) {
const int32_t vpsParentId = pictureParametersObject->GetVpsId(isNodeId);
DE_ASSERT(!isNodeId);
if (vpsParentId == m_lastPictParamsQueue[nodeParent]->GetVpsId(isNodeId)) {
pictureParametersObject->m_parent = m_lastPictParamsQueue[nodeParent];
DE_ASSERT(isNodeId);
}
}
break;
case StdVideoPictureParametersSet::VPS_TYPE:
nodeChild = StdVideoPictureParametersSet::SPS_TYPE;
nodeId = pictureParametersObject->GetVpsId(isNodeId);
if (!((deUint32)nodeId < VkParserVideoPictureParameters::MAX_VPS_IDS)) {
DE_ASSERT(!"VPS ID is out of bounds");
return false;
}
DE_ASSERT(isNodeId);
if (m_lastPictParamsQueue[nodeChild]) {
const int32_t vpsParentId = m_lastPictParamsQueue[nodeChild]->GetVpsId(isNodeId);
DE_ASSERT(!isNodeId);
if (vpsParentId == nodeId) {
m_lastPictParamsQueue[nodeChild]->m_parent = pictureParametersObject;
}
}
break;
default:
DE_ASSERT("!Invalid STD type");
return false;
}
m_lastPictParamsQueue[pictureParametersObject->GetParameterType()] = pictureParametersObject;
return true;
}
VkResult VkParserVideoPictureParameters::AddPictureParametersToQueue(VkSharedBaseObj<StdVideoPictureParametersSet>& pictureParametersSet)
{
m_pictureParametersQueue.push(pictureParametersSet);
return VK_SUCCESS;
}
VkResult VkParserVideoPictureParameters::HandleNewPictureParametersSet(VkSharedBaseObj<VulkanVideoSession>& videoSession,
StdVideoPictureParametersSet* pStdVideoPictureParametersSet)
{
VkResult result;
if (m_sessionParameters == VK_NULL_HANDLE) {
DE_ASSERT(videoSession != VK_NULL_HANDLE);
DE_ASSERT(m_videoSession == VK_NULL_HANDLE);
if (m_templatePictureParameters) {
m_templatePictureParameters->FlushPictureParametersQueue(videoSession);
}
result = CreateParametersObject(videoSession, pStdVideoPictureParametersSet,
m_templatePictureParameters);
DE_ASSERT(result == VK_SUCCESS);
m_templatePictureParameters = nullptr; // the template object is not needed anymore
m_videoSession = videoSession;
} else {
DE_ASSERT(m_videoSession != VK_NULL_HANDLE);
DE_ASSERT(m_sessionParameters != VK_NULL_HANDLE);
result = UpdateParametersObject(pStdVideoPictureParametersSet);
DE_ASSERT(result == VK_SUCCESS);
}
return result;
}
int32_t VkParserVideoPictureParameters::FlushPictureParametersQueue(VkSharedBaseObj<VulkanVideoSession>& videoSession)
{
if (!videoSession) {
return -1;
}
deUint32 numQueueItems = 0;
while (!m_pictureParametersQueue.empty()) {
VkSharedBaseObj<StdVideoPictureParametersSet>& stdVideoPictureParametersSet = m_pictureParametersQueue.front();
VkResult result = HandleNewPictureParametersSet(videoSession, stdVideoPictureParametersSet);
if (result != VK_SUCCESS) {
return -1;
}
m_pictureParametersQueue.pop();
numQueueItems++;
}
return numQueueItems;
}
bool VkParserVideoPictureParameters::CheckStdObjectBeforeUpdate(VkSharedBaseObj<StdVideoPictureParametersSet>& stdPictureParametersSet,
VkSharedBaseObj<VkParserVideoPictureParameters>& currentVideoPictureParameters)
{
if (!stdPictureParametersSet) {
return false;
}
bool stdObjectUpdate = (stdPictureParametersSet->GetUpdateSequenceCount() > 0);
if (!currentVideoPictureParameters || stdObjectUpdate) {
// Create new Vulkan Picture Parameters object
return true;
} else { // existing VkParserVideoPictureParameters object
DE_ASSERT(currentVideoPictureParameters);
// Update with the existing Vulkan Picture Parameters object
}
VkSharedBaseObj<VkVideoRefCountBase> clientObject;
stdPictureParametersSet->GetClientObject(clientObject);
DE_ASSERT(!clientObject);
return false;
}
VkResult
VkParserVideoPictureParameters::AddPictureParameters(DeviceContext& deviceContext,
VkSharedBaseObj<VulkanVideoSession>& /*videoSession*/,
VkSharedBaseObj<StdVideoPictureParametersSet>& stdPictureParametersSet,
VkSharedBaseObj<VkParserVideoPictureParameters>& currentVideoPictureParameters)
{
if (!stdPictureParametersSet) {
return VK_ERROR_INITIALIZATION_FAILED;
}
VkResult result;
if (CheckStdObjectBeforeUpdate(stdPictureParametersSet, currentVideoPictureParameters)) {
result = VkParserVideoPictureParameters::Create(deviceContext,
currentVideoPictureParameters,
currentVideoPictureParameters);
}
result = currentVideoPictureParameters->AddPictureParametersToQueue(stdPictureParametersSet);
return result;
}
int32_t VkParserVideoPictureParameters::AddRef()
{
return ++m_refCount;
}
int32_t VkParserVideoPictureParameters::Release()
{
deUint32 ret;
ret = --m_refCount;
// Destroy the device if refcount reaches zero
if (ret == 0) {
delete this;
}
return ret;
}
} // video
} // vkt