From 9f40a59612951842127c5cf64373bb397facce40 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 8 Nov 2025 21:30:49 +0100 Subject: [PATCH] working project --- Shaders/Compute.glsl | 55 +++++++------ Shaders/Fragment.glsl | 8 ++ Shaders/Vertex.glsl | 15 ++++ src/Main.cpp | 176 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 211 insertions(+), 43 deletions(-) create mode 100644 Shaders/Fragment.glsl create mode 100644 Shaders/Vertex.glsl diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index 50a1882..8ceed32 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -2,31 +2,40 @@ layout(rgba32f, binding = 0) uniform writeonly image2D outputImage; -layout(local_size_x = 16, local_size_y = 16) in; +layout(std430, binding = 3) buffer layoutName +{ + vec2 o_Points[]; +}; + +// 1 -> 1 +// 2 -> 3 +// 3 -> 9 +// 4 -> 27 +// 5 -> 81 +// 6 -> 243 +// ... + +// 4 27 +// 1 + 3 + 9 = 13 + +// Sn = ((3^n)-1)/2 +// S3 = 3^3 - 1 / 2 +// 3^4 + +// gl_NumWorkGroups : This variable contains the number of work groups passed to the dispatch function. +// gl_WorkGroupID : This is the current work group for this shader invocation. Each of the XYZ components will be on the half-open range [0, gl_NumWorkGroups.XYZ). +// gl_LocalInvocationID : This is the current invocation of the shader within the work group. Each of the XYZ components will be on the half-open range [0, gl_WorkGroupSize.XYZ). + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; void main() { - ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); + uint triangleCount = gl_NumWorkGroups.x; + uint currentPoint = gl_WorkGroupID.x; - if (pixelCoord.x >= imageSize(outputImage).x || pixelCoord.y >= imageSize(outputImage).y) - return; + uint offset = (triangleCount - 1) / 2; - ivec2 texSize = imageSize(outputImage); - vec2 fTexSize = vec2(texSize); - vec2 normalizedCoord = vec2(pixelCoord) / vec2(texSize); - - vec4 O = vec4(0, 0, 0, 1); - vec2 I = vec2(pixelCoord); - - float iTime = 2.2; - float i = 0.0, t=iTime; - O *= i; - for(vec2 a=fTexSize.xy, p=(I+I-a)/a.y; i++<20.; - O += (cos(sin(i*.2+t)*vec4(0,4,3,1))+2.) - /(i/1e3+abs(length(a-.5*min(a+a.yx,.1))-.05))) - a.x = abs(a = (fract(.2*t+.3*p*i*mat2(cos(cos(.2*t+.2*i)+vec4(0,11,33,0))))-.5)).x; - - O = tanh(O*O/2e5); - - vec4 color = vec4(normalizedCoord, 0.0, 1.0); - imageStore(outputImage, pixelCoord, O); + uint firstPointIndex = offset * 3 + 1; + o_Points[firstPointIndex + currentPoint * 3 ] = o_Points[offset + currentPoint] / 2 + vec2(0, 0.36); + o_Points[firstPointIndex + currentPoint * 3 + 1] = o_Points[offset + currentPoint] / 2 + vec2(-0.5, -0.5); + o_Points[firstPointIndex + currentPoint * 3 + 2] = o_Points[offset + currentPoint] / 2 + vec2(0.5, -0.5); } \ No newline at end of file diff --git a/Shaders/Fragment.glsl b/Shaders/Fragment.glsl new file mode 100644 index 0000000..835cf1d --- /dev/null +++ b/Shaders/Fragment.glsl @@ -0,0 +1,8 @@ +#version 460 core + +layout (location = 0) out vec4 o_Color; + +void main() +{ + o_Color = vec4(1, 1, 1, 1); +} \ No newline at end of file diff --git a/Shaders/Vertex.glsl b/Shaders/Vertex.glsl new file mode 100644 index 0000000..e8ba39a --- /dev/null +++ b/Shaders/Vertex.glsl @@ -0,0 +1,15 @@ +#version 460 core + +layout(location = 0) in vec2 a_Position; + +layout(std430, binding = 3) buffer layoutName +{ + vec2 data_SSBO[]; +}; + +out vec2 v_TexCoord; + +void main() +{ + gl_Position = vec4(data_SSBO[gl_InstanceID], 0.0, 1.0); +} \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 9d473cf..c82cf47 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,25 +1,93 @@ #include #include +#include #include "Shader.h" #include "Renderer.h" -static uint32_t s_ComputeShader = -1; -static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; +#include -static void ErrorCallback(int error, const char* description) +class Timer +{ +public: + Timer() { Reset(); } + void Reset() { m_Start = std::chrono::high_resolution_clock::now(); } + float Elapsed() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f * 0.001f; } + float ElapsedMillis() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f; } + +private: + std::chrono::time_point m_Start; +}; + +class ScopedTimer +{ +public: + ScopedTimer(std::string_view name) : m_Name(name) {} + ~ScopedTimer() + { + float time = m_Timer.ElapsedMillis(); + std::cout << m_Name << " - " << time << "ms\n"; + } + +private: + Timer m_Timer; + std::string m_Name; +}; + +static uint32_t s_ComputeShader = -1; +static uint32_t s_GraphicsShader = -1; +static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; +static const std::filesystem::path s_VertexShaderPath = "Shaders/Vertex.glsl"; +static const std::filesystem::path s_FragmentShaderPath = "Shaders/Fragment.glsl"; + +static void ErrorCallback(int error, const char *description) { std::cerr << "Error: " << description << std::endl; } -static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); if (key == GLFW_KEY_R) + { s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); + s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); + } +} + +std::vector GenPoints(float x, float y) +{ + x /= 2; + y /= 2; + return { + x, y + 0.36f, + x - 0.5f, y - 0.5f, + x + 0.5f, y - 0.5f}; +} + +std::vector GetPoints(int depth) +{ + std::vector result = {0.0f, 0.0f}; + std::size_t offset = 0; + std::size_t count = 1; + for (std::size_t i = 1; i < depth; i++) + { + for (std::size_t j = 0; j < count; j++) + { + std::size_t index = offset + j * 2; + auto newPoints = GenPoints(result[index], result[index + 1]); + result.insert(result.end(), newPoints.begin(), newPoints.end()); + } + offset += count * 2; + count *= 3; + } + return result; } int main() @@ -35,7 +103,7 @@ int main() int width = 1280; int height = 720; - GLFWwindow* window = glfwCreateWindow(width, height, "Compute", NULL, NULL); + GLFWwindow *window = glfwCreateWindow(width, height, "Compute", NULL, NULL); if (!window) { glfwTerminate(); @@ -55,11 +123,82 @@ int main() return -1; } + s_GraphicsShader = CreateGraphicsShader(s_VertexShaderPath, s_FragmentShaderPath); + if (s_GraphicsShader == -1) + { + std::cerr << "Graphics shader failed\n"; + return -1; + } + Texture computeShaderTexture = CreateTexture(width, height); Framebuffer fb = CreateFramebufferWithTexture(computeShaderTexture); - + + GLuint vertexArray; + glCreateVertexArrays(1, &vertexArray); + + GLuint vertexBuffer; + glCreateBuffers(1, &vertexBuffer); + + constexpr int DEPTH = 13; + + auto vertices = GetPoints(DEPTH); + + glNamedBufferData(vertexBuffer, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); + + glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 2); + + glEnableVertexArrayAttrib(vertexArray, 0); + glEnableVertexArrayAttrib(vertexArray, 1); + + glVertexArrayAttribFormat(vertexArray, 0, 2, GL_FLOAT, GL_FALSE, 0); + + glVertexArrayAttribBinding(vertexArray, 0, 0); + glVertexArrayAttribBinding(vertexArray, 1, 0); + + GLuint ssbo; + glGenBuffers(1, &ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * vertices.size(), nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. + + float lastTime = (float)glfwGetTime(); + + int fps = 0; + float secondsTimer = 0.0f; + + // Compute + glUseProgram(s_ComputeShader); + glBindImageTexture(0, fb.ColorAttachment.Handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + + std::size_t count = 1; + for (std::size_t i = 0; i < DEPTH; i++) + { + glDispatchCompute(count, 1, 1); + + // Ensure all writes to the image are complete + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + count *= 3; + } + while (!glfwWindowShouldClose(window)) { + // ScopedTimer timer("Main Loop"); + + float currentTime = (float)glfwGetTime(); + float dt = currentTime - lastTime; + lastTime = currentTime; + + secondsTimer += dt; + if (secondsTimer >= 1.0f) + { + std::string title = "FPS : " + std::to_string(fps); + glfwSetWindowTitle(window, title.c_str()); + + secondsTimer = 0.0f; + fps = 0; + } + glfwGetFramebufferSize(window, &width, &height); // Resize texture @@ -70,22 +209,14 @@ int main() AttachTextureToFramebuffer(fb, computeShaderTexture); } - // Compute - { - glUseProgram(s_ComputeShader); - glBindImageTexture(0, fb.ColorAttachment.Handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + // Graphics + glBindFramebuffer(GL_FRAMEBUFFER, fb.Handle); + glUseProgram(s_GraphicsShader); - const GLuint workGroupSizeX = 16; - const GLuint workGroupSizeY = 16; + glBindVertexArray(vertexArray); + glDrawArraysInstanced(GL_POINTS, 0, 1, vertices.size()); - GLuint numGroupsX = (width + workGroupSizeX - 1) / workGroupSizeX; - GLuint numGroupsY = (height + workGroupSizeY - 1) / workGroupSizeY; - - glDispatchCompute(numGroupsX, numGroupsY, 1); - - // Ensure all writes to the image are complete - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - } + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Blit { @@ -94,6 +225,11 @@ int main() glfwSwapBuffers(window); glfwPollEvents(); + + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 1); + + fps++; } glfwDestroyWindow(window);