Compare commits

...

4 Commits

Author SHA1 Message Date
ubuntu1804 fd9c1c89e6 调整渲染文字内容 2025-11-10 21:29:00 +08:00
ubuntu1804 4b04a1adf7 调整文字大小和位置 2025-11-10 21:01:35 +08:00
ubuntu1804 96a744bde0 修复文字显示bug 2025-11-10 20:26:57 +08:00
ubuntu1804 25e6159176 增加freetype支持 2025-11-10 20:00:34 +08:00
13 changed files with 1562 additions and 329 deletions

View File

@ -60,6 +60,15 @@ endif()
find_package(Qt5 REQUIRED COMPONENTS ${QT_COMPONENTS}) find_package(Qt5 REQUIRED COMPONENTS ${QT_COMPONENTS})
# FreeType support (for text rendering in Vulkan)
find_package(Freetype)
if(FREETYPE_FOUND)
message(STATUS "FreeType found: ${FREETYPE_LIBRARIES}")
message(STATUS "FreeType include: ${FREETYPE_INCLUDE_DIRS}")
else()
message(WARNING "FreeType not found, text rendering may be limited")
endif()
# Vulkan support (optional) - only headers needed, volk loads dynamically # Vulkan support (optional) - only headers needed, volk loads dynamically
option(ENABLE_VULKAN "Enable Vulkan support" ON) option(ENABLE_VULKAN "Enable Vulkan support" ON)
set(VULKAN_FOUND FALSE) set(VULKAN_FOUND FALSE)
@ -190,6 +199,13 @@ if(VULKAN_FOUND)
target_link_libraries(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME}
volk volk
) )
# Add FreeType support for text rendering in Vulkan
if(FREETYPE_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${FREETYPE_LIBRARIES})
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_FREETYPE)
endif()
endif() endif()
# Platform-specific linking # Platform-specific linking
@ -235,6 +251,12 @@ if(VULKAN_FOUND)
message(STATUS "Vulkan headers: ${VULKAN_HEADERS_DIR}") message(STATUS "Vulkan headers: ${VULKAN_HEADERS_DIR}")
message(STATUS "Volk directory: ${VOLK_DIR}") message(STATUS "Volk directory: ${VOLK_DIR}")
message(STATUS "Note: No Vulkan library linking - volk loads dynamically at runtime") message(STATUS "Note: No Vulkan library linking - volk loads dynamically at runtime")
if(FREETYPE_FOUND)
message(STATUS "FreeType support: ENABLED (for text rendering)")
message(STATUS "FreeType libraries: ${FREETYPE_LIBRARIES}")
else()
message(STATUS "FreeType support: DISABLED")
endif()
else() else()
message(STATUS "Vulkan support: DISABLED") message(STATUS "Vulkan support: DISABLED")
endif() endif()

186
TEXT_RENDERING.md Normal file
View File

@ -0,0 +1,186 @@
# Text Rendering Implementation in VulkanWidget
## Overview
This document describes the text rendering implementation added to the VulkanWidget using FreeType library.
## Features Implemented
### 1. FreeType Integration
- **Library**: Uses system libfreetype.a (found at `/usr/local/lib/libfreetype.a`)
- **Font Loading**: Automatically searches common font paths:
- `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf`
- `/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf`
- `/usr/share/fonts/TTF/DejaVuSans.ttf`
- `/System/Library/Fonts/Helvetica.ttc` (macOS)
- `/usr/local/share/fonts/DejaVuSans.ttf`
### 2. Font Atlas Generation
- **Size**: 512x512 texture atlas
- **Character Range**: ASCII 32-126 (95 printable characters)
- **Format**: Single-channel R8_UNORM texture
- **Packing**: Automatic row-based packing with 1-pixel padding
- **Storage**: CharInfo map stores texture coordinates, size, bearing, and advance for each character
### 3. Text Rendering Pipeline
- **Shaders**:
- `text.vert` - Converts pixel coordinates to NDC
- `text.frag` - Samples font atlas with alpha blending
- **Blending**: Alpha blending enabled for smooth text rendering
- **Descriptors**:
- Binding 0: Uniform Buffer (time, resolution, rotation, wavePhase)
- Binding 1: Font texture sampler
### 4. Text Content (Matching CustomWidget)
The text rendering displays the same information as CustomWidget:
#### Active State:
- **Title**: "Screen Lock Detector - Painting Active" (top center, white, scale 0.8)
- **Statistics Box** (top left, green, scale 0.6):
- Frame Count
- FPS: ~60
- Rotation angle
- Running Time
- **Lock Info Box** (below stats, magenta, scale 0.65/0.5):
- Last Lock Info title
- Lock time
- Duration
- Frame count at lock
- Total locks
- **Hint**: "Lock your screen..." (bottom center, yellow, scale 0.65)
#### Locked State:
- **Title**: "PAINTING DISABLED" (center, white, scale 1.2)
- **Subtitle**: "(Screen Locked)" (center, gray, scale 0.9)
- **Stats**: Total frames painted (bottom left, gray, scale 0.7)
## Implementation Details
### Code Structure
1. **VulkanRenderer::initializeTextRendering()**
- Initializes FreeType library
- Loads font face
- Generates character glyphs
- Creates font texture atlas
- Sets up Vulkan image, image view, and sampler
2. **VulkanRenderer::createTextPipeline()**
- Loads text vertex and fragment shaders
- Sets up vertex input (position, color, texCoord)
- Configures alpha blending
- Creates descriptor set layout with texture sampler
- Builds graphics pipeline
3. **VulkanRenderer::generateTextQuads()**
- Converts text string to quad vertices
- Handles newlines
- Uses pixel coordinates (shader converts to NDC)
- Sets texture coordinates from CharInfo map
- Applies scale and color
4. **VulkanRenderer::drawText()**
- Binds text pipeline
- Binds descriptor sets (UBO + font texture)
- Generates text quads based on painting state
- Creates temporary vertex/index buffers
- Issues draw calls
### Coordinate System
- **Input**: Pixel coordinates (0,0 = top-left, width,height = bottom-right)
- **Shader**: Converts to NDC (-1,-1 = bottom-left, 1,1 = top-right)
- **Y-axis**: Flipped in shader (Vulkan Y-down → traditional Y-up)
### Resource Management
- Font texture and sampler are persistent (created once)
- Text vertex/index buffers are recreated each frame (using static variables)
- Old buffers are destroyed before creating new ones
- Descriptor sets are updated after text rendering initialization
## CMake Configuration
```cmake
# FreeType support (for text rendering in Vulkan)
find_package(Freetype)
if(FREETYPE_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${FREETYPE_LIBRARIES})
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_FREETYPE)
endif()
```
## Debugging
Debug output is enabled every ~5 seconds (300 frames):
```
Initializing text rendering with FreeType...
Text rendering initialized successfully with 95 characters
Font texture: OK
Font texture view: OK
Font sampler: OK
Creating text pipeline...
Text pipeline created successfully
Updating descriptor sets with font texture...
Descriptor sets updated with font texture
drawText called: charMap=95 pipeline=OK fontTexView=OK
Drawing text with 572 vertices, 858 indices
Window size: 756x425
First vertex pos: (30.4, 1.2)
First vertex color: (1, 1, 1, 1)
```
## Known Issues and Future Improvements
### Current Limitations:
1. Text buffers are recreated every frame (performance impact)
2. No text caching or batching
3. Limited to ASCII characters only
4. Fixed font size (48pt base)
### Potential Improvements:
1. Implement text buffer caching for static text
2. Add support for Unicode/UTF-8
3. Multiple font sizes/styles
4. Text layout system (word wrapping, alignment)
5. Better memory management for text resources
6. Dynamic font atlas resizing
7. SDF (Signed Distance Field) rendering for scalable text
## Testing
To verify text rendering:
1. Build project: `./build.sh`
2. Run application: `./run.sh`
3. Check console for text rendering initialization messages
4. Verify text appears on screen matching CustomWidget layout
5. Lock screen to test state changes
## Dependencies
- FreeType 2.x
- Vulkan 1.x
- Volk (for Vulkan function loading)
- Qt 5.15.x (for window management)
## Files Modified
- `CMakeLists.txt` - Added FreeType support
- `src/vulkanrenderer.h` - Added text rendering declarations
- `src/vulkanrenderer.cpp` - Implemented text rendering functions
- `shaders/text.vert` - Text vertex shader
- `shaders/text.frag` - Text fragment shader
## References
- FreeType Documentation: https://freetype.org/freetype2/docs/
- Vulkan Text Rendering: https://learnopengl.com/In-Practice/Text-Rendering
- Font Atlas Generation: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02

141
check_text_rendering.sh Executable file
View File

@ -0,0 +1,141 @@
#!/bin/bash
echo "========================================"
echo "Text Rendering Diagnostic Script"
echo "========================================"
echo ""
# Check if FreeType is installed
echo "1. Checking FreeType installation..."
if pkg-config --exists freetype2; then
echo " ✓ FreeType found:"
pkg-config --modversion freetype2
echo " Library: $(pkg-config --variable=libdir freetype2)/libfreetype.a"
echo " Include: $(pkg-config --cflags freetype2)"
else
echo " ✗ FreeType not found via pkg-config"
fi
echo ""
# Check for font files
echo "2. Checking available fonts..."
FONTS=(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
"/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
"/usr/share/fonts/TTF/DejaVuSans.ttf"
"/usr/local/share/fonts/DejaVuSans.ttf"
)
FOUND_FONT=false
for font in "${FONTS[@]}"; do
if [ -f "$font" ]; then
echo " ✓ Found: $font"
FOUND_FONT=true
fi
done
if [ "$FOUND_FONT" = false ]; then
echo " ✗ No fonts found in standard locations"
echo " Installing DejaVu fonts might help:"
echo " sudo apt-get install fonts-dejavu-core"
fi
echo ""
# Check if shaders are compiled
echo "3. Checking text shaders..."
if [ -f "src/shaders_spirv/text.vert.spv" ]; then
echo " ✓ text.vert.spv exists"
else
echo " ✗ text.vert.spv missing"
fi
if [ -f "src/shaders_spirv/text.frag.spv" ]; then
echo " ✓ text.frag.spv exists"
else
echo " ✗ text.frag.spv missing"
fi
if [ -f "src/shaders_spirv/text_vert.inc" ]; then
echo " ✓ text_vert.inc exists"
else
echo " ✗ text_vert.inc missing"
fi
if [ -f "src/shaders_spirv/text_frag.inc" ]; then
echo " ✓ text_frag.inc exists"
else
echo " ✗ text_frag.inc missing"
fi
echo ""
# Check build configuration
echo "4. Checking build configuration..."
if [ -f "build/CMakeCache.txt" ]; then
if grep -q "ENABLE_FREETYPE" build/CMakeCache.txt 2>/dev/null; then
echo " ✓ ENABLE_FREETYPE is defined"
else
echo " ✗ ENABLE_FREETYPE not found in build"
fi
if grep -q "FREETYPE_LIBRARY" build/CMakeCache.txt 2>/dev/null; then
FREETYPE_LIB=$(grep "FREETYPE_LIBRARY" build/CMakeCache.txt | cut -d= -f2)
echo " ✓ FreeType library linked: $FREETYPE_LIB"
fi
else
echo " ⚠ Build directory not found - run ./build.sh first"
fi
echo ""
# Check if executable exists and has FreeType symbols
echo "5. Checking executable..."
if [ -f "build/bin/ScreenLockDetector" ]; then
echo " ✓ Executable exists"
# Check for FreeType symbols
if nm build/bin/ScreenLockDetector 2>/dev/null | grep -q "FT_Init_FreeType"; then
echo " ✓ FreeType symbols found in executable"
else
echo " ⚠ FreeType symbols not found (might be dynamically linked)"
fi
# Check for Vulkan symbols
if nm build/bin/ScreenLockDetector 2>/dev/null | grep -q "vkCreateGraphicsPipeline"; then
echo " ✓ Vulkan symbols found"
fi
else
echo " ✗ Executable not found - build first with ./build.sh"
fi
echo ""
# Run the application with text rendering debug output
echo "6. Testing text rendering (5 seconds)..."
echo " Starting application..."
if [ -f "build/bin/ScreenLockDetector" ]; then
timeout 5 ./run.sh 2>&1 | grep -E "Text|text|Font|font|FreeType|pipeline|charMap|Drawing text" | head -20
echo ""
echo " If you see 'Drawing text with X vertices' above, text rendering is working!"
else
echo " ✗ Cannot test - executable not found"
fi
echo ""
# Summary
echo "========================================"
echo "Summary"
echo "========================================"
echo ""
echo "Text rendering requires:"
echo " 1. FreeType library installed ✓"
echo " 2. At least one font file available"
echo " 3. Text shaders compiled (text.vert/frag.spv)"
echo " 4. ENABLE_FREETYPE defined in build"
echo " 5. Application successfully initializes text pipeline"
echo ""
echo "If text is not visible but pipeline is created:"
echo " - Check shader coordinate system"
echo " - Verify alpha blending is enabled"
echo " - Ensure text color contrasts with background"
echo " - Check if text is positioned within viewport"
echo ""
echo "For more details, see: TEXT_RENDERING.md"
echo "========================================"

View File

@ -20,13 +20,13 @@ void main() {
// Create dynamic gradient based on time // Create dynamic gradient based on time
float t = ubo.time / 360.0; float t = ubo.time / 360.0;
// Calculate color components with sine waves // Calculate color components matching Qt CustomWidget
float r = 0.39 + 0.20 * sin(t * 6.28318); float r = 0.392 + 0.196 * sin(t * 6.28318);
float g = 0.59 + 0.20 * sin(t * 6.28318 + 1.047); float g = 0.588 + 0.196 * sin(t * 6.28318 + 1.047);
float b = 0.78 + 0.22 * sin(t * 6.28318 + 2.094); float b = 0.784 + 0.216 * sin(t * 6.28318 + 2.094);
vec3 color1 = vec3(r, g, b); vec3 color1 = vec3(r, g, b);
vec3 color2 = vec3(0.12, 0.12, 0.24); vec3 color2 = vec3(0.118, 0.118, 0.235);
// Linear gradient from top-left to bottom-right // Linear gradient from top-left to bottom-right
float gradient = uv.x * 0.5 + uv.y * 0.5; float gradient = uv.x * 0.5 + uv.y * 0.5;

View File

@ -7,24 +7,30 @@ layout(location = 2) in vec2 inTexCoord;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragTexCoord; layout(location = 1) out vec2 fragTexCoord;
layout(binding = 0) uniform UniformBufferObject { // Use std140 layout and separate floats instead of vec2 to avoid alignment issues
float time; layout(binding = 0, std140) uniform UniformBufferObject {
vec2 resolution; float time; // offset 0
float rotation; float resX; // offset 4
float wavePhase; float resY; // offset 8
float rotation; // offset 12
float wavePhase; // offset 16
float padding1; // offset 20
float padding2; // offset 24
} ubo; } ubo;
void main() { void main() {
// Transform position from pixel coordinates to normalized device coordinates // Input position is in pixel coordinates (0,0 = top-left)
vec2 pos = inPosition; vec2 pos = inPosition;
// Convert to NDC: (0, 0) to (width, height) -> (-1, -1) to (1, 1) // Convert to NDC: (0, 0) to (width, height) -> (-1, -1) to (1, 1)
vec2 ndc = (pos / ubo.resolution) * 2.0 - 1.0; // Note: Vulkan NDC has Y pointing down, but we want traditional Y-up
float ndcX = (pos.x / ubo.resX) * 2.0 - 1.0;
float ndcY = (pos.y / ubo.resY) * 2.0 - 1.0;
// Flip Y axis (Vulkan has Y down, we want Y up for easier math) // NO Y-flip needed here - text coordinates are already in screen space
ndc.y = -ndc.y; // where (0,0) is top-left, which matches Vulkan's framebuffer coordinates
gl_Position = vec4(ndcX, ndcY, 0.0, 1.0);
gl_Position = vec4(ndc, 0.0, 1.0);
fragColor = inColor; fragColor = inColor;
fragTexCoord = inTexCoord; fragTexCoord = inTexCoord;
} }

View File

@ -29,13 +29,13 @@
0x00000006u, 0x00000007u, 0x00000006u, 0x00000006u, 0x00040020u, 0x00000015u, 0x00000002u, 0x00000014u, 0x00000006u, 0x00000007u, 0x00000006u, 0x00000006u, 0x00040020u, 0x00000015u, 0x00000002u, 0x00000014u,
0x0004003bu, 0x00000015u, 0x00000016u, 0x00000002u, 0x00040015u, 0x00000017u, 0x00000020u, 0x00000001u, 0x0004003bu, 0x00000015u, 0x00000016u, 0x00000002u, 0x00040015u, 0x00000017u, 0x00000020u, 0x00000001u,
0x0004002bu, 0x00000017u, 0x00000018u, 0x00000000u, 0x00040020u, 0x00000019u, 0x00000002u, 0x00000006u, 0x0004002bu, 0x00000017u, 0x00000018u, 0x00000000u, 0x00040020u, 0x00000019u, 0x00000002u, 0x00000006u,
0x0004002bu, 0x00000006u, 0x0000001cu, 0x43b40000u, 0x0004002bu, 0x00000006u, 0x0000001fu, 0x3ec7ae14u, 0x0004002bu, 0x00000006u, 0x0000001cu, 0x43b40000u, 0x0004002bu, 0x00000006u, 0x0000001fu, 0x3ec8b439u,
0x0004002bu, 0x00000006u, 0x00000020u, 0x3e4ccccdu, 0x0004002bu, 0x00000006u, 0x00000022u, 0x40c90fd0u, 0x0004002bu, 0x00000006u, 0x00000020u, 0x3e48b439u, 0x0004002bu, 0x00000006u, 0x00000022u, 0x40c90fd0u,
0x0004002bu, 0x00000006u, 0x00000028u, 0x3f170a3du, 0x0004002bu, 0x00000006u, 0x0000002bu, 0x3f860419u, 0x0004002bu, 0x00000006u, 0x00000028u, 0x3f16872bu, 0x0004002bu, 0x00000006u, 0x0000002bu, 0x3f860419u,
0x0004002bu, 0x00000006u, 0x00000031u, 0x3f47ae14u, 0x0004002bu, 0x00000006u, 0x00000032u, 0x3e6147aeu, 0x0004002bu, 0x00000006u, 0x00000031u, 0x3f48b439u, 0x0004002bu, 0x00000006u, 0x00000032u, 0x3e5d2f1bu,
0x0004002bu, 0x00000006u, 0x00000035u, 0x40060419u, 0x00040017u, 0x0000003au, 0x00000006u, 0x00000003u, 0x0004002bu, 0x00000006u, 0x00000035u, 0x40060419u, 0x00040017u, 0x0000003au, 0x00000006u, 0x00000003u,
0x00040020u, 0x0000003bu, 0x00000007u, 0x0000003au, 0x0004002bu, 0x00000006u, 0x00000042u, 0x3df5c28fu, 0x00040020u, 0x0000003bu, 0x00000007u, 0x0000003au, 0x0004002bu, 0x00000006u, 0x00000042u, 0x3df1a9fcu,
0x0004002bu, 0x00000006u, 0x00000043u, 0x3e75c28fu, 0x0006002cu, 0x0000003au, 0x00000044u, 0x00000042u, 0x0004002bu, 0x00000006u, 0x00000043u, 0x3e70a3d7u, 0x0006002cu, 0x0000003au, 0x00000044u, 0x00000042u,
0x00000042u, 0x00000043u, 0x00040015u, 0x00000046u, 0x00000020u, 0x00000000u, 0x0004002bu, 0x00000046u, 0x00000042u, 0x00000043u, 0x00040015u, 0x00000046u, 0x00000020u, 0x00000000u, 0x0004002bu, 0x00000046u,
0x00000047u, 0x00000000u, 0x0004002bu, 0x00000046u, 0x0000004bu, 0x00000001u, 0x00040017u, 0x00000056u, 0x00000047u, 0x00000000u, 0x0004002bu, 0x00000046u, 0x0000004bu, 0x00000001u, 0x00040017u, 0x00000056u,
0x00000006u, 0x00000004u, 0x00040020u, 0x00000057u, 0x00000003u, 0x00000056u, 0x0004003bu, 0x00000057u, 0x00000006u, 0x00000004u, 0x00040020u, 0x00000057u, 0x00000003u, 0x00000056u, 0x0004003bu, 0x00000057u,

Binary file not shown.

View File

@ -1,60 +1,67 @@
// Auto-generated from text.vert.spv // Auto-generated from text.vert.spv
// Size: 1840 bytes (460 words) // Size: 2080 bytes (520 words)
0x07230203u, 0x00010000u, 0x0008000bu, 0x00000039u, 0x00000000u, 0x00020011u, 0x00000001u, 0x0006000bu, 0x07230203u, 0x00010000u, 0x0008000bu, 0x0000003eu, 0x00000000u, 0x00020011u, 0x00000001u, 0x0006000bu,
0x00000001u, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0x00000000u, 0x0003000eu, 0x00000000u, 0x00000001u, 0x00000001u, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0x00000000u, 0x0003000eu, 0x00000000u, 0x00000001u,
0x000b000fu, 0x00000000u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x0000000bu, 0x00000028u, 0x00000031u, 0x000b000fu, 0x00000000u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x0000000bu, 0x0000002eu, 0x00000036u,
0x00000033u, 0x00000036u, 0x00000037u, 0x00030003u, 0x00000002u, 0x000001c2u, 0x00040005u, 0x00000004u, 0x00000038u, 0x0000003bu, 0x0000003cu, 0x00030003u, 0x00000002u, 0x000001c2u, 0x00040005u, 0x00000004u,
0x6e69616du, 0x00000000u, 0x00030005u, 0x00000009u, 0x00736f70u, 0x00050005u, 0x0000000bu, 0x6f506e69u, 0x6e69616du, 0x00000000u, 0x00030005u, 0x00000009u, 0x00736f70u, 0x00050005u, 0x0000000bu, 0x6f506e69u,
0x69746973u, 0x00006e6fu, 0x00030005u, 0x0000000du, 0x0063646eu, 0x00070005u, 0x0000000fu, 0x66696e55u, 0x69746973u, 0x00006e6fu, 0x00040005u, 0x0000000eu, 0x5863646eu, 0x00000000u, 0x00070005u, 0x00000013u,
0x426d726fu, 0x65666675u, 0x6a624f72u, 0x00746365u, 0x00050006u, 0x0000000fu, 0x00000000u, 0x656d6974u, 0x66696e55u, 0x426d726fu, 0x65666675u, 0x6a624f72u, 0x00746365u, 0x00050006u, 0x00000013u, 0x00000000u,
0x00000000u, 0x00060006u, 0x0000000fu, 0x00000001u, 0x6f736572u, 0x6974756cu, 0x00006e6fu, 0x00060006u, 0x656d6974u, 0x00000000u, 0x00050006u, 0x00000013u, 0x00000001u, 0x58736572u, 0x00000000u, 0x00050006u,
0x0000000fu, 0x00000002u, 0x61746f72u, 0x6e6f6974u, 0x00000000u, 0x00060006u, 0x0000000fu, 0x00000003u, 0x00000013u, 0x00000002u, 0x59736572u, 0x00000000u, 0x00060006u, 0x00000013u, 0x00000003u, 0x61746f72u,
0x65766177u, 0x73616850u, 0x00000065u, 0x00030005u, 0x00000011u, 0x006f6275u, 0x00060005u, 0x00000026u, 0x6e6f6974u, 0x00000000u, 0x00060006u, 0x00000013u, 0x00000004u, 0x65766177u, 0x73616850u, 0x00000065u,
0x505f6c67u, 0x65567265u, 0x78657472u, 0x00000000u, 0x00060006u, 0x00000026u, 0x00000000u, 0x505f6c67u, 0x00060006u, 0x00000013u, 0x00000005u, 0x64646170u, 0x31676e69u, 0x00000000u, 0x00060006u, 0x00000013u,
0x7469736fu, 0x006e6f69u, 0x00070006u, 0x00000026u, 0x00000001u, 0x505f6c67u, 0x746e696fu, 0x657a6953u, 0x00000006u, 0x64646170u, 0x32676e69u, 0x00000000u, 0x00030005u, 0x00000015u, 0x006f6275u, 0x00040005u,
0x00000000u, 0x00070006u, 0x00000026u, 0x00000002u, 0x435f6c67u, 0x4470696cu, 0x61747369u, 0x0065636eu, 0x00000020u, 0x5963646eu, 0x00000000u, 0x00060005u, 0x0000002cu, 0x505f6c67u, 0x65567265u, 0x78657472u,
0x00070006u, 0x00000026u, 0x00000003u, 0x435f6c67u, 0x446c6c75u, 0x61747369u, 0x0065636eu, 0x00030005u, 0x00000000u, 0x00060006u, 0x0000002cu, 0x00000000u, 0x505f6c67u, 0x7469736fu, 0x006e6f69u, 0x00070006u,
0x00000028u, 0x00000000u, 0x00050005u, 0x00000031u, 0x67617266u, 0x6f6c6f43u, 0x00000072u, 0x00040005u, 0x0000002cu, 0x00000001u, 0x505f6c67u, 0x746e696fu, 0x657a6953u, 0x00000000u, 0x00070006u, 0x0000002cu,
0x00000033u, 0x6f436e69u, 0x00726f6cu, 0x00060005u, 0x00000036u, 0x67617266u, 0x43786554u, 0x64726f6fu, 0x00000002u, 0x435f6c67u, 0x4470696cu, 0x61747369u, 0x0065636eu, 0x00070006u, 0x0000002cu, 0x00000003u,
0x00000000u, 0x00050005u, 0x00000037u, 0x65546e69u, 0x6f6f4378u, 0x00006472u, 0x00040047u, 0x0000000bu, 0x435f6c67u, 0x446c6c75u, 0x61747369u, 0x0065636eu, 0x00030005u, 0x0000002eu, 0x00000000u, 0x00050005u,
0x0000001eu, 0x00000000u, 0x00050048u, 0x0000000fu, 0x00000000u, 0x00000023u, 0x00000000u, 0x00050048u, 0x00000036u, 0x67617266u, 0x6f6c6f43u, 0x00000072u, 0x00040005u, 0x00000038u, 0x6f436e69u, 0x00726f6cu,
0x0000000fu, 0x00000001u, 0x00000023u, 0x00000008u, 0x00050048u, 0x0000000fu, 0x00000002u, 0x00000023u, 0x00060005u, 0x0000003bu, 0x67617266u, 0x43786554u, 0x64726f6fu, 0x00000000u, 0x00050005u, 0x0000003cu,
0x00000010u, 0x00050048u, 0x0000000fu, 0x00000003u, 0x00000023u, 0x00000014u, 0x00030047u, 0x0000000fu, 0x65546e69u, 0x6f6f4378u, 0x00006472u, 0x00040047u, 0x0000000bu, 0x0000001eu, 0x00000000u, 0x00050048u,
0x00000002u, 0x00040047u, 0x00000011u, 0x00000022u, 0x00000000u, 0x00040047u, 0x00000011u, 0x00000021u, 0x00000013u, 0x00000000u, 0x00000023u, 0x00000000u, 0x00050048u, 0x00000013u, 0x00000001u, 0x00000023u,
0x00000000u, 0x00050048u, 0x00000026u, 0x00000000u, 0x0000000bu, 0x00000000u, 0x00050048u, 0x00000026u, 0x00000004u, 0x00050048u, 0x00000013u, 0x00000002u, 0x00000023u, 0x00000008u, 0x00050048u, 0x00000013u,
0x00000001u, 0x0000000bu, 0x00000001u, 0x00050048u, 0x00000026u, 0x00000002u, 0x0000000bu, 0x00000003u, 0x00000003u, 0x00000023u, 0x0000000cu, 0x00050048u, 0x00000013u, 0x00000004u, 0x00000023u, 0x00000010u,
0x00050048u, 0x00000026u, 0x00000003u, 0x0000000bu, 0x00000004u, 0x00030047u, 0x00000026u, 0x00000002u, 0x00050048u, 0x00000013u, 0x00000005u, 0x00000023u, 0x00000014u, 0x00050048u, 0x00000013u, 0x00000006u,
0x00040047u, 0x00000031u, 0x0000001eu, 0x00000000u, 0x00040047u, 0x00000033u, 0x0000001eu, 0x00000001u, 0x00000023u, 0x00000018u, 0x00030047u, 0x00000013u, 0x00000002u, 0x00040047u, 0x00000015u, 0x00000022u,
0x00040047u, 0x00000036u, 0x0000001eu, 0x00000001u, 0x00040047u, 0x00000037u, 0x0000001eu, 0x00000002u, 0x00000000u, 0x00040047u, 0x00000015u, 0x00000021u, 0x00000000u, 0x00050048u, 0x0000002cu, 0x00000000u,
0x00020013u, 0x00000002u, 0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u, 0x0000000bu, 0x00000000u, 0x00050048u, 0x0000002cu, 0x00000001u, 0x0000000bu, 0x00000001u, 0x00050048u,
0x00040017u, 0x00000007u, 0x00000006u, 0x00000002u, 0x00040020u, 0x00000008u, 0x00000007u, 0x00000007u, 0x0000002cu, 0x00000002u, 0x0000000bu, 0x00000003u, 0x00050048u, 0x0000002cu, 0x00000003u, 0x0000000bu,
0x00040020u, 0x0000000au, 0x00000001u, 0x00000007u, 0x0004003bu, 0x0000000au, 0x0000000bu, 0x00000001u, 0x00000004u, 0x00030047u, 0x0000002cu, 0x00000002u, 0x00040047u, 0x00000036u, 0x0000001eu, 0x00000000u,
0x0006001eu, 0x0000000fu, 0x00000006u, 0x00000007u, 0x00000006u, 0x00000006u, 0x00040020u, 0x00000010u, 0x00040047u, 0x00000038u, 0x0000001eu, 0x00000001u, 0x00040047u, 0x0000003bu, 0x0000001eu, 0x00000001u,
0x00000002u, 0x0000000fu, 0x0004003bu, 0x00000010u, 0x00000011u, 0x00000002u, 0x00040015u, 0x00000012u, 0x00040047u, 0x0000003cu, 0x0000001eu, 0x00000002u, 0x00020013u, 0x00000002u, 0x00030021u, 0x00000003u,
0x00000020u, 0x00000001u, 0x0004002bu, 0x00000012u, 0x00000013u, 0x00000001u, 0x00040020u, 0x00000014u, 0x00000002u, 0x00030016u, 0x00000006u, 0x00000020u, 0x00040017u, 0x00000007u, 0x00000006u, 0x00000002u,
0x00000002u, 0x00000007u, 0x0004002bu, 0x00000006u, 0x00000018u, 0x40000000u, 0x0004002bu, 0x00000006u, 0x00040020u, 0x00000008u, 0x00000007u, 0x00000007u, 0x00040020u, 0x0000000au, 0x00000001u, 0x00000007u,
0x0000001au, 0x3f800000u, 0x00040015u, 0x0000001du, 0x00000020u, 0x00000000u, 0x0004002bu, 0x0000001du, 0x0004003bu, 0x0000000au, 0x0000000bu, 0x00000001u, 0x00040020u, 0x0000000du, 0x00000007u, 0x00000006u,
0x0000001eu, 0x00000001u, 0x00040020u, 0x0000001fu, 0x00000007u, 0x00000006u, 0x00040017u, 0x00000024u, 0x00040015u, 0x0000000fu, 0x00000020u, 0x00000000u, 0x0004002bu, 0x0000000fu, 0x00000010u, 0x00000000u,
0x00000006u, 0x00000004u, 0x0004001cu, 0x00000025u, 0x00000006u, 0x0000001eu, 0x0006001eu, 0x00000026u, 0x0009001eu, 0x00000013u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u,
0x00000024u, 0x00000006u, 0x00000025u, 0x00000025u, 0x00040020u, 0x00000027u, 0x00000003u, 0x00000026u, 0x00000006u, 0x00040020u, 0x00000014u, 0x00000002u, 0x00000013u, 0x0004003bu, 0x00000014u, 0x00000015u,
0x0004003bu, 0x00000027u, 0x00000028u, 0x00000003u, 0x0004002bu, 0x00000012u, 0x00000029u, 0x00000000u, 0x00000002u, 0x00040015u, 0x00000016u, 0x00000020u, 0x00000001u, 0x0004002bu, 0x00000016u, 0x00000017u,
0x0004002bu, 0x00000006u, 0x0000002bu, 0x00000000u, 0x00040020u, 0x0000002fu, 0x00000003u, 0x00000024u, 0x00000001u, 0x00040020u, 0x00000018u, 0x00000002u, 0x00000006u, 0x0004002bu, 0x00000006u, 0x0000001cu,
0x0004003bu, 0x0000002fu, 0x00000031u, 0x00000003u, 0x00040020u, 0x00000032u, 0x00000001u, 0x00000024u, 0x40000000u, 0x0004002bu, 0x00000006u, 0x0000001eu, 0x3f800000u, 0x0004002bu, 0x0000000fu, 0x00000021u,
0x0004003bu, 0x00000032u, 0x00000033u, 0x00000001u, 0x00040020u, 0x00000035u, 0x00000003u, 0x00000007u, 0x00000001u, 0x0004002bu, 0x00000016u, 0x00000024u, 0x00000002u, 0x00040017u, 0x0000002au, 0x00000006u,
0x0004003bu, 0x00000035u, 0x00000036u, 0x00000003u, 0x0004003bu, 0x0000000au, 0x00000037u, 0x00000001u, 0x00000004u, 0x0004001cu, 0x0000002bu, 0x00000006u, 0x00000021u, 0x0006001eu, 0x0000002cu, 0x0000002au,
0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200f8u, 0x00000005u, 0x0004003bu, 0x00000006u, 0x0000002bu, 0x0000002bu, 0x00040020u, 0x0000002du, 0x00000003u, 0x0000002cu, 0x0004003bu,
0x00000008u, 0x00000009u, 0x00000007u, 0x0004003bu, 0x00000008u, 0x0000000du, 0x00000007u, 0x0004003du, 0x0000002du, 0x0000002eu, 0x00000003u, 0x0004002bu, 0x00000016u, 0x0000002fu, 0x00000000u, 0x0004002bu,
0x00000007u, 0x0000000cu, 0x0000000bu, 0x0003003eu, 0x00000009u, 0x0000000cu, 0x0004003du, 0x00000007u, 0x00000006u, 0x00000032u, 0x00000000u, 0x00040020u, 0x00000034u, 0x00000003u, 0x0000002au, 0x0004003bu,
0x0000000eu, 0x00000009u, 0x00050041u, 0x00000014u, 0x00000015u, 0x00000011u, 0x00000013u, 0x0004003du, 0x00000034u, 0x00000036u, 0x00000003u, 0x00040020u, 0x00000037u, 0x00000001u, 0x0000002au, 0x0004003bu,
0x00000007u, 0x00000016u, 0x00000015u, 0x00050088u, 0x00000007u, 0x00000017u, 0x0000000eu, 0x00000016u, 0x00000037u, 0x00000038u, 0x00000001u, 0x00040020u, 0x0000003au, 0x00000003u, 0x00000007u, 0x0004003bu,
0x0005008eu, 0x00000007u, 0x00000019u, 0x00000017u, 0x00000018u, 0x00050050u, 0x00000007u, 0x0000001bu, 0x0000003au, 0x0000003bu, 0x00000003u, 0x0004003bu, 0x0000000au, 0x0000003cu, 0x00000001u, 0x00050036u,
0x0000001au, 0x0000001au, 0x00050083u, 0x00000007u, 0x0000001cu, 0x00000019u, 0x0000001bu, 0x0003003eu, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200f8u, 0x00000005u, 0x0004003bu, 0x00000008u,
0x0000000du, 0x0000001cu, 0x00050041u, 0x0000001fu, 0x00000020u, 0x0000000du, 0x0000001eu, 0x0004003du, 0x00000009u, 0x00000007u, 0x0004003bu, 0x0000000du, 0x0000000eu, 0x00000007u, 0x0004003bu, 0x0000000du,
0x00000006u, 0x00000021u, 0x00000020u, 0x0004007fu, 0x00000006u, 0x00000022u, 0x00000021u, 0x00050041u, 0x00000020u, 0x00000007u, 0x0004003du, 0x00000007u, 0x0000000cu, 0x0000000bu, 0x0003003eu, 0x00000009u,
0x0000001fu, 0x00000023u, 0x0000000du, 0x0000001eu, 0x0003003eu, 0x00000023u, 0x00000022u, 0x0004003du, 0x0000000cu, 0x00050041u, 0x0000000du, 0x00000011u, 0x00000009u, 0x00000010u, 0x0004003du, 0x00000006u,
0x00000007u, 0x0000002au, 0x0000000du, 0x00050051u, 0x00000006u, 0x0000002cu, 0x0000002au, 0x00000000u, 0x00000012u, 0x00000011u, 0x00050041u, 0x00000018u, 0x00000019u, 0x00000015u, 0x00000017u, 0x0004003du,
0x00050051u, 0x00000006u, 0x0000002du, 0x0000002au, 0x00000001u, 0x00070050u, 0x00000024u, 0x0000002eu, 0x00000006u, 0x0000001au, 0x00000019u, 0x00050088u, 0x00000006u, 0x0000001bu, 0x00000012u, 0x0000001au,
0x0000002cu, 0x0000002du, 0x0000002bu, 0x0000001au, 0x00050041u, 0x0000002fu, 0x00000030u, 0x00000028u, 0x00050085u, 0x00000006u, 0x0000001du, 0x0000001bu, 0x0000001cu, 0x00050083u, 0x00000006u, 0x0000001fu,
0x00000029u, 0x0003003eu, 0x00000030u, 0x0000002eu, 0x0004003du, 0x00000024u, 0x00000034u, 0x00000033u, 0x0000001du, 0x0000001eu, 0x0003003eu, 0x0000000eu, 0x0000001fu, 0x00050041u, 0x0000000du, 0x00000022u,
0x0003003eu, 0x00000031u, 0x00000034u, 0x0004003du, 0x00000007u, 0x00000038u, 0x00000037u, 0x0003003eu, 0x00000009u, 0x00000021u, 0x0004003du, 0x00000006u, 0x00000023u, 0x00000022u, 0x00050041u, 0x00000018u,
0x00000036u, 0x00000038u, 0x000100fdu, 0x00010038u 0x00000025u, 0x00000015u, 0x00000024u, 0x0004003du, 0x00000006u, 0x00000026u, 0x00000025u, 0x00050088u,
0x00000006u, 0x00000027u, 0x00000023u, 0x00000026u, 0x00050085u, 0x00000006u, 0x00000028u, 0x00000027u,
0x0000001cu, 0x00050083u, 0x00000006u, 0x00000029u, 0x00000028u, 0x0000001eu, 0x0003003eu, 0x00000020u,
0x00000029u, 0x0004003du, 0x00000006u, 0x00000030u, 0x0000000eu, 0x0004003du, 0x00000006u, 0x00000031u,
0x00000020u, 0x00070050u, 0x0000002au, 0x00000033u, 0x00000030u, 0x00000031u, 0x00000032u, 0x0000001eu,
0x00050041u, 0x00000034u, 0x00000035u, 0x0000002eu, 0x0000002fu, 0x0003003eu, 0x00000035u, 0x00000033u,
0x0004003du, 0x0000002au, 0x00000039u, 0x00000038u, 0x0003003eu, 0x00000036u, 0x00000039u, 0x0004003du,
0x00000007u, 0x0000003du, 0x0000003cu, 0x0003003eu, 0x0000003bu, 0x0000003du, 0x000100fdu, 0x00010038u

File diff suppressed because it is too large Load Diff

View File

@ -263,6 +263,11 @@ private:
std::vector<uint16_t>& indices, std::vector<uint16_t>& indices,
double wavePhase); double wavePhase);
/**
* @brief
*/
float calculateTextWidth(const std::string& text, float scale);
/** /**
* @brief * @brief
*/ */

View File

@ -56,95 +56,95 @@ VulkanWidget::VulkanWidget(QWidget *parent)
setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
// Create render timer // Create render timer
m_renderTimer = new QTimer(this); m_renderTimer = new QTimer(this);
connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer); connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer);
qDebug() << "VulkanWidget created"; qDebug() << "VulkanWidget created";
} }
VulkanWidget::~VulkanWidget() VulkanWidget::~VulkanWidget()
{ {
qDebug() << "VulkanWidget destroying..."; qDebug() << "VulkanWidget destroying...";
if (m_renderTimer) { if (m_renderTimer) {
m_renderTimer->stop(); m_renderTimer->stop();
} }
// Clean up renderer first // Clean up renderer first
if (m_renderer) { if (m_renderer) {
m_renderer->cleanup(); m_renderer->cleanup();
delete m_renderer; delete m_renderer;
m_renderer = nullptr; m_renderer = nullptr;
} }
cleanupVulkan(); cleanupVulkan();
qDebug() << "VulkanWidget destroyed"; qDebug() << "VulkanWidget destroyed";
} }
bool VulkanWidget::initializeVulkan() bool VulkanWidget::initializeVulkan()
{ {
qDebug() << "Initializing Vulkan..."; qDebug() << "Initializing Vulkan...";
if (m_initialized) { if (m_initialized) {
qDebug() << "Vulkan already initialized"; qDebug() << "Vulkan already initialized";
return true; return true;
} }
// Step 1: Initialize volk // Step 1: Initialize volk
if (!initializeVolk()) { if (!initializeVolk()) {
setError("Failed to initialize volk"); setError("Failed to initialize volk");
return false; return false;
} }
// Step 2: Create Vulkan instance // Step 2: Create Vulkan instance
if (!createInstance()) { if (!createInstance()) {
setError("Failed to create Vulkan instance"); setError("Failed to create Vulkan instance");
return false; return false;
} }
// Step 3: Create surface from native window // Step 3: Create surface from native window
if (!createSurface()) { if (!createSurface()) {
setError("Failed to create Vulkan surface"); setError("Failed to create Vulkan surface");
return false; return false;
} }
// Step 4: Select physical device // Step 4: Select physical device
if (!selectPhysicalDevice()) { if (!selectPhysicalDevice()) {
setError("Failed to select physical device"); setError("Failed to select physical device");
return false; return false;
} }
// Step 5: Create logical device // Step 5: Create logical device
if (!createDevice()) { if (!createDevice()) {
setError("Failed to create logical device"); setError("Failed to create logical device");
return false; return false;
} }
// Step 6: Create swapchain // Step 6: Create swapchain
if (!createSwapchain()) { if (!createSwapchain()) {
setError("Failed to create swapchain"); setError("Failed to create swapchain");
return false; return false;
} }
// Step 7: Create command objects // Step 7: Create command objects
if (!createCommandObjects()) { if (!createCommandObjects()) {
setError("Failed to create command objects"); setError("Failed to create command objects");
return false; return false;
} }
// Step 8: Create synchronization objects // Step 8: Create synchronization objects
if (!createSyncObjects()) { if (!createSyncObjects()) {
setError("Failed to create sync objects"); setError("Failed to create sync objects");
return false; return false;
} }
// Step 9: Create VulkanRenderer - but only if we have reasonable dimensions // Step 9: Create VulkanRenderer - but only if we have reasonable dimensions
if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) {
m_renderer = new VulkanRenderer(); m_renderer = new VulkanRenderer();
// Get swapchain format // Get swapchain format
VkSurfaceFormatKHR surfaceFormat; VkSurfaceFormatKHR surfaceFormat;
uint32_t formatCount = 0; uint32_t formatCount = 0;
@ -154,7 +154,7 @@ bool VulkanWidget::initializeVulkan()
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data());
surfaceFormat = formats[0]; surfaceFormat = formats[0];
} }
// Initialize renderer // Initialize renderer
if (!m_renderer->initialize(m_device, m_physicalDevice, if (!m_renderer->initialize(m_device, m_physicalDevice,
m_queue, m_queueFamilyIndex, m_queue, m_queueFamilyIndex,
@ -165,14 +165,14 @@ bool VulkanWidget::initializeVulkan()
m_renderer = nullptr; m_renderer = nullptr;
return false; return false;
} }
qDebug() << "VulkanRenderer initialized successfully!"; qDebug() << "VulkanRenderer initialized successfully!";
qDebug() << "Widget size:" << width() << "x" << height() qDebug() << "Widget size:" << width() << "x" << height()
<< "| Surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; << "| Surface size:" << m_surfaceWidth << "x" << m_surfaceHeight;
} else { } else {
qDebug() << "VulkanRenderer initialization deferred - window too small:" << m_surfaceWidth << "x" << m_surfaceHeight; qDebug() << "VulkanRenderer initialization deferred - window too small:" << m_surfaceWidth << "x" << m_surfaceHeight;
} }
m_initialized = true; m_initialized = true;
qDebug() << "Vulkan initialization successful!"; qDebug() << "Vulkan initialization successful!";
return true; return true;
@ -181,13 +181,13 @@ bool VulkanWidget::initializeVulkan()
bool VulkanWidget::initializeVolk() bool VulkanWidget::initializeVolk()
{ {
qDebug() << "Initializing volk..."; qDebug() << "Initializing volk...";
VkResult result = volkInitialize(); VkResult result = volkInitialize();
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to initialize volk, error code:" << result; qDebug() << "Failed to initialize volk, error code:" << result;
return false; return false;
} }
qDebug() << "Volk initialized successfully"; qDebug() << "Volk initialized successfully";
return true; return true;
} }
@ -195,7 +195,7 @@ bool VulkanWidget::initializeVolk()
bool VulkanWidget::createInstance() bool VulkanWidget::createInstance()
{ {
qDebug() << "Creating Vulkan instance..."; qDebug() << "Creating Vulkan instance...";
VkApplicationInfo appInfo = {}; VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "VulkanWidget"; appInfo.pApplicationName = "VulkanWidget";
@ -203,25 +203,25 @@ bool VulkanWidget::createInstance()
appInfo.pEngineName = "No Engine"; appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0; appInfo.apiVersion = VK_API_VERSION_1_0;
std::vector<const char*> extensions = getRequiredInstanceExtensions(); std::vector<const char*> extensions = getRequiredInstanceExtensions();
VkInstanceCreateInfo createInfo = {}; VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo; createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data(); createInfo.ppEnabledExtensionNames = extensions.data();
createInfo.enabledLayerCount = 0; createInfo.enabledLayerCount = 0;
VkResult result = vkCreateInstance(&createInfo, nullptr, &m_instance); VkResult result = vkCreateInstance(&createInfo, nullptr, &m_instance);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to create Vulkan instance, error code:" << result; qDebug() << "Failed to create Vulkan instance, error code:" << result;
return false; return false;
} }
// Load instance-level functions // Load instance-level functions
volkLoadInstance(m_instance); volkLoadInstance(m_instance);
qDebug() << "Vulkan instance created successfully"; qDebug() << "Vulkan instance created successfully";
return true; return true;
} }
@ -229,7 +229,7 @@ bool VulkanWidget::createInstance()
bool VulkanWidget::createSurface() bool VulkanWidget::createSurface()
{ {
qDebug() << "Creating Vulkan surface from native window..."; qDebug() << "Creating Vulkan surface from native window...";
if (!windowHandle()) { if (!windowHandle()) {
qDebug() << "Window handle not available, creating window..."; qDebug() << "Window handle not available, creating window...";
create(); create();
@ -238,17 +238,17 @@ bool VulkanWidget::createSurface()
return false; return false;
} }
} }
QWindow *window = windowHandle(); QWindow *window = windowHandle();
#ifdef _WIN32 #ifdef _WIN32
VkWin32SurfaceCreateInfoKHR createInfo = {}; VkWin32SurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.hwnd = reinterpret_cast<HWND>(window->winId()); createInfo.hwnd = reinterpret_cast<HWND>(window->winId());
createInfo.hinstance = GetModuleHandle(nullptr); createInfo.hinstance = GetModuleHandle(nullptr);
VkResult result = vkCreateWin32SurfaceKHR(m_instance, &createInfo, nullptr, &m_surface); VkResult result = vkCreateWin32SurfaceKHR(m_instance, &createInfo, nullptr, &m_surface);
#elif defined(__linux__) #elif defined(__linux__)
VkXlibSurfaceCreateInfoKHR createInfo = {}; VkXlibSurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
@ -259,26 +259,26 @@ bool VulkanWidget::createSurface()
return false; return false;
} }
createInfo.window = static_cast<Window>(window->winId()); createInfo.window = static_cast<Window>(window->winId());
VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface); VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface);
#elif defined(__APPLE__) #elif defined(__APPLE__)
// macOS requires MoltenVK and Metal // macOS requires MoltenVK and Metal
VkMetalSurfaceCreateInfoEXT createInfo = {}; VkMetalSurfaceCreateInfoEXT createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
createInfo.pLayer = nullptr; // This needs proper Metal layer setup createInfo.pLayer = nullptr; // This needs proper Metal layer setup
VkResult result = vkCreateMetalSurfaceEXT(m_instance, &createInfo, nullptr, &m_surface); VkResult result = vkCreateMetalSurfaceEXT(m_instance, &createInfo, nullptr, &m_surface);
#else #else
qDebug() << "Unsupported platform for Vulkan surface creation"; qDebug() << "Unsupported platform for Vulkan surface creation";
return false; return false;
#endif #endif
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to create Vulkan surface, error code:" << result; qDebug() << "Failed to create Vulkan surface, error code:" << result;
return false; return false;
} }
qDebug() << "Vulkan surface created successfully"; qDebug() << "Vulkan surface created successfully";
return true; return true;
} }
@ -286,28 +286,28 @@ bool VulkanWidget::createSurface()
bool VulkanWidget::selectPhysicalDevice() bool VulkanWidget::selectPhysicalDevice()
{ {
qDebug() << "Selecting physical device..."; qDebug() << "Selecting physical device...";
uint32_t deviceCount = 0; uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr); vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
if (deviceCount == 0) { if (deviceCount == 0) {
qDebug() << "Failed to find GPUs with Vulkan support"; qDebug() << "Failed to find GPUs with Vulkan support";
return false; return false;
} }
std::vector<VkPhysicalDevice> devices(deviceCount); std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data()); vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data());
// Select the first suitable device // Select the first suitable device
for (const auto& device : devices) { for (const auto& device : devices) {
VkPhysicalDeviceProperties properties; VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(device, &properties); vkGetPhysicalDeviceProperties(device, &properties);
qDebug() << "Found device:" << properties.deviceName; qDebug() << "Found device:" << properties.deviceName;
// Temporarily set physical device to check queue families // Temporarily set physical device to check queue families
m_physicalDevice = device; m_physicalDevice = device;
// Check if device supports our queue family // Check if device supports our queue family
uint32_t queueFamilyIndex; uint32_t queueFamilyIndex;
if (findQueueFamily(queueFamilyIndex)) { if (findQueueFamily(queueFamilyIndex)) {
@ -316,7 +316,7 @@ bool VulkanWidget::selectPhysicalDevice()
return true; return true;
} }
} }
// Reset if no suitable device found // Reset if no suitable device found
m_physicalDevice = VK_NULL_HANDLE; m_physicalDevice = VK_NULL_HANDLE;
qDebug() << "Failed to find suitable physical device"; qDebug() << "Failed to find suitable physical device";
@ -327,42 +327,42 @@ bool VulkanWidget::findQueueFamily(uint32_t &queueFamilyIndex)
{ {
uint32_t queueFamilyCount = 0; uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies.data()); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies.data());
for (uint32_t i = 0; i < queueFamilyCount; i++) { for (uint32_t i = 0; i < queueFamilyCount; i++) {
// Check if queue family supports graphics // Check if queue family supports graphics
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
// Check if queue family supports presentation // Check if queue family supports presentation
VkBool32 presentSupport = false; VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &presentSupport); vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &presentSupport);
if (presentSupport) { if (presentSupport) {
queueFamilyIndex = i; queueFamilyIndex = i;
return true; return true;
} }
} }
} }
return false; return false;
} }
bool VulkanWidget::createDevice() bool VulkanWidget::createDevice()
{ {
qDebug() << "Creating logical device..."; qDebug() << "Creating logical device...";
float queuePriority = 1.0f; float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo = {}; VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = m_queueFamilyIndex; queueCreateInfo.queueFamilyIndex = m_queueFamilyIndex;
queueCreateInfo.queueCount = 1; queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority; queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {}; VkPhysicalDeviceFeatures deviceFeatures = {};
std::vector<const char*> deviceExtensions = getRequiredDeviceExtensions(); std::vector<const char*> deviceExtensions = getRequiredDeviceExtensions();
VkDeviceCreateInfo createInfo = {}; VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.pQueueCreateInfos = &queueCreateInfo;
@ -371,19 +371,19 @@ bool VulkanWidget::createDevice()
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledLayerCount = 0; createInfo.enabledLayerCount = 0;
VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device); VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to create logical device, error code:" << result; qDebug() << "Failed to create logical device, error code:" << result;
return false; return false;
} }
// Load device-level functions // Load device-level functions
volkLoadDevice(m_device); volkLoadDevice(m_device);
// Get queue handle // Get queue handle
vkGetDeviceQueue(m_device, m_queueFamilyIndex, 0, &m_queue); vkGetDeviceQueue(m_device, m_queueFamilyIndex, 0, &m_queue);
qDebug() << "Logical device created successfully"; qDebug() << "Logical device created successfully";
return true; return true;
} }
@ -393,40 +393,40 @@ bool VulkanWidget::createSwapchain()
qDebug() << "Creating swapchain..."; qDebug() << "Creating swapchain...";
qDebug() << "Widget size:" << width() << "x" << height(); qDebug() << "Widget size:" << width() << "x" << height();
qDebug() << "Device pixel ratio:" << devicePixelRatioF(); qDebug() << "Device pixel ratio:" << devicePixelRatioF();
// Query surface capabilities // Query surface capabilities
VkSurfaceCapabilitiesKHR capabilities; VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities);
qDebug() << "Surface capabilities - current extent:" qDebug() << "Surface capabilities - current extent:"
<< capabilities.currentExtent.width << "x" << capabilities.currentExtent.height; << capabilities.currentExtent.width << "x" << capabilities.currentExtent.height;
qDebug() << "Surface capabilities - min extent:" qDebug() << "Surface capabilities - min extent:"
<< capabilities.minImageExtent.width << "x" << capabilities.minImageExtent.height; << capabilities.minImageExtent.width << "x" << capabilities.minImageExtent.height;
qDebug() << "Surface capabilities - max extent:" qDebug() << "Surface capabilities - max extent:"
<< capabilities.maxImageExtent.width << "x" << capabilities.maxImageExtent.height; << capabilities.maxImageExtent.width << "x" << capabilities.maxImageExtent.height;
// Query surface formats // Query surface formats
uint32_t formatCount; uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr);
std::vector<VkSurfaceFormatKHR> formats(formatCount); std::vector<VkSurfaceFormatKHR> formats(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data());
// Query present modes // Query present modes
uint32_t presentModeCount; uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, nullptr); vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, nullptr);
std::vector<VkPresentModeKHR> presentModes(presentModeCount); std::vector<VkPresentModeKHR> presentModes(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, presentModes.data()); vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, presentModes.data());
// Select format // Select format
VkSurfaceFormatKHR surfaceFormat = formats[0]; VkSurfaceFormatKHR surfaceFormat = formats[0];
for (const auto& format : formats) { for (const auto& format : formats) {
if (format.format == VK_FORMAT_B8G8R8A8_SRGB && if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
surfaceFormat = format; surfaceFormat = format;
break; break;
} }
} }
// Select present mode (prefer mailbox, fallback to FIFO) // Select present mode (prefer mailbox, fallback to FIFO)
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
for (const auto& mode : presentModes) { for (const auto& mode : presentModes) {
@ -435,7 +435,7 @@ bool VulkanWidget::createSwapchain()
break; break;
} }
} }
// Determine extent // Determine extent
VkExtent2D extent; VkExtent2D extent;
if (capabilities.currentExtent.width != UINT32_MAX) { if (capabilities.currentExtent.width != UINT32_MAX) {
@ -445,27 +445,27 @@ bool VulkanWidget::createSwapchain()
// Calculate extent based on widget size with DPI scaling // Calculate extent based on widget size with DPI scaling
uint32_t pixelWidth = static_cast<uint32_t>(width() * devicePixelRatioF()); uint32_t pixelWidth = static_cast<uint32_t>(width() * devicePixelRatioF());
uint32_t pixelHeight = static_cast<uint32_t>(height() * devicePixelRatioF()); uint32_t pixelHeight = static_cast<uint32_t>(height() * devicePixelRatioF());
extent.width = std::max(capabilities.minImageExtent.width, extent.width = std::max(capabilities.minImageExtent.width,
std::min(capabilities.maxImageExtent.width, pixelWidth)); std::min(capabilities.maxImageExtent.width, pixelWidth));
extent.height = std::max(capabilities.minImageExtent.height, extent.height = std::max(capabilities.minImageExtent.height,
std::min(capabilities.maxImageExtent.height, pixelHeight)); std::min(capabilities.maxImageExtent.height, pixelHeight));
qDebug() << "Calculated extent from widget:" << extent.width << "x" << extent.height qDebug() << "Calculated extent from widget:" << extent.width << "x" << extent.height
<< "(widget:" << width() << "x" << height() << "(widget:" << width() << "x" << height()
<< "* DPR:" << devicePixelRatioF() << ")"; << "* DPR:" << devicePixelRatioF() << ")";
} }
m_surfaceWidth = extent.width; m_surfaceWidth = extent.width;
m_surfaceHeight = extent.height; m_surfaceHeight = extent.height;
qDebug() << "Final swapchain extent:" << m_surfaceWidth << "x" << m_surfaceHeight; qDebug() << "Final swapchain extent:" << m_surfaceWidth << "x" << m_surfaceHeight;
// Determine image count // Determine image count
uint32_t imageCount = capabilities.minImageCount + 1; uint32_t imageCount = capabilities.minImageCount + 1;
if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
imageCount = capabilities.maxImageCount; imageCount = capabilities.maxImageCount;
} }
VkSwapchainCreateInfoKHR createInfo = {}; VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = m_surface; createInfo.surface = m_surface;
@ -481,19 +481,19 @@ bool VulkanWidget::createSwapchain()
createInfo.presentMode = presentMode; createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE; createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE; createInfo.oldSwapchain = VK_NULL_HANDLE;
VkResult result = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapchain); VkResult result = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapchain);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to create swapchain, error code:" << result; qDebug() << "Failed to create swapchain, error code:" << result;
return false; return false;
} }
// Retrieve swapchain images // Retrieve swapchain images
vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, nullptr); vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, nullptr);
m_swapchainImages.resize(imageCount); m_swapchainImages.resize(imageCount);
vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount,
reinterpret_cast<VkImage*>(m_swapchainImages.data())); reinterpret_cast<VkImage*>(m_swapchainImages.data()));
// Create image views for swapchain images // Create image views for swapchain images
m_swapchainImageViews.resize(imageCount); m_swapchainImageViews.resize(imageCount);
for (uint32_t i = 0; i < imageCount; i++) { for (uint32_t i = 0; i < imageCount; i++) {
@ -511,7 +511,7 @@ bool VulkanWidget::createSwapchain()
viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1; viewInfo.subresourceRange.layerCount = 1;
VkImageView imageView; VkImageView imageView;
result = vkCreateImageView(m_device, &viewInfo, nullptr, &imageView); result = vkCreateImageView(m_device, &viewInfo, nullptr, &imageView);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
@ -520,42 +520,42 @@ bool VulkanWidget::createSwapchain()
} }
m_swapchainImageViews[i] = reinterpret_cast<void*>(imageView); m_swapchainImageViews[i] = reinterpret_cast<void*>(imageView);
} }
qDebug() << "Swapchain created successfully with" << imageCount << "images, size:" qDebug() << "Swapchain created successfully with" << imageCount << "images, size:"
<< m_surfaceWidth << "x" << m_surfaceHeight; << m_surfaceWidth << "x" << m_surfaceHeight;
return true; return true;
} }
bool VulkanWidget::createCommandObjects() bool VulkanWidget::createCommandObjects()
{ {
qDebug() << "Creating command objects..."; qDebug() << "Creating command objects...";
VkCommandPoolCreateInfo poolInfo = {}; VkCommandPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.queueFamilyIndex = m_queueFamilyIndex; poolInfo.queueFamilyIndex = m_queueFamilyIndex;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkResult result = vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool); VkResult result = vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to create command pool, error code:" << result; qDebug() << "Failed to create command pool, error code:" << result;
return false; return false;
} }
m_commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); m_commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
VkCommandBufferAllocateInfo allocInfo = {}; VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = m_commandPool; allocInfo.commandPool = m_commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = static_cast<uint32_t>(m_commandBuffers.size()); allocInfo.commandBufferCount = static_cast<uint32_t>(m_commandBuffers.size());
result = vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data()); result = vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data());
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to allocate command buffers, error code:" << result; qDebug() << "Failed to allocate command buffers, error code:" << result;
return false; return false;
} }
qDebug() << "Command objects created successfully"; qDebug() << "Command objects created successfully";
return true; return true;
} }
@ -563,18 +563,18 @@ bool VulkanWidget::createCommandObjects()
bool VulkanWidget::createSyncObjects() bool VulkanWidget::createSyncObjects()
{ {
qDebug() << "Creating synchronization objects..."; qDebug() << "Creating synchronization objects...";
m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); m_imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); m_renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); m_inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
VkSemaphoreCreateInfo semaphoreInfo = {}; VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fenceInfo = {}; VkFenceCreateInfo fenceInfo = {};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS || if (vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]) != VK_SUCCESS ||
vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS || vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]) != VK_SUCCESS ||
@ -583,7 +583,7 @@ bool VulkanWidget::createSyncObjects()
return false; return false;
} }
} }
qDebug() << "Synchronization objects created successfully"; qDebug() << "Synchronization objects created successfully";
return true; return true;
} }
@ -591,25 +591,25 @@ bool VulkanWidget::createSyncObjects()
bool VulkanWidget::recreateSwapchain() bool VulkanWidget::recreateSwapchain()
{ {
qDebug() << "Recreating swapchain..."; qDebug() << "Recreating swapchain...";
// Wait for device to be idle // Wait for device to be idle
vkDeviceWaitIdle(m_device); vkDeviceWaitIdle(m_device);
// Cleanup old swapchain // Cleanup old swapchain
cleanupSwapchain(); cleanupSwapchain();
// Create new swapchain // Create new swapchain
if (!createSwapchain()) { if (!createSwapchain()) {
qDebug() << "Failed to recreate swapchain"; qDebug() << "Failed to recreate swapchain";
return false; return false;
} }
// Update renderer with new surface dimensions // Update renderer with new surface dimensions
if (m_renderer) { if (m_renderer) {
qDebug() << "Updating VulkanRenderer to surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; qDebug() << "Updating VulkanRenderer to surface size:" << m_surfaceWidth << "x" << m_surfaceHeight;
m_renderer->resize(m_surfaceWidth, m_surfaceHeight); m_renderer->resize(m_surfaceWidth, m_surfaceHeight);
} }
qDebug() << "Swapchain recreated successfully"; qDebug() << "Swapchain recreated successfully";
return true; return true;
} }
@ -619,16 +619,16 @@ void VulkanWidget::renderFrame()
if (!m_initialized || !m_renderingEnabled) { if (!m_initialized || !m_renderingEnabled) {
return; return;
} }
// Wait for previous frame // Wait for previous frame
vkWaitForFences(m_device, 1, &m_inFlightFences[m_currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(m_device, 1, &m_inFlightFences[m_currentFrame], VK_TRUE, UINT64_MAX);
// Acquire next image // Acquire next image
uint32_t imageIndex; uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, VkResult result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX,
m_imageAvailableSemaphores[m_currentFrame], m_imageAvailableSemaphores[m_currentFrame],
VK_NULL_HANDLE, &imageIndex); VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapchain(); recreateSwapchain();
return; return;
@ -636,18 +636,18 @@ void VulkanWidget::renderFrame()
qDebug() << "Failed to acquire swapchain image"; qDebug() << "Failed to acquire swapchain image";
return; return;
} }
// Reset fence // Reset fence
vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]); vkResetFences(m_device, 1, &m_inFlightFences[m_currentFrame]);
// Record command buffer // Record command buffer
vkResetCommandBuffer(m_commandBuffers[m_currentFrame], 0); vkResetCommandBuffer(m_commandBuffers[m_currentFrame], 0);
recordCommandBuffer(m_commandBuffers[m_currentFrame], imageIndex); recordCommandBuffer(m_commandBuffers[m_currentFrame], imageIndex);
// Submit command buffer // Submit command buffer
VkSubmitInfo submitInfo = {}; VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {m_imageAvailableSemaphores[m_currentFrame]}; VkSemaphore waitSemaphores[] = {m_imageAvailableSemaphores[m_currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
@ -655,37 +655,37 @@ void VulkanWidget::renderFrame()
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &m_commandBuffers[m_currentFrame]; submitInfo.pCommandBuffers = &m_commandBuffers[m_currentFrame];
VkSemaphore signalSemaphores[] = {m_renderFinishedSemaphores[m_currentFrame]}; VkSemaphore signalSemaphores[] = {m_renderFinishedSemaphores[m_currentFrame]};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]); result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to submit draw command buffer"; qDebug() << "Failed to submit draw command buffer";
return; return;
} }
// Present // Present
VkPresentInfoKHR presentInfo = {}; VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1; presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores; presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapchains[] = {m_swapchain}; VkSwapchainKHR swapchains[] = {m_swapchain};
presentInfo.swapchainCount = 1; presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapchains; presentInfo.pSwapchains = swapchains;
presentInfo.pImageIndices = &imageIndex; presentInfo.pImageIndices = &imageIndex;
result = vkQueuePresentKHR(m_queue, &presentInfo); result = vkQueuePresentKHR(m_queue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_needsResize) { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_needsResize) {
m_needsResize = false; m_needsResize = false;
recreateSwapchain(); recreateSwapchain();
} else if (result != VK_SUCCESS) { } else if (result != VK_SUCCESS) {
qDebug() << "Failed to present swapchain image"; qDebug() << "Failed to present swapchain image";
} }
m_currentFrame = (m_currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; m_currentFrame = (m_currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
m_frameCount++; m_frameCount++;
} }
@ -696,7 +696,7 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
if (!m_renderer && m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { if (!m_renderer && m_surfaceWidth >= 100 && m_surfaceHeight >= 100) {
qDebug() << "Creating deferred VulkanRenderer with actual surface size:" << m_surfaceWidth << "x" << m_surfaceHeight; qDebug() << "Creating deferred VulkanRenderer with actual surface size:" << m_surfaceWidth << "x" << m_surfaceHeight;
m_renderer = new VulkanRenderer(); m_renderer = new VulkanRenderer();
VkSurfaceFormatKHR surfaceFormat; VkSurfaceFormatKHR surfaceFormat;
uint32_t formatCount = 0; uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr);
@ -705,7 +705,7 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data());
surfaceFormat = formats[0]; surfaceFormat = formats[0];
} }
if (!m_renderer->initialize(m_device, m_physicalDevice, if (!m_renderer->initialize(m_device, m_physicalDevice,
m_queue, m_queueFamilyIndex, m_queue, m_queueFamilyIndex,
static_cast<uint32_t>(surfaceFormat.format), static_cast<uint32_t>(surfaceFormat.format),
@ -714,48 +714,50 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
delete m_renderer; delete m_renderer;
m_renderer = nullptr; m_renderer = nullptr;
} else { } else {
qDebug() << "Deferred VulkanRenderer initialized successfully with surface size:" qDebug() << "Deferred VulkanRenderer initialized successfully with surface size:"
<< m_surfaceWidth << "x" << m_surfaceHeight; << m_surfaceWidth << "x" << m_surfaceHeight;
} }
} }
// Use VulkanRenderer if available // Use VulkanRenderer if available
if (m_renderer) { if (m_renderer) {
if (imageIndex >= m_swapchainImageViews.size()) { if (imageIndex >= m_swapchainImageViews.size()) {
qDebug() << "ERROR: imageIndex out of bounds!"; qDebug() << "ERROR: imageIndex out of bounds!";
return; return;
} }
VkImageView imageView = reinterpret_cast<VkImageView>(m_swapchainImageViews[imageIndex]); VkImageView imageView = reinterpret_cast<VkImageView>(m_swapchainImageViews[imageIndex]);
// Build lock info string // Build lock info string
QString lockInfo; QString lockInfo;
if (m_lastLockTime.isValid()) { if (m_lastLockTime.isValid()) {
lockInfo = QString("Last Lock: %1\nDuration: %2s\nLock Count: %3") lockInfo = QString("Last Lock: %1\nDuration: %2s\nFrame Count at Lock: %3\nFrames During Lock: %4\nLock Count: %5")
.arg(m_lastLockTime.toString("hh:mm:ss")) .arg(m_lastLockTime.toString("hh:mm:ss"))
.arg(m_lastLockDuration) .arg(m_lastLockDuration)
.arg(m_lastLockFrameCount)
.arg(m_lockPaintFrameCount)
.arg(m_lockCount); .arg(m_lockCount);
} }
// Debug: Print dimensions occasionally to check for mismatch // Debug: Print dimensions occasionally to check for mismatch
static int debugCounter = 0; static int debugCounter = 0;
if (debugCounter++ % 300 == 0) { // Every ~5 seconds at 60fps if (debugCounter++ % 300 == 0) { // Every ~5 seconds at 60fps
qDebug() << "Rendering - Widget:" << width() << "x" << height() qDebug() << "Rendering - Widget:" << width() << "x" << height()
<< "| Surface:" << m_surfaceWidth << "x" << m_surfaceHeight; << "| Surface:" << m_surfaceWidth << "x" << m_surfaceHeight;
} }
m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView, m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView,
m_frameCount, m_rotationAngle, m_wavePhase, m_frameCount, m_rotationAngle, m_wavePhase,
m_renderingEnabled, lockInfo.toStdString()); m_renderingEnabled, lockInfo.toStdString());
return; return;
} }
// Fallback: Simple clear color pass // Fallback: Simple clear color pass
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vkBeginCommandBuffer(commandBuffer, &beginInfo); vkBeginCommandBuffer(commandBuffer, &beginInfo);
VkClearColorValue clearColor; VkClearColorValue clearColor;
float hue = (m_frameCount % 360) / 360.0f; float hue = (m_frameCount % 360) / 360.0f;
float r = std::abs(std::sin(hue * 6.28318f)); float r = std::abs(std::sin(hue * 6.28318f));
@ -765,16 +767,16 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
clearColor.float32[1] = g * 0.5f + 0.1f; clearColor.float32[1] = g * 0.5f + 0.1f;
clearColor.float32[2] = b * 0.5f + 0.1f; clearColor.float32[2] = b * 0.5f + 0.1f;
clearColor.float32[3] = 1.0f; clearColor.float32[3] = 1.0f;
VkImageSubresourceRange range = {}; VkImageSubresourceRange range = {};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0; range.baseMipLevel = 0;
range.levelCount = 1; range.levelCount = 1;
range.baseArrayLayer = 0; range.baseArrayLayer = 0;
range.layerCount = 1; range.layerCount = 1;
VkImage image = reinterpret_cast<VkImage>(m_swapchainImages[imageIndex]); VkImage image = reinterpret_cast<VkImage>(m_swapchainImages[imageIndex]);
VkImageMemoryBarrier barrier1 = {}; VkImageMemoryBarrier barrier1 = {};
barrier1.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier1.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier1.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier1.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -785,13 +787,13 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
barrier1.subresourceRange = range; barrier1.subresourceRange = range;
barrier1.srcAccessMask = 0; barrier1.srcAccessMask = 0;
barrier1.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier1.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier1); VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier1);
vkCmdClearColorImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vkCmdClearColorImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearColor, 1, &range); &clearColor, 1, &range);
VkImageMemoryBarrier barrier2 = {}; VkImageMemoryBarrier barrier2 = {};
barrier2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier2.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier2.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@ -802,10 +804,10 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
barrier2.subresourceRange = range; barrier2.subresourceRange = range;
barrier2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier2.dstAccessMask = 0; barrier2.dstAccessMask = 0;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier2); VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier2);
vkEndCommandBuffer(commandBuffer); vkEndCommandBuffer(commandBuffer);
} }
@ -818,12 +820,12 @@ void VulkanWidget::cleanupSwapchain()
} }
} }
m_swapchainImageViews.clear(); m_swapchainImageViews.clear();
if (m_swapchain != VK_NULL_HANDLE) { if (m_swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr); vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE; m_swapchain = VK_NULL_HANDLE;
} }
m_swapchainImages.clear(); m_swapchainImages.clear();
} }
@ -832,11 +834,11 @@ void VulkanWidget::cleanupVulkan()
if (!m_initialized) { if (!m_initialized) {
return; return;
} }
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
vkDeviceWaitIdle(m_device); vkDeviceWaitIdle(m_device);
} }
// Cleanup sync objects // Cleanup sync objects
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (m_imageAvailableSemaphores[i] != VK_NULL_HANDLE) { if (m_imageAvailableSemaphores[i] != VK_NULL_HANDLE) {
@ -849,30 +851,30 @@ void VulkanWidget::cleanupVulkan()
vkDestroyFence(m_device, m_inFlightFences[i], nullptr); vkDestroyFence(m_device, m_inFlightFences[i], nullptr);
} }
} }
// Cleanup command pool // Cleanup command pool
if (m_commandPool != VK_NULL_HANDLE) { if (m_commandPool != VK_NULL_HANDLE) {
vkDestroyCommandPool(m_device, m_commandPool, nullptr); vkDestroyCommandPool(m_device, m_commandPool, nullptr);
} }
// Cleanup swapchain // Cleanup swapchain
cleanupSwapchain(); cleanupSwapchain();
// Cleanup device // Cleanup device
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
vkDestroyDevice(m_device, nullptr); vkDestroyDevice(m_device, nullptr);
} }
// Cleanup surface // Cleanup surface
if (m_surface != VK_NULL_HANDLE) { if (m_surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
} }
// Cleanup instance // Cleanup instance
if (m_instance != VK_NULL_HANDLE) { if (m_instance != VK_NULL_HANDLE) {
vkDestroyInstance(m_instance, nullptr); vkDestroyInstance(m_instance, nullptr);
} }
m_initialized = false; m_initialized = false;
qDebug() << "Vulkan cleanup complete"; qDebug() << "Vulkan cleanup complete";
} }
@ -882,13 +884,13 @@ void VulkanWidget::setRenderingEnabled(bool enabled)
if (m_renderingEnabled == enabled) { if (m_renderingEnabled == enabled) {
return; return;
} }
m_renderingEnabled = enabled; m_renderingEnabled = enabled;
if (m_renderingEnabled) { if (m_renderingEnabled) {
qDebug() << "Vulkan rendering ENABLED - Resuming animations"; qDebug() << "Vulkan rendering ENABLED - Resuming animations";
m_renderTimer->start(16); // ~60 FPS m_renderTimer->start(16); // ~60 FPS
// Unlocked: calculate lock duration // Unlocked: calculate lock duration
if (m_lastLockTime.isValid()) { if (m_lastLockTime.isValid()) {
QDateTime unlockTime = QDateTime::currentDateTime(); QDateTime unlockTime = QDateTime::currentDateTime();
@ -898,12 +900,12 @@ void VulkanWidget::setRenderingEnabled(bool enabled)
qDebug() << "Frames at lock:" << m_lastLockFrameCount qDebug() << "Frames at lock:" << m_lastLockFrameCount
<< "- Frames painted during lock:" << m_lockPaintFrameCount; << "- Frames painted during lock:" << m_lockPaintFrameCount;
} }
m_startTime = QDateTime::currentDateTime(); m_startTime = QDateTime::currentDateTime();
} else { } else {
qDebug() << "Vulkan rendering DISABLED - Stopping animations"; qDebug() << "Vulkan rendering DISABLED - Stopping animations";
m_renderTimer->stop(); m_renderTimer->stop();
// Locked: record lock time // Locked: record lock time
m_pauseTime = QDateTime::currentDateTime(); m_pauseTime = QDateTime::currentDateTime();
m_lastLockTime = m_pauseTime; m_lastLockTime = m_pauseTime;
@ -934,7 +936,7 @@ void VulkanWidget::resetFrameCount()
void VulkanWidget::showEvent(QShowEvent *event) void VulkanWidget::showEvent(QShowEvent *event)
{ {
QWidget::showEvent(event); QWidget::showEvent(event);
if (!m_initialized) { if (!m_initialized) {
initializeVulkan(); initializeVulkan();
} }
@ -949,12 +951,12 @@ void VulkanWidget::hideEvent(QHideEvent *event)
void VulkanWidget::resizeEvent(QResizeEvent *event) void VulkanWidget::resizeEvent(QResizeEvent *event)
{ {
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
if (m_initialized) { if (m_initialized) {
m_needsResize = true; m_needsResize = true;
// Note: Don't update renderer size here - it will be updated after swapchain recreation // Note: Don't update renderer size here - it will be updated after swapchain recreation
// The renderer must use the actual surface dimensions (m_surfaceWidth/Height), // The renderer must use the actual surface dimensions (m_surfaceWidth/Height),
// not the widget dimensions, which may differ on high DPI displays // not the widget dimensions, which may differ on high DPI displays
} }
} }
@ -979,13 +981,13 @@ void VulkanWidget::onRenderTimer()
if (m_rotationAngle >= 360.0) { if (m_rotationAngle >= 360.0) {
m_rotationAngle -= 360.0; m_rotationAngle -= 360.0;
} }
m_wavePhase += 0.05; m_wavePhase += 0.05;
if (m_wavePhase >= 2 * M_PI) { if (m_wavePhase >= 2 * M_PI) {
m_wavePhase -= 2 * M_PI; m_wavePhase -= 2 * M_PI;
} }
} }
renderFrame(); renderFrame();
} }
@ -998,9 +1000,9 @@ void VulkanWidget::setError(const QString &error)
std::vector<const char*> VulkanWidget::getRequiredInstanceExtensions() std::vector<const char*> VulkanWidget::getRequiredInstanceExtensions()
{ {
std::vector<const char*> extensions; std::vector<const char*> extensions;
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32 #ifdef _WIN32
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif defined(__linux__) #elif defined(__linux__)
@ -1008,7 +1010,7 @@ std::vector<const char*> VulkanWidget::getRequiredInstanceExtensions()
#elif defined(__APPLE__) #elif defined(__APPLE__)
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME); extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
#endif #endif
return extensions; return extensions;
} }
@ -1017,4 +1019,4 @@ std::vector<const char*> VulkanWidget::getRequiredDeviceExtensions()
std::vector<const char*> extensions; std::vector<const char*> extensions;
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
return extensions; return extensions;
} }

View File

@ -26,7 +26,7 @@ typedef VkFlags VkSurfaceTransformFlagsKHR;
/** /**
* @brief Vulkan渲染组件类 * @brief Vulkan渲染组件类
* *
* 使Qt的native window属性创建Vulkan Surface * 使Qt的native window属性创建Vulkan Surface
* volk机制加载Vulkan函数 * volk机制加载Vulkan函数
*/ */
@ -249,7 +249,7 @@ private:
// VulkanRenderer // VulkanRenderer
VulkanRenderer *m_renderer; VulkanRenderer *m_renderer;
// 动画参数 // 动画参数
double m_rotationAngle; double m_rotationAngle;
double m_wavePhase; double m_wavePhase;
@ -265,4 +265,4 @@ private:
static const int MAX_FRAMES_IN_FLIGHT = 2; static const int MAX_FRAMES_IN_FLIGHT = 2;
}; };
#endif // VULKANWIDGET_H #endif // VULKANWIDGET_H