blob: 7f4598a33f515c97671652abfcc1868e779659ab [file] [log] [blame]
/*
* Copyright (c) 2022-2025 The Khronos Group Inc.
* Copyright (c) 2022-2025 RasterGrid Kft.
*
* 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
*/
#include "../framework/video_objects.h"
class NegativeSyncValVideo : public VkVideoSyncLayerTest {};
TEST_F(NegativeSyncValVideo, DecodeOutputPicture) {
TEST_DESCRIPTION("Test video decode output picture sync hazard");
RETURN_IF_SKIP(Init());
VideoConfig config = GetConfigDecode();
if (!config) {
GTEST_SKIP() << "Test requires decode support";
}
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin());
cb.ControlVideoCoding(context.Control().Reset());
cb.DecodeVideo(context.DecodeFrame());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.DecodeVideo(context.DecodeFrame());
m_errorMonitor->VerifyFound();
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, DecodeReconstructedPicture) {
TEST_DESCRIPTION("Test video decode reconstructed picture sync hazard");
RETURN_IF_SKIP(Init());
auto config = GetConfig(FilterConfigs(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsDecode()), 2),
[](const VideoConfig& config) { return config.SupportsDecodeOutputDistinct(); }));
if (!config) {
GTEST_SKIP() << "Test requires video decode support with references, 2 DPB slots, and distinct mode support";
}
config.SessionCreateInfo()->maxDpbSlots = 2;
config.SessionCreateInfo()->maxActiveReferencePictures = 1;
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1));
cb.ControlVideoCoding(context.Control().Reset());
cb.DecodeVideo(context.DecodeFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.DecodeVideo(context.DecodeReferenceFrame(0));
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.DecodeVideo(context.DecodeFrame(0));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
cb.DecodeVideo(context.DecodeReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
cb.DecodeVideo(context.DecodeFrame(1).AddReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, DecodeReferencePicture) {
TEST_DESCRIPTION("Test video decode reference picture sync hazard");
RETURN_IF_SKIP(Init());
auto config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsDecode()), 3));
if (!config) {
GTEST_SKIP() << "Test requires video decode support with references and 3 DPB slots";
}
config.SessionCreateInfo()->maxDpbSlots = 3;
config.SessionCreateInfo()->maxActiveReferencePictures = 1;
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1).AddResource(2, 2));
cb.ControlVideoCoding(context.Control().Reset());
cb.DecodeVideo(context.DecodeReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
cb.DecodeVideo(context.DecodeReferenceFrame(1));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-READ-AFTER-WRITE");
cb.DecodeVideo(context.DecodeFrame(2).AddReferenceFrame(0));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(2, 1));
cb.DecodeVideo(context.DecodeFrame(2).AddReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.DecodeOutput()->MemoryBarrier());
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(2, 1));
m_errorMonitor->SetDesiredError("SYNC-HAZARD-READ-AFTER-WRITE");
cb.DecodeVideo(context.DecodeFrame(2).AddReferenceFrame(1));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(1, 2));
cb.DecodeVideo(context.DecodeFrame(2).AddReferenceFrame(1));
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, EncodeBitstream) {
TEST_DESCRIPTION("Test video encode bitstream sync hazard");
RETURN_IF_SKIP(Init());
VideoConfig config = GetConfigEncode();
if (!config) {
GTEST_SKIP() << "Test requires Encode support";
}
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin());
cb.ControlVideoCoding(context.Control().Reset());
cb.EncodeVideo(context.EncodeFrame());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.EncodeVideo(context.EncodeFrame());
m_errorMonitor->VerifyFound();
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, EncodeReconstructedPicture) {
TEST_DESCRIPTION("Test video encode reconstructed picture sync hazard");
RETURN_IF_SKIP(Init());
auto config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncode()), 2));
if (!config) {
GTEST_SKIP() << "Test requires video encode support with references and 2 DPB slots";
}
config.SessionCreateInfo()->maxDpbSlots = 2;
config.SessionCreateInfo()->maxActiveReferencePictures = 1;
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1));
cb.ControlVideoCoding(context.Control().Reset());
cb.EncodeVideo(context.EncodeFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.EncodeVideo(context.EncodeReferenceFrame(0));
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-WRITE");
cb.EncodeVideo(context.EncodeFrame(0));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
cb.EncodeVideo(context.EncodeReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
cb.EncodeVideo(context.EncodeFrame(1).AddReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, EncodeReferencePicture) {
TEST_DESCRIPTION("Test video encode reference picture sync hazard");
RETURN_IF_SKIP(Init());
auto config = GetConfig(GetConfigsWithDpbSlots(GetConfigsWithReferences(GetConfigsEncode()), 3));
if (!config) {
GTEST_SKIP() << "Test requires video encode support with references and 3 DPB slots";
}
config.SessionCreateInfo()->maxDpbSlots = 3;
config.SessionCreateInfo()->maxActiveReferencePictures = 1;
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
vkt::CommandBuffer& cb = context.CmdBuffer();
cb.Begin();
cb.BeginVideoCoding(context.Begin().AddResource(0, 0).AddResource(1, 1).AddResource(2, 2));
cb.ControlVideoCoding(context.Control().Reset());
cb.EncodeVideo(context.EncodeReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
cb.EncodeVideo(context.EncodeReferenceFrame(1));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-READ-AFTER-WRITE");
cb.EncodeVideo(context.EncodeFrame(2).AddReferenceFrame(0));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(0, 1));
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(2, 1));
cb.EncodeVideo(context.EncodeFrame(2).AddReferenceFrame(0));
vk::CmdPipelineBarrier2KHR(cb, context.Bitstream().MemoryBarrier());
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(2, 1));
m_errorMonitor->SetDesiredError("SYNC-HAZARD-READ-AFTER-WRITE");
cb.EncodeVideo(context.EncodeFrame(2).AddReferenceFrame(1));
m_errorMonitor->VerifyFound();
vk::CmdPipelineBarrier2KHR(cb, context.Dpb()->MemoryBarrier(1, 2));
cb.EncodeVideo(context.EncodeFrame(2).AddReferenceFrame(1));
cb.EndVideoCoding(context.End());
cb.End();
}
TEST_F(NegativeSyncValVideo, EncodeQuantizationMap) {
TEST_DESCRIPTION("Test video encode quantization map sync hazard");
AddRequiredExtensions(VK_KHR_VIDEO_ENCODE_QUANTIZATION_MAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::videoEncodeQuantizationMap);
RETURN_IF_SKIP(Init());
VideoConfig delta_config = GetConfigWithQuantDeltaMap(GetConfigsEncode());
VideoConfig emphasis_config = GetConfigWithEmphasisMap(GetConfigsEncode());
if ((!delta_config || (QueueFamilyFlags(delta_config.QueueFamilyIndex()) & VK_QUEUE_TRANSFER_BIT) == 0) &&
(!emphasis_config || (QueueFamilyFlags(emphasis_config.QueueFamilyIndex()) & VK_QUEUE_TRANSFER_BIT) == 0)) {
GTEST_SKIP() << "Test case requires video encode queue to also support transfer";
}
struct TestConfig {
VideoConfig config;
VkVideoEncodeFlagBitsKHR encode_flag;
VkVideoSessionCreateFlagBitsKHR session_create_flag;
const VkVideoFormatPropertiesKHR* map_props;
};
std::vector<TestConfig> tests;
if (delta_config) {
tests.emplace_back(TestConfig{delta_config, VK_VIDEO_ENCODE_WITH_QUANTIZATION_DELTA_MAP_BIT_KHR,
VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_QUANTIZATION_DELTA_MAP_BIT_KHR,
delta_config.QuantDeltaMapProps()});
}
if (emphasis_config) {
tests.emplace_back(TestConfig{emphasis_config, VK_VIDEO_ENCODE_WITH_EMPHASIS_MAP_BIT_KHR,
VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_EMPHASIS_MAP_BIT_KHR,
emphasis_config.EmphasisMapProps()});
}
for (auto& [config, encode_flag, session_create_flag, map_props] : tests) {
config.SessionCreateInfo()->flags |= session_create_flag;
VideoContext context(m_device, config);
context.CreateAndBindSessionMemory();
context.CreateResources();
const auto texel_size = config.GetQuantMapTexelSize(*map_props);
auto params = context.CreateSessionParamsWithQuantMapTexelSize(texel_size);
vkt::CommandBuffer& cb = context.CmdBuffer();
VideoEncodeQuantizationMap quantization_map(m_device, config, *map_props);
cb.Begin();
VkClearColorValue clear_value{};
VkImageSubresourceRange subres_range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vk::CmdClearColorImage(cb, quantization_map.Image(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, &subres_range);
cb.BeginVideoCoding(context.Begin().SetSessionParams(params));
cb.ControlVideoCoding(context.Control().Reset());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-READ-AFTER-WRITE");
cb.EncodeVideo(context.EncodeFrame().QuantizationMap(encode_flag, texel_size, quantization_map));
m_errorMonitor->VerifyFound();
cb.EndVideoCoding(context.End());
cb.End();
cb.Begin();
cb.BeginVideoCoding(context.Begin().SetSessionParams(params));
cb.ControlVideoCoding(context.Control().Reset());
cb.EncodeVideo(context.EncodeFrame().QuantizationMap(encode_flag, texel_size, quantization_map));
m_errorMonitor->VerifyFound();
cb.EndVideoCoding(context.End());
m_errorMonitor->SetDesiredError("SYNC-HAZARD-WRITE-AFTER-READ");
vk::CmdClearColorImage(cb, quantization_map.Image(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, &subres_range);
m_errorMonitor->VerifyFound();
cb.End();
}
if (!delta_config || (QueueFamilyFlags(delta_config.QueueFamilyIndex()) & VK_QUEUE_TRANSFER_BIT) == 0 || !emphasis_config ||
(QueueFamilyFlags(emphasis_config.QueueFamilyIndex()) & VK_QUEUE_TRANSFER_BIT) == 0) {
GTEST_SKIP() << "Not all quantization map types could be tested";
}
}