14using namespace bicameral::multires;
32 static_assert(
sizeof(ImGpuCell) == 40 &&
sizeof(ImGpuFace) == 32,
33 "implicit_build.hlsl の CELL_BYTES・FACE_BYTES");
57 constexpr std::array<const char*, PassCount>
PASS_NAMES = {
"Clear",
76 std::string file =
"sim/implicit_build_";
77 for (
size_t i = 0; i < name.size(); ++i) {
78 const char letter = name[i];
79 const bool upper = letter >=
'A' && letter <=
'Z';
83 file += upper ?
static_cast<char>(letter -
'A' +
'a') : letter;
94 void CopyToReadback(ID3D12GraphicsCommandList* list, ID3D12Resource* source, ID3D12Resource* readback,
96 D3D12_RESOURCE_BARRIER barrier =
gpu::Transition(source, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
97 D3D12_RESOURCE_STATE_COPY_SOURCE);
98 list->ResourceBarrier(1, &barrier);
99 list->CopyBufferRegion(readback, 0, source, 0, bytes);
100 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
101 list->ResourceBarrier(1, &barrier);
104 template <
typename T>
105 std::vector<T>
Slice(std::span<const std::byte> bytes, uint64_t offset, uint32_t count) {
106 std::vector<T> values(count);
108 std::memcpy(values.data(), bytes.data() + offset,
size_t{count} *
sizeof(T));
120 return std::unexpected(
"陰解法の系の上限が正しくない");
127 const uint64_t mapWords = uint64_t{capacity.
worldBlocks} * MR_BLOCK_CELLS;
129 const uint64_t entries = uint64_t{MR_FACES} * limits.
unknowns;
130 const uint64_t entryGroups = (entries + SCAN_THREADS - 1) / SCAN_THREADS;
131 const uint64_t cellGroups = (uint64_t{limits.
cells} + SCAN_THREADS - 1) / SCAN_THREADS;
132 const uint64_t workWords = HEADER_WORDS + (2 * mapWords) + capacity.
worldBlocks + 1 + (ENTRY_WORDS * entries) +
133 (uint64_t{CELL_WORDS} * limits.
cells) + 1 + (2 * (entryGroups + 1)) +
134 (cellGroups + 1) + (uint64_t{4} * entries) + (uint64_t{KEY_WORDS} * limits.
cells);
138 for (
const char* name : PASS_NAMES) {
139 const std::string shader = ShaderFile(name);
142 return std::unexpected(bytecode.error());
146 return std::unexpected(std::format(
"系を作る段のパイプラインを作れない({})", shader));
154 return std::unexpected(applyBytecode.error());
158 return std::unexpected(
"解いた変化を足す段のパイプラインを作れない");
168 return std::unexpected(
"系を作る段のバッファを作れない");
170 const D3D12_QUERY_HEAP_DESC queryDesc{
171 .Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP, .Count =
MAX_TIMESTAMPS, .NodeMask = 0};
172 if (FAILED(device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&result.
m_timestamps))))
173 return std::unexpected(
"タイムスタンプのヒープを作れない");
180 const uint64_t mapWords = uint64_t{
m_worldBlocks} * MR_BLOCK_CELLS;
181 const uint64_t entries = uint64_t{MR_FACES} *
m_limits.unknowns;
182 const uint64_t entryGroups = (entries + SCAN_THREADS - 1) / SCAN_THREADS;
183 const uint64_t cellGroups = (uint64_t{
m_limits.cells} + SCAN_THREADS - 1) / SCAN_THREADS;
184 const uint64_t words = HEADER_WORDS + (2 * mapWords) +
m_worldBlocks + 1 + (ENTRY_WORDS * entries) +
185 (uint64_t{CELL_WORDS} *
m_limits.cells) + 1 + (2 * (entryGroups + 1)) +
186 (cellGroups + 1) + (uint64_t{2} * entries);
188 return static_cast<uint32_t
>(words);
196 return uint64_t{
m_limits.cells} *
sizeof(ImGpuCell);
206 FX_ASSERT(!afterAdmit || useFrozenMarks);
207 RecordPasses(list, debugRing, multires, options, useFrozenMarks, afterAdmit ? PassNumberUnknowns : PassClear,
213 RecordPasses(list, debugRing, multires, options,
true, PassClear, PassNumberUnknowns);
218 uint32_t firstPass, uint32_t endPass) {
219 const std::array<uint32_t, 4> external =
ExternalConstants(options, useFrozenMarks);
222 const uint64_t mapWords = uint64_t{
m_worldBlocks} * MR_BLOCK_CELLS;
223 const uint64_t entries = uint64_t{MR_FACES} *
m_limits.unknowns;
224 const auto scanGroups = [](uint64_t count) {
225 return static_cast<uint32_t
>((count + SCAN_THREADS - 1) / SCAN_THREADS);
227 const std::array<uint32_t, PassCount> groups = {Groups(HEADER_WORDS + (2 * mapWords)),
242 Groups(2 * entries)};
244 multires.SetExternalViews(
m_work->GetGPUVirtualAddress(),
m_system->GetGPUVirtualAddress());
245 for (uint32_t pass = firstPass; pass < endPass; ++pass) {
249 multires.RecordExternalDispatch(list, debugRing,
m_pipelines[pass].Get(), groups[pass], external);
255 multires.SetExternalViews(0, 0);
260 bool useFrozenMarks)
const {
261 const auto base =
static_cast<uint16_t
>(
static_cast<int16_t
>(options.
subcycleBaseLevel));
262 const uint32_t packed = uint32_t{base} | (std::min(options.
implicitMaxGap, 255u) << 16) |
263 (useFrozenMarks ? FROZEN_MARKS_BIT : 0u);
270 ID3D12Resource* solvedCells) {
271 multires.SetExternalViews(
m_work->GetGPUVirtualAddress(), solvedCells->GetGPUVirtualAddress());
274 multires.SetExternalViews(0, 0);
278 std::array<D3D12_RESOURCE_BARRIER, 2> barriers = {
280 gpu::Transition(
m_work.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE)};
281 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
283 uint64_t{HEADER_FACES} *
sizeof(uint32_t));
284 for (D3D12_RESOURCE_BARRIER& barrier : barriers)
285 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
287 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
296 return pass < PASS_NAMES.size() ? PASS_NAMES[pass] :
"?";
303 list->EndQuery(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, index);
317 std::array<uint32_t, HEADER_WORDS> header{};
321 return std::unexpected(
"作った系を読み戻せない");
324 system.
unknowns = header[HEADER_UNKNOWNS];
325 system.
boundary = header[HEADER_BOUNDARY];
326 system.
faces = header[HEADER_FACES];
327 system.
overflow = header[HEADER_OVERFLOW] != 0;
ComPtr< ID3D12Resource > m_workReadback
static constexpr uint32_t MAX_TIMESTAMPS
void RecordAdmit(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, GpuMultires &multires, const MultiresStepOptions &options)
ComPtr< ID3D12Resource > m_system
std::vector< uint64_t > ReadTimestamps(uint32_t count) const
uint64_t ListsOffset() const
GpuImplicitBuildLimits m_limits
uint32_t CellKeysWord() const
void RecordReadback(ID3D12GraphicsCommandList *list)
void RecordApply(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, GpuMultires &multires, const MultiresStepOptions &options, ID3D12Resource *solvedCells)
uint32_t m_timestampCount
ComPtr< ID3D12PipelineState > m_applyPipeline
ComPtr< ID3D12QueryHeap > m_timestamps
static std::expected< GpuImplicitBuild, std::string > Create(ID3D12Device5 *device, const GpuMultires &multires, const MultiresCapacity &capacity, const GpuImplicitBuildLimits &limits)
void RecordPasses(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, GpuMultires &multires, const MultiresStepOptions &options, bool useFrozenMarks, uint32_t firstPass, uint32_t endPass)
std::expected< GpuImplicitSystem, std::string > Read() const
static const char * StageName(uint32_t pass)
void RecordTimestamp(ID3D12GraphicsCommandList *list, uint32_t index)
GpuImplicitBuild()=default
ComPtr< ID3D12Resource > m_timestampReadback
uint32_t ListCellsWord() const
void RecordCopyTo(ID3D12GraphicsCommandList *list, GpuImplicit &implicit)
uint64_t FacesOffset() const
std::vector< ComPtr< ID3D12PipelineState > > m_pipelines
ComPtr< ID3D12Resource > m_work
std::array< uint32_t, 4 > ExternalConstants(const MultiresStepOptions &options, bool useFrozenMarks) const
void RecordBuild(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, GpuMultires &multires, const MultiresStepOptions &options, bool useFrozenMarks=false, bool afterAdmit=false)
ComPtr< ID3D12Resource > m_systemReadback
static uint32_t StageCount()
void RecordCopySystem(ID3D12GraphicsCommandList *list, ID3D12Resource *source, uint64_t cellsOffset, uint64_t facesOffset, uint64_t listsOffset, ID3D12Resource *header, uint64_t faceCountOffset)
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)
uint32_t Groups(uint64_t threads)
constexpr uint32_t FROZEN_MARKS_BIT
constexpr uint32_t HEADER_WORDS
constexpr uint32_t SCAN_THREADS
constexpr uint32_t HEADER_UNKNOWNS
constexpr uint32_t HEADER_OVERFLOW
std::string ShaderFile(std::string_view name)
void CopyToReadback(ID3D12GraphicsCommandList *list, ID3D12Resource *source, ID3D12Resource *readback, uint64_t bytes)
constexpr uint32_t ENTRY_WORDS
constexpr std::array< const char *, PassCount > PASS_NAMES
constexpr uint32_t HEADER_FACES
constexpr uint32_t HEADER_BOUNDARY
std::vector< T > Slice(std::span< const std::byte > bytes, uint64_t offset, uint32_t count)
constexpr uint32_t THREADS
constexpr uint32_t KEY_WORDS
constexpr uint32_t CELL_WORDS
std::vector< multires::ImGpuCell > cells
std::vector< uint32_t > lists
std::vector< multires::ImGpuFace > faceList
int32_t subcycleBaseLevel