• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 #ifndef DAWNNATIVE_BINDGROUPTRACKER_H_
16 #define DAWNNATIVE_BINDGROUPTRACKER_H_
17 
18 #include "common/Constants.h"
19 #include "dawn_native/BindGroupLayout.h"
20 #include "dawn_native/Pipeline.h"
21 #include "dawn_native/PipelineLayout.h"
22 
23 #include <array>
24 #include <bitset>
25 
26 namespace dawn_native {
27 
28     // Keeps track of the dirty bind groups so they can be lazily applied when we know the
29     // pipeline state or it changes.
30     // |DynamicOffset| is a template parameter because offsets in Vulkan are uint32_t but uint64_t
31     // in other backends.
32     template <bool CanInheritBindGroups, typename DynamicOffset>
33     class BindGroupTrackerBase {
34       public:
OnSetBindGroup(BindGroupIndex index,BindGroupBase * bindGroup,uint32_t dynamicOffsetCount,uint32_t * dynamicOffsets)35         void OnSetBindGroup(BindGroupIndex index,
36                             BindGroupBase* bindGroup,
37                             uint32_t dynamicOffsetCount,
38                             uint32_t* dynamicOffsets) {
39             ASSERT(index < kMaxBindGroupsTyped);
40 
41             if (mBindGroupLayoutsMask[index]) {
42                 // It is okay to only dirty bind groups that are used by the current pipeline
43                 // layout. If the pipeline layout changes, then the bind groups it uses will
44                 // become dirty.
45 
46                 if (mBindGroups[index] != bindGroup) {
47                     mDirtyBindGroups.set(index);
48                     mDirtyBindGroupsObjectChangedOrIsDynamic.set(index);
49                 }
50 
51                 if (dynamicOffsetCount > 0) {
52                     mDirtyBindGroupsObjectChangedOrIsDynamic.set(index);
53                 }
54             }
55 
56             mBindGroups[index] = bindGroup;
57             mDynamicOffsetCounts[index] = dynamicOffsetCount;
58             SetDynamicOffsets(mDynamicOffsets[index].data(), dynamicOffsetCount, dynamicOffsets);
59         }
60 
OnSetPipeline(PipelineBase * pipeline)61         void OnSetPipeline(PipelineBase* pipeline) {
62             mPipelineLayout = pipeline->GetLayout();
63         }
64 
65       protected:
66         // The Derived class should call this before it applies bind groups.
BeforeApply()67         void BeforeApply() {
68             if (mLastAppliedPipelineLayout == mPipelineLayout) {
69                 return;
70             }
71 
72             // Use the bind group layout mask to avoid marking unused bind groups as dirty.
73             mBindGroupLayoutsMask = mPipelineLayout->GetBindGroupLayoutsMask();
74 
75             // Changing the pipeline layout sets bind groups as dirty. If CanInheritBindGroups,
76             // the first |k| matching bind groups may be inherited.
77             if (CanInheritBindGroups && mLastAppliedPipelineLayout != nullptr) {
78                 // Dirty bind groups that cannot be inherited.
79                 BindGroupLayoutMask dirtiedGroups =
80                     ~mPipelineLayout->InheritedGroupsMask(mLastAppliedPipelineLayout);
81 
82                 mDirtyBindGroups |= dirtiedGroups;
83                 mDirtyBindGroupsObjectChangedOrIsDynamic |= dirtiedGroups;
84 
85                 // Clear any bind groups not in the mask.
86                 mDirtyBindGroups &= mBindGroupLayoutsMask;
87                 mDirtyBindGroupsObjectChangedOrIsDynamic &= mBindGroupLayoutsMask;
88             } else {
89                 mDirtyBindGroups = mBindGroupLayoutsMask;
90                 mDirtyBindGroupsObjectChangedOrIsDynamic = mBindGroupLayoutsMask;
91             }
92         }
93 
94         // The Derived class should call this after it applies bind groups.
AfterApply()95         void AfterApply() {
96             // Reset all dirty bind groups. Dirty bind groups not in the bind group layout mask
97             // will be dirtied again by the next pipeline change.
98             mDirtyBindGroups.reset();
99             mDirtyBindGroupsObjectChangedOrIsDynamic.reset();
100             // Keep track of the last applied pipeline layout. This allows us to avoid computing
101             // the intersection of the dirty bind groups and bind group layout mask in next Draw
102             // or Dispatch (which is very hot code) until the layout is changed again.
103             mLastAppliedPipelineLayout = mPipelineLayout;
104         }
105 
106         BindGroupLayoutMask mDirtyBindGroups = 0;
107         BindGroupLayoutMask mDirtyBindGroupsObjectChangedOrIsDynamic = 0;
108         BindGroupLayoutMask mBindGroupLayoutsMask = 0;
109         ityp::array<BindGroupIndex, BindGroupBase*, kMaxBindGroups> mBindGroups = {};
110         ityp::array<BindGroupIndex, uint32_t, kMaxBindGroups> mDynamicOffsetCounts = {};
111         ityp::array<BindGroupIndex,
112                     std::array<DynamicOffset, kMaxDynamicBuffersPerPipelineLayout>,
113                     kMaxBindGroups>
114             mDynamicOffsets = {};
115 
116         // |mPipelineLayout| is the current pipeline layout set on the command buffer.
117         // |mLastAppliedPipelineLayout| is the last pipeline layout for which we applied changes
118         // to the bind group bindings.
119         PipelineLayoutBase* mPipelineLayout = nullptr;
120         PipelineLayoutBase* mLastAppliedPipelineLayout = nullptr;
121 
122       private:
123         // We have two overloads here because offsets in Vulkan are uint32_t but uint64_t
124         // in other backends.
SetDynamicOffsets(uint64_t * data,uint32_t dynamicOffsetCount,uint32_t * dynamicOffsets)125         static void SetDynamicOffsets(uint64_t* data,
126                                       uint32_t dynamicOffsetCount,
127                                       uint32_t* dynamicOffsets) {
128             for (uint32_t i = 0; i < dynamicOffsetCount; ++i) {
129                 data[i] = static_cast<uint64_t>(dynamicOffsets[i]);
130             }
131         }
132 
SetDynamicOffsets(uint32_t * data,uint32_t dynamicOffsetCount,uint32_t * dynamicOffsets)133         static void SetDynamicOffsets(uint32_t* data,
134                                       uint32_t dynamicOffsetCount,
135                                       uint32_t* dynamicOffsets) {
136             memcpy(data, dynamicOffsets, sizeof(uint32_t) * dynamicOffsetCount);
137         }
138     };
139 
140 }  // namespace dawn_native
141 
142 #endif  // DAWNNATIVE_BINDGROUPTRACKER_H_
143