|
| 1 | +// spinning_triangle.cpp — OpenGL spinning triangle demo with Tracy GPU profiling. |
| 2 | + |
| 3 | +#ifdef __APPLE__ |
| 4 | +// NOTE: OpenGL is only available on MacOS (no iOS support) |
| 5 | +// Including and using anything related to OpenGL on Apple (like <OpenGL/gl3.h>) |
| 6 | +// will emit deprecation warnings, unless GL_SILENCE_DEPRECATION is defined |
| 7 | +#define GL_SILENCE_DEPRECATION |
| 8 | +// NOTE: TracyOpenGL.hpp will not work as expected even on Apple devices that |
| 9 | +// support OpenGL, because the OpenGL drivers do not implement ARB_timer_query |
| 10 | +// properly (querying GL_TIMESTAMP always resolves to 0). TracyOpenGL.hpp will |
| 11 | +// emit a compiler warning, and a Tracy message to the trace/profiler, but the |
| 12 | +// program will still run. |
| 13 | +#endif |
| 14 | + |
| 15 | +#include "platform/platform.h" // also includes OpenGL headers |
| 16 | + |
| 17 | +#include <tracy/Tracy.hpp> |
| 18 | + |
| 19 | +// NOTE: opt-in toggle for periodic recalibrations during Collect() |
| 20 | +#define TRACY_OPENGL_AUTO_CALIBRATION |
| 21 | +#include <tracy/TracyOpenGL.hpp> |
| 22 | + |
| 23 | +static const int kWidth = 800; |
| 24 | +static const int kHeight = 600; |
| 25 | + |
| 26 | +static GLuint gProgram = 0; |
| 27 | +static GLuint gVao = 0; |
| 28 | +static GLint gAngleLoc = -1; |
| 29 | + |
| 30 | +// Vertex colors and positions are baked in; rotation is driven by a uniform. |
| 31 | +static const char* kVertSrc = R"( |
| 32 | +#version 150 core |
| 33 | +uniform float uAngle; |
| 34 | +const vec2 kPos[3] = vec2[3]( |
| 35 | + vec2( 0.0, 0.5 ), |
| 36 | + vec2(-0.433, -0.25 ), |
| 37 | + vec2( 0.433, -0.25 ) |
| 38 | +); |
| 39 | +const vec3 kCol[3] = vec3[3]( |
| 40 | + vec3(1.0, 0.0, 0.0), |
| 41 | + vec3(0.0, 1.0, 0.0), |
| 42 | + vec3(0.0, 0.0, 1.0) |
| 43 | +); |
| 44 | +out vec3 vColor; |
| 45 | +void main() { |
| 46 | + float c = cos(uAngle); |
| 47 | + float s = sin(uAngle); |
| 48 | + vec2 p = kPos[gl_VertexID]; |
| 49 | + gl_Position = vec4(p.x*c - p.y*s, p.x*s + p.y*c, 0.0, 1.0); |
| 50 | + vColor = kCol[gl_VertexID]; |
| 51 | +} |
| 52 | +)"; |
| 53 | + |
| 54 | +static const char* kFragSrc = R"( |
| 55 | +#version 150 core |
| 56 | +in vec3 vColor; |
| 57 | +out vec4 fragColor; |
| 58 | +void main() { fragColor = vec4(vColor, 1.0); } |
| 59 | +)"; |
| 60 | + |
| 61 | +static GLuint compileShader(GLenum type, const char* src) { |
| 62 | + GLuint s = glCreateShader(type); |
| 63 | + glShaderSource(s, 1, &src, nullptr); |
| 64 | + glCompileShader(s); |
| 65 | + GLint ok = 0; |
| 66 | + glGetShaderiv(s, GL_COMPILE_STATUS, &ok); |
| 67 | + if (!ok) { |
| 68 | + char log[512]; |
| 69 | + glGetShaderInfoLog(s, sizeof(log), nullptr, log); |
| 70 | + fprintf(stderr, "Shader compile error: %s\n", log); |
| 71 | + glDeleteShader(s); |
| 72 | + return 0; |
| 73 | + } |
| 74 | + return s; |
| 75 | +} |
| 76 | + |
| 77 | +static int initGL() { |
| 78 | + if (!platformInitGL()) return 1; |
| 79 | + |
| 80 | + TracyGpuContext; |
| 81 | + TracyGpuContextName("OpenGL", 6); |
| 82 | + |
| 83 | + GLuint vert = compileShader(GL_VERTEX_SHADER, kVertSrc); |
| 84 | + GLuint frag = compileShader(GL_FRAGMENT_SHADER, kFragSrc); |
| 85 | + if (!vert || !frag) return 1; |
| 86 | + |
| 87 | + gProgram = glCreateProgram(); |
| 88 | + glAttachShader(gProgram, vert); |
| 89 | + glAttachShader(gProgram, frag); |
| 90 | + glLinkProgram(gProgram); |
| 91 | + glDeleteShader(vert); |
| 92 | + glDeleteShader(frag); |
| 93 | + |
| 94 | + GLint ok = 0; |
| 95 | + glGetProgramiv(gProgram, GL_LINK_STATUS, &ok); |
| 96 | + if (!ok) { |
| 97 | + char log[512]; |
| 98 | + glGetProgramInfoLog(gProgram, sizeof(log), nullptr, log); |
| 99 | + fprintf(stderr, "Program link error: %s\n", log); |
| 100 | + return 1; |
| 101 | + } |
| 102 | + |
| 103 | + gAngleLoc = glGetUniformLocation(gProgram, "uAngle"); |
| 104 | + |
| 105 | + // Core profile requires a bound VAO even with no vertex attributes. |
| 106 | + glGenVertexArrays(1, &gVao); |
| 107 | + glBindVertexArray(gVao); |
| 108 | + |
| 109 | + glClearColor(0.05f, 0.05f, 0.08f, 1.0f); |
| 110 | + float scaleX, scaleY; |
| 111 | + platformGetPixelDensityScale(&scaleX, &scaleY); |
| 112 | + glViewport(0, 0, (int)(kWidth * scaleX), (int)(kHeight * scaleY)); |
| 113 | + return 0; |
| 114 | +} |
| 115 | + |
| 116 | +static void renderFrame() { |
| 117 | + ZoneScoped; |
| 118 | + |
| 119 | + glClear(GL_COLOR_BUFFER_BIT); |
| 120 | + glUseProgram(gProgram); |
| 121 | + |
| 122 | + { |
| 123 | + TracyGpuZone("triangle draw"); |
| 124 | + glUniform1f(gAngleLoc, (float)platformGetTime()); |
| 125 | + glDrawArrays(GL_TRIANGLES, 0, 3); |
| 126 | + } |
| 127 | + |
| 128 | + platformSwapBuffers(); |
| 129 | + TracyGpuCollect; |
| 130 | +} |
| 131 | + |
| 132 | +static void shutdown() { |
| 133 | + fprintf(stderr, "application is shutting down...\n"); |
| 134 | + glDeleteVertexArrays(1, &gVao); |
| 135 | + glDeleteProgram(gProgram); |
| 136 | +} |
| 137 | + |
| 138 | +int main() { |
| 139 | + if (!platformInit(kWidth, kHeight, "OpenGL Spinning Triangle")) |
| 140 | + return 1; |
| 141 | + if (initGL() != 0) |
| 142 | + return 2; |
| 143 | + platformRunLoop(renderFrame, shutdown); |
| 144 | + return 0; |
| 145 | +} |
0 commit comments