diff --git a/SPOUTSDK/SpoutGL/Spout.cpp b/SPOUTSDK/SpoutGL/Spout.cpp index 3d78b94e..4b6fae53 100644 --- a/SPOUTSDK/SpoutGL/Spout.cpp +++ b/SPOUTSDK/SpoutGL/Spout.cpp @@ -216,6 +216,7 @@ // 17.12.21 - Remove adapter gets from Sender/Receiver init // Adapter index and name are retrieved with Get functions // 20.12.21 - Restore log notice for ReleaseSender +// 24.02.22 - Restore GetSenderAdpater for testing // // ==================================================================================== /* @@ -303,6 +304,8 @@ Spout::Spout() // Initialize adapter name global // Adapter index and name are retrieved with create sender or receiver m_AdapterName[0] = 0; + m_bAdapt = false; // Receiver adapt to the sender adapter + } Spout::~Spout() @@ -1145,6 +1148,73 @@ bool Spout::SetAdapter(int index) return true; } +//--------------------------------------------------------- +// Function: GetSenderAdapter +// Get sender adapter index and name for a given sender +// +// Testing only. +// Note that OpenDX11shareHandle fails and can crash if the share handle +// has been created using a different graphics adapter (see spoutDirectX) +// Try/Catch can catch the exception but not recommended for general use. +int Spout::GetSenderAdapter(const char* sendername, char* adaptername, int maxchars) +{ + if (!sendername || !sendername[0]) + return -1; + + int senderadapter = -1; + ID3D11Texture2D* pSharedTexture = nullptr; + ID3D11Device* pDummyDevice = nullptr; + ID3D11DeviceContext* pContext = nullptr; + IDXGIAdapter* pAdapter = nullptr; + + // Get the current device adapter pointer (could be null default) + IDXGIAdapter* pCurrentAdapter = spoutdx.GetAdapterPointer(); + + SpoutLogNotice("Spout::GetSenderAdapter - testing for sender adapter (%s)", sendername); + + SharedTextureInfo info; + if (sendernames.getSharedInfo(sendername, &info)) { + int nAdapters = spoutdx.GetNumAdapters(); + for (int i = 0; i < nAdapters; i++) { + pAdapter = spoutdx.GetAdapterPointer(i); + if (pAdapter) { + SpoutLogNotice(" testing adapter %d", i); + // Set the adapter pointer for CreateDX11device to use temporarily + spoutdx.SetAdapterPointer(pAdapter); + // Create a dummy device using this adapter + pDummyDevice = spoutdx.CreateDX11device(); + if (pDummyDevice) { + // Try to open the share handle with the device created from the adapter + if (spoutdx.OpenDX11shareHandle(pDummyDevice, &pSharedTexture, LongToHandle((long)info.shareHandle))) { + // break as soon as it succeeds + SpoutLogNotice(" found sender adapter %d (0x%.7X)", i, PtrToUint(pAdapter)); + senderadapter = i; + // Return the adapter name + if (adaptername) + spoutdx.GetAdapterName(i, adaptername, maxchars); + pDummyDevice->GetImmediateContext(&pContext); + if (pContext) pContext->Flush(); + pDummyDevice->Release(); + pAdapter->Release(); + break; + } + pDummyDevice->GetImmediateContext(&pContext); + if (pContext) pContext->Flush(); + pDummyDevice->Release(); + } + pAdapter->Release(); + } + } + } + + // Set the SpoutDirectX class adapter pointer back to what it was + spoutdx.SetAdapterPointer(pCurrentAdapter); + + return senderadapter; + +} + + //--------------------------------------------------------- // Function: GetAdapterInfo // Get the current adapter description @@ -2011,13 +2081,15 @@ bool Spout::ReceiveSenderData() // Get a new shared texture pointer (m_pSharedTexture) if (!spoutdx.OpenDX11shareHandle(spoutdx.GetDX11Device(), &m_pSharedTexture, dxShareHandle)) { + // If this fails, something is wrong. - // The sender graphics adapter might be different or some other reason. - // Error log is generated in OpenDX11shareHandle. - // SpoutLogWarning("Spout::ReceiveSenderData - could not retrieve sender texture from share handle"); + // The sender graphics adapter might be different. + // Warning not required here -Error log is generated in OpenDX11shareHandle. + // Retain the share handle so we don't query the same sender again. // m_pSharedTexture is null but will not be used. - // Return true and wait until another sender is selected. + // Wait until another sender is selected or the shared texture handle is valid. + return true; } } @@ -2062,6 +2134,7 @@ bool Spout::ReceiveSenderData() } + //--------------------------------------------------------- // Check whether SpoutPanel opened and return the new sender name bool Spout::CheckSpoutPanel(char *sendername, int maxchars) diff --git a/SPOUTSDK/SpoutGL/Spout.h b/SPOUTSDK/SpoutGL/Spout.h index b1c3d8b5..c8028d53 100644 --- a/SPOUTSDK/SpoutGL/Spout.h +++ b/SPOUTSDK/SpoutGL/Spout.h @@ -186,9 +186,12 @@ class SPOUT_DLLEXP Spout : public spoutGL { int GetAdapter(); // Set graphics adapter for output bool SetAdapter(int index = 0); + // Get sender adapter index and name for a given sender + int GetSenderAdapter(const char* sendername, char* adaptername = nullptr, int maxchars = 256); // Get the current adapter description bool GetAdapterInfo(char *renderdescription, char *displaydescription, int maxchars); + // // 2.006 compatibility // @@ -242,13 +245,15 @@ class SPOUT_DLLEXP Spout : public spoutGL { void InitReceiver(const char * sendername, unsigned int width, unsigned int height, DWORD dwFormat); // Receiver find sender and retrieve information bool ReceiveSenderData(); - + // - // Class global + // Class globals // // Graphics adapter name char m_AdapterName[256]; + bool m_bAdapt; // Receiver adapt to the sender adapter + }; diff --git a/SPOUTSDK/SpoutGL/SpoutCopy.cpp b/SPOUTSDK/SpoutGL/SpoutCopy.cpp index 14a8a080..5e854a3e 100644 --- a/SPOUTSDK/SpoutGL/SpoutCopy.cpp +++ b/SPOUTSDK/SpoutGL/SpoutCopy.cpp @@ -53,6 +53,7 @@ 09.12.20 - Correct movsd line pitch in RemovePadding 13.03.21 - Change CopyPixels and FlipBuffer to accept GL_LUMINANCE 09.07.21 - memcpy_sse2 - return for null dst or src + 21.02.22 - use std:: prefix for floor in rgba2rgbResample for Clang compatibility. PR#81 */ @@ -1102,8 +1103,8 @@ void spoutCopy::rgba2bgrResample(const void* source, void* dest, unsigned int pixel, nearestMatch; for (i = 0; i < destHeight; i++) { for (j = 0; j < destWidth; j++) { - px = floor((float)j*x_ratio); - py = floor((float)i*y_ratio); + px = std::floor((float)j*x_ratio); + py = std::floor((float)i*y_ratio); if (bInvert) pixel = (destHeight - i - 1)*destWidth * 3 + j * 3; // flip vertically else diff --git a/SPOUTSDK/SpoutGL/SpoutCopy.h b/SPOUTSDK/SpoutGL/SpoutCopy.h index 0228832e..1e3f3aa2 100644 --- a/SPOUTSDK/SpoutGL/SpoutCopy.h +++ b/SPOUTSDK/SpoutGL/SpoutCopy.h @@ -40,6 +40,7 @@ #include // for cpuid to test for SSE2 #include // for SSE2 #include // for SSSE3 +#include // For compatibility with Clang. PR#81 class SPOUT_DLLEXP spoutCopy { diff --git a/SPOUTSDK/SpoutGL/SpoutDirectX.cpp b/SPOUTSDK/SpoutGL/SpoutDirectX.cpp index 07e2dfd5..e8e4eb05 100644 --- a/SPOUTSDK/SpoutGL/SpoutDirectX.cpp +++ b/SPOUTSDK/SpoutGL/SpoutDirectX.cpp @@ -104,6 +104,8 @@ // 17.12.21 - Use passed texture pointer directly in CreateDX11Texture // 26.12.21 - Context flush after texture release in ReleaseDX11Texture // Clean up DebugLog function +// 25.01.22 - Correct log notice in ReleaseDX11Texture to show texture instead of device +// Move adapter pointer release from release device to destructor // // ==================================================================================== /* @@ -159,6 +161,12 @@ spoutDirectX::spoutDirectX() { spoutDirectX::~spoutDirectX() { + // Release adapter pointer if specified by SetAdapter + if (m_pAdapterDX11) { + m_pAdapterDX11->Release(); + m_pAdapterDX11 = nullptr; + } + } // Function: OpenDirectX11 @@ -170,10 +178,10 @@ bool spoutDirectX::OpenDirectX11(ID3D11Device* pDevice) // Can be set externally (See also - SetDX11device) if (m_pd3dDevice) { if (m_bClassDevice) { - SpoutLogNotice("spoutDirectX::OpenDirectX11(0x%.7X) - Class device initialized", PtrToUint(m_pd3dDevice)); + SpoutLogNotice("spoutDirectX::OpenDirectX11(0x%.7X) - Class device already initialized", PtrToUint(m_pd3dDevice)); } else { - SpoutLogNotice("spoutDirectX::OpenDirectX11(0x%.7X) - External device", PtrToUint(m_pd3dDevice)); + SpoutLogNotice("spoutDirectX::OpenDirectX11(0x%.7X) - External device used", PtrToUint(m_pd3dDevice)); } return true; } @@ -203,10 +211,6 @@ bool spoutDirectX::OpenDirectX11(ID3D11Device* pDevice) return false; } - // ?J DEBUG - SpoutLogNotice(" Device (0x%.7X) - Context (0x%.7X)", PtrToUint(m_pd3dDevice), PtrToUint(m_pImmediateContext)); - // SpoutLogNotice(" Device (0x%.7X)", PtrToUint(m_pd3dDevice)); - return true; } @@ -233,7 +237,7 @@ void spoutDirectX::CloseDirectX11() // An application device was used (SetDX11Device). Do not release it. SpoutLogNotice("spoutDirectX::CloseDirectX11 - external device used (0x%.7X)", PtrToUint(m_pd3dDevice)); // Release adapter pointer if specified by SetAdapter - // Normally done in ReleaseDX11Device + // Normally done in destructor if (m_pAdapterDX11) m_pAdapterDX11->Release(); m_pAdapterDX11 = nullptr; @@ -285,9 +289,12 @@ ID3D11Device* spoutDirectX::CreateDX11device() ID3D11Device* pd3dDevice = nullptr; HRESULT hr = S_OK; UINT createDeviceFlags = 0; + + // Adapter pointer null by default + // or specified by SetAdapter or SetAdapterPointer IDXGIAdapter* pAdapterDX11 = m_pAdapterDX11; - SpoutLogNotice("spoutDirectX::CreateDX11device - pAdapterDX11 (0x%.7X)", PtrToUint(m_pAdapterDX11) ); + SpoutLogNotice("spoutDirectX::CreateDX11device - pAdapter (0x%.7X)", PtrToUint(pAdapterDX11) ); // // If the project is in a debug build, enable debugging via SDK Layers with this flag. @@ -300,9 +307,11 @@ ID3D11Device* spoutDirectX::CreateDX11device() // See also : void spoutDirectX::DebugLog // +/* #if defined(_DEBUG) createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif +*/ // GL/DX interop Spec // ID3D11Device can only be used on WDDM operating systems : Must be multithreaded @@ -389,7 +398,7 @@ ID3D11Device* spoutDirectX::CreateDX11device() // All OK - return the device pointer to the caller // m_pImmediateContext has also been created - SpoutLogNotice(" device (0x%.7X)", PtrToUint(pd3dDevice) ); + SpoutLogNotice(" Device (0x%.7X) - Context (0x%.7X)", PtrToUint(pd3dDevice), PtrToUint(m_pImmediateContext)); return pd3dDevice; @@ -672,7 +681,6 @@ bool spoutDirectX::OpenDX11shareHandle(ID3D11Device* pDevice, ID3D11Texture2D** return false; } - // Can get sender format here // ID3D11Texture2D * texturePointer = *ppSharedTexture; // D3D11_TEXTURE2D_DESC td; @@ -730,14 +738,19 @@ bool spoutDirectX::SetAdapter(int index) SpoutLogNotice("spoutDirectX::SetAdapter(%d) [%s]", index, adaptername); // Get the adapter pointer for DX11 CreateDevice to use - if (m_pAdapterDX11) m_pAdapterDX11->Release(); + if (m_pAdapterDX11) { + m_pAdapterDX11->Release(); + m_pAdapterDX11 = nullptr; + } + pAdapter = GetAdapterPointer(index); if(!pAdapter) { SpoutLogError("spoutDirectX::SetAdapter - could not get pointer for adapter %d", index); return false; } - // Set the global adapter index (used for DX9 and to retrieve the index) + // Set the global adapter index + // (used for DX11 create device and to retrieve the index) m_AdapterIndex = index; // Set the adapter pointer for DX11 @@ -747,6 +760,7 @@ bool spoutDirectX::SetAdapter(int index) // For >= 2.007 only DX11 test is supported SpoutLogNotice(" creating test device"); + // printf(" testing adapter %d (0x%7.7X) [%s]", m_AdapterIndex, PtrToUint(m_pAdapterDX11), adaptername); // Try to create a DirectX 11 device for this adapter ID3D11Device* pd3dDevice = CreateDX11device(); @@ -757,13 +771,15 @@ bool spoutDirectX::SetAdapter(int index) m_pAdapterDX11 = nullptr; return false; } + // Close the device because this is just a test // See : https://github.com/leadedge/Spout2/issues/17 ReleaseDX11Device(pd3dDevice); pd3dDevice = nullptr; // Selected adapter OK - SpoutLogNotice(" successfully set adapter %d [%s]", m_AdapterIndex, adaptername); + SpoutLogNotice(" successfully set adapter %d (0x%7.7X) [%s]", + m_AdapterIndex, PtrToUint(m_pAdapterDX11), adaptername); return true; @@ -872,7 +888,7 @@ int spoutDirectX::GetNumAdapters() // Is there a first first output on this adapter ? if (adapter1_ptr->EnumOutputs(0, &p_output) == DXGI_ERROR_NOT_FOUND) { // Warning only - SpoutLogWarning("spoutDirectX::GetNumAdapters Adapter(%d) : No outputs", i); + SpoutLogWarning("spoutDirectX::GetNumAdapters - No outputs for Adapter %d : %S", i, desc.Description); } else { p_output->Release(); @@ -1037,7 +1053,7 @@ unsigned long spoutDirectX::ReleaseDX11Texture(ID3D11Device* pd3dDevice, ID3D11T return 0; } - SpoutLogNotice("spoutDirectX::ReleaseDX11Texture (0x%.7X)", PtrToUint(pd3dDevice) ); + SpoutLogNotice("spoutDirectX::ReleaseDX11Texture (0x%.7X)", PtrToUint(pTexture) ); unsigned long refcount = pTexture->Release(); pTexture = nullptr; @@ -1045,7 +1061,7 @@ unsigned long spoutDirectX::ReleaseDX11Texture(ID3D11Device* pd3dDevice, ID3D11T if (refcount > 1) { SpoutLogWarning("spoutDirectX::ReleaseDX11Texture - refcount = %lu", refcount); DebugLog(pd3dDevice, "spoutDirectX::ReleaseDX11Texture - refcount = %lu\n", refcount); - printf("spoutDirectX::ReleaseDX11Texture - refcount = %lu\n", refcount); + // printf("spoutDirectX::ReleaseDX11Texture - refcount = %lu\n", refcount); } // Calling Flush will destroy any objects whose destruction has been deferred. @@ -1064,12 +1080,6 @@ unsigned long spoutDirectX::ReleaseDX11Device(ID3D11Device* pd3dDevice) if (!pd3dDevice) return 0; - // Release adapter pointer if specified by SetAdapter - if (m_pAdapterDX11) { - m_pAdapterDX11->Release(); - m_pAdapterDX11 = nullptr; - } - // Release the global context or there is an outstanding ref count // when the device is released if (m_pImmediateContext) { @@ -1156,14 +1166,13 @@ void spoutDirectX::DebugLog(ID3D11Device* pd3dDevice, const char* format, ...) if (!pd3dDevice) return; - // // Output for debug build // Manually remove the comment block below if you have D3D11_1SDKLayers.dll installed. // See comments in : ID3D11Device* spoutDirectX::CreateDX11device() // - // Construct the log here to avoid UNREFERENCED_PARAMETER warning + // Construct the log here in any case to avoid UNREFERENCED_PARAMETER warning char dlog[128]; va_list args; va_start(args, format); diff --git a/SPOUTSDK/SpoutGL/SpoutFrameCount.cpp b/SPOUTSDK/SpoutGL/SpoutFrameCount.cpp index 12fa7b68..7c4d1b29 100644 --- a/SPOUTSDK/SpoutGL/SpoutFrameCount.cpp +++ b/SPOUTSDK/SpoutGL/SpoutFrameCount.cpp @@ -48,6 +48,8 @@ // Use monitor refresh rate if no argument is specified. // 13.11.21 - Revise UpdateSenderFps // Zero frame counter variables on reset and init +// 25.01.22 - Clean up logs in CreateAccessMutex and EnableFrameCount +// 21.02.22 - Change "_uuidof" to "__uuidof" in CheckKeyedAccess. PR#81 // // ==================================================================================== // @@ -242,25 +244,21 @@ void spoutFrameCount::EnableFrameCount(const char* SenderName) #endif // Return if already enabled for this sender - if (m_hCountSemaphore && strcmp(SenderName, m_SenderName) == 0) { - SpoutLogNotice("SpoutFrameCount::EnableFrameCount already enabled [%s]", SenderName); + // The sender name can be the same if the adapter has changed + if (m_hCountSemaphore) { + SpoutLogNotice("SpoutFrameCount::EnableFrameCount (%s) frame count semaphore already enabled [0x%.7X] ", SenderName, m_hCountSemaphore); return; } - SpoutLogNotice("SpoutFrameCount::EnableFrameCount : sender name [%s]", SenderName); - - // Close any existing semaphore - if (m_hCountSemaphore) { - CloseHandle(m_hCountSemaphore); - m_hCountSemaphore = NULL; - m_CountSemaphoreName[0] = 0; - } + // Frame count semaphore (m_hCountSemaphore) has not been created yet // Set the new name for subsequent checks strcpy_s(m_SenderName, 256, SenderName); - // Create or open a semaphore with this sender name + // Create a name for the frame count semaphore using the sender name sprintf_s(m_CountSemaphoreName, 256, "%s_Count_Semaphore", SenderName); + + // Create or open a named frame count semaphore with this name HANDLE hSemaphore = CreateSemaphoreA( NULL, // default security attributes 1, // initial count @@ -273,18 +271,23 @@ void spoutFrameCount::EnableFrameCount(const char* SenderName) return; } if (dwError == ERROR_ALREADY_EXISTS) { - SpoutLogNotice(" Semaphore already exists"); - // OK if it already exists - the sender or receiver can create it + SpoutLogNotice("SpoutFrameCount::EnableFrameCount - frame count semaphore [%s] exists", m_CountSemaphoreName); + SpoutLogNotice(" Handle for access [0x%7.7X]", LOWORD(hSemaphore)); + // OK if it already exists - either the sender or receiver can create it } + else { + SpoutLogNotice("SpoutFrameCount::EnableFrameCount - frame count semaphore [%s] created", m_CountSemaphoreName); + SpoutLogNotice(" Handle [0x%7.7X]", LOWORD(hSemaphore)); + } + if (hSemaphore == NULL) { SpoutLogError(" Unknown error"); return; } + // Save the handle for access m_hCountSemaphore = hSemaphore; - SpoutLogNotice(" Semaphore handle [0x%.7X]", LOWORD(m_hCountSemaphore) ); - } // ----------------------------------------------- @@ -621,13 +624,16 @@ bool spoutFrameCount::CreateAccessMutex(const char *SenderName) } // Here we can find if the mutex already exists else if (errnum == ERROR_ALREADY_EXISTS) { - SpoutLogNotice("spoutFrameCount::CreateAccessMutex - [%s] already exists", szMutexName); + SpoutLogNotice("spoutFrameCount::CreateAccessMutex - texture access mutex [%s] exists", szMutexName); + SpoutLogNotice(" Handle for access [0x%.7X]", hMutex); } else { - SpoutLogNotice("spoutFrameCount::CreateAccessMutex - [%s] created - 0x%.7X", szMutexName, PtrToUint(hMutex) ); + SpoutLogNotice("spoutFrameCount::CreateAccessMutex - texture access mutex [%s] created ", szMutexName); + SpoutLogNotice(" Handle [0x%.7X]", hMutex); } } + // Save the handle for access m_hAccessMutex = hMutex; return true; @@ -813,7 +819,7 @@ bool spoutFrameCount::CheckKeyedAccess(ID3D11Texture2D* pTexture) IDXGIKeyedMutex* pDXGIKeyedMutex = nullptr; // Check the keyed mutex - pTexture->QueryInterface(_uuidof(IDXGIKeyedMutex), (void**)&pDXGIKeyedMutex); + pTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&pDXGIKeyedMutex); // PR#81 if (pDXGIKeyedMutex) { HRESULT hr = pDXGIKeyedMutex->AcquireSync(0, 67); // TODO - link with SPOUT_WAIT_TIMEOUT switch (hr) { diff --git a/SPOUTSDK/SpoutGL/SpoutGL.cpp b/SPOUTSDK/SpoutGL/SpoutGL.cpp index 20816050..a59860f5 100644 --- a/SPOUTSDK/SpoutGL/SpoutGL.cpp +++ b/SPOUTSDK/SpoutGL/SpoutGL.cpp @@ -73,13 +73,20 @@ // 15.12.21 - Change no context log warning to notice in CleanupGL and CleanupDX11 // LoadGLextensions - warn if pbo extensions not available or user disable // CleanupGL() - release staging textures +// 16.12.21 - Add "No error: case comment to LinkGLDXtextures +// Remove un-necessary wglDXSetResourceShareHandle from LinkGLDXtextures // 17.12.21 - Device argument only for OpenDirectx11 // Remove wglDXSetResourceShareHandleNV from LinkGLDXtextures // Remove dxShareHandle argument from LinkGLDXtextures // 18.12.21 - Restore default draw for all fbo functions // Release interop objects after LinkGLDXtextures in GLDXready -// Create registry entry for GLDXready function to avoid repeats +// Create m_bGLDXdone flag for GLDXready to avoid repeats // 27.12.21 - Restore default fbo in SetSharedTextureData if texture ID is zero +// 23.01.22 - Change pointer comparision from >0 to nullptr in OpenSpout (PR #80) +// 25.01.22 - Remove m_hInteropDevice created check in OpenSpout +// Clean up logs in LoadGLextensions +// 21.02.22 - Restore glBufferData method for in UnloadTexturePixels +// Pending implementation of glFencSync for glMapBufferRange method // // ==================================================================================== /* @@ -131,11 +138,12 @@ spoutGL::spoutGL() m_bConnected = false; m_bInitialized = false; - m_bSpoutPanelOpened = false;; - m_bSpoutPanelActive = false;; + m_bSpoutPanelOpened = false; + m_bSpoutPanelActive = false; m_bUpdated = false; m_bMirror = false; m_bSwapRB = false; + m_bGLDXdone = false; // Compatibility test not done yet m_glTexture = 0; m_TexID = 0; @@ -415,9 +423,8 @@ bool spoutGL::OpenSpout(bool bRetest) { // Return if already initialized and not re-testing compatibility // Look for DirectX device to prevent repeat - if(spoutdx.GetDX11Device() > 0 - && m_hInteropDevice > 0 - && !bRetest) + // m_hInteropDevice is created in CreateInterop + if (spoutdx.GetDX11Device() != nullptr && !bRetest) return true; // This is the start, so make a new line in the log @@ -452,6 +459,7 @@ bool spoutGL::OpenSpout(bool bRetest) CleanupInterop(); } SpoutLogNotice("spoutGL::OpenSpout - GL extensions loaded sucessfully"); + // Drop through for detail notices } else { SpoutLogFatal("spoutGL::OpenSpout - Could not load GL extensions"); @@ -481,11 +489,11 @@ bool spoutGL::OpenSpout(bool bRetest) // if (GLDXready()) { - // GL/DX compatible. - SpoutLogNotice("spoutGL::OpenSpout - GL/DX interop compatible"); + // GL/DX compatible - m_bUseGLDX is set true + SpoutLogNotice(" GL/DX interop compatible"); } else { - // Not GL/DX compatible. + // Not GL/DX compatible - m_bUseGLDX is set false SpoutLogWarning("spoutGL::OpenSpout - system is not compatible with GL/DX interop"); } @@ -505,7 +513,7 @@ bool spoutGL::OpenSpout(bool bRetest) m_bTextureShare = false; // Do not use texture share m_bCPUshare = true; // Use CPU share } - + // Show the sharing method to be used if (m_bTextureShare) { SpoutLogNotice(" Using GPU OpenGL GL/DX methods"); @@ -738,12 +746,9 @@ bool spoutGL::GLDXready() // m_bCPUshare = true; // return false; - // Check whether the test has already been done - DWORD dwMode = 0; - if (ReadDwordFromRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\Spout", "GLDXready", &dwMode)) { - // Use the registry setting - m_bUseGLDX = (dwMode == 1); - // Use of texture sharing or CPU backup is assessed in OpenSpout (see below) + // Return if the test has already been done + if (m_bGLDXdone) { + SpoutLogNotice("spoutGL::GLDXready - test previously completed"); return m_bUseGLDX; } @@ -852,8 +857,8 @@ bool spoutGL::GLDXready() // If not GLDX compatible, LinkGLDXtexture will not be called (see CreateDX11interop) // ReadDX11Texture and WriteDX11Texture will be used instead via CPU staging textures - // Write the result to the registry so it isn't tested again - WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\Spout", "GLDXready", (DWORD)m_bUseGLDX); + // Set a class flag so the test is not repeated + m_bGLDXdone = true; return m_bUseGLDX; @@ -951,7 +956,6 @@ bool spoutGL::CreateInterop(unsigned int width, unsigned int height, DWORD dwFor return false; } } - SpoutLogNotice("spoutGL::CreateInterop - m_pSharedTexture = 0x%.7X : m_dxShareHandle = 0x%.7X", PtrToUint(m_pSharedTexture), LOWORD(m_dxShareHandle)); // // Link the shared DirectX texture to the OpenGL texture @@ -981,6 +985,7 @@ bool spoutGL::CreateInterop(unsigned int width, unsigned int height, DWORD dwFor return false; } + SpoutLogNotice("spoutGL::CreateInterop - m_pSharedTexture [0x%.7X] m_dxShareHandle [0x%.7X]", PtrToUint(m_pSharedTexture), LOWORD(m_dxShareHandle)); SpoutLogNotice(" m_hInteropObject = 0x%.7X", LOWORD(m_hInteropObject)); // Create an fbo if not already @@ -1043,6 +1048,9 @@ HANDLE spoutGL::LinkGLDXtextures(void* pDXdevice, void* pSharedTexture, GLuint // Other errors reported // 1008, 0x3F0 - ERROR_NO_TOKEN switch (LOWORD(dwError)) { + case 0: + strcat_s(tmp, 128, " No error"); + break; case ERROR_OPEN_FAILED: strcat_s(tmp, 128, " Could not open the Direct3D device."); break; @@ -1087,6 +1095,9 @@ HANDLE spoutGL::LinkGLDXtextures(void* pDXdevice, void* pSharedTexture, GLuint sprintf_s(tmp, 128, "spoutGL::LinkGLDXtextures - wglDXRegisterObjectNV :error %u, (0x%.X)\n", LOWORD(dwError), LOWORD(dwError)); switch (LOWORD(dwError)) { + case 0: + strcat_s(tmp, 128, " No error"); + break; case ERROR_INVALID_HANDLE: strcat_s(tmp, 128, " No GL context is current."); break; @@ -1681,6 +1692,113 @@ bool spoutGL::UnloadTexturePixels(GLuint TextureID, GLuint TextureTarget, glGenFramebuffersEXT(1, &m_fbo); } + // Create pbos if not already + if (m_pbo[0] == 0) { + SpoutLogNotice("spoutGL::UnloadTexturePixels - creating PBO"); + glGenBuffersEXT(m_nBuffers, m_pbo); + PboIndex = 0; + NextPboIndex = 0; + } + + PboIndex = (PboIndex + 1) % m_nBuffers; + NextPboIndex = (PboIndex + 1) % m_nBuffers; + + // If Texture ID is zero, the texture is already attached to the Host Fbo + // and we do nothing. If not we need to create an fbo and attach the user texture + if (TextureID > 0) { + // Attach the texture to point 0 + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, TextureTarget, TextureID, 0); + // Set the target framebuffer to read + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + else if (HostFBO == 0) { + // If no texture ID, a Host FBO must be provided + // testing only - error log will repeat + return false; + } + + // Bind the PBO + glBindBufferEXT(GL_PIXEL_PACK_BUFFER, m_pbo[PboIndex]); + + // Check it's size + GLint size = 0; + glGetBufferParameterivEXT(GL_PIXEL_PACK_BUFFER, GL_BUFFER_SIZE_EXT, &size); + if (size > 0 && size != (int)(pitch * height)) { + // All PBOs must be re-created + glBindBufferEXT(GL_PIXEL_PACK_BUFFER, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, HostFBO); + glDeleteBuffersEXT(m_nBuffers, m_pbo); + m_pbo[0] = m_pbo[1] = m_pbo[2] = m_pbo[3] = 0; + return false; + } + + // Null existing PBO data to avoid a stall + // This allocates memory for the PBO pitch*height wide + glBufferDataEXT(GL_PIXEL_PACK_BUFFER, pitch*height, 0, GL_STREAM_READ); + + // Read pixels from framebuffer to PBO - glReadPixels() should return immediately. + glPixelStorei(GL_PACK_ROW_LENGTH, pitch / channels); // row length in pixels + glReadPixels(0, 0, width, height, glFormat, GL_UNSIGNED_BYTE, (GLvoid *)0); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + + // If there is data in the next pbo from the previous call, read it back + glBindBufferEXT(GL_PIXEL_PACK_BUFFER, m_pbo[NextPboIndex]); + + // Map the PBO to process its data by CPU + pboMemory = glMapBufferEXT(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + + // glMapBuffer can return NULL when called the first time + // when the next pbo has not been filled with data yet + glGetError(); // remove the last error + + if (pboMemory && data) { + // Update data directly from the mapped buffer (TODO: RGB) + spoutcopy.CopyPixels((const unsigned char*)pboMemory, (unsigned char*)data, pitch / channels, height, glFormat, bInvert); + glUnmapBufferEXT(GL_PIXEL_PACK_BUFFER); + } + // skip the copy rather than return false. + + // Back to conventional pixel operation + glBindBufferEXT(GL_PIXEL_PACK_BUFFER, 0); + + // Restore the previous fbo binding + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, HostFBO); + + return true; + +} + +/* +// +// glMapBufferRange method +// Requires work using glFenceSync to avoid stall +// +bool spoutGL::UnloadTexturePixels(GLuint TextureID, GLuint TextureTarget, + unsigned int width, unsigned int height, unsigned int rowpitch, + unsigned char* data, GLenum glFormat, + bool bInvert, GLuint HostFBO) +{ + void *pboMemory = nullptr; + int channels = 4; // RGBA or RGB + + if (!data) { + return false; + } + + if (glFormat == GL_RGB || glFormat == GL_BGR_EXT) { + channels = 3; + } + + unsigned int pitch = rowpitch; // row pitch passed in + if (rowpitch == 0) + pitch = width * channels; // RGB or RGBA + + if (m_fbo == 0) { + SpoutLogNotice("spoutGL::UnloadTexturePixels - creating FBO"); + glGenFramebuffersEXT(1, &m_fbo); + } + // Create pbos if not already if (m_pbo[0] == 0) { SpoutLogNotice("spoutGL::UnloadTexturePixels - creating %d PBOs", m_nBuffers); @@ -1767,6 +1885,7 @@ bool spoutGL::UnloadTexturePixels(GLuint TextureID, GLuint TextureTarget, return true; } +*/ // @@ -2789,8 +2908,6 @@ bool spoutGL::LoadGLextensions() return false; } - SpoutLogNotice("spoutGL::LoadGLextensions"); - m_bFBOavailable = false; m_bGLDXavailable = false; m_bBLITavailable = false; @@ -2823,34 +2940,41 @@ bool spoutGL::LoadGLextensions() if (m_caps & GLEXT_SUPPORT_BGRA) m_bBGRAavailable = true; if (m_caps & GLEXT_SUPPORT_COPY) m_bCOPYavailable = true; if (m_caps & GLEXT_SUPPORT_CONTEXT) m_bCONTEXTavailable = true; + // Test PBO availability unless user has selected buffering off // m_bPBOavailable also set by SetBufferMode() if (m_bPBOavailable) { if (!(m_caps && GLEXT_SUPPORT_PBO)) m_bPBOavailable = false; } - if (!m_bGLDXavailable) - SpoutLogWarning("spoutGL::LoadGLextensions - interop extensions not available"); - if (!m_bBLITavailable) - SpoutLogWarning("spoutGL::LoadGLextensions - fbo blit extension not available"); - if (!m_bSWAPavailable) - SpoutLogWarning("spoutGL::LoadGLextensions - sync control extensions not available"); - if (!m_bBGRAavailable) - SpoutLogWarning("spoutGL::LoadGLextensions - bgra extension not available"); - if (!m_bCOPYavailable) - SpoutLogWarning("spoutGL::LoadGLextensions - copy extensions not available"); + + // Show status if (!m_bPBOavailable) { if (!(m_caps && GLEXT_SUPPORT_PBO)) SpoutLogWarning("spoutGL::LoadGLextensions - pbo extensions not available"); else - SpoutLogWarning("spoutGL::LoadGLextensions - pbo functions disabled"); + SpoutLogWarning("spoutGL::LoadGLextensions - pbo functions disabled by settings"); } - if (!m_bCONTEXTavailable) + else if (!m_bGLDXavailable) + SpoutLogWarning("spoutGL::LoadGLextensions - interop extensions not available"); + else if (!m_bBLITavailable) + SpoutLogWarning("spoutGL::LoadGLextensions - fbo blit extension not available"); + else if (!m_bSWAPavailable) + SpoutLogWarning("spoutGL::LoadGLextensions - sync control extensions not available"); + else if (!m_bBGRAavailable) + SpoutLogWarning("spoutGL::LoadGLextensions - bgra extension not available"); + else if (!m_bCOPYavailable) + SpoutLogWarning("spoutGL::LoadGLextensions - copy extensions not available"); + else if (!m_bCONTEXTavailable) SpoutLogWarning("spoutGL::LoadGLextensions - context extension not available"); + else + SpoutLogNotice("spoutGL::LoadGLextensions - all extensions available"); + m_bExtensionsLoaded = true; return true; } + //--------------------------------------------------------- bool spoutGL::IsGLDXavailable() { diff --git a/SPOUTSDK/SpoutGL/SpoutGL.h b/SPOUTSDK/SpoutGL/SpoutGL.h index 9295aaaf..af173320 100644 --- a/SPOUTSDK/SpoutGL/SpoutGL.h +++ b/SPOUTSDK/SpoutGL/SpoutGL.h @@ -46,10 +46,6 @@ #include // for PROCESSENTRY32 #include // for _tcsicmp -// LJ DEBUG -#include -#include - using namespace spoututils; class SPOUT_DLLEXP spoutGL { @@ -102,7 +98,7 @@ class SPOUT_DLLEXP spoutGL { int GetMaxSenders(); // Set user Maximum senders allowed void SetMaxSenders(int maxSenders); - + // // 2.006 compatibility // @@ -373,6 +369,7 @@ protected : bool m_bInitialized; bool m_bMirror; // Mirror image (used for SpoutCam) bool m_bSwapRB; // RGB <> BGR (used for SpoutCam) + bool m_bGLDXdone; // Compatibility test done // Sharing modes bool m_bAuto; // Auto share mode - user set diff --git a/SPOUTSDK/SpoutGL/SpoutSenderNames.cpp b/SPOUTSDK/SpoutGL/SpoutSenderNames.cpp index 8b2b4ab1..15022801 100644 --- a/SPOUTSDK/SpoutGL/SpoutSenderNames.cpp +++ b/SPOUTSDK/SpoutGL/SpoutSenderNames.cpp @@ -471,7 +471,6 @@ void spoutSenderNames::SetMaxSenders(int maxSenders) m_MaxSenders = maxSenders; // Set to the registry so that other applications will read the new maximum size WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\Spout", "MaxSenders", (DWORD)maxSenders); - } int spoutSenderNames::GetMaxSenders() diff --git a/SPOUTSDK/SpoutGL/SpoutUtils.cpp b/SPOUTSDK/SpoutGL/SpoutUtils.cpp index 786cfb19..ae2822fe 100644 --- a/SPOUTSDK/SpoutGL/SpoutUtils.cpp +++ b/SPOUTSDK/SpoutGL/SpoutUtils.cpp @@ -81,6 +81,7 @@ Use .clear() instead of "" to clear strings 20.12.21 - Change from string to to char array for last log Update Version to "2.007.006" + 29.01.21 - Change return logic of RemovePathFromRegistry */ #include "SpoutUtils.h" @@ -514,9 +515,11 @@ namespace spoututils { // Read the key Filepath value regres = RegQueryValueExA(hRegKey, valuename, NULL, &dwKey, (BYTE*)filepath, &dwSize); RegCloseKey(hRegKey); - if (regres == ERROR_SUCCESS) + if (regres == ERROR_SUCCESS) { return true; + } } + // Quit if the key does not exist return false; } @@ -595,8 +598,8 @@ namespace spoututils { bool RemovePathFromRegistry(HKEY hKey, const char *subkey, const char *valuename) { - HKEY hRegKey = NULL; - LONG regres = 0; + HKEY hRegKey = NULL; + LONG regres = 0; // 01.01.18 if (!subkey[0]) { @@ -608,9 +611,11 @@ namespace spoututils { if (regres == ERROR_SUCCESS) { regres = RegDeleteValueA(hRegKey, valuename); RegCloseKey(hRegKey); - return true; } + if (regres == ERROR_SUCCESS) + return true; + // Quit if the key does not exist SpoutLogWarning("RemovePathFromRegistry - could not open key [%s]", subkey); return false;