PDA

View Full Version : Share a GlTexture between two threads



Zetfire
07-11-2017, 03:44 AM
Hi,

I'm trying to save a gltexture to a tiff File from an other thread. I'm trying to do that because at the end the gltexture will be a video stream from a camera and i want to be able to save the stream when i want.
I've created a thread on stackoverflow here: https://stackoverflow.com/questions/45006833/save-an-opengl-texture-in-tiff-file-from-an-other-thread
It will allow you to access the code.
To update it, i know that i can save to tiff file if i'm using one thread but if i'm trying to launch a new thread to save. I have to create an other context so i have two contexts gl and gl2 which are shared thanks to wglsharelists(gl,gl2)
Does it allow the texture to be shared or only i have to generate the texture in a display list? Because actually it isn't enough to share the texture.

Do you have any idea?
Thanks

Dark Photon
07-11-2017, 06:40 AM
Couple thoughts for you. Yes, you could do this with two contexts, one per thread, which share objects (e.g. textures) if you're careful about synchronization. However, it may not be the simplest solution.

And you can ignore display lists; those aren't helpful here. The "share objects" flag is named share lists for legacy reasons, but you can ignore that. It's not implying you need display lists to share objects between contexts.

Have you considered whether another tech approach might be simpler? How does the camera video make its way to the GPU? What does the "non-TIFF-saving GL thread do"?

The reason I ask is because GPUs (particularly desktop GPUs) are typically optimized for rendering frames for scan-out on or more of their video ports, not feeding the frames back over the bus to the CPU (though you can do this). And some GPU vendor(s) cripple GPU->CPU frame readback performance on some of their consumer GPUs. If your video stream from the camera is uploaded to the GPU so your GL threads can access it, rather than read these frames back across the bus from the GPU to save them, it might be simpler and more efficient to just intercept that video stream before it gets sent to the GPU in the first place and save that.

If you can't do that, another approach to consider would be to use a 2-threaded approach where only 1 thread talks to GL (and thus only 1 thread has a context). Basically you'd use GL to read back the frames into PBOs. These PBOs can then be mapped by the GL thread into CPU memory. Once mapped, you can just pass a pointer to a mapped PBO to a background "save TIFF" thread where it can read the frames and write them to disk. This allows the "save TIFF" thread to have access to the image data without having to have a GL context. There are other variations on this theme, but hopefully you get the idea.

Zetfire
07-11-2017, 07:18 AM
Thanks for your answer,
To sum up my application, there is three threads one main which launch the other threads, one to capture the video stream from the camera and i'd like an other to save it in tiff file.
I'm using the nvapi to capture the sdi stream (https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwjdkuG3pYHVAhVC2hoKHZIdDGEQFggtMAE&url=http%3A%2F%2Finternational.download.nvidia.com %2Fquadro%2Fproduct-literature%2Fprogrammers-guides%2FPG-03776-001_v05.pdf&usg=AFQjCNG48gA6v-9SAM2pHnE44sU2UKxddQ&cad=rja)

And when the capture is done i have directly a gltexture with the video stream. If i load back the texture to the cpu, it's mainly because i don't know how to save directly a gltexture to a tiff file (That's why i'm using the libtiff, but to do so i need to retrieve it from te GPUs)
Do you know a way to save directly the gltexture?
(After a quick check, i can't use glreadpixels as i'm drawing several textures on my framebuffer, that's why i get the data from each gltexture)
EDIT---
I'm trying the other solution, The main thread launch the capture which require an opengl Context and can launch an other thread to save the texture. For the moment, i only have a white Tiff file as a result. (and i know that my texture is correctly captured because i display the video stream from the camera)
Here is the switch where i make the different action in the main thread (depending on which button is clicked)


switch (message)
{
case WM_CREATE:
buttons[0] = CreateWindow("BUTTON", "Capture", WS_CHILD | WS_VISIBLE, 5, 5, 383, 30, mainWindow, (HMENU) ID_B_STARTCAPTURE, instance, NULL);
buttons[1] = CreateWindow("BUTTON", "Record", WS_CHILD | WS_VISIBLE, 5, 45, 383, 30, mainWindow, (HMENU) ID_B_STARTRECORD,instance, NULL);
return 0;
break;
case WM_COMMAND:
switch(LOWORD(wParam)){
case ID_B_STARTCAPTURE:
{
capture.CaptureCall(gl,mainWindow, instance,CMDLINE , affichage,capture ) ;// Launch the capture thread
capture.launched = true;
} break;
case ID_B_STARTRECORD:
capture.rec[0].Start_StopRecord(capture.m_SDIin.GetTextureObject Handle(0), capture.launched, capture.m_hDC, capture.m_hRC2);//Launch the save thread
break;
}
return 0;
break;
case WM_DESTROY:
C_anccap::exit = true;
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(mainWindow, message, wParam, lParam);
}

Here is the capture function

int C_anccap::CaptureCall (HGLRC &gl,HWND &father, HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow, C_anccap& anccap)
{
HWND g_hWnd;
capture = &anccap;
// Debug console.
SetupConsole();
if(capture->Configure(&lpCmdLine) == E_FAIL)
return FALSE;

if(capture->SetupSDIDevices() == E_FAIL)
return FALSE;

// Calculate the window size based on the incoming and outgoing video signals
capture->CalcWindowSize();

// Create window. Use video dimensions of video initialized above.
// Hack: Compensate for title bar height.
//g_windowHeight += 30;
g_hWnd = capture->SetupWindow(father, hInstance, 0, 0, "NVIDIA Quadro SDI Capture to memory");

// Exit on error.
if (!g_hWnd)
return FALSE;

capture->SetupGL(gl);

if(capture->StartSDIPipeline() == E_FAIL)
return FALSE;



// Show window.
ShowWindow(g_hWnd, nCmdShow);
UpdateWindow(g_hWnd);

wglMakeCurrent(NULL, NULL);
capturethread = std::thread(&C_anccap::LoopAnimation, capture);

}

int C_anccap::LoopAnimation()
{
MSG msg;

// Animation loop.
std::mutex mtx;
while (!C_anccap::exit) {
if (this->CaptureVideo() != GL_FAILURE_NV)
{
this->DisplayVideo();
if (this->rec[0].isStarted) {
mtx.lock();
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->rec[0].pixels.get());
mtx.unlock();
auto e =glGetError();
printf("test");
}
}
}
this->Shutdown();
wglMakeCurrent(NULL, NULL);
return FALSE;
}


And this is the saving function:


void Recorder::Start_StopRecord(GLuint Texture, bool launched,HDC &hdc, HGLRC & gl){
if (launched) {
if (isStarted) {
isStarted = false;
recordThread.join();
CloseTifFile();
pixels.release();
}
else {
pixels = std::unique_ptr<int>(new int[width*height]);
OpenTifFile(Texture);
isStarted = true;

recordThread = std::thread(&Recorder::RecordShot, this,&Texture,&hdc,&gl);
}
}
}
void Recorder::RecordShot(GLuint* texture, HDC* hdc, HGLRC* gl){
std::mutex mtx;
mtx.lock();
while (isStarted) {
WriteTif8Bits();
WriteDirectory();
}
mtx.unlock();
pixels.release();

}

void Recorder::OpenTifFile(GLuint &Texture){
char* filename="C:/Users/BOOM/Documents/textures/test3.tiff";

mp_fileTifIn = TIFFOpen(filename,"w");


}

void Recorder::CloseTifFile(){
TIFFClose(mp_fileTifIn);
}
void Recorder::WriteTif8Bits(){
//Setup Tiff Configuration
TIFFSetField(mp_fileTifIn,TIFFTAG_IMAGEWIDTH,width );
TIFFSetField(mp_fileTifIn,TIFFTAG_IMAGELENGTH,heig ht);
TIFFSetField(mp_fileTifIn,TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(mp_fileTifIn,TIFFTAG_BITSPERSAMPLE,8) ;
TIFFSetField(mp_fileTifIn,TIFFTAG_ROWSPERSTRIP,TIF FDefaultStripSize(mp_fileTifIn,width));
TIFFSetField(mp_fileTifIn,TIFFTAG_ORIENTATION,ORIE NTATION_TOPLEFT);
TIFFSetField(mp_fileTifIn,TIFFTAG_PLANARCONFIG,PLA NARCONFIG_CONTIG);
TIFFSetField(mp_fileTifIn, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
//Image Reversal
Reverse(pixels.get(), height, width);

//Write one picture
TIFFWriteEncodedStrip(mp_fileTifIn, 0, pixels.get(), height*width * sizeof(int));
}


EDIT 2
I finally get why i had only a white picture, in fact the glgetteximage was badly configured with GL_TEXTURE_2D and my textures are GL_TEXTURE_RECTANGLE_NV; Thanks again for the idea of one thread which execute all opengl action