ROADMAP.md

This commit is contained in:
2026-01-09 19:12:38 +00:00
parent 72c84ac64b
commit 97fe7b3f2b
9 changed files with 150 additions and 58 deletions

View File

@@ -33,6 +33,10 @@ std::string ToLower(std::string value) {
return value;
}
uint16_t ClampViewExtent(uint32_t value) {
return static_cast<uint16_t>(std::min<uint32_t>(value, std::numeric_limits<uint16_t>::max()));
}
glm::mat4 ToMat4(const std::array<float, 16>& value) {
return glm::make_mat4(value.data());
}
@@ -240,17 +244,9 @@ std::vector<bgfx::RendererType::Enum> BuildPreferredRenderers(
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGL);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::Vulkan);
} else {
const bool waylandOrX11 = (videoLower == "wayland") || (videoLower == "x11");
const bool kmsdrm = (videoLower == "kmsdrm");
if (waylandOrX11 || kmsdrm) {
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::Vulkan);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGL);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGLES);
} else {
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::Vulkan);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGL);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGLES);
}
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::Vulkan);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGL);
AddRendererIfSupported(preferred, supportedRenderers, bgfx::RendererType::OpenGLES);
}
return preferred;
@@ -694,6 +690,7 @@ GraphicsDeviceHandle BgfxGraphicsBackend::CreateDevice() {
}
void BgfxGraphicsBackend::DestroyDevice(GraphicsDeviceHandle device) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "DestroyDevice");
}
@@ -794,8 +791,10 @@ bgfx::TextureHandle BgfxGraphicsBackend::LoadTextureFromFile(const std::string&
// Validate texture dimensions against GPU capabilities
const bgfx::Caps* caps = bgfx::getCaps();
if (caps) {
const uint16_t maxTextureSize = caps->limits.maxTextureSize;
if (width > maxTextureSize || height > maxTextureSize) {
const uint32_t maxTextureSize = caps->limits.maxTextureSize;
const uint32_t widthU = static_cast<uint32_t>(width);
const uint32_t heightU = static_cast<uint32_t>(height);
if (widthU > maxTextureSize || heightU > maxTextureSize) {
if (logger_) {
logger_->Error("BgfxGraphicsBackend::LoadTextureFromFile: texture " + path +
" size (" + std::to_string(width) + "x" + std::to_string(height) +
@@ -936,6 +935,7 @@ void BgfxGraphicsBackend::ApplyMaterialXUniforms(const std::array<float, 16>& mo
GraphicsPipelineHandle BgfxGraphicsBackend::CreatePipeline(GraphicsDeviceHandle device,
const std::string& shaderKey,
const ShaderPaths& shaderPaths) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "CreatePipeline", "shaderKey=" + shaderKey);
}
@@ -1061,6 +1061,7 @@ GraphicsPipelineHandle BgfxGraphicsBackend::CreatePipeline(GraphicsDeviceHandle
}
void BgfxGraphicsBackend::DestroyPipeline(GraphicsDeviceHandle device, GraphicsPipelineHandle pipeline) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "DestroyPipeline");
}
@@ -1088,6 +1089,7 @@ void BgfxGraphicsBackend::DestroyPipeline(GraphicsDeviceHandle device, GraphicsP
GraphicsBufferHandle BgfxGraphicsBackend::CreateVertexBuffer(GraphicsDeviceHandle device,
const std::vector<uint8_t>& data) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "CreateVertexBuffer",
"data.size=" + std::to_string(data.size()));
@@ -1109,6 +1111,7 @@ GraphicsBufferHandle BgfxGraphicsBackend::CreateVertexBuffer(GraphicsDeviceHandl
GraphicsBufferHandle BgfxGraphicsBackend::CreateIndexBuffer(GraphicsDeviceHandle device,
const std::vector<uint8_t>& data) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "CreateIndexBuffer",
"data.size=" + std::to_string(data.size()));
@@ -1129,6 +1132,7 @@ GraphicsBufferHandle BgfxGraphicsBackend::CreateIndexBuffer(GraphicsDeviceHandle
}
void BgfxGraphicsBackend::DestroyBuffer(GraphicsDeviceHandle device, GraphicsBufferHandle buffer) {
(void)device;
if (logger_) {
logger_->Trace("BgfxGraphicsBackend", "DestroyBuffer");
}
@@ -1150,15 +1154,19 @@ void BgfxGraphicsBackend::DestroyBuffer(GraphicsDeviceHandle device, GraphicsBuf
}
bool BgfxGraphicsBackend::BeginFrame(GraphicsDeviceHandle device) {
(void)device;
if (!initialized_) {
return false;
}
bgfx::setViewRect(viewId_, 0, 0, viewportWidth_, viewportHeight_);
const uint16_t viewWidth = ClampViewExtent(viewportWidth_);
const uint16_t viewHeight = ClampViewExtent(viewportHeight_);
bgfx::setViewRect(viewId_, 0, 0, viewWidth, viewHeight);
bgfx::touch(viewId_);
return true;
}
bool BgfxGraphicsBackend::EndFrame(GraphicsDeviceHandle device) {
(void)device;
if (!initialized_) {
return false;
}
@@ -1189,7 +1197,9 @@ void BgfxGraphicsBackend::ConfigureView(GraphicsDeviceHandle device,
return;
}
bgfx::setViewRect(viewId, 0, 0, viewportWidth_, viewportHeight_);
const uint16_t viewWidth = ClampViewExtent(viewportWidth_);
const uint16_t viewHeight = ClampViewExtent(viewportHeight_);
bgfx::setViewRect(viewId, 0, 0, viewWidth, viewHeight);
const bool hasClear = clearConfig.enabled ||
clearConfig.clearColor || clearConfig.clearDepth || clearConfig.clearStencil;
@@ -1223,6 +1233,7 @@ void BgfxGraphicsBackend::Draw(GraphicsDeviceHandle device, GraphicsPipelineHand
GraphicsBufferHandle vertexBuffer, GraphicsBufferHandle indexBuffer,
uint32_t indexOffset, uint32_t indexCount, int32_t vertexOffset,
const std::array<float, 16>& modelMatrix) {
(void)device;
auto reportError = [&](const std::string& code, const std::string& message) {
if (!probeService_) {
return;

View File

@@ -42,14 +42,15 @@ CrashRecoveryService::CrashRecoveryService(std::shared_ptr<ILogger> logger, Cras
, lastHeartbeatNs_(0)
, heartbeatSeen_(false)
, heartbeatMonitorRunning_(false)
, config_(std::move(config))
, memoryLimitBytes_(0)
, lastSuccessfulFrameTime_(0.0)
, consecutiveFrameTimeouts_(0)
, luaExecutionFailures_(0)
, fileFormatErrors_(0)
, memoryWarnings_(0)
, lastHealthCheck_(std::chrono::steady_clock::now())
, signalHandlersInstalled_(false)
, config_(std::move(config)) {
, signalHandlersInstalled_(false) {
heartbeatTimeout_ = std::chrono::milliseconds(config_.heartbeatTimeoutMs);
heartbeatPollInterval_ = std::chrono::milliseconds(config_.heartbeatPollIntervalMs);
memoryLimitBytes_ = config_.memoryLimitMB * 1024 * 1024;
@@ -193,7 +194,7 @@ void CrashRecoveryService::RecordFrameHeartbeat(double frameTimeSeconds) {
void CrashRecoveryService::MonitorHeartbeats() {
logger_->Trace("CrashRecoveryService", "MonitorHeartbeats", "", "Starting heartbeat monitor");
const int64_t timeoutNs = static_cast<int64_t>(heartbeatTimeout_.count()) * 1000 * 1000;
const int64_t timeoutNs = heartbeatTimeout_.count() * 1000 * 1000;
while (heartbeatMonitorRunning_.load()) {
std::this_thread::sleep_for(heartbeatPollInterval_);
if (!heartbeatSeen_.load(std::memory_order_acquire)) {
@@ -572,7 +573,10 @@ size_t CrashRecoveryService::GetCurrentMemoryUsage() const {
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) == 0) {
// Return resident set size in bytes
return usage.ru_maxrss * 1024; // ru_maxrss is in KB on Linux
if (usage.ru_maxrss <= 0) {
return 0;
}
return static_cast<size_t>(usage.ru_maxrss) * 1024; // ru_maxrss is in KB on Linux
}
return 0;

View File

@@ -897,9 +897,9 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
lua_newtable(L);
lua_newtable(L);
for (int component = 0; component < 3; ++component) {
for (size_t component = 0; component < 3; ++component) {
lua_pushnumber(L, payload.positions[vertexIndex][component]);
lua_rawseti(L, -2, component + 1);
lua_rawseti(L, -2, static_cast<int>(component + 1));
}
lua_setfield(L, -2, "position");
@@ -908,9 +908,9 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
if (vertexIndex < payload.normals.size()) {
normal = payload.normals[vertexIndex];
}
for (int component = 0; component < 3; ++component) {
for (size_t component = 0; component < 3; ++component) {
lua_pushnumber(L, normal[component]);
lua_rawseti(L, -2, component + 1);
lua_rawseti(L, -2, static_cast<int>(component + 1));
}
lua_setfield(L, -2, "normal");
@@ -919,16 +919,16 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
if (vertexIndex < payload.tangents.size()) {
tangent = payload.tangents[vertexIndex];
}
for (int component = 0; component < 3; ++component) {
for (size_t component = 0; component < 3; ++component) {
lua_pushnumber(L, tangent[component]);
lua_rawseti(L, -2, component + 1);
lua_rawseti(L, -2, static_cast<int>(component + 1));
}
lua_setfield(L, -2, "tangent");
lua_newtable(L);
for (int component = 0; component < 3; ++component) {
for (size_t component = 0; component < 3; ++component) {
lua_pushnumber(L, payload.colors[vertexIndex][component]);
lua_rawseti(L, -2, component + 1);
lua_rawseti(L, -2, static_cast<int>(component + 1));
}
lua_setfield(L, -2, "color");
@@ -937,9 +937,9 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
if (vertexIndex < payload.texcoords.size()) {
texcoord = payload.texcoords[vertexIndex];
}
for (int component = 0; component < 2; ++component) {
for (size_t component = 0; component < 2; ++component) {
lua_pushnumber(L, texcoord[component]);
lua_rawseti(L, -2, component + 1);
lua_rawseti(L, -2, static_cast<int>(component + 1));
}
lua_setfield(L, -2, "texcoord");

View File

@@ -392,7 +392,7 @@ int PhysicsBridgeService::StepSimulation(float deltaTime, int maxSubSteps) {
if (maxSubSteps < 0) {
maxSubSteps = 0;
}
return static_cast<int>(world_->stepSimulation(deltaTime, maxSubSteps, 1.0f / 60.0f));
return world_->stepSimulation(deltaTime, maxSubSteps, 1.0f / 60.0f);
}
bool PhysicsBridgeService::GetRigidBodyTransform(const std::string& name,

View File

@@ -53,7 +53,7 @@ bool PipelineCompilerService::Compile(const std::string& inputPath,
if (profile == "glsl") {
// For GLSL, just copy the source
outputFile.write(source.c_str(), source.size());
outputFile.write(source.c_str(), static_cast<std::streamsize>(source.size()));
} else {
// For SPIR-V, compile using shaderc library
shaderc_shader_kind kind = isVertex ? shaderc_vertex_shader : shaderc_fragment_shader;
@@ -68,14 +68,15 @@ bool PipelineCompilerService::Compile(const std::string& inputPath,
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(processedSource, kind, inputPath.c_str(), options);
if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
lastError_ = "Shader compilation failed: " + std::string(result.GetErrorMessage());
lastError_ = "Shader compilation failed: " + result.GetErrorMessage();
logger_->Error(lastError_.value());
return false;
}
// Get the SPIR-V binary data
const uint32_t* spirvData = result.begin();
size_t spirvSize = (result.end() - result.begin()) * sizeof(uint32_t);
const size_t spirvWords = static_cast<size_t>(result.end() - result.begin());
const size_t spirvSize = spirvWords * sizeof(uint32_t);
// Write bgfx shader header
const uint32_t shaderBinVersion = 11;
@@ -91,7 +92,7 @@ bool PipelineCompilerService::Compile(const std::string& inputPath,
outputFile.write(reinterpret_cast<const char*>(&hash), sizeof(hash));
// Write SPIR-V data
outputFile.write(reinterpret_cast<const char*>(spirvData), spirvSize);
outputFile.write(reinterpret_cast<const char*>(spirvData), static_cast<std::streamsize>(spirvSize));
// Write uniform information (bgfx expects this after the SPIR-V)
if (isVertex) {
@@ -101,7 +102,7 @@ bool PipelineCompilerService::Compile(const std::string& inputPath,
// Uniform name (null-terminated) - include block name for Vulkan
const char* uniformName = "UniformBuffer.u_modelViewProj";
outputFile.write(uniformName, strlen(uniformName) + 1);
outputFile.write(uniformName, static_cast<std::streamsize>(strlen(uniformName) + 1));
// Uniform type (Mat4 = 4)
uint8_t uniformType = 4;
@@ -131,7 +132,7 @@ bool PipelineCompilerService::Compile(const std::string& inputPath,
// Uniform name (null-terminated)
const char* uniformName = "s_tex";
outputFile.write(uniformName, strlen(uniformName) + 1);
outputFile.write(uniformName, static_cast<std::streamsize>(strlen(uniformName) + 1));
// Uniform type (Sampler = 5)
uint8_t uniformType = 5;

View File

@@ -7,13 +7,16 @@ namespace sdl3cpp::services::impl {
SceneService::SceneService(std::shared_ptr<ISceneScriptService> scriptService,
std::shared_ptr<IEcsService> ecsService,
std::shared_ptr<ILogger> logger)
std::shared_ptr<ILogger> logger,
std::shared_ptr<IProbeService> probeService)
: scriptService_(std::move(scriptService)),
ecsService_(std::move(ecsService)),
logger_(std::move(logger)) {
logger_(std::move(logger)),
probeService_(std::move(probeService)) {
logger_->Trace("SceneService", "SceneService",
"scriptService=" + std::string(scriptService_ ? "set" : "null") +
", ecsService=" + std::string(ecsService_ ? "set" : "null"));
", ecsService=" + std::string(ecsService_ ? "set" : "null") +
", probeService=" + std::string(probeService_ ? "set" : "null"));
if (!scriptService_ || !ecsService_) {
throw std::invalid_argument("Scene script service and ECS service cannot be null");
@@ -39,6 +42,7 @@ void SceneService::LoadScene(const std::vector<SceneObject>& objects) {
if (objects.empty()) {
initialized_ = false;
hasSceneSignature_ = false;
return;
}
@@ -61,6 +65,12 @@ void SceneService::LoadScene(const std::vector<SceneObject>& objects) {
throw std::runtime_error("Scene vertex count exceeds uint16_t index range");
}
const bool shouldReportSceneLoad = ShouldEmitRuntimeProbe() &&
(!hasSceneSignature_ ||
objects.size() != lastSceneObjectCount_ ||
totalVertices != lastSceneVertexCount_ ||
totalIndices != lastSceneIndexCount_);
combinedVertices_.reserve(totalVertices);
combinedIndices_.reserve(totalIndices);
drawInfos_.reserve(objects.size());
@@ -134,6 +144,17 @@ void SceneService::LoadScene(const std::vector<SceneObject>& objects) {
", combinedIndices=" + std::to_string(combinedIndices_.size()) +
", drawCalls=" + std::to_string(drawInfos_.size()));
}
lastSceneObjectCount_ = objects.size();
lastSceneVertexCount_ = totalVertices;
lastSceneIndexCount_ = totalIndices;
hasSceneSignature_ = true;
if (shouldReportSceneLoad) {
ReportRuntimeProbe("SCENE_LOAD",
"Scene loaded",
"objects=" + std::to_string(objects.size()) +
", vertices=" + std::to_string(totalVertices) +
", indices=" + std::to_string(totalIndices));
}
initialized_ = true;
}
@@ -216,4 +237,23 @@ void SceneService::ClearSceneEntities() {
sceneEntities_.clear();
}
bool SceneService::ShouldEmitRuntimeProbe() const {
if (!probeService_ || !logger_) {
return false;
}
LogLevel level = logger_->GetLevel();
return level == LogLevel::TRACE || level == LogLevel::DEBUG;
}
void SceneService::ReportRuntimeProbe(const std::string& code,
const std::string& message,
const std::string& details) const {
ProbeReport report{};
report.severity = ProbeSeverity::Info;
report.code = code;
report.message = message;
report.details = details;
probeService_->Report(report);
}
} // namespace sdl3cpp::services::impl

View File

@@ -4,6 +4,7 @@
#include "../interfaces/i_scene_script_service.hpp"
#include "../interfaces/i_ecs_service.hpp"
#include "../interfaces/i_logger.hpp"
#include "../interfaces/i_probe_service.hpp"
#include "../../di/lifecycle.hpp"
#include <entt/entt.hpp>
#include <memory>
@@ -23,7 +24,8 @@ class SceneService : public ISceneService,
public:
SceneService(std::shared_ptr<ISceneScriptService> scriptService,
std::shared_ptr<IEcsService> ecsService,
std::shared_ptr<ILogger> logger);
std::shared_ptr<ILogger> logger,
std::shared_ptr<IProbeService> probeService = nullptr);
~SceneService() override;
// ISceneService interface
@@ -59,17 +61,26 @@ private:
std::vector<std::string> shaderKeys;
};
bool ShouldEmitRuntimeProbe() const;
void ReportRuntimeProbe(const std::string& code,
const std::string& message,
const std::string& details) const;
void ClearSceneEntities();
std::shared_ptr<ISceneScriptService> scriptService_;
std::shared_ptr<IEcsService> ecsService_;
std::shared_ptr<ILogger> logger_;
std::shared_ptr<IProbeService> probeService_;
entt::registry* registry_ = nullptr;
std::vector<entt::entity> sceneEntities_;
std::vector<core::Vertex> combinedVertices_;
std::vector<uint16_t> combinedIndices_;
std::vector<SceneDrawInfo> drawInfos_;
bool initialized_ = false;
size_t lastSceneObjectCount_ = 0;
size_t lastSceneVertexCount_ = 0;
size_t lastSceneIndexCount_ = 0;
bool hasSceneSignature_ = false;
};
} // namespace sdl3cpp::services::impl

View File

@@ -1,6 +1,7 @@
#include "sdl_audio_service.hpp"
#include <algorithm>
#include <limits>
#include <stdexcept>
#include <string>
@@ -9,6 +10,11 @@ namespace sdl3cpp::services::impl {
namespace {
constexpr int kDecodeChunkSize = 4096;
constexpr int kMixFrames = 1024;
uint32_t GetBytesPerFrame(const SDL_AudioSpec& spec) {
const uint32_t formatMask = SDL_AUDIO_MASK_BITSIZE;
const uint32_t bitsPerSample = static_cast<uint32_t>(spec.format) & formatMask;
return (bitsPerSample / 8u) * static_cast<uint32_t>(spec.channels);
}
} // namespace
SdlAudioService::SdlAudioService(std::shared_ptr<ILogger> logger)
@@ -254,8 +260,8 @@ void SdlAudioService::Update() {
return;
}
const int bytesPerFrame = SDL_AUDIO_FRAMESIZE(mixSpec_);
if (bytesPerFrame <= 0) {
const uint32_t bytesPerFrame = GetBytesPerFrame(mixSpec_);
if (bytesPerFrame == 0) {
return;
}
@@ -267,7 +273,8 @@ void SdlAudioService::Update() {
return;
}
if (queuedBytes >= bytesPerFrame * kMixFrames) {
const uint32_t queueLimit = bytesPerFrame * static_cast<uint32_t>(kMixFrames);
if (static_cast<uint32_t>(queuedBytes) >= queueLimit) {
return;
}
@@ -322,7 +329,8 @@ void SdlAudioService::Update() {
outputBuffer_.assign(sampleCount, 0);
const float volume = volume_;
for (size_t i = 0; i < sampleCount; ++i) {
int32_t value = static_cast<int32_t>(mixBuffer_[i] * volume);
const float mixed = static_cast<float>(mixBuffer_[i]) * volume;
int32_t value = static_cast<int32_t>(mixed);
value = std::clamp(value, -32768, 32767);
outputBuffer_[i] = static_cast<int16_t>(value);
}
@@ -369,7 +377,7 @@ bool SdlAudioService::LoadAudioFile(const std::filesystem::path& path, AudioData
audioData.sourceSpec.format = SDL_AUDIO_S16;
audioData.sourceSpec.channels = info->channels;
audioData.sourceSpec.freq = info->rate;
audioData.sourceSpec.freq = static_cast<int>(info->rate);
audioData.convertStream = SDL_CreateAudioStream(&audioData.sourceSpec, &mixSpec_);
if (!audioData.convertStream) {
ov_clear(&audioData.vorbisFile);
@@ -410,9 +418,17 @@ int SdlAudioService::ReadStreamSamples(AudioData& audioData, std::vector<int16_t
return 0;
}
const int bytesPerFrame = SDL_AUDIO_FRAMESIZE(mixSpec_);
const int bytesNeeded = frames * bytesPerFrame;
const size_t sampleCount = static_cast<size_t>(bytesNeeded / static_cast<int>(sizeof(int16_t)));
const uint32_t bytesPerFrame = GetBytesPerFrame(mixSpec_);
if (bytesPerFrame == 0) {
return 0;
}
const uint32_t bytesNeeded = bytesPerFrame * static_cast<uint32_t>(frames);
if (bytesNeeded > static_cast<uint32_t>(std::numeric_limits<int>::max())) {
audioData.finished = true;
return 0;
}
const int bytesNeededInt = static_cast<int>(bytesNeeded);
const size_t sampleCount = static_cast<size_t>(bytesNeededInt / static_cast<int>(sizeof(int16_t)));
output.assign(sampleCount, 0);
while (!audioData.finished) {
@@ -424,13 +440,17 @@ int SdlAudioService::ReadStreamSamples(AudioData& audioData, std::vector<int16_t
audioData.finished = true;
break;
}
if (available >= bytesNeeded) {
if (available >= bytesNeededInt) {
break;
}
char decodeBuffer[kDecodeChunkSize];
int bytesRead = ov_read(&audioData.vorbisFile, decodeBuffer, kDecodeChunkSize, 0, 2, 1, nullptr);
if (bytesRead > 0) {
long bytesReadLong = ov_read(&audioData.vorbisFile, decodeBuffer, kDecodeChunkSize, 0, 2, 1, nullptr);
if (bytesReadLong > 0) {
if (bytesReadLong > std::numeric_limits<int>::max()) {
bytesReadLong = std::numeric_limits<int>::max();
}
const int bytesRead = static_cast<int>(bytesReadLong);
if (!SDL_PutAudioStreamData(audioData.convertStream, decodeBuffer, bytesRead)) {
if (logger_) {
logger_->Error("Failed to queue decoded audio: " + std::string(SDL_GetError()));
@@ -438,7 +458,7 @@ int SdlAudioService::ReadStreamSamples(AudioData& audioData, std::vector<int16_t
audioData.finished = true;
break;
}
} else if (bytesRead == 0) {
} else if (bytesReadLong == 0) {
if (audioData.loop) {
ov_pcm_seek(&audioData.vorbisFile, 0);
continue;
@@ -455,7 +475,7 @@ int SdlAudioService::ReadStreamSamples(AudioData& audioData, std::vector<int16_t
}
}
int bytesRead = SDL_GetAudioStreamData(audioData.convertStream, output.data(), bytesNeeded);
int bytesRead = SDL_GetAudioStreamData(audioData.convertStream, output.data(), bytesNeededInt);
if (bytesRead < 0) {
if (logger_) {
logger_->Error("Failed to read audio stream data: " + std::string(SDL_GetError()));
@@ -464,10 +484,11 @@ int SdlAudioService::ReadStreamSamples(AudioData& audioData, std::vector<int16_t
return 0;
}
if (bytesRead < bytesNeeded) {
if (bytesRead < bytesNeededInt) {
const size_t samplesRead = static_cast<size_t>(bytesRead / static_cast<int>(sizeof(int16_t)));
if (samplesRead < output.size()) {
std::fill(output.begin() + samplesRead, output.end(), 0);
using Difference = std::vector<int16_t>::difference_type;
std::fill(output.begin() + static_cast<Difference>(samplesRead), output.end(), 0);
}
}

View File

@@ -71,6 +71,8 @@ void ThrowSdlErrorIfFailed(bool success, const char* context, const std::shared_
}
void ShowErrorDialog(const char* title, const std::string& message) {
(void)title;
(void)message;
// Disabled for headless environments
// SDL_ShowSimpleMessageBox(
// SDL_MESSAGEBOX_ERROR,
@@ -185,10 +187,12 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) {
logger_->TraceVariable("sdl.windowFlags", static_cast<int>(flags));
logger_->Trace("SdlWindowService", "CreateWindow", "SDL_CreateWindow");
const int windowWidth = static_cast<int>(config.width);
const int windowHeight = static_cast<int>(config.height);
window_ = SDL_CreateWindow(
config.title.c_str(),
config.width,
config.height,
windowWidth,
windowHeight,
flags
);
@@ -248,7 +252,7 @@ bool SdlWindowService::IsMinimized() const {
return false;
}
uint32_t flags = SDL_GetWindowFlags(window_);
const SDL_WindowFlags flags = SDL_GetWindowFlags(window_);
return (flags & SDL_WINDOW_MINIMIZED) != 0;
}