[client] egl: add new downscale filter

This commit is contained in:
Geoffrey McRae 2021-08-12 15:53:35 +10:00
parent b3173bdddc
commit 117e88c240
6 changed files with 296 additions and 2 deletions

View file

@ -63,6 +63,7 @@ build_shaders(
shader/ffx_cas.frag
shader/ffx_fsr1_easu.frag
shader/ffx_fsr1_rcas.frag
shader/downscale.frag
)
make_defines(
@ -91,6 +92,7 @@ add_library(renderer_EGL STATIC
ffx.c
filter_ffx_cas.c
filter_ffx_fsr1.c
filter_downscale.c
${EGL_SHADER_OBJS}
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl3.cpp

View file

@ -171,8 +171,9 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
return false;
}
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops);
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
return true;
}

View file

@ -0,0 +1,263 @@
/**
* Looking Glass
* Copyright © 2017-2021 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "filter.h"
#include "framebuffer.h"
#include <math.h>
#include "common/debug.h"
#include "common/option.h"
#include "cimgui.h"
#include "basic.vert.h"
#include "downscale.frag.h"
typedef struct EGL_FilterDownscale
{
EGL_Filter base;
EGL_Shader * shader;
bool enable;
EGL_Uniform uniform;
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
float pixelSize;
float vOffset, hOffset;
bool prepared;
EGL_Framebuffer * fb;
GLuint sampler;
}
EGL_FilterDownscale;
static void egl_filterDownscaleEarlyInit(void)
{
// doesn't really make sense to have any options for this filter
// as it's per title. We need presets to make this nicer to use.
static struct Option options[] =
{
{ 0 }
};
option_register(options);
}
static bool egl_filterDownscaleInit(EGL_Filter ** filter)
{
EGL_FilterDownscale * this = calloc(1, sizeof(*this));
if (!this)
{
DEBUG_ERROR("Failed to allocate ram");
return false;
}
if (!egl_shaderInit(&this->shader))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_shaderCompile(this->shader,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_downscale_frag, b_shader_downscale_frag_size)
)
{
DEBUG_ERROR("Failed to compile the shader");
goto error_shader;
}
this->uniform.type = EGL_UNIFORM_TYPE_3F;
this->uniform.location =
egl_shaderGetUniform(this->shader, "uConfig");
if (!egl_framebufferInit(&this->fb))
{
DEBUG_ERROR("Failed to initialize the framebuffer");
goto error_shader;
}
glGenSamplers(1, &this->sampler);
glSamplerParameteri(this->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(this->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
this->enable = false;
this->pixelSize = 2.0f;
this->vOffset = 0.0f;
this->hOffset = 0.0f;
*filter = &this->base;
return true;
error_shader:
egl_shaderFree(&this->shader);
error_this:
free(this);
return false;
}
static void egl_filterDownscaleFree(EGL_Filter * filter)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
egl_shaderFree(&this->shader);
egl_framebufferFree(&this->fb);
glDeleteSamplers(1, &this->sampler);
free(this);
}
static bool egl_filterDownscaleImguiConfig(EGL_Filter * filter)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
bool redraw = false;
bool enable = this->enable;
igCheckbox("Enable", &enable);
if (enable != this->enable)
{
this->enable = enable;
redraw = true;
}
int majorPixelSize = floor(this->pixelSize);
int minorPixelSize = (this->pixelSize - majorPixelSize) * 10.0f;
igSliderInt("Major Pixel Size", &majorPixelSize, 1, 10, NULL, 0);
igSliderInt("Minor Pixel Size", &minorPixelSize, 0, 9, NULL, 0);
float pixelSize = (float)majorPixelSize + (float)minorPixelSize / 10.0f;
igText("Pixel Size: %.2f", pixelSize);
igText("Resolution: %dx%d", this->width, this->height);
if (pixelSize != this->pixelSize)
{
this->pixelSize = pixelSize;
redraw = true;
}
float vOffset = this->vOffset;
igSliderFloat("V-Offset", &vOffset, -2, 2, NULL, 0);
if (vOffset != this->vOffset)
{
this->vOffset = vOffset;
redraw = true;
}
float hOffset = this->hOffset;
igSliderFloat("H-Offset", &hOffset, -2, 2, NULL, 0);
if (hOffset != this->hOffset)
{
this->hOffset = hOffset;
redraw = true;
}
if (redraw)
this->prepared = false;
return redraw;
}
static bool egl_filterDownscaleSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
width = (float)width / this->pixelSize;
height = (float)height / this->pixelSize;
if (this->prepared &&
pixFmt == this->pixFmt &&
this->width == width &&
this->height == height)
return this->pixelSize > 1.0f;
if (!egl_framebufferSetup(this->fb, pixFmt, width, height))
return false;
this->pixFmt = pixFmt;
this->width = width;
this->height = height;
this->prepared = false;
return this->pixelSize > 1.0f;
}
static void egl_filterDownscaleGetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
*width = this->width;
*height = this->height;
}
static bool egl_filterDownscalePrepare(EGL_Filter * filter)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
if (!this->enable)
return false;
if (this->prepared)
return true;
this->uniform.f[0] = this->pixelSize;
this->uniform.f[1] = this->vOffset;
this->uniform.f[2] = this->hOffset;
egl_shaderSetUniforms(this->shader, &this->uniform, 1);
this->prepared = true;
return true;
}
static GLuint egl_filterDownscaleRun(EGL_Filter * filter, EGL_Model * model,
GLuint texture)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
egl_framebufferBind(this->fb);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glGenerateMipmap(GL_TEXTURE_2D);
glBindSampler(0, this->sampler);
egl_shaderUse(this->shader);
egl_modelRender(model);
return egl_framebufferGetTexture(this->fb);
}
EGL_FilterOps egl_filterDownscaleOps =
{
.name = "Downscaler",
.type = EGL_FILTER_TYPE_DOWNSCALE,
.earlyInit = egl_filterDownscaleEarlyInit,
.init = egl_filterDownscaleInit,
.free = egl_filterDownscaleFree,
.imguiConfig = egl_filterDownscaleImguiConfig,
.setup = egl_filterDownscaleSetup,
.getOutputRes = egl_filterDownscaleGetOutputRes,
.prepare = egl_filterDownscalePrepare,
.run = egl_filterDownscaleRun
};

View file

@ -20,5 +20,6 @@
#pragma once
extern EGL_FilterOps egl_filterDownscaleOps;
extern EGL_FilterOps egl_filterFFXCASOps;
extern EGL_FilterOps egl_filterFFXFSR1Ops;

View file

@ -32,6 +32,7 @@
static const EGL_FilterOps * EGL_Filters[] =
{
&egl_filterDownscaleOps,
&egl_filterFFXFSR1Ops,
&egl_filterFFXCASOps
};

View file

@ -0,0 +1,26 @@
#version 300 es
precision mediump float;
in vec2 fragCoord;
out vec4 fragColor;
uniform sampler2D texture;
uniform vec3 uConfig;
void main()
{
float pixelSize = uConfig.x;
float vOffset = uConfig.y;
float hOffset = uConfig.z;
vec2 inRes = vec2(textureSize(texture, 0));
ivec2 point = ivec2(
(floor((fragCoord * inRes) / pixelSize) * pixelSize) +
pixelSize / 2.0f
);
point.x += int(pixelSize * hOffset);
point.y += int(pixelSize * vOffset);
fragColor = texelFetch(texture, point, 0);
}