mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 08:38:20 +00:00
[client] egl: make better use of atomics and fix modulus bug
This commit is contained in:
parent
bd42445ea7
commit
06aee158de
@ -30,7 +30,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
#include <SDL2/SDL_egl.h>
|
#include <SDL2/SDL_egl.h>
|
||||||
|
|
||||||
#define TEXTURE_COUNT 3
|
/* this must be a multiple of 2 */
|
||||||
|
#define TEXTURE_COUNT 2
|
||||||
|
|
||||||
struct Tex
|
struct Tex
|
||||||
{
|
{
|
||||||
@ -41,19 +42,9 @@ struct Tex
|
|||||||
GLsync sync;
|
GLsync sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
union TexState
|
struct TexState
|
||||||
{
|
{
|
||||||
_Atomic(uint32_t) v;
|
_Atomic(uint8_t) w, u, s, d;
|
||||||
struct
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* w = write
|
|
||||||
* u = upload
|
|
||||||
* s = schedule
|
|
||||||
* d = display
|
|
||||||
*/
|
|
||||||
_Atomic(int8_t) w, u, s, d;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EGL_Texture
|
struct EGL_Texture
|
||||||
@ -73,7 +64,7 @@ struct EGL_Texture
|
|||||||
GLenum dataType;
|
GLenum dataType;
|
||||||
size_t pboBufferSize;
|
size_t pboBufferSize;
|
||||||
|
|
||||||
union TexState state;
|
struct TexState state;
|
||||||
int textureCount;
|
int textureCount;
|
||||||
struct Tex tex[TEXTURE_COUNT];
|
struct Tex tex[TEXTURE_COUNT];
|
||||||
};
|
};
|
||||||
@ -182,7 +173,10 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_
|
|||||||
texture->textureCount = streaming ? TEXTURE_COUNT : 1;
|
texture->textureCount = streaming ? TEXTURE_COUNT : 1;
|
||||||
texture->ready = false;
|
texture->ready = false;
|
||||||
|
|
||||||
atomic_store_explicit(&texture->state.v, 0, memory_order_relaxed);
|
atomic_store_explicit(&texture->state.w, 0, memory_order_relaxed);
|
||||||
|
atomic_store_explicit(&texture->state.u, 0, memory_order_relaxed);
|
||||||
|
atomic_store_explicit(&texture->state.s, 0, memory_order_relaxed);
|
||||||
|
atomic_store_explicit(&texture->state.d, 0, memory_order_relaxed);
|
||||||
|
|
||||||
switch(pixFmt)
|
switch(pixFmt)
|
||||||
{
|
{
|
||||||
@ -322,22 +316,22 @@ bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer)
|
|||||||
{
|
{
|
||||||
if (texture->streaming)
|
if (texture->streaming)
|
||||||
{
|
{
|
||||||
union TexState s;
|
const uint8_t sw =
|
||||||
s.v = atomic_load_explicit(&texture->state.v, memory_order_acquire);
|
atomic_load_explicit(&texture->state.w, memory_order_acquire);
|
||||||
|
|
||||||
const uint8_t next = (s.w + 1) % TEXTURE_COUNT;
|
if (atomic_load_explicit(&texture->state.u, memory_order_acquire) == sw + 1)
|
||||||
if (next == s.u)
|
|
||||||
{
|
{
|
||||||
egl_warn_slow();
|
egl_warn_slow();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egl_texture_map(texture, s.w))
|
const uint8_t t = sw % TEXTURE_COUNT;
|
||||||
|
if (!egl_texture_map(texture, t))
|
||||||
return EGL_TEX_STATUS_ERROR;
|
return EGL_TEX_STATUS_ERROR;
|
||||||
|
|
||||||
memcpy(texture->tex[s.w].map, buffer, texture->pboBufferSize);
|
memcpy(texture->tex[t].map, buffer, texture->pboBufferSize);
|
||||||
atomic_store_explicit(&texture->state.w, next, memory_order_release);
|
atomic_fetch_add_explicit(&texture->state.w, 1, memory_order_release);
|
||||||
egl_texture_unmap(texture, s.w);
|
egl_texture_unmap(texture, t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -358,22 +352,22 @@ bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer * fr
|
|||||||
if (!texture->streaming)
|
if (!texture->streaming)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
union TexState s;
|
const uint8_t sw =
|
||||||
s.v = atomic_load_explicit(&texture->state.v, memory_order_acquire);
|
atomic_load_explicit(&texture->state.w, memory_order_acquire);
|
||||||
|
|
||||||
const uint8_t next = (s.w + 1) % TEXTURE_COUNT;
|
if (atomic_load_explicit(&texture->state.u, memory_order_acquire) == sw + 1)
|
||||||
if (next == s.u)
|
|
||||||
{
|
{
|
||||||
egl_warn_slow();
|
egl_warn_slow();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egl_texture_map(texture, s.w))
|
const uint8_t t = sw % TEXTURE_COUNT;
|
||||||
|
if (!egl_texture_map(texture, t))
|
||||||
return EGL_TEX_STATUS_ERROR;
|
return EGL_TEX_STATUS_ERROR;
|
||||||
|
|
||||||
framebuffer_read(
|
framebuffer_read(
|
||||||
frame,
|
frame,
|
||||||
texture->tex[s.w].map,
|
texture->tex[t].map,
|
||||||
texture->stride,
|
texture->stride,
|
||||||
texture->height,
|
texture->height,
|
||||||
texture->width,
|
texture->width,
|
||||||
@ -381,8 +375,8 @@ bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer * fr
|
|||||||
texture->stride
|
texture->stride
|
||||||
);
|
);
|
||||||
|
|
||||||
atomic_store_explicit(&texture->state.w, next, memory_order_release);
|
atomic_fetch_add_explicit(&texture->state.w, 1, memory_order_release);
|
||||||
egl_texture_unmap(texture, s.w);
|
egl_texture_unmap(texture, t);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -392,18 +386,22 @@ enum EGL_TexStatus egl_texture_process(EGL_Texture * texture)
|
|||||||
if (!texture->streaming)
|
if (!texture->streaming)
|
||||||
return EGL_TEX_STATUS_OK;
|
return EGL_TEX_STATUS_OK;
|
||||||
|
|
||||||
union TexState s;
|
const uint8_t su =
|
||||||
s.v = atomic_load_explicit(&texture->state.v, memory_order_acquire);
|
atomic_load_explicit(&texture->state.u, memory_order_acquire);
|
||||||
|
|
||||||
const uint8_t nextu = (s.u + 1) % TEXTURE_COUNT;
|
const uint8_t nextu = su + 1;
|
||||||
if (s.u == s.w || nextu == s.s || nextu == s.d)
|
if (
|
||||||
|
su == atomic_load_explicit(&texture->state.w, memory_order_acquire) ||
|
||||||
|
nextu == atomic_load_explicit(&texture->state.s, memory_order_acquire) ||
|
||||||
|
nextu == atomic_load_explicit(&texture->state.d, memory_order_acquire))
|
||||||
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
|
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
|
||||||
|
|
||||||
/* update the texture */
|
/* update the texture */
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->tex[s.u].pbo);
|
const uint8_t t = su % TEXTURE_COUNT;
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->tex[t].pbo);
|
||||||
for(int p = 0; p < texture->planeCount; ++p)
|
for(int p = 0; p < texture->planeCount; ++p)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->tex[s.u].t[p]);
|
glBindTexture(GL_TEXTURE_2D, texture->tex[t].t[p]);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[p][2]);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[p][2]);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[p][0], texture->planes[p][1],
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[p][0], texture->planes[p][1],
|
||||||
texture->format, texture->dataType, (const void *)texture->offsets[p]);
|
texture->format, texture->dataType, (const void *)texture->offsets[p]);
|
||||||
@ -412,39 +410,39 @@ enum EGL_TexStatus egl_texture_process(EGL_Texture * texture)
|
|||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
/* create a fence to prevent usage before the update is complete */
|
/* create a fence to prevent usage before the update is complete */
|
||||||
texture->tex[s.u].sync =
|
texture->tex[t].sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
||||||
|
|
||||||
/* we must flush to ensure the sync is in the command buffer */
|
/* we must flush to ensure the sync is in the command buffer */
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
texture->ready = true;
|
texture->ready = true;
|
||||||
atomic_store_explicit(&texture->state.u, nextu, memory_order_release);
|
atomic_fetch_add_explicit(&texture->state.u, 1, memory_order_release);
|
||||||
|
|
||||||
return EGL_TEX_STATUS_OK;
|
return EGL_TEX_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
|
enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
|
||||||
{
|
{
|
||||||
union TexState s;
|
uint8_t ss = atomic_load_explicit(&texture->state.s, memory_order_acquire);
|
||||||
s.v = atomic_load_explicit(&texture->state.v, memory_order_acquire);
|
uint8_t sd = atomic_load_explicit(&texture->state.d, memory_order_acquire);
|
||||||
|
|
||||||
if (texture->streaming)
|
if (texture->streaming)
|
||||||
{
|
{
|
||||||
if (!texture->ready)
|
if (!texture->ready)
|
||||||
return EGL_TEX_STATUS_NOTREADY;
|
return EGL_TEX_STATUS_NOTREADY;
|
||||||
|
|
||||||
if (texture->tex[s.s].sync != 0)
|
const uint8_t t = ss % TEXTURE_COUNT;
|
||||||
|
if (texture->tex[t].sync != 0)
|
||||||
{
|
{
|
||||||
switch(glClientWaitSync(texture->tex[s.s].sync, 0, 20000000)) // 20ms
|
switch(glClientWaitSync(texture->tex[t].sync, 0, 20000000)) // 20ms
|
||||||
{
|
{
|
||||||
case GL_ALREADY_SIGNALED:
|
case GL_ALREADY_SIGNALED:
|
||||||
case GL_CONDITION_SATISFIED:
|
case GL_CONDITION_SATISFIED:
|
||||||
glDeleteSync(texture->tex[s.s].sync);
|
glDeleteSync(texture->tex[t].sync);
|
||||||
texture->tex[s.s].sync = 0;
|
texture->tex[t].sync = 0;
|
||||||
|
|
||||||
s.s = (s.s + 1) % TEXTURE_COUNT;
|
ss = atomic_fetch_add_explicit(&texture->state.s, 1,
|
||||||
atomic_store_explicit(&texture->state.s, s.s, memory_order_release);
|
memory_order_release) + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GL_TIMEOUT_EXPIRED:
|
case GL_TIMEOUT_EXPIRED:
|
||||||
@ -452,25 +450,23 @@ enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
|
|||||||
|
|
||||||
case GL_WAIT_FAILED:
|
case GL_WAIT_FAILED:
|
||||||
case GL_INVALID_VALUE:
|
case GL_INVALID_VALUE:
|
||||||
glDeleteSync(texture->tex[s.s].sync);
|
glDeleteSync(texture->tex[t].sync);
|
||||||
texture->tex[s.s].sync = 0;
|
texture->tex[t].sync = 0;
|
||||||
EGL_ERROR("glClientWaitSync failed");
|
EGL_ERROR("glClientWaitSync failed");
|
||||||
return EGL_TEX_STATUS_ERROR;
|
return EGL_TEX_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int8_t nextd = (s.d + 1) % TEXTURE_COUNT;
|
if (ss != sd && ss != sd+1)
|
||||||
if (s.d != s.s && nextd != s.s)
|
sd = atomic_fetch_add_explicit(&texture->state.d, 1,
|
||||||
{
|
memory_order_release) + 1;
|
||||||
s.d = nextd;
|
|
||||||
atomic_store_explicit(&texture->state.d, nextd, memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t t = sd % TEXTURE_COUNT;
|
||||||
for(int i = 0; i < texture->planeCount; ++i)
|
for(int i = 0; i < texture->planeCount; ++i)
|
||||||
{
|
{
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->tex[s.d].t[i]);
|
glBindTexture(GL_TEXTURE_2D, texture->tex[t].t[i]);
|
||||||
glBindSampler(i, texture->samplers[i]);
|
glBindSampler(i, texture->samplers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user