mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-11-17 07:28:44 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
438e9e0969 | ||
|
|
9554e82c47 | ||
|
|
4cf2c7a350 | ||
|
|
664d7dccdb | ||
|
|
21b02efb4d | ||
|
|
d07aa4b29e | ||
|
|
9f33043d17 |
@@ -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;
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user