mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-20 14:22:00 +00:00
[client] egl: add cached uniforms and multipass effects
Replace the per-frame uniform list with stable, name-cached handles that retain their values across shader recompilation. Track dirty uniforms so only changed values are uploaded, reducing redundant GL calls and buffer management. Add a reusable effect-pass pipeline with per-pass shaders, samplers, formats, resolutions, and intermediate render targets. This makes external effects easier to integrate and supports arbitrary multipass chains. Migrate the desktop, cursor, damage, 24-bit, downscale, CAS, and FSR rendering paths to the new APIs. Also ensure framebuffer objects are released correctly.
This commit is contained in:
@@ -85,9 +85,9 @@ add_library(renderer_EGL STATIC
|
||||
cursor.c
|
||||
damage.c
|
||||
framebuffer.c
|
||||
effect.c
|
||||
postprocess.c
|
||||
ffx.c
|
||||
filter.c
|
||||
filter_24bit.c
|
||||
filter_ffx_cas.c
|
||||
filter_ffx_fsr1.c
|
||||
|
||||
@@ -41,12 +41,12 @@ struct CursorTex
|
||||
{
|
||||
struct EGL_Texture * texture;
|
||||
struct EGL_Shader * shader;
|
||||
GLuint uMousePos;
|
||||
GLuint uScale;
|
||||
GLuint uRotate;
|
||||
GLuint uCBMode;
|
||||
GLint uMapSDRtoPQ;
|
||||
GLint uSDRWhiteLevel;
|
||||
EGL_Uniform * uMousePos;
|
||||
EGL_Uniform * uScale;
|
||||
EGL_Uniform * uRotate;
|
||||
EGL_Uniform * uCBMode;
|
||||
EGL_Uniform * uMapSDRtoPQ;
|
||||
EGL_Uniform * uSDRWhiteLevel;
|
||||
};
|
||||
|
||||
struct CursorPos
|
||||
@@ -124,12 +124,12 @@ static inline void setCursorTexUniforms(EGL_Cursor * cursor,
|
||||
struct CursorTex * t, bool mono, float x, float y,
|
||||
float w, float h, float scale)
|
||||
{
|
||||
glUniform4f(t->uMousePos , x, y, w, mono ? h / 2 : h);
|
||||
glUniform1f(t->uScale , scale);
|
||||
glUniform1i(t->uRotate , cursor->rotate);
|
||||
glUniform1i(t->uCBMode , cursor->cbMode);
|
||||
glUniform1i(t->uMapSDRtoPQ , !mono && atomic_load(&cursor->mapSDRtoPQ));
|
||||
glUniform1f(t->uSDRWhiteLevel, atomic_load(&cursor->sdrWhiteLevel));
|
||||
egl_uniform4f(t->uMousePos , x, y, w, mono ? h / 2 : h);
|
||||
egl_uniform1f(t->uScale , scale);
|
||||
egl_uniform1i(t->uRotate , cursor->rotate);
|
||||
egl_uniform1i(t->uCBMode , cursor->cbMode);
|
||||
egl_uniform1i(t->uMapSDRtoPQ , !mono && atomic_load(&cursor->mapSDRtoPQ));
|
||||
egl_uniform1f(t->uSDRWhiteLevel, atomic_load(&cursor->sdrWhiteLevel));
|
||||
}
|
||||
|
||||
static void cursorTexFree(struct CursorTex * t)
|
||||
@@ -391,16 +391,16 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
{
|
||||
case LG_CURSOR_MONOCHROME:
|
||||
{
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
setCursorTexUniforms(cursor, &cursor->norm, true, pos.x, pos.y,
|
||||
size.w, size.h, scale);
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
|
||||
egl_modelSetTexture(cursor->model, cursor->norm.texture);
|
||||
egl_modelRender(cursor->model);
|
||||
|
||||
egl_shaderUse(cursor->mono.shader);
|
||||
setCursorTexUniforms(cursor, &cursor->mono, true, pos.x, pos.y,
|
||||
size.w, size.h, scale);
|
||||
egl_shaderUse(cursor->mono.shader);
|
||||
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||
egl_modelSetTexture(cursor->model, cursor->mono.texture);
|
||||
egl_modelRender(cursor->model);
|
||||
@@ -409,16 +409,16 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
|
||||
case LG_CURSOR_MASKED_COLOR:
|
||||
{
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
setCursorTexUniforms(cursor, &cursor->norm, false, pos.x, pos.y,
|
||||
size.w, size.h, scale);
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
egl_modelSetTexture(cursor->model, cursor->norm.texture);
|
||||
egl_modelRender(cursor->model);
|
||||
|
||||
egl_shaderUse(cursor->mono.shader);
|
||||
setCursorTexUniforms(cursor, &cursor->mono, false, pos.x, pos.y,
|
||||
size.w, size.h, scale);
|
||||
egl_shaderUse(cursor->mono.shader);
|
||||
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||
egl_modelSetTexture(cursor->model, cursor->mono.texture);
|
||||
egl_modelRender(cursor->model);
|
||||
@@ -427,9 +427,9 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
|
||||
|
||||
case LG_CURSOR_COLOR:
|
||||
{
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
setCursorTexUniforms(cursor, &cursor->norm, false, pos.x, pos.y,
|
||||
size.w, size.h, scale);
|
||||
egl_shaderUse(cursor->norm.shader);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
egl_modelSetTexture(cursor->model, cursor->norm.texture);
|
||||
egl_modelRender(cursor->model);
|
||||
|
||||
@@ -49,7 +49,7 @@ struct EGL_Damage
|
||||
LG_RendererRotate rotate;
|
||||
|
||||
// uniforms
|
||||
GLint uTransform;
|
||||
EGL_Uniform * uTransform;
|
||||
};
|
||||
|
||||
void egl_damageConfigUI(EGL_Damage * damage)
|
||||
@@ -143,8 +143,8 @@ bool egl_damageRender(EGL_Damage * damage, LG_RendererRotate rotate, const struc
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
egl_uniformMatrix3x2fv(damage->uTransform, 1, GL_FALSE, damage->transform);
|
||||
egl_shaderUse(damage->shader);
|
||||
glUniformMatrix3x2fv(damage->uTransform, 1, GL_FALSE, damage->transform);
|
||||
|
||||
if (data && data->count != 0)
|
||||
egl_desktopRectsUpdate(damage->mesh, (const struct DamageRects *) data,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "texture.h"
|
||||
@@ -44,16 +43,15 @@
|
||||
struct DesktopShader
|
||||
{
|
||||
EGL_Shader * shader;
|
||||
GLint uTransform;
|
||||
GLint uDesktopSize;
|
||||
GLint uSamplerType;
|
||||
GLint uScaleAlgo;
|
||||
GLint uNVGain;
|
||||
GLint uCBMode;
|
||||
GLint uIsHDR;
|
||||
GLint uMapHDRtoSDR;
|
||||
GLint uMapHDRGain;
|
||||
GLint uMapHDRPQ;
|
||||
EGL_Uniform * uTransform;
|
||||
EGL_Uniform * uDesktopSize;
|
||||
EGL_Uniform * uScaleAlgo;
|
||||
EGL_Uniform * uNVGain;
|
||||
EGL_Uniform * uCBMode;
|
||||
EGL_Uniform * uIsHDR;
|
||||
EGL_Uniform * uMapHDRtoSDR;
|
||||
EGL_Uniform * uMapHDRGain;
|
||||
EGL_Uniform * uMapHDRPQ;
|
||||
};
|
||||
|
||||
struct EGL_Desktop
|
||||
@@ -64,7 +62,7 @@ struct EGL_Desktop
|
||||
EGL_Texture * texture;
|
||||
struct DesktopShader dmaShader, shader;
|
||||
EGL_DesktopRects * mesh;
|
||||
CountedBuffer * matrix;
|
||||
GLfloat matrix[6];
|
||||
|
||||
// internals
|
||||
int width, height;
|
||||
@@ -160,13 +158,6 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
return false;
|
||||
}
|
||||
|
||||
desktop->matrix = countedBufferNew(6 * sizeof(GLfloat));
|
||||
if (!desktop->matrix)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate the desktop matrix buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!egl_initDesktopShader(
|
||||
&desktop->shader,
|
||||
b_shader_desktop_vert , b_shader_desktop_vert_size,
|
||||
@@ -248,8 +239,6 @@ void egl_desktopFree(EGL_Desktop ** desktop)
|
||||
egl_shaderFree (&(*desktop)->shader .shader);
|
||||
egl_shaderFree (&(*desktop)->dmaShader.shader);
|
||||
egl_desktopRectsFree(&(*desktop)->mesh );
|
||||
countedBufferRelease(&(*desktop)->matrix );
|
||||
|
||||
egl_postProcessFree(&(*desktop)->pp);
|
||||
|
||||
free(*desktop);
|
||||
@@ -467,7 +456,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
|
||||
int scaleAlgo = EGL_SCALE_NEAREST;
|
||||
|
||||
egl_desktopRectsMatrix((float *)desktop->matrix->data,
|
||||
egl_desktopRectsMatrix(desktop->matrix,
|
||||
width, height, x, y, scaleX, scaleY, rotate);
|
||||
egl_desktopRectsUpdate(desktop->mesh, rects, width, height);
|
||||
|
||||
@@ -523,57 +512,15 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
const float mapHDRGain =
|
||||
(float)desktop->maxCLL / desktop->peakLuminance;
|
||||
|
||||
EGL_Uniform uniforms[] =
|
||||
{
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uScaleAlgo,
|
||||
.i = { scaleAlgo },
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_2F,
|
||||
.location = shader->uDesktopSize,
|
||||
.f = { width, height },
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_M3x2FV,
|
||||
.location = shader->uTransform,
|
||||
.m.transpose = GL_FALSE,
|
||||
.m.v = desktop->matrix
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1F,
|
||||
.location = shader->uNVGain,
|
||||
.f = { (float)desktop->nvGain }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uCBMode,
|
||||
.i = { desktop->cbMode }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uIsHDR,
|
||||
.i = { desktop->hdr }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uMapHDRtoSDR,
|
||||
.i = { desktop->mapHDRtoSDR && !desktop->nativeHDR }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1F,
|
||||
.location = shader->uMapHDRGain,
|
||||
.f = { mapHDRGain }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uMapHDRPQ,
|
||||
.i = { desktop->hdrPQ }
|
||||
}
|
||||
};
|
||||
|
||||
egl_shaderSetUniforms(shader->shader, uniforms, ARRAY_LENGTH(uniforms));
|
||||
egl_uniform1i (shader->uScaleAlgo , scaleAlgo);
|
||||
egl_uniform2f (shader->uDesktopSize, width, height);
|
||||
egl_uniformMatrix3x2fv(shader->uTransform , 1, GL_FALSE, desktop->matrix);
|
||||
egl_uniform1f (shader->uNVGain , desktop->nvGain);
|
||||
egl_uniform1i (shader->uCBMode , desktop->cbMode);
|
||||
egl_uniform1i (shader->uIsHDR , desktop->hdr);
|
||||
egl_uniform1i (shader->uMapHDRtoSDR, desktop->mapHDRtoSDR && !desktop->nativeHDR);
|
||||
egl_uniform1f (shader->uMapHDRGain , mapHDRGain);
|
||||
egl_uniform1i (shader->uMapHDRPQ , desktop->hdrPQ);
|
||||
egl_shaderUse(shader->shader);
|
||||
egl_desktopRectsRender(desktop->mesh);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
231
client/renderers/EGL/effect.c
Normal file
231
client/renderers/EGL/effect.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 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 "effect.h"
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct EGL_EffectPass
|
||||
{
|
||||
EGL_Shader * shader;
|
||||
EGL_Framebuffer * framebuffer;
|
||||
GLuint sampler;
|
||||
|
||||
EGL_Uniform * uTransform;
|
||||
EGL_Uniform * uDesktopSize;
|
||||
|
||||
GLenum minFilter;
|
||||
GLenum magFilter;
|
||||
GLenum wrapS;
|
||||
GLenum wrapT;
|
||||
|
||||
bool enabled;
|
||||
bool configured;
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
struct EGL_EffectPass * next;
|
||||
};
|
||||
|
||||
struct EGL_Effect
|
||||
{
|
||||
EGL_EffectPass * passes;
|
||||
EGL_EffectPass * passesTail;
|
||||
};
|
||||
|
||||
bool egl_effectInit(EGL_Effect ** effect)
|
||||
{
|
||||
*effect = calloc(1, sizeof(**effect));
|
||||
if (!*effect)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate EGL effect");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_effectFree(EGL_Effect ** effect)
|
||||
{
|
||||
if (!*effect)
|
||||
return;
|
||||
|
||||
EGL_EffectPass * pass = (*effect)->passes;
|
||||
while(pass)
|
||||
{
|
||||
EGL_EffectPass * next = pass->next;
|
||||
glDeleteSamplers(1, &pass->sampler);
|
||||
egl_framebufferFree(&pass->framebuffer);
|
||||
free(pass);
|
||||
pass = next;
|
||||
}
|
||||
|
||||
free(*effect);
|
||||
*effect = NULL;
|
||||
}
|
||||
|
||||
void egl_effectPassSetShader(EGL_EffectPass * pass, EGL_Shader * shader)
|
||||
{
|
||||
if (pass->shader == shader)
|
||||
return;
|
||||
|
||||
pass->shader = shader;
|
||||
if (!shader)
|
||||
{
|
||||
pass->uTransform = NULL;
|
||||
pass->uDesktopSize = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
pass->uTransform = egl_shaderGetUniform(shader, "transform");
|
||||
pass->uDesktopSize = egl_shaderGetUniform(shader, "desktopSize");
|
||||
egl_shaderAssocTextures(shader, 1);
|
||||
}
|
||||
|
||||
bool egl_effectAddPass(EGL_Effect * effect, EGL_Shader * shader,
|
||||
EGL_EffectPass ** result)
|
||||
{
|
||||
EGL_EffectPass * pass = calloc(1, sizeof(*pass));
|
||||
if (!pass)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate EGL effect pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&pass->framebuffer))
|
||||
{
|
||||
free(pass);
|
||||
return false;
|
||||
}
|
||||
|
||||
glGenSamplers(1, &pass->sampler);
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
pass->minFilter = GL_LINEAR;
|
||||
pass->magFilter = GL_LINEAR;
|
||||
pass->wrapS = GL_CLAMP_TO_EDGE;
|
||||
pass->wrapT = GL_CLAMP_TO_EDGE;
|
||||
|
||||
pass->enabled = true;
|
||||
egl_effectPassSetShader(pass, shader);
|
||||
|
||||
if (effect->passesTail)
|
||||
effect->passesTail->next = pass;
|
||||
else
|
||||
effect->passes = pass;
|
||||
effect->passesTail = pass;
|
||||
|
||||
if (result)
|
||||
*result = pass;
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_effectPassSetEnabled(EGL_EffectPass * pass, bool enabled)
|
||||
{
|
||||
pass->enabled = enabled;
|
||||
}
|
||||
|
||||
void egl_effectPassSetFilter(EGL_EffectPass * pass, GLenum minFilter,
|
||||
GLenum magFilter)
|
||||
{
|
||||
if (pass->minFilter != minFilter)
|
||||
{
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_MIN_FILTER, minFilter);
|
||||
pass->minFilter = minFilter;
|
||||
}
|
||||
|
||||
if (pass->magFilter != magFilter)
|
||||
{
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_MAG_FILTER, magFilter);
|
||||
pass->magFilter = magFilter;
|
||||
}
|
||||
}
|
||||
|
||||
void egl_effectPassSetWrap(EGL_EffectPass * pass, GLenum wrapS, GLenum wrapT)
|
||||
{
|
||||
if (pass->wrapS != wrapS)
|
||||
{
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_WRAP_S, wrapS);
|
||||
pass->wrapS = wrapS;
|
||||
}
|
||||
|
||||
if (pass->wrapT != wrapT)
|
||||
{
|
||||
glSamplerParameteri(pass->sampler, GL_TEXTURE_WRAP_T, wrapT);
|
||||
pass->wrapT = wrapT;
|
||||
}
|
||||
}
|
||||
|
||||
bool egl_effectPassSetup(EGL_EffectPass * pass, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
if (pass->configured && pass->pixFmt == pixFmt &&
|
||||
pass->width == width && pass->height == height)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(pass->framebuffer, pixFmt, width, height))
|
||||
return false;
|
||||
|
||||
pass->pixFmt = pixFmt;
|
||||
pass->width = width;
|
||||
pass->height = height;
|
||||
pass->configured = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
EGL_Texture * egl_effectRun(EGL_Effect * effect, EGL_FilterRects * rects,
|
||||
EGL_Texture * texture)
|
||||
{
|
||||
for(EGL_EffectPass * pass = effect->passes; pass; pass = pass->next)
|
||||
{
|
||||
if (!pass->enabled)
|
||||
continue;
|
||||
|
||||
if (!pass->configured || !pass->shader)
|
||||
{
|
||||
DEBUG_ERROR("Attempted to run an unconfigured EGL effect pass");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
egl_framebufferBind(pass->framebuffer);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
glBindSampler(0, pass->sampler);
|
||||
|
||||
egl_uniformMatrix3x2fv(pass->uTransform, 1, GL_FALSE, rects->matrix);
|
||||
egl_uniform2f(pass->uDesktopSize, rects->width, rects->height);
|
||||
egl_shaderUse(pass->shader);
|
||||
egl_desktopRectsRender(rects->rects);
|
||||
|
||||
texture = egl_framebufferGetTexture(pass->framebuffer);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
53
client/renderers/EGL/effect.h
Normal file
53
client/renderers/EGL/effect.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 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 "egltypes.h"
|
||||
#include "shader.h"
|
||||
|
||||
typedef struct EGL_Effect EGL_Effect;
|
||||
typedef struct EGL_EffectPass EGL_EffectPass;
|
||||
typedef struct EGL_Texture EGL_Texture;
|
||||
struct EGL_FilterRects;
|
||||
|
||||
/*
|
||||
* Effects execute their enabled passes in insertion order. Each pass owns an
|
||||
* intermediate render target and sampler, while shaders remain caller-owned
|
||||
* so they can be shared or selected at run time.
|
||||
*/
|
||||
bool egl_effectInit(EGL_Effect ** effect);
|
||||
void egl_effectFree(EGL_Effect ** effect);
|
||||
|
||||
bool egl_effectAddPass(EGL_Effect * effect, EGL_Shader * shader,
|
||||
EGL_EffectPass ** pass);
|
||||
|
||||
void egl_effectPassSetShader(EGL_EffectPass * pass, EGL_Shader * shader);
|
||||
void egl_effectPassSetEnabled(EGL_EffectPass * pass, bool enabled);
|
||||
void egl_effectPassSetFilter(EGL_EffectPass * pass, GLenum minFilter,
|
||||
GLenum magFilter);
|
||||
void egl_effectPassSetWrap(EGL_EffectPass * pass, GLenum wrapS,
|
||||
GLenum wrapT);
|
||||
|
||||
bool egl_effectPassSetup(EGL_EffectPass * pass, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height);
|
||||
|
||||
EGL_Texture * egl_effectRun(EGL_Effect * effect,
|
||||
struct EGL_FilterRects * rects, EGL_Texture * texture);
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 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"
|
||||
|
||||
void egl_filterRectsRender(EGL_Shader * shader, EGL_FilterRects * rects)
|
||||
{
|
||||
glUniformMatrix3x2fv(egl_shaderGetUniform(shader, "transform"),
|
||||
1, GL_FALSE, rects->matrix);
|
||||
glUniform2f(egl_shaderGetUniform(shader, "desktopSize"),
|
||||
rects->width, rects->height);
|
||||
egl_desktopRectsRender(rects->rects);
|
||||
}
|
||||
@@ -183,5 +183,3 @@ static inline void egl_filterRelease(EGL_Filter * filter)
|
||||
if (filter->ops.release)
|
||||
filter->ops.release(filter);
|
||||
}
|
||||
|
||||
void egl_filterRectsRender(EGL_Shader * shader, EGL_FilterRects * rects);
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
*/
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
#include "effect.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
@@ -43,11 +42,11 @@ typedef struct EGL_Filter24bit
|
||||
unsigned int desktopWidth, desktopHeight;
|
||||
bool prepared;
|
||||
|
||||
EGL_Uniform uOutputSize;
|
||||
EGL_Uniform * uOutputSize;
|
||||
|
||||
EGL_Shader * shader;
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler[2];
|
||||
EGL_Shader * shader;
|
||||
EGL_Effect * effect;
|
||||
EGL_EffectPass * pass;
|
||||
}
|
||||
EGL_Filter24bit;
|
||||
|
||||
@@ -68,25 +67,27 @@ static bool egl_filter24bitInit(EGL_Filter ** filter)
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&this->fb))
|
||||
if (!egl_effectInit(&this->effect))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the framebuffer");
|
||||
DEBUG_ERROR("Failed to initialize the effect");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
glGenSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
if (!egl_effectAddPass(this->effect, this->shader, &this->pass))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the effect pass");
|
||||
goto error_effect;
|
||||
}
|
||||
|
||||
egl_effectPassSetFilter(this->pass, GL_NEAREST, GL_NEAREST);
|
||||
this->uOutputSize = egl_shaderGetUniform(this->shader, "outputSize");
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_effect:
|
||||
egl_effectFree(&this->effect);
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->shader);
|
||||
|
||||
@@ -99,9 +100,8 @@ static void egl_filter24bitFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
egl_effectFree(&this->effect);
|
||||
egl_shaderFree(&this->shader);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -133,10 +133,6 @@ static bool egl_filter24bitSetup(EGL_Filter * filter,
|
||||
return false;
|
||||
}
|
||||
|
||||
this->uOutputSize.type = EGL_UNIFORM_TYPE_2F;
|
||||
this->uOutputSize.location =
|
||||
egl_shaderGetUniform(this->shader, "outputSize");
|
||||
|
||||
this->useDMA = useDMA;
|
||||
this->prepared = false;
|
||||
}
|
||||
@@ -148,7 +144,7 @@ static bool egl_filter24bitSetup(EGL_Filter * filter,
|
||||
this->desktopHeight == desktopHeight)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, EGL_PF_BGRA, desktopWidth, desktopHeight))
|
||||
if (!egl_effectPassSetup(this->pass, EGL_PF_BGRA, desktopWidth, desktopHeight))
|
||||
return false;
|
||||
|
||||
this->format = pixFmt;
|
||||
@@ -177,9 +173,7 @@ static bool egl_filter24bitPrepare(EGL_Filter * filter)
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
this->uOutputSize.f[0] = this->desktopWidth;
|
||||
this->uOutputSize.f[1] = this->desktopHeight;
|
||||
egl_shaderSetUniforms(this->shader, &this->uOutputSize, 1);
|
||||
egl_uniform2f(this->uOutputSize, this->desktopWidth, this->desktopHeight);
|
||||
|
||||
this->prepared = true;
|
||||
return true;
|
||||
@@ -190,17 +184,7 @@ static EGL_Texture * egl_filter24bitRun(EGL_Filter * filter,
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
|
||||
glBindSampler(0, this->sampler[0]);
|
||||
|
||||
egl_shaderUse(this->shader);
|
||||
egl_filterRectsRender(this->shader, rects);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
return egl_effectRun(this->effect, rects, texture);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filter24bitOps =
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
*/
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
#include "effect.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
@@ -55,9 +54,11 @@ typedef struct EGL_FilterDownscale
|
||||
|
||||
bool enable;
|
||||
EGL_Shader * nearest;
|
||||
EGL_Uniform uNearest;
|
||||
EGL_Uniform * uNearest;
|
||||
EGL_Shader * linear;
|
||||
EGL_Shader * lanczos2;
|
||||
EGL_Effect * effect;
|
||||
EGL_EffectPass * pass;
|
||||
|
||||
DownscaleFilter filter;
|
||||
int useDMA;
|
||||
@@ -67,8 +68,6 @@ typedef struct EGL_FilterDownscale
|
||||
float vOffset, hOffset;
|
||||
bool prepared;
|
||||
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler[2];
|
||||
}
|
||||
EGL_FilterDownscale;
|
||||
|
||||
@@ -163,48 +162,48 @@ static bool egl_filterDownscaleInit(EGL_Filter ** filter)
|
||||
if (!egl_shaderInit(&this->nearest))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the shader");
|
||||
goto error_this;
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
if (!egl_shaderInit(&this->linear))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the shader");
|
||||
goto error_this;
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
if (!egl_shaderInit(&this->lanczos2))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the shader");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&this->fb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the framebuffer");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
glGenSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
if (!egl_effectInit(&this->effect))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the effect");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
if (!egl_effectAddPass(this->effect, this->nearest, &this->pass))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the effect pass");
|
||||
goto error_effect;
|
||||
}
|
||||
|
||||
this->uNearest = egl_shaderGetUniform(this->nearest, "uConfig");
|
||||
|
||||
egl_filterDownscaleLoadState(&this->base);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_effect:
|
||||
egl_effectFree(&this->effect);
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->nearest);
|
||||
egl_shaderFree(&this->linear);
|
||||
egl_shaderFree(&this->lanczos2);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
@@ -213,11 +212,10 @@ static void egl_filterDownscaleFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
|
||||
|
||||
egl_effectFree(&this->effect);
|
||||
egl_shaderFree(&this->nearest);
|
||||
egl_shaderFree(&this->linear);
|
||||
egl_shaderFree(&this->lanczos2);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -345,10 +343,6 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
|
||||
return false;
|
||||
}
|
||||
|
||||
this->uNearest.type = EGL_UNIFORM_TYPE_3F;
|
||||
this->uNearest.location =
|
||||
egl_shaderGetUniform(this->nearest, "uConfig");
|
||||
|
||||
this->useDMA = useDMA;
|
||||
}
|
||||
|
||||
@@ -358,7 +352,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
|
||||
this->height == height)
|
||||
return this->pixelSize > 1.0f;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, pixFmt, width, height))
|
||||
if (!egl_effectPassSetup(this->pass, pixFmt, width, height))
|
||||
return false;
|
||||
|
||||
this->pixFmt = pixFmt;
|
||||
@@ -388,10 +382,8 @@ static bool egl_filterDownscalePrepare(EGL_Filter * filter)
|
||||
switch (this->filter)
|
||||
{
|
||||
case DOWNSCALE_NEAREST:
|
||||
this->uNearest.f[0] = this->pixelSize;
|
||||
this->uNearest.f[1] = this->vOffset;
|
||||
this->uNearest.f[2] = this->hOffset;
|
||||
egl_shaderSetUniforms(this->nearest, &this->uNearest, 1);
|
||||
egl_uniform3f(this->uNearest, this->pixelSize,
|
||||
this->vOffset, this->hOffset);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -407,38 +399,33 @@ static EGL_Texture * egl_filterDownscaleRun(EGL_Filter * filter,
|
||||
{
|
||||
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
|
||||
EGL_Shader * shader;
|
||||
GLenum sampling;
|
||||
|
||||
switch (this->filter)
|
||||
{
|
||||
case DOWNSCALE_NEAREST:
|
||||
glBindSampler(0, this->sampler[0]);
|
||||
shader = this->nearest;
|
||||
sampling = GL_NEAREST;
|
||||
break;
|
||||
|
||||
case DOWNSCALE_LINEAR:
|
||||
glBindSampler(0, this->sampler[1]);
|
||||
shader = this->linear;
|
||||
sampling = GL_LINEAR;
|
||||
break;
|
||||
|
||||
case DOWNSCALE_LANCZOS2:
|
||||
glBindSampler(0, this->sampler[0]);
|
||||
shader = this->lanczos2;
|
||||
sampling = GL_NEAREST;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_UNREACHABLE();
|
||||
}
|
||||
|
||||
egl_shaderUse(shader);
|
||||
egl_filterRectsRender(shader, rects);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
egl_effectPassSetShader(this->pass, shader);
|
||||
egl_effectPassSetFilter(this->pass, sampling, sampling);
|
||||
return egl_effectRun(this->effect, rects, texture);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterDownscaleOps =
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
#include "effect.h"
|
||||
|
||||
#include "common/countedbuffer.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
@@ -34,18 +33,18 @@ typedef struct EGL_FilterFFXCAS
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
EGL_Shader * shader;
|
||||
bool enable;
|
||||
EGL_Shader * shader;
|
||||
EGL_Uniform * uConsts;
|
||||
EGL_Effect * effect;
|
||||
EGL_EffectPass * pass;
|
||||
bool enable;
|
||||
|
||||
int useDMA;
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
unsigned int width, height;
|
||||
float sharpness;
|
||||
CountedBuffer * consts;
|
||||
GLuint consts[8];
|
||||
bool prepared;
|
||||
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler;
|
||||
}
|
||||
EGL_FilterFFXCAS;
|
||||
|
||||
@@ -77,9 +76,10 @@ static void egl_filterFFXCASEarlyInit(void)
|
||||
|
||||
static void casUpdateConsts(EGL_FilterFFXCAS * this)
|
||||
{
|
||||
ffxCasConst((uint32_t *) this->consts->data, this->sharpness,
|
||||
ffxCasConst((uint32_t *)this->consts, this->sharpness,
|
||||
this->width, this->height,
|
||||
this->width, this->height);
|
||||
egl_uniform4uiv(this->uConsts, 2, this->consts);
|
||||
}
|
||||
|
||||
static void egl_filterFFXCASSaveState(EGL_Filter * filter)
|
||||
@@ -115,32 +115,26 @@ static bool egl_filterFFXCASInit(EGL_Filter ** filter)
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
this->consts = countedBufferNew(8 * sizeof(GLuint));
|
||||
if (!this->consts)
|
||||
if (!egl_effectInit(&this->effect))
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate consts buffer");
|
||||
DEBUG_ERROR("Failed to initialize the effect");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
egl_filterFFXCASLoadState(&this->base);
|
||||
|
||||
if (!egl_framebufferInit(&this->fb))
|
||||
if (!egl_effectAddPass(this->effect, this->shader, &this->pass))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the framebuffer");
|
||||
goto error_consts;
|
||||
DEBUG_ERROR("Failed to initialize the effect pass");
|
||||
goto error_effect;
|
||||
}
|
||||
|
||||
glGenSamplers(1, &this->sampler);
|
||||
glSamplerParameteri(this->sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
this->uConsts = egl_shaderGetUniform(this->shader, "uConsts");
|
||||
egl_filterFFXCASLoadState(&this->base);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_consts:
|
||||
countedBufferRelease(&this->consts);
|
||||
error_effect:
|
||||
egl_effectFree(&this->effect);
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->shader);
|
||||
@@ -154,10 +148,8 @@ static void egl_filterFFXCASFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
egl_effectFree(&this->effect);
|
||||
egl_shaderFree(&this->shader);
|
||||
countedBufferRelease(&this->consts);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(1, &this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -229,19 +221,13 @@ static bool egl_filterFFXCASSetup(EGL_Filter * filter,
|
||||
return false;
|
||||
}
|
||||
|
||||
egl_shaderSetUniforms(this->shader, &(EGL_Uniform) {
|
||||
.type = EGL_UNIFORM_TYPE_4UIV,
|
||||
.location = egl_shaderGetUniform(this->shader, "uConsts"),
|
||||
.v = this->consts,
|
||||
}, 1);
|
||||
|
||||
this->useDMA = useDMA;
|
||||
}
|
||||
|
||||
if (pixFmt == this->pixFmt && this->width == width && this->height == height)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, pixFmt, width, height))
|
||||
if (!egl_effectPassSetup(this->pass, pixFmt, width, height))
|
||||
return false;
|
||||
|
||||
this->pixFmt = pixFmt;
|
||||
@@ -279,16 +265,7 @@ static EGL_Texture * egl_filterFFXCASRun(EGL_Filter * filter,
|
||||
{
|
||||
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
|
||||
egl_shaderUse(this->shader);
|
||||
egl_filterRectsRender(this->shader, rects);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
return egl_effectRun(this->effect, rects, texture);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterFFXCASOps =
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
#include "effect.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/countedbuffer.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
@@ -36,11 +34,16 @@ typedef struct EGL_FilterFFXFSR1
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
EGL_Shader * easu, * rcas;
|
||||
bool enable, active;
|
||||
float sharpness;
|
||||
CountedBuffer * consts;
|
||||
EGL_Uniform easuUniform[2], rcasUniform;
|
||||
EGL_Shader * easu, * rcas;
|
||||
EGL_Uniform * uEasuConsts;
|
||||
EGL_Uniform * uEasuOutRes;
|
||||
EGL_Uniform * uRcasConsts;
|
||||
EGL_Effect * effect;
|
||||
EGL_EffectPass * easuPass, * rcasPass;
|
||||
bool enable, active;
|
||||
float sharpness;
|
||||
GLuint easuConsts[16];
|
||||
GLuint rcasConsts[4];
|
||||
|
||||
int useDMA;
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
@@ -49,8 +52,6 @@ typedef struct EGL_FilterFFXFSR1
|
||||
bool sizeChanged;
|
||||
bool prepared;
|
||||
|
||||
EGL_Framebuffer * easuFb, * rcasFb;
|
||||
GLuint sampler;
|
||||
}
|
||||
EGL_FilterFFXFSR1;
|
||||
|
||||
@@ -82,7 +83,8 @@ static void egl_filterFFXFSR1EarlyInit(void)
|
||||
|
||||
static void rcasUpdateUniform(EGL_FilterFFXFSR1 * this)
|
||||
{
|
||||
ffxFsrRcasConst(this->rcasUniform.ui, 2.0f - this->sharpness * 2.0f);
|
||||
ffxFsrRcasConst(this->rcasConsts, 2.0f - this->sharpness * 2.0f);
|
||||
egl_uniform4uiv(this->uRcasConsts, 1, this->rcasConsts);
|
||||
}
|
||||
|
||||
static void egl_filterFFXFSR1SaveState(EGL_Filter * filter)
|
||||
@@ -134,45 +136,36 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
|
||||
goto error_rcas;
|
||||
}
|
||||
|
||||
this->consts = countedBufferNew(16 * sizeof(GLuint));
|
||||
if (!this->consts)
|
||||
if (!egl_effectInit(&this->effect))
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate consts buffer");
|
||||
DEBUG_ERROR("Failed to initialize the effect");
|
||||
goto error_rcas;
|
||||
}
|
||||
|
||||
if (!egl_effectAddPass(this->effect, this->easu, &this->easuPass))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Easu effect pass");
|
||||
goto error_effect;
|
||||
}
|
||||
|
||||
if (!egl_effectAddPass(this->effect, this->rcas, &this->rcasPass))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Rcas effect pass");
|
||||
goto error_effect;
|
||||
}
|
||||
|
||||
this->uEasuConsts = egl_shaderGetUniform(this->easu, "uConsts");
|
||||
this->uEasuOutRes = egl_shaderGetUniform(this->easu, "uOutRes");
|
||||
this->uRcasConsts = egl_shaderGetUniform(this->rcas, "uConsts");
|
||||
|
||||
egl_filterFFXFSR1LoadState(&this->base);
|
||||
|
||||
this->rcasUniform.type = EGL_UNIFORM_TYPE_4UI;
|
||||
this->rcasUniform.location = egl_shaderGetUniform(this->rcas, "uConsts");
|
||||
rcasUpdateUniform(this);
|
||||
|
||||
if (!egl_framebufferInit(&this->easuFb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the Easu framebuffer");
|
||||
goto error_consts;
|
||||
}
|
||||
|
||||
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_consts:
|
||||
countedBufferRelease(&this->consts);
|
||||
error_effect:
|
||||
egl_effectFree(&this->effect);
|
||||
|
||||
error_rcas:
|
||||
egl_shaderFree(&this->rcas);
|
||||
@@ -189,12 +182,9 @@ static void egl_filterFFXFSR1Free(EGL_Filter * filter)
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
egl_effectFree(&this->effect);
|
||||
egl_shaderFree(&this->easu);
|
||||
egl_shaderFree(&this->rcas);
|
||||
countedBufferRelease(&this->consts);
|
||||
egl_framebufferFree(&this->easuFb);
|
||||
egl_framebufferFree(&this->rcasFb);
|
||||
glDeleteSamplers(1, &this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -343,14 +333,6 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||
return false;
|
||||
}
|
||||
|
||||
this->easuUniform[0].type = EGL_UNIFORM_TYPE_4UIV;
|
||||
this->easuUniform[0].location =
|
||||
egl_shaderGetUniform(this->easu, "uConsts");
|
||||
this->easuUniform[0].v = this->consts;
|
||||
this->easuUniform[1].type = EGL_UNIFORM_TYPE_2F;
|
||||
this->easuUniform[1].location =
|
||||
egl_shaderGetUniform(this->easu, "uOutRes");
|
||||
|
||||
this->useDMA = useDMA;
|
||||
}
|
||||
|
||||
@@ -362,10 +344,10 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||
width == this->inWidth && height == this->inHeight)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->easuFb, pixFmt, this->width, this->height))
|
||||
if (!egl_effectPassSetup(this->easuPass, pixFmt, this->width, this->height))
|
||||
return false;
|
||||
|
||||
if (!egl_framebufferSetup(this->rcasFb, pixFmt, this->width, this->height))
|
||||
if (!egl_effectPassSetup(this->rcasPass, pixFmt, this->width, this->height))
|
||||
return false;
|
||||
|
||||
this->inWidth = width;
|
||||
@@ -374,10 +356,10 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
|
||||
this->pixFmt = pixFmt;
|
||||
this->prepared = false;
|
||||
|
||||
this->easuUniform[1].f[0] = this->width;
|
||||
this->easuUniform[1].f[1] = this->height;
|
||||
ffxFsrEasuConst((uint32_t *)this->consts->data, this->inWidth, this->inHeight,
|
||||
egl_uniform2f(this->uEasuOutRes, this->width, this->height);
|
||||
ffxFsrEasuConst(this->easuConsts, this->inWidth, this->inHeight,
|
||||
this->inWidth, this->inHeight, this->width, this->height);
|
||||
egl_uniform4uiv(this->uEasuConsts, 4, this->easuConsts);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -401,8 +383,6 @@ static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter)
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
egl_shaderSetUniforms(this->easu, this->easuUniform, ARRAY_LENGTH(this->easuUniform));
|
||||
egl_shaderSetUniforms(this->rcas, &this->rcasUniform, 1);
|
||||
this->prepared = true;
|
||||
|
||||
return true;
|
||||
@@ -413,25 +393,7 @@ static EGL_Texture * egl_filterFFXFSR1Run(EGL_Filter * filter,
|
||||
{
|
||||
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
|
||||
|
||||
// pass 1, Easu
|
||||
egl_framebufferBind(this->easuFb);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
egl_shaderUse(this->easu);
|
||||
egl_filterRectsRender(this->easu, rects);
|
||||
texture = egl_framebufferGetTexture(this->easuFb);
|
||||
|
||||
// pass 2, Rcas
|
||||
egl_framebufferBind(this->rcasFb);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
glBindSampler(0, this->sampler);
|
||||
egl_shaderUse(this->rcas);
|
||||
egl_filterRectsRender(this->rcas, rects);
|
||||
texture = egl_framebufferGetTexture(this->rcasFb);
|
||||
|
||||
return texture;
|
||||
return egl_effectRun(this->effect, rects, texture);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filterFFXFSR1Ops =
|
||||
|
||||
@@ -57,7 +57,11 @@ void egl_framebufferFree(EGL_Framebuffer ** fb)
|
||||
{
|
||||
EGL_Framebuffer * this = *fb;
|
||||
|
||||
if (!this)
|
||||
return;
|
||||
|
||||
egl_textureFree(&this->tex);
|
||||
glDeleteFramebuffers(1, &this->fbo);
|
||||
free(this);
|
||||
*fb = NULL;
|
||||
}
|
||||
|
||||
@@ -23,18 +23,40 @@
|
||||
#include "common/stringutils.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct EGL_Uniform
|
||||
{
|
||||
char * name;
|
||||
GLint location;
|
||||
|
||||
enum EGL_UniformType type;
|
||||
GLsizei count;
|
||||
GLboolean transpose;
|
||||
bool initialized;
|
||||
bool dirty;
|
||||
|
||||
void * data;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
|
||||
EGL_Shader * shader;
|
||||
struct EGL_Uniform * next;
|
||||
struct EGL_Uniform * dirtyNext;
|
||||
};
|
||||
|
||||
struct EGL_Shader
|
||||
{
|
||||
bool hasShader;
|
||||
GLuint shader;
|
||||
|
||||
EGL_Uniform * uniforms;
|
||||
int uniformCount;
|
||||
int uniformUsed;
|
||||
EGL_Uniform * uniformsTail;
|
||||
EGL_Uniform * dirtyUniforms;
|
||||
EGL_Uniform * dirtyUniformsTail;
|
||||
};
|
||||
|
||||
bool egl_shaderInit(EGL_Shader ** this)
|
||||
@@ -58,8 +80,15 @@ void egl_shaderFree(EGL_Shader ** shader)
|
||||
if (this->hasShader)
|
||||
glDeleteProgram(this->shader);
|
||||
|
||||
egl_shaderFreeUniforms(this);
|
||||
free(this->uniforms);
|
||||
EGL_Uniform * uniform = this->uniforms;
|
||||
while (uniform)
|
||||
{
|
||||
EGL_Uniform * next = uniform->next;
|
||||
free(uniform->name);
|
||||
free(uniform->data);
|
||||
free(uniform);
|
||||
uniform = next;
|
||||
}
|
||||
|
||||
free(this);
|
||||
*shader = NULL;
|
||||
@@ -98,6 +127,34 @@ bool egl_shaderLoad(EGL_Shader * this,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uniformMarkDirty(EGL_Uniform * uniform)
|
||||
{
|
||||
if (uniform->dirty)
|
||||
return;
|
||||
|
||||
uniform->dirty = true;
|
||||
if (uniform->shader->dirtyUniformsTail)
|
||||
uniform->shader->dirtyUniformsTail->dirtyNext = uniform;
|
||||
else
|
||||
uniform->shader->dirtyUniforms = uniform;
|
||||
uniform->shader->dirtyUniformsTail = uniform;
|
||||
}
|
||||
|
||||
static void shaderResolveUniforms(EGL_Shader * this)
|
||||
{
|
||||
this->dirtyUniforms = NULL;
|
||||
this->dirtyUniformsTail = NULL;
|
||||
|
||||
for(EGL_Uniform * uniform = this->uniforms; uniform; uniform = uniform->next)
|
||||
{
|
||||
uniform->location = glGetUniformLocation(this->shader, uniform->name);
|
||||
uniform->dirty = false;
|
||||
uniform->dirtyNext = NULL;
|
||||
if (uniform->initialized)
|
||||
uniformMarkDirty(uniform);
|
||||
}
|
||||
}
|
||||
|
||||
static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
size_t vertex_size, const char * fragment_code, size_t fragment_size)
|
||||
{
|
||||
@@ -187,10 +244,15 @@ static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
if (logLength > 0)
|
||||
{
|
||||
char *log = malloc(logLength + 1);
|
||||
glGetProgramInfoLog(this->shader, logLength, NULL, log);
|
||||
log[logLength] = 0;
|
||||
DEBUG_ERROR("%s", log);
|
||||
free(log);
|
||||
if (!log)
|
||||
DEBUG_ERROR("out of memory");
|
||||
else
|
||||
{
|
||||
glGetProgramInfoLog(this->shader, logLength, NULL, log);
|
||||
log[logLength] = 0;
|
||||
DEBUG_ERROR("%s", log);
|
||||
free(log);
|
||||
}
|
||||
}
|
||||
|
||||
glDetachShader(this->shader, vertexShader );
|
||||
@@ -198,6 +260,7 @@ static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
glDeleteShader(fragmentShader);
|
||||
glDeleteShader(vertexShader );
|
||||
glDeleteProgram(this->shader );
|
||||
this->shader = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -207,6 +270,7 @@ static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
glDeleteShader(vertexShader );
|
||||
|
||||
this->hasShader = true;
|
||||
shaderResolveUniforms(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -353,310 +417,325 @@ exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
void egl_shaderSetUniforms(EGL_Shader * this, EGL_Uniform * uniforms, int count)
|
||||
static bool uniformLayout(enum EGL_UniformType type, size_t * scalarSize,
|
||||
size_t * components)
|
||||
{
|
||||
egl_shaderFreeUniforms(this);
|
||||
if (count > this->uniformCount)
|
||||
switch(type)
|
||||
{
|
||||
free(this->uniforms);
|
||||
this->uniforms = malloc(sizeof(*this->uniforms) * count);
|
||||
if (!this->uniforms)
|
||||
{
|
||||
DEBUG_ERROR("out of memory");
|
||||
return;
|
||||
}
|
||||
case EGL_UNIFORM_TYPE_1F:
|
||||
case EGL_UNIFORM_TYPE_1FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 1; break;
|
||||
case EGL_UNIFORM_TYPE_2F:
|
||||
case EGL_UNIFORM_TYPE_2FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 2; break;
|
||||
case EGL_UNIFORM_TYPE_3F:
|
||||
case EGL_UNIFORM_TYPE_3FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 3; break;
|
||||
case EGL_UNIFORM_TYPE_4F:
|
||||
case EGL_UNIFORM_TYPE_4FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 4; break;
|
||||
|
||||
this->uniformCount = count;
|
||||
case EGL_UNIFORM_TYPE_1I:
|
||||
case EGL_UNIFORM_TYPE_1IV:
|
||||
*scalarSize = sizeof(GLint); *components = 1; break;
|
||||
case EGL_UNIFORM_TYPE_2I:
|
||||
case EGL_UNIFORM_TYPE_2IV:
|
||||
*scalarSize = sizeof(GLint); *components = 2; break;
|
||||
case EGL_UNIFORM_TYPE_3I:
|
||||
case EGL_UNIFORM_TYPE_3IV:
|
||||
*scalarSize = sizeof(GLint); *components = 3; break;
|
||||
case EGL_UNIFORM_TYPE_4I:
|
||||
case EGL_UNIFORM_TYPE_4IV:
|
||||
*scalarSize = sizeof(GLint); *components = 4; break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1UI:
|
||||
case EGL_UNIFORM_TYPE_1UIV:
|
||||
*scalarSize = sizeof(GLuint); *components = 1; break;
|
||||
case EGL_UNIFORM_TYPE_2UI:
|
||||
case EGL_UNIFORM_TYPE_2UIV:
|
||||
*scalarSize = sizeof(GLuint); *components = 2; break;
|
||||
case EGL_UNIFORM_TYPE_3UI:
|
||||
case EGL_UNIFORM_TYPE_3UIV:
|
||||
*scalarSize = sizeof(GLuint); *components = 3; break;
|
||||
case EGL_UNIFORM_TYPE_4UI:
|
||||
case EGL_UNIFORM_TYPE_4UIV:
|
||||
*scalarSize = sizeof(GLuint); *components = 4; break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 4; break;
|
||||
case EGL_UNIFORM_TYPE_M3FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 9; break;
|
||||
case EGL_UNIFORM_TYPE_M4FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 16; break;
|
||||
case EGL_UNIFORM_TYPE_M2x3FV:
|
||||
case EGL_UNIFORM_TYPE_M3x2FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 6; break;
|
||||
case EGL_UNIFORM_TYPE_M2x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x2FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 8; break;
|
||||
case EGL_UNIFORM_TYPE_M3x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x3FV:
|
||||
*scalarSize = sizeof(GLfloat); *components = 12; break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
this->uniformUsed = count;
|
||||
memcpy(this->uniforms, uniforms, sizeof(*this->uniforms) * count);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < this->uniformUsed; ++i)
|
||||
{
|
||||
switch(this->uniforms[i].type)
|
||||
{
|
||||
case EGL_UNIFORM_TYPE_1FV:
|
||||
case EGL_UNIFORM_TYPE_2FV:
|
||||
case EGL_UNIFORM_TYPE_3FV:
|
||||
case EGL_UNIFORM_TYPE_4FV:
|
||||
case EGL_UNIFORM_TYPE_1IV:
|
||||
case EGL_UNIFORM_TYPE_2IV:
|
||||
case EGL_UNIFORM_TYPE_3IV:
|
||||
case EGL_UNIFORM_TYPE_4IV:
|
||||
case EGL_UNIFORM_TYPE_1UIV:
|
||||
case EGL_UNIFORM_TYPE_2UIV:
|
||||
case EGL_UNIFORM_TYPE_3UIV:
|
||||
case EGL_UNIFORM_TYPE_4UIV:
|
||||
countedBufferAddRef(this->uniforms[i].v);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2FV:
|
||||
case EGL_UNIFORM_TYPE_M3FV:
|
||||
case EGL_UNIFORM_TYPE_M4FV:
|
||||
case EGL_UNIFORM_TYPE_M2x3FV:
|
||||
case EGL_UNIFORM_TYPE_M3x2FV:
|
||||
case EGL_UNIFORM_TYPE_M2x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x2FV:
|
||||
case EGL_UNIFORM_TYPE_M3x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x3FV:
|
||||
countedBufferAddRef(this->uniforms[i].m.v);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void egl_shaderFreeUniforms(EGL_Shader * this)
|
||||
EGL_Uniform * egl_shaderGetUniform(EGL_Shader * this, const char * name)
|
||||
{
|
||||
for(int i = 0; i < this->uniformUsed; ++i)
|
||||
for(EGL_Uniform * uniform = this->uniforms; uniform; uniform = uniform->next)
|
||||
if (!strcmp(uniform->name, name))
|
||||
return uniform;
|
||||
|
||||
EGL_Uniform * uniform = calloc(1, sizeof(*uniform));
|
||||
if (!uniform)
|
||||
{
|
||||
switch(this->uniforms[i].type)
|
||||
{
|
||||
case EGL_UNIFORM_TYPE_1FV:
|
||||
case EGL_UNIFORM_TYPE_2FV:
|
||||
case EGL_UNIFORM_TYPE_3FV:
|
||||
case EGL_UNIFORM_TYPE_4FV:
|
||||
case EGL_UNIFORM_TYPE_1IV:
|
||||
case EGL_UNIFORM_TYPE_2IV:
|
||||
case EGL_UNIFORM_TYPE_3IV:
|
||||
case EGL_UNIFORM_TYPE_4IV:
|
||||
case EGL_UNIFORM_TYPE_1UIV:
|
||||
case EGL_UNIFORM_TYPE_2UIV:
|
||||
case EGL_UNIFORM_TYPE_3UIV:
|
||||
case EGL_UNIFORM_TYPE_4UIV:
|
||||
countedBufferRelease(&this->uniforms[i].v);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2FV:
|
||||
case EGL_UNIFORM_TYPE_M3FV:
|
||||
case EGL_UNIFORM_TYPE_M4FV:
|
||||
case EGL_UNIFORM_TYPE_M2x3FV:
|
||||
case EGL_UNIFORM_TYPE_M3x2FV:
|
||||
case EGL_UNIFORM_TYPE_M2x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x2FV:
|
||||
case EGL_UNIFORM_TYPE_M3x4FV:
|
||||
case EGL_UNIFORM_TYPE_M4x3FV:
|
||||
countedBufferRelease(&this->uniforms[i].m.v);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBUG_ERROR("Failed to allocate uniform `%s`", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t nameSize = strlen(name) + 1;
|
||||
uniform->name = malloc(nameSize);
|
||||
if (!uniform->name)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate uniform name `%s`", name);
|
||||
free(uniform);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(uniform->name, name, nameSize);
|
||||
uniform->shader = this;
|
||||
uniform->location = this->hasShader ?
|
||||
glGetUniformLocation(this->shader, name) : -1;
|
||||
|
||||
if (this->uniformsTail)
|
||||
this->uniformsTail->next = uniform;
|
||||
else
|
||||
this->uniforms = uniform;
|
||||
this->uniformsTail = uniform;
|
||||
|
||||
return uniform;
|
||||
}
|
||||
|
||||
bool egl_uniformSet(EGL_Uniform * uniform, enum EGL_UniformType type,
|
||||
GLsizei count, GLboolean transpose, const void * data)
|
||||
{
|
||||
if (!uniform || !data || count < 1)
|
||||
return false;
|
||||
|
||||
size_t scalarSize, components;
|
||||
if (!uniformLayout(type, &scalarSize, &components) ||
|
||||
components > SIZE_MAX / scalarSize ||
|
||||
(size_t)count > SIZE_MAX / (scalarSize * components))
|
||||
return false;
|
||||
|
||||
const size_t size = scalarSize * components * count;
|
||||
const bool changed = !uniform->initialized ||
|
||||
uniform->type != type ||
|
||||
uniform->count != count ||
|
||||
uniform->transpose != transpose ||
|
||||
uniform->size != size ||
|
||||
memcmp(uniform->data, data, size);
|
||||
|
||||
if (!changed)
|
||||
return true;
|
||||
|
||||
if (size > uniform->capacity)
|
||||
{
|
||||
void * newData = realloc(uniform->data, size);
|
||||
if (!newData)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate data for uniform `%s`", uniform->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
uniform->data = newData;
|
||||
uniform->capacity = size;
|
||||
}
|
||||
|
||||
memcpy(uniform->data, data, size);
|
||||
uniform->type = type;
|
||||
uniform->count = count;
|
||||
uniform->transpose = transpose;
|
||||
uniform->size = size;
|
||||
uniform->initialized = true;
|
||||
uniformMarkDirty(uniform);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_uniform1f(EGL_Uniform * uniform, GLfloat x)
|
||||
{
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_1F, 1, GL_FALSE, &x);
|
||||
}
|
||||
|
||||
bool egl_uniform2f(EGL_Uniform * uniform, GLfloat x, GLfloat y)
|
||||
{
|
||||
const GLfloat value[] = { x, y };
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_2F, 1, GL_FALSE, value);
|
||||
}
|
||||
|
||||
bool egl_uniform3f(EGL_Uniform * uniform, GLfloat x, GLfloat y, GLfloat z)
|
||||
{
|
||||
const GLfloat value[] = { x, y, z };
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_3F, 1, GL_FALSE, value);
|
||||
}
|
||||
|
||||
bool egl_uniform4f(EGL_Uniform * uniform, GLfloat x, GLfloat y, GLfloat z,
|
||||
GLfloat w)
|
||||
{
|
||||
const GLfloat value[] = { x, y, z, w };
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_4F, 1, GL_FALSE, value);
|
||||
}
|
||||
|
||||
bool egl_uniform1i(EGL_Uniform * uniform, GLint x)
|
||||
{
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_1I, 1, GL_FALSE, &x);
|
||||
}
|
||||
|
||||
bool egl_uniform1ui(EGL_Uniform * uniform, GLuint x)
|
||||
{
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_1UI, 1, GL_FALSE, &x);
|
||||
}
|
||||
|
||||
bool egl_uniform4ui(EGL_Uniform * uniform, GLuint x, GLuint y, GLuint z,
|
||||
GLuint w)
|
||||
{
|
||||
const GLuint value[] = { x, y, z, w };
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_4UI, 1, GL_FALSE, value);
|
||||
}
|
||||
|
||||
bool egl_uniform4uiv(EGL_Uniform * uniform, GLsizei count,
|
||||
const GLuint * value)
|
||||
{
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_4UIV, count, GL_FALSE,
|
||||
value);
|
||||
}
|
||||
|
||||
bool egl_uniformMatrix3x2fv(EGL_Uniform * uniform, GLsizei count,
|
||||
GLboolean transpose, const GLfloat * value)
|
||||
{
|
||||
return egl_uniformSet(uniform, EGL_UNIFORM_TYPE_M3x2FV, count, transpose,
|
||||
value);
|
||||
}
|
||||
|
||||
static void uniformUpload(EGL_Uniform * uniform)
|
||||
{
|
||||
switch(uniform->type)
|
||||
{
|
||||
case EGL_UNIFORM_TYPE_1F:
|
||||
glUniform1fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2F:
|
||||
glUniform2fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3F:
|
||||
glUniform3fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4F:
|
||||
glUniform4fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_1I:
|
||||
glUniform1iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2I:
|
||||
glUniform2iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3I:
|
||||
glUniform3iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4I:
|
||||
glUniform4iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_1UI:
|
||||
glUniform1uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2UI:
|
||||
glUniform2uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3UI:
|
||||
glUniform3uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4UI:
|
||||
glUniform4uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1FV:
|
||||
glUniform1fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2FV:
|
||||
glUniform2fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3FV:
|
||||
glUniform3fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4FV:
|
||||
glUniform4fv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_1IV:
|
||||
glUniform1iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2IV:
|
||||
glUniform2iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3IV:
|
||||
glUniform3iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4IV:
|
||||
glUniform4iv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_1UIV:
|
||||
glUniform1uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_2UIV:
|
||||
glUniform2uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_3UIV:
|
||||
glUniform3uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_4UIV:
|
||||
glUniform4uiv(uniform->location, uniform->count, uniform->data); break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2FV:
|
||||
glUniformMatrix2fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M3FV:
|
||||
glUniformMatrix3fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M4FV:
|
||||
glUniformMatrix4fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M2x3FV:
|
||||
glUniformMatrix2x3fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M3x2FV:
|
||||
glUniformMatrix3x2fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M2x4FV:
|
||||
glUniformMatrix2x4fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M4x2FV:
|
||||
glUniformMatrix4x2fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M3x4FV:
|
||||
glUniformMatrix3x4fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
case EGL_UNIFORM_TYPE_M4x3FV:
|
||||
glUniformMatrix4x3fv(uniform->location, uniform->count,
|
||||
uniform->transpose, uniform->data); break;
|
||||
}
|
||||
this->uniformUsed = 0;
|
||||
}
|
||||
|
||||
void egl_shaderUse(EGL_Shader * this)
|
||||
{
|
||||
if (this->hasShader)
|
||||
glUseProgram(this->shader);
|
||||
else
|
||||
DEBUG_ERROR("Shader program has not been compiled");
|
||||
|
||||
for(int i = 0; i < this->uniformUsed; ++i)
|
||||
if (!this->hasShader)
|
||||
{
|
||||
EGL_Uniform * uniform = &this->uniforms[i];
|
||||
switch(uniform->type)
|
||||
{
|
||||
case EGL_UNIFORM_TYPE_1F:
|
||||
glUniform1f(uniform->location, uniform->f[0]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2F:
|
||||
glUniform2f(uniform->location, uniform->f[0], uniform->f[1]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3F:
|
||||
glUniform3f(uniform->location, uniform->f[0], uniform->f[1],
|
||||
uniform->f[2]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4F:
|
||||
glUniform4f(uniform->location, uniform->f[0], uniform->f[1],
|
||||
uniform->f[2], uniform->f[3]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1I:
|
||||
glUniform1i(uniform->location, uniform->i[0]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2I:
|
||||
glUniform2i(uniform->location, uniform->i[0], uniform->i[1]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3I:
|
||||
glUniform3i(uniform->location, uniform->i[0], uniform->i[1],
|
||||
uniform->i[2]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4I:
|
||||
glUniform4i(uniform->location, uniform->i[0], uniform->i[1],
|
||||
uniform->i[2], uniform->i[3]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1UI:
|
||||
glUniform1ui(uniform->location, uniform->ui[0]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2UI:
|
||||
glUniform2ui(uniform->location, uniform->ui[0], uniform->ui[1]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3UI:
|
||||
glUniform3ui(uniform->location, uniform->ui[0], uniform->ui[1],
|
||||
uniform->ui[2]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4UI:
|
||||
glUniform4ui(uniform->location, uniform->ui[0], uniform->ui[1],
|
||||
uniform->ui[2], uniform->ui[3]);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1FV:
|
||||
glUniform1fv(uniform->location, uniform->v->size / sizeof(GLfloat),
|
||||
(const GLfloat *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2FV:
|
||||
glUniform2fv(uniform->location, uniform->v->size / sizeof(GLfloat) / 2,
|
||||
(const GLfloat *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3FV:
|
||||
glUniform3fv(uniform->location, uniform->v->size / sizeof(GLfloat) / 3,
|
||||
(const GLfloat *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4FV:
|
||||
glUniform4fv(uniform->location, uniform->v->size / sizeof(GLfloat) / 4,
|
||||
(const GLfloat *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1IV:
|
||||
glUniform1iv(uniform->location, uniform->v->size / sizeof(GLint),
|
||||
(const GLint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2IV:
|
||||
glUniform2iv(uniform->location, uniform->v->size / sizeof(GLint) / 2,
|
||||
(const GLint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3IV:
|
||||
glUniform3iv(uniform->location, uniform->v->size / sizeof(GLint) / 3,
|
||||
(const GLint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4IV:
|
||||
glUniform4iv(uniform->location, uniform->v->size / sizeof(GLint) / 4,
|
||||
(const GLint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_1UIV:
|
||||
glUniform1uiv(uniform->location, uniform->v->size / sizeof(GLuint),
|
||||
(const GLuint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_2UIV:
|
||||
glUniform2uiv(uniform->location, uniform->v->size / sizeof(GLuint) / 2,
|
||||
(const GLuint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_3UIV:
|
||||
glUniform3uiv(uniform->location, uniform->v->size / sizeof(GLuint) / 3,
|
||||
(const GLuint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_4UIV:
|
||||
glUniform4uiv(uniform->location, uniform->v->size / sizeof(GLuint) / 4,
|
||||
(const GLuint *)uniform->v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2FV:
|
||||
glUniformMatrix2fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 2,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M3FV:
|
||||
glUniformMatrix3fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 3,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M4FV:
|
||||
glUniformMatrix4fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 4,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2x3FV:
|
||||
glUniformMatrix2x3fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 6,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M3x2FV:
|
||||
glUniformMatrix3x2fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 6,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M2x4FV:
|
||||
glUniformMatrix2x4fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 8,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M4x2FV:
|
||||
glUniformMatrix4x2fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 8,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M3x4FV:
|
||||
glUniformMatrix3x4fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 12,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
|
||||
case EGL_UNIFORM_TYPE_M4x3FV:
|
||||
glUniformMatrix4x3fv(uniform->location,
|
||||
uniform->v->size / sizeof(GLfloat) / 12,
|
||||
uniform->m.transpose, (const GLfloat *)uniform->m.v->data);
|
||||
break;
|
||||
}
|
||||
DEBUG_ERROR("Shader program has not been compiled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void egl_shaderAssocTextures(EGL_Shader * this, const int count)
|
||||
{
|
||||
char name[] = "sampler1";
|
||||
glUseProgram(this->shader);
|
||||
for(int i = 0; i < count; ++i, name[7]++)
|
||||
{
|
||||
GLint loc = glGetUniformLocation(this->shader, name);
|
||||
if (loc == -1)
|
||||
{
|
||||
DEBUG_WARN("Shader uniform location `%s` not found", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
glUniform1i(loc, i);
|
||||
while(this->dirtyUniforms)
|
||||
{
|
||||
EGL_Uniform * uniform = this->dirtyUniforms;
|
||||
this->dirtyUniforms = uniform->dirtyNext;
|
||||
uniform->dirtyNext = NULL;
|
||||
uniform->dirty = false;
|
||||
|
||||
if (uniform->location != -1)
|
||||
uniformUpload(uniform);
|
||||
}
|
||||
glUseProgram(0);
|
||||
|
||||
this->dirtyUniformsTail = NULL;
|
||||
}
|
||||
|
||||
GLint egl_shaderGetUniform(EGL_Shader * this, const char * name)
|
||||
void egl_shaderAssocTextures(EGL_Shader * this, int count)
|
||||
{
|
||||
if (!this->shader)
|
||||
char name[32];
|
||||
for(int i = 0; i < count; ++i)
|
||||
{
|
||||
DEBUG_ERROR("Shader program has not been compiled");
|
||||
return 0;
|
||||
snprintf(name, sizeof(name), "sampler%d", i + 1);
|
||||
egl_uniform1i(egl_shaderGetUniform(this, name), i);
|
||||
}
|
||||
|
||||
return glGetUniformLocation(this->shader, name);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
|
||||
#include "common/countedbuffer.h"
|
||||
|
||||
typedef struct EGL_Shader EGL_Shader;
|
||||
typedef struct EGL_Shader EGL_Shader;
|
||||
typedef struct EGL_Uniform EGL_Uniform;
|
||||
|
||||
enum EGL_UniformType
|
||||
{
|
||||
@@ -70,29 +69,6 @@ enum EGL_UniformType
|
||||
EGL_UNIFORM_TYPE_M4x3FV
|
||||
};
|
||||
|
||||
typedef struct EGL_Uniform
|
||||
{
|
||||
enum EGL_UniformType type;
|
||||
GLint location;
|
||||
|
||||
union
|
||||
{
|
||||
GLfloat f [4];
|
||||
GLint i [4];
|
||||
GLuint ui[4];
|
||||
|
||||
CountedBuffer * v;
|
||||
|
||||
struct
|
||||
{
|
||||
CountedBuffer * v;
|
||||
GLboolean transpose;
|
||||
}
|
||||
m;
|
||||
};
|
||||
}
|
||||
EGL_Uniform;
|
||||
|
||||
typedef struct EGL_ShaderDefine
|
||||
{
|
||||
const char * name;
|
||||
@@ -103,19 +79,37 @@ EGL_ShaderDefine;
|
||||
bool egl_shaderInit(EGL_Shader ** shader);
|
||||
void egl_shaderFree(EGL_Shader ** shader);
|
||||
|
||||
bool egl_shaderLoad(EGL_Shader * model, const char * vertex_file,
|
||||
const char * fragment_file, bool useDMA, const EGL_ShaderDefine * defines);
|
||||
bool egl_shaderLoad(EGL_Shader * shader, const char * vertex_file,
|
||||
const char * fragment_file, bool useDMA,
|
||||
const EGL_ShaderDefine * defines);
|
||||
|
||||
bool egl_shaderCompile(EGL_Shader * model, const char * vertex_code,
|
||||
bool egl_shaderCompile(EGL_Shader * shader, const char * vertex_code,
|
||||
size_t vertex_size, const char * fragment_code, size_t fragment_size,
|
||||
bool useDMA, const EGL_ShaderDefine * defines);
|
||||
|
||||
void egl_shaderSetUniforms(EGL_Shader * shader, EGL_Uniform * uniforms,
|
||||
int count);
|
||||
void egl_shaderFreeUniforms(EGL_Shader * shader);
|
||||
/*
|
||||
* Uniform handles remain valid when a shader is recompiled. Values are copied
|
||||
* into the shader and are only uploaded when they have changed or the program
|
||||
* has been relinked. count is the number of vectors or matrices in data.
|
||||
*/
|
||||
EGL_Uniform * egl_shaderGetUniform(EGL_Shader * shader, const char * name);
|
||||
bool egl_uniformSet(EGL_Uniform * uniform, enum EGL_UniformType type,
|
||||
GLsizei count, GLboolean transpose, const void * data);
|
||||
|
||||
bool egl_uniform1f (EGL_Uniform * uniform, GLfloat x);
|
||||
bool egl_uniform2f (EGL_Uniform * uniform, GLfloat x, GLfloat y);
|
||||
bool egl_uniform3f (EGL_Uniform * uniform, GLfloat x, GLfloat y, GLfloat z);
|
||||
bool egl_uniform4f (EGL_Uniform * uniform, GLfloat x, GLfloat y, GLfloat z,
|
||||
GLfloat w);
|
||||
bool egl_uniform1i (EGL_Uniform * uniform, GLint x);
|
||||
bool egl_uniform1ui(EGL_Uniform * uniform, GLuint x);
|
||||
bool egl_uniform4ui(EGL_Uniform * uniform, GLuint x, GLuint y, GLuint z,
|
||||
GLuint w);
|
||||
|
||||
bool egl_uniform4uiv(EGL_Uniform * uniform, GLsizei count,
|
||||
const GLuint * value);
|
||||
bool egl_uniformMatrix3x2fv(EGL_Uniform * uniform, GLsizei count,
|
||||
GLboolean transpose, const GLfloat * value);
|
||||
|
||||
void egl_shaderUse(EGL_Shader * shader);
|
||||
|
||||
void egl_shaderAssocTextures(EGL_Shader * shader, const int count);
|
||||
|
||||
GLint egl_shaderGetUniform(EGL_Shader * shader, const char * name);
|
||||
void egl_shaderAssocTextures(EGL_Shader * shader, int count);
|
||||
|
||||
Reference in New Issue
Block a user