mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 23:07:18 +00:00
[client] egl: cleanup texture filtering/post-processing
This commit is contained in:
parent
f78154d282
commit
f0ea882165
@ -86,7 +86,11 @@ add_library(renderer_EGL STATIC
|
||||
draw.c
|
||||
splash.c
|
||||
damage.c
|
||||
framebuffer.c
|
||||
postprocess.c
|
||||
ffx.c
|
||||
filter_ffx_cas.c
|
||||
filter_ffx_fsr1.c
|
||||
${EGL_SHADER_OBJS}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
||||
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl3.cpp
|
||||
|
@ -80,11 +80,11 @@ struct EGL_Cursor
|
||||
struct EGL_Model * model;
|
||||
};
|
||||
|
||||
static bool cursorTexInit(EGL * egl, struct CursorTex * t,
|
||||
static bool cursorTexInit(struct CursorTex * t,
|
||||
const char * vertex_code , size_t vertex_size,
|
||||
const char * fragment_code, size_t fragment_size)
|
||||
{
|
||||
if (!egl_textureInit(egl, &t->texture, NULL, EGL_TEXTYPE_BUFFER, false))
|
||||
if (!egl_textureInit(&t->texture, NULL, EGL_TEXTYPE_BUFFER, false))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the cursor texture");
|
||||
return false;
|
||||
@ -133,7 +133,7 @@ static void cursorTexFree(struct CursorTex * t)
|
||||
egl_shaderFree (&t->shader );
|
||||
};
|
||||
|
||||
bool egl_cursorInit(EGL * egl, EGL_Cursor ** cursor)
|
||||
bool egl_cursorInit(EGL_Cursor ** cursor)
|
||||
{
|
||||
*cursor = (EGL_Cursor *)malloc(sizeof(EGL_Cursor));
|
||||
if (!*cursor)
|
||||
@ -145,12 +145,12 @@ bool egl_cursorInit(EGL * egl, EGL_Cursor ** cursor)
|
||||
memset(*cursor, 0, sizeof(EGL_Cursor));
|
||||
LG_LOCK_INIT((*cursor)->lock);
|
||||
|
||||
if (!cursorTexInit(egl, &(*cursor)->norm,
|
||||
if (!cursorTexInit(&(*cursor)->norm,
|
||||
b_shader_cursor_vert , b_shader_cursor_vert_size,
|
||||
b_shader_cursor_rgb_frag, b_shader_cursor_rgb_frag_size))
|
||||
return false;
|
||||
|
||||
if (!cursorTexInit(egl, &(*cursor)->mono,
|
||||
if (!cursorTexInit(&(*cursor)->mono,
|
||||
b_shader_cursor_vert , b_shader_cursor_vert_size,
|
||||
b_shader_cursor_mono_frag, b_shader_cursor_mono_frag_size))
|
||||
return false;
|
||||
|
@ -32,7 +32,7 @@ struct CursorState {
|
||||
struct Rect rect;
|
||||
};
|
||||
|
||||
bool egl_cursorInit(EGL * egl, EGL_Cursor ** cursor);
|
||||
bool egl_cursorInit(EGL_Cursor ** cursor);
|
||||
void egl_cursorFree(EGL_Cursor ** cursor);
|
||||
|
||||
bool egl_cursorSetShape(
|
||||
|
@ -38,10 +38,8 @@
|
||||
#include "desktop_rgb.frag.h"
|
||||
#include "desktop_rgb.def.h"
|
||||
|
||||
#include "basic.vert.h"
|
||||
#include "ffx_cas.frag.h"
|
||||
#include "ffx_fsr1_easu.frag.h"
|
||||
#include "ffx_fsr1_rcas.frag.h"
|
||||
#include "postprocess.h"
|
||||
#include "filters.h"
|
||||
|
||||
struct DesktopShader
|
||||
{
|
||||
@ -60,6 +58,7 @@ struct EGL_Desktop
|
||||
EGLDisplay * display;
|
||||
|
||||
EGL_Texture * texture;
|
||||
GLuint sampler;
|
||||
struct DesktopShader shader;
|
||||
EGL_DesktopRects * mesh;
|
||||
CountedBuffer * matrix;
|
||||
@ -67,7 +66,6 @@ struct EGL_Desktop
|
||||
// internals
|
||||
int width, height;
|
||||
LG_RendererRotate rotate;
|
||||
bool upscale;
|
||||
|
||||
// scale algorithm
|
||||
int scaleAlgo;
|
||||
@ -82,15 +80,8 @@ struct EGL_Desktop
|
||||
bool useDMA;
|
||||
LG_RendererFormat format;
|
||||
|
||||
EGL_Shader * ffxFSR1[2];
|
||||
bool ffxFSR1Enable;
|
||||
PostProcessHandle ffxFSR1Handle[2];
|
||||
EGL_Uniform ffxFSR1Uniform;
|
||||
|
||||
EGL_Shader * ffxCAS;
|
||||
bool ffxCASEnable;
|
||||
PostProcessHandle ffxCASHandle;
|
||||
EGL_Uniform ffxCASUniform;
|
||||
EGL_PostProcess * pp;
|
||||
_Atomic(bool) processFrame;
|
||||
};
|
||||
|
||||
// forwards
|
||||
@ -122,20 +113,6 @@ static bool egl_initDesktopShader(
|
||||
return true;
|
||||
}
|
||||
|
||||
static void setupFilters(EGL_Desktop * desktop)
|
||||
{
|
||||
desktop->ffxFSR1Handle[0] =
|
||||
egl_textureAddFilter(desktop->texture, desktop->ffxFSR1[0],
|
||||
desktop->ffxFSR1Enable);
|
||||
desktop->ffxFSR1Handle[1] =
|
||||
egl_textureAddFilter(desktop->texture, desktop->ffxFSR1[1],
|
||||
desktop->ffxFSR1Enable);
|
||||
|
||||
desktop->ffxCASHandle =
|
||||
egl_textureAddFilter(desktop->texture, desktop->ffxCAS,
|
||||
desktop->ffxCASEnable);
|
||||
}
|
||||
|
||||
bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
bool useDMA, int maxRects)
|
||||
{
|
||||
@ -150,7 +127,7 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
desktop->egl = egl;
|
||||
desktop->display = display;
|
||||
|
||||
if (!egl_textureInit(egl, &desktop->texture, display,
|
||||
if (!egl_textureInit(&desktop->texture, display,
|
||||
useDMA ? EGL_TEXTYPE_DMABUF : EGL_TEXTYPE_FRAMEBUFFER, true))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the desktop texture");
|
||||
@ -188,41 +165,14 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
desktop->scaleAlgo = option_get_int("egl", "scale" );
|
||||
desktop->useDMA = useDMA;
|
||||
|
||||
// AMD FidelidyFX FSR
|
||||
egl_shaderInit(&desktop->ffxFSR1[0]);
|
||||
egl_shaderCompile(desktop->ffxFSR1[0],
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size);
|
||||
|
||||
egl_shaderInit(&desktop->ffxFSR1[1]);
|
||||
egl_shaderCompile(desktop->ffxFSR1[1],
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size);
|
||||
|
||||
desktop->ffxFSR1Enable = option_get_bool("eglFilter", "ffxFSR");
|
||||
desktop->ffxFSR1Uniform.type = EGL_UNIFORM_TYPE_1F;
|
||||
desktop->ffxFSR1Uniform.location =
|
||||
egl_shaderGetUniform(desktop->ffxFSR1[1], "uSharpness");
|
||||
desktop->ffxFSR1Uniform.f[0] =
|
||||
option_get_float("eglFilter", "ffxFSRSharpness");
|
||||
egl_shaderSetUniforms(desktop->ffxFSR1[1], &desktop->ffxFSR1Uniform, 1);
|
||||
|
||||
// AMD FidelidyFX CAS
|
||||
egl_shaderInit(&desktop->ffxCAS);
|
||||
egl_shaderCompile(desktop->ffxCAS,
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_ffx_cas_frag, b_shader_ffx_cas_frag_size);
|
||||
|
||||
desktop->ffxCASEnable = option_get_bool("eglFilter", "ffxCAS");
|
||||
desktop->ffxCASUniform.type = EGL_UNIFORM_TYPE_1F;
|
||||
desktop->ffxCASUniform.location =
|
||||
egl_shaderGetUniform(desktop->ffxCAS, "uSharpness");
|
||||
desktop->ffxCASUniform.f[0] =
|
||||
option_get_float("eglFilter", "ffxCASSharpness");
|
||||
egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxCASUniform, 1);
|
||||
|
||||
setupFilters(desktop);
|
||||
if (!egl_postProcessInit(&desktop->pp))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the post process manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops);
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -258,9 +208,7 @@ void egl_desktopFree(EGL_Desktop ** desktop)
|
||||
egl_desktopRectsFree(&(*desktop)->mesh );
|
||||
countedBufferRelease(&(*desktop)->matrix );
|
||||
|
||||
egl_shaderFree(&(*desktop)->ffxFSR1[0]);
|
||||
egl_shaderFree(&(*desktop)->ffxFSR1[1]);
|
||||
egl_shaderFree(&(*desktop)->ffxCAS);
|
||||
egl_postProcessFree(&(*desktop)->pp);
|
||||
|
||||
free(*desktop);
|
||||
*desktop = NULL;
|
||||
@ -304,81 +252,10 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
|
||||
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
bool invalidateTex = false;
|
||||
// AMD FidelityFX FSR
|
||||
bool fsr1 = desktop->ffxFSR1Enable;
|
||||
igCheckbox("AMD FidelityFX FSR", &fsr1);
|
||||
if (fsr1 != desktop->ffxFSR1Enable)
|
||||
if (egl_postProcessImgui(desktop->pp))
|
||||
{
|
||||
desktop->ffxFSR1Enable = fsr1;
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[0],
|
||||
fsr1 && desktop->upscale);
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[1],
|
||||
fsr1 && desktop->upscale);
|
||||
invalidateTex = true;
|
||||
}
|
||||
|
||||
float fsr1Sharpness = desktop->ffxFSR1Uniform.f[0];
|
||||
igText("Sharpness:");
|
||||
igSameLine(0.0f, -1.0f);
|
||||
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
|
||||
igGetStyle()->WindowPadding.x);
|
||||
igSliderFloat("##fsr1Sharpness", &fsr1Sharpness, 0.0f, 1.0f, NULL, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
if (fsr1Sharpness != desktop->ffxFSR1Uniform.f[0])
|
||||
{
|
||||
// enable FSR1 if the sharpness was changed
|
||||
if (!fsr1)
|
||||
{
|
||||
fsr1 = true;
|
||||
desktop->ffxFSR1Enable = fsr1;
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[0],
|
||||
fsr1 && desktop->upscale);
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[1],
|
||||
fsr1 && desktop->upscale);
|
||||
}
|
||||
desktop->ffxFSR1Uniform.f[0] = 2.0f - fsr1Sharpness * 2.0f;
|
||||
egl_shaderSetUniforms(desktop->ffxFSR1[1], &desktop->ffxFSR1Uniform, 1);
|
||||
invalidateTex = true;
|
||||
}
|
||||
|
||||
// AMD FiedlityFX CAS
|
||||
bool cas = desktop->ffxCASEnable;
|
||||
igCheckbox("AMD FidelityFX CAS", &cas);
|
||||
if (cas != desktop->ffxCASEnable)
|
||||
{
|
||||
desktop->ffxCASEnable = cas;
|
||||
egl_textureEnableFilter(desktop->ffxCASHandle, cas);
|
||||
invalidateTex = true;
|
||||
}
|
||||
|
||||
float casSharpness = desktop->ffxCASUniform.f[0];
|
||||
igText("Sharpness:");
|
||||
igSameLine(0.0f, -1.0f);
|
||||
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
|
||||
igGetStyle()->WindowPadding.x);
|
||||
igSliderFloat("##casSharpness", &casSharpness, 0.0f, 1.0f, NULL, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
if (casSharpness != desktop->ffxCASUniform.f[0])
|
||||
{
|
||||
// enable CAS if the sharpness was changed
|
||||
if (!cas)
|
||||
{
|
||||
cas = true;
|
||||
desktop->ffxCASEnable = cas;
|
||||
egl_textureEnableFilter(desktop->ffxCASHandle, cas);
|
||||
}
|
||||
desktop->ffxCASUniform.f[0] = casSharpness;
|
||||
egl_shaderSetUniforms(desktop->ffxCAS, &desktop->ffxCASUniform, 1);
|
||||
invalidateTex = true;
|
||||
}
|
||||
|
||||
if (invalidateTex)
|
||||
{
|
||||
egl_textureInvalidate(desktop->texture);
|
||||
app_invalidateWindow(true);
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
app_invalidateWindow(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,6 +302,12 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
return false;
|
||||
}
|
||||
|
||||
glGenSamplers(1, &desktop->sampler);
|
||||
glSamplerParameteri(desktop->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(desktop->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(desktop->sampler, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(desktop->sampler, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -434,52 +317,43 @@ bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dma
|
||||
if (desktop->useDMA && dmaFd >= 0)
|
||||
{
|
||||
if (egl_textureUpdateFromDMA(desktop->texture, frame, dmaFd))
|
||||
{
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_WARN("DMA update failed, disabling DMABUF imports");
|
||||
desktop->useDMA = false;
|
||||
|
||||
egl_textureFree(&desktop->texture);
|
||||
if (!egl_textureInit(desktop->egl, &desktop->texture, desktop->display,
|
||||
if (!egl_textureInit(&desktop->texture, desktop->display,
|
||||
EGL_TEXTYPE_FRAMEBUFFER, true))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the desktop texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
setupFilters(desktop);
|
||||
|
||||
if (!egl_desktopSetup(desktop, desktop->format))
|
||||
return false;
|
||||
}
|
||||
|
||||
return egl_textureUpdateFromFrame(desktop->texture, frame, damageRects, damageRectsCount);
|
||||
if (egl_textureUpdateFromFrame(desktop->texture, frame,
|
||||
damageRects, damageRectsCount))
|
||||
{
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void egl_desktopResize(EGL_Desktop * desktop, int width, int height)
|
||||
{
|
||||
if (width > desktop->width && height > desktop->height)
|
||||
{
|
||||
desktop->upscale = true;
|
||||
if (desktop->ffxFSR1Enable)
|
||||
{
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[0], true);
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[1], true);
|
||||
}
|
||||
egl_textureSetFilterRes(desktop->ffxFSR1Handle[0], width, height);
|
||||
egl_textureSetFilterRes(desktop->ffxFSR1Handle[1], width, height);
|
||||
egl_textureSetFilterRes(desktop->ffxCASHandle , width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
desktop->upscale = false;
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[0], false);
|
||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[1], false);
|
||||
egl_textureSetFilterRes(desktop->ffxCASHandle, 0, 0);
|
||||
}
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
}
|
||||
|
||||
bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
|
||||
bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
unsigned int outputHeight, const float x, const float y,
|
||||
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
|
||||
LG_RendererRotate rotate, const struct DamageRects * rects)
|
||||
{
|
||||
@ -492,10 +366,21 @@ bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
|
||||
|
||||
int scaleAlgo = EGL_SCALE_NEAREST;
|
||||
|
||||
struct Rect finalSize;
|
||||
egl_textureBind(desktop->texture);
|
||||
egl_textureGetFinalSize(desktop->texture, &finalSize);
|
||||
if (finalSize.x > desktop->width || finalSize.y > desktop->height)
|
||||
if (atomic_exchange(&desktop->processFrame, false))
|
||||
egl_postProcessRun(desktop->pp, desktop->texture, outputWidth, outputHeight);
|
||||
|
||||
unsigned int finalSizeX, finalSizeY;
|
||||
GLuint texture = egl_postProcessGetOutput(desktop->pp,
|
||||
&finalSizeX, &finalSizeY);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
egl_resetViewport(desktop->egl);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBindSampler(0, desktop->sampler);
|
||||
|
||||
if (finalSizeX > desktop->width || finalSizeY > desktop->height)
|
||||
scaleType = EGL_DESKTOP_DOWNSCALE;
|
||||
|
||||
switch (desktop->scaleAlgo)
|
||||
@ -538,7 +423,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_2I,
|
||||
.location = shader->uTextureSize,
|
||||
.i = { finalSize.x, finalSize.y },
|
||||
.i = { finalSizeX, finalSizeY },
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_M3x2FV,
|
||||
|
@ -46,6 +46,7 @@ bool egl_desktopSetup (EGL_Desktop * desktop, const LG_RendererFormat format);
|
||||
bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
|
||||
const FrameDamageRect * damageRects, int damageRectsCount);
|
||||
void egl_desktopResize(EGL_Desktop * desktop, int width, int height);
|
||||
bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
|
||||
bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
unsigned int outputHeight, const float x, const float y,
|
||||
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
|
||||
LG_RendererRotate rotate, const struct DamageRects * rects);
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "desktop.h"
|
||||
#include "cursor.h"
|
||||
#include "splash.h"
|
||||
#include "postprocess.h"
|
||||
#include "util.h"
|
||||
|
||||
#define SPLASH_FADE_TIME 1000000
|
||||
@ -182,35 +183,6 @@ static struct Option egl_options[] =
|
||||
.value.x_bool = false
|
||||
},
|
||||
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxFSR",
|
||||
.description = "AMD FidelityFX FSR",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false
|
||||
},
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxFSRSharpness",
|
||||
.description = "AMD FidelityFX FSR Sharpness",
|
||||
.type = OPTION_TYPE_FLOAT,
|
||||
.value.x_float = 1.0f
|
||||
},
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxCAS",
|
||||
.description = "AMD FidelityFX CAS",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false
|
||||
},
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxCASSharpness",
|
||||
.description = "AMD FidelityFX CAS Sharpness",
|
||||
.type = OPTION_TYPE_FLOAT,
|
||||
.value.x_float = 0.0f
|
||||
},
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -222,6 +194,7 @@ static const char * egl_getName(void)
|
||||
static void egl_setup(void)
|
||||
{
|
||||
option_register(egl_options);
|
||||
egl_postProcessEarlyInit();
|
||||
}
|
||||
|
||||
static bool egl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
||||
@ -824,7 +797,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!egl_cursorInit(this, &this->cursor))
|
||||
if (!egl_cursorInit(&this->cursor))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the cursor");
|
||||
return false;
|
||||
@ -989,6 +962,7 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
|
||||
if (this->start)
|
||||
{
|
||||
if (egl_desktopRender(this->desktop,
|
||||
this->destRect.w, this->destRect.h,
|
||||
this->translateX, this->translateY,
|
||||
this->scaleX , this->scaleY ,
|
||||
this->scaleType , rotate, renderAll ? NULL : accumulated))
|
||||
|
72
client/renderers/EGL/egltypes.h
Normal file
72
client/renderers/EGL/egltypes.h
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum EGL_TexType
|
||||
{
|
||||
EGL_TEXTYPE_BUFFER,
|
||||
EGL_TEXTYPE_FRAMEBUFFER,
|
||||
EGL_TEXTYPE_DMABUF
|
||||
}
|
||||
EGL_TexType;
|
||||
|
||||
typedef enum EGL_PixelFormat
|
||||
{
|
||||
EGL_PF_RGBA,
|
||||
EGL_PF_BGRA,
|
||||
EGL_PF_RGBA10,
|
||||
EGL_PF_RGBA16F
|
||||
}
|
||||
EGL_PixelFormat;
|
||||
|
||||
typedef enum EGL_TexStatus
|
||||
{
|
||||
EGL_TEX_STATUS_NOTREADY,
|
||||
EGL_TEX_STATUS_OK,
|
||||
EGL_TEX_STATUS_ERROR
|
||||
}
|
||||
EGL_TexStatus;
|
||||
|
||||
typedef struct EGL_TexSetup
|
||||
{
|
||||
/* the pixel format of the texture */
|
||||
EGL_PixelFormat pixFmt;
|
||||
|
||||
/* the width of the texture in pixels */
|
||||
size_t width;
|
||||
|
||||
/* the height of the texture in pixels */
|
||||
size_t height;
|
||||
|
||||
/* the stide of the texture in bytes */
|
||||
size_t stride;
|
||||
}
|
||||
EGL_TexSetup;
|
||||
|
||||
typedef enum EGL_FilterType
|
||||
{
|
||||
EGL_FILTER_TYPE_EFFECT,
|
||||
EGL_FILTER_TYPE_UPSCALE,
|
||||
EGL_FILTER_TYPE_DOWNSCALE
|
||||
}
|
||||
EGL_FilterType;
|
140
client/renderers/EGL/filter.h
Normal file
140
client/renderers/EGL/filter.h
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util.h"
|
||||
#include "shader.h"
|
||||
#include "egltypes.h"
|
||||
#include "model.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef struct EGL_Filter EGL_Filter;
|
||||
|
||||
typedef struct EGL_FilterOps
|
||||
{
|
||||
/* the friendly name of this filter */
|
||||
const char * name;
|
||||
|
||||
/* the type of this filter */
|
||||
EGL_FilterType type;
|
||||
|
||||
/* early initialization for registration of options */
|
||||
void (*earlyInit)(void);
|
||||
|
||||
/* initialize the filter */
|
||||
bool (*init)(EGL_Filter ** filter);
|
||||
|
||||
/* free the filter */
|
||||
void (*free)(EGL_Filter * filter);
|
||||
|
||||
/* render any imgui config
|
||||
* Returns true if a redraw is required */
|
||||
bool (*imguiConfig)(EGL_Filter * filter);
|
||||
|
||||
/* set the input format of the filter */
|
||||
bool (*setup)(EGL_Filter * filter, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height);
|
||||
|
||||
/* set the output resolution hint for the filter
|
||||
* this is optional and only a hint */
|
||||
void (*setOutputResHint)(EGL_Filter * filter,
|
||||
unsigned int x, unsigned int y);
|
||||
|
||||
/* returns the output resolution of the filter */
|
||||
void (*getOutputRes)(EGL_Filter * filter,
|
||||
unsigned int *x, unsigned int *y);
|
||||
|
||||
/* prepare the shader for use
|
||||
* A filter can return false to bypass it */
|
||||
bool (*prepare)(EGL_Filter * filter);
|
||||
|
||||
/* runs the filter on the provided texture
|
||||
* returns the processed texture as the output */
|
||||
GLuint (*run)(EGL_Filter * filter, EGL_Model * model, GLuint texture);
|
||||
|
||||
/* called when the filter output is no loger needed so it can release memory
|
||||
* this is optional */
|
||||
void (*release)(EGL_Filter * filter);
|
||||
}
|
||||
EGL_FilterOps;
|
||||
|
||||
typedef struct EGL_Filter
|
||||
{
|
||||
EGL_FilterOps ops;
|
||||
}
|
||||
EGL_Filter;
|
||||
|
||||
static inline bool egl_filterInit(const EGL_FilterOps * ops, EGL_Filter ** filter)
|
||||
{
|
||||
if (!ops->init(filter))
|
||||
return false;
|
||||
|
||||
memcpy(&(*filter)->ops, ops, sizeof(*ops));
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void egl_filterFree(EGL_Filter ** filter)
|
||||
{
|
||||
(*filter)->ops.free(*filter);
|
||||
*filter = NULL;
|
||||
}
|
||||
|
||||
static inline bool egl_filterImguiConfig(EGL_Filter * filter)
|
||||
{
|
||||
return filter->ops.imguiConfig(filter);
|
||||
}
|
||||
|
||||
static inline bool egl_filterSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
|
||||
{
|
||||
return filter->ops.setup(filter, pixFmt, width, height);
|
||||
}
|
||||
|
||||
static inline void egl_filterSetOutputResHint(EGL_Filter * filter,
|
||||
unsigned int x, unsigned int y)
|
||||
{
|
||||
if (filter->ops.setOutputResHint)
|
||||
filter->ops.setOutputResHint(filter, x, y);
|
||||
}
|
||||
|
||||
static inline void egl_filterGetOutputRes(EGL_Filter * filter,
|
||||
unsigned int *x, unsigned int *y)
|
||||
{
|
||||
return filter->ops.getOutputRes(filter, x, y);
|
||||
}
|
||||
|
||||
static inline bool egl_filterPrepare(EGL_Filter * filter)
|
||||
{
|
||||
return filter->ops.prepare(filter);
|
||||
}
|
||||
|
||||
static inline GLuint egl_filterRun(EGL_Filter * filter, EGL_Model * model,
|
||||
GLuint texture)
|
||||
{
|
||||
return filter->ops.run(filter, model, texture);
|
||||
}
|
||||
|
||||
static inline void egl_filterRelease(EGL_Filter * filter)
|
||||
{
|
||||
if (filter->ops.release)
|
||||
filter->ops.release(filter);
|
||||
}
|
250
client/renderers/EGL/filter_ffx_cas.c
Normal file
250
client/renderers/EGL/filter_ffx_cas.c
Normal file
@ -0,0 +1,250 @@
|
||||
/**
|
||||
* 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 "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include "basic.vert.h"
|
||||
#include "ffx_cas.frag.h"
|
||||
|
||||
typedef struct EGL_FilterFFXCAS
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
EGL_Shader * shader;
|
||||
bool enable;
|
||||
EGL_Uniform uniform;
|
||||
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
unsigned int width, height;
|
||||
bool prepared;
|
||||
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler;
|
||||
}
|
||||
EGL_FilterFFXCAS;
|
||||
|
||||
static void egl_filterFFXCASEarlyInit(void)
|
||||
{
|
||||
static struct Option options[] =
|
||||
{
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxCAS",
|
||||
.description = "AMD FidelityFX CAS",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false
|
||||
},
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxCASSharpness",
|
||||
.description = "AMD FidelityFX CAS Sharpness",
|
||||
.type = OPTION_TYPE_FLOAT,
|
||||
.value.x_float = 0.0f
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static bool egl_filterFFXCASInit(EGL_Filter ** filter)
|
||||
{
|
||||
EGL_FilterFFXCAS * 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_ffx_cas_frag, b_shader_ffx_cas_frag_size)
|
||||
)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the shader");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
this->enable = option_get_bool("eglFilter", "ffxCAS");
|
||||
this->uniform.type = EGL_UNIFORM_TYPE_1F;
|
||||
this->uniform.location =
|
||||
egl_shaderGetUniform(this->shader, "uSharpness");
|
||||
this->uniform.f[0] =
|
||||
option_get_float("eglFilter", "ffxCASSharpness");
|
||||
|
||||
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);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->shader);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void egl_filterFFXCASFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
egl_shaderFree(&this->shader);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(1, &this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
bool redraw = false;
|
||||
bool cas = this->enable;
|
||||
float casSharpness = this->uniform.f[0];
|
||||
|
||||
igCheckbox("AMD FidelityFX CAS", &cas);
|
||||
if (cas != this->enable)
|
||||
{
|
||||
this->enable = cas;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
igText("Sharpness:");
|
||||
igSameLine(0.0f, -1.0f);
|
||||
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
|
||||
igGetStyle()->WindowPadding.x);
|
||||
|
||||
igSliderFloat("##casSharpness", &casSharpness, 0.0f, 1.0f, NULL, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
if (casSharpness != this->uniform.f[0])
|
||||
{
|
||||
// enable CAS if the sharpness was changed
|
||||
if (!cas)
|
||||
{
|
||||
cas = true;
|
||||
this->enable = true;
|
||||
}
|
||||
|
||||
this->uniform.f[0] = casSharpness;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
this->prepared = false;
|
||||
|
||||
return redraw;
|
||||
}
|
||||
|
||||
static bool egl_filterFFXCASSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
if (pixFmt == this->pixFmt && this->width == width && this->height == height)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, pixFmt, width, height))
|
||||
return false;
|
||||
|
||||
this->pixFmt = pixFmt;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->prepared = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void egl_filterFFXCASGetOutputRes(EGL_Filter * filter,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
*width = this->width;
|
||||
*height = this->height;
|
||||
}
|
||||
|
||||
static bool egl_filterFFXCASPrepare(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
if (!this->enable)
|
||||
return false;
|
||||
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
egl_shaderSetUniforms(this->shader, &this->uniform, 1);
|
||||
this->prepared = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static GLuint egl_filterFFXCASRun(EGL_Filter * filter, EGL_Model * model,
|
||||
GLuint texture)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
|
||||
egl_shaderUse(this->shader);
|
||||
egl_modelRender(model);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterFFXCASOps =
|
||||
{
|
||||
.name = "AMD FidelityFX CAS",
|
||||
.type = EGL_FILTER_TYPE_EFFECT,
|
||||
.earlyInit = egl_filterFFXCASEarlyInit,
|
||||
.init = egl_filterFFXCASInit,
|
||||
.free = egl_filterFFXCASFree,
|
||||
.imguiConfig = egl_filterFFXCASImguiConfig,
|
||||
.setup = egl_filterFFXCASSetup,
|
||||
.getOutputRes = egl_filterFFXCASGetOutputRes,
|
||||
.prepare = egl_filterFFXCASPrepare,
|
||||
.run = egl_filterFFXCASRun
|
||||
};
|
317
client/renderers/EGL/filter_ffx_fsr1.c
Normal file
317
client/renderers/EGL/filter_ffx_fsr1.c
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* 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 "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include "basic.vert.h"
|
||||
#include "ffx_fsr1_easu.frag.h"
|
||||
#include "ffx_fsr1_rcas.frag.h"
|
||||
|
||||
typedef struct EGL_FilterFFXFSR1
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
EGL_Shader * easu, * rcas;
|
||||
bool enable, active;
|
||||
float sharpness;
|
||||
EGL_Uniform easuUniform, rcasUniform;
|
||||
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
unsigned int width, height;
|
||||
bool sizeChanged;
|
||||
bool prepared;
|
||||
|
||||
EGL_Framebuffer * easuFb, * rcasFb;
|
||||
GLuint sampler;
|
||||
}
|
||||
EGL_FilterFFXFSR1;
|
||||
|
||||
static void egl_filterFFXFSR1EarlyInit(void)
|
||||
{
|
||||
static struct Option options[] =
|
||||
{
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxFSR",
|
||||
.description = "AMD FidelityFX FSR",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false
|
||||
},
|
||||
{
|
||||
.module = "eglFilter",
|
||||
.name = "ffxFSRSharpness",
|
||||
.description = "AMD FidelityFX FSR Sharpness",
|
||||
.type = OPTION_TYPE_FLOAT,
|
||||
.value.x_float = 1.0f
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate ram");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!egl_shaderInit(&this->easu))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Easu shader");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_shaderInit(&this->rcas))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Rcas shader");
|
||||
goto error_esau;
|
||||
}
|
||||
|
||||
if (!egl_shaderCompile(this->easu,
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size)
|
||||
)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the Easu shader");
|
||||
goto error_rcas;
|
||||
}
|
||||
|
||||
if (!egl_shaderCompile(this->rcas,
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size)
|
||||
)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the Rcas shader");
|
||||
goto error_rcas;
|
||||
}
|
||||
|
||||
|
||||
this->enable = option_get_bool("eglFilter", "ffxFSR");
|
||||
|
||||
this->easuUniform.type = EGL_UNIFORM_TYPE_2UI;
|
||||
this->easuUniform.location =
|
||||
egl_shaderGetUniform(this->easu, "uOutRes");
|
||||
|
||||
this->rcasUniform.type = EGL_UNIFORM_TYPE_1F;
|
||||
this->rcasUniform.location =
|
||||
egl_shaderGetUniform(this->rcas, "uSharpness");
|
||||
this->sharpness = option_get_float("eglFilter", "ffxFSRSharpness");
|
||||
this->rcasUniform.f[0] = 2.0f - this->sharpness * 2.0f;
|
||||
|
||||
if (!egl_framebufferInit(&this->easuFb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Easu framebuffer");
|
||||
goto error_rcas;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&this->rcasFb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Rcas framebuffer");
|
||||
goto error_easuFb;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_easuFb:
|
||||
egl_framebufferFree(&this->rcasFb);
|
||||
|
||||
error_rcas:
|
||||
egl_shaderFree(&this->rcas);
|
||||
|
||||
error_esau:
|
||||
egl_shaderFree(&this->easu);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void egl_filterFFXFSR1Free(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
egl_shaderFree(&this->easu);
|
||||
egl_shaderFree(&this->rcas);
|
||||
egl_framebufferFree(&this->easuFb);
|
||||
egl_framebufferFree(&this->rcasFb);
|
||||
glDeleteSamplers(1, &this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool egl_filterFFXFSR1ImguiConfig(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
bool redraw = false;
|
||||
bool enable = this->enable;
|
||||
float sharpness = this->sharpness;
|
||||
|
||||
igCheckbox("AMD FidelityFX FSR", &enable);
|
||||
if (enable != this->enable)
|
||||
{
|
||||
this->enable = enable;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
igText("Sharpness:");
|
||||
igSameLine(0.0f, -1.0f);
|
||||
igPushItemWidth(igGetWindowWidth() - igGetCursorPosX() -
|
||||
igGetStyle()->WindowPadding.x);
|
||||
igSliderFloat("##fsr1Sharpness", &sharpness, 0.0f, 1.0f, NULL, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
if (sharpness != this->sharpness)
|
||||
{
|
||||
// enable FSR1 if the sharpness was changed
|
||||
if (!enable)
|
||||
{
|
||||
enable = true;
|
||||
this->enable = true;
|
||||
}
|
||||
|
||||
this->sharpness = sharpness;
|
||||
this->rcasUniform.f[0] = 2.0f - sharpness * 2.0f;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
this->prepared = false;
|
||||
|
||||
return redraw;
|
||||
}
|
||||
|
||||
static void egl_filterFFXFSR1SetOutputResHint(EGL_Filter * filter,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
if (this->width == width && this->height == height)
|
||||
return;
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->sizeChanged = true;
|
||||
this->prepared = false;
|
||||
}
|
||||
|
||||
static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
if (pixFmt == this->pixFmt && !this->sizeChanged)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->easuFb, pixFmt, this->width, this->height))
|
||||
return false;
|
||||
|
||||
if (!egl_framebufferSetup(this->rcasFb, pixFmt, this->width, this->height))
|
||||
return false;
|
||||
|
||||
this->active = this->width > width && this->height > height;
|
||||
this->sizeChanged = false;
|
||||
this->pixFmt = pixFmt;
|
||||
this->prepared = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void egl_filterFFXFSR1GetOutputRes(EGL_Filter * filter,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
*width = this->width;
|
||||
*height = this->height;
|
||||
}
|
||||
|
||||
static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
if (!this->enable || !this->active)
|
||||
return false;
|
||||
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
this->easuUniform.ui[0] = this->width;
|
||||
this->easuUniform.ui[1] = this->height;
|
||||
|
||||
egl_shaderSetUniforms(this->easu, &this->easuUniform, 1);
|
||||
egl_shaderSetUniforms(this->rcas, &this->rcasUniform, 1);
|
||||
this->prepared = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter, EGL_Model * model,
|
||||
GLuint texture)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
// pass 1, Easu
|
||||
egl_framebufferBind(this->easuFb);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
egl_shaderUse(this->easu);
|
||||
egl_modelRender(model);
|
||||
texture = egl_framebufferGetTexture(this->easuFb);
|
||||
|
||||
// pass 2, Rcas
|
||||
egl_framebufferBind(this->rcasFb);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
egl_shaderUse(this->rcas);
|
||||
egl_modelRender(model);
|
||||
texture = egl_framebufferGetTexture(this->rcasFb);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterFFXFSR1Ops =
|
||||
{
|
||||
.name = "AMD FidelityFX FSR",
|
||||
.type = EGL_FILTER_TYPE_UPSCALE,
|
||||
.earlyInit = egl_filterFFXFSR1EarlyInit,
|
||||
.init = egl_filterFFXFSR1Init,
|
||||
.free = egl_filterFFXFSR1Free,
|
||||
.imguiConfig = egl_filterFFXFSR1ImguiConfig,
|
||||
.setup = egl_filterFFXFSR1Setup,
|
||||
.setOutputResHint = egl_filterFFXFSR1SetOutputResHint,
|
||||
.getOutputRes = egl_filterFFXFSR1GetOutputRes,
|
||||
.prepare = egl_filterFFXFSR1Prepare,
|
||||
.run = egl_filterFFXFSR1Run
|
||||
};
|
24
client/renderers/EGL/filters.h
Normal file
24
client/renderers/EGL/filters.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern EGL_FilterOps egl_filterFFXCASOps;
|
||||
extern EGL_FilterOps egl_filterFFXFSR1Ops;
|
106
client/renderers/EGL/framebuffer.c
Normal file
106
client/renderers/EGL/framebuffer.c
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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 "framebuffer.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
struct EGL_Framebuffer
|
||||
{
|
||||
GLuint fbo;
|
||||
EGL_Texture * tex;
|
||||
};
|
||||
|
||||
bool egl_framebufferInit(EGL_Framebuffer ** fb)
|
||||
{
|
||||
EGL_Framebuffer * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate ram");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!egl_textureInit(&this->tex, NULL, EGL_TEXTYPE_BUFFER, false))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
glGenFramebuffers(1, &this->fbo);
|
||||
|
||||
*fb = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_framebufferFree(EGL_Framebuffer ** fb)
|
||||
{
|
||||
EGL_Framebuffer * this = *fb;
|
||||
|
||||
free(this);
|
||||
*fb = NULL;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
DEBUG_ERROR("Failed to setup the texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint tex;
|
||||
egl_textureGet(this->tex, &tex, NULL, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, tex, 0);
|
||||
glDrawBuffers(1, &(GLenum){GL_COLOR_ATTACHMENT0});
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
DEBUG_ERROR("Failed to setup the framebuffer");
|
||||
return false;
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_framebufferBind(EGL_Framebuffer * this)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
|
||||
glViewport(0, 0, this->tex->format.width, this->tex->format.height);
|
||||
}
|
||||
|
||||
GLuint egl_framebufferGetTexture(EGL_Framebuffer * this)
|
||||
{
|
||||
GLuint output;
|
||||
egl_textureGet(this->tex, &output, NULL, NULL);
|
||||
return output;
|
||||
}
|
35
client/renderers/EGL/framebuffer.h
Normal file
35
client/renderers/EGL/framebuffer.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
typedef struct EGL_Framebuffer EGL_Framebuffer;
|
||||
|
||||
bool egl_framebufferInit(EGL_Framebuffer ** fb);
|
||||
void egl_framebufferFree(EGL_Framebuffer ** fb);
|
||||
|
||||
bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height);
|
||||
|
||||
void egl_framebufferBind(EGL_Framebuffer * this);
|
||||
|
||||
GLuint egl_framebufferGetTexture(EGL_Framebuffer * this);
|
163
client/renderers/EGL/postprocess.c
Normal file
163
client/renderers/EGL/postprocess.c
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
* 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 "postprocess.h"
|
||||
#include "filters.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "ll.h"
|
||||
|
||||
static const EGL_FilterOps * EGL_Filters[] =
|
||||
{
|
||||
&egl_filterFFXFSR1Ops,
|
||||
&egl_filterFFXCASOps
|
||||
};
|
||||
|
||||
struct EGL_PostProcess
|
||||
{
|
||||
struct ll * filters;
|
||||
GLuint output;
|
||||
unsigned int outputX, outputY;
|
||||
|
||||
EGL_Model * model;
|
||||
};
|
||||
|
||||
void egl_postProcessEarlyInit(void)
|
||||
{
|
||||
for(int i = 0; i < ARRAY_LENGTH(EGL_Filters); ++i)
|
||||
EGL_Filters[i]->earlyInit();
|
||||
}
|
||||
|
||||
bool egl_postProcessInit(EGL_PostProcess ** pp)
|
||||
{
|
||||
EGL_PostProcess * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->filters = ll_new(sizeof(EGL_Filter *));
|
||||
if (!this->filters)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate the filter list");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_modelInit(&this->model))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the model");
|
||||
goto error_filters;
|
||||
}
|
||||
egl_modelSetDefault(this->model, false);
|
||||
|
||||
*pp = this;
|
||||
return true;
|
||||
|
||||
error_filters:
|
||||
ll_free(this->filters);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
void egl_postProcessFree(EGL_PostProcess ** pp)
|
||||
{
|
||||
if (!*pp)
|
||||
return;
|
||||
|
||||
EGL_PostProcess * this = *pp;
|
||||
|
||||
if (this->filters)
|
||||
{
|
||||
EGL_Filter * filter;
|
||||
while(ll_shift(this->filters, (void **)&filter))
|
||||
egl_filterFree(&filter);
|
||||
ll_free(this->filters);
|
||||
}
|
||||
|
||||
egl_modelFree(&this->model);
|
||||
free(this);
|
||||
*pp = NULL;
|
||||
}
|
||||
|
||||
bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops)
|
||||
{
|
||||
EGL_Filter * filter;
|
||||
if (!egl_filterInit(ops, &filter))
|
||||
return false;
|
||||
|
||||
ll_push(this->filters, filter);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_postProcessImgui(EGL_PostProcess * this)
|
||||
{
|
||||
bool redraw = false;
|
||||
EGL_Filter * filter;
|
||||
for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); )
|
||||
redraw |= egl_filterImguiConfig(filter);
|
||||
|
||||
return redraw;
|
||||
}
|
||||
|
||||
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
|
||||
unsigned int targetX, unsigned int targetY)
|
||||
{
|
||||
EGL_Filter * lastFilter = NULL, * filter;
|
||||
unsigned int sizeX, sizeY;
|
||||
|
||||
GLuint texture;
|
||||
if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
|
||||
return false;
|
||||
|
||||
for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); )
|
||||
{
|
||||
egl_filterSetOutputResHint(filter, targetX, targetY);
|
||||
egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY);
|
||||
|
||||
if (!egl_filterPrepare(filter))
|
||||
continue;
|
||||
|
||||
texture = egl_filterRun(filter, this->model, texture);
|
||||
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
|
||||
|
||||
if (lastFilter)
|
||||
egl_filterRelease(lastFilter);
|
||||
|
||||
lastFilter = filter;
|
||||
}
|
||||
|
||||
this->output = texture;
|
||||
this->outputX = sizeX;
|
||||
this->outputY = sizeY;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint egl_postProcessGetOutput(EGL_PostProcess * this,
|
||||
unsigned int * outputX, unsigned int * outputY)
|
||||
{
|
||||
*outputX = this->outputX;
|
||||
*outputY = this->outputY;
|
||||
return this->output;
|
||||
}
|
46
client/renderers/EGL/postprocess.h
Normal file
46
client/renderers/EGL/postprocess.h
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filter.h"
|
||||
#include "texture.h"
|
||||
|
||||
typedef struct EGL_PostProcess EGL_PostProcess;
|
||||
|
||||
void egl_postProcessEarlyInit(void);
|
||||
|
||||
bool egl_postProcessInit(EGL_PostProcess ** pp);
|
||||
void egl_postProcessFree(EGL_PostProcess ** pp);
|
||||
|
||||
/* create and add a filter to this processor */
|
||||
bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops);
|
||||
|
||||
/* render the imgui options
|
||||
* returns true if the filter needs to be re-run */
|
||||
bool egl_postProcessImgui(EGL_PostProcess * this);
|
||||
|
||||
/* apply the filters to the supplied texture
|
||||
* targetX/Y is the final target output dimension hint if scalers are present */
|
||||
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
|
||||
unsigned int targetX, unsigned int targetY);
|
||||
|
||||
GLuint egl_postProcessGetOutput(EGL_PostProcess * this,
|
||||
unsigned int * outputX, unsigned int * outputY);
|
@ -5,10 +5,10 @@ precision mediump float;
|
||||
layout(location = 0) in vec2 uVertex;
|
||||
layout(location = 1) in vec2 uUV;
|
||||
|
||||
out vec2 iFragCoord;
|
||||
out vec2 fragCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(uVertex, 0.0, 1.0);
|
||||
iFragCoord = uUV;
|
||||
fragCoord = uUV;
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ precision mediump float;
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
in vec2 iFragCoord;
|
||||
in vec2 fragCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D iChannel0;
|
||||
uniform uvec2 uInRes[8];
|
||||
uniform uvec2 uOutRes;
|
||||
uniform sampler2D texture;
|
||||
uniform float uSharpness;
|
||||
|
||||
#define A_GPU 1
|
||||
@ -18,7 +16,7 @@ uniform float uSharpness;
|
||||
|
||||
vec3 imageLoad(ivec2 point)
|
||||
{
|
||||
return texelFetch(iChannel0, point, 0).rgb;
|
||||
return texelFetch(texture, point, 0).rgb;
|
||||
}
|
||||
|
||||
AF3 CasLoad(ASU2 p)
|
||||
@ -32,18 +30,15 @@ void CasInput(inout AF1 r,inout AF1 g,inout AF1 b) {}
|
||||
|
||||
void main()
|
||||
{
|
||||
uvec2 point = uvec2(iFragCoord * vec2(uInRes[0].xy));
|
||||
vec2 res = vec2(textureSize(texture, 0));
|
||||
uvec2 point = uvec2(fragCoord * res);
|
||||
|
||||
vec4 color;
|
||||
vec2 inputResolution = vec2(uInRes[0]);
|
||||
vec2 outputResolution = vec2(uOutRes);
|
||||
|
||||
uvec4 const0;
|
||||
uvec4 const1;
|
||||
|
||||
CasSetup(const0, const1, uSharpness,
|
||||
inputResolution.x, inputResolution.y,
|
||||
outputResolution.x, outputResolution.y);
|
||||
res.x, res.y, res.x, res.y);
|
||||
|
||||
CasFilter(
|
||||
fragColor.r, fragColor.g, fragColor.b,
|
||||
|
@ -3,11 +3,10 @@ precision mediump float;
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
in vec2 iFragCoord;
|
||||
in vec2 fragCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D iChannel0;
|
||||
uniform uvec2 uInRes[8];
|
||||
uniform sampler2D texture;
|
||||
uniform uvec2 uOutRes;
|
||||
|
||||
#define A_GPU 1
|
||||
@ -20,7 +19,8 @@ uniform uvec2 uOutRes;
|
||||
|
||||
vec4 _textureGather(sampler2D tex, vec2 uv, int comp)
|
||||
{
|
||||
ivec2 p = ivec2((uv * vec2(uInRes[0])) - 0.5f);
|
||||
vec2 res = vec2(textureSize(tex, 0));
|
||||
ivec2 p = ivec2((uv * res) - 0.5f);
|
||||
vec4 c0 = texelFetchOffset(tex, p, 0, ivec2(0,1));
|
||||
vec4 c1 = texelFetchOffset(tex, p, 0, ivec2(1,1));
|
||||
vec4 c2 = texelFetchOffset(tex, p, 0, ivec2(1,0));
|
||||
@ -28,18 +28,18 @@ vec4 _textureGather(sampler2D tex, vec2 uv, int comp)
|
||||
return vec4(c0[comp], c1[comp], c2[comp],c3[comp]);
|
||||
}
|
||||
|
||||
AF4 FsrEasuRF(AF2 p){return AF4(_textureGather(iChannel0, p, 0));}
|
||||
AF4 FsrEasuGF(AF2 p){return AF4(_textureGather(iChannel0, p, 1));}
|
||||
AF4 FsrEasuBF(AF2 p){return AF4(_textureGather(iChannel0, p, 2));}
|
||||
AF4 FsrEasuRF(AF2 p){return AF4(_textureGather(texture, p, 0));}
|
||||
AF4 FsrEasuGF(AF2 p){return AF4(_textureGather(texture, p, 1));}
|
||||
AF4 FsrEasuBF(AF2 p){return AF4(_textureGather(texture, p, 2));}
|
||||
|
||||
#include "ffx_fsr1.h"
|
||||
|
||||
void main()
|
||||
{
|
||||
AU4 con0, con1, con2, con3;
|
||||
vec2 inRes = vec2(uInRes[0]);
|
||||
vec2 inRes = vec2(textureSize(texture, 0));
|
||||
vec2 outRes = vec2(uOutRes);
|
||||
|
||||
AU4 con0, con1, con2, con3;
|
||||
FsrEasuCon(
|
||||
con0,
|
||||
con1,
|
||||
@ -51,7 +51,7 @@ void main()
|
||||
);
|
||||
|
||||
vec3 color;
|
||||
uvec2 point = uvec2(iFragCoord * outRes);
|
||||
uvec2 point = uvec2(fragCoord * outRes);
|
||||
FsrEasuF(color, point, con0, con1, con2, con3);
|
||||
fragColor = vec4(color.xyz, 1);
|
||||
}
|
||||
|
@ -3,11 +3,10 @@ precision mediump float;
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
in vec2 iFragCoord;
|
||||
in vec2 fragCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D iChannel0;
|
||||
uniform uvec2 uInRes[8];
|
||||
uniform sampler2D texture;
|
||||
uniform float uSharpness;
|
||||
|
||||
#define A_GPU 1
|
||||
@ -16,7 +15,7 @@ uniform float uSharpness;
|
||||
|
||||
#include "ffx_a.h"
|
||||
|
||||
AF4 FsrRcasLoadF(ASU2 p) { return texelFetch(iChannel0, ASU2(p), 0); }
|
||||
AF4 FsrRcasLoadF(ASU2 p) { return texelFetch(texture, ASU2(p), 0); }
|
||||
void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||
|
||||
#define FSR_RCAS_F 1
|
||||
@ -25,8 +24,8 @@ void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 inRes = vec2(uInRes[0]);
|
||||
uvec2 point = uvec2(iFragCoord * (inRes + 0.5f));
|
||||
vec2 inRes = vec2(textureSize(texture, 0));
|
||||
uvec2 point = uvec2(fragCoord * (inRes + 0.5f));
|
||||
|
||||
uvec4 const0;
|
||||
FsrRcasCon(const0, uSharpness);
|
||||
|
@ -54,8 +54,8 @@ typedef struct RenderStep
|
||||
}
|
||||
RenderStep;
|
||||
|
||||
bool egl_textureInit(EGL * egl, EGL_Texture ** texture_,
|
||||
EGLDisplay * display, EGL_TexType type, bool streaming)
|
||||
bool egl_textureInit(EGL_Texture ** texture_, EGLDisplay * display,
|
||||
EGL_TexType type, bool streaming)
|
||||
{
|
||||
const EGL_TextureOps * ops;
|
||||
|
||||
@ -85,7 +85,6 @@ bool egl_textureInit(EGL * egl, EGL_Texture ** texture_,
|
||||
|
||||
EGL_Texture * this = *texture_;
|
||||
memcpy(&this->ops, ops, sizeof(*ops));
|
||||
this->egl = egl;
|
||||
|
||||
glGenSamplers(1, &this->sampler);
|
||||
glSamplerParameteri(this->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
@ -99,52 +98,12 @@ void egl_textureFree(EGL_Texture ** tex)
|
||||
{
|
||||
EGL_Texture * this = *tex;
|
||||
|
||||
if (this->render)
|
||||
{
|
||||
RenderStep * step;
|
||||
while(ll_shift(this->render, (void **)&step))
|
||||
{
|
||||
if (step->fb)
|
||||
glDeleteFramebuffers(1, &step->fb);
|
||||
|
||||
glDeleteTextures(1, &step->tex);
|
||||
free(step);
|
||||
}
|
||||
ll_free(this->render);
|
||||
egl_modelFree(&this->model);
|
||||
ringbuffer_free(&this->textures);
|
||||
free(this->bindData);
|
||||
}
|
||||
|
||||
glDeleteSamplers(1, &this->sampler);
|
||||
|
||||
this->ops.free(this);
|
||||
*tex = NULL;
|
||||
}
|
||||
|
||||
bool setupRenderStep(EGL_Texture * this, RenderStep * step)
|
||||
{
|
||||
if (step->ready && (step->width > 0 || step->height > 0))
|
||||
return true;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, step->tex);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
this->format.intFormat,
|
||||
step->width > 0 ? step->width : this->format.width,
|
||||
step->height > 0 ? step->height : this->format.height,
|
||||
0,
|
||||
this->format.format,
|
||||
this->format.dataType,
|
||||
NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
step->ready = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
|
||||
size_t width, size_t height, size_t stride)
|
||||
{
|
||||
@ -155,21 +114,10 @@ bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
|
||||
.height = height,
|
||||
.stride = stride
|
||||
};
|
||||
this->size = height * stride;
|
||||
|
||||
if (!egl_texUtilGetFormat(&setup, &this->format))
|
||||
return false;
|
||||
|
||||
this->formatValid = true;
|
||||
|
||||
/* reconfigure any intermediate render steps */
|
||||
if (this->render)
|
||||
{
|
||||
RenderStep * step;
|
||||
for(ll_reset(this->render); ll_walk(this->render, (void **)&step); )
|
||||
step->ready = false;
|
||||
}
|
||||
|
||||
return this->ops.setup(this, &setup);
|
||||
}
|
||||
|
||||
@ -181,13 +129,7 @@ bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer)
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
if (this->ops.update(this, &update))
|
||||
{
|
||||
atomic_store(&this->updated, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this->ops.update(this, &update);
|
||||
}
|
||||
|
||||
bool egl_textureUpdateFromFrame(EGL_Texture * this,
|
||||
@ -202,13 +144,7 @@ bool egl_textureUpdateFromFrame(EGL_Texture * this,
|
||||
.rectCount = damageRectsCount,
|
||||
};
|
||||
|
||||
if (this->ops.update(this, &update))
|
||||
{
|
||||
atomic_store(&this->updated, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this->ops.update(this, &update);
|
||||
}
|
||||
|
||||
bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
||||
@ -221,54 +157,14 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
||||
};
|
||||
|
||||
/* wait for completion */
|
||||
framebuffer_wait(frame, this->size);
|
||||
framebuffer_wait(frame, this->format.bufferSize);
|
||||
|
||||
if (this->ops.update(this, &update))
|
||||
{
|
||||
atomic_store(&this->updated, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this->ops.update(this, &update);
|
||||
}
|
||||
|
||||
enum EGL_TexStatus egl_textureProcess(EGL_Texture * this)
|
||||
{
|
||||
EGL_TexStatus status;
|
||||
if ((status = this->ops.process(this)) == EGL_TEX_STATUS_OK)
|
||||
{
|
||||
if (atomic_exchange(&this->updated, false))
|
||||
this->postProcessed = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
typedef struct BindInfo
|
||||
{
|
||||
GLuint tex;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
}
|
||||
BindInfo;
|
||||
|
||||
typedef struct BindData
|
||||
{
|
||||
GLuint sampler;
|
||||
GLuint dimensions[];
|
||||
}
|
||||
BindData;
|
||||
|
||||
static bool rbBindTexture(int index, void * value, void * udata)
|
||||
{
|
||||
BindInfo * bi = (BindInfo *)value;
|
||||
BindData * bd = (BindData *)udata;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
glBindTexture(GL_TEXTURE_2D, bi->tex);
|
||||
glBindSampler(index, bd->sampler);
|
||||
bd->dimensions[index * 2 + 0] = bi->width;
|
||||
bd->dimensions[index * 2 + 1] = bi->height;
|
||||
return true;
|
||||
return this->ops.process(this);
|
||||
}
|
||||
|
||||
enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
||||
@ -276,8 +172,6 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
||||
GLuint tex;
|
||||
EGL_TexStatus status;
|
||||
|
||||
if (!this->render)
|
||||
{
|
||||
if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK)
|
||||
return status;
|
||||
|
||||
@ -286,196 +180,3 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
||||
glBindSampler(0, this->sampler);
|
||||
return EGL_TEX_STATUS_OK;
|
||||
}
|
||||
|
||||
if (this->bindDataSize < ll_count(this->render))
|
||||
{
|
||||
free(this->bindData);
|
||||
|
||||
BindData * bd = (BindData *)calloc(1, sizeof(struct BindData) +
|
||||
sizeof(bd->dimensions[0]) * (ll_count(this->render)+1) * 2);
|
||||
bd->sampler = this->sampler;
|
||||
|
||||
this->bindData = bd;
|
||||
this->bindDataSize = ll_count(this->render);
|
||||
}
|
||||
|
||||
BindData * bd = (BindData *)this->bindData;
|
||||
RenderStep * step;
|
||||
|
||||
/* if the postProcessing has not yet been done */
|
||||
if (!this->postProcessed)
|
||||
{
|
||||
ringbuffer_reset(this->textures);
|
||||
|
||||
/* configure all the filters */
|
||||
for(ll_reset(this->render); ll_walk(this->render, (void **)&step); )
|
||||
{
|
||||
if (!step->enabled)
|
||||
continue;
|
||||
|
||||
if (!step->ready)
|
||||
setupRenderStep(this, step);
|
||||
}
|
||||
|
||||
if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK)
|
||||
return status;
|
||||
|
||||
struct Rect finalSz =
|
||||
{
|
||||
.x = this->format.width,
|
||||
.y = this->format.height
|
||||
};
|
||||
|
||||
ringbuffer_push(this->textures, &(BindInfo) {
|
||||
.tex = tex,
|
||||
.width = this->format.width,
|
||||
.height = this->format.height
|
||||
});
|
||||
|
||||
ringbuffer_forEach(this->textures, rbBindTexture, bd, true);
|
||||
|
||||
bool cleanup = false;
|
||||
for(ll_reset(this->render); ll_walk(this->render, (void **)&step); )
|
||||
{
|
||||
if (!step->enabled)
|
||||
continue;
|
||||
|
||||
cleanup = true;
|
||||
|
||||
/* create the framebuffer here as it must be in the same gl context as
|
||||
* it's usage */
|
||||
if (!step->fb)
|
||||
{
|
||||
glGenFramebuffers(1, &step->fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, step->fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, step->tex, 0);
|
||||
glDrawBuffers(1, &(GLenum){GL_COLOR_ATTACHMENT0});
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
DEBUG_ERROR("Failed to setup the shader framebuffer");
|
||||
return EGL_TEX_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, step->fb);
|
||||
|
||||
const struct Rect sz =
|
||||
{
|
||||
.x = step->width > 0 ? step->width : this->format.width,
|
||||
.y = step->height > 0 ? step->height : this->format.height
|
||||
};
|
||||
|
||||
glViewport(0, 0, sz.x, sz.y);
|
||||
|
||||
/* use the shader (also configures it's set uniforms) */
|
||||
egl_shaderUse(step->shader);
|
||||
|
||||
/* set the size uniforms */
|
||||
glUniform2uiv(step->uInRes,
|
||||
ringbuffer_getCount(this->textures), bd->dimensions);
|
||||
glUniform2ui(step->uOutRes, sz.x, sz.y);
|
||||
|
||||
/* render the scene */
|
||||
egl_modelRender(this->model);
|
||||
finalSz.x = sz.x;
|
||||
finalSz.y = sz.y;
|
||||
|
||||
/* push the details into the ringbuffer for the next pass */
|
||||
ringbuffer_push(this->textures, &(BindInfo) {
|
||||
.tex = step->tex,
|
||||
.width = sz.x,
|
||||
.height = sz.y
|
||||
});
|
||||
|
||||
/* bind the textures for the next pass */
|
||||
ringbuffer_forEach(this->textures, rbBindTexture, bd, true);
|
||||
}
|
||||
|
||||
/* restore the state and the viewport */
|
||||
if (cleanup)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glUseProgram(0);
|
||||
egl_resetViewport(this->egl);
|
||||
}
|
||||
|
||||
this->finalWidth = finalSz.x;
|
||||
this->finalHeight = finalSz.y;
|
||||
this->postProcessed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bind the last texture */
|
||||
BindInfo * bi = (BindInfo *)ringBuffer_getLastValue(this->textures);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, bi->tex);
|
||||
glBindSampler(0, this->sampler);
|
||||
}
|
||||
|
||||
return EGL_TEX_STATUS_OK;
|
||||
}
|
||||
|
||||
PostProcessHandle egl_textureAddFilter(EGL_Texture * this, EGL_Shader * shader,
|
||||
bool enabled)
|
||||
{
|
||||
if (!this->render)
|
||||
{
|
||||
this->render = ll_new();
|
||||
egl_modelInit(&this->model);
|
||||
egl_modelSetDefault(this->model, false);
|
||||
this->textures = ringbuffer_new(8, sizeof(BindInfo));
|
||||
}
|
||||
|
||||
RenderStep * step = calloc(1, sizeof(*step));
|
||||
glGenTextures(1, &step->tex);
|
||||
step->owner = this;
|
||||
step->shader = shader;
|
||||
step->uInRes = egl_shaderGetUniform(shader, "uInRes" );
|
||||
step->uOutRes = egl_shaderGetUniform(shader, "uOutRes");
|
||||
step->enabled = enabled;
|
||||
|
||||
ll_push(this->render, step);
|
||||
return (PostProcessHandle)step;
|
||||
}
|
||||
|
||||
void egl_textureEnableFilter(PostProcessHandle * handle, bool enable)
|
||||
{
|
||||
RenderStep * step = (RenderStep *)handle;
|
||||
if (step->enabled == enable)
|
||||
return;
|
||||
|
||||
step->enabled = enable;
|
||||
egl_textureInvalidate(step->owner);
|
||||
}
|
||||
|
||||
void egl_textureSetFilterRes(PostProcessHandle * handle,
|
||||
unsigned int x, unsigned int y)
|
||||
{
|
||||
RenderStep * step = (RenderStep *)handle;
|
||||
if (step->width == x && step->height == y)
|
||||
return;
|
||||
|
||||
step->width = x;
|
||||
step->height = y;
|
||||
step->ready = false;
|
||||
egl_textureInvalidate(step->owner);
|
||||
}
|
||||
|
||||
void egl_textureInvalidate(EGL_Texture * texture)
|
||||
{
|
||||
texture->postProcessed = false;
|
||||
}
|
||||
|
||||
void egl_textureGetFinalSize(EGL_Texture * this, struct Rect * rect)
|
||||
{
|
||||
if (!this->render)
|
||||
{
|
||||
rect->x = this->format.width;
|
||||
rect->y = this->format.height;
|
||||
return;
|
||||
}
|
||||
|
||||
rect->x = this->finalWidth;
|
||||
rect->y = this->finalHeight;
|
||||
}
|
||||
|
@ -22,10 +22,10 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "egl.h"
|
||||
#include "egltypes.h"
|
||||
#include "shader.h"
|
||||
#include "model.h"
|
||||
#include "common/framebuffer.h"
|
||||
#include "common/ringbuffer.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "util.h"
|
||||
@ -38,47 +38,6 @@
|
||||
|
||||
typedef struct EGL_Model EGL_Model;
|
||||
|
||||
typedef enum EGL_TexType
|
||||
{
|
||||
EGL_TEXTYPE_BUFFER,
|
||||
EGL_TEXTYPE_FRAMEBUFFER,
|
||||
EGL_TEXTYPE_DMABUF
|
||||
}
|
||||
EGL_TexType;
|
||||
|
||||
typedef enum EGL_PixelFormat
|
||||
{
|
||||
EGL_PF_RGBA,
|
||||
EGL_PF_BGRA,
|
||||
EGL_PF_RGBA10,
|
||||
EGL_PF_RGBA16F
|
||||
}
|
||||
EGL_PixelFormat;
|
||||
|
||||
typedef enum EGL_TexStatus
|
||||
{
|
||||
EGL_TEX_STATUS_NOTREADY,
|
||||
EGL_TEX_STATUS_OK,
|
||||
EGL_TEX_STATUS_ERROR
|
||||
}
|
||||
EGL_TexStatus;
|
||||
|
||||
typedef struct EGL_TexSetup
|
||||
{
|
||||
/* the pixel format of the texture */
|
||||
EGL_PixelFormat pixFmt;
|
||||
|
||||
/* the width of the texture in pixels */
|
||||
size_t width;
|
||||
|
||||
/* the height of the texture in pixels */
|
||||
size_t height;
|
||||
|
||||
/* the stide of the texture in bytes */
|
||||
size_t stride;
|
||||
}
|
||||
EGL_TexSetup;
|
||||
|
||||
typedef struct EGL_TexUpdate
|
||||
{
|
||||
/* the type of this update */
|
||||
@ -130,28 +89,12 @@ EGL_TextureOps;
|
||||
struct EGL_Texture
|
||||
{
|
||||
struct EGL_TextureOps ops;
|
||||
EGL * egl;
|
||||
GLuint sampler;
|
||||
RingBuffer textures;
|
||||
|
||||
EGL_TexFormat format;
|
||||
bool formatValid;
|
||||
|
||||
// needed for dmabuf
|
||||
size_t size;
|
||||
|
||||
// for applying shaders
|
||||
struct ll * render;
|
||||
_Atomic(bool) updated;
|
||||
bool postProcessed;
|
||||
EGL_Model * model;
|
||||
unsigned int finalWidth, finalHeight;
|
||||
|
||||
void * bindData;
|
||||
int bindDataSize;
|
||||
};
|
||||
|
||||
bool egl_textureInit(EGL * egl, EGL_Texture ** texture, EGLDisplay * display,
|
||||
bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
|
||||
EGL_TexType type, bool streaming);
|
||||
void egl_textureFree(EGL_Texture ** tex);
|
||||
|
||||
@ -169,6 +112,16 @@ bool egl_textureUpdateFromDMA(EGL_Texture * texture,
|
||||
|
||||
enum EGL_TexStatus egl_textureProcess(EGL_Texture * texture);
|
||||
|
||||
static inline EGL_TexStatus egl_textureGet(EGL_Texture * texture, GLuint * tex,
|
||||
unsigned int * sizeX, unsigned int * sizeY)
|
||||
{
|
||||
if (sizeX)
|
||||
*sizeX = texture->format.width;
|
||||
if (sizeY)
|
||||
*sizeY = texture->format.height;
|
||||
return texture->ops.get(texture, tex);
|
||||
}
|
||||
|
||||
enum EGL_TexStatus egl_textureBind(EGL_Texture * texture);
|
||||
|
||||
typedef void * PostProcessHandle;
|
||||
|
@ -79,12 +79,22 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
return false;
|
||||
}
|
||||
|
||||
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->bufferSize = setup->height * setup->stride;
|
||||
}
|
||||
|
||||
fmt->bufferSize = fmt->height * fmt->stride;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "texture.h"
|
||||
#include "egltypes.h"
|
||||
|
||||
typedef struct EGL_TexSetup EGL_TexSetup;
|
||||
//typedef struct EGL_TexSetup EGL_TexSetup;
|
||||
|
||||
typedef struct EGL_TexFormat
|
||||
{
|
||||
EGL_PixelFormat pixFmt;
|
||||
|
||||
size_t bpp;
|
||||
GLenum format;
|
||||
GLenum intFormat;
|
||||
|
Loading…
Reference in New Issue
Block a user