diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d739f1..f19cce8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,22 @@ cmake_minimum_required(VERSION 3.15) project(Informatikprojekt C) set(CMAKE_C_STANDARD 11) +set(PROJECT_SOURCES particlesystem.h particlesystem.c init.h initOpenGL.h initOpenGL.c glad/src/glad.c) + +add_executable(Informatikprojekt cpuMain.c ${PROJECT_SOURCES}) +add_executable(Informatikprojekt_OpenGL openglMain.c ${PROJECT_SOURCES}) +add_executable(Informatikprojekt_Vulkan vulkanMain.c ${PROJECT_SOURCES}) + +# Vulkan +find_package(Vulkan REQUIRED) +target_include_directories(${PROJECT_NAME} PUBLIC ${Vulkan_INCLUDE_DIRS}) -add_executable(Informatikprojekt main.c particlesystem.h particlesystem.c init.h initOpenGL.h initOpenGL.c glad/src/glad.c) # GLFW - include_directories(./glfw/include) target_link_libraries(Informatikprojekt ${CMAKE_SOURCE_DIR}/glfw/lib-mingw-w64/libglfw3.a) +target_link_libraries(Informatikprojekt_OpenGL ${CMAKE_SOURCE_DIR}/glfw/lib-mingw-w64/libglfw3.a) +target_link_libraries(Informatikprojekt_Vulkan Vulkan::Vulkan ${CMAKE_SOURCE_DIR}/glfw/lib-mingw-w64/libglfw3.a) # glad include_directories(./glad/include) diff --git a/cpuMain.c b/cpuMain.c new file mode 100644 index 0000000..b6199df --- /dev/null +++ b/cpuMain.c @@ -0,0 +1,93 @@ +#include "particlesystem.h" +#include "initOpenGL.h" + +#define PARTICLE_AMOUNT 1000 +#define WIDTH 800 +#define HEIGHT 800 + +#define UPPER_AGE 250 +#define LOWER_AGE 60 + +void calcPos(particle *p, float dt); +void calcCol(particle *p); + +int main() +{ + /************* INIT *************/ + // Init OpenGL and GLFW + initGLFW(); + setErrorCallbackGL(); + + int width = WIDTH, height = HEIGHT; + GLFWwindow *window = createGLFWWindow(WIDTH, HEIGHT, "Informatikprojekt - OpenGL CPU"); + + setCurrentContextGL(window); + setFramebufferSizeCallbackGL(window); + + // glad + initGlad(); + + /************* PARTICLE SYSTEM *************/ + vector3f *epos1 = initVector3f(0, 0, 0); + emitter *e1 = initEmitter(epos1, PARTICLE_AMOUNT); + particle_system *ps = initParticleSystem(1); + (ps->emitters)[0] = e1; + initRandomParticles(e1); + + /************* RENDER LOOP *************/ + double time, tFrame, tLast = 0; + while (!glfwWindowShouldClose(window)) + { + time = glfwGetTime(); + tFrame = time - tLast; + tLast = time; + + /*** UPDATE ***/ + updateParticles((float) tFrame, ps, calcPos, calcCol); + + /*** RENDER ***/ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glfwGetFramebufferSize(window, &width, &height); + + emitter *e; + particle *p; + vector3f *pos; + for (int j = 0; j < ps->eamount; j++) + { + e = (ps->emitters)[j]; + for (int i = 0; i < e->pamount; i++) + { + p = (e->particles)[i]; + pos = p->position; + + glColor3f(p->color->x, p->color->y, p->color->z); + glBegin(GL_POINTS); + glVertex3f(pos->x, pos->y, pos->z); + glEnd(); + } + } + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + //END + terminateGLFW(window); + freeParticleSystem(ps); + + return 0; +} + +void calcPos(particle *p, float dt) +{ + p->position->x += p->velocity->x * dt; + p->position->y += p->velocity->y * dt; + p->position->z += p->velocity->z * dt; +} + +void calcCol(particle *p) +{ + p->color->x -= 0.00001f; + p->color->y -= 0.00001f; + p->color->z -= 0.00001f; +} diff --git a/main.c b/main.c deleted file mode 100644 index fd0b8c6..0000000 --- a/main.c +++ /dev/null @@ -1,334 +0,0 @@ -#include -#include -#include -#include - -#include "particlesystem.h" -#include "initOpenGL.h" - -#define PARTICLE_AMOUNT 10000 -#define WIDTH 800 -#define HEIGHT 800 - -void printVector(vector3f *v); -void printParticle(particle *v); -void printEmitter(emitter *e); -void initRandomParticles(emitter *e); -void error_callback(int error, const char* description); - -void calcPos(particle *p, float dt); -void calcCol(particle *p); - -int main() -{ - /************* INIT *************/ - // Init OpenGL and GLFW - initGLFW(); - setErrorCallbackGL(); - - int width = WIDTH, height = HEIGHT; - GLFWwindow *window = createGLFWWindow(WIDTH, HEIGHT, "Informatikprojekt - OpenGL"); - - setCurrentContextGL(window); - setFramebufferSizeCallbackGL(window); - - // glad - initGlad(); - - /************* PARTICLE SYSTEM *************/ - vector3f *epos1 = initVector3f(0, 0, 0); - emitter *e1 = initEmitter(epos1, PARTICLE_AMOUNT); - particle_system *ps = initParticleSystem(1); - (ps->emitters)[0] = e1; - initRandomParticles(e1); - - /************* SHADER *************/ - const GLchar *computeShaderSource = "#version 460 core\n" - "#extension GL_ARB_compute_shader : enable\n" - "#extension GL_ARB_shader_storage_buffer_object : enable\n" - "\n" - "struct particle\n" - "{\n" - " vec3 pos;\n" - " vec3 vel;\n" - " vec3 col;\n" - " float age;\n" - "};\n" - "\n" - "layout(std430, binding = 0) buffer particles\n" - "{\n" - " particle p[];\n" - "};\n" - "\n" - "uniform float dt;\n" - "uniform vec3 resetPos;\n" - "uniform uint seed;\n" - "\n" - "layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n" - "\n" - "float rand()\n" - "{\n" - " uint seedR;\n" - " seedR = (seed * 1103515245u + 12345u);\n" - " return float(seed) / 4294967296.0;\n" - "}\n" - "\n" - "vec3 rand3() {\n" - " vec3 result;\n" - " uint seedR;\n" - " seedR = (seed * 1103515245u + 12345u);\n" - " result.x = float(seed);\n" - " seedR = (seed * 1103515245u + 12345u);\n" - " result.y = float(seed);\n" - " seedR = (seed * 1103515245u + 12345u);\n" - " result.z = float(seed);\n" - " return (result / 2147483648.0) - vec3(1,1,1);\n" - "}\n" - "\n" - "void main()\n" - "{\n" - " uint gid = gl_GlobalInvocationID.x;\n" - " particle part = p[gid];\n" - "\n" - " if (part.age < 0 || part.pos.x > 1 || part.pos.y > 1 || part.pos.z > 1\n" - " || part.pos.x < -1 || part.pos.y < -1 || part.pos.z < -1 )\n" - " {\n" - " part.pos = resetPos;\n" - " //part.vel = rand3();\n" - " //part.col = vec3(rand(), rand(), rand());\n" - " //part.age = rand() * 0x7fff * 0.01f;\n" - " \n" - " }\n" - " else\n" - " {\n" - " part.pos += part.vel * dt;\n" - " part.age -= 0.01f;\n" - " }\n" - "\n" - " p[gid] = part;\n" - "}"; - - const GLchar *vertexShaderSource = "#version 460\n" - "\n" - "layout(location = 0) in vec3 pos;\n" - "layout(location = 1) in vec3 colIn;\n" - "\n" - "out vec3 colV;\n" - "\n" - "void main(void)\n" - "{\n" - " colV = colIn;\n" - " gl_Position = vec4(pos, 1);\n" - "}"; - - const GLchar *fragmentShaderSource = "#version 460 core\n" - "\n" - "in vec3 colV;\n" - "out vec4 colOut;\n" - "\n" - "void main(void)\n" - "{\n" - " colOut = vec4(colV, 1);\n" - "}"; - - GLuint computeShader = compileShader(computeShaderSource, GL_COMPUTE_SHADER); - GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER); - GLuint fragmentShader = compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER); - - GLuint computeShaders[] = { computeShader }; - GLuint computeShaderProgram = linkShaders(computeShaders, 1); - glUseProgram(computeShaderProgram); - GLint dtUniformLocation = glGetUniformLocation(computeShaderProgram, "dt"); - GLint resetPosUniformLocation = glGetUniformLocation(computeShaderProgram, "resetPos"); - GLint seedUniformLocation = glGetUniformLocation(computeShaderProgram, "seed"); - glUniform3f(resetPosUniformLocation, e1->position->x, e1->position->y, e1->position->z); - - GLuint renderShaders[] = { vertexShader, fragmentShader }; - GLuint renderShaderProgram = linkShaders(renderShaders, 2); - - float *particles = serializeParticlesystem(ps); - GLsizeiptr sizeOfParticle = 3 * sizeof(vector3f) + sizeof(float); - - GLuint particleBuffer; - glGenBuffers(1, &particleBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, particleBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, PARTICLE_AMOUNT * sizeOfParticle, particles, GL_STATIC_DRAW); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, particleBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - - GLuint vertexArray; - glGenVertexArrays(1, &vertexArray); - glBindVertexArray(vertexArray); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, particleBuffer); - glBindBuffer(GL_ARRAY_BUFFER, particleBuffer); - // position - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeOfParticle, (GLvoid *)0); - // color - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeOfParticle, (GLvoid *)24); - glBindVertexArray(0); - - /************* RENDER LOOP *************/ - double time, tFrame, tLast = 0; - while (!glfwWindowShouldClose(window)) - { - time = glfwGetTime(); - tFrame = time - tLast; - tLast = time; - - /*** UPDATE ***/ - glUseProgram(computeShaderProgram); - glUniform1f(dtUniformLocation, tFrame); - glUniform1ui(seedUniformLocation, rand()); - glDispatchCompute((PARTICLE_AMOUNT / 256) + 1, 1, 1); - glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT); - - /*** RENDER ***/ - glClear(GL_COLOR_BUFFER_BIT); - glfwGetFramebufferSize(window, &width, &height); - glBindVertexArray(vertexArray); - glUseProgram(renderShaderProgram); - glDrawArrays(GL_POINTS, 0, PARTICLE_AMOUNT); - glBindVertexArray(0); - - glfwSwapBuffers(window); - glfwPollEvents(); - } - - //END - deleteShaders(renderShaders, 2); - deleteShaders(computeShaders, 1); - - terminateGLFW(window); - freeParticleSystem(ps); - - return 0; -} - -void calcPos(particle *p, float dt) -{ - p->position->x += p->velocity->x * dt; - p->position->y += p->velocity->y * dt; - p->position->z += p->velocity->z * dt; -} - -void calcCol(particle *p) -{ -// p->color->x -= 0.01f; -// p->color->y -= 0.01f; -// p->color->z -= 0.01f; -} - -/*************************************************************************************************************/ -void initRandomParticles(emitter *e) -{ - for (int i = 0; i < e->pamount; i++) - { - vector3f *pos = initVector3f(e->position->x, e->position->y, e->position->z); - vector3f *dir = initVector3f(((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX, - ((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX, - ((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX); - vector3f *color = initVector3f(((float) (rand() % 255)) / 255, - ((float) (rand() % 255)) / 255, - ((float) (rand() % 255)) / 255); - (e->particles)[i] = initParticle(pos, dir, color, rand() / 100.0f); - } -} - -void printParticle(particle *v) -{ - printVector(v->position); - printf("; "); - printVector(v->velocity); - printf("; "); - printVector(v->color); - printf("; %f\n", v->age); -} - -void printVector(vector3f *v) -{ - printf("(%f, %f, %f)", v->x, v->y, v->z); -} - -/// VERY OLD -// glUseProgram(shaderProgram); -// glBindVertexArray(vao); -// glDrawArrays(GL_POINTS, 0, particleAmount); - -// updateParticles((float) tFrame, ps, calcPos, calcCol); -// -// emitter *e; -// particle *p; -// vector3f *pos; -// for (int j = 0; j < ps->eamount; j++) -// { -// e = (ps->emitters)[j]; -// for (int i = 0; i < e->pamount; i++) -// { -// p = (e->particles)[i]; -// pos = p->position; -// -// glColor3f(p->color->x, p->color->y, p->color->z); -// glBegin(GL_POINTS); -// glVertex3f(pos->x, pos->y, pos->z); -// glEnd(); -// } -// } - -/// FEEDBACK TRANSFORM BEFORE -// /*************** NEW ***************/ -// float *vertexData = serializeParticlesystem(ps); -// unsigned int currentVertexBuffer = 0, currentTransformFeedbackBuffer = 1; -// int buffersSize = 2; -// unsigned int particleBuffers[buffersSize], transformFeedbackBuffers[buffersSize]; -// -// glGenTransformFeedbacks(buffersSize, transformFeedbackBuffers); -// glGenBuffers(buffersSize, particleBuffers); -// -// for (int i = 0; i < buffersSize; i++) -// { -// glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackBuffers[i]); -// glBindBuffer(GL_ARRAY_BUFFER, particleBuffers[i]); -// glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_DYNAMIC_DRAW); -// glBindBufferBase(GL_TRANSFORM_FEEDBACK, 0, particleBuffers[i]); -// } - -// // position attribute -// glEnableVertexAttribArray(0); -// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)0); -// // velocity attribute -// glEnableVertexAttribArray(1); -// glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(3 * sizeof(float))); -// // color attribute -// glEnableVertexAttribArray(2); -// glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(6 * sizeof(float))); -// // age attribute -// glEnableVertexAttribArray(3); -// glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (void*)(9 * sizeof(float))); - -/// TRANSFORM FEEDBACK RENDER LOOP -///*** UPDATE PARTICLES ***/ -//glEnable(GL_RASTERIZER_DISCARD); -//glBindBuffer(GL_ARRAY_BUFFER, particleBuffers[currentVertexBuffer]); -//glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackBuffers[currentTransformFeedbackBuffer]); -//glBeginTransformFeedback(GL_POINTS); -//if (isFirst) -//{ -//glDrawArrays(GL_POINTS, 0, particleAmount); -//isFirst = !isFirst; -//} -//else -//{ -//glDrawTransformFeedback(GL_POINTS, transformFeedbackBuffers[currentVertexBuffer]); -//} -//glEndTransformFeedback(); -// -///*** RENDER PARTICLES ***/ -//glDisable(GL_RASTERIZER_DISCARD); -//glBindBuffer(GL_ARRAY_BUFFER, particleBuffers[currentTransformFeedbackBuffer]); -//glDrawTransformFeedback(GL_POINTS, transformFeedbackBuffers[currentTransformFeedbackBuffer]); -// -///***************************************************/ -//currentVertexBuffer = currentTransformFeedbackBuffer; -//currentTransformFeedbackBuffer = !currentTransformFeedbackBuffer; \ No newline at end of file diff --git a/openglMain.c b/openglMain.c new file mode 100644 index 0000000..190c89c --- /dev/null +++ b/openglMain.c @@ -0,0 +1,216 @@ +#include "particlesystem.h" +#include "initOpenGL.h" + +#define PARTICLE_AMOUNT 1000000 +#define WIDTH 800 +#define HEIGHT 800 + +int main() +{ + /************* INIT *************/ + // Init OpenGL and GLFW + initGLFW(); + setErrorCallbackGL(); + + int width = WIDTH, height = HEIGHT; + GLFWwindow *window = createGLFWWindow(WIDTH, HEIGHT, "Informatikprojekt - OpenGL"); + + setCurrentContextGL(window); + setFramebufferSizeCallbackGL(window); + + // glad + initGlad(); + + /************* PARTICLE SYSTEM *************/ + vector3f *epos1 = initVector3f(0, 0, 0); + emitter *e1 = initEmitter(epos1, PARTICLE_AMOUNT); + particle_system *ps = initParticleSystem(1); + (ps->emitters)[0] = e1; + initRandomParticles(e1); + + /************* SHADER *************/ + const GLchar *computeShaderSource = "#version 460\n" + "\n" + "#define FLOAT_MAX 4294967296.0f\n" + "\n" + "struct particle\n" + "{\n" + " float px, py, pz;\n" + " float vx, vy, vz;\n" + " float cx, cy, cz;\n" + " float age;\n" + "};\n" + "\n" + "layout(std430, binding = 0) buffer particles\n" + "{\n" + " particle p[];\n" + "};\n" + "\n" + "layout(location = 0) uniform float dt;\n" + "layout(location = 1) uniform vec3 resetPos;\n" + "layout(location = 2) uniform uint maxParticles;\n" + "\n" + "layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "uint hash(uvec3 seed)\n" + "{\n" + " uint hash;\n" + " hash = (seed.x ^ 61u) ^ (seed.y >> 16u);\n" + " hash *= 9u;\n" + " hash = seed.z ^ (seed.x >> 4u);\n" + " hash *= 0x27d4eb2du;\n" + " hash = seed.y ^ (seed.z >> 15u);\n" + " return hash;\n" + "}\n" + "\n" + "uint rand(uint seed)\n" + "{\n" + " // Xorshift algorithm from George Marsaglia's paper\n" + " seed ^= (seed << 13u);\n" + " seed ^= (seed >> 17u);\n" + " seed ^= (seed << 5u);\n" + " return seed;\n" + "}\n" + "\n" + "void main()\n" + "{\n" + " uint gid = gl_GlobalInvocationID.x;\n" + "\n" + " if (gid <= maxParticles)\n" + " {\n" + " particle part = p[gid];\n" + "\n" + " uint hash1 = hash(uvec3(uint(part.px * FLOAT_MAX), uint(part.cy * FLOAT_MAX), uint(part.vz * FLOAT_MAX)));\n" + " uint hash2 = hash(uvec3(uint(part.vx * FLOAT_MAX), uint(part.py * FLOAT_MAX), uint(part.cz * FLOAT_MAX)));\n" + " uint hash3 = hash(uvec3(uint(part.cx * FLOAT_MAX), uint(part.vy * FLOAT_MAX), uint(part.pz * FLOAT_MAX)));\n" + " \n" + " if (part.age < 0 || part.px > 1 || part.py > 1 || part.pz > 1 || part.px < -1 || part.py < -1 || part.pz < -1)\n" + " {\n" + " part.px = resetPos.x;\n" + " part.py = resetPos.y;\n" + " part.pz = resetPos.z;\n" + "\n" + " part.age = rand(hash(uvec3(hash1, hash2, hash3))) % (250 - 60 + 1) + 60;\n" + "\n" + " part.vx = (rand(hash1) % 2 == 0 ? 1 : -1) * float(rand(hash2)) * (1.0f / FLOAT_MAX);\n" + " part.vy = (rand(hash3) % 2 == 0 ? 1 : -1) * float(rand(hash1)) * (1.0f / FLOAT_MAX);\n" + " part.vz = (rand(hash2) % 2 == 0 ? 1 : -1) * float(rand(hash3)) * (1.0f / FLOAT_MAX);\n" + "\n" + " part.cx = float(rand(hash3)) * (1.0f / FLOAT_MAX);\n" + " part.cy = float(rand(hash2)) * (1.0f / FLOAT_MAX);\n" + " part.cz = float(rand(hash1)) * (1.0f / FLOAT_MAX);\n" + " }\n" + " else\n" + " {\n" + " part.px += part.vx * dt;\n" + " part.py += part.vy * dt;\n" + " part.pz += part.vz * dt;\n" + "\n" + " part.cx = float(rand(hash1)) * (1.0f / FLOAT_MAX);\n" + " part.cy = float(rand(hash1)) * (1.0f / FLOAT_MAX);\n" + " part.cz = float(rand(hash1)) * (1.0f / FLOAT_MAX);\n" + "\n" + " part.age -= 0.01f;\n" + " }\n" + "\n" + " p[gid] = part;\n" + " }\n" + "}"; + + const GLchar *vertexShaderSource = "#version 460\n" + "\n" + "layout(location = 0) in vec3 pos;\n" + "layout(location = 1) in vec3 colIn;\n" + "\n" + "layout(location = 0) out vec3 colV;\n" + "\n" + "void main(void)\n" + "{\n" + " colV = colIn;\n" + " gl_Position = vec4(pos, 1);\n" + "}"; + + const GLchar *fragmentShaderSource = "#version 460\n" + "\n" + "layout(location = 0) in vec3 colV;\n" + "layout(location = 0) out vec4 colOut;\n" + "\n" + "void main(void)\n" + "{\n" + " colOut = vec4(colV, 1);\n" + "}"; + + GLuint computeShader = compileShader(computeShaderSource, GL_COMPUTE_SHADER); + GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER); + GLuint fragmentShader = compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER); + + GLuint computeShaders[] = { computeShader }; + GLuint computeShaderProgram = linkShaders(computeShaders, 1); + glUseProgram(computeShaderProgram); + GLint dtUniformLocation = glGetUniformLocation(computeShaderProgram, "dt"); + GLint resetPosUniformLocation = glGetUniformLocation(computeShaderProgram, "resetPos"); + glUniform3f(resetPosUniformLocation, e1->position->x, e1->position->y, e1->position->z); + GLint maxParticlesUniformLocation = glGetUniformLocation(computeShaderProgram, "maxParticles"); + glUniform1ui(maxParticlesUniformLocation, PARTICLE_AMOUNT); + + GLuint renderShaders[] = { vertexShader, fragmentShader }; + GLuint renderShaderProgram = linkShaders(renderShaders, 2); + + float *particles = serializeParticlesystem(ps); + GLsizeiptr sizeOfParticle = 3 * sizeof(vector3f) + sizeof(float); + + GLuint particleBuffer; + glGenBuffers(1, &particleBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, particleBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, PARTICLE_AMOUNT * sizeOfParticle, particles, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, particleBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLuint vertexArray; + glGenVertexArrays(1, &vertexArray); + glBindVertexArray(vertexArray); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, particleBuffer); + glBindBuffer(GL_ARRAY_BUFFER, particleBuffer); + // position + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeOfParticle, (GLvoid *)0); + // color + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeOfParticle, (GLvoid *)24); // 32 + glBindVertexArray(0); + + /************* RENDER LOOP *************/ + double time, tFrame, tLast = 0; + while (!glfwWindowShouldClose(window)) + { + time = glfwGetTime(); + tFrame = time - tLast; + tLast = time; + + /*** UPDATE ***/ + glUseProgram(computeShaderProgram); + glUniform1f(dtUniformLocation, tFrame); + glDispatchCompute(PARTICLE_AMOUNT / 256, 1, 1); + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT); + + /*** RENDER ***/ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glfwGetFramebufferSize(window, &width, &height); + glBindVertexArray(vertexArray); + glUseProgram(renderShaderProgram); + glDrawArrays(GL_POINTS, 0, PARTICLE_AMOUNT); + glBindVertexArray(0); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + //END + deleteShaders(renderShaders, 2); + deleteShaders(computeShaders, 1); + + terminateGLFW(window); + freeParticleSystem(ps); + + return 0; +} \ No newline at end of file diff --git a/particlesystem.c b/particlesystem.c index 203caf8..a7ae7fb 100644 --- a/particlesystem.c +++ b/particlesystem.c @@ -1,5 +1,6 @@ #include #include +#include #include "particlesystem.h" @@ -158,7 +159,7 @@ float *serializeParticlesystem(particle_system *ps) } unsigned long particleBytesAmount = sizeof(vector3f) * 3 + sizeof(float); - float *vert = malloc(particleBytesAmount * particleAmount); + float *vert = malloc(particleAmount * particleBytesAmount); emitter *e; particle *p; @@ -168,6 +169,7 @@ float *serializeParticlesystem(particle_system *ps) for (int x = 0; x < e->pamount; x++) { p = e->particles[x]; + // Position vert[j++] = p->position->x; vert[j++] = p->position->y; @@ -190,3 +192,21 @@ float *serializeParticlesystem(particle_system *ps) return vert; } + +/* + * Inits random particles + */ +void initRandomParticles(emitter *e) +{ + for (int i = 0; i < e->pamount; i++) + { + vector3f *pos = initVector3f(e->position->x, e->position->y, e->position->z); + vector3f *dir = initVector3f(((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX, + ((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX, + ((float) (rand()%2 ? -1 : 1) * rand()) / RAND_MAX); + vector3f *color = initVector3f(((float) (rand() % 255)) / 255, + ((float) (rand() % 255)) / 255, + ((float) (rand() % 255)) / 255); + (e->particles)[i] = initParticle(pos, dir, color, (float) (rand() % (UPPER_AGE - LOWER_AGE + 1) + LOWER_AGE)); + } +} diff --git a/particlesystem.h b/particlesystem.h index a258f74..3fd3035 100644 --- a/particlesystem.h +++ b/particlesystem.h @@ -1,3 +1,6 @@ +#define UPPER_AGE 250 +#define LOWER_AGE 60 + /* * A vector with three floats */ @@ -107,4 +110,9 @@ void freeParticleSystem(particle_system *ps); /* * Creates float array out of a particle system */ -float *serializeParticlesystem(particle_system *ps); \ No newline at end of file +float *serializeParticlesystem(particle_system *ps); + +/* + * Inits random particle + */ +void initRandomParticles(emitter *e); \ No newline at end of file diff --git a/shaders/ComputeShader.glsl b/shaders/ComputeShader.glsl deleted file mode 100644 index 7cf94a3..0000000 --- a/shaders/ComputeShader.glsl +++ /dev/null @@ -1,64 +0,0 @@ -#version 460 core -#extension GL_ARB_compute_shader : enable -#extension GL_ARB_shader_storage_buffer_object : enable - -struct particle -{ - vec3 pos; - vec3 vel; - vec3 col; - float age; -}; - -layout(std430, binding = 0) buffer particles -{ - particle p[]; -}; - -uniform float dt; -uniform vec3 resetPos; -uniform uint seed; - -layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; - -float rand() -{ - uint seedR; - seedR = (seed * 1103515245u + 12345u); - return float(seed) / 4294967296.0; -} - -vec3 rand3() { - vec3 result; - uint seedR; - seedR = (seed * 1103515245u + 12345u); - result.x = float(seed); - seedR = (seed * 1103515245u + 12345u); - result.y = float(seed); - seedR = (seed * 1103515245u + 12345u); - result.z = float(seed); - return (result / 2147483648.0) - vec3(1,1,1); -} - -void main() -{ - uint gid = gl_GlobalInvocationID.x; - particle part = p[gid]; - - if (part.age < 0 || part.pos.x > 1 || part.pos.y > 1 || part.pos.z > 1 - || part.pos.x < -1 || part.pos.y < -1 || part.pos.z < -1 ) - { - part.pos = resetPos; - part.vel = rand3(); - part.col = vec3(rand(), rand(), rand()); - part.age = rand() * 0x7fff * 0.01f; - - } - else - { - part.pos += part.vel * dt; - part.age -= 0.01f; - } - - p[gid] = part; -} diff --git a/shaders/FragmentShader.glsl b/shaders/FragmentShader.glsl deleted file mode 100644 index ae1e4e2..0000000 --- a/shaders/FragmentShader.glsl +++ /dev/null @@ -1,9 +0,0 @@ -#version 460 core - -in vec3 colV; -out vec4 colOut; - -void main(void) -{ - colOut = vec4(colV, 1); -} \ No newline at end of file diff --git a/shaders/GeometryShader.glsl b/shaders/GeometryShader.glsl deleted file mode 100644 index 921b852..0000000 --- a/shaders/GeometryShader.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#version 460 core - -layout(points) in; -layout(points, max_vertices = 256) out; - -in vec3 colV; -out vec3 colG; - -void main(void) -{ - colG = colV; -} diff --git a/shaders/RenderShader.glsl b/shaders/RenderShader.glsl deleted file mode 100644 index c3709e9..0000000 --- a/shaders/RenderShader.glsl +++ /dev/null @@ -1,30 +0,0 @@ -#version 460 core - -layout (points) in; -layout (points) out; -layout (max_vertices = 40) out; - -in vec3 pos0[]; -in vec3 vel0[]; -in vec3 col0[]; -in float age0[]; - -out vec3 posOut; -out vec3 velOut; -out vec3 colOut; -out float ageOut; - -void main() -{ - if (age0[0] < 0) - { - posOut = vec3(0, 0, 0); - } - else - { - posOut = pos0[0]; - velOut = vel0[0]; - colOut = col0[0]; - ageOut = age0[0] - 0.01f; - } -} diff --git a/shaders/UpdateShader.glsl b/shaders/UpdateShader.glsl deleted file mode 100644 index d799694..0000000 --- a/shaders/UpdateShader.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 core - -layout (location = 0) in vec3 pos; // the position variable has attribute position 0 -layout (location = 1) in vec3 vel; // the velocity variable has attribute position 1 -layout (location = 2) in vec3 col; // the color variable has attribute position 2 -layout (location = 3) in float age; // the age variable has attribute position 3 - -out vec3 pos0; -out vec3 vel0; -out vec3 col0; -out float age0; - -void main() -{ - pos0 = pos; - vel0 = vel; - col0 = col; - age0 = age; -} \ No newline at end of file diff --git a/shaders/opengl/ComputeShader.glsl b/shaders/opengl/ComputeShader.glsl new file mode 100644 index 0000000..5ae8169 --- /dev/null +++ b/shaders/opengl/ComputeShader.glsl @@ -0,0 +1,87 @@ +#version 460 + +#define FLOAT_MAX 4294967296.0f + +struct particle +{ + float px, py, pz; + float vx, vy, vz; + float cx, cy, cz; + float age; +}; + +layout(std430, binding = 0) buffer particles +{ + particle p[]; +}; + +layout(location = 0) uniform float dt; +layout(location = 1) uniform vec3 resetPos; +layout(location = 2) uniform uint maxParticles; + +layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; + +uint hash(uvec3 seed) +{ + uint hash; + hash = (seed.x ^ 61u) ^ (seed.y >> 16u); + hash *= 9u; + hash = seed.z ^ (seed.x >> 4u); + hash *= 0x27d4eb2du; + hash = seed.y ^ (seed.z >> 15u); + return hash; +} + +uint rand(uint seed) +{ + // Xorshift algorithm from George Marsaglia's paper + seed ^= (seed << 13u); + seed ^= (seed >> 17u); + seed ^= (seed << 5u); + return seed; +} + +void main() +{ + uint gid = gl_GlobalInvocationID.x; + + if (gid <= maxParticles) + { + particle part = p[gid]; + + uint hash1 = hash(uvec3(uint(part.px * FLOAT_MAX), uint(part.cy * FLOAT_MAX), uint(part.vz * FLOAT_MAX))); + uint hash2 = hash(uvec3(uint(part.vx * FLOAT_MAX), uint(part.py * FLOAT_MAX), uint(part.cz * FLOAT_MAX))); + uint hash3 = hash(uvec3(uint(part.cx * FLOAT_MAX), uint(part.vy * FLOAT_MAX), uint(part.pz * FLOAT_MAX))); + + if (part.age < 0 || part.px > 1 || part.py > 1 || part.pz > 1 || part.px < -1 || part.py < -1 || part.pz < -1) + { + part.px = resetPos.x; + part.py = resetPos.y; + part.pz = resetPos.z; + + part.age = rand(hash(uvec3(hash1, hash2, hash3))) % (250 - 60 + 1) + 60; + + part.vx = (rand(hash1) % 2 == 0 ? 1 : -1) * float(rand(hash2)) * (1.0f / FLOAT_MAX); + part.vy = (rand(hash3) % 2 == 0 ? -1 : 1) * float(rand(hash1)) * (1.0f / FLOAT_MAX); + part.vz = (rand(hash2) % 2 == 0 ? 1 : -1) * float(rand(hash3)) * (1.0f / FLOAT_MAX); + + part.cx = float(rand(hash1)) * (1.0f / FLOAT_MAX); + part.cy = float(rand(hash1)) * (1.0f / FLOAT_MAX); + part.cz = float(rand(hash1)) * (1.0f / FLOAT_MAX); + } + else + { + part.px += part.vx * dt; + part.py += part.vy * dt; + part.pz += part.vz * dt; + + part.cx = float(rand(hash1)) * (1.0f / FLOAT_MAX); + part.cy = float(rand(hash1)) * (1.0f / FLOAT_MAX); + part.cz = float(rand(hash1)) * (1.0f / FLOAT_MAX); + + part.age -= 0.01f; + } + + p[gid] = part; + } +} diff --git a/shaders/VertexShader.glsl b/shaders/opengl/VertexShader.glsl similarity index 73% rename from shaders/VertexShader.glsl rename to shaders/opengl/VertexShader.glsl index 1375ea1..2c66e6a 100644 --- a/shaders/VertexShader.glsl +++ b/shaders/opengl/VertexShader.glsl @@ -1,9 +1,9 @@ -#version 460 core +#version 460 layout(location = 0) in vec3 pos; layout(location = 1) in vec3 colIn; -out vec3 colV; +layout(location = 0) out vec3 colV; void main(void) { diff --git a/vulkanMain.c b/vulkanMain.c new file mode 100644 index 0000000..70dd2b7 --- /dev/null +++ b/vulkanMain.c @@ -0,0 +1,368 @@ +#include +#include +#include "vulkan/vulkan.h" + +#define GLFW_INCLUDE_VULKAN +#include "GLFW/glfw3.h" + +#define APP_NAME "Vulkan Tutorial" +#define APP_VERSION VK_MAKE_VERSION(0, 0, 0) +#define ENGINE_NAME "Memobio Game Engine" +#define ENGINE_VERSION VK_MAKE_VERSION(0, 0, 0) + +#define SUCCESS 0 +#define FAILURE -1 +#define ASSERT_SUCCESS(res)\ + if (res != SUCCESS) { printf("Error-Code: %d", res); return FAILURE; } +#define ASSERT_GLFW_SUCCESS(res)\ + if (res != GLFW_TRUE) { printf("Error-Code: %d", res); return FAILURE; } +#define ASSERT_VK_SUCCESS(res)\ + if (res != VK_SUCCESS) { printf("Error-Code: %d", res); return FAILURE; } +#define BOOL_LITERAL(val)\ + val ? "True" : "False" +#define HUMAN_READABLE(val)\ + val * 9.313226e-10 + +#define WIDTH 500 +#define HEIGHT 500 + +int initVulkan(VkInstance *vkInstance, VkDevice *device, VkSurfaceKHR *surface, GLFWwindow *window, + VkSwapchainKHR *swapChain, VkImageView *imageViews, uint32_t *amountImages); +void initAppInfo(VkApplicationInfo *appInfo); +void initCreateInfo(VkApplicationInfo *appInfo, VkInstanceCreateInfo *instanceInfo); +void initQueueInfo(VkDeviceQueueCreateInfo *queueInfo); +void initDeviceInfo(VkDeviceQueueCreateInfo *queueInfo, VkDeviceCreateInfo *deviceInfo, VkPhysicalDeviceFeatures *features); +void initImageViewInfo(VkImageViewCreateInfo *imageViewInfo, VkImage *swapChainImages, int index); +void printStats(VkPhysicalDevice *physicalDevice, VkSurfaceKHR *surface); + +void initSwapChainInfo(VkSwapchainCreateInfoKHR *swapChainCreateInfo, VkSurfaceKHR *surface); + +void shutdownVulkan(VkInstance *vkInstance, VkDevice *device, VkSurfaceKHR *surface, VkSwapchainKHR *swapChain, + VkImageView *imageViews, uint32_t amountImages); + +void shutdownGLFW(GLFWwindow *window); + +int main() +{ + VkInstance vkInstance; + VkDevice device; + VkSurfaceKHR surface; + VkSwapchainKHR swapChain; + VkImageView *imageViews = NULL; + uint32_t amountImages; + + // GLFW + ASSERT_GLFW_SUCCESS(glfwInit()) + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Particlesystem", NULL, NULL); + + // Init Vulkan + ASSERT_SUCCESS(initVulkan(&vkInstance, &device, &surface, window, &swapChain, imageViews, &amountImages)) + + // Render Loop + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + } + + // Stop Vulkan + shutdownVulkan(&vkInstance, &device, &surface, &swapChain, imageViews, amountImages); + + // Stop GLFW + shutdownGLFW(window); + + return SUCCESS; +} + + +int initVulkan(VkInstance *vkInstance, VkDevice *device, VkSurfaceKHR *surface, GLFWwindow *window, + VkSwapchainKHR *swapChain, VkImageView *imageViews, uint32_t *amountImages) +{ + // VkApplicationInfo + VkApplicationInfo appInfo; + initAppInfo(&appInfo); + + // VkInstanceCreateInfo + uint32_t amountOfLayers; + vkEnumerateInstanceLayerProperties(&amountOfLayers, NULL); + VkLayerProperties layers[amountOfLayers]; + vkEnumerateInstanceLayerProperties(&amountOfLayers, layers); + + VkInstanceCreateInfo instanceInfo; + initCreateInfo(&appInfo, &instanceInfo); + + // Vulkan Instance + ASSERT_VK_SUCCESS(vkCreateInstance(&instanceInfo, NULL, vkInstance)) + + // Get physical device + uint32_t amountOfPhysicalDevices = 0; + ASSERT_VK_SUCCESS(vkEnumeratePhysicalDevices(*vkInstance, &amountOfPhysicalDevices, NULL)) // Let fill amount first automatically + VkPhysicalDevice physicalDevices[amountOfPhysicalDevices]; // create array for physical devices + ASSERT_VK_SUCCESS(vkEnumeratePhysicalDevices(*vkInstance, &amountOfPhysicalDevices, physicalDevices)) // Call again with array + + // Create Window Surface + ASSERT_VK_SUCCESS(glfwCreateWindowSurface(*vkInstance, window, NULL, surface)) + + printStats(&physicalDevices[0], surface); + + // Queue info + VkDeviceQueueCreateInfo queueInfo; + initQueueInfo(&queueInfo); + + // Device info + VkPhysicalDeviceFeatures usedFeatures = {}; + VkDeviceCreateInfo deviceInfo; + initDeviceInfo(&queueInfo, &deviceInfo, &usedFeatures); + + // Logical device + ASSERT_VK_SUCCESS(vkCreateDevice(physicalDevices[0], &deviceInfo, NULL, device)) + + // Queue + VkQueue queue; + vkGetDeviceQueue(*device, 0, 0, &queue); + + // Swap chain support + VkBool32 swapChainSupport; + ASSERT_VK_SUCCESS(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevices[0], 0, *surface, &swapChainSupport)) + if (!swapChainSupport) + { + printf("Swap chain not supported!"); + return FAILURE; + } + + // Swap chain info + VkSwapchainCreateInfoKHR swapChainCreateInfo; + initSwapChainInfo(&swapChainCreateInfo, surface); + + // Swap chain + ASSERT_VK_SUCCESS(vkCreateSwapchainKHR(*device, &swapChainCreateInfo, NULL, swapChain)) + + // Swap chain images + vkGetSwapchainImagesKHR(*device, *swapChain, amountImages, NULL); + VkImage swapChainImages[*amountImages]; + ASSERT_VK_SUCCESS(vkGetSwapchainImagesKHR(*device, *swapChain, amountImages, swapChainImages)) + + // Image view + imageViews = malloc(*amountImages * sizeof(VkImageView)); + VkImageViewCreateInfo imageViewInfo; + for (int i = 0; i < *amountImages; i++) + { + initImageViewInfo(&imageViewInfo, swapChainImages, i); + ASSERT_VK_SUCCESS(vkCreateImageView(*device, &imageViewInfo, NULL, &imageViews[i])) + } + + return SUCCESS; +} + +void initAppInfo(VkApplicationInfo *appInfo) +{ + appInfo->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo->pNext = NULL; + appInfo->pApplicationName = APP_NAME; + appInfo->applicationVersion = APP_VERSION; + appInfo->pEngineName = ENGINE_NAME; + appInfo->engineVersion = ENGINE_VERSION; + appInfo->apiVersion = VK_API_VERSION_1_1; +} + +void initCreateInfo(VkApplicationInfo *appInfo, VkInstanceCreateInfo *instanceInfo) +{ + GLuint amountOfGLFWExtensions; + const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&amountOfGLFWExtensions); + + instanceInfo->sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceInfo->pNext = NULL; + instanceInfo->flags = 0; + instanceInfo->pApplicationInfo = appInfo; + instanceInfo->enabledLayerCount = 0; + instanceInfo->ppEnabledLayerNames = NULL; + instanceInfo->enabledExtensionCount = amountOfGLFWExtensions; + instanceInfo->ppEnabledExtensionNames = glfwExtensions; +} + +void initQueueInfo(VkDeviceQueueCreateInfo *queueInfo) +{ + queueInfo->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo->pNext = NULL; + queueInfo->flags = 0; + queueInfo->queueFamilyIndex = 0; + queueInfo->queueCount = 1; + queueInfo->pQueuePriorities = NULL; +} + +void initDeviceInfo(VkDeviceQueueCreateInfo *queueInfo, VkDeviceCreateInfo *deviceInfo, VkPhysicalDeviceFeatures *features) +{ + const char *deviceExtensions[1] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + + deviceInfo->sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceInfo->pNext = NULL; + deviceInfo->flags = 0; + deviceInfo->queueCreateInfoCount = 1; + deviceInfo->pQueueCreateInfos = queueInfo; + deviceInfo->enabledLayerCount = 0; + deviceInfo->ppEnabledLayerNames = NULL; + deviceInfo->enabledExtensionCount = 1; + deviceInfo->ppEnabledExtensionNames = deviceExtensions; + deviceInfo->pEnabledFeatures = features; +} + +void initSwapChainInfo(VkSwapchainCreateInfoKHR *swapChainCreateInfo, VkSurfaceKHR *surface) +{ + VkExtent2D imageExtent = { WIDTH, HEIGHT }; + + swapChainCreateInfo->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapChainCreateInfo->pNext = NULL; + swapChainCreateInfo->flags = 0; + swapChainCreateInfo->surface = *surface; + swapChainCreateInfo->minImageCount = 1; + swapChainCreateInfo->imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + swapChainCreateInfo->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + swapChainCreateInfo->imageExtent = imageExtent; + swapChainCreateInfo->imageArrayLayers = 1; + swapChainCreateInfo->imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapChainCreateInfo->imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainCreateInfo->queueFamilyIndexCount = 0; + swapChainCreateInfo->pQueueFamilyIndices = NULL; + swapChainCreateInfo->preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapChainCreateInfo->compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapChainCreateInfo->presentMode = VK_PRESENT_MODE_FIFO_KHR; + swapChainCreateInfo->clipped = VK_FALSE; + swapChainCreateInfo->oldSwapchain = VK_NULL_HANDLE; +} + +void initImageViewInfo(VkImageViewCreateInfo *imageViewInfo, VkImage *swapChainImages, int index) +{ + VkComponentMapping componentMapping = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY + }; + VkImageSubresourceRange subresourceRange = { + VK_IMAGE_ASPECT_COLOR_BIT,0, 1, 0, 1 + }; + + imageViewInfo->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo->pNext = NULL; + imageViewInfo->flags = 0; + imageViewInfo->image = swapChainImages[index]; + imageViewInfo->viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo->format = VK_FORMAT_B8G8R8A8_UNORM; + imageViewInfo->components = componentMapping; + imageViewInfo->subresourceRange = subresourceRange; +} + +void shutdownVulkan(VkInstance *vkInstance, VkDevice *device, VkSurfaceKHR *surface, VkSwapchainKHR *swapChain, + VkImageView *imageViews, uint32_t amountImages) +{ + vkDeviceWaitIdle(*device); + + for (int i = 0; i < amountImages; i++) + { + vkDestroyImageView(*device, imageViews[i], NULL); + } + + vkDestroySwapchainKHR(*device, *swapChain, NULL); + vkDestroySurfaceKHR(*vkInstance, *surface, NULL); + vkDestroyDevice(*device, NULL); + vkDestroyInstance(*vkInstance, NULL); +} + +void shutdownGLFW(GLFWwindow *window) +{ + glfwDestroyWindow(window); + glfwTerminate(); +} + +void printStats(VkPhysicalDevice *physicalDevice, VkSurfaceKHR *surface) +{ + // Device Properties + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(*physicalDevice, &properties); + + printf("--------- DEVICE PROPERTIES ---------\n"); + uint32_t apiVersion = properties.apiVersion; + printf("Name: %s\n", properties.deviceName); + printf("API Version: %d.%d.%d\n", VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion), VK_VERSION_PATCH(apiVersion)); + + // Features + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceFeatures(*physicalDevice, &features); + + printf("\n--------- FEATURES ---------\n"); + printf("Geometry Shader: %s\n", (BOOL_LITERAL(features.geometryShader))); + printf("Tessellation Shader: %s\n", (BOOL_LITERAL(features.tessellationShader))); + + // Memory Properties + VkPhysicalDeviceMemoryProperties memoryProperties; + vkGetPhysicalDeviceMemoryProperties(*physicalDevice, &memoryProperties); + + printf("\n--------- MEMORY PROPERTIES ---------\n"); + printf("Heapsize: %llu Byte / %f GiB\n", memoryProperties.memoryHeaps->size, + (HUMAN_READABLE(memoryProperties.memoryHeaps->size))); + + // Queue Properties + uint32_t amountQueueFamilies = 0; + vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &amountQueueFamilies, NULL); + VkQueueFamilyProperties familyProperties[amountQueueFamilies]; + vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &amountQueueFamilies, familyProperties); + + printf("\n--------- QUEUE PROPERTIES ---------\n"); + printf("Queue Families Amount: %d\n", amountQueueFamilies); + + for (int i = 0; i < amountQueueFamilies; i++) + { + printf("-- Queue Family #%d --\n", i); + printf(" Graphics bit: %s\n", (BOOL_LITERAL((familyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0))); + printf(" Compute bit: %s\n", (BOOL_LITERAL((familyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0))); + printf(" Transfer bit: %s\n", (BOOL_LITERAL((familyProperties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0))); + printf(" Sparse Binding bit: %s\n", (BOOL_LITERAL((familyProperties[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0))); + printf(" Queue Count: %d\n", familyProperties[i].queueCount); + } + + // Surface Capabilities + VkSurfaceCapabilitiesKHR surfaceCapabilities; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*physicalDevice, *surface, &surfaceCapabilities); + printf("\n--------- SURFACE CAPABILITIES ---------\n"); + printf(" Min Image Count: %d\n", surfaceCapabilities.minImageCount); + printf(" Max Image Count: %d\n", surfaceCapabilities.maxImageCount); + printf(" Current Extent: (%d; %d)\n", surfaceCapabilities.currentExtent.width, surfaceCapabilities.currentExtent.height); + printf(" Min Image Extent: (%d; %d)\n", surfaceCapabilities.minImageExtent.width, surfaceCapabilities.minImageExtent.height); + printf(" Max Image Extent: (%d; %d)\n", surfaceCapabilities.maxImageExtent.width, surfaceCapabilities.maxImageExtent.height); + printf(" Max Image Array Layers: %d\n", surfaceCapabilities.maxImageArrayLayers); + printf(" Supported Transforms: %d\n", surfaceCapabilities.supportedTransforms); + printf(" Current Transform: %d\n", surfaceCapabilities.currentTransform); + printf(" Supported Composite Alpha: %d\n", surfaceCapabilities.supportedCompositeAlpha); + printf(" Supported Usage Flags: %d\n", surfaceCapabilities.supportedUsageFlags); + + // Surface Formats + uint32_t amountFormats; + vkGetPhysicalDeviceSurfaceFormatsKHR(*physicalDevice, *surface, &amountFormats, NULL); + VkSurfaceFormatKHR formats[amountFormats]; + vkGetPhysicalDeviceSurfaceFormatsKHR(*physicalDevice, *surface, &amountFormats, formats); + + printf("\n--------- SURFACE FORMATS ---------\n"); + printf("Surface Formats Amount: %d\n", amountFormats); + + for (int i = 0; i < amountFormats; i++) + { + printf("-- Surface Format #%d --\n", i); + printf(" Format: %d\n", formats[i].format); + } + + // Presentation Modes + uint32_t amountPresentModes; + vkGetPhysicalDeviceSurfacePresentModesKHR(*physicalDevice, *surface, &amountPresentModes, NULL); + VkPresentModeKHR presentModes[amountPresentModes]; + vkGetPhysicalDeviceSurfacePresentModesKHR(*physicalDevice, *surface, &amountPresentModes, presentModes); + + printf("\n--------- PRESENTATION MODES ---------\n"); + printf("Presentation Modes Amount: %d\n", amountPresentModes); + + for (int i = 0; i < amountPresentModes; ++i) + { + printf("-- Present Mode #%d --\n", i); + printf(" Mode: %d\n", presentModes[i]); + } +} \ No newline at end of file