OpenGL Texturing Garbage - qt

I have a problem with texturing – it loads the image correctly, but renders garbage onto the geometry. The geometry itself draws fine (a simple triangle), but no matter which texture I load it just spits random patterns onto the triangle.
I'm using g++ 4.2.1 on Mac OS X with Qt 4.7 and OpenGL
First of all, here's the console output:
BallGLWidget::initializeGL called
Image format is GL_RGB
Checking textures...
glGetError enum value: GL_NO_ERROR
Also, my logging code for the shader initialization doesn't register any error.
The OpenGL initialization function:
void BallGLWidget::initializeGL()
{
cout << "BallGLWidget::initializeGL called" << endl;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
initializeShaders();
checkOpenGLError();
glEnableVertexAttribArray(VERTEX_POS_NUM);
glEnableVertexAttribArray(TEX_POS_NUM);
glBindAttribLocation(programHandle, VERTEX_POS_NUM, VERTEX_POS_ATTRIB_NAME);
glBindAttribLocation(programHandle, TEX_POS_NUM, TEX_COORD_ATTRIB_NAME);
//this MUST be called AFTER glBindAttribLocation
glLinkProgram(programHandle);
//FIXME:-----------DEBUG-----------
printProgramInfoLog(programHandle);
//-----------END-DEBUG-----------
glUseProgram(programHandle);
//FIXME:-----------DEBUG-----------
printProgramInfoLog(programHandle);
//-----------END-DEBUG-----------
checkOpenGLError();
samplerUniformLocation =
glGetUniformLocation(programHandle, BALL_SAMPLER_NAME);
glUniform1f(samplerUniformLocation, 0);
glActiveTexture(GL_TEXTURE0);
ball_texture_handle = loadTexture(BALL_IMAGE_PATH);
//bind it in initialization because we're only using
//1 texture in the program
glBindTexture(GL_TEXTURE_2D, ball_texture_handle);
}
Here's the loadTexture function:
GLuint BallGLWidget::loadTexture(const char* filenamePtr)
{
//create & prepare a temporary texture handle that will be copied to
//DesktopMain::ball_texture_handle after this function returns
GLuint texHandle;
glGenTextures(1, &texHandle);
glBindTexture(GL_TEXTURE_2D, texHandle);
QImage* img = new QImage();
if(!img->load(filenamePtr))
{
//error loading image, handle error
cerr << "ERROR LOADING TEXTURE" << endl;
}
//This is the Qt way- its commented out for conventional OpenGL code
//bind the texture to the current context
//GLuint texHandle = bindTexture(*img);
GLenum openglImageFormat;
QImage::Format imgFormat = img->format();
switch(imgFormat)
{
case QImage::Format_RGB32:
openglImageFormat = GL_RGB;
cout << "Image format is GL_RGB" << endl;
break;
case QImage::Format_ARGB32:
openglImageFormat = GL_RGBA;
cout << "Image format is GL_RGBA" << endl;
break;
//handle this case the same as ARGB32
case QImage::Format_ARGB32_Premultiplied:
openglImageFormat = GL_RGBA;
cout << "Image format is GL_RGBA (premultiplied)" << endl;
break;
case QImage::Format_Invalid:
cerr << "ERROR: INVALID IMAGE FORMAT" << endl;
return -1;
break;
default:
cerr << "ERROR: UNRECOGNIZED IMAGE FORMT" << endl;
return -1;
break;
}
//use tightly packed pixel values
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//use linear filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
img->width(), img->height(), 0, openglImageFormat,
GL_UNSIGNED_BYTE, img->bits());
cerr << "Checking textures..." << endl;
checkOpenGLError();
delete img;
return texHandle;
}
The vertex shader:
attribute vec2 a_v_position;
attribute vec2 a_tex_position;
varying vec2 tex_coord_output;
void main()
{
//copy attributes to varyings for use in the frag shader
tex_coord_output = a_tex_position;
gl_Position = vec4(a_v_position, 0.0, 1.0);
}
The fragment shader:
varying vec2 tex_coord_output;
uniform sampler2D ballsampler;
void main()
{
gl_FragColor = texture2D(ballsampler, tex_coord_output);
}
EDIT:
A screenshot of the program, as requested.
https://docs.google.com/open?id=0B8xCefwW3X4TY2Y3N2M0MGYtMDQ0NS00MDk4LWEzODgtNDc3OWFkODI3ZWE3
EDIT:
The attribute locations were off because apparently glBindAttribLocation only works if called BEFORE the program object is linked (http://www.opengl.org/sdk/docs/man/xhtml/glBindAttribLocation.xml). I changed the code above accordingly, but the program still looks like below (there is still a problem with the texturing...):
I get the following result:
https://docs.google.com/open?id=0B8xCefwW3X4TNWE0YTQ5MTktZTA2Yy00YmI4LWJmMjMtYTlhOTYxMGNkMTk0

Break it down, try something simple:
vert.glsl
#version 120
uniform mat4 projection;
uniform mat4 modelview;
attribute vec2 position;
attribute vec2 texcoord;
varying vec2 fragTexCoord;
void main(void)
{
fragTexCoord = texcoord;
gl_Position = projection * modelview * vec4( position, 0.0, 1.0 );
}
frag.glsl
#version 120
uniform sampler2D texture;
varying vec2 fragTexCoord;
void main(void)
{
gl_FragColor = texture2D( texture, fragTexCoord );
}
main.cpp
#include <GL/glew.h>
#include <GL/glut.h>
#include <cstdlib>
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
GLuint CreateShader( const GLenum& aShaderType, const string& aShaderSource )
{
GLuint shader = glCreateShader( aShaderType );
const GLchar* shaderString = aShaderSource.c_str();
GLint shaderLength = aShaderSource.size();
glShaderSource( shader, 1, &shaderString, &shaderLength );
glCompileShader( shader );
GLint compiled;
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
if( GL_FALSE == compiled )
{
// compile failure, dump log
GLint loglen;
glGetShaderiv( shader, GL_INFO_LOG_LENGTH , &loglen);
vector< char > log( loglen );
glGetShaderInfoLog( shader, loglen, NULL, &log[0] );
string type;
switch( aShaderType )
{
case GL_VERTEX_SHADER: type = "GL_VERTEX_SHADER"; break;
case GL_FRAGMENT_SHADER: type = "GL_FRAGMENT_SHADER"; break;
default: type = "UNKNOWN SHADER"; break;
}
stringstream err;
err << "*** " << type << " ***" << endl;
err << aShaderSource;
err << "*** Compilation Log ***" << endl;
err << string( log.begin(), log.end() );
throw std::logic_error( err.str() );
}
return shader;
}
GLuint CreateProgram( const string& aVertexShader, const string& aFragmentShader )
{
GLuint vert = CreateShader( GL_VERTEX_SHADER, aVertexShader );
GLuint frag = CreateShader( GL_FRAGMENT_SHADER, aFragmentShader );
GLuint program = glCreateProgram();
glAttachShader( program, vert );
glAttachShader( program, frag );
glLinkProgram( program );
glDeleteShader( vert );
glDeleteShader( frag );
GLint linked;
glGetProgramiv( program, GL_LINK_STATUS, &linked );
if( GL_FALSE == linked )
{
// link failure, dump log
GLint loglen;
glGetProgramiv( program, GL_INFO_LOG_LENGTH , &loglen);
vector< char > log( loglen );
glGetProgramInfoLog( program, loglen, NULL, &log[0] );
stringstream err;
err << "*** Link log ***" << endl;
err << string( log.begin(), log.end() );
throw std::logic_error( err.str() );
}
return program;
}
string LoadFile( const string& filename )
{
ifstream infile(filename.c_str(), ios::binary);
istreambuf_iterator<char> begin(infile), end;
return string(begin, end);
}
GLuint prog = 0;
GLuint tex = 0;
void init()
{
GLenum glewError = glewInit();
if( GLEW_OK != glewError )
{
stringstream err;
err << "GLEW error: " << glewGetErrorString(glewError) << endl;
throw std::logic_error( err.str() );
}
cout << "GLEW_VERSION : " << glewGetString(GLEW_VERSION) << endl;
cout << "GL_VERSION : " << glGetString(GL_VERSION) << endl;
cout << "GLSL VERSION : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
cout << "GL_VENDOR : " << glGetString(GL_VENDOR) << endl;
cout << "GL_RENDERER : " << glGetString(GL_RENDERER) << endl;
if( !GLEW_VERSION_2_1 )
{
stringstream err;
err << "OpenGL 2.1 or better required for GLSL support." << endl;
throw std::logic_error( err.str() );
}
// load shaders
string vert = LoadFile( "vert.glsl" );
string frag = LoadFile( "frag.glsl" );
prog = CreateProgram( vert, frag );
// create random texture
const unsigned int width = 32;
const unsigned int height = 32;
const unsigned int channels = 3;
unsigned char buffer[ width * height * channels ];
for( unsigned int i = 0; i < width * height; ++i )
{
buffer[i*channels + 0] = rand()%255;
buffer[i*channels + 1] = rand()%255;
buffer[i*channels + 2] = rand()%255;
}
// upload texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, channels, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
}
struct Vertex
{
Vertex() : x(0), y(0), s(0), t(0) {}
Vertex( float _x, float _y, float _s, float _t ) : x(_x), y(_y), s(_s), t(_t) {}
float x, y;
float s, t;
};
void display()
{
static float currentTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
float newTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
float frameTime = newTime - currentTime;
currentTime = newTime;
vector< Vertex > verts;
verts.push_back( Vertex( -1, -1, 0, 0 ) );
verts.push_back( Vertex( 1, -1, 1, 0 ) );
verts.push_back( Vertex( 1, 1, 1, 1 ) );
verts.push_back( Vertex( -1, 1, 0, 1 ) );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
static float angle = 0;
angle += 60 * frameTime;
glRotatef( angle, 0, 0, 1 );
glScalef( 5, 5, 5 );
glUseProgram( prog );
// load uniforms
GLfloat projection[16];
glGetFloatv( GL_PROJECTION_MATRIX, projection );
GLint projection_loc = glGetUniformLocation( prog, "projection" );
glUniformMatrix4fv( projection_loc, 1, GL_FALSE, projection );
GLfloat modelview[16];
glGetFloatv( GL_MODELVIEW_MATRIX, modelview );
GLint modelview_loc = glGetUniformLocation( prog, "modelview" );
glUniformMatrix4fv( modelview_loc, 1, GL_FALSE, modelview );
GLint texture_loc = glGetUniformLocation( prog, "texture" );
glUniform1i( texture_loc, 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, tex );
// load attributes
GLint position_loc = glGetAttribLocation( prog, "position" );
glVertexAttribPointer( position_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &verts[0].x );
glEnableVertexAttribArray( position_loc );
GLint texcoord_loc = glGetAttribLocation( prog, "texcoord" );
glVertexAttribPointer( texcoord_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &verts[0].s );
glEnableVertexAttribArray( texcoord_loc );
// render
glDrawArrays( GL_QUADS, 0, verts.size() );
glDisableVertexAttribArray( position_loc );
glDisableVertexAttribArray( texcoord_loc );
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspect = (double)w / (double)h;
glOrtho(-10*aspect, 10*aspect, -10, 10, -1, 1);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800,600);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("GLSL");
try
{
init();
}
catch( std::exception& e )
{
cout << "Init failure: " << endl << e.what() << endl;
return EXIT_FAILURE;
}
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}

Related

MPI - One-sided communications

I'm trying to use one-sided communications in MPI.
The following example consists of an array of 4 doubles that is split between 2 processes.
The first process writes 0, 1, 2, 3 in the distributed array while the second one subsequently tries to read it. Unfortunately, it doesn't work. I must be doing something wrong somewhere.
Thanks!
#include <mpi.h>
#include <iostream>
int main(){
MPI_Init(0, nullptr);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int n=2;
double* data, x;
MPI_Win window;
MPI_Alloc_mem(n*sizeof(double), MPI_INFO_NULL, &data);
MPI_Win_create(data, n*sizeof(float), sizeof(float), MPI_INFO_NULL, MPI_COMM_WORLD, &window);
int i;
MPI_Win_fence(0, window);
if(rank==0){
for(i=0; i<n*size; ++i){
x=i;
MPI_Put(&x, 1, MPI_DOUBLE, i/n, i%n, 1, MPI_DOUBLE, window);
}
MPI_Win_fence(0, window);
}else{
MPI_Win_fence(0, window);
for(i=0; i<n*size; ++i){
MPI_Get(&x, 1, MPI_DOUBLE, i/n, i%n, 1, MPI_DOUBLE, window);
std::cout << i << " " << i/n << " " << i%n << " => " << x << "\n";
}
}
MPI_Win_free(&window);
MPI_Free_mem(data);
MPI_Finalize();
return 0;
}

What is the meaning of using MPI for single server?

I am the novice in the field of distributed-computation and I know the most popular standard is the Message Passing Interface. However, if I only have one server, I can also run my program under the MPI framework as the following demo example.
# include <cmath>
# include <cstdlib>
# include <ctime>
# include <iomanip>
# include <iostream>
# include <mpi.h>
using namespace std;
int main ( int argc, char *argv[] );
double f ( double x );
void timestamp ( );
int main ( int argc, char *argv[] )
{
double end_time;
int i;
int id;
int ierr;
int m;
int p;
double r8_pi = 3.141592653589793238462643;
int process;
double q_global;
double q_local;
int received;
int source;
double start_time;
MPI_Status status;
int tag;
int target;
double x;
double xb[2];
double x_max = 1.0;
double x_min = 0.0;
//
// Establish the MPI environment.
//
ierr = MPI_Init ( &argc, &argv );
if ( ierr != 0 )
{
cout << "\n";
cout << "INTERVALS_MPI - Fatal error!";
cout << " MPI_Init returned ierr = " << ierr << "\n";
exit ( 1 );
}
//
// Determine this processes's rank.
//
ierr = MPI_Comm_rank ( MPI_COMM_WORLD, &id );
//
// Get the number of processes.
//
ierr = MPI_Comm_size ( MPI_COMM_WORLD, &p );
//
// Say hello (once), and shut down right away unless we
// have at least 2 processes available.
//
if ( id == 0 )
{
timestamp ( );
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " C++ version\n";
cout << "\n";
cout << " An MPI example program,\n";
cout << " A quadrature over an interval is done by\n";
cout << " assigning subintervals to processes.\n";
cout << "\n";
cout << " The number of processes is " << p << "\n";
start_time = MPI_Wtime ( );
if ( p <= 1 )
{
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " Need at least 2 processes!\n";
MPI_Finalize ( );
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " Abnormal end of execution.\n";
exit ( 1 );
}
}
cout << "\n";
cout << "Process " << id << ": Active!\n";
//
// Every process could figure out the endpoints of its interval
// on its own. But we want to demonstrate communication. So we
// assume that the assignment of processes to intervals is done
// only by the master process, which then tells each process
// what job it is to do.
//
if ( id == 0 )
{
for ( process = 1; process <= p-1; process++ )
{
xb[0] = ( ( double ) ( p - process ) * x_min
+ ( double ) ( process - 1 ) * x_max )
/ ( double ) ( p - 1 );
xb[1] = ( ( double ) ( p - process - 1 ) * x_min
+ ( double ) ( process ) * x_max )
/ ( double ) ( p - 1 );
target = process;
tag = 1;
ierr = MPI_Send ( xb, 2, MPI_DOUBLE, target, tag, MPI_COMM_WORLD );
}
}
else
{
source = 0;
tag = 1;
ierr = MPI_Recv ( xb, 2, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, &status );
}
//
// Wait here until everyone has gotten their assignment.
//
ierr = MPI_Barrier ( MPI_COMM_WORLD );
if ( id == 0 )
{
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " Subintervals have been assigned.\n";
}
//
// Every process needs to be told the number of points to use.
// Since this is the same value for everybody, we use a broadcast.
// Again, we are doing it in this roundabout way to emphasize that
// the choice for M could really be made at runtime, by processor 0,
// and then sent out to the others.
//
m = 100;
source = 0;
ierr = MPI_Bcast ( &m, 1, MPI_INT, source, MPI_COMM_WORLD );
//
// Now, every process EXCEPT 0 computes its estimate of the
// integral over its subinterval, and sends the result back
// to process 0.
//
if ( id != 0 )
{
q_local = 0.0;
for ( i = 1; i <= m; i++ )
{
x = ( ( double ) ( 2 * m - 2 * i + 1 ) * xb[0]
+ ( double ) ( 2 * i - 1 ) * xb[1] )
/ ( double ) ( 2 * m );
q_local = q_local + f ( x );
}
q_local = q_local * ( xb[1] - xb[0] ) / ( double ) ( m );
target = 0;
tag = 2;
ierr = MPI_Send ( &q_local, 1, MPI_DOUBLE, target, tag, MPI_COMM_WORLD );
}
//
// Process 0 expects to receive N-1 partial results.
//
else
{
received = 0;
q_global = 0.0;
while ( received < p - 1 )
{
source = MPI_ANY_SOURCE;
tag = 2;
ierr = MPI_Recv ( &q_local, 1, MPI_DOUBLE, source, tag, MPI_COMM_WORLD,
&status );
q_global = q_global + q_local;
received = received + 1;
}
}
//
// The master process prints the answer.
//
if ( id == 0 )
{
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " Estimate for PI is " << q_global << "\n";
cout << " Error is " << q_global - r8_pi << "\n";
end_time = MPI_Wtime ( );
cout << "\n";
cout << " Elapsed wall clock seconds = "
<< end_time - start_time << "\n";
}
//
// Terminate MPI.
//
MPI_Finalize ( );
//
// Terminate.
//
if ( id == 0 )
{
cout << "\n";
cout << "INTERVALS - Master process:\n";
cout << " Normal end of execution.\n";
cout << "\n";
timestamp ( );
}
return 0;
}
//****************************************************************************80
double f ( double x )
{
double value;
value = 4.0 / ( 1.0 + x * x );
return value;
}
//****************************************************************************80
void timestamp ( )
{
# define TIME_SIZE 40
static char time_buffer[TIME_SIZE];
const struct std::tm *tm_ptr;
std::time_t now;
now = std::time ( NULL );
tm_ptr = std::localtime ( &now );
std::strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm_ptr );
std::cout << time_buffer << "\n";
return;
# undef TIME_SIZE
}
Actually, this is the simple case that we use the MPI to compute the integral of specific function. I run this program by using 4 processes. I am confused that we can also use the OpenMP to do the share memory programming instead of MPI to reduce the communication cost. I do not know the meaning of MPI on single machine.

Getting undesired behavior when sending-receiving messages using MPI

I'm exploring MPI in C++ and I wanted to parallelize the creation of a picture of the Mandelbrot set. I'm using the ppm format. Each processor builds its part and sends it back to the main process that receives it as MPI_CHAR. This is the code:
#include "mpi.h"
#include <iostream>
#include <string>
#include <fstream>
#include <complex>
using namespace std;
int mandelbrot(int x, int y, int width, int height, int max) {
complex<float> point((float) (y - height/2.0) * 4.0/width, (float) (x - width/2.0) * 4.0/width);
complex<float> z(0, 0);
unsigned int iteration = 0;
while (abs(z) < 4 && iteration < max) {
z = z * z + point;
iteration++;
}
return iteration;
}
int main(int argc, char **argv) {
int numprocs;
int myid;
int buff_size = 404270; // 200x200
char buff[buff_size];
int i;
MPI_Status stat;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
int width = 200, height = 200, max_iter = 1000;
if (myid == 0) {
ofstream image("mandel.ppm");
image << "P3\n" << width << " " << height << " 255\n";
for(i=1; i < numprocs; i++) {
MPI_Probe(i, 0, MPI_COMM_WORLD, &stat);
int length;
MPI_Get_count(&stat, MPI_CHAR, &length);
MPI_Recv(buff, length, MPI_CHAR, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
image << buff;
}
} else {
stringstream ss;
// proc rank: 1, 2, ..., n
int part = height/(numprocs-1), start = (myid - 1) * part, end = part * myid;
printf("%d -> %d\n", start, end);
for (int row = start; row < end; row++) {
for (int col = 0; col < width; col++) {
int iteration = mandelbrot(row, col, width, height, max_iter);
if (row == start) ss << 255 << ' ' << 255 << ' ' << 255 << "\n";
else if (iteration < max_iter) ss << iteration * 255 << ' ' << iteration * 20 << ' ' << iteration * 5 << "\n";
else ss << 0 << ' ' << 0 << ' ' << 0 << "\n";
}
}
printf("\n sizeof = %d\n", ss.str().length());
MPI_Send(ss.str().c_str(), ss.str().length(), MPI_CHAR, 0, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
Code compilation:
$ mpic++ -std=c++0x mpi.mandel.cpp -o mpi.mandel
Running with 3 processes (process main + process rank 1 and 2)
$ mpirun -np 3 ./mpi.mandel
Resulting ppm pictures when running with 3, 4, and 5 process:
It seems that the point-to-point communication of sending-receiving is mixing the results when more than 3 processes try to send the MPI_CHAR elements to the main process. How can avoid this behavior?
It works when creating the buffer buff with the same length as the receiving message:
.
.
for (int i=1; i < numprocs; i++) {
MPI_Probe(i, 0, MPI_COMM_WORLD, &stat);
int length;
MPI_Get_count(&stat, MPI_CHAR, &length);
printf("\nfrom %d <<-- %d (stat.source=%d) Receiving %d chars\n", myid, i, stat.MPI_SOURCE, length);
char buff[length + 1];
MPI_Recv(buff, length, MPI_CHAR, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
buff[length] = '\0';
image << buff;
}
.
.
Thus, we don't need anymore the declaration at the beginning int buff_size = 404270; neither char buff[buff_size];

openGL2.0: How to disable vertex shaders?

I am trying to capture traces from a game but the glInterceptor I use doesn't support vertex shaders. My research suggests I disable vertex shaders and use the default vertex shader but no information about how to do it. So, how can I disable vertex shaders? Here is the code:
pp.fx
#define DISABLE_FOG
#define DISABLE_LIGHTING
technique Default
{
pass P0
{
VertexShader = vertexShaders/diff-tex.vs;
PixelShader = pixelShaders/pp.ps;
#ifdef ENABLE_TWOSIDED
EnableCulling = FALSE;
#endif
#ifdef DISABLE_DEPTH_TEST
EnableDepthTest = FALSE;
#endif
#ifdef ENABLE_ADDITIVE
EnableDepthMask = FALSE;
EnableBlending = TRUE;
BlendFuncSrc = ONE;
BlendFuncDst = ONE;
#endif
#ifdef ENABLE_MULTIPLICATIVE
EnableDepthMask = FALSE;
EnableBlending = TRUE;
BlendFuncSrc = DST_COLOR;
BlendFuncDst = ZERO;
#endif
#ifdef ENABLE_ALPHA_BLENDING
EnableDepthMask = FALSE;
EnableBlending = TRUE;
BlendFuncSrc = SRC_ALPHA;
BlendFuncDst = ONE_MINUS_SRC_ALPHA;
#endif
#ifdef ENABLE_PREMULT_ALPHA_BLENDING
EnableDepthMask = FALSE;
EnableBlending = TRUE;
BlendFuncSrc = ONE;
BlendFuncDst = ONE_MINUS_SRC_ALPHA;
#endif
}
}
diff-tex.vs
#include "../commons/defines.sh"
#include "../commons/attributes.sh"
#include "../commons/uniforms.sh"
#include "../commons/functions.sh"
#include "../commons/varyings.sh"
void main()
{
#ifdef ENABLE_SKINNING
// bone 1 influence
int i = int(DT_BONEINDICES.x);
float w = DT_BONEWEIGHTS.x;
mat4 bonetm = BONEWORLDTM[i];
vec3 worldpos = transform(bonetm, DT_POSITION) * w;
#ifndef DISABLE_LIGHTING
V_Normal = rotate( convertToMat3(bonetm), DT_NORMAL ) * w;
#endif
#ifdef ENABLE_NORMALMAP
vec3 worldtangent = rotate( convertToMat3(bonetm), DT_TANGENT ) * w;
#endif
// bone 2 influence
i = int(DT_BONEINDICES.y);
w = DT_BONEWEIGHTS.y;
bonetm = BONEWORLDTM[i];
worldpos += transform(bonetm, DT_POSITION) * w;
#ifndef DISABLE_LIGHTING
V_Normal += rotate( convertToMat3(bonetm), DT_NORMAL ) * w;
#endif
#ifdef ENABLE_NORMALMAP
worldtangent += rotate( convertToMat3(bonetm), DT_TANGENT ) * w;
#endif
// bone 3 influence
i = int(DT_BONEINDICES.z);
w = (1.0 - DT_BONEWEIGHTS.y - DT_BONEWEIGHTS.x);
bonetm = BONEWORLDTM[i];
worldpos += transform(bonetm, DT_POSITION) * w;
// Can be omitted for optimization, effect is quite small
#ifndef DISABLE_LIGHTING
V_Normal += rotate( convertToMat3(bonetm), DT_NORMAL ) * w;
V_Normal = normalize(V_Normal);
#endif
#ifdef ENABLE_NORMALMAP
worldtangent += rotate( convertToMat3(bonetm), DT_TANGENT ) * w;
worldtangent = normalize(worldtangent);
vec3 worldbinormal = cross( V_Normal, worldtangent );
#endif
gl_Position = VIEWPROJTM * vec4(worldpos, 1);
#else
#if defined(DISABLE_TRANSFORM_EXCEPT_ORIENTATION)
// Vertices are already in screen space coordinates
gl_Position = PROJTM * vec4(DT_POSITION, 1);
#elif defined(DISABLE_TRANSFORM)
gl_Position = vec4(DT_POSITION, 1);
#else
// Transform coordinates to screen space
gl_Position = TOTALTM * vec4(DT_POSITION, 1);
vec3 worldpos = vec3(WORLDTM * vec4(DT_POSITION, 1));
#endif
#endif
}

How to use VAOs with instancing in Qt 5

I'm trying to wrap my head around how to use VAOs appropriately for instanced rendering (specifically in Qt 5.2, using OpenGL 3.3). My understanding is that VAOs save the state of the VBOs and associated attributes so that you don't need to worry about binding and enabling everything at drawing time, you just bind the VAO. But with instancing, you often have multiple VBOs. How do you get around needing to bind them all? Or do I just need to use a single VBO for both my per vertex data and my per instance data?
I've been looking at a couple tutorials, for example: http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html
It looks to me like what he does is use a VAO for his per vertex data and NOT for his per instance data. I've tried doing the same thing with my Qt-based code, and it's not working for me (probably because I don't entirely understand how that works... shouldn't his instance data still need to be bound when drawing happens?)
Some dummy code... this is a bit silly, I'm just drawing a single instance of two triangles, with a perspective matrix as a per instance attribute.
glwindow.cpp:
#include "glwindow.h"
#include <QColor>
#include <QMatrix4x4>
#include <QVector>
#include <QVector3D>
#include <QVector4D>
#include <QDebug>
GLWindow::GLWindow(QWindow *parent)
: QWindow(parent)
, _vbo(QOpenGLBuffer::VertexBuffer)
, _matbo(QOpenGLBuffer::VertexBuffer)
, _context(0)
{
setSurfaceType(QWindow::OpenGLSurface);
}
GLWindow::~GLWindow()
{}
void GLWindow::initGL()
{
setupShaders();
_program->bind();
_positionAttr = _program->attributeLocation("position");
_colourAttr = _program->attributeLocation("colour");
_matrixAttr = _program->attributeLocation("matrix");
QVector<QVector3D> triangles;
triangles << QVector3D(-0.5, 0.5, 1) << QVector3D(-0.5, -0.5, 1) << QVector3D(0.5, -0.5, 1);
triangles << QVector3D(0.5, 0.5, 0.5) << QVector3D(-0.5, -0.5, 0.5) << QVector3D(0.5, -0.5, 0.5);
QVector<QVector3D> colours;
colours << QVector3D(1, 0, 0) << QVector3D(0, 1, 0) << QVector3D(0, 0, 1);
colours << QVector3D(1, 1, 1) << QVector3D(1, 1, 1) << QVector3D(1, 1, 1);
_vao.create();
_vao.bind();
_vbo.create();
_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
_vbo.bind();
size_t positionSize = triangles.size() * sizeof(QVector3D);
size_t colourSize = colours.size() * sizeof(QVector3D);
_vbo.allocate(positionSize + colourSize);
_vbo.bind();
_vbo.write(0, triangles.constData(), positionSize);
_vbo.write(positionSize, colours.constData(), colourSize);
_colourOffset = positionSize;
_program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
_program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);
_program->enableAttributeArray(_positionAttr);
_program->enableAttributeArray(_colourAttr);
_vao.release();
_matbo.create();
_matbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
_matbo.bind();
_matbo.allocate(4 * sizeof(QVector4D));
_program->setAttributeBuffer(_matrixAttr, GL_FLOAT, 0, 4, 4 * sizeof(QVector4D));
_program->enableAttributeArray(_matrixAttr);
_func330->glVertexAttribDivisor(_matrixAttr, 1);
_matbo.release();
_program->release();
resizeGL(width(), height());
}
void GLWindow::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void GLWindow::paintGL()
{
if (! _context) // not yet initialized
return;
_context->makeCurrent(this);
QColor background(Qt::black);
glClearColor(background.redF(), background.greenF(), background.blueF(), 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
_program->bind();
_matbo.bind();
_matbo.write(0, matrix.constData(), 4 * sizeof(QVector4D));
_vao.bind();
glEnable(GL_DEPTH_TEST);
_func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
_vao.release();
_program->release();
_context->swapBuffers(this);
_context->doneCurrent();
}
void GLWindow::setupShaders()
{
QString vShaderSrc("#version 330\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec4 colour;\n"
"layout(location = 2) in mat4 matrix;\n"
"smooth out vec4 col;\n"
"void main() {\n"
" col = colour;\n"
" gl_Position = matrix * position;\n"
"}\n");
QString fShaderSrc("#version 330\n"
"smooth in vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n");
_program = new QOpenGLShaderProgram(this);
_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vShaderSrc);
_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fShaderSrc);
_program->link();
}
void GLWindow::exposeEvent(QExposeEvent *event)
{
Q_UNUSED(event);
if (isExposed())
{
if (! _context)
{
_context = new QOpenGLContext(this);
QSurfaceFormat format(requestedFormat());
format.setVersion(3,3);
format.setDepthBufferSize(24);
_context->setFormat(format);
_context->create();
_context->makeCurrent(this);
initializeOpenGLFunctions();
_func330 = _context->versionFunctions<QOpenGLFunctions_3_3_Core>();
if (_func330)
_func330->initializeOpenGLFunctions();
else
{
qWarning() << "Could not obtain required OpenGL context version";
exit(1);
}
initGL();
}
paintGL();
}
}
glwindow.h:
#ifndef GL_WINDOW_H
#define GL_WINDOW_H
#include <QExposeEvent>
#include <QSurfaceFormat>
#include <QWindow>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
class GLWindow : public QWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
GLWindow(QWindow * = 0);
virtual ~GLWindow();
void initGL();
void paintGL();
void resizeGL(int, int);
protected:
virtual void exposeEvent(QExposeEvent *);
private:
void setupShaders();
QOpenGLBuffer _vbo;
QOpenGLBuffer _matbo;
QOpenGLContext *_context;
QOpenGLShaderProgram *_program;
QOpenGLVertexArrayObject _vao;
QOpenGLFunctions_3_3_Core *_func330;
GLuint _positionAttr;
GLuint _colourAttr;
GLuint _matrixAttr;
size_t _colourOffset;
} ;
#endif
glbuffertest.cpp:
#include <QGuiApplication>
#include <QSurfaceFormat>
#include "glwindow.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
GLWindow window;
window.resize(400, 400);
window.show();
return app.exec();
}
glbuffertest.pro:
######################################################################
# Automatically generated by qmake (3.0) Fri May 16 09:49:41 2014
######################################################################
TEMPLATE = app
TARGET = glbuffertest
INCLUDEPATH += .
CONFIG += qt debug
# Input
SOURCES += glbuffertest.cpp glwindow.cpp
HEADERS += glwindow.h
UPDATE:
I've tried getting rid of my _matbo buffer and instead putting the matrix data into the same VBO as the position and colour attributes, but it's not working for me. My initGL function now looks like:
void GLWindow::initGL()
{
setupShaders();
_program->bind();
_positionAttr = _program->attributeLocation("position");
_colourAttr = _program->attributeLocation("colour");
_matrixAttr = _program->attributeLocation("matrix");
QVector<QVector3D> triangles;
triangles << QVector3D(-0.5, 0.5, 1) << QVector3D(-0.5, -0.5, 1) << QVector3D(0.5, -0.5, 1);
triangles << QVector3D(0.5, 0.5, 0.5) << QVector3D(-0.5, -0.5, 0.5) << QVector3D(0.5, -0.5, 0.5);
QVector<QVector3D> colours;
colours << QVector3D(1, 0, 0) << QVector3D(0, 1, 0) << QVector3D(0, 0, 1);
colours << QVector3D(1, 1, 1) << QVector3D(1, 1, 1) << QVector3D(1, 1, 1);
_vao.create();
_vao.bind();
_vbo.create();
_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
_vbo.bind();
size_t positionSize = triangles.size() * sizeof(QVector3D);
size_t colourSize = colours.size() * sizeof(QVector3D);
size_t matrixSize = 4 * sizeof(QVector4D);
_vbo.allocate(positionSize + colourSize + matrixSize);
_vbo.bind();
_vbo.write(0, triangles.constData(), positionSize);
_vbo.write(positionSize, colours.constData(), colourSize);
_colourOffset = positionSize;
_matrixOffset = positionSize + colourSize;
_program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
_program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);
_program->setAttributeBuffer(_matrixAttr, GL_FLOAT, _matrixOffset, 4, 4 * sizeof(QVector4D));
_program->enableAttributeArray(_positionAttr);
_program->enableAttributeArray(_colourAttr);
_program->enableAttributeArray(_matrixAttr);
_func330->glVertexAttribDivisor(_matrixAttr, 1);
_vao.release();
_program->release();
resizeGL(width(), height());
}
and paintGL:
void GLWindow::paintGL()
{
if (! _context) // not yet initialized
return;
_context->makeCurrent(this);
QColor background(Qt::black);
glClearColor(background.redF(), background.greenF(), background.blueF(), 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
_program->bind();
_vao.bind();
_vbo.write(_matrixOffset, matrix.constData(), 4 * sizeof(QVector4D));
/* I tried replacing the three preceding lines with the following, without success: */
/*
_vao.bind();
_vbo.bind();
_vbo.write(_matrixOffset, matrix.constData(), 4 * sizeof(QVector4D));
_program->bind();
_program->enableAttributeArray(_matrixAttr);
_func330->glVertexAttribDivisor(_matrixAttr, 1); */
glEnable(GL_DEPTH_TEST);
_func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
_vao.release();
_program->release();
_context->swapBuffers(this);
_context->doneCurrent();
}
So it seems my instancing problems are bigger than just having the wrong buffer bound at the wrong time. What else am I doing wrong?
I think you must create one VBO for positions and one VBO for colors (or use interleaved data with a stride). VAO allows you to use multiple VBO, one per attribute.
vao.create();
vao.bind();
// prepare your shader program
// ...
// prepare your VBOs : one VBO for pos, one VBO for colors, one for normals,...
// example for position
vertexPositionBuffer.create();
vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexPositionBuffer.bind();
// if your store the points using QVector<QVector3D>
vertexPositionBuffer.allocate(vertices.constData(), vertices.size() * sizeof(QVector3D));
vertexPositionBuffer.release();
// do the same for colors or other attributes
// ...
// after all buffers are created
shaderProgram.bind();
// Bind the position buffer
vertexPositionBuffer.bind();
shaderProgram.enableAttributeArray("vertexPosition");
shaderProgram.setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3);
vertexPositionBuffer.release();
// do the same for all other buffers
// ...
shaderProgram.release();
// release vao
vao.release();
and in your paintGL function:
// update your matrices
// bind your shader program
// set you uniform variables
// then
vao.bind();
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
vao.release();
// release your shader program
I've got it. The main problems were that:
I had to loop through all four columns of my mat4 attribute, setting and enabling each of them, and calling glVertexAttribDivisor() on each.
I had completely messed up the call to QOpenGLShaderProgram::setAttributeBuffer() for my mat4 attribute.
Essentially, you have to treat a mat4 as four separate vec4 attributes (one for each column). This doesn't affect how you copy QMatrix4x4 data to a QOpenGLBuffer object in the slightest, just how you tell the shader program to deal with the data. This is well described in both the tutorial I linked to in my original question and in The OpenGL Programming Guide's instancing tutorial, I just didn't get it. So, going back to the first attempt at glwindow.cpp above, I've changed very little and things now work:
#include "glwindow.h"
#include <QColor>
#include <QMatrix4x4>
#include <QVector>
#include <QVector3D>
#include <QVector4D>
#include <QDebug>
GLWindow::GLWindow(QWindow *parent)
: QWindow(parent)
, _vbo(QOpenGLBuffer::VertexBuffer)
, _matbo(QOpenGLBuffer::VertexBuffer)
, _context(0)
{
setSurfaceType(QWindow::OpenGLSurface);
}
GLWindow::~GLWindow()
{}
void GLWindow::initGL()
{
setupShaders();
_program->bind();
_positionAttr = _program->attributeLocation("position");
_colourAttr = _program->attributeLocation("colour");
_matrixAttr = _program->attributeLocation("matrix");
QVector<QVector3D> triangles;
triangles << QVector3D(-0.5, 0.5, 1) << QVector3D(-0.5, -0.5, 1) << QVector3D(0.5, -0.5, 1);
triangles << QVector3D(0.5, 0.5, 0.5) << QVector3D(-0.5, -0.5, 0.5) << QVector3D(0.5, -0.5, 0.5);
QVector<QVector3D> colours;
colours << QVector3D(1, 0, 0) << QVector3D(0, 1, 0) << QVector3D(0, 0, 1);
colours << QVector3D(1, 1, 1) << QVector3D(1, 1, 1) << QVector3D(1, 1, 1);
_vao.create();
_vao.bind();
_vbo.create();
_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
_vbo.bind();
size_t positionSize = triangles.size() * sizeof(QVector3D);
size_t colourSize = colours.size() * sizeof(QVector3D);
_vbo.allocate(positionSize + colourSize);
_vbo.bind();
_vbo.write(0, triangles.constData(), positionSize);
_vbo.write(positionSize, colours.constData(), colourSize);
_colourOffset = positionSize;
_program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
_program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);
_program->enableAttributeArray(_positionAttr);
_program->enableAttributeArray(_colourAttr);
_matbo.create();
_matbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
_matbo.bind();
_matbo.allocate(4 * sizeof(QVector4D));
// This is completely wrong
/*_program->setAttributeBuffer(_matrixAttr, GL_FLOAT, 0, 4, 4 * sizeof(QVector4D));
_program->enableAttributeArray(_matrixAttr);
_func330->glVertexAttribDivisor(_matrixAttr, 1);
*/
// The right way to set up a mat4 attribute for instancing
for (unsigned i = 0; i < 4; i++)
{
_program->setAttributeBuffer(_matrixAttr + i, GL_FLOAT, i * sizeof(QVector4D), 4, 4 * sizeof(QVector4D));
_program->enableAttributeArray(_matrixAttr + i);
_func330->glVertexAttribDivisor(_matrixAttr + i, 1);
}
_matbo.release();
_vao.release();
_program->release();
resizeGL(width(), height());
}
void GLWindow::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void GLWindow::paintGL()
{
if (! _context) // not yet initialized
return;
_context->makeCurrent(this);
QColor background(Qt::black);
glClearColor(background.redF(), background.greenF(), background.blueF(), 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
_program->bind();
_vao.bind();
_matbo.bind();
_matbo.write(0, matrix.constData(), 4 * sizeof(QVector4D));
glEnable(GL_DEPTH_TEST);
_func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
_vao.release();
_program->release();
_context->swapBuffers(this);
_context->doneCurrent();
}
void GLWindow::setupShaders()
{
QString vShaderSrc("#version 330\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec4 colour;\n"
"layout(location = 2) in mat4 matrix;\n"
"smooth out vec4 col;\n"
"void main() {\n"
" col = colour;\n"
" gl_Position = matrix * position;\n"
"}\n");
QString fShaderSrc("#version 330\n"
"smooth in vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n");
_program = new QOpenGLShaderProgram(this);
_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vShaderSrc);
_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fShaderSrc);
_program->link();
}
void GLWindow::exposeEvent(QExposeEvent *event)
{
Q_UNUSED(event);
if (isExposed())
{
if (! _context)
{
_context = new QOpenGLContext(this);
QSurfaceFormat format(requestedFormat());
format.setVersion(3,3);
format.setDepthBufferSize(24);
_context->setFormat(format);
_context->create();
_context->makeCurrent(this);
initializeOpenGLFunctions();
_func330 = _context->versionFunctions<QOpenGLFunctions_3_3_Core>();
if (_func330)
_func330->initializeOpenGLFunctions();
else
{
qWarning() << "Could not obtain required OpenGL context version";
exit(1);
}
initGL();
}
paintGL();
}
}
Note that I also moved the binding of _matbo and setting up of the mat4 attribute so that it's all done before releasing the VAO. I was initially very confused over how many VBOs were allowed and when they needed to be bound. There's no problem having multiple VBOs inside a single VAO, it's just that the right one needs to be bound to be written to, and the right one needs to be bound before calling QOpenGLShaderProgram::setAttributeBuffer(). It doesn't matter which buffer is bound when glDraw*() is called (I trust someone will comment if I'm wrong about that).

Resources