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
|
draw.c
|
||||||
splash.c
|
splash.c
|
||||||
damage.c
|
damage.c
|
||||||
|
framebuffer.c
|
||||||
|
postprocess.c
|
||||||
ffx.c
|
ffx.c
|
||||||
|
filter_ffx_cas.c
|
||||||
|
filter_ffx_fsr1.c
|
||||||
${EGL_SHADER_OBJS}
|
${EGL_SHADER_OBJS}
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
||||||
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl3.cpp
|
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl3.cpp
|
||||||
|
@ -80,11 +80,11 @@ struct EGL_Cursor
|
|||||||
struct EGL_Model * model;
|
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 * vertex_code , size_t vertex_size,
|
||||||
const char * fragment_code, size_t fragment_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");
|
DEBUG_ERROR("Failed to initialize the cursor texture");
|
||||||
return false;
|
return false;
|
||||||
@ -133,7 +133,7 @@ static void cursorTexFree(struct CursorTex * t)
|
|||||||
egl_shaderFree (&t->shader );
|
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));
|
*cursor = (EGL_Cursor *)malloc(sizeof(EGL_Cursor));
|
||||||
if (!*cursor)
|
if (!*cursor)
|
||||||
@ -145,12 +145,12 @@ bool egl_cursorInit(EGL * egl, EGL_Cursor ** cursor)
|
|||||||
memset(*cursor, 0, sizeof(EGL_Cursor));
|
memset(*cursor, 0, sizeof(EGL_Cursor));
|
||||||
LG_LOCK_INIT((*cursor)->lock);
|
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_vert , b_shader_cursor_vert_size,
|
||||||
b_shader_cursor_rgb_frag, b_shader_cursor_rgb_frag_size))
|
b_shader_cursor_rgb_frag, b_shader_cursor_rgb_frag_size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!cursorTexInit(egl, &(*cursor)->mono,
|
if (!cursorTexInit(&(*cursor)->mono,
|
||||||
b_shader_cursor_vert , b_shader_cursor_vert_size,
|
b_shader_cursor_vert , b_shader_cursor_vert_size,
|
||||||
b_shader_cursor_mono_frag, b_shader_cursor_mono_frag_size))
|
b_shader_cursor_mono_frag, b_shader_cursor_mono_frag_size))
|
||||||
return false;
|
return false;
|
||||||
|
@ -32,7 +32,7 @@ struct CursorState {
|
|||||||
struct Rect rect;
|
struct Rect rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool egl_cursorInit(EGL * egl, EGL_Cursor ** cursor);
|
bool egl_cursorInit(EGL_Cursor ** cursor);
|
||||||
void egl_cursorFree(EGL_Cursor ** cursor);
|
void egl_cursorFree(EGL_Cursor ** cursor);
|
||||||
|
|
||||||
bool egl_cursorSetShape(
|
bool egl_cursorSetShape(
|
||||||
|
@ -38,10 +38,8 @@
|
|||||||
#include "desktop_rgb.frag.h"
|
#include "desktop_rgb.frag.h"
|
||||||
#include "desktop_rgb.def.h"
|
#include "desktop_rgb.def.h"
|
||||||
|
|
||||||
#include "basic.vert.h"
|
#include "postprocess.h"
|
||||||
#include "ffx_cas.frag.h"
|
#include "filters.h"
|
||||||
#include "ffx_fsr1_easu.frag.h"
|
|
||||||
#include "ffx_fsr1_rcas.frag.h"
|
|
||||||
|
|
||||||
struct DesktopShader
|
struct DesktopShader
|
||||||
{
|
{
|
||||||
@ -60,6 +58,7 @@ struct EGL_Desktop
|
|||||||
EGLDisplay * display;
|
EGLDisplay * display;
|
||||||
|
|
||||||
EGL_Texture * texture;
|
EGL_Texture * texture;
|
||||||
|
GLuint sampler;
|
||||||
struct DesktopShader shader;
|
struct DesktopShader shader;
|
||||||
EGL_DesktopRects * mesh;
|
EGL_DesktopRects * mesh;
|
||||||
CountedBuffer * matrix;
|
CountedBuffer * matrix;
|
||||||
@ -67,7 +66,6 @@ struct EGL_Desktop
|
|||||||
// internals
|
// internals
|
||||||
int width, height;
|
int width, height;
|
||||||
LG_RendererRotate rotate;
|
LG_RendererRotate rotate;
|
||||||
bool upscale;
|
|
||||||
|
|
||||||
// scale algorithm
|
// scale algorithm
|
||||||
int scaleAlgo;
|
int scaleAlgo;
|
||||||
@ -82,15 +80,8 @@ struct EGL_Desktop
|
|||||||
bool useDMA;
|
bool useDMA;
|
||||||
LG_RendererFormat format;
|
LG_RendererFormat format;
|
||||||
|
|
||||||
EGL_Shader * ffxFSR1[2];
|
EGL_PostProcess * pp;
|
||||||
bool ffxFSR1Enable;
|
_Atomic(bool) processFrame;
|
||||||
PostProcessHandle ffxFSR1Handle[2];
|
|
||||||
EGL_Uniform ffxFSR1Uniform;
|
|
||||||
|
|
||||||
EGL_Shader * ffxCAS;
|
|
||||||
bool ffxCASEnable;
|
|
||||||
PostProcessHandle ffxCASHandle;
|
|
||||||
EGL_Uniform ffxCASUniform;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// forwards
|
// forwards
|
||||||
@ -122,20 +113,6 @@ static bool egl_initDesktopShader(
|
|||||||
return true;
|
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 egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||||
bool useDMA, int maxRects)
|
bool useDMA, int maxRects)
|
||||||
{
|
{
|
||||||
@ -150,7 +127,7 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
|||||||
desktop->egl = egl;
|
desktop->egl = egl;
|
||||||
desktop->display = display;
|
desktop->display = display;
|
||||||
|
|
||||||
if (!egl_textureInit(egl, &desktop->texture, display,
|
if (!egl_textureInit(&desktop->texture, display,
|
||||||
useDMA ? EGL_TEXTYPE_DMABUF : EGL_TEXTYPE_FRAMEBUFFER, true))
|
useDMA ? EGL_TEXTYPE_DMABUF : EGL_TEXTYPE_FRAMEBUFFER, true))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the desktop texture");
|
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->scaleAlgo = option_get_int("egl", "scale" );
|
||||||
desktop->useDMA = useDMA;
|
desktop->useDMA = useDMA;
|
||||||
|
|
||||||
// AMD FidelidyFX FSR
|
if (!egl_postProcessInit(&desktop->pp))
|
||||||
egl_shaderInit(&desktop->ffxFSR1[0]);
|
{
|
||||||
egl_shaderCompile(desktop->ffxFSR1[0],
|
DEBUG_ERROR("Failed to initialize the post process manager");
|
||||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
return false;
|
||||||
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);
|
|
||||||
|
|
||||||
|
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops);
|
||||||
|
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,9 +208,7 @@ void egl_desktopFree(EGL_Desktop ** desktop)
|
|||||||
egl_desktopRectsFree(&(*desktop)->mesh );
|
egl_desktopRectsFree(&(*desktop)->mesh );
|
||||||
countedBufferRelease(&(*desktop)->matrix );
|
countedBufferRelease(&(*desktop)->matrix );
|
||||||
|
|
||||||
egl_shaderFree(&(*desktop)->ffxFSR1[0]);
|
egl_postProcessFree(&(*desktop)->pp);
|
||||||
egl_shaderFree(&(*desktop)->ffxFSR1[1]);
|
|
||||||
egl_shaderFree(&(*desktop)->ffxCAS);
|
|
||||||
|
|
||||||
free(*desktop);
|
free(*desktop);
|
||||||
*desktop = NULL;
|
*desktop = NULL;
|
||||||
@ -304,81 +252,10 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
|
|||||||
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
|
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
|
||||||
igPopItemWidth();
|
igPopItemWidth();
|
||||||
|
|
||||||
bool invalidateTex = false;
|
if (egl_postProcessImgui(desktop->pp))
|
||||||
// AMD FidelityFX FSR
|
|
||||||
bool fsr1 = desktop->ffxFSR1Enable;
|
|
||||||
igCheckbox("AMD FidelityFX FSR", &fsr1);
|
|
||||||
if (fsr1 != desktop->ffxFSR1Enable)
|
|
||||||
{
|
{
|
||||||
desktop->ffxFSR1Enable = fsr1;
|
atomic_store(&desktop->processFrame, true);
|
||||||
egl_textureEnableFilter(desktop->ffxFSR1Handle[0],
|
app_invalidateWindow(false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,6 +302,12 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
|||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,52 +317,43 @@ bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dma
|
|||||||
if (desktop->useDMA && dmaFd >= 0)
|
if (desktop->useDMA && dmaFd >= 0)
|
||||||
{
|
{
|
||||||
if (egl_textureUpdateFromDMA(desktop->texture, frame, dmaFd))
|
if (egl_textureUpdateFromDMA(desktop->texture, frame, dmaFd))
|
||||||
|
{
|
||||||
|
atomic_store(&desktop->processFrame, true);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_WARN("DMA update failed, disabling DMABUF imports");
|
DEBUG_WARN("DMA update failed, disabling DMABUF imports");
|
||||||
desktop->useDMA = false;
|
desktop->useDMA = false;
|
||||||
|
|
||||||
egl_textureFree(&desktop->texture);
|
egl_textureFree(&desktop->texture);
|
||||||
if (!egl_textureInit(desktop->egl, &desktop->texture, desktop->display,
|
if (!egl_textureInit(&desktop->texture, desktop->display,
|
||||||
EGL_TEXTYPE_FRAMEBUFFER, true))
|
EGL_TEXTYPE_FRAMEBUFFER, true))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the desktop texture");
|
DEBUG_ERROR("Failed to initialize the desktop texture");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupFilters(desktop);
|
|
||||||
|
|
||||||
if (!egl_desktopSetup(desktop, desktop->format))
|
if (!egl_desktopSetup(desktop, desktop->format))
|
||||||
return false;
|
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)
|
void egl_desktopResize(EGL_Desktop * desktop, int width, int height)
|
||||||
{
|
{
|
||||||
if (width > desktop->width && height > desktop->height)
|
atomic_store(&desktop->processFrame, true);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
|
||||||
LG_RendererRotate rotate, const struct DamageRects * rects)
|
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;
|
int scaleAlgo = EGL_SCALE_NEAREST;
|
||||||
|
|
||||||
struct Rect finalSize;
|
if (atomic_exchange(&desktop->processFrame, false))
|
||||||
egl_textureBind(desktop->texture);
|
egl_postProcessRun(desktop->pp, desktop->texture, outputWidth, outputHeight);
|
||||||
egl_textureGetFinalSize(desktop->texture, &finalSize);
|
|
||||||
if (finalSize.x > desktop->width || finalSize.y > desktop->height)
|
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;
|
scaleType = EGL_DESKTOP_DOWNSCALE;
|
||||||
|
|
||||||
switch (desktop->scaleAlgo)
|
switch (desktop->scaleAlgo)
|
||||||
@ -538,7 +423,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, const float x, const float y,
|
|||||||
{
|
{
|
||||||
.type = EGL_UNIFORM_TYPE_2I,
|
.type = EGL_UNIFORM_TYPE_2I,
|
||||||
.location = shader->uTextureSize,
|
.location = shader->uTextureSize,
|
||||||
.i = { finalSize.x, finalSize.y },
|
.i = { finalSizeX, finalSizeY },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.type = EGL_UNIFORM_TYPE_M3x2FV,
|
.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,
|
bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
|
||||||
const FrameDamageRect * damageRects, int damageRectsCount);
|
const FrameDamageRect * damageRects, int damageRectsCount);
|
||||||
void egl_desktopResize(EGL_Desktop * desktop, int width, int height);
|
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,
|
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
|
||||||
LG_RendererRotate rotate, const struct DamageRects * rects);
|
LG_RendererRotate rotate, const struct DamageRects * rects);
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "splash.h"
|
#include "splash.h"
|
||||||
|
#include "postprocess.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define SPLASH_FADE_TIME 1000000
|
#define SPLASH_FADE_TIME 1000000
|
||||||
@ -182,35 +183,6 @@ static struct Option egl_options[] =
|
|||||||
.value.x_bool = false
|
.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}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -222,6 +194,7 @@ static const char * egl_getName(void)
|
|||||||
static void egl_setup(void)
|
static void egl_setup(void)
|
||||||
{
|
{
|
||||||
option_register(egl_options);
|
option_register(egl_options);
|
||||||
|
egl_postProcessEarlyInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool egl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egl_cursorInit(this, &this->cursor))
|
if (!egl_cursorInit(&this->cursor))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the cursor");
|
DEBUG_ERROR("Failed to initialize the cursor");
|
||||||
return false;
|
return false;
|
||||||
@ -989,6 +962,7 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
|
|||||||
if (this->start)
|
if (this->start)
|
||||||
{
|
{
|
||||||
if (egl_desktopRender(this->desktop,
|
if (egl_desktopRender(this->desktop,
|
||||||
|
this->destRect.w, this->destRect.h,
|
||||||
this->translateX, this->translateY,
|
this->translateX, this->translateY,
|
||||||
this->scaleX , this->scaleY ,
|
this->scaleX , this->scaleY ,
|
||||||
this->scaleType , rotate, renderAll ? NULL : accumulated))
|
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 = 0) in vec2 uVertex;
|
||||||
layout(location = 1) in vec2 uUV;
|
layout(location = 1) in vec2 uUV;
|
||||||
|
|
||||||
out vec2 iFragCoord;
|
out vec2 fragCoord;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = vec4(uVertex, 0.0, 1.0);
|
gl_Position = vec4(uVertex, 0.0, 1.0);
|
||||||
iFragCoord = uUV;
|
fragCoord = uUV;
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,10 @@ precision mediump float;
|
|||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
in vec2 iFragCoord;
|
in vec2 fragCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
uniform sampler2D iChannel0;
|
uniform sampler2D texture;
|
||||||
uniform uvec2 uInRes[8];
|
|
||||||
uniform uvec2 uOutRes;
|
|
||||||
uniform float uSharpness;
|
uniform float uSharpness;
|
||||||
|
|
||||||
#define A_GPU 1
|
#define A_GPU 1
|
||||||
@ -18,7 +16,7 @@ uniform float uSharpness;
|
|||||||
|
|
||||||
vec3 imageLoad(ivec2 point)
|
vec3 imageLoad(ivec2 point)
|
||||||
{
|
{
|
||||||
return texelFetch(iChannel0, point, 0).rgb;
|
return texelFetch(texture, point, 0).rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
AF3 CasLoad(ASU2 p)
|
AF3 CasLoad(ASU2 p)
|
||||||
@ -32,18 +30,15 @@ void CasInput(inout AF1 r,inout AF1 g,inout AF1 b) {}
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
uvec2 point = uvec2(iFragCoord * vec2(uInRes[0].xy));
|
vec2 res = vec2(textureSize(texture, 0));
|
||||||
|
uvec2 point = uvec2(fragCoord * res);
|
||||||
|
|
||||||
vec4 color;
|
vec4 color;
|
||||||
vec2 inputResolution = vec2(uInRes[0]);
|
|
||||||
vec2 outputResolution = vec2(uOutRes);
|
|
||||||
|
|
||||||
uvec4 const0;
|
uvec4 const0;
|
||||||
uvec4 const1;
|
uvec4 const1;
|
||||||
|
|
||||||
CasSetup(const0, const1, uSharpness,
|
CasSetup(const0, const1, uSharpness,
|
||||||
inputResolution.x, inputResolution.y,
|
res.x, res.y, res.x, res.y);
|
||||||
outputResolution.x, outputResolution.y);
|
|
||||||
|
|
||||||
CasFilter(
|
CasFilter(
|
||||||
fragColor.r, fragColor.g, fragColor.b,
|
fragColor.r, fragColor.g, fragColor.b,
|
||||||
|
@ -3,11 +3,10 @@ precision mediump float;
|
|||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
in vec2 iFragCoord;
|
in vec2 fragCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
uniform sampler2D iChannel0;
|
uniform sampler2D texture;
|
||||||
uniform uvec2 uInRes[8];
|
|
||||||
uniform uvec2 uOutRes;
|
uniform uvec2 uOutRes;
|
||||||
|
|
||||||
#define A_GPU 1
|
#define A_GPU 1
|
||||||
@ -20,7 +19,8 @@ uniform uvec2 uOutRes;
|
|||||||
|
|
||||||
vec4 _textureGather(sampler2D tex, vec2 uv, int comp)
|
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 c0 = texelFetchOffset(tex, p, 0, ivec2(0,1));
|
||||||
vec4 c1 = texelFetchOffset(tex, p, 0, ivec2(1,1));
|
vec4 c1 = texelFetchOffset(tex, p, 0, ivec2(1,1));
|
||||||
vec4 c2 = texelFetchOffset(tex, p, 0, ivec2(1,0));
|
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]);
|
return vec4(c0[comp], c1[comp], c2[comp],c3[comp]);
|
||||||
}
|
}
|
||||||
|
|
||||||
AF4 FsrEasuRF(AF2 p){return AF4(_textureGather(iChannel0, p, 0));}
|
AF4 FsrEasuRF(AF2 p){return AF4(_textureGather(texture, p, 0));}
|
||||||
AF4 FsrEasuGF(AF2 p){return AF4(_textureGather(iChannel0, p, 1));}
|
AF4 FsrEasuGF(AF2 p){return AF4(_textureGather(texture, p, 1));}
|
||||||
AF4 FsrEasuBF(AF2 p){return AF4(_textureGather(iChannel0, p, 2));}
|
AF4 FsrEasuBF(AF2 p){return AF4(_textureGather(texture, p, 2));}
|
||||||
|
|
||||||
#include "ffx_fsr1.h"
|
#include "ffx_fsr1.h"
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
AU4 con0, con1, con2, con3;
|
vec2 inRes = vec2(textureSize(texture, 0));
|
||||||
vec2 inRes = vec2(uInRes[0]);
|
|
||||||
vec2 outRes = vec2(uOutRes);
|
vec2 outRes = vec2(uOutRes);
|
||||||
|
|
||||||
|
AU4 con0, con1, con2, con3;
|
||||||
FsrEasuCon(
|
FsrEasuCon(
|
||||||
con0,
|
con0,
|
||||||
con1,
|
con1,
|
||||||
@ -51,7 +51,7 @@ void main()
|
|||||||
);
|
);
|
||||||
|
|
||||||
vec3 color;
|
vec3 color;
|
||||||
uvec2 point = uvec2(iFragCoord * outRes);
|
uvec2 point = uvec2(fragCoord * outRes);
|
||||||
FsrEasuF(color, point, con0, con1, con2, con3);
|
FsrEasuF(color, point, con0, con1, con2, con3);
|
||||||
fragColor = vec4(color.xyz, 1);
|
fragColor = vec4(color.xyz, 1);
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,10 @@ precision mediump float;
|
|||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
in vec2 iFragCoord;
|
in vec2 fragCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
uniform sampler2D iChannel0;
|
uniform sampler2D texture;
|
||||||
uniform uvec2 uInRes[8];
|
|
||||||
uniform float uSharpness;
|
uniform float uSharpness;
|
||||||
|
|
||||||
#define A_GPU 1
|
#define A_GPU 1
|
||||||
@ -16,7 +15,7 @@ uniform float uSharpness;
|
|||||||
|
|
||||||
#include "ffx_a.h"
|
#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) {}
|
void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||||
|
|
||||||
#define FSR_RCAS_F 1
|
#define FSR_RCAS_F 1
|
||||||
@ -25,8 +24,8 @@ void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec2 inRes = vec2(uInRes[0]);
|
vec2 inRes = vec2(textureSize(texture, 0));
|
||||||
uvec2 point = uvec2(iFragCoord * (inRes + 0.5f));
|
uvec2 point = uvec2(fragCoord * (inRes + 0.5f));
|
||||||
|
|
||||||
uvec4 const0;
|
uvec4 const0;
|
||||||
FsrRcasCon(const0, uSharpness);
|
FsrRcasCon(const0, uSharpness);
|
||||||
|
@ -54,8 +54,8 @@ typedef struct RenderStep
|
|||||||
}
|
}
|
||||||
RenderStep;
|
RenderStep;
|
||||||
|
|
||||||
bool egl_textureInit(EGL * egl, EGL_Texture ** texture_,
|
bool egl_textureInit(EGL_Texture ** texture_, EGLDisplay * display,
|
||||||
EGLDisplay * display, EGL_TexType type, bool streaming)
|
EGL_TexType type, bool streaming)
|
||||||
{
|
{
|
||||||
const EGL_TextureOps * ops;
|
const EGL_TextureOps * ops;
|
||||||
|
|
||||||
@ -85,7 +85,6 @@ bool egl_textureInit(EGL * egl, EGL_Texture ** texture_,
|
|||||||
|
|
||||||
EGL_Texture * this = *texture_;
|
EGL_Texture * this = *texture_;
|
||||||
memcpy(&this->ops, ops, sizeof(*ops));
|
memcpy(&this->ops, ops, sizeof(*ops));
|
||||||
this->egl = egl;
|
|
||||||
|
|
||||||
glGenSamplers(1, &this->sampler);
|
glGenSamplers(1, &this->sampler);
|
||||||
glSamplerParameteri(this->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glSamplerParameteri(this->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
@ -99,52 +98,12 @@ void egl_textureFree(EGL_Texture ** tex)
|
|||||||
{
|
{
|
||||||
EGL_Texture * this = *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);
|
glDeleteSamplers(1, &this->sampler);
|
||||||
|
|
||||||
this->ops.free(this);
|
this->ops.free(this);
|
||||||
*tex = NULL;
|
*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,
|
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)
|
||||||
{
|
{
|
||||||
@ -155,21 +114,10 @@ bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
|
|||||||
.height = height,
|
.height = height,
|
||||||
.stride = stride
|
.stride = stride
|
||||||
};
|
};
|
||||||
this->size = height * stride;
|
|
||||||
|
|
||||||
if (!egl_texUtilGetFormat(&setup, &this->format))
|
if (!egl_texUtilGetFormat(&setup, &this->format))
|
||||||
return false;
|
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);
|
return this->ops.setup(this, &setup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,13 +129,7 @@ bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer)
|
|||||||
.buffer = buffer
|
.buffer = buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this->ops.update(this, &update))
|
return this->ops.update(this, &update);
|
||||||
{
|
|
||||||
atomic_store(&this->updated, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_textureUpdateFromFrame(EGL_Texture * this,
|
bool egl_textureUpdateFromFrame(EGL_Texture * this,
|
||||||
@ -202,13 +144,7 @@ bool egl_textureUpdateFromFrame(EGL_Texture * this,
|
|||||||
.rectCount = damageRectsCount,
|
.rectCount = damageRectsCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this->ops.update(this, &update))
|
return this->ops.update(this, &update);
|
||||||
{
|
|
||||||
atomic_store(&this->updated, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
||||||
@ -221,54 +157,14 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* wait for completion */
|
/* wait for completion */
|
||||||
framebuffer_wait(frame, this->size);
|
framebuffer_wait(frame, this->format.bufferSize);
|
||||||
|
|
||||||
if (this->ops.update(this, &update))
|
return this->ops.update(this, &update);
|
||||||
{
|
|
||||||
atomic_store(&this->updated, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EGL_TexStatus egl_textureProcess(EGL_Texture * this)
|
enum EGL_TexStatus egl_textureProcess(EGL_Texture * this)
|
||||||
{
|
{
|
||||||
EGL_TexStatus status;
|
return this->ops.process(this);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
||||||
@ -276,206 +172,11 @@ enum EGL_TexStatus egl_textureBind(EGL_Texture * this)
|
|||||||
GLuint tex;
|
GLuint tex;
|
||||||
EGL_TexStatus status;
|
EGL_TexStatus status;
|
||||||
|
|
||||||
if (!this->render)
|
if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK)
|
||||||
{
|
return status;
|
||||||
if ((status = this->ops.get(this, &tex)) != EGL_TEX_STATUS_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
glBindSampler(0, this->sampler);
|
||||||
return EGL_TEX_STATUS_OK;
|
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 <stdbool.h>
|
||||||
#include "egl.h"
|
#include "egl.h"
|
||||||
|
#include "egltypes.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "common/framebuffer.h"
|
#include "common/framebuffer.h"
|
||||||
#include "common/ringbuffer.h"
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -38,47 +38,6 @@
|
|||||||
|
|
||||||
typedef struct EGL_Model EGL_Model;
|
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
|
typedef struct EGL_TexUpdate
|
||||||
{
|
{
|
||||||
/* the type of this update */
|
/* the type of this update */
|
||||||
@ -130,28 +89,12 @@ EGL_TextureOps;
|
|||||||
struct EGL_Texture
|
struct EGL_Texture
|
||||||
{
|
{
|
||||||
struct EGL_TextureOps ops;
|
struct EGL_TextureOps ops;
|
||||||
EGL * egl;
|
|
||||||
GLuint sampler;
|
GLuint sampler;
|
||||||
RingBuffer textures;
|
|
||||||
|
|
||||||
EGL_TexFormat format;
|
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);
|
EGL_TexType type, bool streaming);
|
||||||
void egl_textureFree(EGL_Texture ** tex);
|
void egl_textureFree(EGL_Texture ** tex);
|
||||||
|
|
||||||
@ -169,6 +112,16 @@ bool egl_textureUpdateFromDMA(EGL_Texture * texture,
|
|||||||
|
|
||||||
enum EGL_TexStatus egl_textureProcess(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);
|
enum EGL_TexStatus egl_textureBind(EGL_Texture * texture);
|
||||||
|
|
||||||
typedef void * PostProcessHandle;
|
typedef void * PostProcessHandle;
|
||||||
|
@ -79,12 +79,22 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt->width = setup->width;
|
fmt->pixFmt = setup->pixFmt;
|
||||||
fmt->height = setup->height;
|
fmt->width = setup->width;
|
||||||
fmt->stride = setup->stride;
|
fmt->height = setup->height;
|
||||||
fmt->pitch = setup->stride / fmt->bpp;
|
|
||||||
fmt->bufferSize = setup->height * setup->stride;
|
|
||||||
|
|
||||||
|
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 = fmt->height * fmt->stride;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +20,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "texture.h"
|
#include "egltypes.h"
|
||||||
|
|
||||||
typedef struct EGL_TexSetup EGL_TexSetup;
|
//typedef struct EGL_TexSetup EGL_TexSetup;
|
||||||
|
|
||||||
typedef struct EGL_TexFormat
|
typedef struct EGL_TexFormat
|
||||||
{
|
{
|
||||||
|
EGL_PixelFormat pixFmt;
|
||||||
|
|
||||||
size_t bpp;
|
size_t bpp;
|
||||||
GLenum format;
|
GLenum format;
|
||||||
GLenum intFormat;
|
GLenum intFormat;
|
||||||
|
Loading…
Reference in New Issue
Block a user