[host] kvmfr: allow the frame size to exceed the available memory

This change allows the host to still transmit a frame that is truncated
if the IVSHMEM size is too small to allow for a full frame.
This commit is contained in:
Geoffrey McRae 2021-06-12 18:44:28 +10:00
parent 4b99bba200
commit d36c4f0e83
5 changed files with 44 additions and 65 deletions

View File

@ -28,7 +28,7 @@
#include "types.h"
#define KVMFR_MAGIC "KVMFR---"
#define KVMFR_VERSION 9
#define KVMFR_VERSION 10
#define LGMP_Q_POINTER 1
#define LGMP_Q_FRAME 2
@ -68,8 +68,9 @@ typedef struct KVMFRFrame
{
uint32_t formatVer; // the frame format version number
FrameType type; // the frame data type
uint32_t width; // the width
uint32_t height; // the height
uint32_t width; // the frame width
uint32_t height; // the frame height
uint32_t realHeight; // the real height if the frame was truncated due to low mem
FrameRotation rotation; // the frame rotation
uint32_t stride; // the row stride (zero if compressed data)
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)

View File

@ -64,6 +64,7 @@ typedef struct CaptureFrame
unsigned int formatVer;
unsigned int width;
unsigned int height;
unsigned int realHeight;
unsigned int pitch;
unsigned int stride;
CaptureFormat format;
@ -99,15 +100,14 @@ typedef struct CaptureInterface
CapturePostPointerBuffer postPointerBufferFn
);
bool (*init )();
void (*stop )();
bool (*deinit )();
void (*free )();
unsigned int (*getMaxFrameSize)();
unsigned int (*getMouseScale )();
bool (*init )();
void (*stop )();
bool (*deinit )();
void (*free )();
unsigned int (*getMouseScale)();
CaptureResult (*capture )();
CaptureResult (*waitFrame )(CaptureFrame * frame);
CaptureResult (*getFrame )(FrameBuffer * frame);
CaptureResult (*waitFrame )(CaptureFrame * frame, const size_t maxFrameSize);
CaptureResult (*getFrame )(FrameBuffer * frame, const unsigned int height);
}
CaptureInterface;

View File

@ -714,14 +714,6 @@ static void dxgi_free(void)
this = NULL;
}
static unsigned int dxgi_getMaxFrameSize(void)
{
assert(this);
assert(this->initialized);
return this->height * this->pitch;
}
static unsigned int dxgi_getMouseScale(void)
{
assert(this);
@ -928,7 +920,7 @@ static CaptureResult dxgi_capture(void)
return CAPTURE_RESULT_OK;
}
static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameSize)
{
assert(this);
assert(this->initialized);
@ -980,26 +972,30 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
tex->state = TEXTURE_STATE_MAPPED;
frame->formatVer = tex->formatVer;
frame->width = this->width;
frame->height = this->height;
frame->pitch = this->pitch;
frame->stride = this->stride;
frame->format = this->format;
frame->rotation = this->rotation;
const unsigned int maxHeight = maxFrameSize / this->pitch;
frame->formatVer = tex->formatVer;
frame->width = this->width;
frame->height = maxHeight > this->height ? this->height : maxHeight;
frame->realHeight = this->height;
frame->pitch = this->pitch;
frame->stride = this->stride;
frame->format = this->format;
frame->rotation = this->rotation;
atomic_fetch_sub_explicit(&this->texReady, 1, memory_order_release);
return CAPTURE_RESULT_OK;
}
static CaptureResult dxgi_getFrame(FrameBuffer * frame)
static CaptureResult dxgi_getFrame(FrameBuffer * frame,
const unsigned int height)
{
assert(this);
assert(this->initialized);
Texture * tex = &this->texture[this->texRIndex];
framebuffer_write(frame, tex->map.pData, this->pitch * this->height);
framebuffer_write(frame, tex->map.pData, this->pitch * height);
LOCKED({ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);});
tex->state = TEXTURE_STATE_UNUSED;
@ -1052,7 +1048,6 @@ struct CaptureInterface Capture_DXGI =
.stop = dxgi_stop,
.deinit = dxgi_deinit,
.free = dxgi_free,
.getMaxFrameSize = dxgi_getMaxFrameSize,
.getMouseScale = dxgi_getMouseScale,
.capture = dxgi_capture,
.waitFrame = dxgi_waitFrame,

View File

@ -275,11 +275,6 @@ static void nvfbc_free(void)
NvFBCFree();
}
static unsigned int nvfbc_getMaxFrameSize(void)
{
return this->maxWidth * this->maxHeight * 4;
}
static unsigned int nvfbc_getMouseScale(void)
{
return this->dpi * 100 / DPI_100_PERCENT;
@ -320,7 +315,8 @@ static CaptureResult nvfbc_capture(void)
return CAPTURE_RESULT_OK;
}
static CaptureResult nvfbc_waitFrame(CaptureFrame * frame)
static CaptureResult nvfbc_waitFrame(CaptureFrame * frame,
const size_t maxFrameSize)
{
if (!lgWaitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
@ -339,12 +335,15 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame)
++this->formatVer;
}
frame->formatVer = this->formatVer;
frame->width = this->grabWidth;
frame->height = this->grabHeight;
frame->pitch = this->grabStride * 4;
frame->stride = this->grabStride;
frame->rotation = CAPTURE_ROT_0;
const unsigned int maxHeight = maxFrameSize / (this->grabStride * 4);
frame->formatVer = this->formatVer;
frame->width = this->grabWidth;
frame->height = maxHeight > this->grabHeight ? this->grabHeight : maxHeight;
frame->realHeight = this->grabHeight;
frame->pitch = this->grabStride * 4;
frame->stride = this->grabStride;
frame->rotation = CAPTURE_ROT_0;
#if 0
//NvFBC never sets bIsHDR so instead we check for any data in the alpha channel
@ -366,12 +365,13 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame)
return CAPTURE_RESULT_OK;
}
static CaptureResult nvfbc_getFrame(FrameBuffer * frame)
static CaptureResult nvfbc_getFrame(FrameBuffer * frame,
const unsigned int height)
{
framebuffer_write(
frame,
this->frameBuffer,
this->grabInfo.dwHeight * this->grabInfo.dwBufferWidth * 4
height * this->grabInfo.dwBufferWidth * 4
);
return CAPTURE_RESULT_OK;
}
@ -442,7 +442,6 @@ struct CaptureInterface Capture_NVFBC =
.stop = nvfbc_stop,
.deinit = nvfbc_deinit,
.free = nvfbc_free,
.getMaxFrameSize = nvfbc_getMaxFrameSize,
.getMouseScale = nvfbc_getMouseScale,
.capture = nvfbc_capture,
.waitFrame = nvfbc_waitFrame,

View File

@ -156,7 +156,7 @@ static int frameThread(void * opaque)
continue;
}
switch(app.iface->waitFrame(&frame))
switch(app.iface->waitFrame(&frame, app.maxFrameSize))
{
case CAPTURE_RESULT_OK:
repeatFrame = false;
@ -230,6 +230,7 @@ static int frameThread(void * opaque)
fi->formatVer = frame.formatVer;
fi->width = frame.width;
fi->height = frame.height;
fi->realHeight = frame.realHeight;
fi->stride = frame.stride;
fi->pitch = frame.pitch;
fi->offset = pageSize - FrameBufferStructSize;
@ -248,7 +249,7 @@ static int frameThread(void * opaque)
DEBUG_ERROR("%s", lgmpStatusString(status));
continue;
}
app.iface->getFrame(fb);
app.iface->getFrame(fb, frame.height);
}
DEBUG_INFO("Frame thread stopped");
return 0;
@ -295,24 +296,7 @@ static bool captureStart(void)
}
}
const unsigned int maxFrameSize = app.iface->getMaxFrameSize();
if (maxFrameSize > app.maxFrameSize)
{
DEBUG_ERROR("Maximum frame size of %d bytes exceeds maximum space available", maxFrameSize);
const float needed = ((maxFrameSize * 2) / 1048576.0f) + 10.0f;
const int size = (int)powf(2.0f, ceilf(logf(needed) / logf(2.0f)));
char * msg;
alloc_sprintf(&msg, "IVSHMEM size too small, increase to %d MiB", size);
os_showMessage("Looking Glass Error", msg);
free(msg);
return false;
}
DEBUG_INFO("Capture Size : %u MiB (%u)", maxFrameSize / 1048576, maxFrameSize);
DEBUG_INFO("==== [ Capture Start ] ====");
DEBUG_INFO("==== [ Capture Start ] ====");
return true;
}