Skip to content

Commit

Permalink
Serialize and parse VkSamplerYcbcrConversionInfo.
Browse files Browse the repository at this point in the history
  • Loading branch information
HansKristian-Work committed Feb 1, 2022
1 parent e733f03 commit a76ae40
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 6 deletions.
150 changes: 150 additions & 0 deletions fossilize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ struct StateReplayer::Impl
bool parse_discard_rectangles(const Value &state, VkPipelineDiscardRectangleStateCreateInfoEXT **out_info) FOSSILIZE_WARN_UNUSED;
bool parse_memory_barrier2(const Value &state, VkMemoryBarrier2KHR **out_info) FOSSILIZE_WARN_UNUSED;
bool parse_fragment_shading_rate(const Value &state, VkPipelineFragmentShadingRateStateCreateInfoKHR **out_info) FOSSILIZE_WARN_UNUSED;
bool parse_sampler_ycbcr_conversion(const Value &state,
VkSamplerYcbcrConversionCreateInfo **out_info) FOSSILIZE_WARN_UNUSED;
bool parse_uints(const Value &attachments, const uint32_t **out_uints) FOSSILIZE_WARN_UNUSED;
bool parse_sints(const Value &attachments, const int32_t **out_uints) FOSSILIZE_WARN_UNUSED;
const char *duplicate_string(const char *str, size_t len);
Expand All @@ -258,6 +260,7 @@ struct StateRecorder::Impl

ScratchAllocator allocator;
ScratchAllocator temp_allocator;
ScratchAllocator ycbcr_temp_allocator;
DatabaseInterface *database_iface = nullptr;
ApplicationInfoFilter *application_info_filter = nullptr;
bool need_prepare = false;
Expand All @@ -270,6 +273,7 @@ struct StateRecorder::Impl
std::unordered_map<Hash, VkRayTracingPipelineCreateInfoKHR *> raytracing_pipelines;
std::unordered_map<Hash, void *> render_passes;
std::unordered_map<Hash, VkSamplerCreateInfo *> samplers;
std::unordered_map<VkSamplerYcbcrConversion, const VkSamplerYcbcrConversionCreateInfo *> ycbcr_conversions;

std::unordered_map<VkDescriptorSetLayout, Hash> descriptor_set_layout_to_hash;
std::unordered_map<VkPipelineLayout, Hash> pipeline_layout_to_hash;
Expand Down Expand Up @@ -310,6 +314,8 @@ struct StateRecorder::Impl
VkRayTracingPipelineCreateInfoKHR **out_info) FOSSILIZE_WARN_UNUSED;
bool copy_sampler(const VkSamplerCreateInfo *create_info, ScratchAllocator &alloc,
VkSamplerCreateInfo **out_info) FOSSILIZE_WARN_UNUSED;
bool copy_ycbcr_conversion(const VkSamplerYcbcrConversionCreateInfo *create_info, ScratchAllocator &alloc,
VkSamplerYcbcrConversionCreateInfo **out_info) FOSSILIZE_WARN_UNUSED;
bool copy_render_pass(const VkRenderPassCreateInfo *create_info, ScratchAllocator &alloc,
VkRenderPassCreateInfo **out_info) FOSSILIZE_WARN_UNUSED;
bool copy_render_pass2(const VkRenderPassCreateInfo2 *create_info, ScratchAllocator &alloc,
Expand Down Expand Up @@ -386,6 +392,8 @@ struct StateRecorder::Impl
ScratchAllocator &alloc) FOSSILIZE_WARN_UNUSED;
void *copy_pnext_struct(const VkPipelineFragmentShadingRateStateCreateInfoKHR *create_info,
ScratchAllocator &alloc) FOSSILIZE_WARN_UNUSED;
void *copy_pnext_struct(const VkSamplerYcbcrConversionCreateInfo *create_info,
ScratchAllocator &alloc) FOSSILIZE_WARN_UNUSED;

bool remap_sampler_handle(VkSampler sampler, VkSampler *out_sampler) const FOSSILIZE_WARN_UNUSED;
bool remap_descriptor_set_layout_handle(VkDescriptorSetLayout layout, VkDescriptorSetLayout *out_layout) const FOSSILIZE_WARN_UNUSED;
Expand Down Expand Up @@ -1013,6 +1021,23 @@ static void hash_pnext_struct(const StateRecorder *,
}
}

static void hash_pnext_struct(const StateRecorder *,
Hasher &h,
const VkSamplerYcbcrConversionCreateInfo &info)
{
h.u32(info.format);
h.u32(info.ycbcrModel);
h.u32(info.ycbcrRange);
h.u32(info.components.r);
h.u32(info.components.g);
h.u32(info.components.b);
h.u32(info.components.a);
h.u32(info.xChromaOffset);
h.u32(info.yChromaOffset);
h.u32(info.chromaFilter);
h.u32(info.forceExplicitReconstruction);
}

static bool hash_pnext_chain(const StateRecorder *recorder, Hasher &h, const void *pNext,
const DynamicStateInfo *dynamic_state_info)
{
Expand Down Expand Up @@ -1121,6 +1146,10 @@ static bool hash_pnext_chain(const StateRecorder *recorder, Hasher &h, const voi
hash_pnext_struct(recorder, h, *static_cast<const VkPipelineFragmentShadingRateStateCreateInfoKHR *>(pNext), dynamic_state_info);
break;

case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO:
hash_pnext_struct(recorder, h, *static_cast<const VkSamplerYcbcrConversionCreateInfo *>(pNext));
break;

default:
log_error_pnext_chain("Unsupported pNext found, cannot hash.", pNext);
return false;
Expand Down Expand Up @@ -3895,6 +3924,27 @@ bool StateReplayer::Impl::parse_fragment_shading_rate(const Value &state,
return true;
}

bool StateReplayer::Impl::parse_sampler_ycbcr_conversion(const Value &state,
VkSamplerYcbcrConversionCreateInfo **out_info)
{
auto *info = allocator.allocate_cleared<VkSamplerYcbcrConversionCreateInfo>();
*out_info = info;

info->format = static_cast<VkFormat>(state["format"].GetUint());
info->ycbcrModel = static_cast<VkSamplerYcbcrModelConversion>(state["ycbcrModel"].GetUint());
info->ycbcrRange = static_cast<VkSamplerYcbcrRange>(state["ycbcrRange"].GetUint());
info->components.r = static_cast<VkComponentSwizzle>(state["components"][0].GetUint());
info->components.g = static_cast<VkComponentSwizzle>(state["components"][1].GetUint());
info->components.b = static_cast<VkComponentSwizzle>(state["components"][2].GetUint());
info->components.a = static_cast<VkComponentSwizzle>(state["components"][3].GetUint());
info->xChromaOffset = static_cast<VkChromaLocation>(state["xChromaOffset"].GetUint());
info->yChromaOffset = static_cast<VkChromaLocation>(state["yChromaOffset"].GetUint());
info->chromaFilter = static_cast<VkFilter>(state["chromaFilter"].GetUint());
info->forceExplicitReconstruction = state["forceExplicitReconstruction"].GetUint();

return true;
}

bool StateReplayer::Impl::parse_mutable_descriptor_type(const Value &state,
VkMutableDescriptorTypeCreateInfoVALVE **out_info)
{
Expand Down Expand Up @@ -4190,6 +4240,15 @@ bool StateReplayer::Impl::parse_pnext_chain(const Value &pnext, const void **out
break;
}

case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO:
{
VkSamplerYcbcrConversionCreateInfo *conv = nullptr;
if (!parse_sampler_ycbcr_conversion(next, &conv))
return false;
new_struct = reinterpret_cast<VkBaseInStructure *>(conv);
break;
}

default:
LOGE_LEVEL("Failed to parse pNext chain for sType: %d\n", int(sType));
return false;
Expand Down Expand Up @@ -4689,6 +4748,13 @@ void *StateRecorder::Impl::copy_pnext_struct(const VkPipelineFragmentShadingRate
return fragment_shading_rate;
}

void *StateRecorder::Impl::copy_pnext_struct(const VkSamplerYcbcrConversionCreateInfo *create_info,
ScratchAllocator &alloc)
{
auto *conv = copy(create_info, 1, alloc);
return conv;
}

template <typename T>
bool StateRecorder::Impl::copy_pnext_chains(const T *ts, uint32_t count, ScratchAllocator &alloc,
const DynamicStateInfo *dynamic_state_info)
Expand Down Expand Up @@ -4885,6 +4951,30 @@ bool StateRecorder::Impl::copy_pnext_chain(const void *pNext, ScratchAllocator &
break;
}

case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO:
{
auto *ci = static_cast<const VkSamplerYcbcrConversionCreateInfo *>(pNext);
*ppNext = static_cast<VkBaseInStructure *>(copy_pnext_struct(ci, alloc));
break;
}

case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
{
// Special case. Instead of serializing the YCbCr object link, serialize the original create info.
// Reduces excessive churn for supporting an extremely niche object type.
auto *ci = static_cast<const VkSamplerYcbcrConversionInfo *>(pNext);
auto ycbcr = ycbcr_conversions.find(ci->conversion);
if (ycbcr == ycbcr_conversions.end())
return false;

VkSamplerYcbcrConversionCreateInfo *new_create_info;
if (!copy_ycbcr_conversion(ycbcr->second, alloc, &new_create_info))
return false;

*ppNext = reinterpret_cast<VkBaseInStructure *>(new_create_info);
break;
}

default:
LOGE_LEVEL("Cannot copy unknown pNext sType: %d.\n", int(pin->sType));
return false;
Expand Down Expand Up @@ -5077,6 +5167,24 @@ bool StateRecorder::record_sampler(VkSampler sampler, const VkSamplerCreateInfo
return true;
}

bool StateRecorder::record_ycbcr_conversion(VkSamplerYcbcrConversion conv,
const VkSamplerYcbcrConversionCreateInfo &create_info)
{
{
std::lock_guard<std::mutex> lock(impl->record_lock);

VkSamplerYcbcrConversionCreateInfo *new_info = nullptr;
if (!impl->copy_ycbcr_conversion(&create_info, impl->ycbcr_temp_allocator, &new_info))
return false;

// We don't directly serialize these objects. Just remember it for later if a VkSampler is created.
impl->ycbcr_conversions[conv] = new_info;
}

impl->pump_synchronized_recording(this);
return true;
}

bool StateRecorder::record_descriptor_set_layout(VkDescriptorSetLayout set_layout, const VkDescriptorSetLayoutCreateInfo &create_info,
Hash custom_hash)
{
Expand Down Expand Up @@ -5405,6 +5513,19 @@ bool StateRecorder::Impl::copy_sampler(const VkSamplerCreateInfo *create_info, S
return true;
}

bool StateRecorder::Impl::copy_ycbcr_conversion(const VkSamplerYcbcrConversionCreateInfo *create_info,
ScratchAllocator &alloc, VkSamplerYcbcrConversionCreateInfo **out_info)
{
auto *info = copy(create_info, 1, alloc);

// Don't support pNext in this struct.
if (create_info->pNext)
return false;

*out_info = info;
return true;
}

void *StateRecorder::Impl::copy_pnext_struct(
const VkPhysicalDeviceRobustness2FeaturesEXT *create_info,
ScratchAllocator &alloc)
Expand Down Expand Up @@ -7229,6 +7350,30 @@ static bool json_value(const VkPipelineFragmentShadingRateStateCreateInfoKHR &cr
return true;
}

template <typename Allocator>
static bool json_value(const VkSamplerYcbcrConversionCreateInfo &create_info, Allocator &alloc, Value *out_value)
{
Value value(kObjectType);
Value comp(kArrayType);

value.AddMember("sType", create_info.sType, alloc);
value.AddMember("format", create_info.format, alloc);
value.AddMember("ycbcrModel", create_info.ycbcrModel, alloc);
value.AddMember("ycbcrRange", create_info.ycbcrRange, alloc);
comp.PushBack(create_info.components.r, alloc);
comp.PushBack(create_info.components.g, alloc);
comp.PushBack(create_info.components.b, alloc);
comp.PushBack(create_info.components.a, alloc);
value.AddMember("components", comp, alloc);
value.AddMember("xChromaOffset", create_info.xChromaOffset, alloc);
value.AddMember("yChromaOffset", create_info.yChromaOffset, alloc);
value.AddMember("chromaFilter", create_info.chromaFilter, alloc);
value.AddMember("forceExplicitReconstruction", create_info.forceExplicitReconstruction, alloc);

*out_value = value;
return true;
}

template <typename Allocator>
static bool json_value(const VkSubpassDescriptionDepthStencilResolve &create_info, Allocator &alloc, Value *out_value);
template <typename Allocator>
Expand Down Expand Up @@ -7366,6 +7511,11 @@ static bool pnext_chain_json_value(const void *pNext, Allocator &alloc, Value *o
return false;
break;

case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO:
if (!json_value(*static_cast<const VkSamplerYcbcrConversionCreateInfo *>(pNext), alloc, &next))
return false;
break;

default:
log_error_pnext_chain("Unsupported pNext found, cannot hash sType.", pNext);
return false;
Expand Down
6 changes: 6 additions & 0 deletions fossilize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ class StateRecorder
bool record_raytracing_pipeline(VkPipeline pipeline, const VkRayTracingPipelineCreateInfoKHR &create_info,
const VkPipeline *base_pipelines, uint32_t base_pipeline_count,
Hash custom_hash = 0) FOSSILIZE_WARN_UNUSED;
// YCbCr conversion objects are treated somewhat differently and their create infos
// are inlined into a sampler create info.
// In a replay scenario, the YCbCr create info is fished out of the pNext chain and replaced
// with a Conversion Info.
bool record_ycbcr_conversion(VkSamplerYcbcrConversion conv,
const VkSamplerYcbcrConversionCreateInfo &create_info) FOSSILIZE_WARN_UNUSED;

// Used by hashing functions in Hashing namespace. Should be considered an implementation detail.
bool get_hash_for_descriptor_set_layout(VkDescriptorSetLayout layout, Hash *hash) const FOSSILIZE_WARN_UNUSED;
Expand Down
29 changes: 23 additions & 6 deletions test/fossilize_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,8 @@ static void record_samplers(StateRecorder &recorder)
abort();

// Intentionally trip an error.
VkSamplerYcbcrConversionCreateInfo ycbcr = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO};
VkSamplerYcbcrConversionCreateInfo reduction = {VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT};
VkSamplerYcbcrConversionInfo ycbcr = { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO };
sampler.pNext = &ycbcr;
ycbcr.pNext = &reduction;
bool ret = recorder.record_sampler(fake_handle<VkSampler>(102), sampler);
if (ret)
{
Expand All @@ -217,6 +215,25 @@ static void record_samplers(StateRecorder &recorder)
LOGE("=== Tripped intentional error for testing ===\n");
}

VkSamplerYcbcrConversionCreateInfo ycbcr_info = { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO };
ycbcr_info.format = VK_FORMAT_R8G8B8A8_UNORM;
ycbcr_info.forceExplicitReconstruction = 10;
ycbcr_info.chromaFilter = VK_FILTER_LINEAR;
ycbcr_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
ycbcr_info.components.g = VK_COMPONENT_SWIZZLE_G;
ycbcr_info.components.b = VK_COMPONENT_SWIZZLE_B;
ycbcr_info.components.a = VK_COMPONENT_SWIZZLE_A;
ycbcr_info.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
ycbcr_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
ycbcr_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
if (!recorder.record_ycbcr_conversion(fake_handle<VkSamplerYcbcrConversion>(10), ycbcr_info))
abort();

ycbcr.conversion = fake_handle<VkSamplerYcbcrConversion>(10);
if (!recorder.record_sampler(fake_handle<VkSampler>(102), sampler))
abort();

VkSamplerCustomBorderColorCreateInfoEXT custom_border_color =
{ VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT };
custom_border_color.customBorderColor.uint32[0] = 0;
Expand Down Expand Up @@ -2761,7 +2778,7 @@ static bool test_export_concurrent_archive(bool with_read_only)
static bool test_logging()
{
VkSamplerCreateInfo create_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
VkSamplerYcbcrConversionCreateInfo conv_info = { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO };
VkSamplerYcbcrConversionInfo conv_info = { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO };
create_info.pNext = &conv_info;

const auto immutable = fake_handle<VkSampler>(100);
Expand Down Expand Up @@ -2817,7 +2834,7 @@ static bool test_logging()
if (recorder.record_sampler(immutable, create_info, 100))
return false;

if (userdata.warn_count != 0 || userdata.err_count != 1 || userdata.info_count != 0)
if (userdata.warn_count != 0 || userdata.err_count != 0 || userdata.info_count != 0)
return false;

// Should succeed, but will fail later when trying to resolve sampler.
Expand All @@ -2828,7 +2845,7 @@ static bool test_logging()
LOGI("=======================\n");

unsigned expected_warn = i < 2 ? 1 : 0;
if (userdata.warn_count != expected_warn || userdata.err_count != 1 || userdata.info_count != 0)
if (userdata.warn_count != expected_warn || userdata.err_count != 0 || userdata.info_count != 0)
return false;
}
remove(".__test_archive.foz");
Expand Down

0 comments on commit a76ae40

Please sign in to comment.