1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/BindGroupLayout.h" 16 17 #include "common/BitSetIterator.h" 18 #include "common/HashUtils.h" 19 #include "dawn_native/Device.h" 20 #include "dawn_native/ValidationUtils_autogen.h" 21 22 #include <functional> 23 24 namespace dawn_native { 25 ValidateBindGroupLayoutDescriptor(DeviceBase *,const BindGroupLayoutDescriptor * descriptor)26 MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase*, 27 const BindGroupLayoutDescriptor* descriptor) { 28 if (descriptor->nextInChain != nullptr) { 29 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); 30 } 31 32 std::bitset<kMaxBindingsPerGroup> bindingsSet; 33 for (uint32_t i = 0; i < descriptor->bindingCount; ++i) { 34 const BindGroupLayoutBinding& binding = descriptor->bindings[i]; 35 DAWN_TRY(ValidateShaderStageBit(binding.visibility)); 36 DAWN_TRY(ValidateBindingType(binding.type)); 37 38 if (binding.binding >= kMaxBindingsPerGroup) { 39 return DAWN_VALIDATION_ERROR("some binding index exceeds the maximum value"); 40 } 41 if (bindingsSet[binding.binding]) { 42 return DAWN_VALIDATION_ERROR("some binding index was specified more than once"); 43 } 44 45 switch (binding.type) { 46 case dawn::BindingType::UniformBuffer: 47 case dawn::BindingType::StorageBuffer: 48 break; 49 case dawn::BindingType::SampledTexture: 50 case dawn::BindingType::Sampler: 51 if (binding.dynamic) { 52 return DAWN_VALIDATION_ERROR("Samplers and textures cannot be dynamic"); 53 } 54 break; 55 case dawn::BindingType::ReadonlyStorageBuffer: 56 return DAWN_VALIDATION_ERROR("readonly storage buffers aren't supported (yet)"); 57 case dawn::BindingType::StorageTexture: 58 return DAWN_VALIDATION_ERROR("storage textures aren't supported (yet)"); 59 } 60 61 if (binding.multisampled) { 62 return DAWN_VALIDATION_ERROR( 63 "BindGroupLayoutBinding::multisampled must be false (for now)"); 64 } 65 66 bindingsSet.set(binding.binding); 67 } 68 return {}; 69 } 70 71 namespace { HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo & info)72 size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) { 73 size_t hash = Hash(info.mask); 74 HashCombine(&hash, info.dynamic, info.multisampled); 75 76 for (uint32_t binding : IterateBitSet(info.mask)) { 77 HashCombine(&hash, info.visibilities[binding], info.types[binding]); 78 } 79 80 return hash; 81 } 82 operator ==(const BindGroupLayoutBase::LayoutBindingInfo & a,const BindGroupLayoutBase::LayoutBindingInfo & b)83 bool operator==(const BindGroupLayoutBase::LayoutBindingInfo& a, 84 const BindGroupLayoutBase::LayoutBindingInfo& b) { 85 if (a.mask != b.mask || a.dynamic != b.dynamic || a.multisampled != b.multisampled) { 86 return false; 87 } 88 89 for (uint32_t binding : IterateBitSet(a.mask)) { 90 if ((a.visibilities[binding] != b.visibilities[binding]) || 91 (a.types[binding] != b.types[binding])) { 92 return false; 93 } 94 } 95 96 return true; 97 } 98 } // namespace 99 100 // BindGroupLayoutBase 101 BindGroupLayoutBase(DeviceBase * device,const BindGroupLayoutDescriptor * descriptor,bool blueprint)102 BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, 103 const BindGroupLayoutDescriptor* descriptor, 104 bool blueprint) 105 : ObjectBase(device), mIsBlueprint(blueprint) { 106 for (uint32_t i = 0; i < descriptor->bindingCount; ++i) { 107 auto& binding = descriptor->bindings[i]; 108 109 uint32_t index = binding.binding; 110 mBindingInfo.visibilities[index] = binding.visibility; 111 mBindingInfo.types[index] = binding.type; 112 113 if (binding.dynamic) { 114 mBindingInfo.dynamic.set(index); 115 mDynamicBufferCount++; 116 } 117 118 mBindingInfo.multisampled.set(index, binding.multisampled); 119 120 ASSERT(!mBindingInfo.mask[index]); 121 mBindingInfo.mask.set(index); 122 } 123 } 124 BindGroupLayoutBase(DeviceBase * device,ObjectBase::ErrorTag tag)125 BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, ObjectBase::ErrorTag tag) 126 : ObjectBase(device, tag), mIsBlueprint(true) { 127 } 128 ~BindGroupLayoutBase()129 BindGroupLayoutBase::~BindGroupLayoutBase() { 130 // Do not uncache the actual cached object if we are a blueprint 131 if (!mIsBlueprint && !IsError()) { 132 GetDevice()->UncacheBindGroupLayout(this); 133 } 134 } 135 136 // static MakeError(DeviceBase * device)137 BindGroupLayoutBase* BindGroupLayoutBase::MakeError(DeviceBase* device) { 138 return new BindGroupLayoutBase(device, ObjectBase::kError); 139 } 140 GetBindingInfo() const141 const BindGroupLayoutBase::LayoutBindingInfo& BindGroupLayoutBase::GetBindingInfo() const { 142 ASSERT(!IsError()); 143 return mBindingInfo; 144 } 145 operator ()(const BindGroupLayoutBase * bgl) const146 size_t BindGroupLayoutBase::HashFunc::operator()(const BindGroupLayoutBase* bgl) const { 147 return HashBindingInfo(bgl->mBindingInfo); 148 } 149 operator ()(const BindGroupLayoutBase * a,const BindGroupLayoutBase * b) const150 bool BindGroupLayoutBase::EqualityFunc::operator()(const BindGroupLayoutBase* a, 151 const BindGroupLayoutBase* b) const { 152 return a->mBindingInfo == b->mBindingInfo; 153 } 154 GetDynamicBufferCount() const155 uint32_t BindGroupLayoutBase::GetDynamicBufferCount() const { 156 return mDynamicBufferCount; 157 } 158 159 } // namespace dawn_native 160