| // Copyright 2017 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. | |
| #ifndef DAWNNATIVE_SHADERMODULE_H_ | |
| #define DAWNNATIVE_SHADERMODULE_H_ | |
| #include "common/Constants.h" | |
| #include "common/ityp_array.h" | |
| #include "dawn_native/BindingInfo.h" | |
| #include "dawn_native/CachedObject.h" | |
| #include "dawn_native/CompilationMessages.h" | |
| #include "dawn_native/Error.h" | |
| #include "dawn_native/Format.h" | |
| #include "dawn_native/Forward.h" | |
| #include "dawn_native/IntegerTypes.h" | |
| #include "dawn_native/ObjectBase.h" | |
| #include "dawn_native/PerStage.h" | |
| #include "dawn_native/VertexFormat.h" | |
| #include "dawn_native/dawn_platform.h" | |
| #include <bitset> | |
| #include <map> | |
| #include <unordered_map> | |
| #include <unordered_set> | |
| #include <vector> | |
| namespace tint { | |
| class Program; | |
| namespace transform { | |
| class DataMap; | |
| class Transform; | |
| class VertexPulling; | |
| } // namespace transform | |
| } // namespace tint | |
| namespace dawn::native { | |
| struct EntryPointMetadata; | |
| // Base component type of an inter-stage variable | |
| enum class InterStageComponentType { | |
| Sint, | |
| Uint, | |
| Float, | |
| }; | |
| enum class InterpolationType { | |
| Perspective, | |
| Linear, | |
| Flat, | |
| }; | |
| enum class InterpolationSampling { | |
| None, | |
| Center, | |
| Centroid, | |
| Sample, | |
| }; | |
| using PipelineLayoutEntryPointPair = std::pair<PipelineLayoutBase*, std::string>; | |
| struct PipelineLayoutEntryPointPairHashFunc { | |
| size_t operator()(const PipelineLayoutEntryPointPair& pair) const; | |
| }; | |
| // A map from name to EntryPointMetadata. | |
| using EntryPointMetadataTable = | |
| std::unordered_map<std::string, std::unique_ptr<EntryPointMetadata>>; | |
| // Source for a tint program | |
| class TintSource; | |
| struct ShaderModuleParseResult { | |
| ShaderModuleParseResult(); | |
| ~ShaderModuleParseResult(); | |
| ShaderModuleParseResult(ShaderModuleParseResult&& rhs); | |
| ShaderModuleParseResult& operator=(ShaderModuleParseResult&& rhs); | |
| bool HasParsedShader() const; | |
| std::unique_ptr<tint::Program> tintProgram; | |
| std::unique_ptr<TintSource> tintSource; | |
| }; | |
| MaybeError ValidateShaderModuleDescriptor(DeviceBase* device, | |
| const ShaderModuleDescriptor* descriptor, | |
| ShaderModuleParseResult* parseResult, | |
| OwnedCompilationMessages* outMessages); | |
| MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device, | |
| const EntryPointMetadata& entryPoint, | |
| const PipelineLayoutBase* layout); | |
| RequiredBufferSizes ComputeRequiredBufferSizesForLayout(const EntryPointMetadata& entryPoint, | |
| const PipelineLayoutBase* layout); | |
| ResultOrError<tint::Program> RunTransforms(tint::transform::Transform* transform, | |
| const tint::Program* program, | |
| const tint::transform::DataMap& inputs, | |
| tint::transform::DataMap* outputs, | |
| OwnedCompilationMessages* messages); | |
| /// Creates and adds the tint::transform::VertexPulling::Config to transformInputs. | |
| void AddVertexPullingTransformConfig(const RenderPipelineBase& renderPipeline, | |
| const std::string& entryPoint, | |
| BindGroupIndex pullingBufferBindingSet, | |
| tint::transform::DataMap* transformInputs); | |
| // Mirrors wgpu::SamplerBindingLayout but instead stores a single boolean | |
| // for isComparison instead of a wgpu::SamplerBindingType enum. | |
| struct ShaderSamplerBindingInfo { | |
| bool isComparison; | |
| }; | |
| // Mirrors wgpu::TextureBindingLayout but instead has a set of compatible sampleTypes | |
| // instead of a single enum. | |
| struct ShaderTextureBindingInfo { | |
| SampleTypeBit compatibleSampleTypes; | |
| wgpu::TextureViewDimension viewDimension; | |
| bool multisampled; | |
| }; | |
| // Per-binding shader metadata contains some SPIRV specific information in addition to | |
| // most of the frontend per-binding information. | |
| struct ShaderBindingInfo { | |
| // The SPIRV ID of the resource. | |
| uint32_t id; | |
| uint32_t base_type_id; | |
| BindingNumber binding; | |
| BindingInfoType bindingType; | |
| BufferBindingLayout buffer; | |
| ShaderSamplerBindingInfo sampler; | |
| ShaderTextureBindingInfo texture; | |
| StorageTextureBindingLayout storageTexture; | |
| }; | |
| using BindingGroupInfoMap = std::map<BindingNumber, ShaderBindingInfo>; | |
| using BindingInfoArray = ityp::array<BindGroupIndex, BindingGroupInfoMap, kMaxBindGroups>; | |
| // The WebGPU overridable constants only support these scalar types | |
| union OverridableConstantScalar { | |
| // Use int32_t for boolean to initialize the full 32bit | |
| int32_t b; | |
| float f32; | |
| int32_t i32; | |
| uint32_t u32; | |
| }; | |
| // Contains all the reflection data for a valid (ShaderModule, entryPoint, stage). They are | |
| // stored in the ShaderModuleBase and destroyed only when the shader program is destroyed so | |
| // pointers to EntryPointMetadata are safe to store as long as you also keep a Ref to the | |
| // ShaderModuleBase. | |
| struct EntryPointMetadata { | |
| // bindings[G][B] is the reflection data for the binding defined with | |
| // [[group=G, binding=B]] in WGSL / SPIRV. | |
| BindingInfoArray bindings; | |
| struct SamplerTexturePair { | |
| BindingSlot sampler; | |
| BindingSlot texture; | |
| }; | |
| std::vector<SamplerTexturePair> samplerTexturePairs; | |
| // The set of vertex attributes this entryPoint uses. | |
| ityp::array<VertexAttributeLocation, VertexFormatBaseType, kMaxVertexAttributes> | |
| vertexInputBaseTypes; | |
| ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes> usedVertexInputs; | |
| // An array to record the basic types (float, int and uint) of the fragment shader outputs. | |
| struct FragmentOutputVariableInfo { | |
| wgpu::TextureComponentType baseType; | |
| uint8_t componentCount; | |
| }; | |
| ityp::array<ColorAttachmentIndex, FragmentOutputVariableInfo, kMaxColorAttachments> | |
| fragmentOutputVariables; | |
| ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments> fragmentOutputsWritten; | |
| struct InterStageVariableInfo { | |
| InterStageComponentType baseType; | |
| uint32_t componentCount; | |
| InterpolationType interpolationType; | |
| InterpolationSampling interpolationSampling; | |
| }; | |
| // Now that we only support vertex and fragment stages, there can't be both inter-stage | |
| // inputs and outputs in one shader stage. | |
| std::bitset<kMaxInterStageShaderVariables> usedInterStageVariables; | |
| std::array<InterStageVariableInfo, kMaxInterStageShaderVariables> interStageVariables; | |
| // The local workgroup size declared for a compute entry point (or 0s otehrwise). | |
| Origin3D localWorkgroupSize; | |
| // The shader stage for this binding. | |
| SingleShaderStage stage; | |
| struct OverridableConstant { | |
| uint32_t id; | |
| // Match tint::inspector::OverridableConstant::Type | |
| // Bool is defined as a macro on linux X11 and cannot compile | |
| enum class Type { Boolean, Float32, Uint32, Int32 } type; | |
| // If the constant doesn't not have an initializer in the shader | |
| // Then it is required for the pipeline stage to have a constant record to initialize a | |
| // value | |
| bool isInitialized; | |
| // Store the default initialized value in shader | |
| // This is used by metal backend as the function_constant does not have dafault values | |
| // Initialized when isInitialized == true | |
| OverridableConstantScalar defaultValue; | |
| }; | |
| using OverridableConstantsMap = std::unordered_map<std::string, OverridableConstant>; | |
| // Map identifier to overridable constant | |
| // Identifier is unique: either the variable name or the numeric ID if specified | |
| OverridableConstantsMap overridableConstants; | |
| // Overridable constants that are not initialized in shaders | |
| // They need value initialization from pipeline stage or it is a validation error | |
| std::unordered_set<std::string> uninitializedOverridableConstants; | |
| // Store constants with shader initialized values as well | |
| // This is used by metal backend to set values with default initializers that are not | |
| // overridden | |
| std::unordered_set<std::string> initializedOverridableConstants; | |
| bool usesNumWorkgroups = false; | |
| }; | |
| class ShaderModuleBase : public ApiObjectBase, public CachedObject { | |
| public: | |
| ShaderModuleBase(DeviceBase* device, | |
| const ShaderModuleDescriptor* descriptor, | |
| ApiObjectBase::UntrackedByDeviceTag tag); | |
| ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor); | |
| ~ShaderModuleBase() override; | |
| static Ref<ShaderModuleBase> MakeError(DeviceBase* device); | |
| ObjectType GetType() const override; | |
| // Return true iff the program has an entrypoint called `entryPoint`. | |
| bool HasEntryPoint(const std::string& entryPoint) const; | |
| // Return the metadata for the given `entryPoint`. HasEntryPoint with the same argument | |
| // must be true. | |
| const EntryPointMetadata& GetEntryPoint(const std::string& entryPoint) const; | |
| // Functions necessary for the unordered_set<ShaderModuleBase*>-based cache. | |
| size_t ComputeContentHash() override; | |
| struct EqualityFunc { | |
| bool operator()(const ShaderModuleBase* a, const ShaderModuleBase* b) const; | |
| }; | |
| const tint::Program* GetTintProgram() const; | |
| void APIGetCompilationInfo(wgpu::CompilationInfoCallback callback, void* userdata); | |
| void InjectCompilationMessages( | |
| std::unique_ptr<OwnedCompilationMessages> compilationMessages); | |
| OwnedCompilationMessages* GetCompilationMessages() const; | |
| protected: | |
| // Constructor used only for mocking and testing. | |
| ShaderModuleBase(DeviceBase* device); | |
| void DestroyImpl() override; | |
| MaybeError InitializeBase(ShaderModuleParseResult* parseResult); | |
| private: | |
| ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag); | |
| // The original data in the descriptor for caching. | |
| enum class Type { Undefined, Spirv, Wgsl }; | |
| Type mType; | |
| std::vector<uint32_t> mOriginalSpirv; | |
| std::string mWgsl; | |
| EntryPointMetadataTable mEntryPoints; | |
| std::unique_ptr<tint::Program> mTintProgram; | |
| std::unique_ptr<TintSource> mTintSource; // Keep the tint::Source::File alive | |
| std::unique_ptr<OwnedCompilationMessages> mCompilationMessages; | |
| }; | |
| } // namespace dawn::native | |
| #endif // DAWNNATIVE_SHADERMODULE_H_ |