13 using namespace bicameral::physics;
21 .uavCount = 14, .rootConstantCount =
ROOT_CONSTANT_COUNT, .debugRing =
true, .srvCount = 2};
27 "sim/physics_initialize.cso",
"sim/physics_begin_substep.cso",
"sim/physics_broadphase.cso",
28 "sim/physics_narrowphase.cso",
"sim/physics_prepare_manifolds.cso",
"sim/physics_color_round.cso",
29 "sim/physics_finish_coloring.cso",
"sim/physics_recollide.cso",
"sim/physics_solve_color.cso",
30 "sim/physics_update_duals.cso",
"sim/physics_update_velocity.cso",
"sim/physics_finish.cso",
31 "sim/physics_build_manifolds.cso"};
35 "Initialize",
"BeginSubstep",
"Broadphase",
"Narrowphase",
"PrepareManifolds",
36 "ColorRound",
"FinishColoring",
"Recollide",
"SolveColor",
"UpdateDuals",
37 "UpdateVelocity",
"Finish",
"BuildManifolds",
"BroadphaseGraph",
"SolveColorGraph"};
42 static_assert(
sizeof(D3D12_NODE_GPU_INPUT) == 24);
56 const auto bytes = std::as_bytes(data);
58 void* mapped =
nullptr;
59 const D3D12_RANGE noRead{.Begin = 0, .End = 0};
60 if (!buffer || FAILED(buffer->Map(0, &noRead, &mapped)))
63 std::memcpy(mapped, bytes.data(), bytes.size());
64 buffer->Unmap(0,
nullptr);
76 const PxParameters& parameters,
85 return std::unexpected(std::format(
"slotsPerBody は {} まで", PX_GPU_MAX_SLOTS_PER_BODY));
88 return std::unexpected(created.error());
90 if (
auto created = result.
CreateBuffers(device, scene); !created)
91 return std::unexpected(created.error());
100 return std::unexpected(
"物理のルート署名を作れない");
102 for (
size_t pass = 0; pass < SHADER_NAMES.size(); ++pass) {
105 return std::unexpected(bytecode.error());
109 return std::unexpected(std::format(
"パイプラインを作れない: {}", SHADER_NAMES[pass]));
113 if ((
m_bodyCount + BROADPHASE_THREADS - 1) / BROADPHASE_THREADS > BROADPHASE_MAX_GROUPS)
114 return std::unexpected(
"物が多すぎる(広域の選別の Work Graph の NodeMaxDispatchGrid)");
118 return std::unexpected(library.error());
122 return std::unexpected(graph.error());
124 m_graph = std::make_unique<gpu::WorkGraph>(std::move(*graph));
128 return std::unexpected(
"physics_graph.cso に BroadphaseNode か SolveBodyNode が無い");
137 const uint64_t slots = n *
m_options.slotsPerBody;
138 const std::array<uint64_t, 14> uavBytes = {
140 2 * slots * MANIFOLD_HEADER_BYTES,
141 2 * n *
sizeof(uint32_t),
142 slots *
sizeof(uint32_t),
143 n *
m_options.incidentPerBody *
sizeof(uint32_t),
144 n *
sizeof(uint32_t),
145 n *
sizeof(uint64_t),
146 2 * n *
sizeof(int32_t),
149 slots *
sizeof(PxContactGeometry),
150 COLOR_COUNT *
sizeof(D3D12_NODE_GPU_INPUT),
151 COLOR_COUNT * n *
sizeof(uint32_t),
152 COLOR_COUNT *
sizeof(uint64_t)};
153 for (
size_t i = 0; i < uavBytes.size(); ++i) {
156 return std::unexpected(
"物理のバッファを作れない");
159 std::vector<PhysicsBody> initialBodies;
160 initialBodies.reserve(scene.
bodies.size());
165 const std::array<PxParameters, 1> parameterArray = {
m_parameters};
166 m_srvs = {CreateUploadBuffer(device, std::span<const PxParameters>(parameterArray)),
167 CreateUploadBuffer(device, std::span<const PhysicsBody>(initialBodies))};
171 return std::unexpected(
"物理のアップロード・読み戻しのバッファを作れない");
179 .incidentPerBody =
m_options.incidentPerBody,
181 .tickLow = (uint32_t)
m_tick,
182 .tickHigh = (uint32_t)(
m_tick >> 32),
185 .colorBodiesLow = (uint32_t)
m_uavs[12]->GetGPUVirtualAddress(),
186 .colorBodiesHigh = (uint32_t)(
m_uavs[12]->GetGPUVirtualAddress() >> 32)};
191 const Constants& constants, uint32_t threadCount) {
194 list->SetPipelineState(
m_pipelines[(
size_t)pass].Get());
196 BindRoot(list, debugRing, constants);
197 list->Dispatch(GroupsFor(threadCount), 1, 1);
199 list->ResourceBarrier(1, &barrier);
208 BindRoot(list, debugRing, constants);
210 const uint32_t groupCount = (
m_bodyCount + BROADPHASE_THREADS - 1) / BROADPHASE_THREADS;
213 list->ResourceBarrier(1, &barrier);
219 const Constants& constants, int32_t color) {
222 BindRoot(list, debugRing, constants);
224 const D3D12_GPU_VIRTUAL_ADDRESS input =
m_uavs[11]->GetGPUVirtualAddress() +
225 (uint64_t)color *
sizeof(D3D12_NODE_GPU_INPUT);
228 list->ResourceBarrier(1, &barrier);
235 const D3D12_RESOURCE_STATES uav = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
236 const D3D12_RESOURCE_STATES input = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
237 const D3D12_RESOURCE_STATES before = toGraphInput ? uav : input;
238 const D3D12_RESOURCE_STATES after = toGraphInput ? input : uav;
239 const std::array<D3D12_RESOURCE_BARRIER, 2> barriers = {
gpu::Transition(
m_uavs[11].Get(), before, after),
241 list->ResourceBarrier((uint32_t)barriers.size(), barriers.data());
259 static_assert(
sizeof(
Constants) == ROOT_CONSTANT_COUNT *
sizeof(uint32_t));
260 static_assert(std::tuple_size_v<
decltype(
m_uavs)> == ROOT_LAYOUT.
uavCount);
261 for (uint32_t i = 0; i <
m_uavs.size(); ++i)
262 list->SetComputeRootUnorderedAccessView(i,
m_uavs[i]->GetGPUVirtualAddress());
264 list->SetComputeRoot32BitConstants(ROOT_LAYOUT.
RootConstantIndex(), ROOT_CONSTANT_COUNT, &constants, 0);
265 list->SetComputeRootUnorderedAccessView(ROOT_LAYOUT.
DebugRingIndex(), debugRing);
266 for (uint32_t i = 0; i <
m_srvs.size(); ++i)
267 list->SetComputeRootShaderResourceView(ROOT_LAYOUT.
SrvIndex(i),
m_srvs[i]->GetGPUVirtualAddress());
273 const D3D12_QUERY_HEAP_DESC queryDesc{
274 .Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP, .Count = MAX_TIMESTAMPS + 1, .NodeMask = 0};
275 if (FAILED(device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&
m_timestamps))))
287 list->EndQuery(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 0);
318 static_assert(PASS_NAMES.size() == (
size_t)
Pass::Count);
319 static_assert(SHADER_NAMES.size() + 2 ==
322 std::vector<GpuPhysicsPassTime> result;
323 for (
size_t pass = 0; pass < PASS_NAMES.size(); ++pass) {
340 for (uint32_t substep = 0; substep <
m_parameters.substeps; ++substep)
380 for (uint32_t colorRound = 0; colorRound <
m_options.colorRounds; ++colorRound) {
381 constants.
colorIn = colorRound % 2;
398 for (uint32_t iteration = 0; iteration <= iterations; ++iteration) {
402 constants.
alphaQ16 = iteration < iterations ? (uint32_t)PX_ALPHA_ONE_Q16 : 0;
405 if (iteration < iterations)
408 if (iteration + 1 == iterations)
421 for (int32_t color = 0; color < PX_GPU_MAX_COLORS; ++color) {
422 constants.
color = color;
423 if (colorPredicates) {
424 list->SetPredication(
m_uavs[COLOR_PREDICATE_UAV].Get(), (uint64_t)color *
sizeof(uint64_t),
425 D3D12_PREDICATION_OP_EQUAL_ZERO);
436 list->SetPredication(
nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
442 const D3D12_RESOURCE_STATES unordered = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
443 const D3D12_RESOURCE_STATES predication = D3D12_RESOURCE_STATE_PREDICATION;
445 toPredication ? unordered : predication,
446 toPredication ? predication : unordered);
447 list->ResourceBarrier(1, &barrier);
454 list->ResolveQueryData(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 0,
476 uint64_t hash = fx::FxMix64(tick);
478 hash = PxHashBody(hash, body);
static std::expected< WorkGraph, std::string > Create(ID3D12Device5 *device, ID3D12RootSignature *globalRootSignature, std::span< const std::byte > library, std::wstring_view programName)
static void DispatchFromCpu(ID3D12GraphicsCommandList10 *list, uint32_t entrypointIndex, const void *records, uint32_t recordCount, uint64_t recordStrideBytes)
static void DispatchFromGpu(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS nodeGpuInput)
std::unique_ptr< gpu::WorkGraph > m_graph
bool SkipsEmptyColors() const
bool EnableProfiling(ID3D12Device *device)
ComPtr< ID3D12Resource > m_bodiesReadback
void RecordIterations(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, Constants constants)
std::array< ComPtr< ID3D12Resource >, 2 > m_srvs
std::array< uint64_t,(size_t) Pass::Count > m_profileCounts
static std::expected< GpuPhysics, std::string > Create(ID3D12Device5 *device, const PhysicsScene &scene, const physics::PxParameters ¶meters, const GpuPhysicsOptions &options={})
void RecordSolveColorGraph(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const Constants &constants, int32_t color)
std::expected< void, std::string > CreatePipelines(ID3D12Device5 *device)
uint32_t m_broadphaseEntry
std::expected< void, std::string > CreateBuffers(ID3D12Device5 *device, const PhysicsScene &scene)
void RecordInitialize(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
std::array< ComPtr< ID3D12Resource >, 14 > m_uavs
std::array< uint64_t,(size_t) Pass::Count > m_profileTicks
ComPtr< ID3D12RootSignature > m_rootSignature
void RecordColorPredicateStates(ID3D12GraphicsCommandList10 *list, bool toPredication) const
void RecordBroadphaseGraph(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const Constants &constants)
physics::PxParameters m_parameters
void RecordReadback(ID3D12GraphicsCommandList10 *list) const
GpuPhysicsStats ReadStats() const
void RecordColoring(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, Constants constants)
void RecordTimestamp(ID3D12GraphicsCommandList10 *list, Pass pass)
std::vector< GpuPhysicsPassTime > ProfileResult() const
ComPtr< ID3D12QueryHeap > m_timestamps
void RecordPass(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, Pass pass, const Constants &constants, uint32_t threadCount)
void RecordSubstep(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t substep)
void RecordStep(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
static uint64_t StateHash(uint64_t tick, const std::vector< PhysicsBody > &bodies)
std::vector< Pass > m_profiledPasses
void BindRoot(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const Constants &constants) const
void RecordColorListStates(ID3D12GraphicsCommandList10 *list, bool toGraphInput) const
ComPtr< ID3D12Resource > m_statsReadback
Constants BaseConstants() const
void SetGraphProgram(ID3D12GraphicsCommandList10 *list)
GpuPhysicsOptions m_options
ComPtr< ID3D12Resource > m_timestampReadback
std::vector< PhysicsBody > ReadBodies() const
std::array< ComPtr< ID3D12PipelineState >,(size_t) Pass::Count > m_pipelines
void RecordProfileStart(ID3D12GraphicsCommandList10 *list) const
void RecordSolveColors(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, Constants constants)
ComPtr< ID3D12RootSignature > CreateRootSignature(ID3D12Device *device, const RootSignatureLayout &layout)
std::expected< std::vector< std::byte >, std::string > LoadShader(std::string_view relativePath)
bool ReadBuffer(ID3D12Resource *readback, std::span< std::byte > destination)
ComPtr< ID3D12PipelineState > CreateComputePipeline(ID3D12Device *device, ID3D12RootSignature *rootSignature, std::span< const std::byte > bytecode)
D3D12_RESOURCE_BARRIER Transition(ID3D12Resource *resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
ComPtr< ID3D12Resource > CreateBuffer(ID3D12Device *device, uint64_t sizeBytes, BufferKind kind)
void RecordCopyToReadback(ID3D12GraphicsCommandList *list, ID3D12Resource *source, ID3D12Resource *readback)
D3D12_RESOURCE_BARRIER UavBarrier(ID3D12Resource *resource)
constexpr uint32_t COLOR_PREDICATE_UAV
constexpr uint32_t MAX_TIMESTAMPS
constexpr std::array< const char *, 13 > SHADER_NAMES
constexpr uint32_t BROADPHASE_THREADS
constexpr uint32_t STATS_BYTES
constexpr uint64_t MANIFOLD_HEADER_BYTES
constexpr uint32_t BROADPHASE_MAX_GROUPS
constexpr uint32_t ROOT_CONSTANT_COUNT
constexpr auto COLOR_COUNT
constexpr std::array< const char *, 15 > PASS_NAMES
constexpr gpu::RootSignatureLayout ROOT_LAYOUT
uint32_t GroupsFor(uint32_t threadCount)
constexpr uint32_t THREADS_PER_GROUP
ComPtr< ID3D12Resource > CreateUploadBuffer(ID3D12Device *device, std::span< const T > data)
physics::PxContactPoint PhysicsContactPoint
PhysicsBody MakePhysicsBody(const PhysicsSceneBody &source, int64_t rate)
physics::PxBody PhysicsBody
uint32_t DebugRingIndex() const
uint32_t SrvIndex(uint32_t shaderRegister) const
uint32_t RootConstantIndex() const
std::vector< PhysicsSceneBody > bodies