diff --git a/core/rend/dx11/dx11_renderer.cpp b/core/rend/dx11/dx11_renderer.cpp index 450ce65a8e..2c44a437f8 100644 --- a/core/rend/dx11/dx11_renderer.cpp +++ b/core/rend/dx11/dx11_renderer.cpp @@ -1412,6 +1412,11 @@ void DX11Renderer::renderVideoRouting() backBufferTexture->Release(); pResource->Release(); } + else + { + extern void os_VideoRoutingTermDX(); + os_VideoRoutingTermDX(); + } #endif } diff --git a/core/rend/dx11/dx11context.cpp b/core/rend/dx11/dx11context.cpp index 670c4fd897..53440c6861 100644 --- a/core/rend/dx11/dx11context.cpp +++ b/core/rend/dx11/dx11context.cpp @@ -178,8 +178,6 @@ bool DX11Context::init(bool keepCurrentWindow) NOTICE_LOG(RENDERER, "No system-provided shader cache"); } - initVideoRouting(); - imguiDriver = std::unique_ptr(new DX11Driver(pDevice, pDeviceContext)); resize(); shaders.init(pDevice, &D3DCompile); @@ -190,19 +188,6 @@ bool DX11Context::init(bool keepCurrentWindow) return success; } -void DX11Context::initVideoRouting() -{ - #ifdef VIDEO_ROUTING - extern void os_VideoRoutingTermDX(); - extern void os_VideoRoutingInitSpoutDXWithDevice(ID3D11Device* pDevice); - os_VideoRoutingTermDX(); - if (config::VideoRouting) - { - os_VideoRoutingInitSpoutDXWithDevice(pDevice.get()); - } - #endif -} - void DX11Context::term() { NOTICE_LOG(RENDERER, "DX11 Context terminating"); diff --git a/core/rend/dx11/dx11context.h b/core/rend/dx11/dx11context.h index cdb409c4fa..8e8d909c06 100644 --- a/core/rend/dx11/dx11context.h +++ b/core/rend/dx11/dx11context.h @@ -33,7 +33,6 @@ class DX11Context : public GraphicsContext { public: bool init(bool keepCurrentWindow = false); - void initVideoRouting() override; void term() override; void EndImGuiFrame(); void Present(); diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index b6ce618c56..cefa9fd81c 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1472,6 +1472,11 @@ void OpenGLRenderer::renderVideoRouting() extern void os_VideoRoutingPublishFrameTexture(GLuint texID, GLuint texTarget, float w, float h); os_VideoRoutingPublishFrameTexture(gl.videorouting.framebuffer->getTexture(), GL_TEXTURE_2D, targetWidth, targetHeight); } + else + { + extern void os_VideoRoutingTermGL(); + os_VideoRoutingTermGL(); + } #endif } diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 6cda99fff9..4b615f8c66 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -2241,24 +2241,19 @@ static void gui_display_settings() ((renderApi == 0) || (renderApi == 3)) ? header("Video Routing (Spout)") : header("Video Routing (Only available with OpenGL or DirectX 11)"); #endif { -#ifdef __APPLE__ - if (OptionCheckbox("Send video content to another application", config::VideoRouting, - "e.g. Route GPU texture to OBS Studio directly instead of using CPU intensive Display/Window Capture")) -#elif defined(_WIN32) - DisabledScope scope( !( (renderApi == 0) || (renderApi == 3)) ); - if (OptionCheckbox("Send video content to another program", config::VideoRouting, - "e.g. Route GPU texture to OBS Studio directly instead of using CPU intensive Display/Window Capture")) +#ifdef _WIN32 + DisabledScope scope(!((renderApi == 0) || (renderApi == 3))); #endif - { - GraphicsContext::Instance()->initVideoRouting(); - } + OptionCheckbox("Send video content to another program", config::VideoRouting, + "e.g. Route GPU texture to OBS Studio directly instead of using CPU intensive Display/Window Capture"); + { DisabledScope scope(!config::VideoRouting); OptionCheckbox("Scale down before sending", config::VideoRoutingScale, "Could increase performance when sharing a smaller texture, YMMV"); { DisabledScope scope(!config::VideoRoutingScale); static int vres = config::VideoRoutingVRes; - if( ImGui::InputInt("Output vertical resolution", &vres) ) + if (ImGui::InputInt("Output vertical resolution", &vres)) { config::VideoRoutingVRes = vres; } diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index a7596f2dbf..af0f47edd3 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -487,8 +487,6 @@ bool VulkanContext::InitDevice() + std::to_string(props.driverVersion / 10000) + "." + std::to_string((props.driverVersion % 10000) / 100) + "." + std::to_string(props.driverVersion % 100); - - initVideoRouting(); #else driverVersion = std::to_string(VK_API_VERSION_MAJOR(props.driverVersion)) + "." + std::to_string(VK_API_VERSION_MINOR(props.driverVersion)) + "." @@ -513,19 +511,6 @@ bool VulkanContext::InitDevice() return false; } -void VulkanContext::initVideoRouting() -{ -#if defined(VIDEO_ROUTING) && defined(TARGET_MAC) - extern void os_VideoRoutingTermVk(); - extern void os_VideoRoutingInitSyphonWithVkDevice(const vk::UniqueDevice& device); - os_VideoRoutingTermVk(); - if (config::VideoRouting) - { - os_VideoRoutingInitSyphonWithVkDevice(device); - } -#endif -} - void VulkanContext::CreateSwapChain() { try diff --git a/core/rend/vulkan/vulkan_context.h b/core/rend/vulkan/vulkan_context.h index 2b10af48e0..868fdb9357 100644 --- a/core/rend/vulkan/vulkan_context.h +++ b/core/rend/vulkan/vulkan_context.h @@ -60,7 +60,6 @@ class VulkanContext : public GraphicsContext, public FlightManager void Present() noexcept; void PresentFrame(vk::Image image, vk::ImageView imageView, const vk::Extent2D& extent, float aspectRatio) noexcept; void PresentLastFrame(); - void initVideoRouting() override; vk::PhysicalDevice GetPhysicalDevice() const { return physicalDevice; } vk::Device GetDevice() const { return *device; } diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index 771d732232..9924374c0e 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -515,21 +515,16 @@ void os_RunInstance(int argc, const char *argv[]) static SpoutSender* spoutSender; static spoutDX* spoutDXSender; -void os_VideoRoutingInitSpout() +void os_VideoRoutingPublishFrameTexture(GLuint texID, GLuint texTarget, float w, float h) { if (spoutSender == nullptr) { spoutSender = new SpoutSender(); - } - - int boardID = cfgLoadInt("naomi", "BoardId", 0); - char buf[32] = {0}; - vsnprintf(buf, sizeof(buf), (boardID == 0 ? "Flycast - Video Content" : "Flycast - Video Content - %d"), std::va_list(&boardID)); - spoutSender->SetSenderName(buf); -} - -void os_VideoRoutingPublishFrameTexture(GLuint texID, GLuint texTarget, float w, float h) -{ + int boardID = cfgLoadInt("naomi", "BoardId", 0); + char buf[32] = { 0 }; + vsnprintf(buf, sizeof(buf), (boardID == 0 ? "Flycast - Video Content" : "Flycast - Video Content - %d"), std::va_list(&boardID)); + spoutSender->SetSenderName(buf); + } spoutSender->SendTexture(texID, texTarget, w, h, true); } @@ -542,21 +537,30 @@ void os_VideoRoutingTermGL() } } -void os_VideoRoutingInitSpoutDXWithDevice(ID3D11Device* pDevice) +void os_VideoRoutingPublishFrameTexture(ID3D11Texture2D* pTexture) { if (spoutDXSender == nullptr) { spoutDXSender = new spoutDX(); + ID3D11Resource* resource = nullptr; + HRESULT hr = pTexture->QueryInterface(__uuidof(ID3D11Resource), reinterpret_cast(&resource)); + if (SUCCEEDED(hr)) + { + ID3D11Device* pDevice = nullptr; + resource->GetDevice(&pDevice); + resource->Release(); + spoutDXSender->OpenDirectX11(pDevice); + pDevice->Release(); + int boardID = cfgLoadInt("naomi", "BoardId", 0); + char buf[32] = { 0 }; + vsnprintf(buf, sizeof(buf), (boardID == 0 ? "Flycast - Video Content" : "Flycast - Video Content - %d"), std::va_list(&boardID)); + spoutDXSender->SetSenderName(buf); + } + else + { + return; + } } - spoutDXSender->OpenDirectX11(pDevice); - int boardID = cfgLoadInt("naomi", "BoardId", 0); - char buf[32] = {0}; - vsnprintf(buf, sizeof(buf), (boardID == 0 ? "Flycast - Video Content" : "Flycast - Video Content - %d"), std::va_list(&boardID)); - spoutDXSender->SetSenderName(buf); -} - -void os_VideoRoutingPublishFrameTexture(ID3D11Texture2D* pTexture) -{ spoutDXSender->SendTexture(pTexture); } diff --git a/core/wsi/context.h b/core/wsi/context.h index ce29795c32..ec1891f0f1 100644 --- a/core/wsi/context.h +++ b/core/wsi/context.h @@ -34,7 +34,6 @@ class GraphicsContext virtual std::string getDriverName() = 0; virtual std::string getDriverVersion() = 0; virtual bool hasPerPixel() { return false; } - virtual void initVideoRouting() {} void setWindow(void *window, void *display = nullptr) { this->window = window; diff --git a/core/wsi/sdl.cpp b/core/wsi/sdl.cpp index 0eefd0df3d..cbcb9390cc 100644 --- a/core/wsi/sdl.cpp +++ b/core/wsi/sdl.cpp @@ -108,29 +108,10 @@ bool SDLGLGraphicsContext::init() } #endif postInit(); - initVideoRouting(); return true; } -void SDLGLGraphicsContext::initVideoRouting() -{ -#ifdef VIDEO_ROUTING - extern void os_VideoRoutingTermGL(); - os_VideoRoutingTermGL(); - if (config::VideoRouting) - { -#ifdef TARGET_MAC - extern void os_VideoRoutingInitSyphonWithGLContext(void* glContext); - os_VideoRoutingInitSyphonWithGLContext(glcontext); -#elif defined(_WIN32) - extern void os_VideoRoutingInitSpout(); - os_VideoRoutingInitSpout(); -#endif - } -#endif -} - void SDLGLGraphicsContext::swap() { do_swap_automation(); diff --git a/core/wsi/sdl.h b/core/wsi/sdl.h index 2d36f2e891..883b2e5b7f 100644 --- a/core/wsi/sdl.h +++ b/core/wsi/sdl.h @@ -29,7 +29,6 @@ class SDLGLGraphicsContext : public GLGraphicsContext bool init(); void term() override; void swap(); - void initVideoRouting() override; private: SDL_GLContext glcontext = nullptr; diff --git a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm index 4ea0bae2e1..6b3e34ab31 100644 --- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm +++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm @@ -236,14 +236,13 @@ void os_RunInstance(int argc, const char *argv[]) static SyphonOpenGLServer* syphonGLServer; static SyphonMetalServer* syphonMtlServer; -void os_VideoRoutingInitSyphonWithGLContext(void* glContext) -{ - int boardID = cfgLoadInt("naomi", "BoardId", 0); - syphonGLServer = [[SyphonOpenGLServer alloc] initWithName:[NSString stringWithFormat:(boardID == 0 ? @"Video Content" : @"Video Content - %d"), boardID] context:[(__bridge NSOpenGLContext*)glContext CGLContextObj] options:nil]; -} - void os_VideoRoutingPublishFrameTexture(GLuint texID, GLuint texTarget, float w, float h) { + if (syphonGLServer == NULL) + { + int boardID = cfgLoadInt("naomi", "BoardId", 0); + syphonGLServer = [[SyphonOpenGLServer alloc] initWithName:[NSString stringWithFormat:(boardID == 0 ? @"Video Content" : @"Video Content - %d"), boardID] context:[SDL_GL_GetCurrentContext() CGLContextObj] options:nil]; + } CGLLockContext([syphonGLServer context]); [syphonGLServer publishFrameTexture:texID textureTarget:texTarget imageRegion:NSMakeRect(0, 0, w, h) textureDimensions:NSMakeSize(w, h) flipped:NO]; CGLUnlockContext([syphonGLServer context]); @@ -256,18 +255,18 @@ void os_VideoRoutingTermGL() syphonGLServer = NULL; } -void os_VideoRoutingInitSyphonWithVkDevice(const vk::UniqueDevice& device) -{ - vk::ExportMetalDeviceInfoEXT deviceInfo; - auto objectsInfo = vk::ExportMetalObjectsInfoEXT(&deviceInfo); - device->exportMetalObjectsEXT(&objectsInfo); - - int boardID = cfgLoadInt("naomi", "BoardId", 0); - syphonMtlServer = [[SyphonMetalServer alloc] initWithName:[NSString stringWithFormat:(boardID == 0 ? @"Video Content" : @"Video Content - %d"), boardID] device:deviceInfo.mtlDevice options:nil]; -} - void os_VideoRoutingPublishFrameTexture(const vk::Device& device, const vk::Image& image, const vk::Queue& queue, float x, float y, float w, float h) { + if (syphonMtlServer == NULL) + { + vk::ExportMetalDeviceInfoEXT deviceInfo; + auto objectsInfo = vk::ExportMetalObjectsInfoEXT(&deviceInfo); + device.exportMetalObjectsEXT(&objectsInfo); + + int boardID = cfgLoadInt("naomi", "BoardId", 0); + syphonMtlServer = [[SyphonMetalServer alloc] initWithName:[NSString stringWithFormat:(boardID == 0 ? @"Video Content" : @"Video Content - %d"), boardID] device:deviceInfo.mtlDevice options:nil]; + } + auto textureInfo = vk::ExportMetalTextureInfoEXT(image); auto commandInfo = vk::ExportMetalCommandQueueInfoEXT(queue); commandInfo.pNext = &textureInfo;