Compare commits

..

No commits in common. "fd9c1c89e6df3f50e91f008068bb7d49e1e43ab0" and "e8b9571d2565ad8915b63bd2694f1c4b58cf5093" have entirely different histories.

13 changed files with 329 additions and 1562 deletions

View File

@ -60,15 +60,6 @@ endif()
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
option(ENABLE_VULKAN "Enable Vulkan support" ON)
set(VULKAN_FOUND FALSE)
@ -199,13 +190,6 @@ if(VULKAN_FOUND)
target_link_libraries(${PROJECT_NAME}
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()
# Platform-specific linking
@ -251,12 +235,6 @@ if(VULKAN_FOUND)
message(STATUS "Vulkan headers: ${VULKAN_HEADERS_DIR}")
message(STATUS "Volk directory: ${VOLK_DIR}")
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()
message(STATUS "Vulkan support: DISABLED")
endif()

View File

@ -1,186 +0,0 @@
# 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

View File

@ -1,141 +0,0 @@
#!/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
float t = ubo.time / 360.0;
// Calculate color components matching Qt CustomWidget
float r = 0.392 + 0.196 * sin(t * 6.28318);
float g = 0.588 + 0.196 * sin(t * 6.28318 + 1.047);
float b = 0.784 + 0.216 * sin(t * 6.28318 + 2.094);
// Calculate color components with sine waves
float r = 0.39 + 0.20 * sin(t * 6.28318);
float g = 0.59 + 0.20 * sin(t * 6.28318 + 1.047);
float b = 0.78 + 0.22 * sin(t * 6.28318 + 2.094);
vec3 color1 = vec3(r, g, b);
vec3 color2 = vec3(0.118, 0.118, 0.235);
vec3 color2 = vec3(0.12, 0.12, 0.24);
// Linear gradient from top-left to bottom-right
float gradient = uv.x * 0.5 + uv.y * 0.5;

View File

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

View File

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

Binary file not shown.

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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