mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +00:00
[client] implement support for RGB24 packed data
This commit is contained in:
parent
578d98fd22
commit
c665044bfa
@ -76,6 +76,8 @@ typedef struct LG_RendererFormat
|
||||
bool hdrPQ; // if the HDR content is PQ mapped
|
||||
unsigned int screenWidth; // actual width of the host
|
||||
unsigned int screenHeight; // actual height of the host
|
||||
unsigned int dataWidth; // the width of the packed data
|
||||
unsigned int dataHeight; // the height of the packed data
|
||||
unsigned int frameWidth; // width of frame transmitted
|
||||
unsigned int frameHeight; // height of frame transmitted
|
||||
unsigned int stride; // scanline width (zero if compresed)
|
||||
|
@ -56,6 +56,7 @@ build_shaders(
|
||||
shader/damage.vert
|
||||
shader/damage.frag
|
||||
shader/basic.vert
|
||||
shader/convert_bgr_bgra.frag
|
||||
shader/ffx_cas.frag
|
||||
shader/ffx_fsr1_easu.frag
|
||||
shader/ffx_fsr1_rcas.frag
|
||||
@ -87,6 +88,7 @@ add_library(renderer_EGL STATIC
|
||||
postprocess.c
|
||||
ffx.c
|
||||
filter.c
|
||||
filter_bgr_bgra.c
|
||||
filter_ffx_cas.c
|
||||
filter_ffx_fsr1.c
|
||||
filter_downscale.c
|
||||
|
@ -277,7 +277,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
}
|
||||
|
||||
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
|
||||
cursor->width, cursor->height, sizeof(xor[0]));
|
||||
cursor->width, cursor->height, cursor->width, sizeof(xor[0]));
|
||||
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
|
||||
}
|
||||
// fall through
|
||||
@ -285,7 +285,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
case LG_CURSOR_COLOR:
|
||||
{
|
||||
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
|
||||
cursor->width, cursor->height, cursor->stride);
|
||||
cursor->width, cursor->height, cursor->width, cursor->stride);
|
||||
egl_textureUpdate(cursor->norm.texture, data, true);
|
||||
break;
|
||||
}
|
||||
@ -311,9 +311,9 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
}
|
||||
|
||||
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
|
||||
cursor->width, cursor->height, sizeof(and[0]));
|
||||
cursor->width, cursor->height, cursor->width, sizeof(and[0]));
|
||||
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
|
||||
cursor->width, cursor->height, sizeof(xor[0]));
|
||||
cursor->width, cursor->height, cursor->width, sizeof(xor[0]));
|
||||
egl_textureUpdate(cursor->norm.texture, (uint8_t *)and, true);
|
||||
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
|
||||
break;
|
||||
|
@ -119,8 +119,8 @@ static bool egl_initDesktopShader(
|
||||
return false;
|
||||
}
|
||||
|
||||
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
|
||||
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
|
||||
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
|
||||
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
|
||||
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
|
||||
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
|
||||
@ -206,6 +206,9 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
return false;
|
||||
}
|
||||
|
||||
// this MUST be first
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterBGRtoBGRAOps);
|
||||
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
|
||||
@ -337,6 +340,10 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
pixFmt = EGL_PF_RGBA16F;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_BGR:
|
||||
pixFmt = EGL_PF_BGR;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsupported frame format");
|
||||
return false;
|
||||
@ -350,8 +357,9 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
if (!egl_textureSetup(
|
||||
desktop->texture,
|
||||
pixFmt,
|
||||
format.frameWidth,
|
||||
format.frameHeight,
|
||||
format.dataWidth,
|
||||
format.dataHeight,
|
||||
format.stride,
|
||||
format.pitch
|
||||
))
|
||||
{
|
||||
@ -572,6 +580,7 @@ void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
|
||||
EGL_PF_BGRA,
|
||||
width,
|
||||
height,
|
||||
width,
|
||||
width * 4
|
||||
))
|
||||
{
|
||||
@ -595,7 +604,7 @@ void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
|
||||
|
||||
for(; y < height; ++y)
|
||||
egl_textureUpdateRect(desktop->spiceTexture,
|
||||
x, y, width, 1, sizeof(line), (uint8_t *)line, false);
|
||||
x, y, width, 1, width, sizeof(line), (uint8_t *)line, false);
|
||||
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
}
|
||||
@ -604,7 +613,7 @@ void egl_desktopSpiceDrawBitmap(EGL_Desktop * desktop, int x, int y, int width,
|
||||
int height, int stride, uint8_t * data, bool topDown)
|
||||
{
|
||||
egl_textureUpdateRect(desktop->spiceTexture,
|
||||
x, y, width, height, stride, data, topDown);
|
||||
x, y, width, height, width, stride, data, topDown);
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,8 @@ typedef enum EGL_PixelFormat
|
||||
EGL_PF_RGBA,
|
||||
EGL_PF_BGRA,
|
||||
EGL_PF_RGBA10,
|
||||
EGL_PF_RGBA16F
|
||||
EGL_PF_RGBA16F,
|
||||
EGL_PF_BGR
|
||||
}
|
||||
EGL_PixelFormat;
|
||||
|
||||
@ -60,13 +61,17 @@ typedef struct EGL_TexSetup
|
||||
/* the height of the texture in pixels */
|
||||
size_t height;
|
||||
|
||||
/* the stide of the texture in bytes */
|
||||
/* the row length of the texture in pixels */
|
||||
size_t stride;
|
||||
|
||||
/* the row length of the texture in bytes */
|
||||
size_t pitch;
|
||||
}
|
||||
EGL_TexSetup;
|
||||
|
||||
typedef enum EGL_FilterType
|
||||
{
|
||||
EGL_FILTER_TYPE_INTERNAL,
|
||||
EGL_FILTER_TYPE_EFFECT,
|
||||
EGL_FILTER_TYPE_UPSCALE,
|
||||
EGL_FILTER_TYPE_DOWNSCALE
|
||||
|
@ -72,7 +72,8 @@ typedef struct EGL_FilterOps
|
||||
* useDMA will be true if the texture provided needs to use samplerExternalOES
|
||||
*/
|
||||
bool (*setup)(EGL_Filter * filter, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height, bool useDMA);
|
||||
unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight, bool useDMA);
|
||||
|
||||
/* set the output resolution hint for the filter
|
||||
* this is optional and only a hint */
|
||||
@ -104,6 +105,12 @@ typedef struct EGL_Filter
|
||||
}
|
||||
EGL_Filter;
|
||||
|
||||
static inline void egl_filterEarlyInit(const EGL_FilterOps * ops)
|
||||
{
|
||||
if (ops->earlyInit)
|
||||
ops->earlyInit();
|
||||
}
|
||||
|
||||
static inline bool egl_filterInit(const EGL_FilterOps * ops, EGL_Filter ** filter)
|
||||
{
|
||||
if (!ops->init(filter))
|
||||
@ -121,24 +128,30 @@ static inline void egl_filterFree(EGL_Filter ** filter)
|
||||
|
||||
static inline bool egl_filterImguiConfig(EGL_Filter * filter)
|
||||
{
|
||||
if (filter->ops.imguiConfig)
|
||||
return filter->ops.imguiConfig(filter);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void egl_filterSaveState(EGL_Filter * filter)
|
||||
{
|
||||
if (filter->ops.saveState)
|
||||
filter->ops.saveState(filter);
|
||||
}
|
||||
|
||||
static inline void egl_filterLoadState(EGL_Filter * filter)
|
||||
{
|
||||
if (filter->ops.loadState)
|
||||
filter->ops.loadState(filter);
|
||||
}
|
||||
|
||||
static inline bool egl_filterSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
return filter->ops.setup(filter, pixFmt, width, height, useDMA);
|
||||
return filter->ops.setup(filter, pixFmt, width, height,
|
||||
desktopWidth, desktopHeight, useDMA);
|
||||
}
|
||||
|
||||
static inline void egl_filterSetOutputResHint(EGL_Filter * filter,
|
||||
|
211
client/renderers/EGL/filter_bgr_bgra.c
Normal file
211
client/renderers/EGL/filter_bgr_bgra.c
Normal file
@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 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 "filter.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include "basic.vert.h"
|
||||
#include "convert_bgr_bgra.frag.h"
|
||||
|
||||
|
||||
typedef struct EGL_FilterBGRtoBGRA
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
bool enable;
|
||||
int useDMA;
|
||||
unsigned int width, height;
|
||||
unsigned int desktopWidth, desktopHeight;
|
||||
bool prepared;
|
||||
|
||||
EGL_Uniform uOutputSize;
|
||||
|
||||
EGL_Shader * shader;
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler[2];
|
||||
}
|
||||
EGL_FilterBGRtoBGRA;
|
||||
|
||||
static bool egl_filterBGRtoBGRAInit(EGL_Filter ** filter)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate ram");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->useDMA = -1;
|
||||
|
||||
if (!egl_shaderInit(&this->shader))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the shader");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&this->fb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the framebuffer");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
glGenSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->shader);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void egl_filterBGRtoBGRAFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter);
|
||||
|
||||
egl_shaderFree(&this->shader);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool egl_filterBGRtoBGRASetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter);
|
||||
|
||||
if (pixFmt != EGL_PF_BGR)
|
||||
return false;
|
||||
|
||||
if (this->useDMA != useDMA)
|
||||
{
|
||||
if (!egl_shaderCompile(this->shader,
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_convert_bgr_bgra_frag, b_shader_convert_bgr_bgra_frag_size,
|
||||
useDMA)
|
||||
)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->uOutputSize.type = EGL_UNIFORM_TYPE_2F;
|
||||
this->uOutputSize.location =
|
||||
egl_shaderGetUniform(this->shader, "outputSize");
|
||||
|
||||
this->useDMA = useDMA;
|
||||
}
|
||||
|
||||
if (this->prepared &&
|
||||
this->width == width &&
|
||||
this->height == height &&
|
||||
this->desktopWidth == desktopWidth &&
|
||||
this->desktopHeight == desktopHeight)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, pixFmt, desktopWidth, desktopHeight))
|
||||
return false;
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->desktopWidth = desktopWidth;
|
||||
this->desktopHeight = desktopHeight;
|
||||
this->prepared = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void egl_filterBGRtoBGRAGetOutputRes(EGL_Filter * filter,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter);
|
||||
*width = this->desktopWidth;
|
||||
*height = this->desktopHeight;
|
||||
}
|
||||
|
||||
static bool egl_filterBGRtoBGRAPrepare(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter);
|
||||
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
this->uOutputSize.f[0] = this->desktopWidth;
|
||||
this->uOutputSize.f[1] = this->desktopHeight;
|
||||
egl_shaderSetUniforms(this->shader, &this->uOutputSize, 1);
|
||||
|
||||
this->prepared = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static EGL_Texture * egl_filterBGRtoBGRARun(EGL_Filter * filter,
|
||||
EGL_FilterRects * rects, EGL_Texture * texture)
|
||||
{
|
||||
EGL_FilterBGRtoBGRA * this = UPCAST(EGL_FilterBGRtoBGRA, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
|
||||
glBindSampler(0, this->sampler[0]);
|
||||
|
||||
egl_shaderUse(this->shader);
|
||||
egl_filterRectsRender(this->shader, rects);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterBGRtoBGRAOps =
|
||||
{
|
||||
.id = "bgrtobgra",
|
||||
.name = "BGRtoBGRA",
|
||||
.type = EGL_FILTER_TYPE_INTERNAL,
|
||||
.earlyInit = NULL,
|
||||
.init = egl_filterBGRtoBGRAInit,
|
||||
.free = egl_filterBGRtoBGRAFree,
|
||||
.imguiConfig = NULL,
|
||||
.saveState = NULL,
|
||||
.loadState = NULL,
|
||||
.setup = egl_filterBGRtoBGRASetup,
|
||||
.getOutputRes = egl_filterBGRtoBGRAGetOutputRes,
|
||||
.prepare = egl_filterBGRtoBGRAPrepare,
|
||||
.run = egl_filterBGRtoBGRARun
|
||||
};
|
@ -299,6 +299,7 @@ static bool egl_filterDownscaleImguiConfig(EGL_Filter * filter)
|
||||
|
||||
static bool egl_filterDownscaleSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
|
||||
|
@ -209,6 +209,7 @@ static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter)
|
||||
|
||||
static bool egl_filterFFXCASSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
@ -323,6 +323,7 @@ static void egl_filterFFXFSR1SetOutputResHint(EGL_Filter * filter,
|
||||
|
||||
static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
extern EGL_FilterOps egl_filterBGRtoBGRAOps;
|
||||
extern EGL_FilterOps egl_filterDownscaleOps;
|
||||
extern EGL_FilterOps egl_filterFFXCASOps;
|
||||
extern EGL_FilterOps egl_filterFFXFSR1Ops;
|
||||
|
@ -64,7 +64,7 @@ void egl_framebufferFree(EGL_Framebuffer ** fb)
|
||||
bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0))
|
||||
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0, 0))
|
||||
{
|
||||
DEBUG_ERROR("Failed to setup the texture");
|
||||
return false;
|
||||
|
@ -48,7 +48,7 @@ static const EGL_FilterOps * EGL_Filters[] =
|
||||
|
||||
struct EGL_PostProcess
|
||||
{
|
||||
Vector filters;
|
||||
Vector filters, internalFilters;
|
||||
EGL_Texture * output;
|
||||
unsigned int outputX, outputY;
|
||||
_Atomic(bool) modified;
|
||||
@ -85,7 +85,7 @@ void egl_postProcessEarlyInit(void)
|
||||
option_register(options);
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(EGL_Filters); ++i)
|
||||
EGL_Filters[i]->earlyInit();
|
||||
egl_filterEarlyInit(EGL_Filters[i]);
|
||||
}
|
||||
|
||||
static void loadPreset(struct EGL_PostProcess * this, const char * name);
|
||||
@ -464,6 +464,7 @@ static void configUI(void * opaque, int * id)
|
||||
static size_t mouseIdx = -1;
|
||||
static bool moving = false;
|
||||
static size_t moveIdx = 0;
|
||||
|
||||
bool doMove = false;
|
||||
|
||||
ImVec2 window, pos;
|
||||
@ -518,9 +519,16 @@ static void configUI(void * opaque, int * id)
|
||||
{
|
||||
EGL_Filter * tmp = filters[moveIdx];
|
||||
if (mouseIdx > moveIdx) // moving down
|
||||
memmove(filters + moveIdx, filters + moveIdx + 1, (mouseIdx - moveIdx) * sizeof(EGL_Filter *));
|
||||
memmove(
|
||||
filters + moveIdx,
|
||||
filters + moveIdx + 1,
|
||||
(mouseIdx - moveIdx) * sizeof(EGL_Filter *));
|
||||
else // moving up
|
||||
memmove(filters + mouseIdx + 1, filters + mouseIdx, (moveIdx - mouseIdx) * sizeof(EGL_Filter *));
|
||||
memmove(
|
||||
filters + mouseIdx + 1,
|
||||
filters + mouseIdx,
|
||||
(moveIdx - mouseIdx) * sizeof(EGL_Filter *));
|
||||
|
||||
filters[mouseIdx] = tmp;
|
||||
}
|
||||
|
||||
@ -540,16 +548,24 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vector_create(&this->filters, sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
|
||||
if (!vector_create(&this->filters,
|
||||
sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate the filter list");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!vector_create(&this->internalFilters,
|
||||
sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate the filter list");
|
||||
goto error_filters;
|
||||
}
|
||||
|
||||
if (!egl_desktopRectsInit(&this->rects, 1))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the desktop rects");
|
||||
goto error_filters;
|
||||
goto error_internal;
|
||||
}
|
||||
|
||||
loadPresetList(this);
|
||||
@ -559,6 +575,9 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
|
||||
*pp = this;
|
||||
return true;
|
||||
|
||||
error_internal:
|
||||
vector_destroy(&this->internalFilters);
|
||||
|
||||
error_filters:
|
||||
vector_destroy(&this->filters);
|
||||
|
||||
@ -579,6 +598,10 @@ void egl_postProcessFree(EGL_PostProcess ** pp)
|
||||
egl_filterFree(filter);
|
||||
vector_destroy(&this->filters);
|
||||
|
||||
vector_forEachRef(filter, &this->internalFilters)
|
||||
egl_filterFree(filter);
|
||||
vector_destroy(&this->internalFilters);
|
||||
|
||||
free(this->presetDir);
|
||||
if (this->presets)
|
||||
stringlist_free(&this->presets);
|
||||
@ -595,6 +618,9 @@ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops)
|
||||
if (!egl_filterInit(ops, &filter))
|
||||
return false;
|
||||
|
||||
if (ops->type == EGL_FILTER_TYPE_INTERNAL)
|
||||
vector_push(&this->internalFilters, &filter);
|
||||
else
|
||||
vector_push(&this->filters, &filter);
|
||||
return true;
|
||||
}
|
||||
@ -638,11 +664,21 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
|
||||
|
||||
EGL_Filter * filter;
|
||||
EGL_Texture * texture = tex;
|
||||
vector_forEach(filter, &this->filters)
|
||||
|
||||
const Vector * lists[] =
|
||||
{
|
||||
&this->internalFilters,
|
||||
&this->filters,
|
||||
NULL
|
||||
};
|
||||
|
||||
for(const Vector ** filters = lists; *filters; ++filters)
|
||||
vector_forEach(filter, *filters)
|
||||
{
|
||||
egl_filterSetOutputResHint(filter, targetX, targetY);
|
||||
|
||||
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY, useDMA) ||
|
||||
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY,
|
||||
desktopWidth, desktopHeight, useDMA) ||
|
||||
!egl_filterPrepare(filter))
|
||||
continue;
|
||||
|
||||
|
35
client/renderers/EGL/shader/convert_bgr_bgra.frag
Normal file
35
client/renderers/EGL/shader/convert_bgr_bgra.frag
Normal file
@ -0,0 +1,35 @@
|
||||
#version 300 es
|
||||
#extension GL_OES_EGL_image_external_essl3 : enable
|
||||
|
||||
precision highp float;
|
||||
|
||||
in vec2 fragCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D sampler1;
|
||||
uniform vec2 outputSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
uvec2 inputSize = uvec2(textureSize(sampler1, 0));
|
||||
uvec2 pos = uvec2(fragCoord * outputSize);
|
||||
uint outputWidth = uint(outputSize.x);
|
||||
|
||||
uint output_idx = pos.y * outputWidth + pos.x;
|
||||
|
||||
uint fst = output_idx * 3u / 4u;
|
||||
vec4 color_0 = texelFetch(sampler1, ivec2(fst % inputSize.x, fst / inputSize.x), 0);
|
||||
|
||||
uint snd = (output_idx * 3u + 1u) / 4u;
|
||||
vec4 color_1 = texelFetch(sampler1, ivec2(snd % inputSize.x, snd / inputSize.x), 0);
|
||||
|
||||
uint trd = (output_idx * 3u + 2u) / 4u;
|
||||
vec4 color_2 = texelFetch(sampler1, ivec2(trd % inputSize.x, trd / inputSize.x), 0);
|
||||
|
||||
fragColor.bgra = vec4(
|
||||
color_0.barg[output_idx % 4u],
|
||||
color_1.gbar[output_idx % 4u],
|
||||
color_2.rgba[output_idx % 4u],
|
||||
1.0
|
||||
);
|
||||
}
|
@ -94,14 +94,15 @@ void egl_textureFree(EGL_Texture ** tex)
|
||||
}
|
||||
|
||||
bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
|
||||
size_t width, size_t height, size_t stride)
|
||||
size_t width, size_t height, size_t stride, size_t pitch)
|
||||
{
|
||||
const struct EGL_TexSetup setup =
|
||||
{
|
||||
.pixFmt = pixFmt,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.stride = stride
|
||||
.stride = stride,
|
||||
.pitch = pitch,
|
||||
};
|
||||
|
||||
if (!egl_texUtilGetFormat(&setup, &this->format))
|
||||
@ -129,7 +130,7 @@ bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer, bool topDown)
|
||||
}
|
||||
|
||||
bool egl_textureUpdateRect(EGL_Texture * this,
|
||||
int x, int y, int width, int height, int stride,
|
||||
int x, int y, int width, int height, int stride, int pitch,
|
||||
const uint8_t * buffer, bool topDown)
|
||||
{
|
||||
x = clamp(x , 0, this->format.width );
|
||||
@ -147,8 +148,8 @@ bool egl_textureUpdateRect(EGL_Texture * this,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.pitch = stride / this->format.bpp,
|
||||
.stride = stride,
|
||||
.pitch = pitch,
|
||||
.topDown = topDown,
|
||||
.buffer = buffer
|
||||
};
|
||||
@ -193,7 +194,7 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
||||
};
|
||||
|
||||
/* wait for completion */
|
||||
framebuffer_wait(frame, this->format.bufferSize);
|
||||
framebuffer_wait(frame, this->format.dataSize);
|
||||
|
||||
return this->ops.update(this, &update);
|
||||
}
|
||||
|
@ -113,13 +113,13 @@ bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
|
||||
void egl_textureFree(EGL_Texture ** tex);
|
||||
|
||||
bool egl_textureSetup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt,
|
||||
size_t width, size_t height, size_t stride);
|
||||
size_t width, size_t height, size_t stride, size_t pitch);
|
||||
|
||||
bool egl_textureUpdate(EGL_Texture * texture, const uint8_t * buffer,
|
||||
bool topDown);
|
||||
|
||||
bool egl_textureUpdateRect(EGL_Texture * texture,
|
||||
int x, int y, int width, int height, int stride,
|
||||
int x, int y, int width, int height, int stride, int pitch,
|
||||
const uint8_t * buffer, bool topDown);
|
||||
|
||||
bool egl_textureUpdateFromFrame(EGL_Texture * texture,
|
||||
|
@ -112,7 +112,7 @@ static bool egl_texBufferUpdate(EGL_Texture * texture, const EGL_TexUpdate * upd
|
||||
DEBUG_ASSERT(update->type == EGL_TEXTYPE_BUFFER);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, this->tex[0]);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, update->pitch);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, update->stride);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
update->x,
|
||||
@ -187,7 +187,7 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
|
||||
LG_LOCK(this->copyLock);
|
||||
|
||||
uint8_t * dst = this->buf[this->bufIndex].map +
|
||||
texture->format.stride * update->y +
|
||||
texture->format.pitch * update->y +
|
||||
update->x * texture->format.bpp;
|
||||
|
||||
if (update->topDown)
|
||||
@ -195,19 +195,19 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
|
||||
const uint8_t * src = update->buffer;
|
||||
for(int y = 0; y < update->height; ++y)
|
||||
{
|
||||
memcpy(dst, src, update->stride);
|
||||
dst += texture->format.stride;
|
||||
src += update->stride;
|
||||
memcpy(dst, src, update->pitch);
|
||||
dst += texture->format.bufferPitch;
|
||||
src += update->pitch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t * src = update->buffer + update->stride * update->height;
|
||||
const uint8_t * src = update->buffer + update->pitch * update->height;
|
||||
for(int y = 0; y < update->height; ++y)
|
||||
{
|
||||
src -= update->stride;
|
||||
memcpy(dst, src, update->stride);
|
||||
dst += texture->format.stride;
|
||||
dst += texture->format.bufferPitch;
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +241,8 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture)
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->format.pitch);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->format.width);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0, 0, 0,
|
||||
texture->format.width,
|
||||
|
@ -162,12 +162,12 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
|
||||
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
|
||||
EGLAttrib attribs[] =
|
||||
{
|
||||
EGL_WIDTH , texture->format.width,
|
||||
EGL_WIDTH , texture->format.width ,
|
||||
EGL_HEIGHT , texture->format.height,
|
||||
EGL_LINUX_DRM_FOURCC_EXT , texture->format.fourcc,
|
||||
EGL_DMA_BUF_PLANE0_FD_EXT , update->dmaFD,
|
||||
EGL_DMA_BUF_PLANE0_OFFSET_EXT , 0,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT , texture->format.stride,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT , texture->format.bufferPitch,
|
||||
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, (modifier & 0xffffffff),
|
||||
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (modifier >> 32),
|
||||
EGL_NONE , EGL_NONE
|
||||
|
@ -92,17 +92,20 @@ static bool egl_texFBUpdate(EGL_Texture * texture, const EGL_TexUpdate * update)
|
||||
damage->count + update->rectCount > KVMFR_MAX_DAMAGE_RECTS;
|
||||
|
||||
if (damageAll)
|
||||
{
|
||||
framebuffer_read(
|
||||
update->frame,
|
||||
parent->buf[parent->bufIndex].map,
|
||||
texture->format.stride,
|
||||
texture->format.pitch,
|
||||
texture->format.height,
|
||||
texture->format.width,
|
||||
texture->format.bpp,
|
||||
texture->format.stride
|
||||
texture->format.pitch
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME! This is broken for BGR24
|
||||
memcpy(damage->rects + damage->count, update->rects,
|
||||
update->rectCount * sizeof(FrameDamageRect));
|
||||
damage->count += update->rectCount;
|
||||
@ -111,10 +114,10 @@ static bool egl_texFBUpdate(EGL_Texture * texture, const EGL_TexUpdate * update)
|
||||
damage->count,
|
||||
texture->format.bpp,
|
||||
parent->buf[parent->bufIndex].map,
|
||||
texture->format.stride,
|
||||
texture->format.pitch,
|
||||
texture->format.height,
|
||||
update->frame,
|
||||
texture->format.stride
|
||||
texture->format.pitch
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,11 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
{
|
||||
switch(setup->pixFmt)
|
||||
{
|
||||
//EGL has no support for 24-bit formats, so we stuff it into a 32-bit
|
||||
//texture to unpack with a shader later
|
||||
case EGL_PF_BGR:
|
||||
// fallthrough
|
||||
|
||||
case EGL_PF_BGRA:
|
||||
fmt->bpp = 4;
|
||||
fmt->format = GL_BGRA_EXT;
|
||||
@ -53,7 +58,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
fmt->format = GL_RGBA;
|
||||
fmt->intFormat = GL_RGB10_A2;
|
||||
fmt->dataType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
fmt->fourcc = DRM_FORMAT_BGRA2101010;
|
||||
fmt->fourcc = DRM_FORMAT_ABGR2101010;
|
||||
break;
|
||||
|
||||
case EGL_PF_RGBA16F:
|
||||
@ -72,19 +77,25 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
fmt->pixFmt = setup->pixFmt;
|
||||
fmt->width = setup->width;
|
||||
fmt->height = setup->height;
|
||||
|
||||
if (setup->stride == 0)
|
||||
{
|
||||
fmt->stride = fmt->width * fmt->bpp;
|
||||
fmt->pitch = fmt->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt->stride = setup->stride;
|
||||
fmt->pitch = setup->stride / fmt->bpp;
|
||||
}
|
||||
fmt->pitch = setup->pitch;
|
||||
|
||||
if (!fmt->stride)
|
||||
fmt->stride = setup->width;
|
||||
|
||||
if (!fmt->pitch)
|
||||
fmt->pitch = fmt->stride * fmt->bpp;
|
||||
|
||||
fmt->bufferPitch = setup->pitch;
|
||||
|
||||
// adjust the stride for 24-bit in 32-bit buffers
|
||||
// this is needed to keep values sane for DMABUF support
|
||||
// if (setup->pixFmt == EGL_PF_BGR)
|
||||
// fmt->bufferPitch = setup->width * 4;
|
||||
|
||||
fmt->dataSize = fmt->height * fmt->pitch;
|
||||
fmt->bufferSize = fmt->height * fmt->bufferPitch;
|
||||
|
||||
fmt->bufferSize = fmt->height * fmt->stride;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,14 @@ typedef struct EGL_TexFormat
|
||||
GLenum intFormat;
|
||||
GLenum dataType;
|
||||
unsigned int fourcc;
|
||||
size_t bufferSize;
|
||||
|
||||
size_t dataSize;
|
||||
size_t width , height;
|
||||
size_t stride, pitch;
|
||||
|
||||
// for 24-bit BGR these are the physical adjusted values to get mapping working
|
||||
size_t bufferSize;
|
||||
size_t bufferPitch;
|
||||
}
|
||||
EGL_TexFormat;
|
||||
|
||||
@ -62,9 +66,10 @@ void egl_texUtilUnmapBuffer(EGL_TexBuffer * buffer);
|
||||
*/
|
||||
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
|
||||
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
||||
|
||||
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4')
|
||||
#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4')
|
||||
#define DRM_FORMAT_BGRA2101010 fourcc_code('A', 'B', '3', '0')
|
||||
#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0')
|
||||
#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H')
|
||||
|
||||
#define DRM_FORMAT_MOD_VENDOR_NONE 0
|
||||
|
@ -777,13 +777,29 @@ static enum ConfigStatus configure(struct Inst * this)
|
||||
this->dataFormat = GL_HALF_FLOAT;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_BGR:
|
||||
this->intFormat = GL_RGB8;
|
||||
this->vboFormat = GL_BGR;
|
||||
this->dataFormat = GL_UNSIGNED_BYTE;
|
||||
|
||||
/* The data that the host returns for 24-bit BGR is tightly packed into an
|
||||
* array that the host GPU will support, we need to adjust the parameters
|
||||
* here to the correct dimensions as OpenGL can use it directly
|
||||
*/
|
||||
this->format.dataWidth = this->format.frameWidth;
|
||||
this->format.dataHeight = this->format.frameHeight;
|
||||
this->format.stride = this->format.frameWidth;
|
||||
this->format.pitch = this->format.frameWidth * 3;
|
||||
this->format.bpp = 24;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unknown/unsupported compression type");
|
||||
return CONFIG_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// calculate the texture size in bytes
|
||||
this->texSize = this->format.frameHeight * this->format.pitch;
|
||||
this->texSize = this->format.dataHeight * this->format.pitch;
|
||||
this->texPos = 0;
|
||||
|
||||
g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
|
||||
@ -797,10 +813,10 @@ static enum ConfigStatus configure(struct Inst * this)
|
||||
if (this->amdPinnedMemSupport)
|
||||
{
|
||||
const int pagesize = getpagesize();
|
||||
|
||||
for(int i = 0; i < BUFFER_COUNT; ++i)
|
||||
{
|
||||
this->texPixels[i] = aligned_alloc(pagesize, this->texSize);
|
||||
this->texPixels[i] = aligned_alloc(pagesize,
|
||||
ALIGN_TO(this->texSize, pagesize));
|
||||
if (!this->texPixels[i])
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory for texture");
|
||||
@ -809,7 +825,8 @@ static enum ConfigStatus configure(struct Inst * this)
|
||||
|
||||
memset(this->texPixels[i], 0, this->texSize);
|
||||
|
||||
g_gl_dynProcs.glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
|
||||
g_gl_dynProcs.glBindBuffer(
|
||||
GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
|
||||
if (check_gl_error("glBindBuffer"))
|
||||
{
|
||||
LG_UNLOCK(this->formatLock);
|
||||
@ -1162,16 +1179,15 @@ static bool drawFrame(struct Inst * this)
|
||||
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
|
||||
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
|
||||
|
||||
const int bpp = this->format.bpp / 8;
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.frameWidth);
|
||||
int bpp = this->format.bpp / 8;
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp < 4 ? 1 : 0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.stride);
|
||||
|
||||
this->texPos = 0;
|
||||
|
||||
framebuffer_read_fn(
|
||||
this->frame,
|
||||
this->format.frameHeight,
|
||||
this->format.frameWidth,
|
||||
this->format.dataHeight,
|
||||
this->format.dataWidth,
|
||||
bpp,
|
||||
this->format.pitch,
|
||||
opengl_bufferFn,
|
||||
@ -1194,9 +1210,17 @@ static bool drawFrame(struct Inst * this)
|
||||
);
|
||||
if (check_gl_error("glTexSubImage2D"))
|
||||
{
|
||||
DEBUG_ERROR("texWIndex: %u, width: %u, height: %u, vboFormat: %x, texSize: %lu",
|
||||
this->texWIndex, this->format.frameWidth, this->format.frameHeight,
|
||||
this->vboFormat, this->texSize
|
||||
DEBUG_ERROR(
|
||||
"texWIndex: %u, "
|
||||
"width: %u, "
|
||||
"height: %u, "
|
||||
"vboFormat: %x, "
|
||||
"texSize: %lu",
|
||||
this->texWIndex,
|
||||
this->format.frameWidth,
|
||||
this->format.frameHeight,
|
||||
this->vboFormat,
|
||||
this->texSize
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -625,6 +625,8 @@ int main_frameThread(void * unused)
|
||||
lgrFormat.type = frame->type;
|
||||
lgrFormat.screenWidth = frame->screenWidth;
|
||||
lgrFormat.screenHeight = frame->screenHeight;
|
||||
lgrFormat.dataWidth = frame->dataWidth;
|
||||
lgrFormat.dataHeight = frame->dataHeight;
|
||||
lgrFormat.frameWidth = frame->frameWidth;
|
||||
lgrFormat.frameHeight = frame->frameHeight;
|
||||
lgrFormat.stride = frame->stride;
|
||||
@ -664,21 +666,25 @@ int main_frameThread(void * unused)
|
||||
}
|
||||
g_state.rotate = lgrFormat.rotate;
|
||||
|
||||
dataSize = lgrFormat.dataHeight * lgrFormat.pitch;
|
||||
|
||||
bool error = false;
|
||||
switch(frame->type)
|
||||
{
|
||||
case FRAME_TYPE_RGBA:
|
||||
case FRAME_TYPE_BGRA:
|
||||
case FRAME_TYPE_RGBA10:
|
||||
dataSize = lgrFormat.frameHeight * lgrFormat.pitch;
|
||||
lgrFormat.bpp = 32;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_RGBA16F:
|
||||
dataSize = lgrFormat.frameHeight * lgrFormat.pitch;
|
||||
lgrFormat.bpp = 64;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_BGR:
|
||||
lgrFormat.bpp = 24;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsupported frameType");
|
||||
error = true;
|
||||
@ -695,9 +701,10 @@ int main_frameThread(void * unused)
|
||||
g_state.formatValid = true;
|
||||
formatVer = frame->formatVer;
|
||||
|
||||
DEBUG_INFO("Format: %s %ux%u stride:%u pitch:%u rotation:%d hdr:%d pq:%d",
|
||||
DEBUG_INFO("Format: %s %ux%u (%ux%u) stride:%u pitch:%u rotation:%d hdr:%d pq:%d",
|
||||
FrameTypeStr[frame->type],
|
||||
frame->frameWidth, frame->frameHeight,
|
||||
frame->dataWidth , frame->dataHeight ,
|
||||
frame->stride, frame->pitch,
|
||||
frame->rotation,
|
||||
frame->flags & FRAME_FLAG_HDR ? 1 : 0,
|
||||
|
@ -149,10 +149,10 @@ typedef struct KVMFRFrame
|
||||
FrameType type; // the frame data type
|
||||
uint32_t screenWidth; // the client's screen width
|
||||
uint32_t screenHeight; // the client's screen height
|
||||
uint32_t dataWidth; // the packed width of the frame data
|
||||
uint32_t dataHeight; // the packed height of the frame data
|
||||
uint32_t frameWidth; // the frame width
|
||||
uint32_t frameHeight; // the frame height
|
||||
uint32_t dataWidth; // the packed frame width
|
||||
uint32_t dataHeight; // the packed frame height
|
||||
uint32_t frameWidth; // the unpacked frame width
|
||||
uint32_t frameHeight; // the unpacked frame height
|
||||
FrameRotation rotation; // the frame rotation
|
||||
uint32_t stride; // the row stride (zero if compressed data)
|
||||
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)
|
||||
|
@ -44,6 +44,12 @@ typedef bool (*FrameBufferReadFn)(void * opaque, const void * src, size_t size);
|
||||
*/
|
||||
bool framebuffer_wait(const FrameBuffer * frame, size_t size);
|
||||
|
||||
/**
|
||||
* Read `size` bytes from the KVMFRFrame into the dst buffer
|
||||
*/
|
||||
bool framebuffer_read_linear(const FrameBuffer * frame, void * restrict dst,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Read data from the KVMFRFrame into the dst buffer
|
||||
*/
|
||||
|
@ -28,23 +28,23 @@
|
||||
#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)
|
||||
int ystart, int yend, int dx, int dstPitch, int srcPitch, int width)
|
||||
{
|
||||
for (int i = ystart; i < yend; ++i)
|
||||
{
|
||||
unsigned int srcOffset = i * srcStride + dx;
|
||||
unsigned int dstOffset = i * dstStride + dx;
|
||||
unsigned int srcOffset = i * srcPitch + dx;
|
||||
unsigned int dstOffset = i * dstPitch + dx;
|
||||
memcpy(dest + dstOffset, src + srcOffset, width);
|
||||
}
|
||||
}
|
||||
|
||||
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
|
||||
FrameBuffer * frame, int dstStride, int height,
|
||||
const uint8_t * src, int srcStride);
|
||||
FrameBuffer * frame, int dstPitch, int height,
|
||||
const uint8_t * src, int srcPitch);
|
||||
|
||||
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
|
||||
uint8_t * dst, int dstStride, int height,
|
||||
const FrameBuffer * frame, int srcStride);
|
||||
uint8_t * dst, int dstPitch, int height,
|
||||
const FrameBuffer * frame, int srcPitch);
|
||||
|
||||
int rectsMergeOverlapping(FrameDamageRect * rects, int count);
|
||||
int rectsRejectContained(FrameDamageRect * rects, int count);
|
||||
|
@ -55,7 +55,7 @@ typedef enum FrameType
|
||||
FRAME_TYPE_RGBA , // RGBA interleaved: R,G,B,A 32bpp
|
||||
FRAME_TYPE_RGBA10 , // RGBA interleaved: R,G,B,A 10,10,10,2 bpp
|
||||
FRAME_TYPE_RGBA16F , // RGBA interleaved: R,G,B,A 16,16,16,16 bpp float
|
||||
FRAME_TYPE_BGR , // BGR interleaved: B,G,R 24bpp
|
||||
FRAME_TYPE_BGR , // BGR (DO NOT COMMIT THIS)
|
||||
FRAME_TYPE_MAX , // sentinel value
|
||||
}
|
||||
FrameType;
|
||||
|
@ -38,4 +38,6 @@
|
||||
#define UPCAST(type, x) \
|
||||
(type *)((uintptr_t)(x) - offsetof(type, base))
|
||||
|
||||
#define ALIGN_TO(value, align) (((value) + (align) - 1) & -(align))
|
||||
|
||||
#endif
|
||||
|
@ -47,8 +47,8 @@ bool framebuffer_wait(const FrameBuffer * frame, size_t size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||
size_t dstpitch, size_t height, size_t width, size_t bpp, size_t pitch)
|
||||
bool framebuffer_read_linear(const FrameBuffer * frame, void * restrict dst,
|
||||
size_t size)
|
||||
{
|
||||
#ifdef FB_PROFILE
|
||||
static RunningAvg ra = NULL;
|
||||
@ -62,23 +62,44 @@ bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||
uint_least32_t rp = 0;
|
||||
|
||||
// copy in large 1MB chunks if the pitches match
|
||||
if (dstpitch == pitch)
|
||||
while(size)
|
||||
{
|
||||
size_t remaining = height * pitch;
|
||||
while(remaining)
|
||||
{
|
||||
const size_t copy = remaining < FB_CHUNK_SIZE ? remaining : FB_CHUNK_SIZE;
|
||||
const size_t copy = size < FB_CHUNK_SIZE ? size : FB_CHUNK_SIZE;
|
||||
if (!framebuffer_wait(frame, rp + copy))
|
||||
return false;
|
||||
|
||||
memcpy(d, frame->data + rp, copy);
|
||||
remaining -= copy;
|
||||
size -= copy;
|
||||
rp += copy;
|
||||
d += copy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#ifdef FB_PROFILE
|
||||
runningavg_push(ra, microtime() - ts);
|
||||
if (++raCount % 100 == 0)
|
||||
DEBUG_INFO("Average Copy Time: %.2fμs", runningavg_calc(ra));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||
size_t dstpitch, size_t height, size_t width, size_t bpp, size_t pitch)
|
||||
{
|
||||
if (dstpitch == pitch)
|
||||
return framebuffer_read_linear(frame, dst, height * pitch);
|
||||
|
||||
#ifdef FB_PROFILE
|
||||
static RunningAvg ra = NULL;
|
||||
static int raCount = 0;
|
||||
const uint64_t ts = microtime();
|
||||
if (!ra)
|
||||
ra = runningavg_new(100);
|
||||
#endif
|
||||
|
||||
uint8_t * restrict d = (uint8_t*)dst;
|
||||
uint_least32_t rp = 0;
|
||||
|
||||
// copy per line to match the pitch of the destination buffer
|
||||
const size_t linewidth = width * bpp;
|
||||
for(size_t y = 0; y < height; ++y)
|
||||
@ -90,7 +111,6 @@ bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||
rp += pitch;
|
||||
d += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FB_PROFILE
|
||||
runningavg_push(ra, microtime() - ts);
|
||||
|
@ -194,44 +194,44 @@ inline static void rectsBufferCopy(FrameDamageRect * rects, int count, int bpp,
|
||||
struct ToFramebufferData
|
||||
{
|
||||
FrameBuffer * frame;
|
||||
int stride;
|
||||
int pitch;
|
||||
};
|
||||
|
||||
static void fbRowFinish(int y, void * opaque)
|
||||
{
|
||||
struct ToFramebufferData * data = opaque;
|
||||
framebuffer_set_write_ptr(data->frame, y * data->stride);
|
||||
framebuffer_set_write_ptr(data->frame, y * data->pitch);
|
||||
}
|
||||
|
||||
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
|
||||
FrameBuffer * frame, int dstStride, int height,
|
||||
const uint8_t * src, int srcStride)
|
||||
FrameBuffer * frame, int dstPitch, int height,
|
||||
const uint8_t * src, int srcPitch)
|
||||
{
|
||||
struct ToFramebufferData data = { .frame = frame, .stride = dstStride };
|
||||
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstStride,
|
||||
height, src, srcStride, &data, NULL, fbRowFinish);
|
||||
framebuffer_set_write_ptr(frame, height * dstStride);
|
||||
struct ToFramebufferData data = { .frame = frame, .pitch = dstPitch };
|
||||
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstPitch,
|
||||
height, src, srcPitch, &data, NULL, fbRowFinish);
|
||||
framebuffer_set_write_ptr(frame, height * dstPitch);
|
||||
}
|
||||
|
||||
struct FromFramebufferData
|
||||
{
|
||||
const FrameBuffer * frame;
|
||||
int stride;
|
||||
int pitch;
|
||||
};
|
||||
|
||||
static void fbRowStart(int y, void * opaque)
|
||||
{
|
||||
struct FromFramebufferData * data = opaque;
|
||||
framebuffer_wait(data->frame, y * data->stride);
|
||||
framebuffer_wait(data->frame, y * data->pitch);
|
||||
}
|
||||
|
||||
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
|
||||
uint8_t * dst, int dstStride, int height,
|
||||
const FrameBuffer * frame, int srcStride)
|
||||
uint8_t * dst, int dstPitch, int height,
|
||||
const FrameBuffer * frame, int srcPitch)
|
||||
{
|
||||
struct FromFramebufferData data = { .frame = frame, .stride = srcStride };
|
||||
rectsBufferCopy(rects, count, bpp, dst, dstStride, height,
|
||||
framebuffer_get_buffer(frame), srcStride, &data, fbRowStart, NULL);
|
||||
struct FromFramebufferData data = { .frame = frame, .pitch = srcPitch };
|
||||
rectsBufferCopy(rects, count, bpp, dst, dstPitch, height,
|
||||
framebuffer_get_buffer(frame), srcPitch, &data, fbRowStart, NULL);
|
||||
}
|
||||
|
||||
int rectsMergeOverlapping(FrameDamageRect * rects, int count)
|
||||
|
Loading…
Reference in New Issue
Block a user