mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-02 05:12:02 +00:00
[client] transport: introduce pluggable frame transports
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Move shared-memory ownership, LGMP session handling, queue access, and DMA setup behind a transport interface. The LGMP backend preserves the existing zero-copy frame and DMA paths while owning its lgmp:* options. Expose the initialized EGL context through a versioned renderer interop record for future accelerated decode backends. Add an LGMP-independent, deterministic test transport for graphics-pipeline validation.
This commit is contained in:
607
client/transports/Test/test.c
Normal file
607
client/transports/Test/test.c
Normal file
@@ -0,0 +1,607 @@
|
||||
/**
|
||||
* 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 "interface/transport.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "common/time.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TEST_BUFFER_COUNT 2
|
||||
#define TEST_PQ_LUT_SIZE 4096
|
||||
|
||||
struct TestFormat
|
||||
{
|
||||
const char * name;
|
||||
FrameType type;
|
||||
unsigned bytesPerPixel;
|
||||
bool hdr;
|
||||
bool hdrPQ;
|
||||
};
|
||||
|
||||
static const struct TestFormat testFormats[] =
|
||||
{
|
||||
{ "bgra" , FRAME_TYPE_BGRA , 4, false, false },
|
||||
{ "rgba" , FRAME_TYPE_RGBA , 4, false, false },
|
||||
{ "bgr32" , FRAME_TYPE_BGR_32 , 4, false, false },
|
||||
{ "rgb24" , FRAME_TYPE_RGB_24 , 3, false, false },
|
||||
{ "rgba10" , FRAME_TYPE_RGBA10 , 4, true , true },
|
||||
{ "rgba16f", FRAME_TYPE_RGBA16F, 8, true , false },
|
||||
};
|
||||
|
||||
struct TestBuffer
|
||||
{
|
||||
FrameBuffer * framebuffer;
|
||||
};
|
||||
|
||||
struct LG_Transport
|
||||
{
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned frameRate;
|
||||
unsigned frameCount;
|
||||
bool realtime;
|
||||
bool cycleFormats;
|
||||
unsigned formatIndex;
|
||||
|
||||
bool connected;
|
||||
bool framePending;
|
||||
uint64_t serial;
|
||||
uint64_t nextFrameTime;
|
||||
unsigned bufferIndex;
|
||||
struct TestBuffer buffers[TEST_BUFFER_COUNT];
|
||||
FrameDamageRect damage[2];
|
||||
LG_TransportFrameFormat format;
|
||||
uint16_t pqLUT[TEST_PQ_LUT_SIZE + 1];
|
||||
};
|
||||
|
||||
static void test_setup(void)
|
||||
{
|
||||
static struct Option options[] =
|
||||
{
|
||||
{
|
||||
.module = "test",
|
||||
.name = "width",
|
||||
.description = "Generated frame width",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 1920,
|
||||
},
|
||||
{
|
||||
.module = "test",
|
||||
.name = "height",
|
||||
.description = "Generated frame height",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 1080,
|
||||
},
|
||||
{
|
||||
.module = "test",
|
||||
.name = "frameRate",
|
||||
.description = "Generated frames per second",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 60,
|
||||
},
|
||||
{
|
||||
.module = "test",
|
||||
.name = "frameCount",
|
||||
.description = "Stop after this many frames, or zero to run forever",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 0,
|
||||
},
|
||||
{
|
||||
.module = "test",
|
||||
.name = "realtime",
|
||||
.description = "Pace generated frames in real time",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true,
|
||||
},
|
||||
{
|
||||
.module = "test",
|
||||
.name = "format",
|
||||
.description = "Generated frame format: bgra, rgba, bgr32, rgb24, "
|
||||
"rgba10, rgba16f, or cycle",
|
||||
.type = OPTION_TYPE_STRING,
|
||||
.value.x_string = "bgra",
|
||||
},
|
||||
{0}
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static int test_findFormat(const char * name)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(testFormats); ++i)
|
||||
if (strcmp(name, testFormats[i].name) == 0)
|
||||
return (int)i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static float test_linearToPQ(float linear)
|
||||
{
|
||||
const float m1 = 2610.0f / 16384.0f;
|
||||
const float m2 = 2523.0f / 32.0f;
|
||||
const float c1 = 3424.0f / 4096.0f;
|
||||
const float c2 = 2413.0f / 128.0f;
|
||||
const float c3 = 2392.0f / 128.0f;
|
||||
const float p = powf(linear, m1);
|
||||
return powf((c1 + c2 * p) / (1.0f + c3 * p), m2);
|
||||
}
|
||||
|
||||
static void test_initPQLUT(struct LG_Transport * this)
|
||||
{
|
||||
for (unsigned i = 0; i <= TEST_PQ_LUT_SIZE; ++i)
|
||||
{
|
||||
/* scRGB uses 1.0 for 80 nits; PQ uses 1.0 for 10000 nits. */
|
||||
const float scRGB = (float)i * 4.0f / TEST_PQ_LUT_SIZE;
|
||||
const float pq = test_linearToPQ(scRGB / 125.0f);
|
||||
this->pqLUT[i] = (uint16_t)(pq * 1023.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t test_scRGBToPQ(const struct LG_Transport * this, float scRGB)
|
||||
{
|
||||
const unsigned index = scRGB <= 0.0f ? 0 : scRGB >= 4.0f ?
|
||||
TEST_PQ_LUT_SIZE :
|
||||
(unsigned)(scRGB * (TEST_PQ_LUT_SIZE / 4.0f) + 0.5f);
|
||||
return this->pqLUT[index];
|
||||
}
|
||||
|
||||
static void test_setHDRMetadata(LG_TransportFrameFormat * format)
|
||||
{
|
||||
if (format->hdrPQ)
|
||||
{
|
||||
format->hdrDisplayPrimary[0][0] = 35400;
|
||||
format->hdrDisplayPrimary[0][1] = 14600;
|
||||
format->hdrDisplayPrimary[1][0] = 8500;
|
||||
format->hdrDisplayPrimary[1][1] = 39850;
|
||||
format->hdrDisplayPrimary[2][0] = 6550;
|
||||
format->hdrDisplayPrimary[2][1] = 2300;
|
||||
format->hdrMaxDisplayLuminance = 1000;
|
||||
format->hdrMinDisplayLuminance = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
format->hdrDisplayPrimary[0][0] = 13250;
|
||||
format->hdrDisplayPrimary[0][1] = 34500;
|
||||
format->hdrDisplayPrimary[1][0] = 7500;
|
||||
format->hdrDisplayPrimary[1][1] = 30000;
|
||||
format->hdrDisplayPrimary[2][0] = 34000;
|
||||
format->hdrDisplayPrimary[2][1] = 16000;
|
||||
format->hdrMaxDisplayLuminance = 80;
|
||||
format->hdrMinDisplayLuminance = 50;
|
||||
}
|
||||
|
||||
format->hdrWhitePoint[0] = 15635;
|
||||
format->hdrWhitePoint[1] = 16450;
|
||||
format->hdrMaxContentLightLevel = 1000;
|
||||
format->hdrMaxFrameAverageLightLevel = 400;
|
||||
}
|
||||
|
||||
static bool test_setFormat(struct LG_Transport * this, unsigned index)
|
||||
{
|
||||
if (this->format.version && this->formatIndex == index)
|
||||
return false;
|
||||
|
||||
const struct TestFormat * testFormat = &testFormats[index];
|
||||
const uint32_t version = this->format.version + 1;
|
||||
const bool packedBGR =
|
||||
testFormat->type == FRAME_TYPE_BGR_32;
|
||||
const unsigned pitch = packedBGR ?
|
||||
ALIGN_PAD(this->width * 3, 4) :
|
||||
this->width * testFormat->bytesPerPixel;
|
||||
|
||||
this->formatIndex = index;
|
||||
this->format = (LG_TransportFrameFormat) {
|
||||
.version = version,
|
||||
.type = testFormat->type,
|
||||
.screenWidth = this->width,
|
||||
.screenHeight = this->height,
|
||||
.dataWidth = packedBGR ? pitch / 4 : this->width,
|
||||
.dataHeight = this->height,
|
||||
.frameWidth = this->width,
|
||||
.frameHeight = this->height,
|
||||
.rotation = FRAME_ROT_0,
|
||||
.stride = packedBGR ? pitch / 4 : this->width,
|
||||
.pitch = pitch,
|
||||
.hdr = testFormat->hdr,
|
||||
.hdrPQ = testFormat->hdrPQ,
|
||||
.hdrMetadata = testFormat->hdr,
|
||||
.sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT,
|
||||
};
|
||||
|
||||
if (this->format.hdrMetadata)
|
||||
test_setHDRMetadata(&this->format);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_create(LG_Transport ** result)
|
||||
{
|
||||
struct LG_Transport * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
return false;
|
||||
|
||||
const int width = option_get_int("test", "width");
|
||||
const int height = option_get_int("test", "height");
|
||||
const int frameRate = option_get_int("test", "frameRate");
|
||||
const int frameCount = option_get_int("test", "frameCount");
|
||||
const char * format = option_get_string("test", "format");
|
||||
const bool cycleFormats = strcmp(format, "cycle") == 0;
|
||||
const int formatIndex = cycleFormats ? 0 : test_findFormat(format);
|
||||
const unsigned maxBytesPerPixel = formatIndex < 0 ? 0 :
|
||||
cycleFormats ? 8 : testFormats[formatIndex].bytesPerPixel;
|
||||
if (width < 1 || height < 1 || !maxBytesPerPixel ||
|
||||
width > (int)(UINT32_MAX / maxBytesPerPixel) ||
|
||||
frameRate < 1 || frameRate > 1000000000 || frameCount < 0 ||
|
||||
(size_t)width > (SIZE_MAX - sizeof(FrameBuffer)) /
|
||||
maxBytesPerPixel / (size_t)height)
|
||||
{
|
||||
DEBUG_ERROR(
|
||||
"Invalid test transport dimensions, rate, frame count, or format");
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->frameRate = frameRate;
|
||||
this->frameCount = frameCount;
|
||||
this->realtime = option_get_bool("test", "realtime");
|
||||
this->cycleFormats = cycleFormats;
|
||||
this->formatIndex = (unsigned)formatIndex;
|
||||
test_initPQLUT(this);
|
||||
|
||||
const size_t dataSize =
|
||||
(size_t)this->width * this->height * maxBytesPerPixel;
|
||||
for (unsigned i = 0; i < TEST_BUFFER_COUNT; ++i)
|
||||
{
|
||||
this->buffers[i].framebuffer = malloc(sizeof(FrameBuffer) + dataSize);
|
||||
if (!this->buffers[i].framebuffer)
|
||||
{
|
||||
for (unsigned j = 0; j < i; ++j)
|
||||
free(this->buffers[j].framebuffer);
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*result = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_destroy(LG_Transport ** transport)
|
||||
{
|
||||
if (!transport || !*transport)
|
||||
return;
|
||||
|
||||
struct LG_Transport * this = *transport;
|
||||
for (unsigned i = 0; i < TEST_BUFFER_COUNT; ++i)
|
||||
free(this->buffers[i].framebuffer);
|
||||
free(this);
|
||||
*transport = NULL;
|
||||
}
|
||||
|
||||
static LG_TransportStatus test_connect(LG_Transport * this,
|
||||
LG_TransportSession * session)
|
||||
{
|
||||
memset(session, 0, sizeof(*session));
|
||||
memcpy(session->version, "test", 5);
|
||||
session->os = LG_TRANSPORT_OS_OTHER;
|
||||
memcpy(session->capture, "test", 5);
|
||||
|
||||
this->connected = true;
|
||||
this->framePending = false;
|
||||
this->serial = 0;
|
||||
this->bufferIndex = 0;
|
||||
this->nextFrameTime = nanotime();
|
||||
this->format.version = 0;
|
||||
test_setFormat(this, this->formatIndex);
|
||||
return LG_TRANSPORT_OK;
|
||||
}
|
||||
|
||||
static void test_disconnect(LG_Transport * this)
|
||||
{
|
||||
this->connected = false;
|
||||
this->framePending = false;
|
||||
}
|
||||
|
||||
static bool test_sessionValid(LG_Transport * this)
|
||||
{
|
||||
return this->connected;
|
||||
}
|
||||
|
||||
static bool test_supportsDMA(LG_Transport * this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool test_attachRenderer(LG_Transport * this,
|
||||
const LG_RendererInterop * interop)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_detachRenderer(LG_Transport * this)
|
||||
{
|
||||
}
|
||||
|
||||
static uint16_t test_floatToHalf(float value)
|
||||
{
|
||||
union
|
||||
{
|
||||
float value;
|
||||
uint32_t bits;
|
||||
}
|
||||
input = { .value = value };
|
||||
|
||||
const uint16_t sign = (input.bits >> 16) & 0x8000;
|
||||
int exponent = ((input.bits >> 23) & 0xff) - 127 + 15;
|
||||
uint32_t mantissa = input.bits & 0x7fffff;
|
||||
if (exponent <= 0)
|
||||
return sign;
|
||||
if (exponent >= 31)
|
||||
return sign | 0x7c00;
|
||||
|
||||
mantissa += 0x1000;
|
||||
if (mantissa & 0x800000)
|
||||
{
|
||||
mantissa = 0;
|
||||
if (++exponent >= 31)
|
||||
return sign | 0x7c00;
|
||||
}
|
||||
|
||||
return sign | ((uint16_t)exponent << 10) | (mantissa >> 13);
|
||||
}
|
||||
|
||||
static void test_getColor(const struct LG_Transport * this,
|
||||
unsigned x, unsigned y, uint8_t * r, uint8_t * g, uint8_t * b)
|
||||
{
|
||||
const unsigned widthRange = this->width > 1 ? this->width - 1 : 1;
|
||||
const unsigned heightRange = this->height > 1 ? this->height - 1 : 1;
|
||||
*r = (uint64_t)x * 255 / widthRange;
|
||||
*g = (uint64_t)y * 255 / heightRange;
|
||||
*b = ((x / 32) ^ (y / 32)) & 1 ? 0x30 : 0x90;
|
||||
|
||||
unsigned boxSize = this->width < this->height ?
|
||||
this->width : this->height;
|
||||
if (boxSize > 64)
|
||||
boxSize = 64;
|
||||
const unsigned rangeX = this->width > boxSize ? this->width - boxSize : 1;
|
||||
const unsigned rangeY = this->height > boxSize ?
|
||||
this->height - boxSize : 1;
|
||||
const unsigned boxX = (this->serial * 7) % rangeX;
|
||||
const unsigned boxY = (this->serial * 5) % rangeY;
|
||||
if (x < boxX || y < boxY || x >= boxX + boxSize || y >= boxY + boxSize)
|
||||
return;
|
||||
|
||||
const uint32_t color = this->serial * 2654435761U;
|
||||
*r = color >> 16;
|
||||
*g = color >> 8;
|
||||
*b = color;
|
||||
}
|
||||
|
||||
static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
||||
{
|
||||
uint8_t * data = framebuffer_get_data(fb);
|
||||
if (this->format.type == FRAME_TYPE_BGR_32)
|
||||
memset(data, 0, (size_t)this->format.pitch * this->height);
|
||||
|
||||
for (unsigned y = 0; y < this->height; ++y)
|
||||
for (unsigned x = 0; x < this->width; ++x)
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
test_getColor(this, x, y, &r, &g, &b);
|
||||
const size_t pixel = (size_t)y * this->width + x;
|
||||
switch (this->format.type)
|
||||
{
|
||||
case FRAME_TYPE_BGRA:
|
||||
((uint32_t *)data)[pixel] =
|
||||
0xff000000U | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_BGR_32:
|
||||
{
|
||||
uint8_t * bgr = data + (size_t)y * this->format.pitch + x * 3;
|
||||
bgr[0] = b;
|
||||
bgr[1] = g;
|
||||
bgr[2] = r;
|
||||
break;
|
||||
}
|
||||
|
||||
case FRAME_TYPE_RGBA:
|
||||
((uint32_t *)data)[pixel] =
|
||||
0xff000000U | ((uint32_t)b << 16) | ((uint32_t)g << 8) | r;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_RGB_24:
|
||||
data[pixel * 3 ] = r;
|
||||
data[pixel * 3 + 1] = g;
|
||||
data[pixel * 3 + 2] = b;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_RGBA10:
|
||||
{
|
||||
const float r709 = (float)r * 4.0f / 255.0f;
|
||||
const float g709 = (float)g * 4.0f / 255.0f;
|
||||
const float b709 = (float)b * 4.0f / 255.0f;
|
||||
const float r2020 =
|
||||
r709 * 0.6274039f + g709 * 0.3292830f + b709 * 0.0433131f;
|
||||
const float g2020 =
|
||||
r709 * 0.0690973f + g709 * 0.9195404f + b709 * 0.0113623f;
|
||||
const float b2020 =
|
||||
r709 * 0.0163914f + g709 * 0.0880133f + b709 * 0.8955953f;
|
||||
((uint32_t *)data)[pixel] =
|
||||
((uint32_t)test_scRGBToPQ(this, r2020) ) |
|
||||
((uint32_t)test_scRGBToPQ(this, g2020) << 10) |
|
||||
((uint32_t)test_scRGBToPQ(this, b2020) << 20) |
|
||||
(3U << 30);
|
||||
break;
|
||||
}
|
||||
|
||||
case FRAME_TYPE_RGBA16F:
|
||||
{
|
||||
uint16_t * rgba = (uint16_t *)data + pixel * 4;
|
||||
rgba[0] = test_floatToHalf((float)r * 4.0f / 255.0f);
|
||||
rgba[1] = test_floatToHalf((float)g * 4.0f / 255.0f);
|
||||
rgba[2] = test_floatToHalf((float)b * 4.0f / 255.0f);
|
||||
rgba[3] = test_floatToHalf(1.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
DEBUG_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
framebuffer_set_write_ptr(fb, (size_t)this->format.pitch * this->height);
|
||||
}
|
||||
|
||||
static LG_TransportStatus test_nextFrame(LG_Transport * this, bool useDMA,
|
||||
LG_TransportFrame * frame)
|
||||
{
|
||||
if (!this->connected)
|
||||
return LG_TRANSPORT_DISCONNECTED;
|
||||
if (this->framePending)
|
||||
return LG_TRANSPORT_ERROR;
|
||||
if (this->frameCount && this->serial >= this->frameCount)
|
||||
return LG_TRANSPORT_END;
|
||||
|
||||
if (this->realtime)
|
||||
{
|
||||
const uint64_t now = nanotime();
|
||||
if (now < this->nextFrameTime)
|
||||
{
|
||||
const uint64_t remaining = this->nextFrameTime - now;
|
||||
usleep((remaining > 1000000 ? 1000000 : remaining) / 1000);
|
||||
return LG_TRANSPORT_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
const bool formatChanged = this->cycleFormats && test_setFormat(this,
|
||||
this->serial % ARRAY_LENGTH(testFormats));
|
||||
++this->serial;
|
||||
struct TestBuffer * buffer = &this->buffers[this->bufferIndex];
|
||||
this->bufferIndex = (this->bufferIndex + 1) % TEST_BUFFER_COUNT;
|
||||
framebuffer_prepare(buffer->framebuffer);
|
||||
test_generateFrame(this, buffer->framebuffer);
|
||||
|
||||
memset(frame, 0, sizeof(*frame));
|
||||
frame->serial = this->serial;
|
||||
frame->timestamp = this->realtime ? nanotime() :
|
||||
this->serial * (1000000000ULL / this->frameRate);
|
||||
frame->format = &this->format;
|
||||
frame->framebuffer = buffer->framebuffer;
|
||||
frame->dmaFD = -1;
|
||||
|
||||
if (this->serial == 1 || formatChanged)
|
||||
frame->damageRectsCount = 0;
|
||||
else
|
||||
{
|
||||
unsigned boxSize = this->width < this->height ?
|
||||
this->width : this->height;
|
||||
if (boxSize > 64)
|
||||
boxSize = 64;
|
||||
const unsigned rangeX = this->width > boxSize ?
|
||||
this->width - boxSize : 1;
|
||||
const unsigned rangeY = this->height > boxSize ?
|
||||
this->height - boxSize : 1;
|
||||
this->damage[0] = (FrameDamageRect) {
|
||||
.x = ((this->serial - 1) * 7) % rangeX,
|
||||
.y = ((this->serial - 1) * 5) % rangeY,
|
||||
.width = boxSize,
|
||||
.height = boxSize,
|
||||
};
|
||||
this->damage[1] = (FrameDamageRect) {
|
||||
.x = (this->serial * 7) % rangeX,
|
||||
.y = (this->serial * 5) % rangeY,
|
||||
.width = boxSize,
|
||||
.height = boxSize,
|
||||
};
|
||||
frame->damageRects = this->damage;
|
||||
frame->damageRectsCount = 2;
|
||||
}
|
||||
|
||||
this->framePending = true;
|
||||
this->nextFrameTime += 1000000000ULL / this->frameRate;
|
||||
return LG_TRANSPORT_OK;
|
||||
}
|
||||
|
||||
static void test_releaseFrame(LG_Transport * this, LG_TransportFrame * frame)
|
||||
{
|
||||
this->framePending = false;
|
||||
memset(frame, 0, sizeof(*frame));
|
||||
}
|
||||
|
||||
static LG_TransportStatus test_nextPointer(LG_Transport * this,
|
||||
LG_TransportPointer * pointer)
|
||||
{
|
||||
if (!this->connected)
|
||||
return LG_TRANSPORT_DISCONNECTED;
|
||||
usleep(1000);
|
||||
return LG_TRANSPORT_TIMEOUT;
|
||||
}
|
||||
|
||||
static void test_releasePointer(LG_Transport * this,
|
||||
LG_TransportPointer * pointer)
|
||||
{
|
||||
}
|
||||
|
||||
static LG_TransportStatus test_sendControl(LG_Transport * this,
|
||||
const LG_TransportControl * control, LG_TransportControlToken * token)
|
||||
{
|
||||
if (!this->connected)
|
||||
return LG_TRANSPORT_DISCONNECTED;
|
||||
return LG_TRANSPORT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
static LG_TransportStatus test_controlStatus(LG_Transport * this,
|
||||
LG_TransportControlToken token)
|
||||
{
|
||||
return this->connected ? LG_TRANSPORT_UNAVAILABLE :
|
||||
LG_TRANSPORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
const LG_TransportOps LGT_Test =
|
||||
{
|
||||
.name = "test",
|
||||
.setup = test_setup,
|
||||
.create = test_create,
|
||||
.destroy = test_destroy,
|
||||
.connect = test_connect,
|
||||
.disconnect = test_disconnect,
|
||||
.sessionValid = test_sessionValid,
|
||||
.supportsDMA = test_supportsDMA,
|
||||
.attachRenderer = test_attachRenderer,
|
||||
.detachRenderer = test_detachRenderer,
|
||||
.nextFrame = test_nextFrame,
|
||||
.releaseFrame = test_releaseFrame,
|
||||
.nextPointer = test_nextPointer,
|
||||
.releasePointer = test_releasePointer,
|
||||
.sendControl = test_sendControl,
|
||||
.controlStatus = test_controlStatus,
|
||||
};
|
||||
Reference in New Issue
Block a user