Skip to content

Instantly share code, notes, and snippets.

@lhog
Created March 23, 2020 23:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lhog/432af74ba41259e062f18910b5904684 to your computer and use it in GitHub Desktop.
Save lhog/432af74ba41259e062f18910b5904684 to your computer and use it in GitHub Desktop.
#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, &param);
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