mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 08:38:20 +00:00
[common] rects: refactor rect buffer copy code to common module
This also fixes a bug of accidentally multiplying the stride by 4 when the stride is already in bytes and not pixels.
This commit is contained in:
parent
4205e49786
commit
cab95c5eed
@ -29,6 +29,7 @@ set(COMMON_SOURCES
|
|||||||
src/framebuffer.c
|
src/framebuffer.c
|
||||||
src/KVMFR.c
|
src/KVMFR.c
|
||||||
src/countedbuffer.c
|
src/countedbuffer.c
|
||||||
|
src/rects.c
|
||||||
src/runningavg.c
|
src/runningavg.c
|
||||||
src/ringbuffer.c
|
src/ringbuffer.c
|
||||||
)
|
)
|
||||||
|
45
common/include/common/rects.h
Normal file
45
common/include/common/rects.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2021 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LG_COMMON_RECTS_H_
|
||||||
|
#define _LG_COMMON_RECTS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "common/framebuffer.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
inline static void rectCopyUnaligned(uint8_t * dest, const uint8_t * src,
|
||||||
|
int ystart, int yend, int dx, int dstStride, int srcStride, int width)
|
||||||
|
{
|
||||||
|
for (int i = ystart; i < yend; ++i)
|
||||||
|
{
|
||||||
|
unsigned int srcOffset = i * srcStride + dx;
|
||||||
|
unsigned int dstOffset = i * dstStride + dx;
|
||||||
|
memcpy(dest + dstOffset, src + srcOffset, width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count,
|
||||||
|
FrameBuffer * frame, int dstStride, int height,
|
||||||
|
const uint8_t * src, int srcStride);
|
||||||
|
|
||||||
|
#endif
|
174
common/src/rects.c
Normal file
174
common/src/rects.c
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2021 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 "common/rects.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct Corner
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Edge
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cornerCompare(const void * a_, const void * b_)
|
||||||
|
{
|
||||||
|
const struct Corner * a = a_;
|
||||||
|
const struct Corner * b = b_;
|
||||||
|
|
||||||
|
if (a->y < b->y) return -1;
|
||||||
|
if (a->y > b->y) return +1;
|
||||||
|
if (a->x < b->x) return -1;
|
||||||
|
if (a->x > b->x) return +1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void rectsBufferCopy(FrameDamageRect * rects, int count,
|
||||||
|
uint8_t * dst, int dstStride, int height,
|
||||||
|
const uint8_t * src, int srcStride, void * opaque,
|
||||||
|
void (*rowCopyFinish)(int y, void * opaque))
|
||||||
|
{
|
||||||
|
const int cornerCount = 4 * count;
|
||||||
|
struct Corner corners[cornerCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
FrameDamageRect * rect = rects + i;
|
||||||
|
corners[4 * i + 0] = (struct Corner) {
|
||||||
|
.x = rect->x, .y = rect->y, .delta = 1
|
||||||
|
};
|
||||||
|
corners[4 * i + 1] = (struct Corner) {
|
||||||
|
.x = rect->x + rect->width, .y = rect->y, .delta = -1
|
||||||
|
};
|
||||||
|
corners[4 * i + 2] = (struct Corner) {
|
||||||
|
.x = rect->x, .y = rect->y + rect->height, .delta = -1
|
||||||
|
};
|
||||||
|
corners[4 * i + 3] = (struct Corner) {
|
||||||
|
.x = rect->x + rect->width, .y = rect->y + rect->height, .delta = 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
qsort(corners, cornerCount, sizeof(struct Corner), cornerCompare);
|
||||||
|
|
||||||
|
struct Edge active_[2][cornerCount];
|
||||||
|
struct Edge change[cornerCount];
|
||||||
|
int prev_y = 0;
|
||||||
|
int activeRow = 0;
|
||||||
|
int actives = 0;
|
||||||
|
|
||||||
|
for (int rs = 0;;)
|
||||||
|
{
|
||||||
|
int y = corners[rs].y;
|
||||||
|
int re = rs;
|
||||||
|
while (re < cornerCount && corners[re].y == y)
|
||||||
|
++re;
|
||||||
|
|
||||||
|
if (y > height)
|
||||||
|
y = height;
|
||||||
|
|
||||||
|
int changes = 0;
|
||||||
|
for (int i = rs; i < re; )
|
||||||
|
{
|
||||||
|
int x = corners[i].x;
|
||||||
|
int delta = 0;
|
||||||
|
while (i < re && corners[i].x == x)
|
||||||
|
delta += corners[i++].delta;
|
||||||
|
change[changes++] = (struct Edge) { .x = x, .delta = delta };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Edge * active = active_[activeRow];
|
||||||
|
int x1 = 0;
|
||||||
|
int in_rect = 0;
|
||||||
|
for (int i = 0; i < actives; ++i)
|
||||||
|
{
|
||||||
|
if (!in_rect)
|
||||||
|
x1 = active[i].x;
|
||||||
|
in_rect += active[i].delta;
|
||||||
|
if (!in_rect)
|
||||||
|
rectCopyUnaligned(dst, src, prev_y, y, x1 * 4, dstStride, srcStride,
|
||||||
|
(active[i].x - x1) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (re >= cornerCount || y == height)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (rowCopyFinish)
|
||||||
|
rowCopyFinish(y, opaque);
|
||||||
|
|
||||||
|
struct Edge * new = active_[activeRow ^ 1];
|
||||||
|
int ai = 0;
|
||||||
|
int ci = 0;
|
||||||
|
int ni = 0;
|
||||||
|
|
||||||
|
while (ai < actives && ci < changes)
|
||||||
|
{
|
||||||
|
if (active[ai].x < change[ci].x)
|
||||||
|
new[ni++] = active[ai++];
|
||||||
|
else if (active[ai].x > change[ci].x)
|
||||||
|
new[ni++] = change[ci++];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
active[ai].delta += change[ci++].delta;
|
||||||
|
if (active[ai].delta != 0)
|
||||||
|
new[ni++] = active[ai];
|
||||||
|
++ai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only one of (actives - ai) and (changes - ci) will be non-zero.
|
||||||
|
memcpy(new + ni, active + ai, (actives - ai) * sizeof(struct Edge));
|
||||||
|
memcpy(new + ni, change + ci, (changes - ci) * sizeof(struct Edge));
|
||||||
|
ni += actives - ai;
|
||||||
|
ni += changes - ci;
|
||||||
|
|
||||||
|
actives = ni;
|
||||||
|
prev_y = y;
|
||||||
|
rs = re;
|
||||||
|
activeRow ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ToFramebufferData
|
||||||
|
{
|
||||||
|
FrameBuffer * frame;
|
||||||
|
int stride;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fbRowFinish(int y, void * opaque)
|
||||||
|
{
|
||||||
|
struct ToFramebufferData * data = opaque;
|
||||||
|
framebuffer_set_write_ptr(data->frame, y * data->stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count,
|
||||||
|
FrameBuffer * frame, int dstStride, int height,
|
||||||
|
const uint8_t * src, int srcStride)
|
||||||
|
{
|
||||||
|
struct ToFramebufferData data = { .frame = frame, .stride = dstStride };
|
||||||
|
rectsBufferCopy(rects, count, framebuffer_get_data(frame), dstStride, height,
|
||||||
|
src, srcStride, &data, fbRowFinish);
|
||||||
|
framebuffer_set_write_ptr(frame, height * dstStride);
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
#include "common/locking.h"
|
#include "common/locking.h"
|
||||||
#include "common/event.h"
|
#include "common/event.h"
|
||||||
|
#include "common/rects.h"
|
||||||
#include "common/runningavg.h"
|
#include "common/runningavg.h"
|
||||||
#include "common/KVMFR.h"
|
#include "common/KVMFR.h"
|
||||||
|
|
||||||
@ -1027,144 +1028,6 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
|
|||||||
return CAPTURE_RESULT_OK;
|
return CAPTURE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Corner
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int delta;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Edge
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
int delta;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cornerCompare(const void * a_, const void * b_)
|
|
||||||
{
|
|
||||||
const struct Corner * a = a_;
|
|
||||||
const struct Corner * b = b_;
|
|
||||||
|
|
||||||
if (a->y < b->y) return -1;
|
|
||||||
if (a->y > b->y) return +1;
|
|
||||||
if (a->x < b->x) return -1;
|
|
||||||
if (a->x > b->x) return +1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void rectCopyUnaligned(uint8_t * dest, const uint8_t * src, int ystart,
|
|
||||||
int yend, int dx, int stride, int width)
|
|
||||||
{
|
|
||||||
for (int i = ystart; i < yend; ++i)
|
|
||||||
{
|
|
||||||
unsigned int offset = i * stride + dx;
|
|
||||||
memcpy(dest + offset, src + offset, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyRects(struct FrameDamage * damage, FrameBuffer * frame, int height,
|
|
||||||
const uint8_t * src, int stride)
|
|
||||||
{
|
|
||||||
uint8_t * frameData = framebuffer_get_data(frame);
|
|
||||||
struct Corner corners[4 * KVMFR_MAX_DAMAGE_RECTS];
|
|
||||||
const int cornerCount = 4 * damage->count;
|
|
||||||
|
|
||||||
for (int i = 0; i < damage->count; ++i)
|
|
||||||
{
|
|
||||||
FrameDamageRect * rect = damage->rects + i;
|
|
||||||
corners[4 * i + 0] = (struct Corner) {
|
|
||||||
.x = rect->x, .y = rect->y, .delta = 1
|
|
||||||
};
|
|
||||||
corners[4 * i + 1] = (struct Corner) {
|
|
||||||
.x = rect->x + rect->width, .y = rect->y, .delta = -1
|
|
||||||
};
|
|
||||||
corners[4 * i + 2] = (struct Corner) {
|
|
||||||
.x = rect->x, .y = rect->y + rect->height, .delta = -1
|
|
||||||
};
|
|
||||||
corners[4 * i + 3] = (struct Corner) {
|
|
||||||
.x = rect->x + rect->width, .y = rect->y + rect->height, .delta = 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
qsort(corners, cornerCount, sizeof(struct Corner), cornerCompare);
|
|
||||||
|
|
||||||
struct Edge active_[2][4 * KVMFR_MAX_DAMAGE_RECTS];
|
|
||||||
struct Edge change[4 * KVMFR_MAX_DAMAGE_RECTS];
|
|
||||||
int prev_y = 0;
|
|
||||||
int activeRow = 0;
|
|
||||||
int actives = 0;
|
|
||||||
|
|
||||||
for (int rs = 0;;)
|
|
||||||
{
|
|
||||||
int y = corners[rs].y;
|
|
||||||
int re = rs;
|
|
||||||
while (re < cornerCount && corners[re].y == y)
|
|
||||||
++re;
|
|
||||||
|
|
||||||
if (y > height)
|
|
||||||
y = height;
|
|
||||||
|
|
||||||
int changes = 0;
|
|
||||||
for (int i = rs; i < re; )
|
|
||||||
{
|
|
||||||
int x = corners[i].x;
|
|
||||||
int delta = 0;
|
|
||||||
while (i < re && corners[i].x == x)
|
|
||||||
delta += corners[i++].delta;
|
|
||||||
change[changes++] = (struct Edge) { .x = x, .delta = delta };
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Edge * active = active_[activeRow];
|
|
||||||
int x1 = 0;
|
|
||||||
int in_rect = 0;
|
|
||||||
for (int i = 0; i < actives; ++i)
|
|
||||||
{
|
|
||||||
if (!in_rect)
|
|
||||||
x1 = active[i].x;
|
|
||||||
in_rect += active[i].delta;
|
|
||||||
if (!in_rect)
|
|
||||||
rectCopyUnaligned(frameData, src, prev_y, y, x1 * 4, stride, (active[i].x - x1) * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (re >= cornerCount || y == height)
|
|
||||||
break;
|
|
||||||
|
|
||||||
framebuffer_set_write_ptr(frame, y * stride * 4);
|
|
||||||
|
|
||||||
struct Edge * new = active_[activeRow ^ 1];
|
|
||||||
int ai = 0;
|
|
||||||
int ci = 0;
|
|
||||||
int ni = 0;
|
|
||||||
|
|
||||||
while (ai < actives && ci < changes)
|
|
||||||
{
|
|
||||||
if (active[ai].x < change[ci].x)
|
|
||||||
new[ni++] = active[ai++];
|
|
||||||
else if (active[ai].x > change[ci].x)
|
|
||||||
new[ni++] = change[ci++];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
active[ai].delta += change[ci++].delta;
|
|
||||||
if (active[ai].delta != 0)
|
|
||||||
new[ni++] = active[ai];
|
|
||||||
++ai;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only one of (actives - ai) and (changes - ci) will be non-zero.
|
|
||||||
memcpy(new + ni, active + ai, (actives - ai) * sizeof(struct Edge));
|
|
||||||
memcpy(new + ni, change + ci, (changes - ci) * sizeof(struct Edge));
|
|
||||||
ni += actives - ai;
|
|
||||||
ni += changes - ci;
|
|
||||||
|
|
||||||
actives = ni;
|
|
||||||
prev_y = y;
|
|
||||||
rs = re;
|
|
||||||
activeRow ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
framebuffer_set_write_ptr(frame, height * stride * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CaptureResult dxgi_getFrame(FrameBuffer * frame,
|
static CaptureResult dxgi_getFrame(FrameBuffer * frame,
|
||||||
const unsigned int height, int frameIndex)
|
const unsigned int height, int frameIndex)
|
||||||
{
|
{
|
||||||
@ -1184,7 +1047,8 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame,
|
|||||||
memcpy(damage->rects + damage->count, tex->damageRects,
|
memcpy(damage->rects + damage->count, tex->damageRects,
|
||||||
tex->damageRectsCount * sizeof(FrameDamageRect));
|
tex->damageRectsCount * sizeof(FrameDamageRect));
|
||||||
damage->count += tex->damageRectsCount;
|
damage->count += tex->damageRectsCount;
|
||||||
copyRects(damage, frame, height, tex->map.pData, this->pitch);
|
rectsBufferToFramebuffer(damage->rects, damage->count, frame, this->pitch,
|
||||||
|
height, tex->map.pData, this->pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
#include "common/framebuffer.h"
|
#include "common/framebuffer.h"
|
||||||
#include "common/event.h"
|
#include "common/event.h"
|
||||||
|
#include "common/rects.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "common/KVMFR.h"
|
#include "common/KVMFR.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -482,17 +483,6 @@ static CaptureResult nvfbc_waitFrame(CaptureFrame * frame,
|
|||||||
return CAPTURE_RESULT_OK;
|
return CAPTURE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void rectCopyUnaligned(uint8_t * dest, uint8_t * src, int ystart,
|
|
||||||
int yend, int dx, int dstStride, int srcStride, int width)
|
|
||||||
{
|
|
||||||
for (int i = ystart; i < yend; ++i)
|
|
||||||
{
|
|
||||||
unsigned int srcOffset = i * srcStride + dx;
|
|
||||||
unsigned int dstOffset = i * dstStride + dx;
|
|
||||||
memcpy(dest + dstOffset, src + srcOffset, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CaptureResult nvfbc_getFrame(FrameBuffer * frame,
|
static CaptureResult nvfbc_getFrame(FrameBuffer * frame,
|
||||||
const unsigned int height, int frameIndex)
|
const unsigned int height, int frameIndex)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user