mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 13:52:57 +00:00
[client] implement support for RGB24 packed data
This commit is contained in:
parent
578d98fd22
commit
c665044bfa
30 changed files with 548 additions and 151 deletions
|
@ -76,6 +76,8 @@ typedef struct LG_RendererFormat
|
||||||
bool hdrPQ; // if the HDR content is PQ mapped
|
bool hdrPQ; // if the HDR content is PQ mapped
|
||||||
unsigned int screenWidth; // actual width of the host
|
unsigned int screenWidth; // actual width of the host
|
||||||
unsigned int screenHeight; // actual height 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 frameWidth; // width of frame transmitted
|
||||||
unsigned int frameHeight; // height of frame transmitted
|
unsigned int frameHeight; // height of frame transmitted
|
||||||
unsigned int stride; // scanline width (zero if compresed)
|
unsigned int stride; // scanline width (zero if compresed)
|
||||||
|
|
|
@ -56,6 +56,7 @@ build_shaders(
|
||||||
shader/damage.vert
|
shader/damage.vert
|
||||||
shader/damage.frag
|
shader/damage.frag
|
||||||
shader/basic.vert
|
shader/basic.vert
|
||||||
|
shader/convert_bgr_bgra.frag
|
||||||
shader/ffx_cas.frag
|
shader/ffx_cas.frag
|
||||||
shader/ffx_fsr1_easu.frag
|
shader/ffx_fsr1_easu.frag
|
||||||
shader/ffx_fsr1_rcas.frag
|
shader/ffx_fsr1_rcas.frag
|
||||||
|
@ -87,6 +88,7 @@ add_library(renderer_EGL STATIC
|
||||||
postprocess.c
|
postprocess.c
|
||||||
ffx.c
|
ffx.c
|
||||||
filter.c
|
filter.c
|
||||||
|
filter_bgr_bgra.c
|
||||||
filter_ffx_cas.c
|
filter_ffx_cas.c
|
||||||
filter_ffx_fsr1.c
|
filter_ffx_fsr1.c
|
||||||
filter_downscale.c
|
filter_downscale.c
|
||||||
|
|
|
@ -277,7 +277,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
|
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);
|
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
|
||||||
}
|
}
|
||||||
// fall through
|
// fall through
|
||||||
|
@ -285,7 +285,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||||
case LG_CURSOR_COLOR:
|
case LG_CURSOR_COLOR:
|
||||||
{
|
{
|
||||||
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
|
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);
|
egl_textureUpdate(cursor->norm.texture, data, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -311,9 +311,9 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
|
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,
|
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->norm.texture, (uint8_t *)and, true);
|
||||||
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
|
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -119,8 +119,8 @@ static bool egl_initDesktopShader(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
|
|
||||||
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
|
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
|
||||||
|
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
|
||||||
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
|
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
|
||||||
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
|
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
|
||||||
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
|
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
|
||||||
|
@ -206,6 +206,9 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this MUST be first
|
||||||
|
egl_postProcessAdd(desktop->pp, &egl_filterBGRtoBGRAOps);
|
||||||
|
|
||||||
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
|
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
|
||||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
||||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
|
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
|
||||||
|
@ -337,6 +340,10 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||||
pixFmt = EGL_PF_RGBA16F;
|
pixFmt = EGL_PF_RGBA16F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FRAME_TYPE_BGR:
|
||||||
|
pixFmt = EGL_PF_BGR;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_ERROR("Unsupported frame format");
|
DEBUG_ERROR("Unsupported frame format");
|
||||||
return false;
|
return false;
|
||||||
|
@ -350,8 +357,9 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||||
if (!egl_textureSetup(
|
if (!egl_textureSetup(
|
||||||
desktop->texture,
|
desktop->texture,
|
||||||
pixFmt,
|
pixFmt,
|
||||||
format.frameWidth,
|
format.dataWidth,
|
||||||
format.frameHeight,
|
format.dataHeight,
|
||||||
|
format.stride,
|
||||||
format.pitch
|
format.pitch
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
|
@ -572,6 +580,7 @@ void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
|
||||||
EGL_PF_BGRA,
|
EGL_PF_BGRA,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
width,
|
||||||
width * 4
|
width * 4
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
|
@ -595,7 +604,7 @@ void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
|
||||||
|
|
||||||
for(; y < height; ++y)
|
for(; y < height; ++y)
|
||||||
egl_textureUpdateRect(desktop->spiceTexture,
|
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);
|
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)
|
int height, int stride, uint8_t * data, bool topDown)
|
||||||
{
|
{
|
||||||
egl_textureUpdateRect(desktop->spiceTexture,
|
egl_textureUpdateRect(desktop->spiceTexture,
|
||||||
x, y, width, height, stride, data, topDown);
|
x, y, width, height, width, stride, data, topDown);
|
||||||
atomic_store(&desktop->processFrame, true);
|
atomic_store(&desktop->processFrame, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ typedef enum EGL_PixelFormat
|
||||||
EGL_PF_RGBA,
|
EGL_PF_RGBA,
|
||||||
EGL_PF_BGRA,
|
EGL_PF_BGRA,
|
||||||
EGL_PF_RGBA10,
|
EGL_PF_RGBA10,
|
||||||
EGL_PF_RGBA16F
|
EGL_PF_RGBA16F,
|
||||||
|
EGL_PF_BGR
|
||||||
}
|
}
|
||||||
EGL_PixelFormat;
|
EGL_PixelFormat;
|
||||||
|
|
||||||
|
@ -60,13 +61,17 @@ typedef struct EGL_TexSetup
|
||||||
/* the height of the texture in pixels */
|
/* the height of the texture in pixels */
|
||||||
size_t height;
|
size_t height;
|
||||||
|
|
||||||
/* the stide of the texture in bytes */
|
/* the row length of the texture in pixels */
|
||||||
size_t stride;
|
size_t stride;
|
||||||
|
|
||||||
|
/* the row length of the texture in bytes */
|
||||||
|
size_t pitch;
|
||||||
}
|
}
|
||||||
EGL_TexSetup;
|
EGL_TexSetup;
|
||||||
|
|
||||||
typedef enum EGL_FilterType
|
typedef enum EGL_FilterType
|
||||||
{
|
{
|
||||||
|
EGL_FILTER_TYPE_INTERNAL,
|
||||||
EGL_FILTER_TYPE_EFFECT,
|
EGL_FILTER_TYPE_EFFECT,
|
||||||
EGL_FILTER_TYPE_UPSCALE,
|
EGL_FILTER_TYPE_UPSCALE,
|
||||||
EGL_FILTER_TYPE_DOWNSCALE
|
EGL_FILTER_TYPE_DOWNSCALE
|
||||||
|
|
|
@ -72,7 +72,8 @@ typedef struct EGL_FilterOps
|
||||||
* useDMA will be true if the texture provided needs to use samplerExternalOES
|
* useDMA will be true if the texture provided needs to use samplerExternalOES
|
||||||
*/
|
*/
|
||||||
bool (*setup)(EGL_Filter * filter, enum EGL_PixelFormat pixFmt,
|
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
|
/* set the output resolution hint for the filter
|
||||||
* this is optional and only a hint */
|
* this is optional and only a hint */
|
||||||
|
@ -104,6 +105,12 @@ typedef struct EGL_Filter
|
||||||
}
|
}
|
||||||
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)
|
static inline bool egl_filterInit(const EGL_FilterOps * ops, EGL_Filter ** filter)
|
||||||
{
|
{
|
||||||
if (!ops->init(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)
|
static inline bool egl_filterImguiConfig(EGL_Filter * filter)
|
||||||
{
|
{
|
||||||
return filter->ops.imguiConfig(filter);
|
if (filter->ops.imguiConfig)
|
||||||
|
return filter->ops.imguiConfig(filter);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void egl_filterSaveState(EGL_Filter * filter)
|
static inline void egl_filterSaveState(EGL_Filter * filter)
|
||||||
{
|
{
|
||||||
filter->ops.saveState(filter);
|
if (filter->ops.saveState)
|
||||||
|
filter->ops.saveState(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void egl_filterLoadState(EGL_Filter * filter)
|
static inline void egl_filterLoadState(EGL_Filter * filter)
|
||||||
{
|
{
|
||||||
filter->ops.loadState(filter);
|
if (filter->ops.loadState)
|
||||||
|
filter->ops.loadState(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool egl_filterSetup(EGL_Filter * filter,
|
static inline bool egl_filterSetup(EGL_Filter * filter,
|
||||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||||
|
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||||
bool useDMA)
|
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,
|
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,
|
static bool egl_filterDownscaleSetup(EGL_Filter * filter,
|
||||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||||
|
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||||
bool useDMA)
|
bool useDMA)
|
||||||
{
|
{
|
||||||
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
|
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,
|
static bool egl_filterFFXCASSetup(EGL_Filter * filter,
|
||||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||||
|
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||||
bool useDMA)
|
bool useDMA)
|
||||||
{
|
{
|
||||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
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,
|
static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||||
|
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||||
bool useDMA)
|
bool useDMA)
|
||||||
{
|
{
|
||||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
extern EGL_FilterOps egl_filterBGRtoBGRAOps;
|
||||||
extern EGL_FilterOps egl_filterDownscaleOps;
|
extern EGL_FilterOps egl_filterDownscaleOps;
|
||||||
extern EGL_FilterOps egl_filterFFXCASOps;
|
extern EGL_FilterOps egl_filterFFXCASOps;
|
||||||
extern EGL_FilterOps egl_filterFFXFSR1Ops;
|
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,
|
bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
|
||||||
unsigned int width, unsigned int height)
|
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");
|
DEBUG_ERROR("Failed to setup the texture");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -48,7 +48,7 @@ static const EGL_FilterOps * EGL_Filters[] =
|
||||||
|
|
||||||
struct EGL_PostProcess
|
struct EGL_PostProcess
|
||||||
{
|
{
|
||||||
Vector filters;
|
Vector filters, internalFilters;
|
||||||
EGL_Texture * output;
|
EGL_Texture * output;
|
||||||
unsigned int outputX, outputY;
|
unsigned int outputX, outputY;
|
||||||
_Atomic(bool) modified;
|
_Atomic(bool) modified;
|
||||||
|
@ -85,7 +85,7 @@ void egl_postProcessEarlyInit(void)
|
||||||
option_register(options);
|
option_register(options);
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_LENGTH(EGL_Filters); ++i)
|
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);
|
static void loadPreset(struct EGL_PostProcess * this, const char * name);
|
||||||
|
@ -464,7 +464,8 @@ static void configUI(void * opaque, int * id)
|
||||||
static size_t mouseIdx = -1;
|
static size_t mouseIdx = -1;
|
||||||
static bool moving = false;
|
static bool moving = false;
|
||||||
static size_t moveIdx = 0;
|
static size_t moveIdx = 0;
|
||||||
bool doMove = false;
|
|
||||||
|
bool doMove = false;
|
||||||
|
|
||||||
ImVec2 window, pos;
|
ImVec2 window, pos;
|
||||||
igGetWindowPos(&window);
|
igGetWindowPos(&window);
|
||||||
|
@ -518,9 +519,16 @@ static void configUI(void * opaque, int * id)
|
||||||
{
|
{
|
||||||
EGL_Filter * tmp = filters[moveIdx];
|
EGL_Filter * tmp = filters[moveIdx];
|
||||||
if (mouseIdx > moveIdx) // moving down
|
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
|
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;
|
filters[mouseIdx] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,16 +548,24 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
|
||||||
return false;
|
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");
|
DEBUG_ERROR("Failed to allocate the filter list");
|
||||||
goto error_this;
|
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))
|
if (!egl_desktopRectsInit(&this->rects, 1))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the desktop rects");
|
DEBUG_ERROR("Failed to initialize the desktop rects");
|
||||||
goto error_filters;
|
goto error_internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPresetList(this);
|
loadPresetList(this);
|
||||||
|
@ -559,6 +575,9 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
|
||||||
*pp = this;
|
*pp = this;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error_internal:
|
||||||
|
vector_destroy(&this->internalFilters);
|
||||||
|
|
||||||
error_filters:
|
error_filters:
|
||||||
vector_destroy(&this->filters);
|
vector_destroy(&this->filters);
|
||||||
|
|
||||||
|
@ -579,6 +598,10 @@ void egl_postProcessFree(EGL_PostProcess ** pp)
|
||||||
egl_filterFree(filter);
|
egl_filterFree(filter);
|
||||||
vector_destroy(&this->filters);
|
vector_destroy(&this->filters);
|
||||||
|
|
||||||
|
vector_forEachRef(filter, &this->internalFilters)
|
||||||
|
egl_filterFree(filter);
|
||||||
|
vector_destroy(&this->internalFilters);
|
||||||
|
|
||||||
free(this->presetDir);
|
free(this->presetDir);
|
||||||
if (this->presets)
|
if (this->presets)
|
||||||
stringlist_free(&this->presets);
|
stringlist_free(&this->presets);
|
||||||
|
@ -595,7 +618,10 @@ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops)
|
||||||
if (!egl_filterInit(ops, &filter))
|
if (!egl_filterInit(ops, &filter))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vector_push(&this->filters, &filter);
|
if (ops->type == EGL_FILTER_TYPE_INTERNAL)
|
||||||
|
vector_push(&this->internalFilters, &filter);
|
||||||
|
else
|
||||||
|
vector_push(&this->filters, &filter);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,25 +664,35 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
|
||||||
|
|
||||||
EGL_Filter * filter;
|
EGL_Filter * filter;
|
||||||
EGL_Texture * texture = tex;
|
EGL_Texture * texture = tex;
|
||||||
vector_forEach(filter, &this->filters)
|
|
||||||
|
const Vector * lists[] =
|
||||||
{
|
{
|
||||||
egl_filterSetOutputResHint(filter, targetX, targetY);
|
&this->internalFilters,
|
||||||
|
&this->filters,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY, useDMA) ||
|
for(const Vector ** filters = lists; *filters; ++filters)
|
||||||
!egl_filterPrepare(filter))
|
vector_forEach(filter, *filters)
|
||||||
continue;
|
{
|
||||||
|
egl_filterSetOutputResHint(filter, targetX, targetY);
|
||||||
|
|
||||||
texture = egl_filterRun(filter, &filterRects, texture);
|
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY,
|
||||||
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
|
desktopWidth, desktopHeight, useDMA) ||
|
||||||
|
!egl_filterPrepare(filter))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (lastFilter)
|
texture = egl_filterRun(filter, &filterRects, texture);
|
||||||
egl_filterRelease(lastFilter);
|
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
|
||||||
|
|
||||||
lastFilter = filter;
|
if (lastFilter)
|
||||||
|
egl_filterRelease(lastFilter);
|
||||||
|
|
||||||
// the first filter to run will convert to a normal texture
|
lastFilter = filter;
|
||||||
useDMA = false;
|
|
||||||
}
|
// the first filter to run will convert to a normal texture
|
||||||
|
useDMA = false;
|
||||||
|
}
|
||||||
|
|
||||||
this->output = texture;
|
this->output = texture;
|
||||||
this->outputX = sizeX;
|
this->outputX = sizeX;
|
||||||
|
|
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,
|
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 =
|
const struct EGL_TexSetup setup =
|
||||||
{
|
{
|
||||||
.pixFmt = pixFmt,
|
.pixFmt = pixFmt,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
.stride = stride
|
.stride = stride,
|
||||||
|
.pitch = pitch,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!egl_texUtilGetFormat(&setup, &this->format))
|
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,
|
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)
|
const uint8_t * buffer, bool topDown)
|
||||||
{
|
{
|
||||||
x = clamp(x , 0, this->format.width );
|
x = clamp(x , 0, this->format.width );
|
||||||
|
@ -147,8 +148,8 @@ bool egl_textureUpdateRect(EGL_Texture * this,
|
||||||
.y = y,
|
.y = y,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
.pitch = stride / this->format.bpp,
|
|
||||||
.stride = stride,
|
.stride = stride,
|
||||||
|
.pitch = pitch,
|
||||||
.topDown = topDown,
|
.topDown = topDown,
|
||||||
.buffer = buffer
|
.buffer = buffer
|
||||||
};
|
};
|
||||||
|
@ -193,7 +194,7 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* wait for completion */
|
/* wait for completion */
|
||||||
framebuffer_wait(frame, this->format.bufferSize);
|
framebuffer_wait(frame, this->format.dataSize);
|
||||||
|
|
||||||
return this->ops.update(this, &update);
|
return this->ops.update(this, &update);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ typedef struct EGL_TexUpdate
|
||||||
|
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
|
|
||||||
//pitch = row length in pixels
|
//pitch = row length in pixels
|
||||||
//stride = row length in bytes
|
//stride = row length in bytes
|
||||||
int pitch, stride;
|
int pitch, stride;
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -113,13 +113,13 @@ bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
|
||||||
void egl_textureFree(EGL_Texture ** tex);
|
void egl_textureFree(EGL_Texture ** tex);
|
||||||
|
|
||||||
bool egl_textureSetup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt,
|
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 egl_textureUpdate(EGL_Texture * texture, const uint8_t * buffer,
|
||||||
bool topDown);
|
bool topDown);
|
||||||
|
|
||||||
bool egl_textureUpdateRect(EGL_Texture * texture,
|
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);
|
const uint8_t * buffer, bool topDown);
|
||||||
|
|
||||||
bool egl_textureUpdateFromFrame(EGL_Texture * texture,
|
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);
|
DEBUG_ASSERT(update->type == EGL_TEXTYPE_BUFFER);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, this->tex[0]);
|
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,
|
glTexSubImage2D(GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
update->x,
|
update->x,
|
||||||
|
@ -187,7 +187,7 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
|
||||||
LG_LOCK(this->copyLock);
|
LG_LOCK(this->copyLock);
|
||||||
|
|
||||||
uint8_t * dst = this->buf[this->bufIndex].map +
|
uint8_t * dst = this->buf[this->bufIndex].map +
|
||||||
texture->format.stride * update->y +
|
texture->format.pitch * update->y +
|
||||||
update->x * texture->format.bpp;
|
update->x * texture->format.bpp;
|
||||||
|
|
||||||
if (update->topDown)
|
if (update->topDown)
|
||||||
|
@ -195,19 +195,19 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
|
||||||
const uint8_t * src = update->buffer;
|
const uint8_t * src = update->buffer;
|
||||||
for(int y = 0; y < update->height; ++y)
|
for(int y = 0; y < update->height; ++y)
|
||||||
{
|
{
|
||||||
memcpy(dst, src, update->stride);
|
memcpy(dst, src, update->pitch);
|
||||||
dst += texture->format.stride;
|
dst += texture->format.bufferPitch;
|
||||||
src += update->stride;
|
src += update->pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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)
|
for(int y = 0; y < update->height; ++y)
|
||||||
{
|
{
|
||||||
src -= update->stride;
|
src -= update->stride;
|
||||||
memcpy(dst, 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);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
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,
|
glTexSubImage2D(GL_TEXTURE_2D,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
texture->format.width,
|
texture->format.width,
|
||||||
|
|
|
@ -162,12 +162,12 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
|
||||||
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
|
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
|
||||||
EGLAttrib attribs[] =
|
EGLAttrib attribs[] =
|
||||||
{
|
{
|
||||||
EGL_WIDTH , texture->format.width,
|
EGL_WIDTH , texture->format.width ,
|
||||||
EGL_HEIGHT , texture->format.height,
|
EGL_HEIGHT , texture->format.height,
|
||||||
EGL_LINUX_DRM_FOURCC_EXT , texture->format.fourcc,
|
EGL_LINUX_DRM_FOURCC_EXT , texture->format.fourcc,
|
||||||
EGL_DMA_BUF_PLANE0_FD_EXT , update->dmaFD,
|
EGL_DMA_BUF_PLANE0_FD_EXT , update->dmaFD,
|
||||||
EGL_DMA_BUF_PLANE0_OFFSET_EXT , 0,
|
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_LO_EXT, (modifier & 0xffffffff),
|
||||||
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (modifier >> 32),
|
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (modifier >> 32),
|
||||||
EGL_NONE , EGL_NONE
|
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;
|
damage->count + update->rectCount > KVMFR_MAX_DAMAGE_RECTS;
|
||||||
|
|
||||||
if (damageAll)
|
if (damageAll)
|
||||||
framebuffer_read(
|
{
|
||||||
|
framebuffer_read(
|
||||||
update->frame,
|
update->frame,
|
||||||
parent->buf[parent->bufIndex].map,
|
parent->buf[parent->bufIndex].map,
|
||||||
texture->format.stride,
|
texture->format.pitch,
|
||||||
texture->format.height,
|
texture->format.height,
|
||||||
texture->format.width,
|
texture->format.width,
|
||||||
texture->format.bpp,
|
texture->format.bpp,
|
||||||
texture->format.stride
|
texture->format.pitch
|
||||||
);
|
);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//FIXME! This is broken for BGR24
|
||||||
memcpy(damage->rects + damage->count, update->rects,
|
memcpy(damage->rects + damage->count, update->rects,
|
||||||
update->rectCount * sizeof(FrameDamageRect));
|
update->rectCount * sizeof(FrameDamageRect));
|
||||||
damage->count += update->rectCount;
|
damage->count += update->rectCount;
|
||||||
|
@ -111,10 +114,10 @@ static bool egl_texFBUpdate(EGL_Texture * texture, const EGL_TexUpdate * update)
|
||||||
damage->count,
|
damage->count,
|
||||||
texture->format.bpp,
|
texture->format.bpp,
|
||||||
parent->buf[parent->bufIndex].map,
|
parent->buf[parent->bufIndex].map,
|
||||||
texture->format.stride,
|
texture->format.pitch,
|
||||||
texture->format.height,
|
texture->format.height,
|
||||||
update->frame,
|
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)
|
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:
|
case EGL_PF_BGRA:
|
||||||
fmt->bpp = 4;
|
fmt->bpp = 4;
|
||||||
fmt->format = GL_BGRA_EXT;
|
fmt->format = GL_BGRA_EXT;
|
||||||
|
@ -53,7 +58,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||||
fmt->format = GL_RGBA;
|
fmt->format = GL_RGBA;
|
||||||
fmt->intFormat = GL_RGB10_A2;
|
fmt->intFormat = GL_RGB10_A2;
|
||||||
fmt->dataType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
fmt->dataType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||||
fmt->fourcc = DRM_FORMAT_BGRA2101010;
|
fmt->fourcc = DRM_FORMAT_ABGR2101010;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EGL_PF_RGBA16F:
|
case EGL_PF_RGBA16F:
|
||||||
|
@ -69,22 +74,28 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt->pixFmt = setup->pixFmt;
|
fmt->pixFmt = setup->pixFmt;
|
||||||
fmt->width = setup->width;
|
fmt->width = setup->width;
|
||||||
fmt->height = setup->height;
|
fmt->height = setup->height;
|
||||||
|
fmt->stride = setup->stride;
|
||||||
|
fmt->pitch = setup->pitch;
|
||||||
|
|
||||||
if (setup->stride == 0)
|
if (!fmt->stride)
|
||||||
{
|
fmt->stride = setup->width;
|
||||||
fmt->stride = fmt->width * fmt->bpp;
|
|
||||||
fmt->pitch = fmt->width;
|
if (!fmt->pitch)
|
||||||
}
|
fmt->pitch = fmt->stride * fmt->bpp;
|
||||||
else
|
|
||||||
{
|
fmt->bufferPitch = setup->pitch;
|
||||||
fmt->stride = setup->stride;
|
|
||||||
fmt->pitch = setup->stride / fmt->bpp;
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,14 @@ typedef struct EGL_TexFormat
|
||||||
GLenum intFormat;
|
GLenum intFormat;
|
||||||
GLenum dataType;
|
GLenum dataType;
|
||||||
unsigned int fourcc;
|
unsigned int fourcc;
|
||||||
size_t bufferSize;
|
|
||||||
|
|
||||||
|
size_t dataSize;
|
||||||
size_t width , height;
|
size_t width , height;
|
||||||
size_t stride, pitch;
|
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;
|
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) | \
|
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
|
||||||
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
||||||
|
|
||||||
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4')
|
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4')
|
||||||
#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '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_ABGR16161616F fourcc_code('A', 'B', '4', 'H')
|
||||||
|
|
||||||
#define DRM_FORMAT_MOD_VENDOR_NONE 0
|
#define DRM_FORMAT_MOD_VENDOR_NONE 0
|
||||||
|
|
|
@ -777,13 +777,29 @@ static enum ConfigStatus configure(struct Inst * this)
|
||||||
this->dataFormat = GL_HALF_FLOAT;
|
this->dataFormat = GL_HALF_FLOAT;
|
||||||
break;
|
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:
|
default:
|
||||||
DEBUG_ERROR("Unknown/unsupported compression type");
|
DEBUG_ERROR("Unknown/unsupported compression type");
|
||||||
return CONFIG_STATUS_ERROR;
|
return CONFIG_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the texture size in bytes
|
// 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;
|
this->texPos = 0;
|
||||||
|
|
||||||
g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
|
g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
|
||||||
|
@ -797,10 +813,10 @@ static enum ConfigStatus configure(struct Inst * this)
|
||||||
if (this->amdPinnedMemSupport)
|
if (this->amdPinnedMemSupport)
|
||||||
{
|
{
|
||||||
const int pagesize = getpagesize();
|
const int pagesize = getpagesize();
|
||||||
|
|
||||||
for(int i = 0; i < BUFFER_COUNT; ++i)
|
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])
|
if (!this->texPixels[i])
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to allocate memory for texture");
|
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);
|
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"))
|
if (check_gl_error("glBindBuffer"))
|
||||||
{
|
{
|
||||||
LG_UNLOCK(this->formatLock);
|
LG_UNLOCK(this->formatLock);
|
||||||
|
@ -1162,16 +1179,15 @@ static bool drawFrame(struct Inst * this)
|
||||||
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
|
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
|
||||||
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
|
||||||
|
|
||||||
const int bpp = this->format.bpp / 8;
|
int bpp = this->format.bpp / 8;
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp);
|
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp < 4 ? 1 : 0);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.frameWidth);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.stride);
|
||||||
|
|
||||||
this->texPos = 0;
|
this->texPos = 0;
|
||||||
|
|
||||||
framebuffer_read_fn(
|
framebuffer_read_fn(
|
||||||
this->frame,
|
this->frame,
|
||||||
this->format.frameHeight,
|
this->format.dataHeight,
|
||||||
this->format.frameWidth,
|
this->format.dataWidth,
|
||||||
bpp,
|
bpp,
|
||||||
this->format.pitch,
|
this->format.pitch,
|
||||||
opengl_bufferFn,
|
opengl_bufferFn,
|
||||||
|
@ -1194,9 +1210,17 @@ static bool drawFrame(struct Inst * this)
|
||||||
);
|
);
|
||||||
if (check_gl_error("glTexSubImage2D"))
|
if (check_gl_error("glTexSubImage2D"))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("texWIndex: %u, width: %u, height: %u, vboFormat: %x, texSize: %lu",
|
DEBUG_ERROR(
|
||||||
this->texWIndex, this->format.frameWidth, this->format.frameHeight,
|
"texWIndex: %u, "
|
||||||
this->vboFormat, this->texSize
|
"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.type = frame->type;
|
||||||
lgrFormat.screenWidth = frame->screenWidth;
|
lgrFormat.screenWidth = frame->screenWidth;
|
||||||
lgrFormat.screenHeight = frame->screenHeight;
|
lgrFormat.screenHeight = frame->screenHeight;
|
||||||
|
lgrFormat.dataWidth = frame->dataWidth;
|
||||||
|
lgrFormat.dataHeight = frame->dataHeight;
|
||||||
lgrFormat.frameWidth = frame->frameWidth;
|
lgrFormat.frameWidth = frame->frameWidth;
|
||||||
lgrFormat.frameHeight = frame->frameHeight;
|
lgrFormat.frameHeight = frame->frameHeight;
|
||||||
lgrFormat.stride = frame->stride;
|
lgrFormat.stride = frame->stride;
|
||||||
|
@ -664,21 +666,25 @@ int main_frameThread(void * unused)
|
||||||
}
|
}
|
||||||
g_state.rotate = lgrFormat.rotate;
|
g_state.rotate = lgrFormat.rotate;
|
||||||
|
|
||||||
|
dataSize = lgrFormat.dataHeight * lgrFormat.pitch;
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
switch(frame->type)
|
switch(frame->type)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_RGBA:
|
case FRAME_TYPE_RGBA:
|
||||||
case FRAME_TYPE_BGRA:
|
case FRAME_TYPE_BGRA:
|
||||||
case FRAME_TYPE_RGBA10:
|
case FRAME_TYPE_RGBA10:
|
||||||
dataSize = lgrFormat.frameHeight * lgrFormat.pitch;
|
|
||||||
lgrFormat.bpp = 32;
|
lgrFormat.bpp = 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRAME_TYPE_RGBA16F:
|
case FRAME_TYPE_RGBA16F:
|
||||||
dataSize = lgrFormat.frameHeight * lgrFormat.pitch;
|
|
||||||
lgrFormat.bpp = 64;
|
lgrFormat.bpp = 64;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FRAME_TYPE_BGR:
|
||||||
|
lgrFormat.bpp = 24;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_ERROR("Unsupported frameType");
|
DEBUG_ERROR("Unsupported frameType");
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -695,9 +701,10 @@ int main_frameThread(void * unused)
|
||||||
g_state.formatValid = true;
|
g_state.formatValid = true;
|
||||||
formatVer = frame->formatVer;
|
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],
|
FrameTypeStr[frame->type],
|
||||||
frame->frameWidth, frame->frameHeight,
|
frame->frameWidth, frame->frameHeight,
|
||||||
|
frame->dataWidth , frame->dataHeight ,
|
||||||
frame->stride, frame->pitch,
|
frame->stride, frame->pitch,
|
||||||
frame->rotation,
|
frame->rotation,
|
||||||
frame->flags & FRAME_FLAG_HDR ? 1 : 0,
|
frame->flags & FRAME_FLAG_HDR ? 1 : 0,
|
||||||
|
|
|
@ -149,10 +149,10 @@ typedef struct KVMFRFrame
|
||||||
FrameType type; // the frame data type
|
FrameType type; // the frame data type
|
||||||
uint32_t screenWidth; // the client's screen width
|
uint32_t screenWidth; // the client's screen width
|
||||||
uint32_t screenHeight; // the client's screen height
|
uint32_t screenHeight; // the client's screen height
|
||||||
uint32_t dataWidth; // the packed width of the frame data
|
uint32_t dataWidth; // the packed frame width
|
||||||
uint32_t dataHeight; // the packed height of the frame data
|
uint32_t dataHeight; // the packed frame height
|
||||||
uint32_t frameWidth; // the frame width
|
uint32_t frameWidth; // the unpacked frame width
|
||||||
uint32_t frameHeight; // the frame height
|
uint32_t frameHeight; // the unpacked frame height
|
||||||
FrameRotation rotation; // the frame rotation
|
FrameRotation rotation; // the frame rotation
|
||||||
uint32_t stride; // the row stride (zero if compressed data)
|
uint32_t stride; // the row stride (zero if compressed data)
|
||||||
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)
|
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);
|
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
|
* Read data from the KVMFRFrame into the dst buffer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,23 +28,23 @@
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
inline static void rectCopyUnaligned(uint8_t * dest, const uint8_t * src,
|
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)
|
for (int i = ystart; i < yend; ++i)
|
||||||
{
|
{
|
||||||
unsigned int srcOffset = i * srcStride + dx;
|
unsigned int srcOffset = i * srcPitch + dx;
|
||||||
unsigned int dstOffset = i * dstStride + dx;
|
unsigned int dstOffset = i * dstPitch + dx;
|
||||||
memcpy(dest + dstOffset, src + srcOffset, width);
|
memcpy(dest + dstOffset, src + srcOffset, width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
|
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
|
||||||
FrameBuffer * frame, int dstStride, int height,
|
FrameBuffer * frame, int dstPitch, int height,
|
||||||
const uint8_t * src, int srcStride);
|
const uint8_t * src, int srcPitch);
|
||||||
|
|
||||||
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
|
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
|
||||||
uint8_t * dst, int dstStride, int height,
|
uint8_t * dst, int dstPitch, int height,
|
||||||
const FrameBuffer * frame, int srcStride);
|
const FrameBuffer * frame, int srcPitch);
|
||||||
|
|
||||||
int rectsMergeOverlapping(FrameDamageRect * rects, int count);
|
int rectsMergeOverlapping(FrameDamageRect * rects, int count);
|
||||||
int rectsRejectContained(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_RGBA , // RGBA interleaved: R,G,B,A 32bpp
|
||||||
FRAME_TYPE_RGBA10 , // RGBA interleaved: R,G,B,A 10,10,10,2 bpp
|
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_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
|
FRAME_TYPE_MAX , // sentinel value
|
||||||
}
|
}
|
||||||
FrameType;
|
FrameType;
|
||||||
|
|
|
@ -38,4 +38,6 @@
|
||||||
#define UPCAST(type, x) \
|
#define UPCAST(type, x) \
|
||||||
(type *)((uintptr_t)(x) - offsetof(type, base))
|
(type *)((uintptr_t)(x) - offsetof(type, base))
|
||||||
|
|
||||||
|
#define ALIGN_TO(value, align) (((value) + (align) - 1) & -(align))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,8 +47,8 @@ bool framebuffer_wait(const FrameBuffer * frame, size_t size)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
bool framebuffer_read_linear(const FrameBuffer * frame, void * restrict dst,
|
||||||
size_t dstpitch, size_t height, size_t width, size_t bpp, size_t pitch)
|
size_t size)
|
||||||
{
|
{
|
||||||
#ifdef FB_PROFILE
|
#ifdef FB_PROFILE
|
||||||
static RunningAvg ra = NULL;
|
static RunningAvg ra = NULL;
|
||||||
|
@ -62,34 +62,54 @@ bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
|
||||||
uint_least32_t rp = 0;
|
uint_least32_t rp = 0;
|
||||||
|
|
||||||
// copy in large 1MB chunks if the pitches match
|
// copy in large 1MB chunks if the pitches match
|
||||||
if (dstpitch == pitch)
|
while(size)
|
||||||
{
|
{
|
||||||
size_t remaining = height * pitch;
|
const size_t copy = size < FB_CHUNK_SIZE ? size : FB_CHUNK_SIZE;
|
||||||
while(remaining)
|
if (!framebuffer_wait(frame, rp + copy))
|
||||||
{
|
return false;
|
||||||
const size_t copy = remaining < FB_CHUNK_SIZE ? remaining : FB_CHUNK_SIZE;
|
|
||||||
if (!framebuffer_wait(frame, rp + copy))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memcpy(d, frame->data + rp, copy);
|
memcpy(d, frame->data + rp, copy);
|
||||||
remaining -= copy;
|
size -= copy;
|
||||||
rp += copy;
|
rp += copy;
|
||||||
d += copy;
|
d += copy;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
if (!framebuffer_wait(frame, rp + linewidth))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memcpy(d, frame->data + rp, dstpitch);
|
#ifdef FB_PROFILE
|
||||||
rp += pitch;
|
runningavg_push(ra, microtime() - ts);
|
||||||
d += dstpitch;
|
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)
|
||||||
|
{
|
||||||
|
if (!framebuffer_wait(frame, rp + linewidth))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(d, frame->data + rp, dstpitch);
|
||||||
|
rp += pitch;
|
||||||
|
d += dstpitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FB_PROFILE
|
#ifdef FB_PROFILE
|
||||||
|
|
|
@ -194,44 +194,44 @@ inline static void rectsBufferCopy(FrameDamageRect * rects, int count, int bpp,
|
||||||
struct ToFramebufferData
|
struct ToFramebufferData
|
||||||
{
|
{
|
||||||
FrameBuffer * frame;
|
FrameBuffer * frame;
|
||||||
int stride;
|
int pitch;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fbRowFinish(int y, void * opaque)
|
static void fbRowFinish(int y, void * opaque)
|
||||||
{
|
{
|
||||||
struct ToFramebufferData * data = 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,
|
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
|
||||||
FrameBuffer * frame, int dstStride, int height,
|
FrameBuffer * frame, int dstPitch, int height,
|
||||||
const uint8_t * src, int srcStride)
|
const uint8_t * src, int srcPitch)
|
||||||
{
|
{
|
||||||
struct ToFramebufferData data = { .frame = frame, .stride = dstStride };
|
struct ToFramebufferData data = { .frame = frame, .pitch = dstPitch };
|
||||||
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstStride,
|
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstPitch,
|
||||||
height, src, srcStride, &data, NULL, fbRowFinish);
|
height, src, srcPitch, &data, NULL, fbRowFinish);
|
||||||
framebuffer_set_write_ptr(frame, height * dstStride);
|
framebuffer_set_write_ptr(frame, height * dstPitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FromFramebufferData
|
struct FromFramebufferData
|
||||||
{
|
{
|
||||||
const FrameBuffer * frame;
|
const FrameBuffer * frame;
|
||||||
int stride;
|
int pitch;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fbRowStart(int y, void * opaque)
|
static void fbRowStart(int y, void * opaque)
|
||||||
{
|
{
|
||||||
struct FromFramebufferData * data = 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,
|
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
|
||||||
uint8_t * dst, int dstStride, int height,
|
uint8_t * dst, int dstPitch, int height,
|
||||||
const FrameBuffer * frame, int srcStride)
|
const FrameBuffer * frame, int srcPitch)
|
||||||
{
|
{
|
||||||
struct FromFramebufferData data = { .frame = frame, .stride = srcStride };
|
struct FromFramebufferData data = { .frame = frame, .pitch = srcPitch };
|
||||||
rectsBufferCopy(rects, count, bpp, dst, dstStride, height,
|
rectsBufferCopy(rects, count, bpp, dst, dstPitch, height,
|
||||||
framebuffer_get_buffer(frame), srcStride, &data, fbRowStart, NULL);
|
framebuffer_get_buffer(frame), srcPitch, &data, fbRowStart, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rectsMergeOverlapping(FrameDamageRect * rects, int count)
|
int rectsMergeOverlapping(FrameDamageRect * rects, int count)
|
||||||
|
|
Loading…
Reference in a new issue