text: // 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.
  
  #include "dawn_native/Pipeline.h"
  
  #include "dawn_native/DepthStencilState.h"
  #include "dawn_native/Device.h"
  #include "dawn_native/InputState.h"
  #include "dawn_native/PipelineLayout.h"
  #include "dawn_native/ShaderModule.h"
  
  namespace dawn_native {
  
      // PipelineBase
  
      PipelineBase::PipelineBase(DeviceBase* device,
                                 PipelineLayoutBase* layout,
                                 dawn::ShaderStageBit stages)
          : mStageMask(stages), mLayout(layout), mDevice(device) {
      }
  
      PipelineBase::PipelineBase(DeviceBase* device, PipelineBuilder* builder)
          : mStageMask(builder->mStageMask), mLayout(std::move(builder->mLayout)), mDevice(device) {
          if (!mLayout) {
              PipelineLayoutDescriptor descriptor;
              descriptor.numBindGroupLayouts = 0;
              descriptor.bindGroupLayouts = nullptr;
              mLayout = builder->GetParentBuilder()->GetDevice()->CreatePipelineLayout(&descriptor);
              // Remove the external ref objects are created with
              mLayout->Release();
          }
  
          for (auto stage : IterateStages(builder->mStageMask)) {
              if (!builder->mStages[stage].module->IsCompatibleWithPipelineLayout(mLayout.Get())) {
                  builder->GetParentBuilder()->HandleError("Stage not compatible with layout");
                  return;
              }
  
              ExtractModuleData(stage, builder->mStages[stage].module.Get());
          }
      }
  
      void PipelineBase::ExtractModuleData(dawn::ShaderStage stage, ShaderModuleBase* module) {
          PushConstantInfo* info = &mPushConstants[stage];
  
          const auto& moduleInfo = module->GetPushConstants();
          info->mask = moduleInfo.mask;
  
          for (uint32_t i = 0; i < moduleInfo.names.size(); i++) {
              uint32_t size = moduleInfo.sizes[i];
              if (size == 0) {
                  continue;
              }
  
              for (uint32_t offset = 0; offset < size; offset++) {
                  info->types[i + offset] = moduleInfo.types[i];
              }
              i += size - 1;
          }
      }
  
      const PipelineBase::PushConstantInfo& PipelineBase::GetPushConstants(
          dawn::ShaderStage stage) const {
          return mPushConstants[stage];
      }
  
      dawn::ShaderStageBit PipelineBase::GetStageMask() const {
          return mStageMask;
      }
  
      PipelineLayoutBase* PipelineBase::GetLayout() {
          return mLayout.Get();
      }
  
      DeviceBase* PipelineBase::GetDevice() const {
          return mDevice;
      }
  
      // PipelineBuilder
  
      PipelineBuilder::PipelineBuilder(BuilderBase* parentBuilder)
          : mParentBuilder(parentBuilder), mStageMask(static_cast<dawn::ShaderStageBit>(0)) {
      }
  
      const PipelineBuilder::StageInfo& PipelineBuilder::GetStageInfo(dawn::ShaderStage stage) const {
          ASSERT(mStageMask & StageBit(stage));
          return mStages[stage];
      }
  
      BuilderBase* PipelineBuilder::GetParentBuilder() const {
          return mParentBuilder;
      }
  
      void PipelineBuilder::SetLayout(PipelineLayoutBase* layout) {
          mLayout = layout;
      }
  
      void PipelineBuilder::SetStage(dawn::ShaderStage stage,
                                     ShaderModuleBase* module,
                                     const char* entryPoint) {
          if (entryPoint != std::string("main")) {
              mParentBuilder->HandleError("Currently the entry point has to be main()");
              return;
          }
  
          if (stage != module->GetExecutionModel()) {
              mParentBuilder->HandleError("Setting module with wrong execution model");
              return;
          }
  
          dawn::ShaderStageBit bit = StageBit(stage);
          if (mStageMask & bit) {
              mParentBuilder->HandleError("Setting already set stage");
              return;
          }
          mStageMask |= bit;
  
          mStages[stage].module = module;
          mStages[stage].entryPoint = entryPoint;
      }
  
  }  // namespace dawn_native
  