mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-12 14:57:20 +00:00
[common/client] ivshmem: add portable external frames
This commit is contained in:
@@ -35,6 +35,20 @@ if(LG_CLIENT_PLATFORM_LINUX)
|
||||
set_tests_properties(config-platform-tests PROPERTIES
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_executable(lgmp-platform-tests
|
||||
lgmp_platform_test.c
|
||||
)
|
||||
target_link_libraries(lgmp-platform-tests
|
||||
${EXE_FLAGS}
|
||||
lg_common
|
||||
)
|
||||
add_test(NAME lgmp-platform-tests
|
||||
COMMAND lgmp-platform-tests
|
||||
)
|
||||
set_tests_properties(lgmp-platform-tests PROPERTIES
|
||||
TIMEOUT 10
|
||||
)
|
||||
endif()
|
||||
|
||||
if(LG_CLIENT_PLATFORM_WINDOWS)
|
||||
@@ -999,6 +1013,7 @@ if(ENABLE_EGL)
|
||||
poll
|
||||
saturation
|
||||
release
|
||||
identity
|
||||
)
|
||||
foreach(name IN LISTS TEXTURE_DMABUF_CASES)
|
||||
add_test(NAME texture-dmabuf-${name}
|
||||
|
||||
@@ -527,7 +527,7 @@ static bool testDMAUnavailable(TestState * state)
|
||||
CHECK(postShared(state, &frame));
|
||||
CHECK(state->frameOps->nextFrame(state->transport, false, &result) ==
|
||||
LG_TRANSPORT_OK);
|
||||
CHECK(result.dmaFD == -1);
|
||||
CHECK(result.externalFrame == NULL);
|
||||
CHECK(releaseFrame(state, &result));
|
||||
return true;
|
||||
}
|
||||
|
||||
97
client/tests/lgmp_platform_test.c
Normal file
97
client/tests/lgmp_platform_test.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ivshmemGetDMABuf testIVSHMEMGetDMABuf
|
||||
#include "../transports/LGMP/platform/linux.c"
|
||||
#undef ivshmemGetDMABuf
|
||||
|
||||
static struct IVSHMEM * expectedDevice;
|
||||
static uint64_t expectedOffset;
|
||||
static uint64_t expectedSize;
|
||||
static int sourceFD;
|
||||
static unsigned int exportCalls;
|
||||
static bool exportFails;
|
||||
|
||||
int testIVSHMEMGetDMABuf(struct IVSHMEM * device, uint64_t offset,
|
||||
uint64_t size)
|
||||
{
|
||||
++exportCalls;
|
||||
CHECK(device == expectedDevice);
|
||||
CHECK(offset == expectedOffset);
|
||||
CHECK(size == expectedSize);
|
||||
return exportFails ? -1 : dup(sourceFD);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct IVSHMEM device = { 0 };
|
||||
|
||||
expectedDevice = &device;
|
||||
expectedOffset = 4096;
|
||||
expectedSize = 8192;
|
||||
sourceFD = open("/dev/null", O_RDONLY);
|
||||
CHECK(sourceFD >= 0);
|
||||
|
||||
LG_ExternalFrame * frame = lgmpPlatformCreateExternalFrame(
|
||||
&device, expectedOffset, expectedSize);
|
||||
CHECK(frame);
|
||||
CHECK(exportCalls == 1);
|
||||
CHECK(lgExternalFrameType(frame) == LG_EXTERNAL_FRAME_DMABUF);
|
||||
|
||||
int frameFD = -1;
|
||||
CHECK(lgExternalFrameQuery(frame, LG_EXTERNAL_FRAME_DMABUF,
|
||||
&frameFD, sizeof(frameFD)));
|
||||
CHECK(frameFD >= 0);
|
||||
CHECK(frameFD != sourceFD);
|
||||
CHECK(fcntl(frameFD, F_GETFD) != -1);
|
||||
CHECK(!lgExternalFrameQuery(frame, LG_EXTERNAL_FRAME_INVALID,
|
||||
&frameFD, sizeof(frameFD)));
|
||||
CHECK(!lgExternalFrameQuery(frame, LG_EXTERNAL_FRAME_DMABUF,
|
||||
NULL, sizeof(frameFD)));
|
||||
CHECK(!lgExternalFrameQuery(frame, LG_EXTERNAL_FRAME_DMABUF,
|
||||
&frameFD, sizeof(frameFD) - 1));
|
||||
|
||||
CHECK(lgExternalFrameRetain(frame) == frame);
|
||||
lgExternalFrameRelease(frame);
|
||||
CHECK(fcntl(frameFD, F_GETFD) != -1);
|
||||
|
||||
lgExternalFrameRelease(frame);
|
||||
errno = 0;
|
||||
CHECK(fcntl(frameFD, F_GETFD) == -1);
|
||||
CHECK(errno == EBADF);
|
||||
CHECK(fcntl(sourceFD, F_GETFD) != -1);
|
||||
|
||||
exportFails = true;
|
||||
CHECK(!lgmpPlatformCreateExternalFrame(
|
||||
&device, expectedOffset, expectedSize));
|
||||
CHECK(exportCalls == 2);
|
||||
|
||||
CHECK(close(sourceFD) == 0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -53,14 +53,66 @@ struct Trace
|
||||
unsigned int failFence;
|
||||
};
|
||||
|
||||
struct FakeExternalFrame
|
||||
{
|
||||
LG_ExternalFrame base;
|
||||
unsigned int refs;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct Releases
|
||||
{
|
||||
unsigned int count;
|
||||
uint64_t handle[MAX_REL];
|
||||
struct FakeExternalFrame externalFrame;
|
||||
unsigned int count;
|
||||
uint64_t handle[MAX_REL];
|
||||
};
|
||||
|
||||
static struct Trace t;
|
||||
|
||||
static void externalFrameRetain(LG_ExternalFrame * frame)
|
||||
{
|
||||
struct FakeExternalFrame * external = (struct FakeExternalFrame *)frame;
|
||||
CHECK(external->refs > 0);
|
||||
++external->refs;
|
||||
}
|
||||
|
||||
static void externalFrameRelease(LG_ExternalFrame * frame)
|
||||
{
|
||||
struct FakeExternalFrame * external = (struct FakeExternalFrame *)frame;
|
||||
CHECK(external->refs > 0);
|
||||
--external->refs;
|
||||
}
|
||||
|
||||
static bool externalFrameQuery(const LG_ExternalFrame * frame,
|
||||
void * result, size_t resultSize)
|
||||
{
|
||||
if (!result || resultSize != sizeof(int))
|
||||
return false;
|
||||
|
||||
const struct FakeExternalFrame * external =
|
||||
(const struct FakeExternalFrame *)frame;
|
||||
*(int *)result = external->fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const LG_ExternalFrameOps externalFrameOps =
|
||||
{
|
||||
.type = LG_EXTERNAL_FRAME_DMABUF,
|
||||
.retain = externalFrameRetain,
|
||||
.release = externalFrameRelease,
|
||||
.query = externalFrameQuery,
|
||||
};
|
||||
|
||||
static void externalFrameInit(struct FakeExternalFrame * external)
|
||||
{
|
||||
if (external->base.ops)
|
||||
return;
|
||||
|
||||
external->base.ops = &externalFrameOps;
|
||||
external->refs = 1;
|
||||
external->fd = 7;
|
||||
}
|
||||
|
||||
struct EGLDynProcs g_egl_dynProcs;
|
||||
_Thread_local EGL_StateCache g_eglState;
|
||||
|
||||
@@ -380,10 +432,7 @@ static TexDMABUF * newTex(void)
|
||||
LG_LOCK_INIT(texture->base.copyLock);
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(texture->images); ++i)
|
||||
{
|
||||
texture->images[i].fd = -1;
|
||||
texture->images[i].image = EGL_NO_IMAGE;
|
||||
}
|
||||
for (int i = 0; i < ARRAY_LENGTH(texture->snapshots); ++i)
|
||||
{
|
||||
texture->snapshots[i].texture = 200 + i;
|
||||
@@ -400,16 +449,21 @@ static TexDMABUF * newTex(void)
|
||||
static bool update(TexDMABUF * texture, LG_RendererFrameToken token,
|
||||
struct Releases * releases, uint64_t handle)
|
||||
{
|
||||
externalFrameInit(&releases->externalFrame);
|
||||
LG_ExternalFrame * externalFrame =
|
||||
lgExternalFrameRetain(&releases->externalFrame.base);
|
||||
const EGL_TexUpdate value =
|
||||
{
|
||||
.type = EGL_TEXTYPE_DMABUF,
|
||||
.frameToken = token,
|
||||
.externalFrame = externalFrame,
|
||||
.releaseFn = onRelease,
|
||||
.releaseOpaque = releases,
|
||||
.releaseHandle = handle,
|
||||
.dmaFD = 7,
|
||||
};
|
||||
return egl_texDMABUFUpdate(&texture->base.base, &value);
|
||||
const bool result = egl_texDMABUFUpdate(&texture->base.base, &value);
|
||||
lgExternalFrameRelease(externalFrame);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void setSlot(TexDMABUF * texture, int index,
|
||||
@@ -500,6 +554,7 @@ static void testPoll(void)
|
||||
CHECK(releases.count == 2);
|
||||
egl_texDMABUFFree(&texture->base.base);
|
||||
CHECK(releases.count == 2);
|
||||
CHECK(releases.externalFrame.refs == 1);
|
||||
}
|
||||
|
||||
static void testSaturation(void)
|
||||
@@ -533,6 +588,7 @@ static void testSaturation(void)
|
||||
|
||||
egl_texDMABUFFree(&texture->base.base);
|
||||
CHECK(releases.count == 6);
|
||||
CHECK(releases.externalFrame.refs == 1);
|
||||
for (uint64_t handle = 10; handle <= 60; handle += 10)
|
||||
CHECK(relCount(&releases, handle) == 1);
|
||||
}
|
||||
@@ -554,6 +610,24 @@ static void testRelease(void)
|
||||
egl_texDMABUFFree(&second->base.base);
|
||||
CHECK(relCount(&releases, 202) == 1);
|
||||
CHECK(releases.count == 2);
|
||||
CHECK(releases.externalFrame.refs == 1);
|
||||
}
|
||||
|
||||
static void testIdentity(void)
|
||||
{
|
||||
struct Releases first = { 0 };
|
||||
struct Releases second = { 0 };
|
||||
TexDMABUF * texture = newTex();
|
||||
|
||||
CHECK(update(texture, 1, &first, 1));
|
||||
CHECK(update(texture, 2, &second, 2));
|
||||
CHECK(t.imageNew == 2);
|
||||
|
||||
egl_texDMABUFFree(&texture->base.base);
|
||||
CHECK(first.count == 1);
|
||||
CHECK(second.count == 1);
|
||||
CHECK(first.externalFrame.refs == 1);
|
||||
CHECK(second.externalFrame.refs == 1);
|
||||
}
|
||||
|
||||
struct Test
|
||||
@@ -568,6 +642,7 @@ static const struct Test tests[] =
|
||||
{ "poll" , testPoll },
|
||||
{ "saturation", testSaturation },
|
||||
{ "release" , testRelease },
|
||||
{ "identity" , testIdentity },
|
||||
};
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
|
||||
Reference in New Issue
Block a user