Simplify {vulkan,dx12,xaudio}_check macro (#1015)

This changes `vulkan_check` and other macros to directly take the call
to be executed. It will execute it and check the result, if it's not
successful, it will log an error with the function name.

It also returns the result code, allowing further processing.
This commit is contained in:
Dennis Brakhane
2025-01-13 17:25:57 +01:00
committed by GitHub
parent 4660a680c4
commit 187c3108b6
7 changed files with 362 additions and 575 deletions
+57 -66
View File
@@ -31,7 +31,9 @@ static constexpr T AlignTo(T value, T alignment)
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'
#define xaudio_check(hr) wilog_assert(SUCCEEDED(hr), "XAudio2 error: %s, line %d, hr = %s", relative_path(__FILE__), __LINE__, wi::helper::GetPlatformErrorString(hr).c_str())
#define xaudio_assert(cond, fname) { wilog_assert(cond, "XAudio2 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr), relative_path(__FILE__), __LINE__); }
#define xaudio_check(call) [&]() { HRESULT hr = call; char buf[256]; xaudio_assert(SUCCEEDED(hr), wi::backlog::internal::extract_function_name(buf, #call)); return hr; }()
namespace wi::audio
{
@@ -87,17 +89,15 @@ namespace wi::audio
wi::Timer timer;
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = xaudio_check(CoInitializeEx(NULL, COINIT_MULTITHREADED));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: CoInitializeEx returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
hr = XAudio2Create(&audioEngine, 0, XAUDIO2_USE_DEFAULT_PROCESSOR);
hr = xaudio_check(XAudio2Create(&audioEngine, 0, XAUDIO2_USE_DEFAULT_PROCESSOR));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: XAudio2Create returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
@@ -108,10 +108,9 @@ namespace wi::audio
audioEngine->SetDebugConfiguration(&debugConfig);
#endif // _DEBUG
hr = audioEngine->CreateMasteringVoice(&masteringVoice);
hr = xaudio_check(audioEngine->CreateMasteringVoice(&masteringVoice));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: CreateMasteringVoice returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
@@ -123,7 +122,7 @@ namespace wi::audio
for (int i = 0; i < SUBMIX_TYPE_COUNT; ++i)
{
hr = audioEngine->CreateSubmixVoice(
hr = xaudio_check(audioEngine->CreateSubmixVoice(
&submixVoices[i],
masteringVoiceDetails.InputChannels,
masteringVoiceDetails.InputSampleRate,
@@ -131,36 +130,33 @@ namespace wi::audio
0,
0,
0
);
));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: CreateSubmixVoice returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
}
DWORD channelMask;
masteringVoice->GetChannelMask(&channelMask);
hr = X3DAudioInitialize(channelMask, X3DAUDIO_SPEED_OF_SOUND, audio3D);
hr = xaudio_check(X3DAudioInitialize(channelMask, X3DAUDIO_SPEED_OF_SOUND, audio3D));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: X3DAudioInitialize returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
// Reverb setup:
{
hr = XAudio2CreateReverb(&reverbEffect);
hr = xaudio_check(XAudio2CreateReverb(&reverbEffect));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: XAudio2CreateReverb returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
XAUDIO2_EFFECT_DESCRIPTOR effects[] = { { reverbEffect.Get(), TRUE, 1 } };
XAUDIO2_EFFECT_CHAIN effectChain = { arraysize(effects), effects };
hr = audioEngine->CreateSubmixVoice(
hr = xaudio_check(audioEngine->CreateSubmixVoice(
&reverbSubmix,
1, // reverb is mono
masteringVoiceDetails.InputSampleRate,
@@ -168,19 +164,17 @@ namespace wi::audio
0,
nullptr,
&effectChain
);
));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: CreateSubmixVoice returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
XAUDIO2FX_REVERB_PARAMETERS native;
ReverbConvertI3DL2ToNative(&reverbPresets[REVERB_PRESET_DEFAULT], &native);
HRESULT hr = reverbSubmix->SetEffectParameters(0, &native, sizeof(native));
HRESULT hr = xaudio_check(reverbSubmix->SetEffectParameters(0, &native, sizeof(native)));
if (!SUCCEEDED(hr))
{
wilog_error("XAudio2: SetEffectParameters returned error: %s", wi::helper::GetPlatformErrorString(hr).c_str());
return;
}
}
@@ -443,18 +437,18 @@ namespace wi::audio
instanceinternal->audio = audio_internal;
instanceinternal->soundinternal = soundinternal;
XAUDIO2_SEND_DESCRIPTOR SFXSend[] = {
XAUDIO2_SEND_DESCRIPTOR SFXSend[] = {
{ XAUDIO2_SEND_USEFILTER, instanceinternal->audio->submixVoices[instance->type] },
{ XAUDIO2_SEND_USEFILTER, instanceinternal->audio->reverbSubmix }, // this should be last to enable/disable reverb simply
};
XAUDIO2_VOICE_SENDS SFXSendList = {
XAUDIO2_VOICE_SENDS SFXSendList = {
(instance->IsEnableReverb() && instanceinternal->audio->reverbSubmix != nullptr) ? (uint32_t)arraysize(SFXSend) : 1,
SFXSend
SFXSend
};
hr = instanceinternal->audio->audioEngine->CreateSourceVoice(&instanceinternal->sourceVoice, &soundinternal->wfx,
0, XAUDIO2_DEFAULT_FREQ_RATIO, instanceinternal.get(), &SFXSendList, NULL);
xaudio_check(hr);
hr = xaudio_check(instanceinternal->audio->audioEngine->CreateSourceVoice(&instanceinternal->sourceVoice, &soundinternal->wfx,
0, XAUDIO2_DEFAULT_FREQ_RATIO, instanceinternal.get(), &SFXSendList, NULL));
if (FAILED(hr))
{
return false;
@@ -494,8 +488,8 @@ namespace wi::audio
instanceinternal->buffer.Flags = XAUDIO2_END_OF_STREAM;
instanceinternal->buffer.LoopCount = instance->IsLooped() ? XAUDIO2_LOOP_INFINITE : 0;
hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer);
xaudio_check(hr);
hr = xaudio_check(instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer));
if (FAILED(hr))
{
return false;
@@ -508,8 +502,8 @@ namespace wi::audio
if (instance != nullptr && instance->IsValid())
{
auto instanceinternal = to_internal(instance);
HRESULT hr = instanceinternal->sourceVoice->Start();
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->Start());
}
}
void Pause(SoundInstance* instance)
@@ -517,8 +511,8 @@ namespace wi::audio
if (instance != nullptr && instance->IsValid())
{
auto instanceinternal = to_internal(instance);
HRESULT hr = instanceinternal->sourceVoice->Stop(); // preserves cursor position
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->Stop()); // preserves cursor position
}
}
void Stop(SoundInstance* instance)
@@ -526,31 +520,31 @@ namespace wi::audio
if (instance != nullptr && instance->IsValid())
{
auto instanceinternal = to_internal(instance);
HRESULT hr = instanceinternal->sourceVoice->Stop(); // preserves cursor position
xaudio_check(hr);
hr = instanceinternal->sourceVoice->FlushSourceBuffers(); // reset submitted audio buffer
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->Stop()); // preserves cursor position
xaudio_check(instanceinternal->sourceVoice->FlushSourceBuffers()); // reset submitted audio buffer
if (!instanceinternal->ended) // if already ended, don't submit end again, it can cause high pitched jerky sound
{
hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&audio_internal->termination_mark); // mark this as terminated, this resets XAUDIO2_VOICE_STATE::SamplesPlayed to zero
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SubmitSourceBuffer(&audio_internal->termination_mark)); // mark this as terminated, this resets XAUDIO2_VOICE_STATE::SamplesPlayed to zero
}
hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer); // resubmit
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer)); // resubmit
}
}
void SetVolume(float volume, SoundInstance* instance)
{
if (instance == nullptr || !instance->IsValid())
{
HRESULT hr = audio_internal->masteringVoice->SetVolume(volume);
xaudio_check(hr);
xaudio_check(audio_internal->masteringVoice->SetVolume(volume));
}
else
{
auto instanceinternal = to_internal(instance);
HRESULT hr = instanceinternal->sourceVoice->SetVolume(volume);
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SetVolume(volume));
}
}
float GetVolume(const SoundInstance* instance)
@@ -574,13 +568,13 @@ namespace wi::audio
auto instanceinternal = to_internal(instance);
if (instanceinternal->buffer.LoopCount == 0)
return;
HRESULT hr = instanceinternal->sourceVoice->ExitLoop();
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->ExitLoop());
if (instanceinternal->ended)
{
instanceinternal->buffer.LoopCount = 0;
hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer);
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer));
}
}
}
@@ -621,8 +615,8 @@ namespace wi::audio
void SetSubmixVolume(SUBMIX_TYPE type, float volume)
{
HRESULT hr = audio_internal->submixVoices[type]->SetVolume(volume);
xaudio_check(hr);
xaudio_check(audio_internal->submixVoices[type]->SetVolume(volume));
}
float GetSubmixVolume(SUBMIX_TYPE type)
{
@@ -674,30 +668,27 @@ namespace wi::audio
X3DAudioCalculate(instanceinternal->audio->audio3D, &listener, &emitter, flags, &settings);
HRESULT hr;
xaudio_check(instanceinternal->sourceVoice->SetFrequencyRatio(settings.DopplerFactor));
hr = instanceinternal->sourceVoice->SetFrequencyRatio(settings.DopplerFactor);
xaudio_check(hr);
hr = instanceinternal->sourceVoice->SetOutputMatrix(
xaudio_check(instanceinternal->sourceVoice->SetOutputMatrix(
instanceinternal->audio->submixVoices[instance->type],
settings.SrcChannelCount,
settings.DstChannelCount,
settings.SrcChannelCount,
settings.DstChannelCount,
settings.pMatrixCoefficients
);
xaudio_check(hr);
));
XAUDIO2_FILTER_PARAMETERS FilterParametersDirect = { LowPassFilter, 2.0f * sinf(X3DAUDIO_PI / 6.0f * settings.LPFDirectCoefficient), 1.0f };
hr = instanceinternal->sourceVoice->SetOutputFilterParameters(instanceinternal->audio->submixVoices[instance->type], &FilterParametersDirect);
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SetOutputFilterParameters(instanceinternal->audio->submixVoices[instance->type], &FilterParametersDirect));
if (instance->IsEnableReverb() && instanceinternal->audio->reverbSubmix != nullptr)
{
hr = instanceinternal->sourceVoice->SetOutputMatrix(instanceinternal->audio->reverbSubmix, settings.SrcChannelCount, 1, &settings.ReverbLevel);
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SetOutputMatrix(instanceinternal->audio->reverbSubmix, settings.SrcChannelCount, 1, &settings.ReverbLevel));
XAUDIO2_FILTER_PARAMETERS FilterParametersReverb = { LowPassFilter, 2.0f * sinf(X3DAUDIO_PI / 6.0f * settings.LPFReverbCoefficient), 1.0f };
hr = instanceinternal->sourceVoice->SetOutputFilterParameters(instanceinternal->audio->reverbSubmix, &FilterParametersReverb);
xaudio_check(hr);
xaudio_check(instanceinternal->sourceVoice->SetOutputFilterParameters(instanceinternal->audio->reverbSubmix, &FilterParametersReverb));
}
}
}
@@ -706,8 +697,8 @@ namespace wi::audio
{
XAUDIO2FX_REVERB_PARAMETERS native;
ReverbConvertI3DL2ToNative(&reverbPresets[preset], &native);
HRESULT hr = audio_internal->reverbSubmix->SetEffectParameters(0, &native, sizeof(native));
xaudio_check(hr);
xaudio_check(audio_internal->reverbSubmix->SetEffectParameters(0, &native, sizeof(native)));
}
}
+10
View File
@@ -23,6 +23,16 @@ using namespace std::chrono_literals;
namespace wi::backlog
{
namespace internal {
char* extract_function_name(char* dst, const char* src)
{
int i = 0;
while (src[i] != '(') i++;
memcpy(dst, src, i);
dst[i] = 0;
return dst;
}
}
bool enabled = false;
bool was_ever_enabled = enabled;
struct LogEntry
+5
View File
@@ -17,6 +17,11 @@
namespace wi::backlog
{
namespace internal {
// Used by various *_check macros
char* extract_function_name(char* dst, const char* src);
}
// Do not modify the order, as this is exposed to LUA scripts as int!
enum class LogLevel
{
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -33,7 +33,9 @@
#include <atomic>
#include <mutex>
#define dx12_check(hr) wilog_assert(SUCCEEDED(hr), "DX12 error: %s, line %d, hr = %s", relative_path(__FILE__), __LINE__, wi::helper::GetPlatformErrorString(hr).c_str())
#define dx12_assert(cond, fname) { wilog_assert(cond, "DX 12 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr), relative_path(__FILE__), __LINE__); }
#define dx12_check(call) [&]() { HRESULT hr = call; char buf[256]; dx12_assert(SUCCEEDED(hr), wi::backlog::internal::extract_function_name(buf, #call)); return hr; }()
namespace wi::graphics
{
@@ -141,8 +143,7 @@ namespace wi::graphics
if (semaphore_pool.empty())
{
Semaphore& dependency = semaphore_pool.emplace_back();
HRESULT hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, PPV_ARGS(dependency.fence));
dx12_check(hr);
dx12_check(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, PPV_ARGS(dependency.fence)));
}
Semaphore semaphore = std::move(semaphore_pool.back());
semaphore_pool.pop_back();
@@ -456,8 +457,7 @@ namespace wi::graphics
{
// Descriptor heaps' progress is recorded by the GPU:
fenceValue = allocationOffset.load();
HRESULT hr = queue->Signal(fence.Get(), fenceValue);
dx12_check(hr);
dx12_check(queue->Signal(fence.Get(), fenceValue));
cached_completedValue = fence->GetCompletedValue();
}
};
@@ -492,8 +492,7 @@ namespace wi::graphics
void block_allocate()
{
heaps.emplace_back();
HRESULT hr = device->device->CreateDescriptorHeap(&desc, PPV_ARGS(heaps.back()));
dx12_check(hr);
dx12_check(device->device->CreateDescriptorHeap(&desc, PPV_ARGS(heaps.back())));
D3D12_CPU_DESCRIPTOR_HANDLE heap_start = heaps.back()->GetCPUDescriptorHandleForHeapStart();
for (UINT i = 0; i < desc.NumDescriptors; ++i)
{
File diff suppressed because it is too large Load Diff
+11 -9
View File
@@ -28,7 +28,13 @@
#include <mutex>
#include <algorithm>
#define vulkan_check(res) wilog_assert(res == VK_SUCCESS, "Vulkan error: %s, line %d, result = %s", relative_path(__FILE__), __LINE__, string_VkResult(res))
#define vulkan_assert(cond, fname) { wilog_assert(cond, "Vulkan error: %s failed with %s (%s:%d)", fname, string_VkResult(res), relative_path(__FILE__), __LINE__); }
#define vulkan_check_cond(cond, call) [&]() { VkResult res = call; char buf[256]; vulkan_assert(cond, wi::backlog::internal::extract_function_name(buf, #call)); return res; }()
#define vulkan_check(call) vulkan_check_cond(res == VK_SUCCESS, call)
#define vulkan_check_lenient(call) vulkan_check_cond(res >= VK_SUCCESS, call)
namespace wi::graphics
{
@@ -210,8 +216,7 @@ namespace wi::graphics
VkSemaphore& sema = semaphore_pool.emplace_back();
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkResult res = vkCreateSemaphore(device, &info, nullptr, &sema);
vulkan_check(res);
vulkan_check(vkCreateSemaphore(device, &info, nullptr, &sema));
}
VkSemaphore semaphore = semaphore_pool.back();
semaphore_pool.pop_back();
@@ -505,8 +510,7 @@ namespace wi::graphics
poolInfo.maxSets = 1;
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
VkResult res = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool);
vulkan_check(res);
vulkan_check(vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool));
#if 0
VkDebugUtilsObjectNameInfoEXT info{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
@@ -541,16 +545,14 @@ namespace wi::graphics
bindingFlagsInfo.pBindingFlags = &bindingFlags;
layoutInfo.pNext = &bindingFlagsInfo;
res = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &descriptorSetLayout);
vulkan_check(res);
vulkan_check(vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &descriptorSetLayout));
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &descriptorSetLayout;
res = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet);
vulkan_check(res);
vulkan_check(vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet));
for (int i = 0; i < (int)descriptorCount; ++i)
{