Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
debug_ring.h
Go to the documentation of this file.
1// debug_ring.h — シェーダーの printf / assert のリング(shaders/common/debug_ring.hlsli)を CPU 側で持つ(T-0003、16 §1)。
2//
3// データの流れ: シェーダーが DEBUG_PRINT / DEBUG_ASSERT でリングに書く → RecordReadbackAndReset() が読み戻しのバッファへ写して
4// リングを空にする → GPU が終わった後に Drain() が書式(shaders/common/debug_formats.hlsli)に当てはめてログ(ADR-0006)へ出す。
5//
6// 1 本のコマンドリストの中での使い方:
7// ring.RecordBegin(list); // リングを UAV にする
8// list->SetComputeRootUnorderedAccessView(layout.DebugRingIndex(), ring.GpuAddress());
9// ... Dispatch / DispatchGraph ...
10// ring.RecordReadbackAndReset(list); // 読み戻して空にする(リストの終わりで COMMON に戻る)
11// queue.ExecuteAndWait(); const auto contents = ring.Drain();
12// 読み戻しのバッファは slot ごと(Create の slotCount 個。gpu/readback_ring.h)。フレームを重ねるときは
13// slot = フレーム(バッチ)の番号 % slotCount にして、その slot のリストが終わってから Drain(max, slot) する(T-0004)。
14#pragma once
15
16#include <cstdint>
17#include <expected>
18#include <span>
19#include <string>
20#include <string_view>
21#include <vector>
22
23#include "common/debug_ring.hlsli"
24#include "core/log.h"
25#include "gpu/readback_ring.h"
26
27namespace bicameral::gpu {
28
29 // 読み戻した 1 レコード
30 struct DebugMessage {
31 DebugFormat format = DebugFormat::Count; // 知らない番号なら Count
32 bool isAssert = false;
33 uint32_t line = 0; // シェーダーのソースの行(__LINE__)
34
35 // --- 書式の一覧から ---
36 Channel channel = Channel::Gpu; // 書式の一覧のチャンネル
37 std::string_view where; // 書式の一覧の「場所」(ファイル名かノード名)
38 std::string text; // 書式に引数を当てはめたもの
39 };
40
41 // 1 レコード(16 語)を読む。知らない書式の番号や、書式と引数が合わないときも、生の値を並べた文字列にする
42 [[nodiscard]] DebugMessage DecodeDebugRecord(std::span<const uint32_t, DEBUG_RECORD_WORDS> record);
43
45 uint32_t requestedCount = 0; // シェーダーが書こうとした数
46 uint32_t droppedCount = 0; // 容量(DEBUG_RING_CAPACITY)を超えて書けなかった数
47 uint32_t assertCount = 0; // 読めたレコードの中の assert の数
48 std::vector<DebugMessage> messages; // 並びは atomic で空きを取った順(毎回同じとは限らない)
49 };
50
51 class DebugRing {
52 public:
53 // 1 回の Drain() でログに出す行の数の既定。残りは件数だけ出す(リングは毎フレーム数千件になりうる)
54 static constexpr uint32_t DEFAULT_MAX_LOGGED_MESSAGES = 32;
55
56 [[nodiscard]] static std::expected<DebugRing, std::string> Create(ID3D12Device* device, uint32_t slotCount = 1);
57
58 // ルートの UAV(u0 space1)に渡すアドレス
59 [[nodiscard]] D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const { return m_ring.GpuAddress(); }
60
61 // シェーダーが書く前に: COMMON → UNORDERED_ACCESS
62 void RecordBegin(ID3D12GraphicsCommandList* list) const;
63
64 // シェーダーが書いた後に: 読み戻しのバッファへ写し、見出し(書こうとした数)を 0 に戻す。最後は COMMON に戻す
65 void RecordReadbackAndReset(ID3D12GraphicsCommandList* list, uint32_t slot = 0) const;
66
67 // GPU が RecordReadbackAndReset() まで終えた後に呼ぶ。読んだものをログに出し(最大 maxLoggedMessages 行)、返す
68 DebugRingContents Drain(uint32_t maxLoggedMessages = DEFAULT_MAX_LOGGED_MESSAGES, uint32_t slot = 0) const;
69
70 private:
71 explicit DebugRing(ReadbackRing&& ring) : m_ring(std::move(ring)) {}
72
74 };
75
76} // namespace bicameral::gpu
DebugRing(ReadbackRing &&ring)
Definition debug_ring.h:71
void RecordReadbackAndReset(ID3D12GraphicsCommandList *list, uint32_t slot=0) const
D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const
Definition debug_ring.h:59
DebugRingContents Drain(uint32_t maxLoggedMessages=DEFAULT_MAX_LOGGED_MESSAGES, uint32_t slot=0) const
static constexpr uint32_t DEFAULT_MAX_LOGGED_MESSAGES
Definition debug_ring.h:54
static std::expected< DebugRing, std::string > Create(ID3D12Device *device, uint32_t slotCount=1)
void RecordBegin(ID3D12GraphicsCommandList *list) const
DebugMessage DecodeDebugRecord(std::span< const uint32_t, DEBUG_RECORD_WORDS > record)
Channel
Definition log.h:38
std::vector< DebugMessage > messages
Definition debug_ring.h:48