void SetupD3D11(IDXGISwapChain *swapChain) { ClearD3D11Data(); DXGI_SWAP_CHAIN_DESC scd; if(SUCCEEDED(swapChain->GetDesc(&scd))) { d3d11CaptureInfo.format = ConvertGIBackBufferFormat(scd.BufferDesc.Format); if(d3d11CaptureInfo.format != GS_UNKNOWNFORMAT) { if( dxgiFormat != scd.BufferDesc.Format || d3d11CaptureInfo.cx != scd.BufferDesc.Width || d3d11CaptureInfo.cy != scd.BufferDesc.Height ) { dxgiFormat = scd.BufferDesc.Format; d3d11CaptureInfo.cx = scd.BufferDesc.Width; d3d11CaptureInfo.cy = scd.BufferDesc.Height; d3d11CaptureInfo.hwndCapture = scd.OutputWindow; bIsMultisampled = scd.SampleDesc.Count > 1; } } } lastTime = 0; OSInitializeTimer(); }
void SetupD3D101(IDXGISwapChain *swapChain) { logOutput << CurrentTimeString() << "setting up d3d10.1 data" << endl; ClearD3D101Data(); DXGI_SWAP_CHAIN_DESC scd; if(SUCCEEDED(swapChain->GetDesc(&scd))) { d3d101CaptureInfo.format = ConvertGIBackBufferFormat(scd.BufferDesc.Format); if(d3d101CaptureInfo.format != GS_UNKNOWNFORMAT) { if( dxgiFormat != scd.BufferDesc.Format || d3d101CaptureInfo.cx != scd.BufferDesc.Width || d3d101CaptureInfo.cy != scd.BufferDesc.Height || d3d101CaptureInfo.hwndCapture != (DWORD)scd.OutputWindow) { dxgiFormat = FixCopyTextureFormat(scd.BufferDesc.Format); d3d101CaptureInfo.cx = scd.BufferDesc.Width; d3d101CaptureInfo.cy = scd.BufferDesc.Height; d3d101CaptureInfo.hwndCapture = (DWORD)scd.OutputWindow; bIsMultisampled = scd.SampleDesc.Count > 1; logOutput << CurrentTimeString() << "found dxgi format (dx10.1) of: " << UINT(dxgiFormat) << ", size: {" << scd.BufferDesc.Width << ", " << scd.BufferDesc.Height << "}, multisampled: " << (bIsMultisampled ? "true" : "false") << endl; } } } lastTime = 0; OSInitializeTimer(); }
void HandleGLSceneUpdate(HDC hDC) { if(!bTargetAcquired && hdcAcquiredDC == NULL) { logOutput << CurrentTimeString() << "setting up gl data" << endl; PIXELFORMATDESCRIPTOR pfd; hwndTarget = WindowFromDC(hDC); int pixFormat = GetPixelFormat(hDC); DescribePixelFormat(hDC, pixFormat, sizeof(pfd), &pfd); if(pfd.cColorBits == 32 && hwndTarget) { bTargetAcquired = true; hdcAcquiredDC = hDC; glcaptureInfo.format = GS_BGR; } OSInitializeTimer(); } if(hDC == hdcAcquiredDC) { if(bCapturing && WaitForSingleObject(hSignalEnd, 0) == WAIT_OBJECT_0) bStopRequested = true; if(bCapturing && !IsWindow(hwndOBS)) { hwndOBS = NULL; bStopRequested = true; } if(bCapturing && bStopRequested) { RUNEVERYRESET logOutput << CurrentTimeString() << "stop requested, terminating gl capture" << endl; ClearGLData(); bCapturing = false; bStopRequested = false; bReacquiring = false; } if(!bCapturing && WaitForSingleObject(hSignalRestart, 0) == WAIT_OBJECT_0) { hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(hwndOBS) bCapturing = true; } RECT rc; GetClientRect(hwndTarget, &rc); if(bCapturing && bReacquiring) { if(lastCX != rc.right || lastCY != rc.bottom) //reset if continuing to size within the 3 seconds { reacquireStart = OSGetTimeMicroseconds(); lastCX = rc.right; lastCY = rc.bottom; } if(OSGetTimeMicroseconds()-reacquireTime >= 3000000) { //3 second to reacquire RUNEVERYRESET logOutput << CurrentTimeString() << "reacquiring gl due to resize..." << endl; bReacquiring = false; } else { return; } } if(bCapturing && (!bHasTextures || rc.right != glcaptureInfo.cx || rc.bottom != glcaptureInfo.cy)) { if (!rc.right || !rc.bottom) return; if(bHasTextures) //resizing { ClearGLData(); bReacquiring = true; reacquireStart = OSGetTimeMicroseconds(); lastCX = rc.right; lastCY = rc.bottom; return; } else { if(hwndOBS) DoGLCPUHook(rc); else ClearGLData(); } } LONGLONG timeVal = OSGetTimeMicroseconds(); //check keep alive state, dumb but effective if(bCapturing) { if (!keepAliveTime) keepAliveTime = timeVal; if((timeVal-keepAliveTime) > 5000000) { HANDLE hKeepAlive = OpenEvent(EVENT_ALL_ACCESS, FALSE, strKeepAlive.c_str()); if (hKeepAlive) { CloseHandle(hKeepAlive); } else { ClearGLData(); logOutput << CurrentTimeString() << "Keepalive no longer found on gl, freeing capture data" << endl; bCapturing = false; } keepAliveTime = timeVal; } } if(bHasTextures) { LONGLONG frameTime; if(bCapturing) { if(copyData) { if(frameTime = copyData->frameTime) { LONGLONG timeElapsed = timeVal-lastTime; if(timeElapsed >= frameTime) { lastTime += frameTime; if(timeElapsed > frameTime*2) lastTime = timeVal; GLuint texture = gltextures[curCapture]; DWORD nextCapture = (curCapture == NUM_BUFFERS-1) ? 0 : (curCapture+1); glReadBuffer(GL_BACK); glBindBuffer(GL_PIXEL_PACK_BUFFER, texture); if(glLockedTextures[curCapture]) { OSEnterMutex(glDataMutexes[curCapture]); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glLockedTextures[curCapture] = false; OSLeaveMutex(glDataMutexes[curCapture]); } glReadPixels(0, 0, glcaptureInfo.cx, glcaptureInfo.cy, GL_BGRA, GL_UNSIGNED_BYTE, 0); //---------------------------------- glBindBuffer(GL_PIXEL_PACK_BUFFER, gltextures[nextCapture]); pCopyData = (void*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); if(pCopyData) { curCPUTexture = nextCapture; glLockedTextures[nextCapture] = true; RUNEVERYRESET logOutput << CurrentTimeString() << "successfully capturing gl frames via RAM" << endl; SetEvent(hCopyEvent); } else { RUNEVERYRESET logOutput << CurrentTimeString() << "one or more gl frames failed to capture for some reason" << endl; } //---------------------------------- glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); curCapture = nextCapture; } } } } else { RUNEVERYRESET logOutput << CurrentTimeString() << "no longer capturing, terminating gl capture" << endl; ClearGLData(); } } } }
bool SetupDDraw() { logOutput << CurrentTimeString() << "called SetupDDraw()" << endl; if (!g_ddInterface) { logOutput << CurrentTimeString() << "SetupDDraw: DirectDraw interface not set, returning" << endl; return false; } bool bSuccess = true; bKillThread = false; if (hCopyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CopyDDrawTextureThread, NULL, 0, NULL)) { if (!(hCopyEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { logOutput << CurrentTimeString() << "SetupDDraw: CreateEvent failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } } else { logOutput << CurrentTimeString() << "SetupDDraw: CreateThread failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } if (bSuccess) { if (!ddUnlockFctMutex) { ddUnlockFctMutex = CreateMutex(NULL, FALSE, mutexName); if (!ddUnlockFctMutex) { RUNEVERYRESET logOutput << CurrentTimeString() << "SetupDDraw: CreateMutex failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } } } if (bSuccess && !g_frontSurface) { RUNEVERYRESET logOutput << "SetupDDraw: frontSurface and surface descriptor not set, returning" << endl; CleanUpDDraw(); return false; } else if (bSuccess) { LPDIRECTDRAWPALETTE palette = NULL; HRESULT err; if (SUCCEEDED(err = g_frontSurface->GetPalette(&palette))) { if (palette) SetupPalette(palette); } else if (err == DDERR_NOPALETTEATTACHED) { //logOutput << CurrentTimeString() << "No palette attached to primary surface" << endl; } else { logOutput << CurrentTimeString() << "Error retrieving palette" << endl; printDDrawError(err, "getFrontSurface"); } } if (bSuccess && !g_surfaceDesc) { logOutput << CurrentTimeString() << "SetupDDraw: no surface descriptor found, creating a new one (not an error)" << endl; g_surfaceDesc = new DDSURFACEDESC2; g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC); HRESULT hr; if (FAILED(hr = ((LPDIRECTDRAWSURFACE)g_frontSurface)->GetSurfaceDesc((LPDDSURFACEDESC)g_surfaceDesc))) { g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC2); if (FAILED(g_frontSurface->GetSurfaceDesc(g_surfaceDesc))) { logOutput << CurrentTimeString() << "SetupDDraw: error getting surface descriptor" << endl; printDDrawError(hr, "SetupDDraw"); bSuccess = false; } } } if (bSuccess && g_surfaceDesc) { const DDPIXELFORMAT& pf = g_surfaceDesc->ddpfPixelFormat; if (pf.dwFlags & DDPF_RGB) { if (pf.dwRGBBitCount == 16) { logOutput << CurrentTimeString() << "SetupDDraw: found 16bit format (using R5G6B5 conversion)" << endl; g_bConvert16to32 = true; } else if (pf.dwRGBBitCount == 32) { logOutput << CurrentTimeString() << "SetupDDraw: found 32bit format (using plain copy)" << endl; g_bUse32bitCapture = true; } } else if (pf.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1)) { logOutput << CurrentTimeString() << "SetupDDraw: front surface uses palette indices" << endl; } } if (bSuccess) { logOutput << CurrentTimeString() << "SetupDDraw: primary surface width = " << g_surfaceDesc->dwWidth << ", height = " << g_surfaceDesc->dwHeight << endl; g_dwSize = g_surfaceDesc->lPitch*g_surfaceDesc->dwHeight; ddrawCaptureInfo.captureType = CAPTURETYPE_MEMORY; ddrawCaptureInfo.cx = g_surfaceDesc->dwWidth; ddrawCaptureInfo.cy = g_surfaceDesc->dwHeight; ddrawCaptureInfo.pitch = 4 * ddrawCaptureInfo.cx; ddrawCaptureInfo.hwndCapture = (DWORD)hwndSender; ddrawCaptureInfo.format = GS_BGRA; DWORD g_dwCaptureSize = ddrawCaptureInfo.pitch*ddrawCaptureInfo.cy; ddrawCaptureInfo.bFlip = FALSE; ddrawCaptureInfo.mapID = InitializeSharedMemoryCPUCapture(g_dwCaptureSize, &ddrawCaptureInfo.mapSize, ©Data, textureBuffers); memcpy(infoMem, &ddrawCaptureInfo, sizeof(CaptureInfo)); DDSURFACEDESC2 captureDesc; ZeroMemory(&captureDesc, sizeof(captureDesc)); captureDesc.dwSize = sizeof(DDSURFACEDESC2); captureDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_PITCH; captureDesc.dwWidth = g_surfaceDesc->dwWidth; captureDesc.dwHeight = g_surfaceDesc->dwHeight; captureDesc.lPitch = g_surfaceDesc->lPitch; captureDesc.ddpfPixelFormat = g_surfaceDesc->ddpfPixelFormat; captureDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; HRESULT err; ddrawSurfaceCreate.Unhook(); for (int i = 0; i < NUM_BUFFERS && bSuccess; i++) { if (FAILED(err = g_ddInterface->CreateSurface(&captureDesc, &ddCaptures[i], NULL))) { logOutput << CurrentTimeString() << "SetupDDraw: Could not create offscreen capture" << endl; printDDrawError(err, "SetupDDraw"); bSuccess = false; break; } } ddrawSurfaceCreate.Rehook(); if (bSuccess) { bHasTextures = true; SetEvent(hSignalReady); OSInitializeTimer(); } } if (bSuccess) { logOutput << CurrentTimeString() << "SetupDDraw successfull" << endl; HookAll(); return true; } else { logOutput << CurrentTimeString() << "SetupDDraw failed" << endl; CleanUpDDraw(); return false; } }
void DoGLCPUHook(RECT &rc) { glcaptureInfo.cx = rc.right; glcaptureInfo.cy = rc.bottom; glGenBuffers(NUM_BUFFERS, gltextures); DWORD dwSize = glcaptureInfo.cx*glcaptureInfo.cy*4; BOOL bSuccess = true; for(UINT i=0; i<NUM_BUFFERS; i++) { UINT test = 0; glBindBuffer(GL_PIXEL_PACK_BUFFER, gltextures[i]); glBufferData(GL_PIXEL_PACK_BUFFER, dwSize, 0, GL_STREAM_READ); if(!(glDataMutexes[i] = OSCreateMutex())) { logOutput << CurrentTimeString() << "DoGLCPUHook: OSCreateMutex " << i << " failed, GetLastError = " << GetLastError(); bSuccess = false; break; } } glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); if(bSuccess) { bKillThread = false; if(hCopyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CopyGLCPUTextureThread, NULL, 0, NULL)) { if(!(hCopyEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { logOutput << CurrentTimeString() << "DoGLCPUHook: CreateEvent failed, GetLastError = " << GetLastError(); bSuccess = false; } } else { logOutput << CurrentTimeString() << "DoGLCPUHook: CreateThread failed, GetLastError = " << GetLastError(); bSuccess = false; } } if(bSuccess) { glcaptureInfo.mapID = InitializeSharedMemoryCPUCapture(dwSize, &glcaptureInfo.mapSize, ©Data, textureBuffers); if(!glcaptureInfo.mapID) bSuccess = false; } if(bSuccess) { bHasTextures = true; glcaptureInfo.captureType = CAPTURETYPE_MEMORY; glcaptureInfo.hwndCapture = (DWORD)hwndTarget; glcaptureInfo.pitch = glcaptureInfo.cx*4; glcaptureInfo.bFlip = TRUE; memcpy(infoMem, &glcaptureInfo, sizeof(CaptureInfo)); SetEvent(hSignalReady); logOutput << CurrentTimeString() << "DoGLCPUHook: success" << endl; OSInitializeTimer(); } else ClearGLData(); }