opengl binding of target in thread fails - opengl

I am trying to update the content of a vertex buffer by a thread.
Inside the thread function it is not possible to bind the buffer
to a target, or retrieve a pointer via glMapBufferRange.
I always get the error 1282. Outside thge thread function everything
works fine.
while( t_con->out_loop )
{
Sleep( t_con->sleep_time );
if( t_con->in_loop )
{
t_con->count++; // thread counter up
EnterCriticalSection( &__cr_sec );
/*******************************************/
/* create the strings for the variables */
/*******************************************/
str_run = sfs_p->str_ptr;
sprintf( str_run, "%4.0f / %4.0f", __mou.pos.x, __mou.pos.y ); // actual mouse position
str_run += sfs_p->str_size;
sprintf( str_run, "%4.0f / %4.0f", __mou.old_pos.x, __mou.old_pos.y ); // old mouse position
str_run += sfs_p->str_size;
sprintf( str_run, "%4.0f / %4.0f", __mou.travel.x, __mou.travel.y ); // mouse travel delta
str_run += sfs_p->str_size;
sprintf( str_run, "%d", __mou.but_l ); // mouse button left
str_run += sfs_p->str_size;
sprintf( str_run, "%d", __mou.but_m ); // mouse button center
str_run += sfs_p->str_size;
sprintf( str_run, "%d", __mou.but_r ); // mouse buttom right
str_run += sfs_p->str_size;
sprintf( str_run, "%f", __mou.speed ); // mouse speed
/******************************************************************/
/* create a Vertex_Buffer_Struct with the chars geometry data */
/******************************************************************/
vx = SFS_to_Vx_Buf( sfs_p );
glBindBuffer( GL_ARRAY_BUFFER, m_dbg->vao->vx_b->id );
G_E_C;
// bind the buffer
gl_ptr = glMapBufferRange( GL_ARRAY_BUFFER, 0, 300, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT ); // get the pointer
G_E_C;
Destroy_Vertex_Buffer_Struct( vx );
LeaveCriticalSection( &__cr_sec );
}
}
Any suggestions?

In addition to #Ripi2's answe it must be noted that a GL context can be current to at most on thread at any time. One has actually to release the context on the main thread before any worker thread can make it current. As a consequence, using a single OpenGL context in multiple threads is neither convenient nor efficient in most cases.
I am trying to update the content of a vertex buffer by a thread. Inside the thread function it is not possible to bind the buffer to a target, or retrieve a pointer via glMapBufferRange.
There are much better options for that, notably:
Just keep all GL calls in a single thread, and do the glMapBufferRange in the GL thread. While the buffer is mapped, it is writeable by the whole process, so any other thread can fill it.
Use multiple GL contexts. Each thread can have it's own context and keep it current all the time. By using shared context, the actual data objects like textures, buffers are shared between the context, so you can access the data the GL context in the other thread will be using.
In any case, you will need some proper means of synchronization between those threads, and OpenGL Sync Objects might be helpful there.

Before any gl-command is executed the gl-context must be set as current to the thread that uses those gl-commands.
Just call the SetCurrent() command or similar in your thread.
And remember that the main thread (where the app starts) is also a thread. Thus, it also needs SetCurrent() if it uses any gl-command.

Related

DirectX - GetSurfaceLevel Performance Issue

I'm implementing deferred shading in a directx 9 application. My method of deferred shading requires 3 render targets( color, position, and normal ). It is necessary to:
set the render targets in the device at the beginning of the 'render' function
draw the data to them in the 'rt pass'
remove the render targets from the device( so as not to draw over them during subsequent passes)
set the render targets as textures for subsequent passes so that the effect can recall data 'drawn' to the rt's in the 'rt pass'...
This method works fine, however, I am experiencing performance issues. I've narrowed them down to two function calls:
IDirect3DTexture9::GetSurfaceLevel()
IDirect3DDevice9::SetRenderTarget()
Here is code to set render target:
IDirect3DDevice9 *pd3dDevice = CEffectManager::GetDevice();
IDirect3DTexture9 *pRT = CEffectManager::GetColorRT();
IDirect3DSurface9 *pSrf = NULL;
pRT->GetSurfaceLevel( 0, &pSrf );
pd3dDevice->SetRenderTarget( 0, pSrf );
PIX indicates that the duration( cycles ) of the call to GetSurfaceLevel() is very high ~1/2 ms per call( Duration / Total Duration * 1 / FrameRate ). Because it is necessary to get 3 surfaces, combined, the duration is too high! Its more than 4 times greater than the combined draw calls...
I tried to eliminate the call to GetSurfaceLevel() by storing a pointer to the surface during render target creation...oddly enough, the SetRenderTarget() function assumed the same duration( when before its duration was negligible ). Here is altered code:
IDirect3DDevice9 *pd3dDevice = CEffectManager::GetDevice();
IDirect3DSurface9 *pSrf = CEffectManager::GetColorSurface();
pd3dDevice->SetRenderTarget( 0, pSrf );
Is there a way around this performance issue? Why does the second method take as long as the first? It seems as though the process within IDirect3DDevice9::SetRenderTarget() simply takes time...is there a device state that I can set to help performance?
Update:
I've implemented the following code in order to better test performance:
IDirect3DDevice9 *pd3dDevice = CEffectManager::GetDevice();
IDirect3DTexture9 *pRT = CEffectManager::GetColorRT();
IDirect3DSurface9 *pSRF = NULL;
IDirect3DQuery9 *pEvent = NULL;
LARG_INTEGER lnStart, lnStop, lnFrequency;
// create query
pd3dDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pEvent );
// insert 'end' marker
pEvent->Issue( D3DISSUE_END );
// flush command buffer
while( S_FALSE == pEvent->GetData( NULL, 0, D3DGETDATA_FLUSH ) );
// get start time
QueryPerformanceCounter( &lnStart );
// api call
pRT->GetSurfaceLevel();
// insert 'end' marker
pEvent->Issue( D3DISSUE_END )
// flush the command buffer
while( S_FALSE == pEvent->GetData( NULL, 0, D3DGETDATA_FLUSH ) );
QueryPerformanceCounter( &lnStop );
QueryPerformanceFrequency( &lnFreq );
lnStop.QuadPart -= lnStart.QuadPart;
float fElapsedTime = ( float )lnStop.QuadPart / ( float )lnFreq.QuadPart;
fElapsedTime on average measured 10 - 50 microseconds
I performed the same test on IDirect3DDevice9::SetRenderTarget() and the results on average measured 5 - 30 microseconds...
This data is much better than what I got from PIX...It suggests that there is not as much of a delay as I thought, however, the framerate is drastically reduced using deferred shading...this seems to be the most likely source for the loss of performance...did I effectively query the device?

Display Different images per monitor directX 10

I am fairly new to DirectX 10 programming, and I have been trying to do the following with my limited skills (though I have a strong background with OpenGL)
I am trying to display 2 different textured Quads, 1 per monitor. To do so, I understood that I need a single D3D10 Device, multiple (2) swap chains, and single VertexBuffer
While I think I'm able to create all of those, I'm still pretty unsure how to handle all of them. Do I need multiple ID3D10RenderTargetView(s) ? How and where should I Use OMSetRenderTargets(...) ?
Other than MSDN, documentation or explaination of those concepts are rather limited, so any help would be very welcome. Here is some code I have :
Here's the rendering code
for(int i = 0; i < screenNumber; i++){
//clear scene
pD3DDevice->ClearRenderTargetView( pRenderTargetView, D3DXCOLOR(0,1,0,0) );
//fill vertex buffer with vertices
UINT numVertices = 4;
vertex* v = NULL;
//lock vertex buffer for CPU use
pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**) &v );
v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1), D3DXVECTOR2(0.0f, 1.0f) );
v[1] = vertex( D3DXVECTOR3(-1,1,0), D3DXVECTOR4(0,1,0,1), D3DXVECTOR2(0.0f, 0.0f) );
v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1), D3DXVECTOR2(1.0f, 1.0f) );
v[3] = vertex( D3DXVECTOR3(1,1,0), D3DXVECTOR4(1,1,0,1), D3DXVECTOR2(1.0f, 0.0f) );
pVertexBuffer->Unmap();
// Set primitive topology
pD3DDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
//set texture
pTextureSR->SetResource( textureSRV[textureIndex] );
//get technique desc
D3D10_TECHNIQUE_DESC techDesc;
pBasicTechnique->GetDesc( &techDesc );
// This is where you actually use the shader code
for( UINT p = 0; p < techDesc.Passes; ++p )
{
//apply technique
pBasicTechnique->GetPassByIndex( p )->Apply( 0 );
//draw
pD3DDevice->Draw( numVertices, 0 );
}
//flip buffers
pSwapChain[i]->Present(0,0);
}
And here's the code for creating rendering targets, which I am not sure is good
for(int i = 0; i < screenNumber; ++i){
//try to get the back buffer
ID3D10Texture2D* pBackBuffer;
if ( FAILED( pSwapChain[1]->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*) &pBackBuffer) ) ) return fatalError("Could not get back buffer");
//try to create render target view
if ( FAILED( pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView) ) ) return fatalError("Could not create render target view");
pBackBuffer->Release();
pD3DDevice->OMSetRenderTargets(1, &pRenderTargetView, NULL);
}
return true;
}
I hope I got the gist of what you wish to do - render different content on two different monitors while using a single graphics card (graphics adapter) which maps its output to those monitors. For that, you're going to need one device (for the single graphics card/adapter) and enumerate just how many outputs there are at the user's machine.
So, in total - that means one device, two outputs, two windows and therefore - two swap chains.
Here's a quick result of my little experiment:
A little introduction
With DirectX 10+, this falls into the DXGI (DirectX Graphics Infrastructure) which manages the common low-level logistics involved with DirectX 10+ development which, as you probably know, dumped the old requirement of enumerating feature sets and the like - requiring every DX10+ capable card to share in on all of the features defined by the API. The only thing that varies is the extent and capability of the card (in other words, lousy performance is preferable to the app crashing and burning). This was all within DirectX 9 in the past, but people at Microsoft decided to pull it out and call it DXGI. Now, we can use DXGI functionality to set up our multi monitor environment.
Do I need multiple ID3D10RenderTargetView(s) ?
Yes, you do need multiple render target views, count depends (like the swap chains and windows) on the number of monitors you have. But, to save you from spewing words, let's write it out as simple as possible and additional information where it's needed:
Enumerate all adapters available on the system.
For each adapter, enumerate all outputs available (and active) and create a device to accompany it.
With the enumerated data stored in a suitable structure (think arrays which can quickly relinquish size information), use it to create n windows, swap chains, render target views, depth/stencil textures and their respective views where n is equal to the number of outputs.
With everything created, for each window you are rendering into, you can define special routines which will use the available geometry (and other) data to output your results - which resolves to what each monitor gets in fullscreen (don't forget to adjust the viewport for every window accordingly).
Present your data by iterating over every swap chain which is linked to its respective window and swap buffers with Present()
Now, while this is rich in word count, some code is worth a lot more. This is designed to give you a coarse idea of what goes into implementing a simple multimonitor application. So, assumptions are that there is only one adapter ( a rather bold statement nowadays ) and multiple outputs - and no failsafes. I'll leave the fun part to you. Answer to the second question is downstairs...
Do note there's no memory management involved. We assume everything magically gets cleaned up when it is not needed for illustration purposes. Be a good memory citizen.
Getting the adapter
IDXGIAdapter* adapter = NULL;
void GetAdapter() // applicable for multiple ones with little effort
{
// remember, we assume there's only one adapter (example purposes)
for( int i = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters( i, &adapter ); ++i )
{
// get the description of the adapter, assuming no failure
DXGI_ADAPTER_DESC adapterDesc;
HRESULT hr = adapter->GetDesc( &adapterDesc );
// Getting the outputs active on our adapter
EnumOutputsOnAdapter();
}
Acquiring the outputs on our adapter
std::vector<IDXGIOutput*> outputArray; // contains outputs per adapter
void EnumOutputsOnAdapter()
{
IDXGIOutput* output = NULL;
for(int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
// get the description
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc( &outputDesc );
outputArray.push_back( output );
}
}
Now, I must assume that you're at least aware of the Win32 API considerations, creating window classes, registering with the system, creating windows, etc... Therefore, I will not qualify its creation, only elaborate how it pertains to multiple windows. Also, I will only consider the fullscreen case here, but creating it in windowed mode is more than possible and rather trivial.
Creating the actual windows for our outputs
Since we assume existence of just one adapter, we only consider the enumerated outputs linked to that particular adapter. It would be preferable to organize all window data in neat little structures, but for the purposes of this answer, we'll just shove them into a simple struct and then into yet another std::vector object, and by them I mean handles to respective windows (HWND) and their size (although for our case it's constant).
But still, we have to address the fact that we have one swap chain, one render target view, one depth/stencil view per window. So, why not feed all of that in that little struct which describes each of our windows? Makes sense, right?
struct WindowDataContainer
{
//Direct3D 10 stuff per window data
IDXGISwapChain* swapChain;
ID3D10RenderTargetView* renderTargetView;
ID3D10DepthStencilView* depthStencilView;
// window goodies
HWND hWnd;
int width;
int height;
}
Nice. Well, not really. But still... Moving on! Now to create the windows for outputs:
std::vector<WindowDataContainer*> windowsArray;
void CreateWindowsForOutputs()
{
for( int i = 0; i < outputArray.size(); ++i )
{
IDXGIOutput* output = outputArray.at(i);
DXGI_OUTPUT_DESC outputDesc;
p_Output->GetDesc( &outputDesc );
int x = outputDesc.DesktopCoordinates.left;
int y = outputDesc.DesktopCoordinates.top;
int width = outputDesc.DesktopCoordinates.right - x;
int height = outputDesc.DesktopCoordinates.bottom - y;
// Don't forget to clean this up. And all D3D COM objects.
WindowDataContainer* window = new WindowDataContainer;
window->hWnd = CreateWindow( windowClassName,
windowName,
WS_POPUP,
x,
y,
width,
height,
NULL,
0,
instance,
NULL );
// show the window
ShowWindow( window->hWnd, SW_SHOWDEFAULT );
// set width and height
window->width = width;
window->height = height;
// shove it in the std::vector
windowsArray.push_back( window );
//if first window, associate it with DXGI so it can jump in
// when there is something of interest in the message queue
// think fullscreen mode switches etc. MSDN for more info.
if(i == 0)
factory->MakeWindowAssociation( window->hWnd, 0 );
}
}
Cute, now that's done. Since we only have one adapter and therefore only one device to accompany it, create it as usual. In my case, it's simply a global interface pointer which can be accessed all over the place. We are not going for code of the year here, so why the hell not, eh?
Creating the swap chains, views and the depth/stencil 2D texture
Now, our friendly swap chains... You might be used to actually creating them by invoking the "naked" function D3D10CreateDeviceAndSwapChain(...), but as you know, we've already made our device. We only want one. And multiple swap chains. Well, that's a pickle. Luckily, our DXGIFactory interface has swap chains on its production line which we can receive for free with complementary kegs of rum. Onto the swap chains then, create for every window one:
void CreateSwapChainsAndViews()
{
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// get the dxgi device
IDXGIDevice* DXGIDevice = NULL;
device->QueryInterface( IID_IDXGIDevice, ( void** )&DXGIDevice ); // COM stuff, hopefully you are familiar
// create a swap chain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
// fill it in
HRESULT hr = factory->CreateSwapChain( DXGIDevice, &swapChainDesc, &p_Window->swapChain );
DXGIDevice->Release();
DXGIDevice = NULL;
// get the backbuffer
ID3D10Texture2D* backBuffer = NULL;
hr = window->swapChain->GetBuffer( 0, IID_ID3D10Texture2D, ( void** )&backBuffer );
// get the backbuffer desc
D3D10_TEXTURE2D_DESC backBufferDesc;
backBuffer->GetDesc( &backBufferDesc );
// create the render target view
D3D10_RENDER_TARGET_VIEW_DESC RTVDesc;
// fill it in
device->CreateRenderTargetView( backBuffer, &RTVDesc, &window->renderTargetView );
backBuffer->Release();
backBuffer = NULL;
// Create depth stencil texture
ID3D10Texture2D* depthStencil = NULL;
D3D10_TEXTURE2D_DESC descDepth;
// fill it in
device->CreateTexture2D( &descDepth, NULL, &depthStencil );
// Create the depth stencil view
D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;
// fill it in
device->CreateDepthStencilView( depthStencil, &descDSV, &window->depthStencilView );
}
}
We now have everything we need. All that you need to do is define a function which iterates over all windows and draws different stuff appropriately.
How and where should I Use OMSetRenderTargets(...) ?
In the just mentioned function which iterates over all windows and uses the appropriate render target (courtesy of our per-window data container):
void MultiRender( )
{
// Clear them all
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// There is the answer to your second question:
device->OMSetRenderTargets( 1, &window->renderTargetView, window->depthStencilView );
// Don't forget to adjust the viewport, in fullscreen it's not important...
D3D10_VIEWPORT Viewport;
Viewport.TopLeftX = 0;
Viewport.TopLeftY = 0;
Viewport.Width = window->width;
Viewport.Height = window->height;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
device->RSSetViewports( 1, &Viewport );
// TO DO: AMAZING STUFF PER WINDOW
}
}
Of course, don't forget to run through all the swap chains and swap buffers per window basis. The code here is just for the purposes of this answer, it requires a bit more work, error checking (failsafes) and contemplation to get it working just the way you like it - in other words - it should give you a simplified overview, not a production solution.
Good luck and happy coding! Sheesh, this is huge.

SDL flips both surfaces

I use SDL for my programs graphics and I have a problem with it in flipping surfaces.When I compile following code:
int main(int argc , char* argv[])
{
SDL_Surface* scr1 = SDL_SetVideoMode(880 , 600 , 0 , SDL_HWSURFACE |SDL_DOUBLEBUF );
SDL_Surface* scr2 = SDL_SetVideoMode(880 , 600 , 0 , SDL_HWSURFACE |SDL_DOUBLEBUF );
aacircleRGBA(scr1 , 50 , 50 , 30 , 255 , 0 , 0 , 255);
SDL_Flip(scr2);
return 0;
}
It shows the circle on the screen.But I flipped only scr2.Why does it show the circle?
After you call SDL_SetVideoMode() a second time, the original screen buffer pointer is, in the general case, invalid. You shouldn’t be reusing it, because it doesn’t point to an allocated surface anymore.
In this case, calling SDL_SetVideoMode() twice with the same parameters gives scr2 == scr1, because there is no need for SDL to reallocate the video surface. Drawing on the surface referred to by scr1 is thus the same as drawing on that referred to by scr2.
On success. The returned surface is freed by SDL_Quit and must not be freed by the
caller. This rule also includes consecutive calls to SDL_!SetVideoMode (i.e. resize or resolution change) because the existing surface will be released automatically. Whatever flags SDL_!SetVideoMode could satisfy are set in the flags member of the returned surface.
-- SDL_SetVideoMode function (emphasis mine)
There is only one hardware surface to render to, the one that appears on screen immediately after calling SDL_SetVideoMode. where else would you expect that buffer to draw to?

glGenBuffers returning non-unique names

I thought that this was impossible but I'm seeing it with my software. I have built a wrapper object to manage my buffer objects (I am working with shared contexts so I can't use VAOs), and the VBO side of things was working fine until I starting testing it with IBOs (glDrawElements(), I'm using a pure OpenGL 3+ environment).
Here is the code for adding a buffer to my object (Sy_GLObject):
QList< uint > Sy_GLObject::addBuffers( uint numBuffers, GLenum target,
GLenum numericType, GLenum usage )
{
uint* adds = new uint[numBuffers];
glGenBuffers( numBuffers, adds );
QList< uint > l;
for ( uint i = 0; i < numBuffers; ++i ) {
Buffer buffer( target, adds[i], 0, numericType, usage );
buffers_ << buffer;
l << i;
}
delete[] adds;
Sy_GL::checkError();
return l;
}
And the buffer names returned by this function are fine, until it is called by this code:
void Sy_BVH::initialiseGLObject()
{
Sy_application::getMainWindow()->getActiveProject(
)->getModelContext()->makeCurrent();
GLuint vLoc = Sy_settings::get( "shader/flat/vertexLoc" ).toUInt();
drawBBs_ = Sy_GLObject::createObject();
// Add vertex array.
drawBBs_->addBuffers( 1 );
drawBBs_->buffers()[0].setVertexPointer( vLoc );
// Add indices array.
drawBBs_->addBuffers( 1, GL_ELEMENT_ARRAY_BUFFER, GL_UNSIGNED_INT );
}
For some reason the indices array and vertex array names are both the same! setVertexPointer() does not actually call glVertexAttribPointer(), it just stores the parameters for it in a POD class - so no OpenGL calls are made between the two addBuffers() commands. The vertex call is 'correct' as it is one higher than the previous glGenBuffers() result, but from addBuffers() point of view there should be no difference between the calls.
Are there circumstances where glGenBuffers can possibly return the name of a buffer already in use!?
Thanks!
Update
To make sure threading was not a factor, I wrapped a static mutex around the glGenBuffers() block.
QMutexLocker locker( &mutex_ ); // mutex_ is a QMutex static class member.
uint* adds = new uint[numBuffers];
glGenBuffers( numBuffers, adds );
locker.unlock();
But it had absolutely no effect...
Thanks to Ilian Dinev over at the OpenGL.org forums for pointing out this stupid error. I created my Buffer object on the stack and conveniently had it's destructor call glDeleteBuffers(). Fantastic bit of design.

Console menu updating OpenGL window

I am making an application that does some custom image processing. The program will be driven by a simple menu in the console. The user will input the filename of an image, and that image will be displayed using openGL in a window. When the user selects some processing to be done to the image, the processing is done, and the openGL window should redraw the image.
My problem is that my image is never drawn to the window, instead the window is always black. I think it may have to do with the way I am organizing the threads in my program. The main execution thread handles the menu input/output and the image processing and makes calls to the Display method, while a second thread runs the openGL mainloop.
Here is my main code:
#include <iostream>
#include <GL/glut.h>
#include "ImageProcessor.h"
#include "BitmapImage.h"
using namespace std;
DWORD WINAPI openglThread( LPVOID param );
void InitGL();
void Reshape( GLint newWidth, GLint newHeight );
void Display( void );
BitmapImage* b;
ImageProcessor ip;
int main( int argc, char *argv[] ) {
DWORD threadID;
b = new BitmapImage();
CreateThread( 0, 0, openglThread, NULL, 0, &threadID );
while( true ) {
char choice;
string path = "TestImages\\";
string filename;
cout << "Enter filename: ";
cin >> filename;
path += filename;
b = new BitmapImage( path );
Display();
cout << "1) Invert" << endl;
cout << "2) Line Thin" << endl;
cout << "Enter choice: ";
cin >> choice;
if( choice == '1' ) {
ip.InvertColour( *b );
}
else {
ip.LineThinning( *b );
}
Display();
}
return 0;
}
void InitGL() {
int argc = 1;
char* argv[1];
argv[0] = new char[20];
strcpy( argv[0], "main" );
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition( 0, 0 );
glutInitWindowSize( 800, 600 );
glutCreateWindow( "ICIP Program - Character recognition using line thinning, Hilbert curve, and wavelet approximation" );
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glClearColor(0.0,0.0,0.0,1.0);
glEnable(GL_DEPTH_TEST);
}
void Reshape( GLint newWidth, GLint newHeight ) {
/* Reset viewport and projection parameters */
glViewport( 0, 0, newWidth, newHeight );
}
void Display( void ) {
glClear (GL_COLOR_BUFFER_BIT); // Clear display window.
b->Draw();
glutSwapBuffers();
}
DWORD WINAPI openglThread( LPVOID param ) {
InitGL();
glutMainLoop();
return 0;
}
Here is my draw method for BitmapImage:
void BitmapImage::Draw() {
cout << "Drawing" << endl;
if( _loaded ) {
glBegin( GL_POINTS );
for( unsigned int i = 0; i < _height * _width; i++ ) {
glColor3f( _bitmap_image[i*3] / 255.0, _bitmap_image[i*3+1] / 255.0, _bitmap_image[i*3+2] / 255.0 );
// invert the y-axis while drawing
glVertex2i( i % _width, _height - (i / _width) );
}
glEnd();
}
}
Any ideas as to the problem?
Edit: The problem was technically solved by starting a glutTimer from the openglThread which calls glutPostRedisplay() every 500ms. This is OK for now, but I would prefer a solution in which I only have to redisplay every time I make changes to the bitmap (to save on processing time) and one in which I don't have to run another thread (the timer is another thread im assuming). This is mainly because the main processing thread is going to be doing a lot of intensive work and I would like to dedicate most of the resources to this thread rather than anything else.
I've had this problem before - it's pretty annoying. The problem is that all of your OpenGL calls must be done in the thread where you started the OpenGL context. So when you want your main (input) thread to change something in the OpenGL thread, you need to somehow signal to the thread that it needs to do stuff (set a flag or something).
Note: I don't know what your BitmapImage loading function (here, your constructor) does, but it probably has some OpenGL calls in it. The above applies to that too! So you'll need to signal to the other thread to create a BitmapImage for you, or at least to do the OpenGL-related part of creating the bitmap.
A few points:
Generally, if you're going the multithreaded route, it's preferable if your main thread is your GUI thread i.e. it does minimal tasks keeping the GUI responsive. In your case, I would recommend moving the intensive image processing tasks into a thread and doing the OpenGL rendering in your main thread.
For drawing your image, you're using vertices instead of a textured quad. Unless you have a very good reason, it's much faster to use a single textured quad (the processed image being the texture). Check out glTexImage2D and glTexSubImage2D.
Rendering at a framerate of 2fps (500ms, as you mentioned) will have negligible impact on resources if you're using an OpenGL implementation that is accelerated, which is almost guaranteed on any modern system, and if you use a textured quad instead of a vertex per pixel.
Your problem may be in Display() at the line
b->Draw();
I don't see where b is passed into the scope of Display().
You need to make OpenGL calls on the thread in which context was created (glutInitDisplayMode). Hence glXX calls inside Display method which is on different thread will not be defined. You can see this easily by dumping the function address, hopefully it would be undefined or NULL.
It sounds like the 500ms timer is calling Display() regularly, after 2 calls it fills the back-buffer and the front-buffer with the same rendering. Display() continues to be called until the user enters something, which the OpenGL thread never knows about, but, since, global variable b is now different, the thread blindly uses that in Display().
So how about doing what Jesse Beder says and use a global int, call it flag, to flag when the user entered something. For example:
set flag = 1; after you do the b = new BitmapImage( path );
then set flag = 0; after you call Display() from the OpenGL thread.
You loop on the timer, but, now check if flag = 1. You only need call glutPostRedisplay() when flag = 1, i.e. the user entered something.
Seems like a good way without using a sleep/wake mechanism. Accessing global variables among more than one thread can also be unsafe. I think the worst that can happen here is the OpenGL thread miss-reads flag = 0 when it should read flag = 1. It should then catch it after no more than a few iterations. If you get strange behavior go to synchronization.
With the code you show, you call Display() twice in main(). Actually, main() doesn't even need to call Display(), the OpenGL thread does it.