[client] copy the header and kick the guest early

This commit is contained in:
Geoffrey McRae 2017-11-26 13:32:54 +11:00
parent e8ac71263b
commit 638f836927

View File

@ -99,7 +99,8 @@ inline bool areFormatsSame(const struct KVMGFXHeader s1, const struct KVMGFXHead
int renderThread(void * unused) int renderThread(void * unused)
{ {
struct KVMGFXHeader format; struct KVMGFXHeader header;
struct KVMGFXHeader newHeader;
SDL_Texture *texture = NULL; SDL_Texture *texture = NULL;
GLuint vboID[2] = {0, 0}; GLuint vboID[2] = {0, 0};
GLuint intFormat = 0; GLuint intFormat = 0;
@ -110,11 +111,7 @@ int renderThread(void * unused)
uint8_t *pixels = (uint8_t*)state.shm; uint8_t *pixels = (uint8_t*)state.shm;
uint8_t *texPixels[2] = {NULL, NULL}; uint8_t *texPixels[2] = {NULL, NULL};
format.version = 1; memset(&header, 0, sizeof(struct KVMGFXHeader));
format.frameType = FRAME_TYPE_INVALID;
format.width = 0;
format.height = 0;
format.stride = 0;
// kick the guest early for our intial frame // kick the guest early for our intial frame
// the guestID may be invalid, it doesn't matter // the guestID may be invalid, it doesn't matter
@ -122,11 +119,14 @@ int renderThread(void * unused)
while(state.running) while(state.running)
{ {
// copy the header for our use
memcpy(&newHeader, state.shm, sizeof(struct KVMGFXHeader));
// ensure the header magic is valid, this will help prevent crash out when the memory hasn't yet been initialized // ensure the header magic is valid, this will help prevent crash out when the memory hasn't yet been initialized
if (memcmp(state.shm->magic, KVMGFX_HEADER_MAGIC, sizeof(KVMGFX_HEADER_MAGIC)) != 0) if (memcmp(newHeader.magic, KVMGFX_HEADER_MAGIC, sizeof(KVMGFX_HEADER_MAGIC)) != 0)
continue; continue;
if (state.shm->version != KVMGFX_HEADER_VERSION) if (newHeader.version != KVMGFX_HEADER_VERSION)
continue; continue;
bool ready = false; bool ready = false;
@ -141,7 +141,7 @@ int renderThread(void * unused)
break; break;
case IVSHMEM_WAIT_RESULT_TIMEOUT: case IVSHMEM_WAIT_RESULT_TIMEOUT:
ivshmem_kick_irq(state.shm->guestID, 0); ivshmem_kick_irq(newHeader.guestID, 0);
ready = false; ready = false;
break; break;
@ -157,8 +157,14 @@ int renderThread(void * unused)
break; break;
} }
// if the format is invalid or it has changed // we can tell the guest to advance early, it won't
if (!areFormatsSame(format, *state.shm)) // touch the frame @ dataPos as it double buffers
// so we can safely read from it while the guest now
// writes the next frame
ivshmem_kick_irq(newHeader.guestID, 0);
// if the header is invalid or it has changed
if (!areFormatsSame(header, newHeader))
{ {
if (state.hasBufferStorage) if (state.hasBufferStorage)
{ {
@ -186,7 +192,7 @@ int renderThread(void * unused)
Uint32 sdlFormat; Uint32 sdlFormat;
unsigned int bpp; unsigned int bpp;
switch(state.shm->frameType) switch(newHeader.frameType)
{ {
case FRAME_TYPE_ARGB: case FRAME_TYPE_ARGB:
sdlFormat = SDL_PIXELFORMAT_ARGB8888; sdlFormat = SDL_PIXELFORMAT_ARGB8888;
@ -203,14 +209,14 @@ int renderThread(void * unused)
break; break;
default: default:
format.frameType = FRAME_TYPE_INVALID; header.frameType = FRAME_TYPE_INVALID;
continue; continue;
} }
// update the window size and create the render texture // update the window size and create the render texture
if (params.autoResize) if (params.autoResize)
{ {
SDL_SetWindowSize(state.window, state.shm->width, state.shm->height); SDL_SetWindowSize(state.window, newHeader.width, newHeader.height);
if (params.center) if (params.center)
SDL_SetWindowPosition(state.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_SetWindowPosition(state.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
} }
@ -218,10 +224,10 @@ int renderThread(void * unused)
if (state.hasBufferStorage) if (state.hasBufferStorage)
{ {
// calculate the texture size in bytes // calculate the texture size in bytes
texSize = state.shm->width * state.shm->stride * bpp; texSize = newHeader.width * newHeader.stride * bpp;
// ensure the size makes sense // ensure the size makes sense
if (state.shm->dataPos + texSize > state.shmSize) if (newHeader.dataPos + texSize > state.shmSize)
{ {
DEBUG_ERROR("The guest sent an invalid dataPos"); DEBUG_ERROR("The guest sent an invalid dataPos");
break; break;
@ -271,7 +277,7 @@ int renderThread(void * unused)
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, 0,
intFormat, intFormat,
state.shm->width, state.shm->height, newHeader.width, newHeader.height,
0, 0,
vboFormat, vboFormat,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
@ -281,7 +287,7 @@ int renderThread(void * unused)
} }
else else
{ {
texture = SDL_CreateTexture(state.renderer, sdlFormat, SDL_TEXTUREACCESS_STREAMING, state.shm->width, state.shm->height); texture = SDL_CreateTexture(state.renderer, sdlFormat, SDL_TEXTUREACCESS_STREAMING, newHeader.width, newHeader.height);
if (!texture) if (!texture)
{ {
DEBUG_ERROR("Failed to create a texture"); DEBUG_ERROR("Failed to create a texture");
@ -289,19 +295,16 @@ int renderThread(void * unused)
} }
} }
memcpy(&format, state.shm, sizeof(format)); memcpy(&header, &newHeader, sizeof(header));
state.windowChanged = true; state.windowChanged = true;
} }
format.dataPos = state.shm->dataPos;
format.guestID = state.shm->guestID;
//beyond this point DO NOT use state.shm for security //beyond this point DO NOT use state.shm for security
// final sanity checks on the data presented by the guest // final sanity checks on the data presented by the guest
// this is critical as the guest could overflow this buffer to // this is critical as the guest could overflow this buffer to
// try to take control of the host // try to take control of the host
if (format.dataPos + texSize > state.shmSize) if (newHeader.dataPos + texSize > state.shmSize)
{ {
DEBUG_ERROR("The guest sent an invalid dataPos"); DEBUG_ERROR("The guest sent an invalid dataPos");
break; break;
@ -315,8 +318,7 @@ int renderThread(void * unused)
SDL_GetWindowSize(state.window, &w, &h); SDL_GetWindowSize(state.window, &w, &h);
// copy the buffer to the texture and let the guest advance // copy the buffer to the texture and let the guest advance
memcpySSE(texPixels[texIndex], pixels + format.dataPos, texSize); memcpySSE(texPixels[texIndex], pixels + newHeader.dataPos, texSize);
ivshmem_kick_irq(format.guestID, 0);
// update the texture // update the texture
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -326,7 +328,7 @@ int renderThread(void * unused)
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, 0,
0, 0, 0, 0,
format.width, format.height, header.width, header.height,
vboFormat, vboFormat,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
(void*)0 (void*)0
@ -358,11 +360,10 @@ int renderThread(void * unused)
DEBUG_ERROR("Failed to lock the texture for update"); DEBUG_ERROR("Failed to lock the texture for update");
break; break;
} }
texSize = format.height * pitch; texSize = header.height * pitch;
// copy the buffer to the texture and let the guest advance // copy the buffer to the texture and let the guest advance
memcpySSE(texPixels[texIndex], pixels + format.dataPos, texSize); memcpySSE(texPixels[texIndex], pixels + newHeader.dataPos, texSize);
ivshmem_kick_irq(format.guestID, 0);
SDL_UnlockTexture(texture); SDL_UnlockTexture(texture);
SDL_RenderCopy(state.renderer, texture, NULL, NULL); SDL_RenderCopy(state.renderer, texture, NULL, NULL);