retappingly

This commit is contained in:
Lily Tsuru 2024-11-23 21:30:39 -05:00
parent c1bb08c31f
commit 2f2114aca3
3 changed files with 74 additions and 91 deletions

View file

@ -2,7 +2,7 @@
namespace hazelnut {
// capture_nvfbc.cpp
// capture_nvfbc.cpp
IFramebufferCapture* CreateFramebufferCapture_NVFBC();
DisplayCaptureInterface GuessBestCaptureInterface() {
@ -14,15 +14,13 @@ namespace hazelnut {
IFramebufferCapture* pCapture = nullptr;
switch(type) {
case DisplayCaptureInterface::NVFBC:
pCapture = CreateFramebufferCapture_NVFBC();
break;
case DisplayCaptureInterface::NVFBC: pCapture = CreateFramebufferCapture_NVFBC(); break;
default: return nullptr;
}
// Initalize capture.
if (pCapture->Initialize())
if(pCapture->Initialize())
return nullptr;
return std::unique_ptr<IFramebufferCapture>(pCapture);

View file

@ -1,6 +1,7 @@
#include "Utils.hpp"
#include <memory>
#include "Utils.hpp"
namespace hazelnut {
enum class DisplayCaptureResult {
@ -17,15 +18,15 @@ namespace hazelnut {
};
// Difference tile information
struct DiffInformation {
u8* pDiffMap;
u32 diffmapWidth;
u32 diffMapHeight;
};
struct DiffInformation {
u8* pDiffMap;
u32 diffmapWidth;
u32 diffMapHeight;
};
/// Interface used for framebuffer capture independence.
/// Interface used for framebuffer capture independence.
class IFramebufferCapture {
public:
public:
virtual ~IFramebufferCapture() = default;
virtual bool Initialize() = 0;
@ -36,26 +37,25 @@ namespace hazelnut {
/// Get framebuffer information.
virtual FramebufferInformation GetFramebufferInformation() = 0;
/// Gets the tile difference block information.
virtual DiffInformation GetDiffInformation() = 0;
/// Gets the tile difference block information.
virtual DiffInformation GetDiffInformation() = 0;
};
enum class DisplayCaptureInterface : u32 {
Invalid,
NVFBC, // NVFBC capture
// FIXME: DXGI support
};
enum class DisplayCaptureInterface : u32 {
Invalid,
NVFBC, // NVFBC capture
// FIXME: DXGI support
};
/// Returns a guess for the best capture interface.
/// On a NVIDIA GPU on Windows > 8.1, we prefer NVFBC.
/// On a NVIDIA GPU on Windows < 8.1, we prefer NVFBC.
/// Otherwise, we should prefer DXGI.
///
/// If no API works Invalid is returned.
DisplayCaptureInterface GuessBestCaptureInterface();
/// Creates a instance of the framebuffer capture interface for a particular interface.
/// Returns a null pointer on failure to create.
std::unique_ptr<IFramebufferCapture> CreateFramebufferCapture(DisplayCaptureInterface type);
/// Creates a instance of the framebuffer capture interface for a particular interface.
/// Returns a null pointer on failure to create.
std::unique_ptr<IFramebufferCapture> CreateFramebufferCapture(DisplayCaptureInterface type);
} // namespace hazelnut

View file

@ -15,7 +15,7 @@ namespace hazelnut {
NVFBCRESULT nvfbcStatus;
NvFBCLibrary nvfbcLib;
NVFBC_TOSYS_GRAB_FRAME_PARAMS fbcSysGrabParams;
NVFBC_TOSYS_GRAB_FRAME_PARAMS fbcSysGrabParams;
NvFBCFrameGrabInfo grabInfo;
NvFBCToSys* nvfbc;
@ -37,19 +37,19 @@ namespace hazelnut {
nvfbcLib.close();
}
bool Initialize() override {
if (!nvfbcLib.load()) {
bool Initialize() override {
if(!nvfbcLib.load()) {
return false;
}
if (!NvfbcInitSession())
return false;
return true;
}
if(!NvfbcInitSession())
return false;
return true;
}
void NvfbcDestroyInstance() {
if (nvfbc) {
if(nvfbc) {
nvfbc->NvFBCToSysRelease();
nvfbc = nullptr;
@ -66,52 +66,52 @@ namespace hazelnut {
bool NvfbcCreateInstance() {
// Destroy an existing NVFBC session to avoid memory leak
if (nvfbc) {
if(nvfbc) {
NvfbcDestroyInstance();
}
DWORD maxDisplayWidth = -1;
DWORD maxDisplayHeight = -1;
nvfbc = (NvFBCToSys*)nvfbcLib.create(NVFBC_TO_SYS, &maxDisplayWidth, &maxDisplayHeight);
if (!nvfbc) {
return false;
DWORD maxDisplayWidth = -1;
DWORD maxDisplayHeight = -1;
nvfbc = (NvFBCToSys*)nvfbcLib.create(NVFBC_TO_SYS, &maxDisplayWidth, &maxDisplayHeight);
if(!nvfbc) {
return false;
}
return true;
}
bool NvfbcInitSession() {
if (!NvfbcCreateInstance())
if(!NvfbcCreateInstance())
return false;
// set up a session
NVFBC_TOSYS_SETUP_PARAMS fbcSysSetupParams = { 0 };
fbcSysSetupParams.dwVersion = NVFBC_TOSYS_SETUP_PARAMS_VER;
fbcSysSetupParams.eMode = NVFBC_TOSYS_ARGB;
fbcSysSetupParams.bWithHWCursor = true;
fbcSysSetupParams.ppBuffer = (void**)&pRawFramebuffer;
// enable a 32x32 difference map
fbcSysSetupParams.bDiffMap = TRUE;
fbcSysSetupParams.ppDiffMap = (void**)&pDiffMap;
fbcSysSetupParams.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_32X32;
auto status = nvfbc->NvFBCToSysSetUp(&fbcSysSetupParams);
// set up a session
NVFBC_TOSYS_SETUP_PARAMS fbcSysSetupParams = { 0 };
fbcSysSetupParams.dwVersion = NVFBC_TOSYS_SETUP_PARAMS_VER;
fbcSysSetupParams.eMode = NVFBC_TOSYS_ARGB;
fbcSysSetupParams.bWithHWCursor = true;
fbcSysSetupParams.ppBuffer = (void**)&pRawFramebuffer;
// enable a 32x32 difference map
fbcSysSetupParams.bDiffMap = TRUE;
fbcSysSetupParams.ppDiffMap = (void**)&pDiffMap;
fbcSysSetupParams.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_32X32;
auto status = nvfbc->NvFBCToSysSetUp(&fbcSysSetupParams);
if(status != NVFBC_SUCCESS)
return false;
memset(&fbcSysGrabParams, 0, sizeof(NVFBC_TOSYS_GRAB_FRAME_PARAMS));
// set up grab params
fbcSysGrabParams.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER;
fbcSysGrabParams.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT;
fbcSysGrabParams.dwTargetWidth = 0;
fbcSysGrabParams.dwTargetHeight = 0;
fbcSysGrabParams.dwStartX = 0;
fbcSysGrabParams.dwStartY = 0;
fbcSysGrabParams.eGMode = NVFBC_TOSYS_SOURCEMODE_FULL;
fbcSysGrabParams.pNvFBCFrameGrabInfo = &grabInfo;
fbcSysGrabParams.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER;
fbcSysGrabParams.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT;
fbcSysGrabParams.dwTargetWidth = 0;
fbcSysGrabParams.dwTargetHeight = 0;
fbcSysGrabParams.dwStartX = 0;
fbcSysGrabParams.dwStartY = 0;
fbcSysGrabParams.eGMode = NVFBC_TOSYS_SOURCEMODE_FULL;
fbcSysGrabParams.pNvFBCFrameGrabInfo = &grabInfo;
fbcSysGrabParams.dwWaitTime = 16;
return true;
}
@ -119,13 +119,12 @@ namespace hazelnut {
DisplayCaptureResult CaptureFrame() override {
auto nvStatus = nvfbc->NvFBCToSysGrabFrame(&this->fbcSysGrabParams);
switch (nvStatus) {
case NVFBC_SUCCESS:
break;
switch(nvStatus) {
case NVFBC_SUCCESS: break;
// Need to recreate the session. If it fails then we fail too.
case NVFBC_ERROR_INVALIDATED_SESSION: {
if (!NvfbcInitSession())
if(!NvfbcInitSession())
return DisplayCaptureResult::Fail;
// Recurse. This looks naughty, but will allow us to directly retry
@ -133,15 +132,14 @@ namespace hazelnut {
return CaptureFrame();
} break;
default:
return DisplayCaptureResult::Fail;
default: return DisplayCaptureResult::Fail;
}
if (width != grabInfo.dwWidth || height != grabInfo.dwHeight) {
if(width != grabInfo.dwWidth || height != grabInfo.dwHeight) {
width = grabInfo.dwWidth;
height = grabInfo.dwHeight;
diffmapWidth = (u32)ceil((f32)width / 32);
diffmapWidth = (u32)ceil((f32)width / 32);
diffmapHeight = (u32)ceil((f32)height / 32);
convertedFramebuffer.resize(width * height);
@ -151,29 +149,16 @@ namespace hazelnut {
// Splat to the converted framebuffer. It doesn't have padding on it.
auto* pBufferData = convertedFramebuffer.data();
for (u32 y = 0; y < grabInfo.dwHeight; ++y) {
memcpy(&pBufferData[y * width], &pRawFramebuffer[(y * grabInfo.dwBufferWidth)], grabInfo.dwWidth * 4);
for(u32 y = 0; y < grabInfo.dwHeight; ++y) {
memcpy(&pBufferData[y * width], &pRawFramebuffer[(y * grabInfo.dwBufferWidth)], grabInfo.dwWidth * 4);
}
return DisplayCaptureResult::Ok;
}
FramebufferInformation GetFramebufferInformation() override {
return FramebufferInformation{
convertedFramebuffer.data(),
width,
height
};
}
FramebufferInformation GetFramebufferInformation() override { return FramebufferInformation { convertedFramebuffer.data(), width, height }; }
DiffInformation GetDiffInformation() override {
return DiffInformation{
pDiffMap,
diffmapWidth,
diffmapHeight
};
}
DiffInformation GetDiffInformation() override { return DiffInformation { pDiffMap, diffmapWidth, diffmapHeight }; }
};
IFramebufferCapture* CreateFramebufferCapture_NVFBC() {