| // 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 <cstring> |
| #include <map> |
| |
| #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 <typename... VK_STRUCT_TYPES> |
| void ValidatePnextImpl(const VkBaseOutStructure* root) { |
| const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext); |
| while (next != nullptr) { |
| // Assert that the type of each pNext struct is exactly one of the specified |
| // templates. |
| ASSERT(((LvlTypeMap<VK_STRUCT_TYPES>::kSType == next->sType ? 1 : 0) + ... + 0) == 1); |
| next = reinterpret_cast<const VkBaseOutStructure*>(next->pNext); |
| } |
| } |
| |
| template <typename VK_STRUCT_TYPE> |
| void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) { |
| const VkBaseOutStructure* next = reinterpret_cast<const VkBaseOutStructure*>(root->pNext); |
| const VK_STRUCT_TYPE* found = nullptr; |
| while (next != nullptr) { |
| if (LvlTypeMap<VK_STRUCT_TYPE>::kSType == next->sType) { |
| if (found == nullptr) { |
| found = reinterpret_cast<const VK_STRUCT_TYPE*>(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<const VkBaseOutStructure*>(next->pNext); |
| } |
| if (found != nullptr) { |
| StreamIn(sink, found); |
| } |
| } |
| |
| template <typename VK_STRUCT_TYPE, |
| typename... VK_STRUCT_TYPES, |
| typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>> |
| void SerializePnextImpl(stream::Sink* sink, const VkBaseOutStructure* root) { |
| SerializePnextImpl<VK_STRUCT_TYPE>(sink, root); |
| SerializePnextImpl<VK_STRUCT_TYPES...>(sink, root); |
| } |
| |
| template <typename VK_STRUCT_TYPE> |
| 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<const VkBaseOutStructure*>(t); |
| } |
| |
| } // namespace detail |
| |
| template <typename... VK_STRUCT_TYPES, |
| typename VK_STRUCT_TYPE, |
| typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>> |
| void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) { |
| const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t); |
| detail::ValidatePnextImpl<VK_STRUCT_TYPES...>(root); |
| detail::SerializePnextImpl<VK_STRUCT_TYPES...>(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 <typename VK_STRUCT_TYPE> |
| void SerializePnext(stream::Sink* sink, const VK_STRUCT_TYPE* t) { |
| const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t); |
| detail::ValidatePnextImpl<>(root); |
| } |
| |
| } // namespace |
| |
| template <> |
| void stream::Stream<VkDescriptorSetLayoutBinding>::Write(stream::Sink* sink, |
| const VkDescriptorSetLayoutBinding& t) { |
| StreamIn(sink, t.binding, t.descriptorType, t.descriptorCount, t.stageFlags); |
| } |
| |
| template <> |
| void stream::Stream<VkDescriptorSetLayoutCreateInfo>::Write( |
| stream::Sink* sink, |
| const VkDescriptorSetLayoutCreateInfo& t) { |
| StreamIn(sink, t.flags, Iterable(t.pBindings, t.bindingCount)); |
| SerializePnext(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<VkPushConstantRange>::Write(stream::Sink* sink, const VkPushConstantRange& t) { |
| StreamIn(sink, t.stageFlags, t.offset, t.size); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineLayoutCreateInfo>::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<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>::Write( |
| stream::Sink* sink, |
| const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT& t) { |
| StreamIn(sink, t.requiredSubgroupSize); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineRasterizationDepthClipStateCreateInfoEXT>::Write( |
| stream::Sink* sink, |
| const VkPipelineRasterizationDepthClipStateCreateInfoEXT& t) { |
| StreamIn(sink, t.depthClipEnable, t.flags); |
| } |
| |
| template <> |
| void stream::Stream<VkSpecializationMapEntry>::Write(stream::Sink* sink, |
| const VkSpecializationMapEntry& t) { |
| StreamIn(sink, t.constantID, t.offset, t.size); |
| } |
| |
| template <> |
| void stream::Stream<VkSpecializationInfo>::Write(stream::Sink* sink, |
| const VkSpecializationInfo& t) { |
| StreamIn(sink, Iterable(t.pMapEntries, t.mapEntryCount), |
| Iterable(static_cast<const uint8_t*>(t.pData), t.dataSize)); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineShaderStageCreateInfo>::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<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<VkComputePipelineCreateInfo>::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<VkVertexInputBindingDescription>::Write( |
| stream::Sink* sink, |
| const VkVertexInputBindingDescription& t) { |
| StreamIn(sink, t.binding, t.stride, t.inputRate); |
| } |
| |
| template <> |
| void stream::Stream<VkVertexInputAttributeDescription>::Write( |
| stream::Sink* sink, |
| const VkVertexInputAttributeDescription& t) { |
| StreamIn(sink, t.location, t.binding, t.format, t.offset); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineVertexInputStateCreateInfo>::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<VkPipelineInputAssemblyStateCreateInfo>::Write( |
| stream::Sink* sink, |
| const VkPipelineInputAssemblyStateCreateInfo& t) { |
| StreamIn(sink, t.flags, t.topology, t.primitiveRestartEnable); |
| SerializePnext(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineTessellationStateCreateInfo>::Write( |
| stream::Sink* sink, |
| const VkPipelineTessellationStateCreateInfo& t) { |
| StreamIn(sink, t.flags, t.patchControlPoints); |
| SerializePnext(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<VkViewport>::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<VkOffset2D>::Write(stream::Sink* sink, const VkOffset2D& t) { |
| StreamIn(sink, t.x, t.y); |
| } |
| |
| template <> |
| void stream::Stream<VkExtent2D>::Write(stream::Sink* sink, const VkExtent2D& t) { |
| StreamIn(sink, t.width, t.height); |
| } |
| |
| template <> |
| void stream::Stream<VkRect2D>::Write(stream::Sink* sink, const VkRect2D& t) { |
| StreamIn(sink, t.offset, t.extent); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineViewportStateCreateInfo>::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<VkPipelineRasterizationStateCreateInfo>::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<VkPipelineRasterizationDepthClipStateCreateInfoEXT>(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<VkPipelineMultisampleStateCreateInfo>::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<VkStencilOpState>::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<VkPipelineDepthStencilStateCreateInfo>::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<VkPipelineColorBlendAttachmentState>::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<VkPipelineColorBlendStateCreateInfo>::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<VkPipelineDynamicStateCreateInfo>::Write( |
| stream::Sink* sink, |
| const VkPipelineDynamicStateCreateInfo& t) { |
| StreamIn(sink, t.flags, Iterable(t.pDynamicStates, t.dynamicStateCount)); |
| SerializePnext(sink, &t); |
| } |
| |
| template <> |
| void stream::Stream<vulkan::RenderPassCacheQuery>::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<VkGraphicsPipelineCreateInfo>::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 |