Skip to content

Commit

Permalink
DirectX multi-monitor support (#966)
Browse files Browse the repository at this point in the history
* Needed changes before multi-monitor support

* Add multi-monitor and P010 detection

* Initial multi-monitor support

* Fix multi-monitor capturing
  • Loading branch information
awawa-dev authored Nov 21, 2024
1 parent fa32e0f commit 7e94683
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 158 deletions.
2 changes: 2 additions & 0 deletions include/base/Grabber.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ public slots:

int getTargetSystemFrameDimension(int& targetSizeX, int& targetSizeY);

int getTargetSystemFrameDimension(int actualWidth, int actualHeight, int& targetSizeX, int& targetSizeY);

void processSystemFrameBGRA(uint8_t* source, int lineSize = 0, bool useLut = true);

void processSystemFrameBGR(uint8_t* source, int lineSize = 0);
Expand Down
75 changes: 59 additions & 16 deletions include/grabber/windows/DX/DxGrabber.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,61 @@
#include <vector>
#include <map>
#include <chrono>
#include <list>
#include <algorithm>
#endif

// util includes
#include <utils/PixelFormat.h>
#include <base/Grabber.h>
#include <utils/Components.h>

template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}

struct DisplayHandle
{
QString name;
int warningCounter = 6;
bool wideGamut = false;
int actualDivide = -1, actualWidth = 0, actualHeight = 0;
uint targetMonitorNits = 0;
ID3D11Texture2D* d3dConvertTexture = nullptr;
ID3D11RenderTargetView* d3dRenderTargetView = nullptr;
ID3D11ShaderResourceView* d3dConvertTextureView = nullptr;
ID3D11VertexShader* d3dVertexShader = nullptr;
ID3D11PixelShader* d3dPixelShader = nullptr;
ID3D11Buffer* d3dBuffer = nullptr;
ID3D11SamplerState* d3dSampler = nullptr;
ID3D11InputLayout* d3dVertexLayout = nullptr;
IDXGIOutputDuplication* d3dDuplicate = nullptr;
ID3D11Texture2D* d3dSourceTexture = nullptr;
DXGI_OUTDUPL_DESC surfaceProperties{};

DisplayHandle() = default;
DisplayHandle(const DisplayHandle&) = delete;
~DisplayHandle()
{
SafeRelease(&d3dRenderTargetView);
SafeRelease(&d3dSourceTexture);
SafeRelease(&d3dConvertTextureView);
SafeRelease(&d3dConvertTexture);
SafeRelease(&d3dVertexShader);
SafeRelease(&d3dVertexLayout);
SafeRelease(&d3dPixelShader);
SafeRelease(&d3dSampler);
SafeRelease(&d3dBuffer);
SafeRelease(&d3dDuplicate);
printf("SmartPointer is removing: DisplayHandle for %s\n", QSTRING_CSTR(name));
};
};

class DxGrabber : public Grabber
{
Q_OBJECT
Expand Down Expand Up @@ -56,6 +104,13 @@ public slots:
void restart();

private:

const QString MULTI_MONITOR = "MULTI-MONITOR";

void captureFrame(DisplayHandle& display);

int captureFrame(DisplayHandle& display, Image<ColorRgb>& image);

QString GetSharedLut();

void enumerateDevices(bool silent);
Expand All @@ -70,29 +125,17 @@ public slots:

bool initDirectX(QString selectedDeviceName);

bool initShaders();
HRESULT deepScaledCopy(ID3D11Texture2D* source);
bool initShaders(DisplayHandle& display);
HRESULT deepScaledCopy(DisplayHandle& display, ID3D11Texture2D* source);

QString _configurationPath;
QTimer* _timer;
QTimer* _retryTimer;
int _warningCounter;
int _actualDivide;
bool _wideGamut;
bool _multiMonitor;

bool _dxRestartNow;
std::list<std::unique_ptr<DisplayHandle>> _handles;
ID3D11Device* _d3dDevice;
ID3D11DeviceContext* _d3dContext;
ID3D11Buffer* _d3dBuffer;
ID3D11SamplerState* _d3dSampler;
ID3D11InputLayout* _d3dVertexLayout;
ID3D11VertexShader* _d3dVertexShader;
ID3D11PixelShader* _d3dPixelShader;
ID3D11Texture2D* _d3dSourceTexture;
ID3D11Texture2D* _d3dConvertTexture;
ID3D11ShaderResourceView* _d3dConvertTextureView;
ID3D11RenderTargetView* _d3dRenderTargetView;
IDXGIOutputDuplication* _d3dDuplicate;
DXGI_OUTDUPL_DESC _surfaceProperties;
Image<ColorRgb> _cacheImage;
};
2 changes: 2 additions & 0 deletions include/image/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Image

void gradientVBox(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t r, uint8_t g, uint8_t b);

void insertHorizontal(int x, Image<ColorSpace>& source);

unsigned width() const;

unsigned height() const;
Expand Down
9 changes: 9 additions & 0 deletions include/utils/PixelFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum class PixelFormat {
I420,
NV12,
MJPEG,
P010,
NO_CHANGE
};

Expand Down Expand Up @@ -42,6 +43,10 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
{
return PixelFormat::MJPEG;
}
else if (format.compare("p010") == 0)
{
return PixelFormat::P010;
}

return PixelFormat::NO_CHANGE;
}
Expand Down Expand Up @@ -73,6 +78,10 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
{
return "mjpeg";
}
else if (pixelFormat == PixelFormat::P010)
{
return "p010";
}

return "NO_CHANGE";
}
64 changes: 62 additions & 2 deletions sources/base/Grabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,24 @@ void Grabber::setEnabled(bool enable)

void Grabber::setMonitorNits(int nits)
{
_targetMonitorNits = nits;
if (_targetMonitorNits != nits)
{
_targetMonitorNits = nits;

Debug(_log, "Set nits to %i", _targetMonitorNits);

if (_initialized && !_blocked)
{
Debug(_log, "Restarting video grabber");
uninit();
start();
}
else
{
Info(_log, "Delayed restart of the grabber due to change of monitor nits value");
_restartNeeded = true;
}
}
}

void Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
Expand All @@ -128,7 +145,24 @@ void Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTo

void Grabber::enableHardwareAcceleration(bool hardware)
{
_hardware = hardware;
if (_hardware != hardware)
{
_hardware = hardware;

Debug(_log, "Set hardware acceleration to %s", _hardware ? "enabled" : "disabled");

if (_initialized && !_blocked)
{
Debug(_log, "Restarting video grabber");
uninit();
start();
}
else
{
Info(_log, "Delayed restart of the grabber due to change of the hardware acceleration");
_restartNeeded = true;
}
}
}

bool Grabber::trySetInput(int input)
Expand Down Expand Up @@ -518,6 +552,32 @@ int Grabber::getTargetSystemFrameDimension(int& targetSizeX, int& targetSizeY)
return divide;
}

int Grabber::getTargetSystemFrameDimension(int actualWidth, int actualHeight, int& targetSizeX, int& targetSizeY)
{
int realSizeX = actualWidth;
int realSizeY = actualHeight;

if (realSizeX <= 16 || realSizeY <= 16)
{
realSizeX = actualWidth;
realSizeY = actualHeight;
}

int checkWidth = realSizeX;
int divide = 1;

while (checkWidth > _width)
{
divide++;
checkWidth = realSizeX / divide;
}

targetSizeX = realSizeX / divide;
targetSizeY = realSizeY / divide;

return divide;
}

void Grabber::processSystemFrameBGRA(uint8_t* source, int lineSize, bool useLut)
{
int targetSizeX, targetSizeY;
Expand Down
3 changes: 3 additions & 0 deletions sources/grabber/linux/v4l2/V4L2Grabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ static const V4L2Grabber::HyperHdrFormat supportedFormats[] =
{ V4L2_PIX_FMT_YUV420, PixelFormat::I420 },
{ V4L2_PIX_FMT_NV12, PixelFormat::NV12 },
{ V4L2_PIX_FMT_MJPEG, PixelFormat::MJPEG }
#ifdef V4L2_PIX_FMT_P010
,{ V4L2_PIX_FMT_P010, PixelFormat::P010 }
#endif
};


Expand Down
Loading

0 comments on commit 7e94683

Please sign in to comment.