Compare commits

..

8 Commits

Author SHA1 Message Date
Geoffrey McRae
438e9e0969 [common] option: fixed missing null terminator 2019-05-27 01:56:55 +10:00
Geoffrey McRae
9554e82c47 [common] fix failure to initialize structure 2019-05-27 01:50:38 +10:00
Geoffrey McRae
4cf2c7a350 [client] check for failure to map pbo memory 2019-05-27 01:39:01 +10:00
Geoffrey McRae
664d7dccdb [client] fix the binary path when debugging 2019-05-27 01:38:50 +10:00
Geoffrey McRae
21b02efb4d [c-host] dxgi: don't stall the GPU pipeline to map textures to ram
ID3D11DeviceContext_Map by default will force a CPU sync if the prior call to
CopyResource has not completed, this change defers the mapping and sets the
D3D11_MAP_FLAG_DO_NOT_WAIT when attempting to map the texture allowing the
capture to continue without incurring an expensive CPU/GPU sync.

A new tuneable has also been added

  * dxgi:maxTextures
2019-05-26 23:36:17 +10:00
Jonathan (JJRcop) Rubenstein
d07aa4b29e [client] Add win:maximize to maximize on startup 2019-05-26 20:47:59 +10:00
JJRcop
9f33043d17 [client] Fix typo in example of README.md 2019-05-25 10:25:57 +10:00
Geoffrey McRae
2e6301fca1 [common] fixed issue with building for windows (typo) 2019-05-24 21:39:51 +10:00
10 changed files with 93 additions and 31 deletions

View File

@@ -1 +1 @@
a12-232-g759b4ef811+1
B1-rc2-6-g9554e82c47+1

View File

@@ -30,10 +30,16 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "dxgi_extra.h"
#define MAX_TEXTURES 2
enum TextureState
{
TEXTURE_STATE_UNUSED,
TEXTURE_STATE_PENDING_MAP,
TEXTURE_STATE_MAPPED
};
typedef struct Texture
{
enum TextureState state;
ID3D11Texture2D * tex;
D3D11_MAPPED_SUBRESOURCE map;
osEventHandle * evt;
@@ -64,7 +70,8 @@ struct iface
ID3D11DeviceContext * deviceContext;
D3D_FEATURE_LEVEL featureLevel;
IDXGIOutputDuplication * dup;
Texture texture[MAX_TEXTURES];
int maxTextures;
Texture * texture;
int texRIndex;
int texWIndex;
bool needsRelease;
@@ -120,6 +127,13 @@ static void dxgi_initOptions()
.type = OPTION_TYPE_STRING,
.value.x_string = NULL
},
{
.module = "dxgi",
.name = "maxTextures",
.description = "The maximum number of frames to buffer before skipping",
.type = OPTION_TYPE_INT,
.value.x_int = 1
},
{0}
};
@@ -153,6 +167,11 @@ static bool dxgi_create()
return false;
}
this->maxTextures = option_get_int("dxgi", "maxTextures");
if (this->maxTextures <= 0)
this->maxTextures = 1;
this->texture = calloc(sizeof(struct Texture), this->maxTextures);
return true;
}
@@ -434,7 +453,7 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
for(int i = 0; i < MAX_TEXTURES; ++i)
for(int i = 0; i < this->maxTextures; ++i)
{
status = ID3D11Device_CreateTexture2D(this->device, &texDesc, NULL, &this->texture[i].tex);
if (FAILED(status))
@@ -485,8 +504,10 @@ static bool dxgi_deinit()
{
assert(this);
for(int i = 0; i < MAX_TEXTURES; ++i)
for(int i = 0; i < this->maxTextures; ++i)
{
this->texture[i].state = TEXTURE_STATE_UNUSED;
if (this->texture[i].map.pData)
{
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)this->texture[i].tex, 0);
@@ -563,6 +584,7 @@ static void dxgi_free()
os_freeEvent(this->frameEvent );
os_freeEvent(this->pointerEvent);
free(this->texture);
free(this);
this = NULL;
@@ -586,11 +608,35 @@ static CaptureResult dxgi_capture()
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource * res;
// if the read texture is pending a mapping
if (this->texture[this->texRIndex].state == TEXTURE_STATE_PENDING_MAP)
{
Texture * tex = &this->texture[this->texRIndex];
// try to map the resource, but don't wait for it
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);
if (status != DXGI_ERROR_WAS_STILL_DRAWING)
{
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
IDXGIResource_Release(res);
return CAPTURE_RESULT_ERROR;
}
// successful map, set the state and signal that there is a frame available
tex->state = TEXTURE_STATE_MAPPED;
os_signalEvent(this->frameEvent);
}
}
// release the prior frame
result = dxgi_releaseFrame();
if (result != CAPTURE_RESULT_OK)
return result;
status = IDXGIOutputDuplication_AcquireNextFrame(this->dup, 1000, &frameInfo, &res);
status = IDXGIOutputDuplication_AcquireNextFrame(this->dup, 1, &frameInfo, &res);
switch(status)
{
case S_OK:
@@ -616,7 +662,12 @@ static CaptureResult dxgi_capture()
// check if the texture is free, if not skip the frame to keep up
if (!os_waitEvent(tex->evt, 0))
{
DEBUG_WARN("Frame skipped");
/*
NOTE: This is only informational for when debugging, skipping frames is
OK as we are likely getting frames faster then the client can render
them (ie, vsync off in a title)
*/
//DEBUG_WARN("Frame skipped");
}
else
{
@@ -630,33 +681,23 @@ static CaptureResult dxgi_capture()
}
// if the texture was mapped, unmap it
if (tex->map.pData)
if (tex->state == TEXTURE_STATE_MAPPED)
{
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);
tex->map.pData = NULL;
}
// issue the copy from GPU to CPU RAM
// issue the copy from GPU to CPU RAM and release the src
ID3D11DeviceContext_CopyResource(this->deviceContext,
(ID3D11Resource *)tex->tex, (ID3D11Resource *)src);
ID3D11Texture2D_Release(src);
// map the resource (this must be done here as ID3D11DeviceContext is not thread safe)
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0, &tex->map);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
IDXGIResource_Release(res);
return CAPTURE_RESULT_ERROR;
}
// signal that a frame is available
os_signalEvent(this->frameEvent);
// pending map
tex->state = TEXTURE_STATE_PENDING_MAP;
// advance our write pointer
if (++this->texWIndex == MAX_TEXTURES)
if (++this->texWIndex == this->maxTextures)
this->texWIndex = 0;
ID3D11Texture2D_Release(src);
}
}
@@ -745,7 +786,7 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
memcpy(frame->data, tex->map.pData, this->pitch * this->height);
os_signalEvent(tex->evt);
if (++this->texRIndex == MAX_TEXTURES)
if (++this->texRIndex == this->maxTextures)
this->texRIndex = 0;
return CAPTURE_RESULT_OK;

View File

@@ -53,7 +53,7 @@ Below are a list of current key bindings:
The syntax is simple: `module:name=value`, for example:
./looking-glass-host win:fullScreen=yes egl:nvGain=1
./looking-glass-client win:fullScreen=yes egl:nvGain=1
### Setting options via configuration files
@@ -98,6 +98,7 @@ Command line arguments will override any options loaded from the config files.
| win:keepAspect | -r | yes | Maintain the correct aspect ratio |
| win:borderless | -d | no | Borderless mode |
| win:fullScreen | -F | no | Launch in fullscreen borderless mode |
| win:maximize | -T | no | Launch window maximized |
| win:fpsLimit | -K | 200 | Frame rate limit (0 = disable - not recommended) |
| win:showFPS | -k | no | Enable the FPS & UPS display |
| win:ignoreQuit | -Q | no | Ignore requests to quit (ie: Alt+F4) |

View File

@@ -223,6 +223,12 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_
GL_MAP_UNSYNCHRONIZED_BIT |
GL_MAP_INVALIDATE_BUFFER_BIT
);
if (!texture->pboMap[i])
{
DEBUG_ERROR("glMapBufferRange failed for %d of %lu bytes", i, texture->pboBufferSize);
return false;
}
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}

View File

@@ -167,6 +167,14 @@ static struct Option options[] =
.type = OPTION_TYPE_BOOL,
.value.x_bool = false,
},
{
.module = "win",
.name = "maximize",
.description = "Launch window maximized",
.shortopt = 'T',
.type = OPTION_TYPE_BOOL,
.value.x_bool = false,
},
{
.module = "win",
.name = "fpsLimit",
@@ -376,6 +384,7 @@ bool config_load(int argc, char * argv[])
params.keepAspect = option_get_bool ("win", "keepAspect" );
params.borderless = option_get_bool ("win", "borderless" );
params.fullscreen = option_get_bool ("win", "fullScreen" );
params.maximize = option_get_bool ("win", "maximize" );
params.fpsLimit = option_get_int ("win", "fpsLimit" );
params.showFPS = option_get_bool ("win", "showFPS" );
params.ignoreQuit = option_get_bool ("win", "ignoreQuit" );
@@ -550,4 +559,4 @@ static char * optScancodeToString(struct Option * opt)
char * str;
alloc_sprintf(&str, "%d = %s", opt->value.x_int, SDL_GetScancodeName(opt->value.x_int));
return str;
}
}

View File

@@ -1055,6 +1055,7 @@ int run()
(params.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) |
(params.allowResize ? SDL_WINDOW_RESIZABLE : 0) |
(params.borderless ? SDL_WINDOW_BORDERLESS : 0) |
(params.maximize ? SDL_WINDOW_MAXIMIZED : 0) |
sdlFlags
)
);
@@ -1317,7 +1318,7 @@ int run()
int main(int argc, char * argv[])
{
if (!installCrashHandler(argv[0]))
if (!installCrashHandler("/proc/self/exe"))
DEBUG_WARN("Failed to install the crash handler");
config_init();
@@ -1337,4 +1338,4 @@ int main(int argc, char * argv[])
config_free();
return ret;
}
}

View File

@@ -80,6 +80,7 @@ struct AppParams
bool keepAspect;
bool borderless;
bool fullscreen;
bool maximize;
bool center;
int x, y;
unsigned int w, h;
@@ -127,4 +128,4 @@ struct KeybindHandle
// forwards
extern struct AppState state;
extern struct AppParams params;
extern struct AppParams params;

View File

@@ -16,7 +16,7 @@ set(LINUX_SOURCES
src/sysinfo.linux.c
)
set(WINOWS_SOURCES
set(WINDOWS_SOURCES
src/crash.windows.c
src/sysinfo.windows.c
)

View File

@@ -206,7 +206,7 @@ static void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
bool installCrashHandler(const char * exe)
{
struct sigaction sigact;
struct sigaction sigact = { 0 };
crash.exe = realpath(exe, NULL);
sigact.sa_sigaction = crit_err_hdlr;

View File

@@ -427,6 +427,9 @@ bool option_load(const char * filename)
DEBUG_WARN("Ignored unknown option %s:%s", module, name);
else
{
if (value)
value[valueLen] = '\0';
if (!option_set(o, value))
DEBUG_ERROR("Failed to set the option value");
}