TransformFeedback in-shader specification

hi everyone,

i’m trying to replace the call:

glTransformFeedbackVaryings(program, ...)

my application is a simple triangle, but the vertex buffer isnt static, instead i’m using 2 vertex array object + 2 (vertex) buffer objects + 2 transform feedback object:
→ the VAOs + VBOs are set up similarly, as well as the transform feedback object
→ but the transform feedback buffers are doing “buffer pingpong-ing”, building a kind of double-buffered vertex array object


struct Vertex
{
	vec4 Position;
	vec4 Color;
};

unsigned int vertexarray[2] = { 0 };
unsigned int vertexbuffer[2] = { 0 };
unsigned int transformfeedback[2] = { 0 };

glGenVertexArrays(2, vertexarray);
glGenBuffers(2, vertexbuffer);
glGenTransformFeedbacks(2, transformfeedback);

// then the setup for vertex buffer pingponging ...

for (unsigned int i = 0; i < 2; i++)
{
	glBindVertexArray(vertexarray[i]);
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer[i]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_DYNAMIC_COPY);
	glVertexAttribPointer(0, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 0));
	glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 4));
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glBindVertexArray(0);
}

for (unsigned int i = 0; i < 2; i++)
{
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[i]);
	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vertexbuffer[1 - i]);
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
}


the vertex shader for this application is:


#version 450 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_color;

uniform mat4 Model = mat4(1);
uniform mat4 View = mat4(1);
uniform mat4 Projection = mat4(1);

out VS_FS_INTERFACE {
    vec4 color;
} vs_out;

out vec4 out_position;
out vec4 out_color;


void main(void)
{
    mat4 MVP = Projection * View * Model;
    gl_Position = MVP * vec4(in_position.xyz, 1);
    vs_out.color = in_color;

    out_position = Model * vec4(in_position.xyz, 1);
	out_color = in_color;
}

to tell the program object what data to capture, i call:


const char* varyings[] = {
	"out_position",
	"out_color",
};

glTransformFeedbackVaryings(program, sizeof(varyings) / sizeof(const char*), varyings, GL_INTERLEAVED_ATTRIBS);

THAT WORKS.

now i’m trying to replace that call via “in-shader specification”:
(by the way: the transform feedback buffer binding point == 0 for both transform feedback objects)


#version 450 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_color;

uniform mat4 Model = mat4(1);
uniform mat4 View = mat4(1);
uniform mat4 Projection = mat4(1);

out VS_FS_INTERFACE {
    vec4 color;
} vs_out;


layout (xfb_buffer = 0) out Feedback {
	layout (xfb_offset = 0)	vec4 out_position;
	layout (xfb_offset = 16)	vec4 out_color;
};


void main(void)
{
    mat4 MVP = Projection * View * Model;
    gl_Position = MVP * vec4(in_position.xyz, 1);
    vs_out.color = in_color;

    out_position = Model * vec4(in_position.xyz, 1);
	out_color = in_color;
}

THAT DOESNT WORK.

i get a link error saying:

error: Varying (named out_position) specified but not present in the program object.

unless i delete call “glTransformFeedbackVaryings(…)”

then the program object works (renders a triangle), but the triangle isnt rotation anymore
as if i’m not capturing any data, in fact: i checked it, downloaded the data from the both buffers via “glGetBufferSubData(…)”
both buffers steadily contain a static triangle, that means the transform feedback doesnt work

what am i doing wrong ???

here the complete source code:


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <vector>

#include "Shader.h"

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>

using namespace glm;


struct Vertex
{
	vec4 Position;
	vec4 Color;
};


// main functions
void Initialize();
void Render();
void CleanUp();



GLFWwindow* window;

unsigned int vertexbuffer[2] = { 0 };
unsigned int vertexarray[2] = { 0 };

unsigned int vertexshader = 0;
unsigned int fragmentshader = 0;
unsigned int program = 0;

unsigned int transformfeedback[2] = { 0 };


int main(void)
{
	/* Initialize the library */
	if (!glfwInit())
		return -1;

	/* Create a windowed mode window and its OpenGL context */
	window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	/* Make the window's context current */
	glfwMakeContextCurrent(window);

	// init glew
	if (glewInit() != GLEW_OK)
	{
		glfwTerminate();
		return -1;
	}

	Initialize();

	/* Loop until the user closes the window */
	while (!glfwWindowShouldClose(window))
	{
		/* Render here */
		Render();

		/* Swap front and back buffers */
		glfwSwapBuffers(window);

		/* Poll for and process events */
		glfwPollEvents();
	}

	CleanUp();

	glfwTerminate();
	return 0;
}


void Initialize()
{
	// set window title to OpenGL version
	glfwSetWindowTitle(window, (char*)glGetString(GL_VERSION));

	glClearColor(0.3f, 0.3f, 0.3f, 0);
	glEnable(GL_DEPTH_TEST);

	// -------------------------------------------------------------------

	// here begins the shader setup:
	vertexshader = glCreateShader(GL_VERTEX_SHADER);
	fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

	program = glCreateProgram();

	std::string vertexshader_source = LoadTextFile("shader.vs");
	std::string fragmentshader_source = LoadTextFile("shader.fs");

	// compile shaders
	CompileShader(vertexshader, vertexshader_source);
	CompileShader(fragmentshader, fragmentshader_source);

	// set variables to capture (must be done before linking the program !!!)
	//const char* varyings[] = {
	//	"out_position",
	//	"out_color",
	//};
	//
	//glTransformFeedbackVaryings(program, sizeof(varyings) / sizeof(const char*), varyings, GL_INTERLEAVED_ATTRIBS);

	// attach shaders to program and link it
	LinkProgram(program, { vertexshader, fragmentshader });


	// here begins the vertexarray setup:
	std::vector<Vertex> vertices = {
		//  x   y  z  _      r  g  b  a
		{ { 0, 0, 0, 0 },{ 1, 0, 0, 1 } },// 1st triangle point
		{ { 1, 0, 0, 0 },{ 0, 1, 0, 1 } },// 2nd triangle point
		{ { 0, 1, 0, 0 },{ 0, 0, 1, 1 } },// 3rd triangle point
	};

	// setup buffer and vertex array
	glGenVertexArrays(2, vertexarray);
	glGenBuffers(2, vertexbuffer);

	for (unsigned int i = 0; i < 2; i++)
	{
		glBindVertexArray(vertexarray[i]);
		glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer[i]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_DYNAMIC_COPY);
		glVertexAttribPointer(0, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 0));
		glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 4));
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glEnableVertexAttribArray(0);
		glEnableVertexAttribArray(1);
		glBindVertexArray(0);
	}


	// setup transformfeedback
	glGenTransformFeedbacks(2, transformfeedback);

	for (unsigned int i = 0; i < 2; i++)
	{
		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[i]);
		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vertexbuffer[1 - i]);
		glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
	}

}


void Render()
{
	// just a rotation animation
	static float angle = 0.01;
	// NOTE: the angle is const, doesnt vary over time, because the rotation matrix will be applied to an already transformed triangle

	mat4 Model = rotate(angle, vec3(0, 1, 0));
	mat4 View = lookAt(vec3(0, 0, 3), vec3(0, 0, 0), vec3(0, 1, 0));
	mat4 Projection = perspective(radians(45.0f), 1.33f, 0.1f, 10.0f);

	// upload uniform variables to shader program
	glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "Model"),			1, false, value_ptr(Model));
	glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "View"),			1, false, value_ptr(View));
	glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "Projection"),	1, false, value_ptr(Projection));

	// start capturing process
	static unsigned int index = 0;//frame-depedent
	index = !index;


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glUseProgram(program);

	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[index]);
	glBeginTransformFeedback(GL_TRIANGLES);

	glBindVertexArray(vertexarray[index]);
	glDrawArrays(GL_TRIANGLES, 0, 3);
	glBindVertexArray(0);

	glEndTransformFeedback();
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);

	glUseProgram(0);


	// DEBUG:
	// show the captured data:
	std::vector<Vertex> retrieved_data(3);
	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, vertexbuffer[1 - index]);
	glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vertex) * retrieved_data.size(), retrieved_data.data());
	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);

	std::cout << "1st vertex position: 	" << retrieved_data[0].Position.x << "   " << retrieved_data[0].Position.y << "   " << retrieved_data[0].Position.z << std::endl;
	std::cout << "2st vertex position: 	" << retrieved_data[1].Position.x << "   " << retrieved_data[1].Position.y << "   " << retrieved_data[1].Position.z << std::endl;
	std::cout << "3st vertex position: 	" << retrieved_data[2].Position.x << "   " << retrieved_data[2].Position.y << "   " << retrieved_data[2].Position.z << std::endl;

	// ...
}


void CleanUp()
{
	// destroy buffer and vertex array handles
	glDeleteBuffers(2, vertexbuffer);
	glDeleteVertexArrays(2, vertexarray);

	// destroy shaders and program
	glDeleteProgram(program);
	glDeleteShader(vertexshader);
	glDeleteShader(fragmentshader);

	// destroy transformfeedback
	glDeleteTransformFeedbacks(2, transformfeedback);

	// ...
}

thanks for your advices!