我目前正在开发一个Vulkan程序,我希望将其用作游戏引擎,但距离目标还很遥远。第一步,我只是尝试使用动态结构列表来渲染三角形,以获取诸如顶点和着色器之类的数据。为了解决特定于平台的障碍,我使用GLFW创建窗口和Vulkan曲面。
现在,我正尝试从文件中加载SPIR-V着色器,并使用它们创建VkShaderModule
,将在渲染管道中使用它们。目前,我代码的抽象部分是这样开始的:
main.c
#include "application.h"
#include "config.h"
#include "engine_vulkan.h"
#include "glfw/glfw3.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
printf("VLK Engine - Version %s\n", VERSION_NUMBER);
if (enable_validation_layers) {
printf("Validation layers enabled.\n");
}
printf("\n");
struct VulkanData vulkan_data = {0};
struct Application app = {.window = NULL, .vulkan_data = &vulkan_data, .objects = NULL};
bool ret = application_init(&app);
if (ret == false) {
fprintf(stderr, "Cannot initialize applcation.\n");
return EXIT_FAILURE;
}
while (application_loopcondition(&app)) {
application_loopevent(&app);
}
application_close(&app);
return EXIT_SUCCESS;
}
application.c
#include "application.h"
#include "engine_object.h"
#include "engine_vulkan.h"
bool application_init(struct Application *app) {
bool ret;
// Initialize GLFW
glfwInit();
// Create window
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
app->window = glfwCreateWindow(800, 600, "Vulkan window", NULL, NULL);
if (app->window == NULL) {
fprintf(stderr, "Failed to create window.\n");
return false;
}
printf("Created window @ 0x%p\n", app->window);
// Initialize game object list
objectlink_init(app);
// Create game objects
struct RenderObjectCreateInfo ro_create_info = {.vertex_shader_path = "shaders/shader.vert.spv",
.fragment_shader_path =
"shaders/shader.frag.spv",
.is_static = true};
struct RenderObject triangle = {0};
object_init(app, &ro_create_info, &triangle);
objectlink_add(app, &triangle);
// Init Vulkan
ret = vulkan_init(app);
if (!ret) {
fprintf(stderr, "Failed to initialize Vulkan.\n");
return false;
}
return true;
}
bool application_loopcondition(struct Application *app) {
// Close only if GLFW says so
return !glfwWindowShouldClose(app->window);
}
void application_loopevent(struct Application *app) {
// Poll for events like keyboard & mouse
glfwPollEvents();
}
void application_close(struct Application *app) {
// Destroy objects
objectlink_destroy(app);
// Close Vulkan instance
vulkan_close(app);
// End window & GLFW
glfwDestroyWindow(app->window);
glfwTerminate();
}
重要结构
struct Application {
GLFWwindow *window;
struct VulkanData *vulkan_data;
struct RenderObjectLink *objects;
};
struct RenderObject {
char *vertex_shader_path;
struct ShaderFile vertex_shader_data;
VkShaderModule vertex_shader;
char *fragment_shader_path;
struct ShaderFile fragment_shader_data;
VkShaderModule fragment_shader;
bool is_static;
};
struct RenderObjectCreateInfo {
char *vertex_shader_path;
char *fragment_shader_path;
bool is_static;
};
struct RenderObjectLink {
struct RenderObject *render_object;
struct RenderObjectLink *next;
};
在我的应用程序结构中存储VkShaderModule
时出现了我的应用程序中的问题。我的程序应该存储有关对象的信息的方式是在称为Application
的app
结构中,该结构指向RenderObjectLink
字段中的objects
链表。我的函数objectlink_init
和objectlink_add
正常工作,但是当进入GLFW函数render_object
和glfwWindowShouldClose
时,glfwPollEvents
字段指向的结构内的数据会更改/损坏。
由于这两个函数是在初始化Vulkan和创建着色器模块后运行的,因此我在GDB中发现Vulkan函数运行正常,并且仅在运行GLFW循环函数时我的数据结构才被破坏。我已经使用硬件监视点对GDB进行了调试,以确定对这些着色器的引用(以及整个程序中的其他变量)是否在输入这些函数后发生了变化。
Thread 1 hit Hardware watchpoint 4: app->objects->render_object->vertex_shader
Old value = (VkShaderModule) 0x731f0f000000000a
New value = (VkShaderModule) 0x40d625 <glfwPollEvents+43>
_glfwPlatformPollEvents () at C:/Users/dylanweber/Documents/C-Projects/vlkengine/main/glfw/src/win32_window.c:1878
1878 {
这会持续发生,但运行时变量会更改为不同的值。内存分析工具(例如Dr. Memory)(因为我使用Windows,因此无法使用Valgrind)仅显示系统DLL中的内存问题(例如通过GLFW读取控制器输入的xinput),与我的程序无关。造成这种腐败的原因是什么?我可以使用哪些工具/资源来发现这些问题?
根据代码,objectlink_add
函数接受第二个参数作为指针。这种方法最可能的用途是将指针添加到基础数据结构,并保留它以备将来参考。帖子中提到了渲染管道,这可能是一种链接。
但是,该函数是从application_init
过程调用的,该过程在其堆栈上分配了对象triangle
。当函数返回时,其堆栈消失,指针处的值变为无效。
有几种解决方法:
使用malloc(或类似方法)动态分配三角形结构。因此从函数返回后它不会消失。这是最通用的方法,但是希望在某些时候调用free()
函数。
triangle
对象可以是static。
objectlink_add
可以在某些内部结构中复制triangle
字段,但是,如果有多种类型的对象,那就很成问题了。