openGL dummy questions


#1

Hi guys…
hoping for some help here.

I’m new to openGL, but think i’m getting my head wrapped around the basics.

At its simplest, i want my app to have two OpenGLComponents.
Each has a (different) juce Image that gets drawn.
The whole purpose of this exercise is so I can get the rendering happening on a separate thread, to free up the GUI (that’s possible using OpenGL, right!?). I’m sure I"ll have some questions about that, sooner or later, but right now I’m more focussed on just drawing my images using OpenGL…

Ok, first question… I can map my Image to a texture… but do I need to bind it? If I bind both components to ‘texture 1’ are they essentially sharing a texture, or do they each get their own instance…?
Yes, I probably sound confused.

Using the code below, I’m able to draw textures to the screen in each component. Yay. But, sometimes component2’s image is getting drawn into component1, and vice versa… hence, my questions about binding textures.

here’s some sample code… any help greatly appreciated!

[code]
void MyOpenGLComp::MoveImageToTexture()
{
// This gets called periodically (when the Image changes), NOT just in newOpenGLContextCreated)
if(myImage)
{
// needed?
//glDeleteTextures( 1, &myGLTextureId );
// select our current texture
//glBindTexture( GL_TEXTURE_2D, myGLTextureId );

	int stride, pixStride;
	const void* pixels = myImage->lockPixelDataReadOnly (0, 0, myImage->getWidth(), myImage->getHeight(), stride, pixStride);

	glTexImage2D (GL_TEXTURE_2D, 0, 4, myImage->getWidth(), myImage->getHeight(),
				  0, GL_BGR_EXT, //GL_RGB,	// Juce seems to use BGR for its internal pixel format, so try using GL_BGR_EXT instead of GL_RGB
				  GL_UNSIGNED_BYTE, pixels);
	myImage->releasePixelDataReadOnly (pixels);	
}

}

void MyOpenGLComp::newOpenGLContextCreated()
{
glEnable (GL_TEXTURE_2D);
glEnable (GL_BLEND);
glShadeModel (GL_SMOOTH);

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				
glClearDepth(1.0f);									
glEnable(GL_DEPTH_TEST);							
glDepthFunc(GL_LEQUAL);								
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);	// what are these?
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);	

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glPixelStorei (GL_UNPACK_ALIGNMENT, 4);

MoveImageToTexture();

glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint (GL_POINT_SMOOTH_HINT, GL_NICEST);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}

void MyOpenGLComp::renderOpenGL()
{
if(!myImage || myImage->getWidth() <= 0)
return;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho (0.0, getWidth(), 0.0, getHeight(), 0, 1);

// do i need to bind??
//glBindTexture( GL_TEXTURE_2D, myGLTextureId );

glBegin(GL_QUADS);
	glTexCoord2i (0, 0); glVertex2f (0.0, getHeight());					// top left
    glTexCoord2i (1, 0); glVertex2f (myImage->getWidth(), getHeight());	// top right
    glTexCoord2i (1, 1); glVertex2f (myImage->getWidth(), 0.0);			// bottom right
    glTexCoord2i (0, 1); glVertex2f (0.0, 0.0);							// bottom left
glEnd();

}[/code]


#2

OpenGL is very state based. When you bind a texture it sets it as the ‘current’ texture for that context.

So the safe way to start is to always bind each to the texture you want. It’s possible, if each component has it’s own context, that it will stay bound, but at the very least, after/as your context is created, you would need to bind there.

Note that you also need to generate and bind your texture in the place is going to be used, all those are per-context unless you specify shares.

So safe bets:
generate the texture in the context create
bind to it, then move pixels to it

bind to the texture each time before you use it

Bruce


#3

[quote=“Bruce Wheaton”]
So safe bets:
generate the texture in the context create
bind to it, then move pixels to it

bind to the texture each time before you use it

Bruce[/quote]

Ok, thanks for the tips…

So, in the above posted code i have some commented out calls to bind the texture…
if i uncomment them, i’m not getting any textures drawn to the screen (!?).

I guess back to the original question, if i bind the texture, does each component use a unique textureId (ie., Component1 would be ‘1’, Component2 would be ‘2’, etc)?
If i use
glGenTextures(1, &myOpenGLId);

then it always come back as ‘1’…

?

thanks


#4

I think it’s probably a unique ID per context. So it could well be 1 on both, with both having their own context and textures.

BTW, there is a way to update an existing texture’s pixels.

If you’re doing a lot more OpenGL, check out the OpenGL SuperBible, even before and instead of the ‘red book’, ‘blue book’ etc. Great technical book, loads of info. Has a complete index of GLnnnn

Not sure why you’re textures aren’t showing. I would be wary of ‘where’ you generated them. Are they white? That can be using a texture that’s ‘in’ another context.

Bruce


#5

[quote=“Bruce Wheaton”]I think it’s probably a unique ID per context. So it could well be 1 on both, with both having their own context and textures.

BTW, there is a way to update an existing texture’s pixels.

If you’re doing a lot more OpenGL, check out the OpenGL SuperBible, even before and instead of the ‘red book’, ‘blue book’ etc. Great technical book, loads of info. Has a complete index of GLnnnn

Not sure why you’re textures aren’t showing. I would be wary of ‘where’ you generated them. Are they white? That can be using a texture that’s ‘in’ another context.

Bruce[/quote]

They are indeed white…
How could my texture get into another context? lol.

Thanks for the book tip… I’ll try to get my hands on it. This stuff is pretty cool…
unfortunately i’m up against a deadline on this, so i’ll have to figure out what i can…

(And… drawing this stuff from a new thread will be non-rocket-science, right?)

thanks again.


#6

Huh, well, it’s not trivial, as you found. Jules has put some nice hooks in for off the thread rendering, so it’s OK, yes.

On Mac at least, threads and contexts are pretty linked, each thread has one current context, and you can take advantage of that - I read everywhere that context switching is a huge deal.

In your case, check that you generate, bind, draw, then redraw all while in the correct context, bearing in mind juce could refresh (i.e. discard and recreate) your context anytime.

I have to say I have no idea what happens when juce tosses out the context - whether there should be some clean-up or it’s handled by OpenGL? Dunno.

Bruce


#7

Check out the OpenGLComponent::shareWith method. Create two OpenGL components, which will each be initialized with their own context, then call this once to make them share their state. Though a lot of places cite the sharing as simply texture sharing (due to its origins as such), in practice it works with most object extensions like textures, VBOs, shaders, etc. Please note that OpenGL is not threadsafe in any way-- that is, you’ll have to handle synchronization to any of your shared objects if you render the two components with their own threads (which is probable). You could also choose to render them both in the same thread (or using the same timer), which might make synchronization easier, at the cost of interdependency on the rendering frame rate. If you were crazy, you could probably even generate only a single context and switch it between display buffers as needed, but I doubt JUCE handles this well and it’s sort of a silly idea anyway. It’s true that context switches are somewhat expensive, but that will probably be true regardless of running them on different threads… the driver will almost certainly automatically serialize the context switches and commands as it interfaces with the graphics card. Unless you’re doing very advanced things, however, you probably don’t even need to worry about it.


#8

Just FYI, Mac handles shared objects for you. You don’t need to worry about it, just use the objects. The locking is all done internally. Not sure how efficient it is, but it works. Less code = better, in general.

Bruce


#9

Are you sure about that? I would be wary of this without a legit citation to confirm it. On Windows and Linux, it usually appears to work with no explicit synchronization, but it’s not guaranteed; as such, ignoring this aspect could certainly lead to very annoying race conditions. It could vary across drivers for different cards, as well. I really wouldn’t assume anything unless the documentation states it explicitly, or you run the risk of distributing code that bugs for some people.

Agreed, but remember, “Make everything as simple as possible, but not simpler.” (A. Einstein)


#10

I’m sure.


#11

Yep, according to OpenGL Programming Guide for Mac OS X, shared objects are indeed automatically locked automatically when a context accesses them. However, I think my point still stands-- if you intend to keep your app portable, it’s probably a good idea to take the synchronization into account yourself anyway. The linked document has some nice guidelines, imho, that would also be worth looking over.

Hope I’ve been at all helpful, and not just clouded the issue! hehe :oops:


#12