mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 15:27:21 +00:00
[client] network: bound video decoder backlog
Cap decoded snapshots and queued GPU work so a slow presentation path cannot accumulate frames indefinitely. Coalesce deferred damage and retry the latest image when a texture returns, including while JIT rendering is idle.
This commit is contained in:
@@ -143,6 +143,21 @@ struct NetworkVideoEncoded
|
|||||||
LGNetVideoSchedule schedule;
|
LGNetVideoSchedule schedule;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NetworkVideoDeferred
|
||||||
|
{
|
||||||
|
uint64_t decodeGeneration;
|
||||||
|
uint64_t configEpoch;
|
||||||
|
uint64_t frameID;
|
||||||
|
uint64_t epoch;
|
||||||
|
uint64_t timestamp;
|
||||||
|
uint64_t captureTimestampNs;
|
||||||
|
uint64_t presentationTimestampNs;
|
||||||
|
uint64_t receiveTimeNs;
|
||||||
|
uint32_t formatVersion;
|
||||||
|
bool complete;
|
||||||
|
bool valid;
|
||||||
|
};
|
||||||
|
|
||||||
struct NetworkVideo
|
struct NetworkVideo
|
||||||
{
|
{
|
||||||
NetworkConnection * connection;
|
NetworkConnection * connection;
|
||||||
@@ -165,6 +180,7 @@ struct NetworkVideo
|
|||||||
bool waitCancelled;
|
bool waitCancelled;
|
||||||
bool decodeStopping;
|
bool decodeStopping;
|
||||||
bool decodePending;
|
bool decodePending;
|
||||||
|
bool framePollPending;
|
||||||
uint16_t serviceVersion;
|
uint16_t serviceVersion;
|
||||||
|
|
||||||
uint64_t subscriberID;
|
uint64_t subscriberID;
|
||||||
@@ -192,6 +208,7 @@ struct NetworkVideo
|
|||||||
|
|
||||||
struct NetworkVideoAssembly assembly;
|
struct NetworkVideoAssembly assembly;
|
||||||
struct NetworkVideoEncoded pendingDecode;
|
struct NetworkVideoEncoded pendingDecode;
|
||||||
|
struct NetworkVideoDeferred deferred;
|
||||||
struct NetworkVideoScheduleEntry schedules[NETWORK_VIDEO_SCHEDULE_CACHE];
|
struct NetworkVideoScheduleEntry schedules[NETWORK_VIDEO_SCHEDULE_CACHE];
|
||||||
struct NetworkVideoOutput * output;
|
struct NetworkVideoOutput * output;
|
||||||
struct NetworkVideoOutput * leases;
|
struct NetworkVideoOutput * leases;
|
||||||
@@ -354,6 +371,39 @@ static void networkVideoClearEncoded(struct NetworkVideoEncoded * encoded)
|
|||||||
memset(encoded, 0, sizeof(*encoded));
|
memset(encoded, 0, sizeof(*encoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void networkVideoDeferNL(NetworkVideo * video,
|
||||||
|
const struct NetworkVideoEncoded * encoded)
|
||||||
|
{
|
||||||
|
video->deferred = (struct NetworkVideoDeferred)
|
||||||
|
{
|
||||||
|
.decodeGeneration = encoded->generation,
|
||||||
|
.configEpoch = encoded->config.configEpoch,
|
||||||
|
.frameID = encoded->frameID,
|
||||||
|
.epoch = video->status.epoch,
|
||||||
|
.timestamp = encoded->presentationTimestampNs,
|
||||||
|
.captureTimestampNs = encoded->captureTimestampNs,
|
||||||
|
.presentationTimestampNs = encoded->presentationTimestampNs,
|
||||||
|
.receiveTimeNs = encoded->receiveTimeNs,
|
||||||
|
.formatVersion = video->localConfigGeneration,
|
||||||
|
.complete = encoded->complete,
|
||||||
|
.valid = true,
|
||||||
|
};
|
||||||
|
video->framePollPending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool networkVideoDeferredCurrentNL(
|
||||||
|
const NetworkVideo * video, const struct NetworkVideoDeferred * deferred)
|
||||||
|
{
|
||||||
|
return deferred->valid && video->deferred.valid &&
|
||||||
|
deferred->decodeGeneration == video->deferred.decodeGeneration &&
|
||||||
|
deferred->configEpoch == video->deferred.configEpoch &&
|
||||||
|
deferred->frameID == video->deferred.frameID &&
|
||||||
|
deferred->epoch == video->deferred.epoch &&
|
||||||
|
video->decodeGeneration == deferred->decodeGeneration &&
|
||||||
|
video->config.configEpoch == deferred->configEpoch &&
|
||||||
|
video->status.epoch == deferred->epoch;
|
||||||
|
}
|
||||||
|
|
||||||
static void networkVideoInvalidateDecodeNL(NetworkVideo * video,
|
static void networkVideoInvalidateDecodeNL(NetworkVideo * video,
|
||||||
struct NetworkVideoEncoded * pending)
|
struct NetworkVideoEncoded * pending)
|
||||||
{
|
{
|
||||||
@@ -361,6 +411,8 @@ static void networkVideoInvalidateDecodeNL(NetworkVideo * video,
|
|||||||
*pending = video->pendingDecode;
|
*pending = video->pendingDecode;
|
||||||
video->pendingDecode = (struct NetworkVideoEncoded){0};
|
video->pendingDecode = (struct NetworkVideoEncoded){0};
|
||||||
video->decodePending = false;
|
video->decodePending = false;
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct NetworkVideoOutput * networkVideoFindLeaseNL(
|
static struct NetworkVideoOutput * networkVideoFindLeaseNL(
|
||||||
@@ -1102,7 +1154,10 @@ static void networkVideoDecodeFailure(NetworkVideo * video,
|
|||||||
video->wireConfigured &&
|
video->wireConfigured &&
|
||||||
video->config.configEpoch == encoded->config.configEpoch)
|
video->config.configEpoch == encoded->config.configEpoch)
|
||||||
{
|
{
|
||||||
video->lostFrames = networkVideoSaturatingIncrement(video->lostFrames);
|
video->lostFrames = networkVideoSaturatingIncrement(
|
||||||
|
video->lostFrames);
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
|
|
||||||
const LGNetVideoFeedbackFlags flags = result ==
|
const LGNetVideoFeedbackFlags flags = result ==
|
||||||
NETWORK_VIDEO_DECODE_ERROR ?
|
NETWORK_VIDEO_DECODE_ERROR ?
|
||||||
@@ -1141,24 +1196,18 @@ static void networkVideoDecode(NetworkVideo * video,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NetworkVideoOutput * output = calloc(1, sizeof(*output));
|
|
||||||
if (!output)
|
|
||||||
{
|
|
||||||
free(encoded->ownedData);
|
|
||||||
networkVideoDecodeFailure(
|
|
||||||
video, encoded, NETWORK_VIDEO_DECODE_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkVideoDecodedFrame decoded = {0};
|
NetworkVideoDecodedFrame decoded = {0};
|
||||||
const NetworkVideoDecodeResult result = networkVideoDecoderDecode(
|
const NetworkVideoDecodeResult result = networkVideoDecoderDecode(
|
||||||
video->decoder, &encoded->config, encoded->data,
|
video->decoder, &encoded->config, encoded->data,
|
||||||
encoded->length, encoded->blockCount, encoded->update,
|
encoded->length, encoded->blockCount, encoded->update,
|
||||||
encoded->complete, encoded->baseFrameID, encoded->frameID, &decoded);
|
encoded->complete, encoded->baseFrameID, encoded->frameID, &decoded);
|
||||||
free(encoded->ownedData);
|
free(encoded->ownedData);
|
||||||
if (result == NETWORK_VIDEO_DECODE_NO_FRAME)
|
encoded->ownedData = NULL;
|
||||||
|
encoded->data = NULL;
|
||||||
|
if (result == NETWORK_VIDEO_DECODE_NO_FRAME ||
|
||||||
|
result == NETWORK_VIDEO_DECODE_DEFERRED)
|
||||||
{
|
{
|
||||||
free(output);
|
bool pollFrame = false;
|
||||||
LG_LOCK(video->stateLock);
|
LG_LOCK(video->stateLock);
|
||||||
if (video->decodeGeneration == encoded->generation &&
|
if (video->decodeGeneration == encoded->generation &&
|
||||||
video->wireConfigured &&
|
video->wireConfigured &&
|
||||||
@@ -1169,18 +1218,33 @@ static void networkVideoDecode(NetworkVideo * video,
|
|||||||
if (encoded->complete)
|
if (encoded->complete)
|
||||||
video->lastCompleteFrameID = encoded->frameID;
|
video->lastCompleteFrameID = encoded->frameID;
|
||||||
video->lastDecodedFrameID = encoded->frameID;
|
video->lastDecodedFrameID = encoded->frameID;
|
||||||
|
if (result == NETWORK_VIDEO_DECODE_DEFERRED)
|
||||||
|
{
|
||||||
|
networkVideoDeferNL(video, encoded);
|
||||||
|
pollFrame = true;
|
||||||
|
}
|
||||||
networkVideoQueueFeedbackNL(video, 0);
|
networkVideoQueueFeedbackNL(video, 0);
|
||||||
}
|
}
|
||||||
LG_UNLOCK(video->stateLock);
|
LG_UNLOCK(video->stateLock);
|
||||||
|
if (pollFrame)
|
||||||
|
lgSignalEvent(video->frameEvent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result != NETWORK_VIDEO_DECODE_OK)
|
if (result != NETWORK_VIDEO_DECODE_OK)
|
||||||
{
|
{
|
||||||
free(output);
|
|
||||||
networkVideoDecodeFailure(video, encoded, result);
|
networkVideoDecodeFailure(video, encoded, result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NetworkVideoOutput * output = calloc(1, sizeof(*output));
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
networkVideoDecoderRelease(&decoded);
|
||||||
|
networkVideoDecodeFailure(
|
||||||
|
video, encoded, NETWORK_VIDEO_DECODE_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct NetworkVideoOutput * replaced = NULL;
|
struct NetworkVideoOutput * replaced = NULL;
|
||||||
output->decoded = decoded;
|
output->decoded = decoded;
|
||||||
output->frameID = encoded->frameID;
|
output->frameID = encoded->frameID;
|
||||||
@@ -1209,6 +1273,8 @@ static void networkVideoDecode(NetworkVideo * video,
|
|||||||
if (encoded->complete)
|
if (encoded->complete)
|
||||||
video->lastCompleteFrameID = output->frameID;
|
video->lastCompleteFrameID = output->frameID;
|
||||||
video->lastDecodedFrameID = output->frameID;
|
video->lastDecodedFrameID = output->frameID;
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
output->decoded.format.version = video->localConfigGeneration;
|
output->decoded.format.version = video->localConfigGeneration;
|
||||||
output->epoch = video->status.epoch;
|
output->epoch = video->status.epoch;
|
||||||
video->output = output;
|
video->output = output;
|
||||||
@@ -1218,6 +1284,101 @@ static void networkVideoDecode(NetworkVideo * video,
|
|||||||
lgSignalEvent(video->frameEvent);
|
lgSignalEvent(video->frameEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool networkVideoPresentDeferred(NetworkVideo * video,
|
||||||
|
const struct NetworkVideoDeferred * deferred)
|
||||||
|
{
|
||||||
|
LG_LOCK(video->stateLock);
|
||||||
|
const bool current = !video->destroying && !video->decodeStopping &&
|
||||||
|
video->connected && video->wireConfigured && video->rendererAttached &&
|
||||||
|
video->decoderReady && networkVideoDeferredCurrentNL(video, deferred);
|
||||||
|
LG_UNLOCK(video->stateLock);
|
||||||
|
if (!current)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NetworkVideoDecodedFrame decoded = {0};
|
||||||
|
const NetworkVideoDecodeResult result =
|
||||||
|
networkVideoDecoderPresentPending(video->decoder, &decoded);
|
||||||
|
if (result == NETWORK_VIDEO_DECODE_DEFERRED)
|
||||||
|
return false;
|
||||||
|
if (result == NETWORK_VIDEO_DECODE_NO_FRAME)
|
||||||
|
{
|
||||||
|
LG_LOCK(video->stateLock);
|
||||||
|
if (networkVideoDeferredCurrentNL(video, deferred))
|
||||||
|
{
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
|
}
|
||||||
|
LG_UNLOCK(video->stateLock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != NETWORK_VIDEO_DECODE_OK)
|
||||||
|
{
|
||||||
|
struct NetworkVideoEncoded encoded = {0};
|
||||||
|
encoded.config.configEpoch = deferred->configEpoch;
|
||||||
|
encoded.generation = deferred->decodeGeneration;
|
||||||
|
encoded.frameID = deferred->frameID;
|
||||||
|
encoded.complete = deferred->complete;
|
||||||
|
LG_LOCK(video->stateLock);
|
||||||
|
if (networkVideoDeferredCurrentNL(video, deferred))
|
||||||
|
{
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
|
}
|
||||||
|
LG_UNLOCK(video->stateLock);
|
||||||
|
networkVideoDecodeFailure(video, &encoded, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NetworkVideoOutput * output = calloc(1, sizeof(*output));
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
struct NetworkVideoEncoded encoded = {0};
|
||||||
|
encoded.config.configEpoch = deferred->configEpoch;
|
||||||
|
encoded.generation = deferred->decodeGeneration;
|
||||||
|
encoded.frameID = deferred->frameID;
|
||||||
|
encoded.complete = deferred->complete;
|
||||||
|
networkVideoDecoderRelease(&decoded);
|
||||||
|
networkVideoDecodeFailure(
|
||||||
|
video, &encoded, NETWORK_VIDEO_DECODE_ERROR);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NetworkVideoOutput * replaced = NULL;
|
||||||
|
output->decoded = decoded;
|
||||||
|
output->frameID = deferred->frameID;
|
||||||
|
output->timestamp = deferred->timestamp;
|
||||||
|
output->captureTimestampNs = deferred->captureTimestampNs;
|
||||||
|
output->presentationTimestampNs = deferred->presentationTimestampNs;
|
||||||
|
output->receiveTimeNs = deferred->receiveTimeNs;
|
||||||
|
LG_LOCK(video->stateLock);
|
||||||
|
if (!networkVideoDeferredCurrentNL(video, deferred) ||
|
||||||
|
output->frameID != video->lastDecodedFrameID ||
|
||||||
|
!video->rendererAttached || !video->decoderReady)
|
||||||
|
{
|
||||||
|
LG_UNLOCK(video->stateLock);
|
||||||
|
networkVideoFreeOutput(&output);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video->output)
|
||||||
|
{
|
||||||
|
video->lostFrames = networkVideoSaturatingIncrement(video->lostFrames);
|
||||||
|
replaced = video->output;
|
||||||
|
networkVideoMergeDamage(&output->decoded, &replaced->decoded);
|
||||||
|
}
|
||||||
|
output->decoded.format.version = deferred->formatVersion;
|
||||||
|
output->epoch = deferred->epoch;
|
||||||
|
video->output = output;
|
||||||
|
video->framePollPending = false;
|
||||||
|
memset(&video->deferred, 0, sizeof(video->deferred));
|
||||||
|
networkVideoQueueFeedbackNL(video, 0);
|
||||||
|
LG_UNLOCK(video->stateLock);
|
||||||
|
networkVideoFreeOutput(&replaced);
|
||||||
|
lgSignalEvent(video->frameEvent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void networkVideoQueueDecode(NetworkVideo * video,
|
static void networkVideoQueueDecode(NetworkVideo * video,
|
||||||
struct NetworkVideoEncoded * encoded)
|
struct NetworkVideoEncoded * encoded)
|
||||||
{
|
{
|
||||||
@@ -1283,7 +1444,8 @@ static int networkVideoDecodeThread(void * opaque)
|
|||||||
lgWaitEvent(video->decodeEvent, TIMEOUT_INFINITE);
|
lgWaitEvent(video->decodeEvent, TIMEOUT_INFINITE);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
struct NetworkVideoEncoded encoded = {0};
|
struct NetworkVideoEncoded encoded = {0};
|
||||||
|
struct NetworkVideoDeferred deferred = {0};
|
||||||
LG_LOCK(video->stateLock);
|
LG_LOCK(video->stateLock);
|
||||||
if (video->decodeStopping)
|
if (video->decodeStopping)
|
||||||
{
|
{
|
||||||
@@ -1300,11 +1462,18 @@ static int networkVideoDecodeThread(void * opaque)
|
|||||||
video->pendingDecode = (struct NetworkVideoEncoded){0};
|
video->pendingDecode = (struct NetworkVideoEncoded){0};
|
||||||
video->decodePending = false;
|
video->decodePending = false;
|
||||||
}
|
}
|
||||||
|
else if (video->deferred.valid)
|
||||||
|
deferred = video->deferred;
|
||||||
LG_UNLOCK(video->stateLock);
|
LG_UNLOCK(video->stateLock);
|
||||||
|
|
||||||
if (!encoded.ownedData)
|
if (encoded.ownedData)
|
||||||
|
{
|
||||||
|
networkVideoDecode(video, &encoded);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!deferred.valid ||
|
||||||
|
!networkVideoPresentDeferred(video, &deferred))
|
||||||
break;
|
break;
|
||||||
networkVideoDecode(video, &encoded);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1960,6 +2129,7 @@ void networkVideoProcess(NetworkVideo * video)
|
|||||||
const uint64_t now = nanotime();
|
const uint64_t now = nanotime();
|
||||||
struct NetworkVideoAssembly retiredAssembly = {0};
|
struct NetworkVideoAssembly retiredAssembly = {0};
|
||||||
struct NetworkVideoEncoded recovered = {0};
|
struct NetworkVideoEncoded recovered = {0};
|
||||||
|
bool pollFrame = false;
|
||||||
LG_LOCK(video->stateLock);
|
LG_LOCK(video->stateLock);
|
||||||
if (video->destroying)
|
if (video->destroying)
|
||||||
{
|
{
|
||||||
@@ -1978,10 +2148,17 @@ void networkVideoProcess(NetworkVideo * video)
|
|||||||
networkVideoSendSubscribeNL(video, now);
|
networkVideoSendSubscribeNL(video, now);
|
||||||
networkVideoSendKeyframeNL(video, now);
|
networkVideoSendKeyframeNL(video, now);
|
||||||
networkVideoSendFeedbackNL(video, now);
|
networkVideoSendFeedbackNL(video, now);
|
||||||
|
if (video->deferred.valid && !video->framePollPending)
|
||||||
|
{
|
||||||
|
video->framePollPending = true;
|
||||||
|
pollFrame = true;
|
||||||
|
}
|
||||||
LG_UNLOCK(video->stateLock);
|
LG_UNLOCK(video->stateLock);
|
||||||
networkVideoClearAssembly(&retiredAssembly);
|
networkVideoClearAssembly(&retiredAssembly);
|
||||||
if (recovered.ownedData)
|
if (recovered.ownedData)
|
||||||
networkVideoQueueDecode(video, &recovered);
|
networkVideoQueueDecode(video, &recovered);
|
||||||
|
if (pollFrame)
|
||||||
|
lgSignalEvent(video->frameEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool networkVideoTimer(void * opaque)
|
static bool networkVideoTimer(void * opaque)
|
||||||
@@ -2032,7 +2209,7 @@ bool networkVideoCreate(NetworkVideo ** result,
|
|||||||
video->frameEvent = lgCreateEvent(true, 0);
|
video->frameEvent = lgCreateEvent(true, 0);
|
||||||
video->decodeEvent = lgCreateEvent(true, 0);
|
video->decodeEvent = lgCreateEvent(true, 0);
|
||||||
if (!video->frameEvent || !video->decodeEvent ||
|
if (!video->frameEvent || !video->decodeEvent ||
|
||||||
!networkVideoDecoderCreate(&video->decoder) ||
|
!networkVideoDecoderCreate(&video->decoder, video->decodeEvent) ||
|
||||||
!lgCreateThread("networkDecode", networkVideoDecodeThread,
|
!lgCreateThread("networkDecode", networkVideoDecodeThread,
|
||||||
video, &video->decodeThread))
|
video, &video->decodeThread))
|
||||||
{
|
{
|
||||||
@@ -2324,6 +2501,12 @@ LG_TransportStatus networkVideoNextFrame(NetworkVideo * video, bool useDMA,
|
|||||||
frame->releaseHandle = output->handle;
|
frame->releaseHandle = output->handle;
|
||||||
ready = true;
|
ready = true;
|
||||||
}
|
}
|
||||||
|
else if (video->framePollPending)
|
||||||
|
{
|
||||||
|
video->framePollPending = false;
|
||||||
|
status = LG_TRANSPORT_TIMEOUT;
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LG_UNLOCK(video->stateLock);
|
LG_UNLOCK(video->stateLock);
|
||||||
networkVideoFreeOutputList(released);
|
networkVideoFreeOutputList(released);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "interface/renderer.h"
|
#include "interface/renderer.h"
|
||||||
#include "interface/transport.h"
|
#include "interface/transport.h"
|
||||||
|
|
||||||
|
#include "common/event.h"
|
||||||
|
|
||||||
#include <LGProtocol/NetworkServices.h>
|
#include <LGProtocol/NetworkServices.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -36,6 +38,7 @@ typedef enum NetworkVideoDecodeResult
|
|||||||
{
|
{
|
||||||
NETWORK_VIDEO_DECODE_OK,
|
NETWORK_VIDEO_DECODE_OK,
|
||||||
NETWORK_VIDEO_DECODE_NO_FRAME,
|
NETWORK_VIDEO_DECODE_NO_FRAME,
|
||||||
|
NETWORK_VIDEO_DECODE_DEFERRED,
|
||||||
NETWORK_VIDEO_DECODE_UNSUPPORTED,
|
NETWORK_VIDEO_DECODE_UNSUPPORTED,
|
||||||
NETWORK_VIDEO_DECODE_CORRUPT,
|
NETWORK_VIDEO_DECODE_CORRUPT,
|
||||||
NETWORK_VIDEO_DECODE_ERROR,
|
NETWORK_VIDEO_DECODE_ERROR,
|
||||||
@@ -53,7 +56,8 @@ typedef struct NetworkVideoDecodedFrame
|
|||||||
}
|
}
|
||||||
NetworkVideoDecodedFrame;
|
NetworkVideoDecodedFrame;
|
||||||
|
|
||||||
bool networkVideoDecoderCreate(NetworkVideoDecoder ** decoder);
|
bool networkVideoDecoderCreate(NetworkVideoDecoder ** decoder,
|
||||||
|
LGEvent * presentEvent);
|
||||||
void networkVideoDecoderDestroy(NetworkVideoDecoder ** decoder);
|
void networkVideoDecoderDestroy(NetworkVideoDecoder ** decoder);
|
||||||
|
|
||||||
bool networkVideoDecoderAttach(NetworkVideoDecoder * decoder,
|
bool networkVideoDecoderAttach(NetworkVideoDecoder * decoder,
|
||||||
@@ -68,5 +72,7 @@ NetworkVideoDecodeResult networkVideoDecoderDecode(
|
|||||||
const void * data, size_t size, uint32_t blockCount,
|
const void * data, size_t size, uint32_t blockCount,
|
||||||
bool update, bool complete, uint64_t baseFrameID, uint64_t frameID,
|
bool update, bool complete, uint64_t baseFrameID, uint64_t frameID,
|
||||||
NetworkVideoDecodedFrame * frame);
|
NetworkVideoDecodedFrame * frame);
|
||||||
|
NetworkVideoDecodeResult networkVideoDecoderPresentPending(
|
||||||
|
NetworkVideoDecoder * decoder, NetworkVideoDecodedFrame * frame);
|
||||||
|
|
||||||
void networkVideoDecoderRelease(NetworkVideoDecodedFrame * frame);
|
void networkVideoDecoderRelease(NetworkVideoDecodedFrame * frame);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include "shaders.h"
|
#include "shaders.h"
|
||||||
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/event.h"
|
||||||
#include "common/locking.h"
|
#include "common/locking.h"
|
||||||
#include "common/time.h"
|
#include "common/time.h"
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@
|
|||||||
#define NETWORK_VIDEO_ALIGNMENT (1U << NETWORK_VIDEO_LEVELS)
|
#define NETWORK_VIDEO_ALIGNMENT (1U << NETWORK_VIDEO_LEVELS)
|
||||||
#define NETWORK_VIDEO_MIN_SIZE (4U << NETWORK_VIDEO_LEVELS)
|
#define NETWORK_VIDEO_MIN_SIZE (4U << NETWORK_VIDEO_LEVELS)
|
||||||
#define NETWORK_VIDEO_UPLOADS 3U
|
#define NETWORK_VIDEO_UPLOADS 3U
|
||||||
|
#define NETWORK_VIDEO_POOL_MIN_SIZE 2U
|
||||||
#define NETWORK_VIDEO_POOL_SIZE 3U
|
#define NETWORK_VIDEO_POOL_SIZE 3U
|
||||||
#define NETWORK_VIDEO_DAMAGE_HISTORY 64U
|
#define NETWORK_VIDEO_DAMAGE_HISTORY 64U
|
||||||
#define NETWORK_VIDEO_POOL_BYTE_LIMIT \
|
#define NETWORK_VIDEO_POOL_BYTE_LIMIT \
|
||||||
@@ -131,11 +133,13 @@ struct NetworkVideoTexturePool
|
|||||||
LG_Lock lock;
|
LG_Lock lock;
|
||||||
|
|
||||||
atomic_uint references;
|
atomic_uint references;
|
||||||
|
LGEvent * presentEvent;
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLConfig eglConfig;
|
EGLConfig eglConfig;
|
||||||
EGLContext shareContext;
|
EGLContext shareContext;
|
||||||
struct NetworkVideoTexture textures[NETWORK_VIDEO_POOL_SIZE];
|
struct NetworkVideoTexture textures[NETWORK_VIDEO_POOL_SIZE];
|
||||||
unsigned textureCount;
|
unsigned textureCount;
|
||||||
|
unsigned textureAllocated;
|
||||||
unsigned textureLimit;
|
unsigned textureLimit;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
@@ -219,6 +223,8 @@ struct NetworkVideoDecoder
|
|||||||
uint8_t * outputDirty;
|
uint8_t * outputDirty;
|
||||||
struct NetworkVideoDamageHistory
|
struct NetworkVideoDamageHistory
|
||||||
damageHistory[NETWORK_VIDEO_DAMAGE_HISTORY];
|
damageHistory[NETWORK_VIDEO_DAMAGE_HISTORY];
|
||||||
|
LGNetVideoDamage pendingDamage;
|
||||||
|
LGEvent * presentEvent;
|
||||||
|
|
||||||
LGNetVideoStreamConfig config;
|
LGNetVideoStreamConfig config;
|
||||||
struct NetworkVideoBlockMeta
|
struct NetworkVideoBlockMeta
|
||||||
@@ -232,6 +238,7 @@ struct NetworkVideoDecoder
|
|||||||
uint32_t outputTileHeight;
|
uint32_t outputTileHeight;
|
||||||
uint64_t referenceFrameID;
|
uint64_t referenceFrameID;
|
||||||
uint64_t outputGeneration;
|
uint64_t outputGeneration;
|
||||||
|
uint64_t pendingDecodeTimeNs;
|
||||||
unsigned uploadIndex;
|
unsigned uploadIndex;
|
||||||
GLint maxTextureSize;
|
GLint maxTextureSize;
|
||||||
GLint maxArrayLayers;
|
GLint maxArrayLayers;
|
||||||
@@ -240,6 +247,7 @@ struct NetworkVideoDecoder
|
|||||||
bool attached;
|
bool attached;
|
||||||
bool configured;
|
bool configured;
|
||||||
bool referenceValid;
|
bool referenceValid;
|
||||||
|
bool pendingChromaLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetworkVideoExternalFrame
|
struct NetworkVideoExternalFrame
|
||||||
@@ -257,6 +265,12 @@ static uint32_t networkVideoAlign(uint32_t value, uint32_t alignment)
|
|||||||
return (value + alignment - 1U) & ~(alignment - 1U);
|
return (value + alignment - 1U) & ~(alignment - 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t networkVideoSaturatingAdd(
|
||||||
|
uint64_t left, uint64_t right)
|
||||||
|
{
|
||||||
|
return left > UINT64_MAX - right ? UINT64_MAX : left + right;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t networkVideoReadU32(const uint8_t * data)
|
static uint32_t networkVideoReadU32(const uint8_t * data)
|
||||||
{
|
{
|
||||||
return (uint32_t)data[0] |
|
return (uint32_t)data[0] |
|
||||||
@@ -384,21 +398,24 @@ static struct NetworkVideoTexturePool * networkVideoTexturePoolCreate(
|
|||||||
if (!pool)
|
if (!pool)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const uint64_t width = decoder->config.width;
|
const uint64_t width = decoder->config.width;
|
||||||
const uint64_t height = decoder->config.height;
|
const uint64_t height = decoder->config.height;
|
||||||
const uint64_t textureBytes = width * height * NETWORK_VIDEO_PIXEL_BYTES;
|
const uint64_t textureBytes = width * height * NETWORK_VIDEO_PIXEL_BYTES;
|
||||||
const uint64_t textureLimit = textureBytes ?
|
const uint64_t textureLimit = textureBytes ?
|
||||||
NETWORK_VIDEO_POOL_BYTE_LIMIT / textureBytes : 0U;
|
NETWORK_VIDEO_POOL_BYTE_LIMIT / textureBytes : 0U;
|
||||||
|
const uint64_t boundedLimit = textureLimit < NETWORK_VIDEO_POOL_MIN_SIZE ?
|
||||||
|
NETWORK_VIDEO_POOL_MIN_SIZE : textureLimit;
|
||||||
|
|
||||||
LG_LOCK_INIT(pool->lock);
|
LG_LOCK_INIT(pool->lock);
|
||||||
atomic_init(&pool->references, 1U);
|
atomic_init(&pool->references, 1U);
|
||||||
|
pool->presentEvent = decoder->presentEvent;
|
||||||
pool->display = decoder->display;
|
pool->display = decoder->display;
|
||||||
pool->eglConfig = decoder->eglConfig;
|
pool->eglConfig = decoder->eglConfig;
|
||||||
pool->shareContext = decoder->shareContext;
|
pool->shareContext = decoder->shareContext;
|
||||||
pool->width = decoder->config.width;
|
pool->width = decoder->config.width;
|
||||||
pool->height = decoder->config.height;
|
pool->height = decoder->config.height;
|
||||||
pool->textureLimit = textureLimit < NETWORK_VIDEO_POOL_SIZE ?
|
pool->textureLimit = boundedLimit < NETWORK_VIDEO_POOL_SIZE ?
|
||||||
(unsigned)textureLimit : NETWORK_VIDEO_POOL_SIZE;
|
(unsigned)boundedLimit : NETWORK_VIDEO_POOL_SIZE;
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +425,17 @@ static void networkVideoTexturePoolRetain(
|
|||||||
atomic_fetch_add_explicit(&pool->references, 1U, memory_order_relaxed);
|
atomic_fetch_add_explicit(&pool->references, 1U, memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void networkVideoTexturePoolDetachEvent(
|
||||||
|
struct NetworkVideoTexturePool * pool)
|
||||||
|
{
|
||||||
|
if (!pool)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LG_LOCK(pool->lock);
|
||||||
|
pool->presentEvent = NULL;
|
||||||
|
LG_UNLOCK(pool->lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void networkVideoTexturePoolRelease(
|
static void networkVideoTexturePoolRelease(
|
||||||
struct NetworkVideoTexturePool * pool, bool current)
|
struct NetworkVideoTexturePool * pool, bool current)
|
||||||
{
|
{
|
||||||
@@ -452,7 +480,7 @@ static bool networkVideoTexturePoolReturn(
|
|||||||
|
|
||||||
bool retained = false;
|
bool retained = false;
|
||||||
LG_LOCK(pool->lock);
|
LG_LOCK(pool->lock);
|
||||||
if (pool->textureCount < pool->textureLimit)
|
if (pool->textureCount < pool->textureAllocated)
|
||||||
{
|
{
|
||||||
struct NetworkVideoTexture * pooled =
|
struct NetworkVideoTexture * pooled =
|
||||||
&pool->textures[pool->textureCount++];
|
&pool->textures[pool->textureCount++];
|
||||||
@@ -460,6 +488,8 @@ static bool networkVideoTexturePoolReturn(
|
|||||||
pooled->readySync = readySync;
|
pooled->readySync = readySync;
|
||||||
pooled->generation = generation;
|
pooled->generation = generation;
|
||||||
retained = true;
|
retained = true;
|
||||||
|
if (pool->presentEvent)
|
||||||
|
lgSignalEvent(pool->presentEvent);
|
||||||
}
|
}
|
||||||
LG_UNLOCK(pool->lock);
|
LG_UNLOCK(pool->lock);
|
||||||
return retained;
|
return retained;
|
||||||
@@ -549,6 +579,7 @@ static void networkVideoDeleteConfigurationNL(NetworkVideoDecoder * decoder)
|
|||||||
if (upload->payloadBuffer)
|
if (upload->payloadBuffer)
|
||||||
glDeleteBuffers(1, &upload->payloadBuffer);
|
glDeleteBuffers(1, &upload->payloadBuffer);
|
||||||
}
|
}
|
||||||
|
networkVideoTexturePoolDetachEvent(decoder->texturePool);
|
||||||
networkVideoTexturePoolRelease(decoder->texturePool, true);
|
networkVideoTexturePoolRelease(decoder->texturePool, true);
|
||||||
networkVideoFreePacketStates(
|
networkVideoFreePacketStates(
|
||||||
decoder->packetStates, decoder->blockCapacity);
|
decoder->packetStates, decoder->blockCapacity);
|
||||||
@@ -563,23 +594,26 @@ static void networkVideoDeleteConfigurationNL(NetworkVideoDecoder * decoder)
|
|||||||
|
|
||||||
memset(decoder->uploads, 0, sizeof(decoder->uploads));
|
memset(decoder->uploads, 0, sizeof(decoder->uploads));
|
||||||
memset(decoder->damageHistory, 0, sizeof(decoder->damageHistory));
|
memset(decoder->damageHistory, 0, sizeof(decoder->damageHistory));
|
||||||
decoder->texturePool = NULL;
|
memset(&decoder->pendingDamage, 0, sizeof(decoder->pendingDamage));
|
||||||
decoder->offsets = NULL;
|
decoder->texturePool = NULL;
|
||||||
decoder->packetStates = NULL;
|
decoder->offsets = NULL;
|
||||||
decoder->pendingPackets = NULL;
|
decoder->packetStates = NULL;
|
||||||
decoder->dirtyBlocks = NULL;
|
decoder->pendingPackets = NULL;
|
||||||
decoder->outputDirty = NULL;
|
decoder->dirtyBlocks = NULL;
|
||||||
decoder->canonicalTexture = 0;
|
decoder->outputDirty = NULL;
|
||||||
decoder->alignedWidth = 0;
|
decoder->canonicalTexture = 0;
|
||||||
decoder->alignedHeight = 0;
|
decoder->alignedWidth = 0;
|
||||||
decoder->blockCapacity = 0;
|
decoder->alignedHeight = 0;
|
||||||
decoder->outputTileWidth = 0;
|
decoder->blockCapacity = 0;
|
||||||
decoder->outputTileHeight = 0;
|
decoder->outputTileWidth = 0;
|
||||||
decoder->referenceFrameID = 0;
|
decoder->outputTileHeight = 0;
|
||||||
decoder->outputGeneration = 0;
|
decoder->referenceFrameID = 0;
|
||||||
decoder->uploadIndex = 0;
|
decoder->outputGeneration = 0;
|
||||||
decoder->configured = false;
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
decoder->referenceValid = false;
|
decoder->uploadIndex = 0;
|
||||||
|
decoder->configured = false;
|
||||||
|
decoder->referenceValid = false;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
memset(decoder->coefficientTextures, 0,
|
memset(decoder->coefficientTextures, 0,
|
||||||
sizeof(decoder->coefficientTextures));
|
sizeof(decoder->coefficientTextures));
|
||||||
memset(decoder->planeTextures, 0, sizeof(decoder->planeTextures));
|
memset(decoder->planeTextures, 0, sizeof(decoder->planeTextures));
|
||||||
@@ -800,10 +834,32 @@ static bool networkVideoCreateTexture2D(GLuint * texture, GLenum format,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool networkVideoTexturePoolAllocateNL(
|
||||||
|
struct NetworkVideoTexturePool * pool)
|
||||||
|
{
|
||||||
|
while (pool->textureAllocated < NETWORK_VIDEO_POOL_MIN_SIZE)
|
||||||
|
{
|
||||||
|
struct NetworkVideoTexture * pooled =
|
||||||
|
&pool->textures[pool->textureCount];
|
||||||
|
if (!networkVideoCreateTexture2D(&pooled->texture, GL_RGBA16F,
|
||||||
|
pool->width, pool->height, GL_LINEAR))
|
||||||
|
{
|
||||||
|
while (glGetError() != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++pool->textureCount;
|
||||||
|
++pool->textureAllocated;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct NetworkVideoTexture networkVideoTexturePoolAcquire(
|
static struct NetworkVideoTexture networkVideoTexturePoolAcquire(
|
||||||
struct NetworkVideoTexturePool * pool)
|
struct NetworkVideoTexturePool * pool)
|
||||||
{
|
{
|
||||||
struct NetworkVideoTexture pooled = { 0 };
|
struct NetworkVideoTexture pooled = { 0 };
|
||||||
|
bool allocate = false;
|
||||||
LG_LOCK(pool->lock);
|
LG_LOCK(pool->lock);
|
||||||
if (pool->textureCount)
|
if (pool->textureCount)
|
||||||
{
|
{
|
||||||
@@ -811,15 +867,26 @@ static struct NetworkVideoTexture networkVideoTexturePoolAcquire(
|
|||||||
memset(&pool->textures[pool->textureCount], 0,
|
memset(&pool->textures[pool->textureCount], 0,
|
||||||
sizeof(pool->textures[pool->textureCount]));
|
sizeof(pool->textures[pool->textureCount]));
|
||||||
}
|
}
|
||||||
|
else if (pool->textureAllocated < pool->textureLimit)
|
||||||
|
{
|
||||||
|
++pool->textureAllocated;
|
||||||
|
allocate = true;
|
||||||
|
}
|
||||||
LG_UNLOCK(pool->lock);
|
LG_UNLOCK(pool->lock);
|
||||||
|
|
||||||
|
if (allocate && !networkVideoCreateTexture2D(&pooled.texture, GL_RGBA16F,
|
||||||
|
pool->width, pool->height, GL_LINEAR))
|
||||||
|
{
|
||||||
|
while (glGetError() != GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
LG_LOCK(pool->lock);
|
||||||
|
--pool->textureAllocated;
|
||||||
|
pool->textureLimit = pool->textureAllocated;
|
||||||
|
LG_UNLOCK(pool->lock);
|
||||||
|
}
|
||||||
if (pooled.readySync)
|
if (pooled.readySync)
|
||||||
glDeleteSync(pooled.readySync);
|
glDeleteSync(pooled.readySync);
|
||||||
if (pooled.texture)
|
|
||||||
return pooled;
|
|
||||||
|
|
||||||
if (!networkVideoCreateTexture2D(&pooled.texture, GL_RGBA16F,
|
|
||||||
pool->width, pool->height, GL_LINEAR))
|
|
||||||
pooled.texture = 0;
|
|
||||||
return pooled;
|
return pooled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,7 +955,8 @@ static bool networkVideoAllocateNL(NetworkVideoDecoder * decoder)
|
|||||||
outputTileCount, sizeof(*decoder->outputDirty));
|
outputTileCount, sizeof(*decoder->outputDirty));
|
||||||
if (!decoder->offsets || !decoder->packetStates ||
|
if (!decoder->offsets || !decoder->packetStates ||
|
||||||
!decoder->pendingPackets || !decoder->dirtyBlocks ||
|
!decoder->pendingPackets || !decoder->dirtyBlocks ||
|
||||||
!decoder->texturePool || !decoder->outputDirty)
|
!decoder->texturePool || !decoder->outputDirty ||
|
||||||
|
!networkVideoTexturePoolAllocateNL(decoder->texturePool))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (unsigned component = 0;
|
for (unsigned component = 0;
|
||||||
@@ -997,16 +1065,18 @@ static const LG_ExternalFrameOps NETWORK_VIDEO_EXTERNAL_OPS =
|
|||||||
.query = networkVideoExternalQuery,
|
.query = networkVideoExternalQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool networkVideoDecoderCreate(NetworkVideoDecoder ** result)
|
bool networkVideoDecoderCreate(NetworkVideoDecoder ** result,
|
||||||
|
LGEvent * presentEvent)
|
||||||
{
|
{
|
||||||
if (!result)
|
if (!result || !presentEvent)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
NetworkVideoDecoder * decoder = calloc(1, sizeof(*decoder));
|
NetworkVideoDecoder * decoder = calloc(1, sizeof(*decoder));
|
||||||
if (!decoder)
|
if (!decoder)
|
||||||
return false;
|
return false;
|
||||||
LG_LOCK_INIT(decoder->lock);
|
LG_LOCK_INIT(decoder->lock);
|
||||||
*result = decoder;
|
decoder->presentEvent = presentEvent;
|
||||||
|
*result = decoder;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,6 +1097,12 @@ void networkVideoDecoderDetach(NetworkVideoDecoder * decoder)
|
|||||||
}
|
}
|
||||||
eglDestroyContext(decoder->display, decoder->context);
|
eglDestroyContext(decoder->display, decoder->context);
|
||||||
}
|
}
|
||||||
|
if (decoder->texturePool)
|
||||||
|
{
|
||||||
|
networkVideoTexturePoolDetachEvent(decoder->texturePool);
|
||||||
|
networkVideoTexturePoolRelease(decoder->texturePool, false);
|
||||||
|
decoder->texturePool = NULL;
|
||||||
|
}
|
||||||
decoder->display = EGL_NO_DISPLAY;
|
decoder->display = EGL_NO_DISPLAY;
|
||||||
decoder->eglConfig = NULL;
|
decoder->eglConfig = NULL;
|
||||||
decoder->shareContext = EGL_NO_CONTEXT;
|
decoder->shareContext = EGL_NO_CONTEXT;
|
||||||
@@ -1037,8 +1113,11 @@ void networkVideoDecoderDetach(NetworkVideoDecoder * decoder)
|
|||||||
decoder->maxWorkGroupCount[1] = 0;
|
decoder->maxWorkGroupCount[1] = 0;
|
||||||
decoder->maxStorageBlockSize = 0;
|
decoder->maxStorageBlockSize = 0;
|
||||||
decoder->referenceFrameID = 0;
|
decoder->referenceFrameID = 0;
|
||||||
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
decoder->attached = false;
|
decoder->attached = false;
|
||||||
decoder->referenceValid = false;
|
decoder->referenceValid = false;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
memset(&decoder->pendingDamage, 0, sizeof(decoder->pendingDamage));
|
||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,8 +1147,11 @@ void networkVideoDecoderReset(NetworkVideoDecoder * decoder)
|
|||||||
networkVideoRestoreCurrent(decoder, &previous);
|
networkVideoRestoreCurrent(decoder, &previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoder->referenceFrameID = 0;
|
decoder->referenceFrameID = 0;
|
||||||
decoder->referenceValid = false;
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
|
decoder->referenceValid = false;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
memset(&decoder->pendingDamage, 0, sizeof(decoder->pendingDamage));
|
||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1765,6 +1847,11 @@ static bool networkVideoDamageFull(const LGNetVideoDamage * damage)
|
|||||||
return (damage->flags & LG_NET_VIDEO_DAMAGE_FULL) != 0;
|
return (damage->flags & LG_NET_VIDEO_DAMAGE_FULL) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool networkVideoDamagePresent(const LGNetVideoDamage * damage)
|
||||||
|
{
|
||||||
|
return networkVideoDamageFull(damage) || damage->count;
|
||||||
|
}
|
||||||
|
|
||||||
static void networkVideoDispatchRect(GLint offsetUniform,
|
static void networkVideoDispatchRect(GLint offsetUniform,
|
||||||
GLint extentUniform, uint32_t x, uint32_t y,
|
GLint extentUniform, uint32_t x, uint32_t y,
|
||||||
uint32_t width, uint32_t height)
|
uint32_t width, uint32_t height)
|
||||||
@@ -1994,6 +2081,95 @@ static bool networkVideoAppendDamageRect(LGNetVideoDamage * damage,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool networkVideoUnionDamageRect(LGNetVideoDamage * damage,
|
||||||
|
const LGNetVideoDamageRect * source)
|
||||||
|
{
|
||||||
|
uint32_t x = source->x;
|
||||||
|
uint32_t y = source->y;
|
||||||
|
uint32_t endX = source->x + source->width;
|
||||||
|
uint32_t endY = source->y + source->height;
|
||||||
|
for (uint16_t index = 0; index < damage->count;)
|
||||||
|
{
|
||||||
|
const LGNetVideoDamageRect * current = &damage->rects[index];
|
||||||
|
const uint32_t currentEndX =
|
||||||
|
current->x + current->width;
|
||||||
|
const uint32_t currentEndY =
|
||||||
|
current->y + current->height;
|
||||||
|
if (endX < current->x || currentEndX < x ||
|
||||||
|
endY < current->y || currentEndY < y)
|
||||||
|
{
|
||||||
|
++index;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = current->x < x ? current->x : x;
|
||||||
|
y = current->y < y ? current->y : y;
|
||||||
|
endX = currentEndX > endX ? currentEndX : endX;
|
||||||
|
endY = currentEndY > endY ? currentEndY : endY;
|
||||||
|
damage->rects[index] = damage->rects[--damage->count];
|
||||||
|
}
|
||||||
|
return networkVideoAppendDamageRect(
|
||||||
|
damage, x, y, endX - x, endY - y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void networkVideoMergeDamage(LGNetVideoDamage * destination,
|
||||||
|
const LGNetVideoDamage * source)
|
||||||
|
{
|
||||||
|
if (!networkVideoDamagePresent(source) ||
|
||||||
|
networkVideoDamageFull(destination))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (networkVideoDamageFull(source))
|
||||||
|
{
|
||||||
|
memset(destination, 0, sizeof(*destination));
|
||||||
|
destination->flags =
|
||||||
|
(LGNetVideoDamageFlags)LG_NET_VIDEO_DAMAGE_FULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t index = 0; index < source->count; ++index)
|
||||||
|
{
|
||||||
|
const LGNetVideoDamageRect * rect = &source->rects[index];
|
||||||
|
if (networkVideoUnionDamageRect(destination, rect))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32_t left = UINT32_MAX;
|
||||||
|
uint32_t top = UINT32_MAX;
|
||||||
|
uint32_t right = 0;
|
||||||
|
uint32_t bottom = 0;
|
||||||
|
for (unsigned set = 0; set < 2; ++set)
|
||||||
|
{
|
||||||
|
const LGNetVideoDamageRect * rects = set ?
|
||||||
|
source->rects : destination->rects;
|
||||||
|
const uint16_t count = set ?
|
||||||
|
source->count : destination->count;
|
||||||
|
for (uint16_t rectIndex = 0; rectIndex < count; ++rectIndex)
|
||||||
|
{
|
||||||
|
const LGNetVideoDamageRect * current = &rects[rectIndex];
|
||||||
|
const uint32_t currentRight =
|
||||||
|
current->x + current->width;
|
||||||
|
const uint32_t currentBottom =
|
||||||
|
current->y + current->height;
|
||||||
|
left = current->x < left ? current->x : left;
|
||||||
|
top = current->y < top ? current->y : top;
|
||||||
|
right = currentRight > right ? currentRight : right;
|
||||||
|
bottom = currentBottom > bottom ? currentBottom : bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(destination, 0, sizeof(*destination));
|
||||||
|
destination->count = 1;
|
||||||
|
destination->rects[0] = (LGNetVideoDamageRect)
|
||||||
|
{
|
||||||
|
.x = (uint16_t)left,
|
||||||
|
.y = (uint16_t)top,
|
||||||
|
.width = (uint16_t)(right - left),
|
||||||
|
.height = (uint16_t)(bottom - top),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void networkVideoIntersectDamage(
|
static void networkVideoIntersectDamage(
|
||||||
const LGNetVideoDamage * source,
|
const LGNetVideoDamage * source,
|
||||||
const LGNetVideoDamage * reconstruction,
|
const LGNetVideoDamage * reconstruction,
|
||||||
@@ -2074,10 +2250,20 @@ static void networkVideoBuildDamage(const LGNetVideoDamage * damage,
|
|||||||
result->damageRectsCount = damage->count;
|
result->damageRectsCount = damage->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct NetworkVideoExternalFrame * networkVideoConvertNL(
|
static bool networkVideoPresentNL(NetworkVideoDecoder * decoder,
|
||||||
NetworkVideoDecoder * decoder, bool chromaLeft, uint64_t generation,
|
struct NetworkVideoTexture pooled, bool chromaLeft, uint64_t generation,
|
||||||
const LGNetVideoDamage * damage)
|
const LGNetVideoDamage * damage,
|
||||||
|
struct NetworkVideoExternalFrame ** result)
|
||||||
{
|
{
|
||||||
|
*result = NULL;
|
||||||
|
struct NetworkVideoExternalFrame * frame = calloc(1, sizeof(*frame));
|
||||||
|
if (!frame)
|
||||||
|
{
|
||||||
|
networkVideoTexturePoolRecycleCurrent(decoder->texturePool,
|
||||||
|
pooled.texture, pooled.readySync, pooled.generation);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glUseProgram(decoder->yuvProgram);
|
glUseProgram(decoder->yuvProgram);
|
||||||
for (unsigned component = 0;
|
for (unsigned component = 0;
|
||||||
component < NETWORK_VIDEO_COMPONENTS; ++component)
|
component < NETWORK_VIDEO_COMPONENTS; ++component)
|
||||||
@@ -2108,28 +2294,16 @@ static struct NetworkVideoExternalFrame * networkVideoConvertNL(
|
|||||||
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT |
|
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT |
|
||||||
GL_TEXTURE_FETCH_BARRIER_BIT);
|
GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||||
|
|
||||||
struct NetworkVideoTexture pooled =
|
|
||||||
networkVideoTexturePoolAcquire(decoder->texturePool);
|
|
||||||
if (!pooled.texture)
|
|
||||||
return NULL;
|
|
||||||
networkVideoCopyCanonicalNL(decoder, pooled.texture,
|
networkVideoCopyCanonicalNL(decoder, pooled.texture,
|
||||||
pooled.generation, generation, damage);
|
pooled.generation, generation, damage);
|
||||||
|
|
||||||
GLsync readySync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
GLsync readySync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
glFlush();
|
|
||||||
if (!readySync || glGetError() != GL_NO_ERROR)
|
if (!readySync || glGetError() != GL_NO_ERROR)
|
||||||
{
|
{
|
||||||
|
free(frame);
|
||||||
networkVideoTexturePoolRecycleCurrent(
|
networkVideoTexturePoolRecycleCurrent(
|
||||||
decoder->texturePool, pooled.texture, readySync, 0);
|
decoder->texturePool, pooled.texture, readySync, 0);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
struct NetworkVideoExternalFrame * frame = calloc(1, sizeof(*frame));
|
|
||||||
if (!frame)
|
|
||||||
{
|
|
||||||
networkVideoTexturePoolRecycleCurrent(
|
|
||||||
decoder->texturePool, pooled.texture, readySync, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
frame->base.ops = &NETWORK_VIDEO_EXTERNAL_OPS;
|
frame->base.ops = &NETWORK_VIDEO_EXTERNAL_OPS;
|
||||||
frame->pool = decoder->texturePool;
|
frame->pool = decoder->texturePool;
|
||||||
@@ -2138,7 +2312,43 @@ static struct NetworkVideoExternalFrame * networkVideoConvertNL(
|
|||||||
frame->generation = generation;
|
frame->generation = generation;
|
||||||
networkVideoTexturePoolRetain(frame->pool);
|
networkVideoTexturePoolRetain(frame->pool);
|
||||||
atomic_init(&frame->references, 1U);
|
atomic_init(&frame->references, 1U);
|
||||||
return frame;
|
*result = frame;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void networkVideoBuildFrameNL(NetworkVideoDecoder * decoder,
|
||||||
|
struct NetworkVideoExternalFrame * external,
|
||||||
|
const LGNetVideoDamage * damage, uint64_t decodeTime,
|
||||||
|
NetworkVideoDecodedFrame * result)
|
||||||
|
{
|
||||||
|
uint32_t formatVersion = (uint32_t)decoder->config.configEpoch;
|
||||||
|
if (!formatVersion)
|
||||||
|
formatVersion = 1;
|
||||||
|
|
||||||
|
result->externalFrame = &external->base;
|
||||||
|
result->decodeTimeNs = decodeTime;
|
||||||
|
networkVideoBuildDamage(damage, result);
|
||||||
|
result->format = (LG_TransportFrameFormat)
|
||||||
|
{
|
||||||
|
.version = formatVersion,
|
||||||
|
.type = FRAME_TYPE_RGBA16F,
|
||||||
|
.screenWidth = decoder->config.width,
|
||||||
|
.screenHeight = decoder->config.height,
|
||||||
|
.dataWidth = decoder->config.width,
|
||||||
|
.dataHeight = decoder->config.height,
|
||||||
|
.frameWidth = decoder->config.width,
|
||||||
|
.frameHeight = decoder->config.height,
|
||||||
|
.rotation = FRAME_ROT_0,
|
||||||
|
.stride = decoder->config.width,
|
||||||
|
.pitch = decoder->config.width * 8U,
|
||||||
|
.hdr = (decoder->config.flags & LG_NET_VIDEO_STREAM_HDR) != 0,
|
||||||
|
.hdrPQ = decoder->config.colorTransfer ==
|
||||||
|
LG_NET_COLOR_TRANSFER_PQ,
|
||||||
|
.hdrMetadata = false,
|
||||||
|
.sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT,
|
||||||
|
};
|
||||||
|
result->timing.providerValid = true;
|
||||||
|
result->timing.prepareTime = decodeTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkVideoDecodeResult networkVideoDecoderDecode(
|
NetworkVideoDecodeResult networkVideoDecoderDecode(
|
||||||
@@ -2186,7 +2396,9 @@ NetworkVideoDecodeResult networkVideoDecoderDecode(
|
|||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
return NETWORK_VIDEO_DECODE_ERROR;
|
return NETWORK_VIDEO_DECODE_ERROR;
|
||||||
}
|
}
|
||||||
if (update && !changedCount)
|
const bool codecChanges = !update || changedCount;
|
||||||
|
if (!codecChanges &&
|
||||||
|
!networkVideoDamagePresent(&decoder->pendingDamage))
|
||||||
{
|
{
|
||||||
networkVideoCommitPendingPacketsNL(decoder);
|
networkVideoCommitPendingPacketsNL(decoder);
|
||||||
decoder->referenceFrameID = frameID;
|
decoder->referenceFrameID = frameID;
|
||||||
@@ -2194,10 +2406,13 @@ NetworkVideoDecodeResult networkVideoDecoderDecode(
|
|||||||
return NETWORK_VIDEO_DECODE_NO_FRAME;
|
return NETWORK_VIDEO_DECODE_NO_FRAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update)
|
if (codecChanges)
|
||||||
networkVideoPrepareDirtyNL(decoder);
|
{
|
||||||
else
|
if (update)
|
||||||
networkVideoClearDirtyNL(decoder);
|
networkVideoPrepareDirtyNL(decoder);
|
||||||
|
else
|
||||||
|
networkVideoClearDirtyNL(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
struct NetworkVideoCurrent previous;
|
struct NetworkVideoCurrent previous;
|
||||||
if (!networkVideoMakeCurrent(decoder, &previous))
|
if (!networkVideoMakeCurrent(decoder, &previous))
|
||||||
@@ -2210,52 +2425,71 @@ NetworkVideoDecodeResult networkVideoDecoderDecode(
|
|||||||
while (glGetError() != GL_NO_ERROR)
|
while (glGetError() != GL_NO_ERROR)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
struct NetworkVideoUpload * upload = networkVideoUploadNL(
|
struct NetworkVideoUpload * upload = NULL;
|
||||||
decoder, data, size);
|
if (codecChanges)
|
||||||
if (!upload)
|
|
||||||
{
|
{
|
||||||
networkVideoDiscardPendingPacketsNL(decoder);
|
upload = networkVideoUploadNL(decoder, data, size);
|
||||||
networkVideoRestoreCurrent(decoder, &previous);
|
if (!upload)
|
||||||
LG_UNLOCK(decoder->lock);
|
{
|
||||||
return NETWORK_VIDEO_DECODE_ERROR;
|
networkVideoDiscardPendingPacketsNL(decoder);
|
||||||
|
networkVideoRestoreCurrent(decoder, &previous);
|
||||||
|
LG_UNLOCK(decoder->lock);
|
||||||
|
return NETWORK_VIDEO_DECODE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t decodeStart = nanotime();
|
const uint64_t decodeStart = nanotime();
|
||||||
uint64_t generation = decoder->outputGeneration + 1U;
|
uint64_t generation = decoder->outputGeneration + 1U;
|
||||||
|
LGNetVideoDamage damage = { 0 };
|
||||||
if (!generation)
|
if (!generation)
|
||||||
generation = 1U;
|
generation = 1U;
|
||||||
networkVideoDequantNL(decoder, upload, update);
|
if (codecChanges)
|
||||||
upload->readySync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
{
|
||||||
networkVideoIDWTNL(decoder, update);
|
networkVideoDequantNL(decoder, upload, update);
|
||||||
LGNetVideoDamage reconstructionDamage;
|
networkVideoIDWTNL(decoder, update);
|
||||||
LGNetVideoDamage damage;
|
LGNetVideoDamage reconstructionDamage;
|
||||||
networkVideoBuildReconstructionDamageNL(
|
networkVideoBuildReconstructionDamageNL(
|
||||||
decoder, update, &reconstructionDamage);
|
decoder, update, &reconstructionDamage);
|
||||||
/* Wire damage accumulates against the sender's acknowledged reference.
|
/* Wire damage accumulates against the sender's acknowledged reference.
|
||||||
* Limit it to output reconstructed against the decoder's current state. */
|
* Limit it to output reconstructed against the decoder's current state. */
|
||||||
if (update)
|
if (update)
|
||||||
networkVideoIntersectDamage(
|
networkVideoIntersectDamage(
|
||||||
&layout.damage, &reconstructionDamage, &damage);
|
&layout.damage, &reconstructionDamage, &damage);
|
||||||
else
|
else
|
||||||
damage = reconstructionDamage;
|
damage = reconstructionDamage;
|
||||||
const bool hasPresentationDamage =
|
}
|
||||||
networkVideoDamageFull(&damage) || damage.count;
|
|
||||||
|
|
||||||
struct NetworkVideoExternalFrame * external = NULL;
|
LGNetVideoDamage presentationDamage = decoder->pendingDamage;
|
||||||
|
networkVideoMergeDamage(&presentationDamage, &damage);
|
||||||
|
const bool hasPresentationDamage =
|
||||||
|
networkVideoDamagePresent(&presentationDamage);
|
||||||
|
|
||||||
|
struct NetworkVideoTexture pooled = { 0 };
|
||||||
|
struct NetworkVideoExternalFrame * external = NULL;
|
||||||
|
bool presented = true;
|
||||||
if (hasPresentationDamage)
|
if (hasPresentationDamage)
|
||||||
external = networkVideoConvertNL(decoder,
|
{
|
||||||
layout.chromaLeft, generation, &damage);
|
pooled = networkVideoTexturePoolAcquire(decoder->texturePool);
|
||||||
else
|
if (pooled.texture)
|
||||||
glFlush();
|
presented = networkVideoPresentNL(decoder, pooled,
|
||||||
|
layout.chromaLeft, generation, &presentationDamage, &external);
|
||||||
|
}
|
||||||
|
if (upload)
|
||||||
|
upload->readySync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
glFlush();
|
||||||
const uint64_t decodeTime = nanotime() - decodeStart;
|
const uint64_t decodeTime = nanotime() - decodeStart;
|
||||||
const bool success =
|
const bool success = presented &&
|
||||||
(!hasPresentationDamage || external) && glGetError() == GL_NO_ERROR;
|
(!upload || upload->readySync) && glGetError() == GL_NO_ERROR;
|
||||||
networkVideoRestoreCurrent(decoder, &previous);
|
networkVideoRestoreCurrent(decoder, &previous);
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
networkVideoDiscardPendingPacketsNL(decoder);
|
networkVideoDiscardPendingPacketsNL(decoder);
|
||||||
decoder->referenceFrameID = 0;
|
decoder->referenceFrameID = 0;
|
||||||
decoder->referenceValid = false;
|
decoder->referenceValid = false;
|
||||||
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
memset(&decoder->pendingDamage, 0,
|
||||||
|
sizeof(decoder->pendingDamage));
|
||||||
if (external)
|
if (external)
|
||||||
networkVideoExternalRelease(&external->base);
|
networkVideoExternalRelease(&external->base);
|
||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
@@ -2270,41 +2504,111 @@ NetworkVideoDecodeResult networkVideoDecoderDecode(
|
|||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
return NETWORK_VIDEO_DECODE_NO_FRAME;
|
return NETWORK_VIDEO_DECODE_NO_FRAME;
|
||||||
}
|
}
|
||||||
|
if (!pooled.texture)
|
||||||
|
{
|
||||||
|
decoder->pendingDamage = presentationDamage;
|
||||||
|
decoder->pendingDecodeTimeNs = networkVideoSaturatingAdd(
|
||||||
|
decoder->pendingDecodeTimeNs, decodeTime);
|
||||||
|
decoder->pendingChromaLeft = layout.chromaLeft;
|
||||||
|
LG_UNLOCK(decoder->lock);
|
||||||
|
return NETWORK_VIDEO_DECODE_DEFERRED;
|
||||||
|
}
|
||||||
|
const uint64_t totalDecodeTime = networkVideoSaturatingAdd(
|
||||||
|
decoder->pendingDecodeTimeNs, decodeTime);
|
||||||
|
memset(&decoder->pendingDamage, 0, sizeof(decoder->pendingDamage));
|
||||||
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
|
||||||
struct NetworkVideoDamageHistory * history =
|
struct NetworkVideoDamageHistory * history =
|
||||||
&decoder->damageHistory[generation % NETWORK_VIDEO_DAMAGE_HISTORY];
|
&decoder->damageHistory[generation % NETWORK_VIDEO_DAMAGE_HISTORY];
|
||||||
history->generation = generation;
|
history->generation = generation;
|
||||||
history->damage = damage;
|
history->damage = presentationDamage;
|
||||||
decoder->outputGeneration = generation;
|
decoder->outputGeneration = generation;
|
||||||
|
|
||||||
uint32_t formatVersion = (uint32_t)config->configEpoch;
|
networkVideoBuildFrameNL(
|
||||||
if (!formatVersion)
|
decoder, external, &presentationDamage, totalDecodeTime, result);
|
||||||
formatVersion = 1;
|
LG_UNLOCK(decoder->lock);
|
||||||
|
return NETWORK_VIDEO_DECODE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
result->externalFrame = &external->base;
|
NetworkVideoDecodeResult networkVideoDecoderPresentPending(
|
||||||
result->decodeTimeNs = decodeTime;
|
NetworkVideoDecoder * decoder, NetworkVideoDecodedFrame * result)
|
||||||
if (update)
|
{
|
||||||
networkVideoBuildDamage(&damage, result);
|
if (!decoder || !result)
|
||||||
result->format = (LG_TransportFrameFormat)
|
return NETWORK_VIDEO_DECODE_ERROR;
|
||||||
|
memset(result, 0, sizeof(*result));
|
||||||
|
|
||||||
|
LG_LOCK(decoder->lock);
|
||||||
|
if (!decoder->configured)
|
||||||
{
|
{
|
||||||
.version = formatVersion,
|
LG_UNLOCK(decoder->lock);
|
||||||
.type = FRAME_TYPE_RGBA16F,
|
return NETWORK_VIDEO_DECODE_UNSUPPORTED;
|
||||||
.screenWidth = config->width,
|
}
|
||||||
.screenHeight = config->height,
|
if (!networkVideoDamagePresent(&decoder->pendingDamage))
|
||||||
.dataWidth = config->width,
|
{
|
||||||
.dataHeight = config->height,
|
LG_UNLOCK(decoder->lock);
|
||||||
.frameWidth = config->width,
|
return NETWORK_VIDEO_DECODE_NO_FRAME;
|
||||||
.frameHeight = config->height,
|
}
|
||||||
.rotation = FRAME_ROT_0,
|
|
||||||
.stride = config->width,
|
struct NetworkVideoCurrent previous;
|
||||||
.pitch = config->width * 8U,
|
if (!networkVideoMakeCurrent(decoder, &previous))
|
||||||
.hdr = (config->flags & LG_NET_VIDEO_STREAM_HDR) != 0,
|
{
|
||||||
.hdrPQ = config->colorTransfer == LG_NET_COLOR_TRANSFER_PQ,
|
LG_UNLOCK(decoder->lock);
|
||||||
.hdrMetadata = false,
|
return NETWORK_VIDEO_DECODE_ERROR;
|
||||||
.sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT,
|
}
|
||||||
};
|
|
||||||
result->timing.providerValid = true;
|
while (glGetError() != GL_NO_ERROR)
|
||||||
result->timing.prepareTime = decodeTime;
|
{
|
||||||
|
}
|
||||||
|
struct NetworkVideoTexture pooled =
|
||||||
|
networkVideoTexturePoolAcquire(decoder->texturePool);
|
||||||
|
if (!pooled.texture)
|
||||||
|
{
|
||||||
|
networkVideoRestoreCurrent(decoder, &previous);
|
||||||
|
LG_UNLOCK(decoder->lock);
|
||||||
|
return NETWORK_VIDEO_DECODE_DEFERRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t generation = decoder->outputGeneration + 1U;
|
||||||
|
if (!generation)
|
||||||
|
generation = 1U;
|
||||||
|
const uint64_t presentStart = nanotime();
|
||||||
|
struct NetworkVideoExternalFrame * external = NULL;
|
||||||
|
const bool presented = networkVideoPresentNL(
|
||||||
|
decoder, pooled,
|
||||||
|
decoder->pendingChromaLeft, generation, &decoder->pendingDamage,
|
||||||
|
&external);
|
||||||
|
glFlush();
|
||||||
|
const uint64_t presentTime = nanotime() - presentStart;
|
||||||
|
const bool success = presented && glGetError() == GL_NO_ERROR;
|
||||||
|
networkVideoRestoreCurrent(decoder, &previous);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
decoder->referenceFrameID = 0;
|
||||||
|
decoder->referenceValid = false;
|
||||||
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
memset(&decoder->pendingDamage, 0,
|
||||||
|
sizeof(decoder->pendingDamage));
|
||||||
|
if (external)
|
||||||
|
networkVideoExternalRelease(&external->base);
|
||||||
|
LG_UNLOCK(decoder->lock);
|
||||||
|
return NETWORK_VIDEO_DECODE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LGNetVideoDamage damage = decoder->pendingDamage;
|
||||||
|
const uint64_t decodeTime = networkVideoSaturatingAdd(
|
||||||
|
decoder->pendingDecodeTimeNs, presentTime);
|
||||||
|
struct NetworkVideoDamageHistory * history =
|
||||||
|
&decoder->damageHistory[generation % NETWORK_VIDEO_DAMAGE_HISTORY];
|
||||||
|
history->generation = generation;
|
||||||
|
history->damage = damage;
|
||||||
|
decoder->outputGeneration = generation;
|
||||||
|
memset(&decoder->pendingDamage, 0, sizeof(decoder->pendingDamage));
|
||||||
|
decoder->pendingDecodeTimeNs = 0;
|
||||||
|
decoder->pendingChromaLeft = false;
|
||||||
|
networkVideoBuildFrameNL(
|
||||||
|
decoder, external, &damage, decodeTime, result);
|
||||||
LG_UNLOCK(decoder->lock);
|
LG_UNLOCK(decoder->lock);
|
||||||
return NETWORK_VIDEO_DECODE_OK;
|
return NETWORK_VIDEO_DECODE_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user