KiCad PCB EDA Suite
Loading...
Searching...
No Matches
rhi_compute.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <rhi/rhi_compute.h>
21
22#include <array>
23#include <unordered_set>
24
25
27{
28 if( !aLayout.Validate() )
29 return false;
30
31 for( const RHI_BINDING_ENTRY& entry : aLayout.entries )
32 {
33 if( !( entry.stages & RHI_SHADER_STAGE::COMPUTE ) )
34 return false;
35
37 return false;
38 }
39
40 return true;
41}
42
43
45{
47 || aDesc.pushConstantBytes % 4 || aDesc.bindGroupLayouts.size() > RHI_MAX_BIND_GROUPS )
48 {
49 return false;
50 }
51
52 std::unordered_set<uint32_t> ids;
53
54 for( const RHI_SPECIALIZATION_CONSTANT& constant : aDesc.constants )
55 {
56 if( constant.id < RHI_SPEC_ID_USER_FIRST || !ids.insert( constant.id ).second )
57 return false;
58 }
59
60 // Metal flattens sets, so binding numbers must be unique across all of them
61 std::unordered_set<uint32_t> bindings;
62
63 for( const RHI_BIND_GROUP_LAYOUT_DESC& layout : aDesc.bindGroupLayouts )
64 {
66 return false;
67
68 for( const RHI_BINDING_ENTRY& entry : layout.entries )
69 {
70 if( !bindings.insert( entry.binding ).second )
71 return false;
72 }
73 }
74
75 return true;
76}
77
78
80 const RHI_COMPUTE_JOB_LOOKUP& aLookup )
81{
82 using OP = RHI_COMPUTE_JOB::OP;
83
84 if( !aJob.IsValid() )
85 return false;
86
87 const RHI_COMPUTE_PIPELINE_DESC* pipeline = nullptr;
88 std::array<RHI_BindGroupHandle, RHI_MAX_BIND_GROUPS> bound{};
89 bool pushed = false;
90 bool groupsChecked = false;
91
92 for( const RHI_COMPUTE_JOB::COMMAND& command : aJob.Commands() )
93 {
94 switch( command.op )
95 {
96 case OP::UPLOAD:
97 case OP::READBACK:
98 if( !aLookup.storageRange( command.buffer, command.offset, command.bytes ) )
99 return false;
100
101 break;
102
103 case OP::BIND:
104 pipeline = aLookup.pipeline( command.pipeline );
105
106 if( !pipeline )
107 return false;
108
109 pushed = false;
110 groupsChecked = false;
111 break;
112
113 case OP::BIND_GROUP:
114 if( command.index >= bound.size() || !aLookup.groupLayout( command.group ) )
115 return false;
116
117 bound[command.index] = command.group;
118 groupsChecked = false;
119 break;
120
121 case OP::PUSH_CONSTANTS:
122 if( !pipeline || command.bytes != pipeline->pushConstantBytes )
123 return false;
124
125 pushed = true;
126 break;
127
128 case OP::DISPATCH:
129 if( !pipeline || !command.groupsX || !command.groupsY || command.groupsX > aLimits.maxDispatchGroups[0]
130 || command.groupsY > aLimits.maxDispatchGroups[1] || ( pipeline->pushConstantBytes && !pushed ) )
131 {
132 return false;
133 }
134
135 // Layouts only need rechecking after a pipeline or group change
136 if( !groupsChecked )
137 {
138 for( size_t i = 0; i < pipeline->bindGroupLayouts.size(); ++i )
139 {
141
142 if( expected.entries.empty() )
143 continue;
144
145 const RHI_BIND_GROUP_LAYOUT_DESC* actual = aLookup.groupLayout( bound[i] );
146
147 if( !actual || !actual->IsCompatible( expected ) )
148 return false;
149 }
150
151 groupsChecked = true;
152 }
153
154 break;
155
156 case OP::BARRIER: break;
157 }
158 }
159
160 return true;
161}
162
163
164static std::vector<uint8_t> copyBytes( const void* aData, size_t aBytes )
165{
166 const uint8_t* bytes = static_cast<const uint8_t*>( aData );
167 return aData ? std::vector<uint8_t>( bytes, bytes + aBytes ) : std::vector<uint8_t>();
168}
169
170
171void RHI_COMPUTE_JOB::Upload( RHI_BufferHandle aBuffer, const void* aData, size_t aBytes, size_t aOffset )
172{
173 m_valid = m_valid && ( aData || !aBytes );
174 m_commands.push_back( { .op = OP::UPLOAD,
175 .buffer = aBuffer,
176 .offset = aOffset,
177 .bytes = aBytes,
178 .data = copyBytes( aData, aBytes ) } );
179}
180
181
183{
184 m_commands.push_back( { .op = OP::BIND, .pipeline = aPipeline } );
185}
186
187
188void RHI_COMPUTE_JOB::BindGroup( uint32_t aIndex, RHI_BindGroupHandle aGroup )
189{
190 m_commands.push_back( { .op = OP::BIND_GROUP, .group = aGroup, .index = aIndex } );
191}
192
193
194void RHI_COMPUTE_JOB::PushConstants( const void* aData, size_t aBytes )
195{
196 m_valid = m_valid && aBytes <= RHI_MAX_PUSH_CONSTANT_BYTES && aBytes % 4 == 0 && ( aData || !aBytes );
197 m_commands.push_back( { .op = OP::PUSH_CONSTANTS, .bytes = aBytes, .data = copyBytes( aData, aBytes ) } );
198}
199
200
201void RHI_COMPUTE_JOB::Dispatch( uint32_t aGroupsX, uint32_t aGroupsY )
202{
203 m_commands.push_back( { .op = OP::DISPATCH, .groupsX = aGroupsX, .groupsY = aGroupsY } );
204}
205
206
208{
209 m_commands.push_back( { .op = OP::BARRIER } );
210}
211
212
213void RHI_COMPUTE_JOB::Readback( RHI_BufferHandle aBuffer, size_t aOffset, size_t aBytes, void* aDestination )
214{
215 m_valid = m_valid && ( aDestination || !aBytes );
216 m_commands.push_back( { .op = OP::READBACK,
217 .buffer = aBuffer,
218 .offset = aOffset,
219 .bytes = aBytes,
220 .destination = aDestination } );
221}
Plain owning command data, recordable on any thread without device access.
Definition rhi_compute.h:91
void Dispatch(uint32_t aGroupsX, uint32_t aGroupsY=1)
const std::vector< COMMAND > & Commands() const
void BindGroup(uint32_t aIndex, RHI_BindGroupHandle aGroup)
bool IsValid() const
void Readback(RHI_BufferHandle aBuffer, size_t aOffset, size_t aBytes, void *aDestination)
std::vector< COMMAND > m_commands
void Upload(RHI_BufferHandle aBuffer, const void *aData, size_t aBytes, size_t aOffset=0)
Copy upload bytes immediately.
void Bind(RHI_ComputePipelineHandle aPipeline)
void PushConstants(const void *aData, size_t aBytes)
constexpr int RHI_MAX_BIND_GROUPS
Most bind groups one pipeline can use.
constexpr uint32_t RHI_MAX_PUSH_CONSTANT_BYTES
Largest push constant size SetPushConstants() accepts, in bytes.
Definition rhi_command.h:60
bool RhiValidateComputeJob(const RHI_COMPUTE_JOB &aJob, const RHI_COMPUTE_DEVICE_LIMITS &aLimits, const RHI_COMPUTE_JOB_LOOKUP &aLookup)
Check a whole job against live resources before any of it executes, so a bad job has no partial effec...
static std::vector< uint8_t > copyBytes(const void *aData, size_t aBytes)
bool RhiValidateComputePipelineDesc(const RHI_COMPUTE_PIPELINE_DESC &aDesc)
Validate the portable contract without accessing a GPU or inspecting shader bytecode.
bool RhiValidateComputeBindGroupLayout(const RHI_BIND_GROUP_LAYOUT_DESC &aLayout)
Validate a compute bind group layout.
constexpr uint32_t RHI_SPEC_ID_USER_FIRST
Definition rhi_compute.h:34
RHI_HANDLE< RHI_TAG_BUFFER > RHI_BufferHandle
Definition rhi_handle.h:83
RHI_HANDLE< RHI_TAG_BIND_GROUP > RHI_BindGroupHandle
Definition rhi_handle.h:90
RHI_HANDLE< RHI_TAG_COMPUTE_PIPELINE > RHI_ComputePipelineHandle
Definition rhi_handle.h:87
RHI_BINDING_TYPE type
RHI_SHADER_STAGE stages
uint32_t binding
std::vector< RHI_BINDING_ENTRY > entries
std::array< uint32_t, 3 > maxDispatchGroups
Definition rhi_compute.h:66
Backend command representation; payload bytes are owned by the job.
Backend lookups for RhiValidateComputeJob.
std::function< const RHI_BIND_GROUP_LAYOUT_DESC *(RHI_BindGroupHandle)> groupLayout
std::function< bool(RHI_BufferHandle, size_t aOffset, size_t aBytes)> storageRange
std::function< const RHI_COMPUTE_PIPELINE_DESC *(RHI_ComputePipelineHandle)> pipeline
std::vector< RHI_SPECIALIZATION_CONSTANT > constants
Definition rhi_compute.h:47
std::vector< RHI_BIND_GROUP_LAYOUT_DESC > bindGroupLayouts
Definition rhi_compute.h:46
A 32-bit specialization value represented as raw bits.
Definition rhi_compute.h:38
VECTOR3I expected(15, 30, 45)
int actual