// Copyright 2022 The Dawn Authors // // 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 #include #include "dawn/common/Assert.h" #include "dawn/common/vulkan_platform.h" #include "dawn/native/stream/Stream.h" #include "dawn/native/vulkan/RenderPassCache.h" #include "icd/generated/vk_typemap_helper.h" namespace dawn::native { namespace { namespace detail { template void ValidatePnextImpl(const VkBaseOutStructure* root) { const VkBaseOutStructure* next = reinterpret_cast(root->pNext); while (next != nullptr) { // Assert that the type of each pNext struct is exactly one of the specified // templates. ASSERT(((LvlTypeMap::kSType == next->sType ? 1 : 0) + ... + 0) == 1); next = reinterpret_cast(next->pNext); } } template void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) { const VkBaseOutStructure* next = reinterpret_cast(root->pNext); const VK_STRUCT_TYPE* found = nullptr; while (next != nullptr) { if (LvlTypeMap::kSType == next->sType) { if (found == nullptr) { found = reinterpret_cast(next); } else { // Fail an assert here since that means that the chain had more than one of // the same typed chained object. ASSERT(false); } } next = reinterpret_cast(next->pNext); } if (found != nullptr) { StreamIn(sink, found); } } template 0)>> void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) { SerializePnextImpl(sink, root); SerializePnextImpl(sink, root); } template const VkBaseOutStructure* ToVkBaseOutStructure(const VK_STRUCT_TYPE* t) { // Checks to ensure proper type safety. static_assert(offsetof(VK_STRUCT_TYPE, sType) == offsetof(VkBaseOutStructure, sType) && offsetof(VK_STRUCT_TYPE, pNext) == offsetof(VkBaseOutStructure, pNext), "Argument type is not a proper Vulkan structure type"); return reinterpret_cast(t); } } // namespace detail template 0)>> void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) { const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t); detail::ValidatePnextImpl(root); detail::SerializePnextImpl(sink, root); } // Empty template specialization so that we can put this in to ensure failures occur if new // extensions are added without updating serialization. template void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) { const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t); detail::ValidatePnextImpl<>(root); } } // namespace template <> void stream::Stream::Write(stream::Sink* sink, const VkDescriptorSetLayoutBinding& t) { StreamIn(sink, t.binding, t.descriptorType, t.descriptorCount, t.stageFlags); } template <> void stream::Stream::Write( stream::Sink* sink, const VkDescriptorSetLayoutCreateInfo& t) { StreamIn(sink, t.flags, Iterable(t.pBindings, t.bindingCount)); SerializePnext(sink, &t); } template <> void stream::Stream::Write(stream::Sink* sink, const VkPushConstantRange& t) { StreamIn(sink, t.stageFlags, t.offset, t.size); } template <> void stream::Stream::Write(stream::Sink* sink, const VkPipelineLayoutCreateInfo& t) { // The set layouts are not serialized here because they are pointers to backend objects. // They need to be cross-referenced with the frontend objects and serialized from there. StreamIn(sink, t.flags, Iterable(t.pPushConstantRanges, t.pushConstantRangeCount)); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT& t) { StreamIn(sink, t.requiredSubgroupSize); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineRasterizationDepthClipStateCreateInfoEXT& t) { StreamIn(sink, t.depthClipEnable, t.flags); } template <> void stream::Stream::Write(stream::Sink* sink, const VkSpecializationMapEntry& t) { StreamIn(sink, t.constantID, t.offset, t.size); } template <> void stream::Stream::Write(stream::Sink* sink, const VkSpecializationInfo& t) { StreamIn(sink, Iterable(t.pMapEntries, t.mapEntryCount), Iterable(static_cast(t.pData), t.dataSize)); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineShaderStageCreateInfo& t) { // The shader module is not serialized here because it is a pointer to a backend object. StreamIn(sink, t.flags, t.stage, Iterable(t.pName, strlen(t.pName)), t.pSpecializationInfo); SerializePnext(sink, &t); } template <> void stream::Stream::Write(stream::Sink* sink, const VkComputePipelineCreateInfo& t) { // The pipeline layout is not serialized here because it is a pointer to a backend object. // It needs to be cross-referenced with the frontend objects and serialized from there. The // base pipeline information is also currently not serialized since we do not use them in our // backend implementation. If we decide to use them later on, they also need to be // cross-referenced from the frontend. StreamIn(sink, t.flags, t.stage); } template <> void stream::Stream::Write( stream::Sink* sink, const VkVertexInputBindingDescription& t) { StreamIn(sink, t.binding, t.stride, t.inputRate); } template <> void stream::Stream::Write( stream::Sink* sink, const VkVertexInputAttributeDescription& t) { StreamIn(sink, t.location, t.binding, t.format, t.offset); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineVertexInputStateCreateInfo& t) { StreamIn(sink, t.flags, Iterable(t.pVertexBindingDescriptions, t.vertexBindingDescriptionCount), Iterable(t.pVertexAttributeDescriptions, t.vertexAttributeDescriptionCount)); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineInputAssemblyStateCreateInfo& t) { StreamIn(sink, t.flags, t.topology, t.primitiveRestartEnable); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineTessellationStateCreateInfo& t) { StreamIn(sink, t.flags, t.patchControlPoints); SerializePnext(sink, &t); } template <> void stream::Stream::Write(stream::Sink* sink, const VkViewport& t) { StreamIn(sink, t.x, t.y, t.width, t.height, t.minDepth, t.maxDepth); } template <> void stream::Stream::Write(stream::Sink* sink, const VkOffset2D& t) { StreamIn(sink, t.x, t.y); } template <> void stream::Stream::Write(stream::Sink* sink, const VkExtent2D& t) { StreamIn(sink, t.width, t.height); } template <> void stream::Stream::Write(stream::Sink* sink, const VkRect2D& t) { StreamIn(sink, t.offset, t.extent); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineViewportStateCreateInfo& t) { StreamIn(sink, t.flags, Iterable(t.pViewports, t.viewportCount), Iterable(t.pScissors, t.scissorCount)); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineRasterizationStateCreateInfo& t) { StreamIn(sink, t.flags, t.depthClampEnable, t.rasterizerDiscardEnable, t.polygonMode, t.cullMode, t.frontFace, t.depthBiasEnable, t.depthBiasConstantFactor, t.depthBiasClamp, t.depthBiasSlopeFactor, t.lineWidth); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineMultisampleStateCreateInfo& t) { StreamIn(sink, t.flags, t.rasterizationSamples, t.sampleShadingEnable, t.minSampleShading, t.pSampleMask, t.alphaToCoverageEnable, t.alphaToOneEnable); SerializePnext(sink, &t); } template <> void stream::Stream::Write(stream::Sink* sink, const VkStencilOpState& t) { StreamIn(sink, t.failOp, t.passOp, t.depthFailOp, t.compareOp, t.compareMask, t.writeMask, t.reference); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineDepthStencilStateCreateInfo& t) { StreamIn(sink, t.flags, t.depthTestEnable, t.depthWriteEnable, t.depthCompareOp, t.depthBoundsTestEnable, t.stencilTestEnable, t.front, t.back, t.minDepthBounds, t.maxDepthBounds); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineColorBlendAttachmentState& t) { StreamIn(sink, t.blendEnable, t.srcColorBlendFactor, t.dstColorBlendFactor, t.colorBlendOp, t.srcAlphaBlendFactor, t.dstAlphaBlendFactor, t.alphaBlendOp, t.colorWriteMask); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineColorBlendStateCreateInfo& t) { StreamIn(sink, t.flags, t.logicOpEnable, t.logicOp, Iterable(t.pAttachments, t.attachmentCount), t.blendConstants); SerializePnext(sink, &t); } template <> void stream::Stream::Write( stream::Sink* sink, const VkPipelineDynamicStateCreateInfo& t) { StreamIn(sink, t.flags, Iterable(t.pDynamicStates, t.dynamicStateCount)); SerializePnext(sink, &t); } template <> void stream::Stream::Write(stream::Sink* sink, const vulkan::RenderPassCacheQuery& t) { StreamIn(sink, t.colorMask.to_ulong(), t.resolveTargetMask.to_ulong(), t.sampleCount); // Manually iterate the color attachment indices and their corresponding format/load/store // ops because the data is sparse and may be uninitialized. Since we serialize the colorMask // member above, serializing sparse data should be fine here. for (ColorAttachmentIndex i : IterateBitSet(t.colorMask)) { StreamIn(sink, t.colorFormats[i], t.colorLoadOp[i], t.colorStoreOp[i]); } // Serialize the depth-stencil toggle bit, and the parameters if applicable. StreamIn(sink, t.hasDepthStencil); if (t.hasDepthStencil) { StreamIn(sink, t.depthStencilFormat, t.depthLoadOp, t.depthStoreOp, t.stencilLoadOp, t.stencilStoreOp, t.readOnlyDepthStencil); } } template <> void stream::Stream::Write(stream::Sink* sink, const VkGraphicsPipelineCreateInfo& t) { // The pipeline layout and render pass are not serialized here because they are pointers to // backend objects. They need to be cross-referenced with the frontend objects and // serialized from there. The base pipeline information is also currently not serialized since // we do not use them in our backend implementation. If we decide to use them later on, they // also need to be cross-referenced from the frontend. StreamIn(sink, t.flags, Iterable(t.pStages, t.stageCount), t.pVertexInputState, t.pInputAssemblyState, t.pTessellationState, t.pViewportState, t.pRasterizationState, t.pMultisampleState, t.pDepthStencilState, t.pColorBlendState, t.pDynamicState, t.subpass); SerializePnext(sink, &t); } } // namespace dawn::native