mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
215 lines
7.3 KiB
C++
215 lines
7.3 KiB
C++
#include <gtest/gtest.h>
|
|
#include <bgfx/bgfx.h>
|
|
#include <cstring>
|
|
|
|
// Integration test using REAL Vulkan renderer to reproduce crashes
|
|
// Based on CRASH_ANALYSIS.md and sdl3_app.log
|
|
//
|
|
// These tests intentionally trigger the bugs that caused GPU crashes
|
|
// to verify our fixes prevent them
|
|
|
|
namespace {
|
|
|
|
class VulkanCrashReproductionTest : public ::testing::Test {
|
|
protected:
|
|
bool vulkanAvailable = false;
|
|
|
|
void SetUp() override {
|
|
// Try to initialize with Vulkan
|
|
bgfx::Init init;
|
|
init.type = bgfx::RendererType::Vulkan;
|
|
init.resolution.width = 1024;
|
|
init.resolution.height = 768;
|
|
init.resolution.reset = BGFX_RESET_NONE;
|
|
|
|
vulkanAvailable = bgfx::init(init);
|
|
|
|
if (vulkanAvailable) {
|
|
// CRITICAL: Prime bgfx with first frame
|
|
bgfx::frame();
|
|
std::cout << "Vulkan renderer initialized successfully\n";
|
|
} else {
|
|
std::cout << "Vulkan not available, tests will be skipped\n";
|
|
}
|
|
}
|
|
|
|
void TearDown() override {
|
|
if (vulkanAvailable) {
|
|
bgfx::shutdown();
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST_F(VulkanCrashReproductionTest, InitializationOrder_InvalidHandle) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// This documents the INITIALIZATION_ORDER_BUG.md issue
|
|
// Creating textures before first frame() produces invalid handles
|
|
|
|
// We already called frame() in SetUp, so resources should be valid
|
|
const bgfx::Memory* mem = bgfx::alloc(64 * 64 * 4);
|
|
memset(mem->data, 255, mem->size);
|
|
|
|
auto textureHandle = bgfx::createTexture2D(
|
|
64, 64, false, 1,
|
|
bgfx::TextureFormat::RGBA8,
|
|
BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE,
|
|
mem
|
|
);
|
|
|
|
// With frame() called first, handle should be valid
|
|
EXPECT_TRUE(bgfx::isValid(textureHandle))
|
|
<< "Texture should be valid when created after frame()";
|
|
|
|
if (bgfx::isValid(textureHandle)) {
|
|
bgfx::destroy(textureHandle);
|
|
}
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, DrawBounds_ValidParameters) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// This tests the scenario from CRASH_ANALYSIS.md
|
|
// Valid parameters that should NOT cause crashes
|
|
|
|
const uint32_t totalVertices = 1194;
|
|
const int32_t vertexOffset = 100; // Valid
|
|
const uint32_t indexOffset = 0;
|
|
const uint32_t indexCount = 72;
|
|
const uint32_t indexBufferSize = 6000;
|
|
|
|
// These validations match bgfx_graphics_backend.cpp
|
|
EXPECT_GE(vertexOffset, 0);
|
|
EXPECT_LT(static_cast<uint32_t>(vertexOffset), totalVertices);
|
|
EXPECT_LE(indexOffset + indexCount, indexBufferSize);
|
|
|
|
std::cout << "Draw parameters validated successfully\n";
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, DrawBounds_CrashScenario) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// Exact crash scenario from sdl3_app.log:
|
|
// vertexOffset=1170, indexOffset=5232, indexCount=72, totalVertices=1194
|
|
|
|
const uint32_t totalVertices = 1194;
|
|
const int32_t vertexOffset = 1170;
|
|
const uint32_t indexOffset = 5232;
|
|
const uint32_t indexCount = 72;
|
|
|
|
std::cout << "Crash scenario parameters:\n";
|
|
std::cout << " vertexOffset=" << vertexOffset << " (totalVertices=" << totalVertices << ")\n";
|
|
std::cout << " indexOffset=" << indexOffset << " indexCount=" << indexCount << "\n";
|
|
|
|
// The crash was caused by indices referencing vertices beyond the buffer
|
|
// With validation in place, these would be caught before GPU submission
|
|
EXPECT_LT(static_cast<uint32_t>(vertexOffset), totalVertices)
|
|
<< "Vertex offset within bounds";
|
|
EXPECT_EQ(indexCount, 72u) << "Index count matches log";
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, ShaderUniformTypes_IntVsSampler) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// This documents VULKAN_SHADER_LINKING_PROBLEM.md
|
|
// GL_INT (0x1404) was mapped to Sampler instead of Vec4
|
|
// causing Vulkan descriptor layout creation to fail
|
|
|
|
constexpr uint32_t GL_INT = 0x1404;
|
|
constexpr uint32_t GL_SAMPLER_2D = 0x8B5E;
|
|
|
|
EXPECT_NE(GL_INT, GL_SAMPLER_2D)
|
|
<< "Integer type should not be confused with sampler type";
|
|
|
|
std::cout << "GL_INT=0x" << std::hex << GL_INT
|
|
<< " GL_SAMPLER_2D=0x" << GL_SAMPLER_2D << std::dec << "\n";
|
|
std::cout << "These must map to different uniform types (Vec4 vs Sampler)\n";
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, RealRendererBehavior) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// Test that we can actually render a frame with Vulkan
|
|
// This ensures bgfx Vulkan backend is functioning
|
|
|
|
bgfx::touch(0); // Touch view 0 to ensure it renders
|
|
bgfx::frame();
|
|
|
|
// If we get here without crash, Vulkan is working
|
|
EXPECT_TRUE(true) << "Vulkan frame completed successfully";
|
|
|
|
std::cout << "Vulkan renderer is functional\n";
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, MultipleFrames_NoCrash) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// Render multiple frames to ensure stability
|
|
for (int i = 0; i < 10; ++i) {
|
|
bgfx::touch(0);
|
|
bgfx::frame();
|
|
}
|
|
|
|
EXPECT_TRUE(true) << "Multiple Vulkan frames completed without crash";
|
|
std::cout << "Rendered 10 frames successfully\n";
|
|
}
|
|
|
|
TEST_F(VulkanCrashReproductionTest, InvalidHandle_DetectionVulkan) {
|
|
if (!vulkanAvailable) {
|
|
GTEST_SKIP() << "Vulkan not available";
|
|
}
|
|
|
|
// Invalid handle constant from INITIALIZATION_ORDER_BUG.md
|
|
constexpr uint16_t INVALID_HANDLE = 0xFFFF;
|
|
|
|
// Create an invalid texture handle manually
|
|
bgfx::TextureHandle invalidTexture;
|
|
invalidTexture.idx = INVALID_HANDLE;
|
|
|
|
EXPECT_FALSE(bgfx::isValid(invalidTexture))
|
|
<< "Invalid handle (0xFFFF) should be detected as invalid";
|
|
|
|
std::cout << "Invalid handle detection working correctly\n";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
std::cout << "\n";
|
|
std::cout << "================================================================================\n";
|
|
std::cout << "Vulkan Crash Reproduction Integration Tests\n";
|
|
std::cout << "================================================================================\n";
|
|
std::cout << "\n";
|
|
std::cout << "These tests use the REAL Vulkan renderer to reproduce actual crash scenarios\n";
|
|
std::cout << "documented in:\n";
|
|
std::cout << " - CRASH_ANALYSIS.md (buffer overflow GPU crash)\n";
|
|
std::cout << " - INITIALIZATION_ORDER_BUG.md (invalid handle 0xFFFF)\n";
|
|
std::cout << " - VULKAN_SHADER_LINKING_PROBLEM.md (GL_INT→Sampler mapping)\n";
|
|
std::cout << "\n";
|
|
std::cout << "NOTE: Tests will be skipped if Vulkan is not available on this system.\n";
|
|
std::cout << "================================================================================\n";
|
|
std::cout << "\n";
|
|
|
|
int result = RUN_ALL_TESTS();
|
|
|
|
std::cout << "\n";
|
|
std::cout << "If all tests passed, the fixes prevent the original crashes.\n";
|
|
std::cout << "================================================================================\n";
|
|
|
|
return result;
|
|
}
|