Created
March 23, 2020 23:38
-
-
Save lhog/432af74ba41259e062f18910b5904684 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <glad/glad.h> | |
#include <GLFW/glfw3.h> | |
#include <memory> | |
#include <iostream> | |
#include <cassert> | |
void framebuffer_size_callback(GLFWwindow* window, int width, int height); | |
void processInput(GLFWwindow *window); | |
// settings | |
const unsigned int SCR_WIDTH = 1920; | |
const unsigned int SCR_HEIGHT = 1080; | |
//#define RUN_QUERY | |
//#define PRINT_QUERY | |
//#define DUMP_BUFFER | |
//#define DEBUG_GL | |
//#define MAPUNMAP | |
#define DRAW_ARRAYS_INDIRECT | |
#define RENDERING_PATH 1 | |
constexpr int bufferingFactor = 1; | |
constexpr int NUM_TRIANGLES = 128; | |
constexpr int TESS_LEVEL = 32; | |
constexpr int TESS_LEVEL_MAX = 64; | |
const char* vsSrc = R"####( | |
#version 330 core | |
layout (location = 0) in vec3 aPos; | |
void main() | |
{ | |
gl_Position = vec4(aPos, 1.0); | |
} | |
)####"; | |
const char* fsSrc = R"####( | |
#version 330 core | |
out vec4 FragColor; | |
void main() | |
{ | |
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); | |
} | |
)####"; | |
const char* tcsSrc = R"####( | |
#version 330 core | |
#extension GL_ARB_tessellation_shader : enable | |
layout(vertices = 3) out; | |
uniform int tessLevel; | |
void main(void) | |
{ | |
gl_TessLevelOuter[0] = float(tessLevel); | |
gl_TessLevelOuter[1] = gl_TessLevelOuter[0]; | |
gl_TessLevelOuter[2] = gl_TessLevelOuter[0]; | |
gl_TessLevelInner[0] = gl_TessLevelOuter[0]; | |
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; | |
} | |
)####"; | |
const char* tesSrc = R"####( | |
#version 330 core | |
#extension GL_ARB_tessellation_shader : enable | |
layout( triangles, equal_spacing, ccw ) in; | |
uniform int tessLevel; | |
uniform float time; | |
out vec4 vPosTF; | |
void main() | |
{ | |
gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + | |
gl_TessCoord.y * gl_in[1].gl_Position + | |
gl_TessCoord.z * gl_in[2].gl_Position; | |
gl_Position.x += 0.1 * sin(3.0 * time + gl_Position.y); | |
vPosTF = gl_Position; | |
} | |
)####"; | |
const char* gsSrc = R"####( | |
#version 330 core | |
#extension GL_ARB_geometry_shader4 : require | |
#extension GL_ARB_shader_storage_buffer_object : require | |
//#extension GL_ARB_tessellation_shader : enable | |
//#extension GL_ARB_shader_image_load_store : require | |
#line 105 | |
layout ( triangles ) in; | |
layout ( triangle_strip, max_vertices = 3 ) out; | |
//coherent volatile, coherent volatile | |
layout(std140, binding = 1) buffer AuxSSBO { | |
int count; | |
int primCount; | |
int first; | |
int baseInstance; | |
}; | |
//coherent volatile, coherent volatile | |
layout(std140, binding = 2) writeonly buffer TrianglesSSBO { | |
writeonly vec4 pos[]; | |
}; | |
void main() { | |
//takeLock(); | |
int idx = atomicAdd(count, 3); | |
for (int i = 0; i < 3; ++i) { | |
gl_Position = gl_in[i].gl_Position; | |
gl_PrimitiveID = idx / 3; | |
pos[idx + i] = vec4(gl_in[i].gl_Position.xyz, 1.0); | |
EmitVertex(); | |
} | |
EndPrimitive(); | |
//releaseLock(); | |
} | |
)####"; | |
static char infoLog[4096]; | |
GLuint MyCompileShader(GLenum shaderType, const char* shaderSource, const char* shaderName) { | |
GLuint sh = glCreateShader(shaderType); | |
glShaderSource(sh, 1, &shaderSource, NULL); | |
glCompileShader(sh); | |
static int success; | |
glGetShaderiv(sh, GL_COMPILE_STATUS, &success); | |
if (!success) | |
{ | |
if (shaderName) { | |
glGetShaderInfoLog(sh, sizeof(infoLog), NULL, infoLog); | |
std::cout << "ERROR COMPILING SHADER: " << shaderName << "\n\n" << infoLog << std::endl; | |
} | |
glDeleteShader(sh); | |
sh = 0; | |
} | |
return sh; | |
} | |
void APIENTRY glDebugOutput(GLenum source, | |
GLenum type, | |
GLuint id, | |
GLenum severity, | |
GLsizei length, | |
const GLchar* message, | |
const void* userParam) | |
{ | |
// ignore non-significant error/warning codes | |
if (id == 131169 || id == 131185 || id == 131218 || id == 131204) return; | |
std::cout << "---------------" << std::endl; | |
std::cout << "Debug message (" << id << "): " << message << std::endl; | |
switch (source) | |
{ | |
case GL_DEBUG_SOURCE_API: std::cout << "Source: API"; break; | |
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: std::cout << "Source: Window System"; break; | |
case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cout << "Source: Shader Compiler"; break; | |
case GL_DEBUG_SOURCE_THIRD_PARTY: std::cout << "Source: Third Party"; break; | |
case GL_DEBUG_SOURCE_APPLICATION: std::cout << "Source: Application"; break; | |
case GL_DEBUG_SOURCE_OTHER: std::cout << "Source: Other"; break; | |
} std::cout << std::endl; | |
switch (type) | |
{ | |
case GL_DEBUG_TYPE_ERROR: std::cout << "Type: Error"; break; | |
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cout << "Type: Deprecated Behaviour"; break; | |
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: std::cout << "Type: Undefined Behaviour"; break; | |
case GL_DEBUG_TYPE_PORTABILITY: std::cout << "Type: Portability"; break; | |
case GL_DEBUG_TYPE_PERFORMANCE: std::cout << "Type: Performance"; break; | |
case GL_DEBUG_TYPE_MARKER: std::cout << "Type: Marker"; break; | |
case GL_DEBUG_TYPE_PUSH_GROUP: std::cout << "Type: Push Group"; break; | |
case GL_DEBUG_TYPE_POP_GROUP: std::cout << "Type: Pop Group"; break; | |
case GL_DEBUG_TYPE_OTHER: std::cout << "Type: Other"; break; | |
} std::cout << std::endl; | |
switch (severity) | |
{ | |
case GL_DEBUG_SEVERITY_HIGH: std::cout << "Severity: high"; break; | |
case GL_DEBUG_SEVERITY_MEDIUM: std::cout << "Severity: medium"; break; | |
case GL_DEBUG_SEVERITY_LOW: std::cout << "Severity: low"; break; | |
case GL_DEBUG_SEVERITY_NOTIFICATION: std::cout << "Severity: notification"; break; | |
} std::cout << std::endl; | |
std::cout << std::endl; | |
} | |
GLenum glCheckError_(const char* file, int line) | |
{ | |
GLenum errorCode; | |
while ((errorCode = glGetError()) != GL_NO_ERROR) | |
{ | |
std::string error; | |
switch (errorCode) | |
{ | |
case GL_INVALID_ENUM: error = "INVALID_ENUM"; break; | |
case GL_INVALID_VALUE: error = "INVALID_VALUE"; break; | |
case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break; | |
case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break; | |
case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break; | |
case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break; | |
case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; | |
} | |
std::cout << error << " | " << file << " (" << line << ")" << std::endl; | |
} | |
return errorCode; | |
} | |
#define glCheckError() glCheckError_(__FILE__, __LINE__) | |
int main() | |
{ | |
// glfw: initialize and configure | |
// ------------------------------ | |
glfwInit(); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); | |
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |
#ifdef DEBUG_GL | |
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); | |
#endif | |
#ifdef __APPLE__ | |
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X | |
#endif | |
// glfw window creation | |
// -------------------- | |
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); | |
if (window == NULL) | |
{ | |
std::cout << "Failed to create GLFW window" << std::endl; | |
glfwTerminate(); | |
return -1; | |
} | |
glfwMakeContextCurrent(window); | |
glfwSwapInterval(0); | |
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); | |
// glad: load all OpenGL function pointers | |
// --------------------------------------- | |
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) | |
{ | |
std::cout << "Failed to initialize GLAD" << std::endl; | |
return -1; | |
} | |
#ifdef DEBUG_GL | |
// enable OpenGL debug context if context allows for debug context | |
GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags); | |
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) | |
{ | |
glEnable(GL_DEBUG_OUTPUT); | |
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // makes sure errors are displayed synchronously | |
glDebugMessageCallback(glDebugOutput, nullptr); | |
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); | |
} | |
#endif | |
///// | |
GLint param; | |
glGetIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, ¶m); | |
assert(param >= 2); | |
// build and compile our shader program | |
// ------------------------------------ | |
// vertex shader | |
int vertexShader = MyCompileShader(GL_VERTEX_SHADER, vsSrc, "VS"); | |
// fragment shader | |
int fragmentShader = MyCompileShader(GL_FRAGMENT_SHADER, fsSrc, "FS"); | |
// TCS shader | |
int tcsShader = MyCompileShader(GL_TESS_CONTROL_SHADER, tcsSrc, "TCS"); | |
// TES shader | |
int tesShader = MyCompileShader(GL_TESS_EVALUATION_SHADER, tesSrc, "TES"); | |
// GS shader | |
int gsShader = MyCompileShader(GL_GEOMETRY_SHADER, gsSrc, "GS"); | |
// link shaders | |
GLuint drawProg = glCreateProgram(); | |
glAttachShader(drawProg, vertexShader); | |
glAttachShader(drawProg, fragmentShader); | |
glLinkProgram(drawProg); | |
// check for linking errors | |
GLint success; | |
glGetProgramiv(drawProg, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(drawProg, sizeof(infoLog), NULL, infoLog); | |
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; | |
} | |
GLuint tessProg = glCreateProgram(); | |
glAttachShader(tessProg, vertexShader); | |
glAttachShader(tessProg, tcsShader); | |
glAttachShader(tessProg, tesShader); | |
glAttachShader(tessProg, fragmentShader); | |
glLinkProgram(tessProg); | |
// check for linking errors | |
glGetProgramiv(tessProg, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(tessProg, sizeof(infoLog), NULL, infoLog); | |
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; | |
} | |
//////// | |
GLuint tfProg = glCreateProgram(); | |
glAttachShader(tfProg, vertexShader); | |
glAttachShader(tfProg, tcsShader); | |
glAttachShader(tfProg, tesShader); | |
//glAttachShader(tfProg, gsShader); | |
const char* tfVarying = "vPosTF"; | |
glTransformFeedbackVaryings(tfProg, 1, &tfVarying, GL_INTERLEAVED_ATTRIBS); | |
glLinkProgram(tfProg); | |
// check for linking errors | |
glGetProgramiv(tfProg, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(tfProg, sizeof(infoLog), NULL, infoLog); | |
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; | |
} | |
//////// | |
GLuint ssboProg = glCreateProgram(); | |
glAttachShader(ssboProg, vertexShader); | |
glAttachShader(ssboProg, tcsShader); | |
glAttachShader(ssboProg, tesShader); | |
glAttachShader(ssboProg, gsShader); | |
//glAttachShader(ssboProg, fragmentShader); | |
glLinkProgram(ssboProg); | |
// check for linking errors | |
glGetProgramiv(ssboProg, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(ssboProg, sizeof(infoLog), NULL, infoLog); | |
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; | |
} | |
//////// | |
glDeleteShader(vertexShader); | |
glDeleteShader(fragmentShader); | |
glDeleteShader(tcsShader); | |
glDeleteShader(tesShader); | |
// set up vertex data (and buffer(s)) and configure vertex attributes | |
// ------------------------------------------------------------------ | |
const float verticesShape[] = { | |
-1.0f, -0.75f, 0.0f, // left | |
1.0f, -0.75f, 0.0f, // right | |
0.0f, 0.75f, 0.0f, // top | |
}; | |
float vertices[NUM_TRIANGLES * 3 * 3]; | |
constexpr float downScaleFactor = 1.0 / float(NUM_TRIANGLES); | |
constexpr int verticesShapeVC = sizeof(verticesShape) / sizeof(verticesShape[0]); | |
for (int i = 0; i < NUM_TRIANGLES; ++i) { | |
vertices[verticesShapeVC * i + 0] = ((0.5f * verticesShape[0] + 0.5f) * downScaleFactor + i * downScaleFactor) * 2.0f - 1.0f; | |
vertices[verticesShapeVC * i + 1] = verticesShape[1]; | |
vertices[verticesShapeVC * i + 2] = verticesShape[2]; | |
vertices[verticesShapeVC * i + 3] = ((0.5f * verticesShape[3] + 0.5f) * downScaleFactor + i * downScaleFactor) * 2.0f - 1.0f; | |
vertices[verticesShapeVC * i + 4] = verticesShape[4]; | |
vertices[verticesShapeVC * i + 5] = verticesShape[5]; | |
vertices[verticesShapeVC * i + 6] = ((0.5f * verticesShape[6] + 0.5f) * downScaleFactor + i * downScaleFactor) * 2.0f - 1.0f; | |
vertices[verticesShapeVC * i + 7] = verticesShape[7]; | |
vertices[verticesShapeVC * i + 8] = verticesShape[8]; | |
} | |
unsigned int VBO, VAO; | |
glGenVertexArrays(1, &VAO); | |
glGenBuffers(1, &VBO); | |
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). | |
glBindVertexArray(VAO); | |
glBindBuffer(GL_ARRAY_BUFFER, VBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); | |
glEnableVertexAttribArray(0); | |
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other | |
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. | |
glBindVertexArray(0); | |
/////// | |
// Set Tesselation uniforms | |
// ------------------------------------------------------------------ | |
GLint loc, loc2; | |
loc = glGetUniformLocation(tfProg, "tessLevel"); | |
loc2 = glGetUniformLocation(tfProg, "time"); | |
glUseProgram(tfProg); | |
glUniform1i(loc, TESS_LEVEL); | |
glUseProgram(0); | |
loc = glGetUniformLocation(ssboProg, "tessLevel"); | |
loc2 = glGetUniformLocation(ssboProg, "time"); | |
glUseProgram(ssboProg); | |
glUniform1i(loc, TESS_LEVEL); | |
glUseProgram(0); | |
loc = glGetUniformLocation(tessProg, "tessLevel"); | |
loc2 = glGetUniformLocation(tessProg, "time"); | |
glUseProgram(tessProg); | |
glUniform1i(loc, TESS_LEVEL); | |
glUseProgram(0); | |
/////// | |
constexpr int TESS_TRIA_NUM = TESS_LEVEL * TESS_LEVEL * 3 / 2 * NUM_TRIANGLES; | |
constexpr int TESS_TRIA_NUM_MAX = TESS_LEVEL_MAX * TESS_LEVEL_MAX * 3 / 2 * NUM_TRIANGLES; | |
struct TrianglesTF { | |
float pos[3 * TESS_TRIA_NUM][4]; //only xyz are useful | |
}; | |
auto trianglesTF = std::make_unique <TrianglesTF>(); | |
// Transform Feedback part | |
// ------------------------------------------------------------------ | |
GLuint tfvao; | |
GLuint tfbo, tfbb, tfbpw; | |
glGenVertexArrays(1, &tfvao); | |
glGenTransformFeedbacks(1, &tfbo); | |
glGenBuffers(1, &tfbb); | |
glGenQueries(1, &tfbpw); | |
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfbb); | |
// 3 x vec4 in triangle, TESS_TRIA_NUM triangles | |
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(TrianglesTF), nullptr, GL_DYNAMIC_COPY); | |
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfbo); | |
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfbb); | |
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); | |
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); | |
glBindVertexArray(tfvao); | |
glBindBuffer(GL_ARRAY_BUFFER, tfbb); | |
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); | |
glEnableVertexAttribArray(0); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
glBindVertexArray(0); | |
// SSBO part | |
// ------------------------------------------------------------------ | |
struct AuxSSBO { | |
GLuint count; | |
GLuint primCount; | |
GLuint first; | |
GLuint baseInstance; | |
}; | |
std::shared_ptr<AuxSSBO> auxSSBOs[bufferingFactor]; | |
struct TrianglesSSBO { | |
float pos[3 * TESS_TRIA_NUM][4]; //only xyz are useful | |
}; | |
std::shared_ptr<TrianglesSSBO> trianglesSSBOs[bufferingFactor]; | |
for (int i = 0; i < bufferingFactor; ++i) { | |
trianglesSSBOs[i] = std::make_shared<TrianglesSSBO>(); | |
auxSSBOs[i] = std::make_shared<AuxSSBO>(); | |
} | |
GLuint ssboVAOs[bufferingFactor]; | |
//GLuint ssboBuf; | |
GLuint ssboPCBufs[bufferingFactor], ssboTrBufs[bufferingFactor]; | |
GLuint ssboQuerys[bufferingFactor]; | |
glGenVertexArrays(bufferingFactor, &ssboVAOs[0]); | |
//glGenBuffers(1, &ssboBuf); | |
glGenBuffers(bufferingFactor, &ssboPCBufs[0]); | |
glGenBuffers(bufferingFactor, &ssboTrBufs[0]); | |
glGenQueries(bufferingFactor, &ssboQuerys[0]); | |
for (int i = 0; i < bufferingFactor; ++i) { | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ssboPCBufs[i]); | |
//glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(AuxSSBO), nullptr, GL_STATIC_DRAW); | |
//glBufferStorage(GL_DRAW_INDIRECT_BUFFER, sizeof(AuxSSBO), auxSSBOs[i].get(), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT); | |
#ifdef DRAW_ARRAYS_INDIRECT | |
glBufferStorage(GL_DRAW_INDIRECT_BUFFER, sizeof(AuxSSBO), auxSSBOs[i].get(), GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT); | |
#else | |
glBufferStorage(GL_DRAW_INDIRECT_BUFFER, sizeof(AuxSSBO), auxSSBOs[i].get(), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT); | |
#endif | |
//glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(AuxSSBO), auxSSBOs[i].get(), GL_DYNAMIC_DRAW); | |
//glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssboPCBufs[i]); | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); | |
memset(trianglesSSBOs[i].get(), 255, sizeof(TrianglesSSBO)); | |
// GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY | |
//GLenum usage = ; | |
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboTrBufs[i]); | |
glBufferStorage(GL_SHADER_STORAGE_BUFFER, sizeof(TrianglesSSBO), trianglesSSBOs[i].get(), 0); | |
//glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(TrianglesSSBO), trianglesSSBOs[i].get(), GL_DYNAMIC_COPY); | |
//glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssboTrBufs[i]); | |
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); | |
} | |
GLuint blkIdx; | |
GLuint blkBinding; | |
//better done in shader "layout(std140, binding = 1)" | |
blkIdx = glGetProgramResourceIndex(ssboProg, GL_SHADER_STORAGE_BLOCK, "AuxSSBO"); | |
blkBinding = 1; | |
glShaderStorageBlockBinding(ssboProg, blkIdx, blkBinding); | |
//better done in shader "layout(std140, binding = 2)" | |
blkIdx = glGetProgramResourceIndex(ssboProg, GL_SHADER_STORAGE_BLOCK, "TrianglesSSBO"); | |
blkBinding = 2; | |
glShaderStorageBlockBinding(ssboProg, blkIdx, blkBinding); | |
/////// | |
for (int i = 0; i < bufferingFactor; ++i) { | |
glBindVertexArray(ssboVAOs[i]); | |
glBindBuffer(GL_ARRAY_BUFFER, ssboTrBufs[i]); | |
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid*)(0)); | |
glEnableVertexAttribArray(0); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
glBindVertexArray(0); | |
} | |
// uncomment this call to draw in wireframe polygons. | |
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | |
//////// | |
double previousTime = glfwGetTime(); | |
uint32_t frameCount = 0u; | |
uint64_t drawFrame = 0u; | |
// render loop | |
// ----------- | |
while (!glfwWindowShouldClose(window)) | |
{ | |
// input | |
// ----- | |
processInput(window); | |
// Measure speed | |
double currentTime = glfwGetTime(); | |
frameCount++; | |
// If a second has passed. | |
if (currentTime - previousTime >= 1.0) | |
{ | |
// Display the frame count here any way you want. | |
printf("%f ms/frame %I32d FPS\n", 1000.0 / double(frameCount), frameCount); | |
frameCount = 0; | |
previousTime = currentTime; | |
} | |
float time = (float)glfwGetTime(); | |
// TF | |
#if (RENDERING_PATH == 1) | |
GLuint numPrimitivesWritten = 0u; | |
glEnable(GL_RASTERIZER_DISCARD); | |
{ | |
glBindVertexArray(VAO); | |
glUseProgram(tfProg); | |
glUniform1f(loc2, time); | |
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfbo); | |
{ | |
#ifdef RUN_QUERY | |
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, tfbpw); | |
#endif | |
glBeginTransformFeedback(GL_TRIANGLES); | |
glDrawArrays(GL_PATCHES, 0, sizeof(vertices) / sizeof(vertices[0]) / 3); | |
glEndTransformFeedback(); | |
#ifdef RUN_QUERY | |
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); | |
glGetQueryObjectuiv(tfbpw, GL_QUERY_RESULT, &numPrimitivesWritten); //in triangles | |
#ifdef PRINT_QUERY | |
printf("TransformFeedback wrote [%d] primitives\n", numPrimitivesWritten); | |
#endif | |
#endif | |
} | |
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); | |
glUseProgram(0); | |
glBindVertexArray(0); | |
} | |
glDisable(GL_RASTERIZER_DISCARD); | |
#ifdef DUMP_BUFFER | |
memset(trianglesTF.get(), 0, sizeof(TrianglesTF)); | |
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfbb); | |
glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(TrianglesTF), trianglesTF.get()); | |
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); | |
#endif | |
#elif (RENDERING_PATH == 2) | |
uint32_t bufIdx = drawFrame % bufferingFactor; | |
auto ssboVAO = ssboVAOs[bufIdx]; | |
//GLuint ssboBuf; | |
auto ssboPCBuf = ssboPCBufs[bufIdx]; | |
auto ssboTrBuf = ssboTrBufs[bufIdx]; | |
auto ssboQuery = ssboQuerys[bufIdx]; | |
auto auxSSBO = auxSSBOs[bufIdx]; | |
auto trianglesSSBO = trianglesSSBOs[bufIdx]; | |
memset(auxSSBO.get(), 0, sizeof(AuxSSBO)); | |
auxSSBO->primCount = 1u; | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ssboPCBuf); | |
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(AuxSSBO), auxSSBO.get()); | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); | |
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssboPCBuf); | |
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssboTrBuf); | |
GLuint numPrimitivesWritten = 0u; | |
glEnable(GL_RASTERIZER_DISCARD); | |
{ | |
glBindVertexArray(VAO); | |
glUseProgram(ssboProg); | |
glUniform1f(loc2, time); | |
#ifdef RUN_QUERY | |
glBeginQuery(GL_PRIMITIVES_GENERATED, ssboQuery); | |
#endif | |
glDrawArrays(GL_PATCHES, 0, sizeof(vertices) / sizeof(vertices[0]) / 3); | |
#ifdef RUN_QUERY | |
glEndQuery(GL_PRIMITIVES_GENERATED); | |
glGetQueryObjectuiv(ssboQuery, GL_QUERY_RESULT, &numPrimitivesWritten); //in triangles | |
#ifdef PRINT_QUERY | |
printf("SSBO wrote [%d] primitives\n", numPrimitivesWritten); | |
#endif | |
#endif | |
//glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); | |
glUseProgram(0); | |
glBindVertexArray(0); | |
} | |
glDisable(GL_RASTERIZER_DISCARD); | |
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT); | |
#ifdef DUMP_BUFFER | |
memset(trianglesSSBO.get(), 255, sizeof(TrianglesSSBO)); | |
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboTrBuf); | |
/* | |
glMemoryBarrier(GL_ALL_BARRIER_BITS); | |
glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | |
glFinish(); | |
*/ | |
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(TrianglesSSBO), trianglesSSBO.get()); | |
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); | |
memset(auxSSBO.get(), 0, sizeof(AuxSSBO)); | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ssboPCBuf); | |
/* | |
glMemoryBarrier(GL_ALL_BARRIER_BITS); | |
glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | |
glFinish(); | |
*/ | |
glGetBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(AuxSSBO), auxSSBO.get()); | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); | |
#endif | |
#endif | |
// render | |
// ------ | |
// draw our first triangle | |
#if (RENDERING_PATH == 1) | |
glUseProgram(drawProg); | |
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBindVertexArray(tfvao); | |
glDrawTransformFeedback(GL_TRIANGLES, tfbo); | |
glBindVertexArray(0); | |
#elif (RENDERING_PATH == 2) | |
glUseProgram(drawProg); | |
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
//int numPrimToRender = 0; | |
AuxSSBO tmpAuxSSBO; | |
AuxSSBO* pTmpAuxSSBO = &tmpAuxSSBO; | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ssboPCBuf); | |
{ | |
#ifndef DRAW_ARRAYS_INDIRECT | |
#ifdef MAPUNMAP | |
//pTmpAuxSSBO = static_cast<AuxSSBO*>(glMapBuffer(GL_DRAW_INDIRECT_BUFFER, GL_READ_ONLY)); | |
pTmpAuxSSBO = static_cast<AuxSSBO*>(glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(AuxSSBO), GL_MAP_READ_BIT)); | |
#else | |
//glGetBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(AuxSSBO), pTmpAuxSSBO); | |
#endif | |
#endif | |
glBindVertexArray(ssboVAO); | |
#ifndef DRAW_ARRAYS_INDIRECT | |
glDrawArrays(GL_TRIANGLES, 0, pTmpAuxSSBO->count); | |
#else | |
glDrawArraysIndirect(GL_TRIANGLES, 0); | |
#ifdef MAPUNMAP | |
glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); | |
#endif | |
#endif | |
} | |
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); | |
//glDrawArrays(GL_TRIANGLES, 0, 3 * numPrimitivesWritten); | |
glBindVertexArray(0); | |
#elif (RENDERING_PATH == 0) | |
glUseProgram(tessProg); | |
glUniform1f(loc2, time); | |
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized | |
glDrawArrays(GL_PATCHES, 0, sizeof(vertices) / sizeof(vertices[0]) / 3); | |
glBindVertexArray(0); | |
#endif | |
glUseProgram(0); | |
++drawFrame; | |
// glBindVertexArray(0); // no need to unbind it every time | |
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) | |
// ------------------------------------------------------------------------------- | |
glfwSwapBuffers(window); | |
glfwPollEvents(); | |
} | |
// optional: de-allocate all resources once they've outlived their purpose: | |
// ------------------------------------------------------------------------ | |
glDeleteVertexArrays(1, &VAO); | |
glDeleteBuffers(1, &VBO); | |
glDeleteProgram(drawProg); | |
glDeleteProgram(tfProg); | |
glDeleteProgram(tessProg); | |
glDeleteProgram(ssboProg); | |
/////// | |
glDeleteVertexArrays(1, &tfvao); | |
glDeleteBuffers(1, &tfbb); | |
glDeleteQueries(1, &tfbpw); | |
glDeleteTransformFeedbacks(1, &tfbo); | |
///// | |
glDeleteVertexArrays(bufferingFactor, &ssboVAOs[0]); | |
//glDeleteBuffers(1, &ssboBuf); | |
glDeleteBuffers(bufferingFactor, &ssboPCBufs[0]); | |
glDeleteBuffers(bufferingFactor, &ssboTrBufs[0]); | |
glDeleteQueries(bufferingFactor, &ssboQuerys[0]); | |
// glfw: terminate, clearing all previously allocated GLFW resources. | |
// ------------------------------------------------------------------ | |
glfwTerminate(); | |
return 0; | |
} | |
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly | |
// --------------------------------------------------------------------------------------------------------- | |
void processInput(GLFWwindow *window) | |
{ | |
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) | |
glfwSetWindowShouldClose(window, true); | |
} | |
// glfw: whenever the window size changed (by OS or user resize) this callback function executes | |
// --------------------------------------------------------------------------------------------- | |
void framebuffer_size_callback(GLFWwindow* window, int width, int height) | |
{ | |
// make sure the viewport matches the new window dimensions; note that width and | |
// height will be significantly larger than specified on retina displays. | |
glViewport(0, 0, width, height); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment