16 uint32_t
kind = DEBUG_ARG_U32;
23struct std::formatter<
bicameral::gpu::DebugArgument, char> {
27 constexpr std::format_parse_context::iterator
parse(std::format_parse_context& context) {
28 const auto end = std::find(context.begin(), context.end(),
'}');
29 spec = std::string_view(context.begin(), end);
36 std::format_context& context)
const {
38 const std::string pattern = std::format(
"{{:{}}}",
spec);
39 switch (argument.
kind) {
41 auto value =
static_cast<uint32_t
>(argument.
bits);
42 return std::vformat_to(context.out(), pattern, std::make_format_args(value));
45 auto value =
static_cast<int32_t
>(
static_cast<uint32_t
>(argument.
bits));
46 return std::vformat_to(context.out(), pattern, std::make_format_args(value));
49 auto value = argument.
bits;
50 return std::vformat_to(context.out(), pattern, std::make_format_args(value));
53 auto value =
static_cast<int64_t
>(argument.
bits);
54 return std::vformat_to(context.out(), pattern, std::make_format_args(value));
72#define DEBUG_FORMAT(name, channel, where, text) {Channel::channel, where, text},
73#include "common/debug_formats.hlsli"
78 static_assert(std::size(DEBUG_FORMATS) ==
static_cast<size_t>(DebugFormat::Count),
79 "debug_formats.hlsli と DebugFormat の数が合わない");
86 for (uint32_t index = 0; index < argCount; ++index)
87 text += std::format(
"{}{}", index == 0 ?
"" :
", ", arguments[index]);
89 return "[" + text +
"]";
95 case 0:
return std::vformat(pattern, std::make_format_args());
96 case 1:
return std::vformat(pattern, std::make_format_args(a[0]));
97 case 2:
return std::vformat(pattern, std::make_format_args(a[0], a[1]));
98 case 3:
return std::vformat(pattern, std::make_format_args(a[0], a[1], a[2]));
99 case 4:
return std::vformat(pattern, std::make_format_args(a[0], a[1], a[2], a[3]));
100 case 5:
return std::vformat(pattern, std::make_format_args(a[0], a[1], a[2], a[3], a[4]));
101 default:
return std::vformat(pattern, std::make_format_args(a[0], a[1], a[2], a[3], a[4], a[5]));
108 }
catch (
const std::format_error& error) {
109 return std::format(
"(書式 \"{}\" に当てはまらない: {}) {}", pattern, error.what(),
122 const size_t notLogged = contents.
messages.size() - loggedCount;
125 "GPU のデバッグ出力: ほか {} 件はログに出していない(全 {} 件、assert {} 件)", notLogged,
141 const uint32_t formatIndex = record[0];
142 const uint32_t argCount = std::min((record[1] >> 4) & 0xFu, DEBUG_RECORD_MAX_ARGS);
143 const uint32_t argKinds = record[1] >> 8;
144 message.
isAssert = (record[1] & 0xFu) == DEBUG_KIND_ASSERT;
145 message.
line = record[2];
147 DebugArguments arguments{};
148 for (uint32_t index = 0; index < argCount; ++index) {
149 const uint32_t word = DEBUG_RECORD_ARG_WORD + index * 2;
150 arguments[index] = {.bits = record[word] | (uint64_t{record[word + 1]} << 32),
151 .kind = (argKinds >> (index * 2)) & 0x3u};
154 if (formatIndex >= std::size(DEBUG_FORMATS)) {
156 message.
text = std::format(
"(知らない書式の番号 {}) {}", formatIndex, RawArguments(arguments, argCount));
161 const DebugFormatEntry& entry = DEBUG_FORMATS[formatIndex];
162 message.
format =
static_cast<DebugFormat
>(formatIndex);
163 message.
channel = entry.channel;
164 message.
where = entry.where;
165 message.
text = FormatArguments(entry.text, arguments, argCount);
172 std::expected<DebugRing, std::string>
DebugRing::Create(ID3D12Device* device, uint32_t slotCount) {
173 auto ring =
ReadbackRing::Create(device, DEBUG_RING_BYTES, DEBUG_RING_HEADER_BYTES, slotCount, L
"DebugRing");
175 return std::unexpected(
"デバッグのリングを作れない: " + ring.error());
185 m_ring.RecordReadbackAndReset(list, slot);
191 uint32_t requested = 0;
192 if (!
m_ring.Read(slot, std::as_writable_bytes(std::span(&requested, 1))))
196 const uint32_t storedCount = std::min(contents.
requestedCount, DEBUG_RING_CAPACITY);
197 std::vector<uint32_t> words((DEBUG_RING_HEADER_BYTES + storedCount * DEBUG_RECORD_BYTES) / 4);
198 if (storedCount > 0 && !
m_ring.Read(slot, std::as_writable_bytes(std::span(words))))
202 contents.
messages.reserve(storedCount);
203 const std::span<const uint32_t> records = std::span(words).subspan(DEBUG_RING_HEADER_BYTES / 4);
205 for (uint32_t index = 0; index < storedCount; ++index) {
206 const auto record = records.subspan(
size_t{index} * DEBUG_RECORD_WORDS).first<DEBUG_RECORD_WORDS>();
211 contents.
messages.push_back(std::move(message));
215 uint32_t loggedCount = 0;
216 for (
const bool assertPass : {
true,
false}) {
218 if (message.
isAssert != assertPass || loggedCount >= maxLoggedMessages)
226 LogSummary(contents, loggedCount);
DebugRing(ReadbackRing &&ring)
void RecordReadbackAndReset(ID3D12GraphicsCommandList *list, uint32_t slot=0) const
DebugRingContents Drain(uint32_t maxLoggedMessages=DEFAULT_MAX_LOGGED_MESSAGES, uint32_t slot=0) const
static std::expected< DebugRing, std::string > Create(ID3D12Device *device, uint32_t slotCount=1)
void RecordBegin(ID3D12GraphicsCommandList *list) const
static std::expected< ReadbackRing, std::string > Create(ID3D12Device *device, uint64_t bytes, uint64_t headerBytes, uint32_t slotCount, std::wstring_view name)
constexpr DebugFormatEntry DEBUG_FORMATS[]
std::string RawArguments(const DebugArguments &arguments, uint32_t argCount)
std::string VFormatArguments(std::string_view pattern, const DebugArguments &a, uint32_t argCount)
void LogMessage(const DebugMessage &message)
std::string FormatArguments(std::string_view pattern, const DebugArguments &arguments, uint32_t argCount)
std::array< DebugArgument, DEBUG_RECORD_MAX_ARGS > DebugArguments
void LogSummary(const DebugRingContents &contents, uint32_t loggedCount)
DebugMessage DecodeDebugRecord(std::span< const uint32_t, DEBUG_RECORD_WORDS > record)
void Log(Channel channel, Level level, FormatWithLocation< std::type_identity_t< Args >... > pattern, Args &&... args)
std::vector< DebugMessage > messages