OpenGL ES 2.0 support (#187)

* WIP gles2 compat

* More gles2 compat. Playable with ANGLE now, with some rendering bugs.

* fix matrix mult. order in generic laser shader

* gles20: fix indexed rendering

* Update docs about gles20 status

* fix formatting
This commit is contained in:
Andrei Alexeyev 2020-02-15 19:45:09 +02:00 committed by GitHub
parent 44bd09bada
commit 7474ff3a25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 304 additions and 94 deletions

View file

@ -15,7 +15,7 @@ Installation
Dependencies
^^^^^^^^^^^^
- OpenGL >= 3.3 or OpenGL ES >= 3.0
- OpenGL >= 3.3 or OpenGL ES >= 3.0 or OpenGL ES >= 2.0 (with some extensions)
- SDL2 >= 2.0.6
- SDL2_mixer >= 2.0.4
- freetype2
@ -108,8 +108,17 @@ Alternatively, do this to make GLES 3.0 the default backend:
meson configure -Dr_default=gles30
Note that while it's also possible to enable a GLES 2.0 backend, it's currently
not functional.
The OpenGL ES 2.0 backend can be enabled similarly, using ``gles20`` instead of
``gles30``. However, it requires a few extensions to function correctly, most
notably:
- ``OES_depth_texture`` or ``GL_ANGLE_depth_texture``
- ``OES_standard_derivatives``
- ``OES_vertex_array_object``
- ``EXT_frag_depth``
- ``EXT_instanced_arrays`` or ``ANGLE_instanced_arrays`` or
``NV_instanced_arrays``
Where are my replays, screenshots and settings?
-----------------------------------------------

View file

@ -117,10 +117,11 @@ Video and OpenGL
- ``gl33``: the OpenGL 3.3 Core renderer
- ``gles30``: the OpenGL ES 3.0 renderer
- ``gles20``: the OpenGL ES 2.0 renderer
- ``null``: the no-op renderer (nothing is displayed)
Note that the actual subset of usable backends, as well as the default
choice, can be controlled by build options. The ``gles30`` backend is not
choice, can be controlled by build options. The ``gles`` backends are not
built by default.
**TAISEI_LIBGL**

View file

@ -10,10 +10,14 @@ UNIFORM(3) vec2 clear_origin;
UNIFORM(4) int frames;
UNIFORM(5) float progress;
UNIFORM(6) sampler2D noise_tex;
UNIFORM(7) float size;
ivec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
return ivec3(lessThan(vec3(length(pos + m * ofs - origin)), radius));
vec3 xor(vec3 a, vec3 b) {
return abs(a - b);
}
vec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
return step(vec3(length(pos + rot(a) * ofs - origin)), radius);
}
vec3 f(float x, vec3 s) {
@ -40,25 +44,24 @@ void main(void) {
nclr.rgb = max(colormod * vec3(0.1, 0.1, 0.3), nclr.rgb);
vec2 p = texCoord * viewport;
float s = sqrt(pow(viewport.x, 2) + pow(viewport.y, 2));
float o = 32 * (1 + progress);
ivec3 mask = ivec3(0);
vec3 mask = vec3(0);
float a = frames / 30.0;
ivec3 i = ivec3(1,2,3);
vec3 q = 1.0 + 0.01 * i * progress;
mask = mask ^ in_circle(p, vec2(0, 0), 1*a, origin, s * f(pow(progress * 1.5, 1.5), 1.0*q));
mask = mask ^ in_circle(p, vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = xor(mask, in_circle(p, vec2(0, 0), 1*a, origin, size * f(pow(progress * 1.5, 1.5), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = mask ^ in_circle(p, vec2(0, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/1.5), 1.0*q));
mask = mask ^ in_circle(p, vec2(o, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
mask = mask ^ in_circle(p, vec2(0, o), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(o, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(0, o), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
mask = xor(mask, in_circle(p, vec2(0, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/1.5), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(o, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(0, o), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(o, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(0, o), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
fragColor = mix(pclr, nclr, vec4(mask, 0));
}

View file

@ -1,12 +1,17 @@
#version 330 core
#include "lib/fxaa.glslh"
#include "interface/standard.glslh"
UNIFORM(1) sampler2D depth;
VARYING(3) vec4 fxaa_tc;
#include "interface/fxaa.glslh"
void main(void) {
fragColor = vec4(fxaa(tex, fxaa_tc), 1);
gl_FragDepth = texture(depth, fxaa_tc.xy).r;
fragColor = vec4(fxaa(
tex,
v_rcpFrame,
v_coordNW,
v_coordNE,
v_coordSW,
v_coordSE,
v_coordM
), 1);
gl_FragDepth = texture(depth, v_coordM).r;
}

View file

@ -1,12 +1,19 @@
#version 330 core
#include "lib/fxaa.glslh"
#include "interface/standard.glslh"
#include "interface/fxaa.glslh"
#include "lib/render_context.glslh"
VARYING(3) vec4 fxaa_tc;
void main(void) {
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(position, 1.0);
fxaa_tc = fxaaCoords(tex, texCoordRawIn);
v_rcpFrame = 1.0 / tex_SIZE;
fxaaCoords(
texCoordRawIn,
v_rcpFrame,
v_coordNW,
v_coordNE,
v_coordSW,
v_coordSE,
v_coordM
);
}

View file

@ -0,0 +1,29 @@
#ifndef I_FXAA_H
#define I_FXAA_H
#include "../lib/defs.glslh"
#ifdef VERT_STAGE
ATTRIBUTE(0) vec3 position;
// ATTRIBUTE(1) vec3 normalIn;
ATTRIBUTE(2) vec2 texCoordRawIn;
#endif
#ifdef FRAG_STAGE
OUT(0) vec4 fragColor;
#endif
UNIFORM(0) sampler2D tex;
UNIFORM(1) vec2 tex_SIZE;
UNIFORM(2) sampler2D depth;
VARYING(0) vec2 v_coordNW;
VARYING(1) vec2 v_coordNE;
VARYING(2) vec2 v_coordSW;
VARYING(3) vec2 v_coordSE;
VARYING(4) vec2 v_coordM;
VARYING(5) vec2 v_coordRaw;
VARYING(6) vec2 v_rcpFrame;
#endif

View file

@ -5,6 +5,7 @@
#include "interface/standard.glslh"
ATTRIBUTE(3) vec4 instance_pos_delta;
ATTRIBUTE(4) float instance_width;
UNIFORM(1) float timeshift;
UNIFORM(2) float width;
@ -14,8 +15,8 @@ UNIFORM(4) int span;
#include "lasers/vertex_pos.glslh"
void main(void) {
vec2 pos = laser_vertex_pos(instance_pos_delta.xy, instance_pos_delta.zw);
gl_Position = r_modelViewMatrix * r_projectionMatrix * vec4(pos, 0.0, 1.0);
vec2 pos = laser_vertex_pos(instance_pos_delta.xy, instance_pos_delta.zw, instance_width);
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(pos, 0.0, 1.0);
texCoord = (r_textureMatrix * vec4(texCoordRawIn, 0.0, 1.0)).xy;
texCoordRaw = texCoordRawIn;
}

View file

@ -18,7 +18,12 @@ void main(void) {
vec2 p = pos_rule(gl_InstanceID * 0.5 + timeshift);
vec2 d = p - pos_rule(gl_InstanceID * 0.5 + timeshift - 0.1);
vec2 pos = laser_vertex_pos(p, d);
float t1 = gl_InstanceID - span / 2;
float tail = span / 1.9;
float s = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
s = pow(s, width_exponent);
vec2 pos = laser_vertex_pos(p, d, s);
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(pos, 0.0, 1.0);
texCoord = (r_textureMatrix * vec4(texCoordRawIn, 0.0, 1.0)).xy;
texCoordRaw = texCoordRawIn;

View file

@ -1,14 +1,11 @@
vec2 laser_vertex_pos(vec2 origin, vec2 delta) {
vec2 laser_vertex_pos(vec2 origin, vec2 delta, float fragment_width) {
vec2 v = position.xy;
float t1 = gl_InstanceID - span / 2;
float tail = span / 1.9;
float s = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
float a = -angle(delta);
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
v.x *= width * 1.5 * length(delta);
v.y *= width * pow(s, width_exponent);
v.y *= width * fragment_width;;
return m * v + origin;
}

View file

@ -37,4 +37,8 @@
#define NATIVE_ORIGIN_BOTTOMLEFT
#endif
#if defined(BACKEND_GLES20)
#include "legacy_compat.glslh"
#endif
#endif

View file

@ -24,14 +24,20 @@
#ifdef FRAG_STAGE
vec3 fxaa(sampler2D tex, vec4 posPos) {
vec2 rcpFrame = vec2(1.0) / textureSize(tex, 0);
vec3 rgbNW = textureLod(tex, posPos.zw, 0).rgb;
vec3 rgbNE = textureLodOffset(tex, posPos.zw, 0, ivec2(1, 0)).rgb;
vec3 rgbSW = textureLodOffset(tex, posPos.zw, 0, ivec2(0, 1)).rgb;
vec3 rgbSE = textureLodOffset(tex, posPos.zw, 0, ivec2(1, 1)).rgb;
vec3 rgbM = textureLod(tex, posPos.xy, 0).rgb;
vec3 fxaa(
sampler2D tex,
vec2 rcpFrame,
vec2 coordNW,
vec2 coordNE,
vec2 coordSW,
vec2 coordSE,
vec2 coordM
) {
vec3 rgbNW = textureLod(tex, coordNW, 0).rgb;
vec3 rgbNE = textureLod(tex, coordNE, 0).rgb;
vec3 rgbSW = textureLod(tex, coordSW, 0).rgb;
vec3 rgbSE = textureLod(tex, coordSE, 0).rgb;
vec3 rgbM = textureLod(tex, coordM, 0).rgb;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@ -56,13 +62,13 @@ vec3 fxaa(sampler2D tex, vec4 posPos) {
dir = min(vec2(FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX), dir * rcpDirMin)) * rcpFrame.xy;
vec3 rgbA = 0.5 * (
textureLod(tex, posPos.xy + dir * (1.0/3.0 - 0.5), 0).rgb +
textureLod(tex, posPos.xy + dir * (2.0/3.0 - 0.5), 0).rgb
textureLod(tex, coordM + dir * (1.0/3.0 - 0.5), 0).rgb +
textureLod(tex, coordM + dir * (2.0/3.0 - 0.5), 0).rgb
);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
textureLod(tex, posPos.xy + dir * (0.0/3.0 - 0.5), 0).rgb +
textureLod(tex, posPos.xy + dir * (3.0/3.0 - 0.5), 0).rgb
textureLod(tex, coordM + dir * (0.0/3.0 - 0.5), 0).rgb +
textureLod(tex, coordM + dir * (3.0/3.0 - 0.5), 0).rgb
);
float lumaB = dot(rgbB, luma);
@ -78,9 +84,21 @@ vec3 fxaa(sampler2D tex, vec4 posPos) {
#ifdef VERT_STAGE
vec4 fxaaCoords(sampler2D tex, vec2 tc) {
vec2 rcpFrame = vec2(1.0) / textureSize(tex, 0);
return vec4(tc, tc - (rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT)));
void fxaaCoords(
in vec2 texCoord,
in vec2 rcpFrame,
out vec2 o_coordNW,
out vec2 o_coordNE,
out vec2 o_coordSW,
out vec2 o_coordSE,
out vec2 o_coordM
) {
vec2 texCoordShifted = texCoord - (rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT));
o_coordNW = texCoordShifted + vec2( 0.0, 0.0) * rcpFrame;
o_coordNE = texCoordShifted + vec2( 1.0, 0.0) * rcpFrame;
o_coordSW = texCoordShifted + vec2( 0.0, 1.0) * rcpFrame;
o_coordSE = texCoordShifted + vec2( 1.0, 1.0) * rcpFrame;
o_coordM = texCoord;
}
#endif

View file

@ -0,0 +1,17 @@
#ifndef LEGACY_COMPAT_H
#define LEGACY_COMPAT_H
#define LEGACY
#define textureLod(sampler, uv, lod) texture(sampler, uv)
// #define textureLodOffset(sampler, uv, lod) texture(sampler, uv)
#define textureGrad(sampler, uv, dx, dy) texture(sampler, uv)
#define tanh _tanh_compat
float tanh(float x) {
float e2x = exp(2.0 * x);
return (e2x - 1.0) / (e2x + 1.0);
}
#endif

View file

@ -10,10 +10,14 @@ UNIFORM(3) vec2 clear_origin;
UNIFORM(4) int frames;
UNIFORM(5) float progress;
UNIFORM(6) sampler2D noise_tex;
UNIFORM(7) float size;
ivec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
return ivec3(lessThan(vec3(length(pos + m * ofs - origin)), radius));
vec3 xor(vec3 a, vec3 b) {
return abs(a - b);
}
vec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
return step(vec3(length(pos + rot(a) * ofs - origin)), radius);
}
vec3 f(float x, vec3 s) {
@ -40,25 +44,24 @@ void main(void) {
nclr.rgb = max(colormod * vec3(0.1, 0.1, 0.3), nclr.rgb);
vec2 p = texCoord * viewport;
float s = sqrt(pow(viewport.x, 2) + pow(viewport.y, 2));
float o = 32 * (1 + progress);
ivec3 mask = ivec3(0);
vec3 mask = vec3(0);
float a = frames / 30.0;
vec3 i = vec3(1, 2, 3);
vec3 q = 1.0 + 0.01 * i * progress;
mask = mask ^ in_circle(p, vec2(0, 0), 1*a, origin, s * f(pow(progress * 1.5, 1.5), 1.0*q));
mask = mask ^ in_circle(p, vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = mask ^ in_circle(p, -vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
mask = xor(mask, in_circle(p, vec2(0, 0), 1*a, origin, size * f(pow(progress * 1.5, 1.5), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, -vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
mask = xor(mask, in_circle(p, vec2(0, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 4+0.10*i))));
mask = xor(mask, in_circle(p, vec2(o, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
mask = xor(mask, in_circle(p, -vec2(o, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
mask = xor(mask, in_circle(p, vec2(0, o), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
mask = xor(mask, in_circle(p, -vec2(0, o), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
mask = mask ^ in_circle(p, vec2(0, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 4+0.10*i)));
mask = mask ^ in_circle(p, vec2(o, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
mask = mask ^ in_circle(p, -vec2(o, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
mask = mask ^ in_circle(p, vec2(0, o), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
mask = mask ^ in_circle(p, -vec2(0, o), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
fragColor = mix(pclr, nclr, vec4(mask, 0));
}

View file

@ -1221,6 +1221,7 @@ static void boss_death_effect_draw_overlay(Projectile *p, int t) {
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
r_uniform_vec2("clear_origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
r_uniform_float("size", hypotf(VIEWPORT_W, VIEWPORT_H));
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
fbpair_swap(framebuffers);

View file

@ -32,6 +32,7 @@ static struct {
typedef struct LaserInstancedAttribs {
float pos[2];
float delta[2];
float fragment_width;
} LaserInstancedAttribs;
static void lasers_ent_predraw_hook(EntityInterface *ent, void *arg);
@ -78,7 +79,8 @@ void lasers_preload(void) {
// Per-instance attributes (for our own buffer, bound at 1)
// pos and delta packed into a single attribute
{ { 4, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(pos), 1 },
{ { 4, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(pos), 1 },
{ { 1, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(fragment_width), 1 },
};
#undef VERTEX_OFS
@ -222,7 +224,6 @@ static void draw_laser_curve_specialized(Laser *l) {
return;
}
r_shader_ptr(l->shader);
r_color(&l->color);
r_uniform_sampler("tex", "part/lasercurve");
@ -271,15 +272,23 @@ static void draw_laser_curve_generic(Laser *l) {
SDL_RWops *stream = r_vertex_buffer_get_stream(lasers.vbuf);
r_vertex_buffer_invalidate(lasers.vbuf);
float tail = instances / 1.9;
float tail_factor = -0.75 / (tail * tail);
for(uint i = 0; i < instances; ++i) {
cmplx pos = l->prule(l, i * 0.5 + timeshift);
cmplx delta = pos - l->prule(l, i * 0.5 + timeshift - 0.1);
float t1 = i - instances / 2.0;
float s = powf(tail_factor * (t1 - tail) * (t1 + tail), l->width_exponent);
LaserInstancedAttribs attr;
attr.pos[0] = creal(pos);
attr.pos[1] = cimag(pos);
attr.delta[0] = creal(delta);
attr.delta[1] = cimag(delta);
attr.fragment_width = s;
SDL_RWwrite(stream, &attr, sizeof(attr), 1);
}

View file

@ -858,6 +858,7 @@ static void player_death_effect_draw_overlay(Projectile *p, int t) {
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
r_uniform_vec2("clear_origin", creal(global.plr.pos), VIEWPORT_H - cimag(global.plr.pos));
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
r_uniform_float("size", hypotf(VIEWPORT_W, VIEWPORT_H));
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
fbpair_swap(framebuffers);

View file

@ -75,6 +75,10 @@ void r_shutdown(void) {
B.shutdown();
}
const char *r_backend_name(void) {
return _r_backend.name;
}
void r_shader_standard(void) {
r_shader_ptr(R.progs.standard);
}

View file

@ -432,6 +432,7 @@ SDL_Window* r_create_window(const char *title, int x, int y, int w, int h, uint3
void r_init(void);
void r_post_init(void);
void r_shutdown(void);
const char *r_backend_name(void);
r_feature_bits_t r_features(void);
@ -806,13 +807,7 @@ ShaderProgram* r_shader_get(const char *name) {
INLINE
ShaderProgram* r_shader_get_optional(const char *name) {
ShaderProgram *prog = get_resource_data(RES_SHADER_PROGRAM, name, RESF_OPTIONAL | RESF_UNSAFE);
if(!prog) {
log_warn("shader program %s could not be loaded", name);
}
return prog;
return get_resource_data(RES_SHADER_PROGRAM, name, RESF_OPTIONAL | RESF_UNSAFE);
}
INLINE

View file

@ -14,7 +14,7 @@
#include "util/sha256.h"
#include "rwops/all.h"
#define CACHE_VERSION 2
#define CACHE_VERSION 3
#define CRC_INIT 0
static uint8_t* shader_cache_construct_entry(const ShaderSource *src, size_t *out_size) {

View file

@ -258,7 +258,16 @@ bool _spirv_decompile(const ShaderSource *in, ShaderSource *out, const SPIRVDeco
}
if(!glsl_version_supports_instanced_rendering(options->lang->glsl.version)) {
SPVCCALL(spvc_compiler_require_extension(compiler, "GL_ARB_draw_instanced"));
SPVCCALL(spvc_compiler_add_header_line(compiler,
"#ifdef GL_ARB_draw_instanced\n"
"#extension GL_ARB_draw_instanced : enable\n"
"#endif\n"
"#ifdef GL_EXT_frag_depth\n"
"#extension GL_EXT_frag_depth : enable\n"
"#define gl_FragDepth gl_FragDepthEXT\n"
"#endif\n"
));
}
SPVCCALL(spvc_compiler_create_compiler_options(compiler, &spvc_options));

View file

@ -110,7 +110,7 @@ bool spirv_transpile(const ShaderSource *in, ShaderSource *out, const SPIRVTrans
if(
!shader_lang_supports_uniform_locations(&_in.lang) &&
shader_lang_supports_uniform_locations(options->lang) &&
// shader_lang_supports_uniform_locations(options->lang) &&
_in.lang.lang == SHLANG_GLSL
) {
// HACK: This is annoying... shaderc/glslang does not support GL_ARB_explicit_uniform_location

View file

@ -16,7 +16,7 @@
static Uniform *sampler_uniforms;
Uniform* gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
return ht_get(&prog->uniforms, uniform_name, NULL);
}
@ -212,11 +212,13 @@ static void gl33_commit_uniform(Uniform *uniform) {
uniform->cache.update_last_idx = 0;
}
static void* gl33_sync_uniform(const char *key, void *value, void *arg) {
static void *gl33_sync_uniform(const char *key, void *value, void *arg) {
Uniform *uniform = value;
// special case: for sampler uniforms, we have to construct the actual data from the texture pointers array.
if(uniform->type == UNIFORM_SAMPLER) {
Uniform *size_uniform = uniform->size_uniform;
for(uint i = 0; i < uniform->array_size; ++i) {
Texture *tex = uniform->textures[i];
@ -226,6 +228,14 @@ static void* gl33_sync_uniform(const char *key, void *value, void *arg) {
GLuint unit = gl33_bind_texture(tex, true);
gl33_update_uniform(uniform, i, 1, &unit);
if(size_uniform) {
uint w, h;
r_texture_get_size(tex, 0, &w, &h);
vec2_noalign size = { w, h };
gl33_update_uniform(size_uniform, i, 1, &size);
gl33_commit_uniform(size_uniform);
}
}
}
@ -358,6 +368,39 @@ static bool cache_uniforms(ShaderProgram *prog) {
log_debug("%s = %i [array elements: %i; size: %zi bytes]", name, loc, uni.array_size, uni.array_size * uni.elem_size);
}
ht_str2ptr_iter_t iter;
ht_iter_begin(&prog->uniforms, &iter);
while(iter.has_data) {
Uniform *u = iter.value;
if(u->type == UNIFORM_SAMPLER) {
const char *sampler_name = iter.key;
const char size_suffix[] = "_SIZE";
char size_uniform_name[strlen(sampler_name) + sizeof(size_suffix)];
snprintf(size_uniform_name, sizeof(size_uniform_name), "%s%s", sampler_name, size_suffix);
u->size_uniform = ht_get(&prog->uniforms, size_uniform_name, NULL);
if(u->size_uniform) {
Uniform *size_uniform = u->size_uniform;
if(size_uniform->type != UNIFORM_VEC2) {
log_warn("Size uniform %s has invalid type (should be vec2), ignoring", size_uniform_name);
u->size_uniform = NULL;
} else if(size_uniform->array_size != u->array_size) {
log_warn("Size uniform %s has invalid array size (should be %i), ignoring", size_uniform_name, u->array_size);
u->size_uniform = NULL;
} else {
log_debug("Bound size uniform: %s --> %s", sampler_name, size_uniform_name);
}
assert(u->size_uniform != NULL); // fix your shader!
}
}
ht_iter_next(&iter);
}
ht_iter_end(&iter);
return true;
}
@ -390,7 +433,7 @@ static void print_info_log(GLuint prog) {
}
}
static void* free_uniform(const char *key, void *data, void *arg) {
static void *free_uniform(const char *key, void *data, void *arg) {
Uniform *uniform = data;
if(uniform->type == UNIFORM_SAMPLER) {
@ -412,7 +455,7 @@ void gl33_shader_program_destroy(ShaderProgram *prog) {
free(prog);
}
ShaderProgram* gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]) {
ShaderProgram *gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]) {
ShaderProgram *prog = calloc(1, sizeof(*prog));
prog->gl_handle = glCreateProgram();
@ -454,6 +497,6 @@ void gl33_shader_program_set_debug_label(ShaderProgram *prog, const char *label)
glcommon_set_debug_label(prog->debug_label, "Shader program", GL_PROGRAM, prog->gl_handle, label);
}
const char* gl33_shader_program_get_debug_label(ShaderProgram *prog) {
const char *gl33_shader_program_get_debug_label(ShaderProgram *prog) {
return prog->debug_label;
}

View file

@ -34,6 +34,9 @@ struct Uniform {
uint location;
UniformType type;
// corresponding _SIZE uniform (for samplers; optional)
Uniform *size_uniform;
struct {
// buffer size = elem_size * array_size
char *pending;
@ -46,12 +49,12 @@ struct Uniform {
void gl33_sync_uniforms(ShaderProgram *prog);
ShaderProgram* gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]);
ShaderProgram *gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]);
void gl33_shader_program_destroy(ShaderProgram *prog);
void gl33_shader_program_set_debug_label(ShaderProgram *prog, const char *label);
const char* gl33_shader_program_get_debug_label(ShaderProgram *prog);
Uniform* gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name);
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name);
UniformType gl33_uniform_type(Uniform *uniform);
void gl33_uniform(Uniform *uniform, uint offset, uint count, const void *data);
void gl33_unref_texture_from_samplers(Texture *tex);

View file

@ -71,6 +71,11 @@ static void APIENTRY glcommon_debug(
// HACK: Workaround for an ANGLE bug. Seems like it always reports the original array size for
// uniform arrays, even if the arrays has been partially optimized out. Accessing the non-existent
// elements then generates a GL_INVALID_OPERATION error, which should be safe to ignore.
lvl = LOG_ERROR;
}
if(lvl == LOG_FATAL && glext.version.is_ANGLE && !strcmp(message, "Invalid uniform location")) {
// seriously?
lvl = LOG_WARN;
}

View file

@ -168,6 +168,13 @@ GLenum glcommon_texture_base_format(GLenum internal_fmt) {
case GL_RGBA8_SNORM: return GL_RGBA;
case GL_SRGB8: return GL_RGB;
case GL_SRGB8_ALPHA8: return GL_RGBA;
// GLES2 may use these as internal formats
case GL_RED: return GL_RED;
case GL_RG: return GL_RG;
case GL_RGB: return GL_RGB;
case GL_RGBA: return GL_RGBA;
case GL_DEPTH_COMPONENT: return GL_DEPTH_COMPONENT;
}
UNREACHABLE;

View file

@ -35,14 +35,18 @@ static void gles20_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx
void *state;
gl33_begin_draw(varr, &state);
IndexBuffer *ibuf = varr->index_attachment;
gles20_ibo_index_t *indices = ibuf->elements + firstidx;
assert(indices < ibuf->elements + ibuf->num_elements);
if(instances) {
if(base_instance) {
glDrawElementsInstancedBaseInstance(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements, instances, base_instance);
glDrawElementsInstancedBaseInstance(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices, instances, base_instance);
} else {
glDrawElementsInstanced(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements, instances);
glDrawElementsInstanced(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices, instances);
}
} else {
glDrawElements(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements);
glDrawElements(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices);
}
gl33_end_draw(state);

View file

@ -155,7 +155,6 @@ void gles_init_texformats_table(void) {
}
for(uint i = 0; i < sizeof(gles_texformats)/sizeof(*gles_texformats); ++i) {
log_debug("fuck %i", i);
gles_texformats[i].external_formats[0] = gles_texformats[i].primary_external_format;
if(!is_gles3) {
@ -178,6 +177,10 @@ GLTexFormatCapabilities gles_texture_format_caps(GLenum internal_fmt) {
*/
switch(internal_fmt) {
case GL_RED:
case GL_RG:
case GL_RGB:
case GL_RGBA:
case GL_R8:
case GL_RG8:
case GL_RGB8:
@ -227,6 +230,7 @@ GLTexFormatCapabilities gles_texture_format_caps(GLenum internal_fmt) {
}
break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
// FIXME: Is there an extension that makes it filterable?

View file

@ -69,11 +69,25 @@ static void* load_shader_object_begin(const char *path, uint flags) {
struct shobj_load_data *ldata = calloc(1, sizeof(struct shobj_load_data));
char backend_macro[32] = "BACKEND_";
{
const char *backend_name = r_backend_name();
char *out = backend_macro + sizeof("BACKEND_") - 1;
for(const char *in = backend_name; *in;) {
*out++ = toupper(*in++);
}
*out = 0;
}
switch(type->lang) {
case SHLANG_GLSL: {
GLSLSourceOptions opts = {
.version = { 330, GLSL_PROFILE_CORE },
.stage = type->stage,
.macros = (GLSLMacro[]) {
{ backend_macro, "1" },
{ NULL, },
},
};
if(!glsl_load_source(path, &ldata->source, &opts)) {

View file

@ -342,10 +342,12 @@ static void stage1_preload(void) {
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"blur5",
"lasers/linear",
"stage1_water",
"zbuf_fog",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/linear",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,
"boss/cirno",
NULL);

View file

@ -182,6 +182,8 @@ static void stage2_preload(void) {
"bloom",
"zbuf_fog",
"alpha_depth",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/linear",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,

View file

@ -174,6 +174,8 @@ static void stage3_preload(void) {
"zbuf_fog",
"glitch",
"maristar_bombbg",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/accelerated",
"lasers/sine_expanding",
NULL);

View file

@ -232,6 +232,8 @@ static void stage4_preload(void) {
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"zbuf_fog",
"sprite_negative",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/accelerated",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,

View file

@ -163,6 +163,8 @@ static void stage5_preload(void) {
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"tower_light",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/linear",
"lasers/accelerated",
"lasers/iku_cathode",

View file

@ -305,6 +305,10 @@ static void stage6_preload(void) {
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"baryon_feedback",
"stage6_sky",
"tower_wall",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/accelerated",
"lasers/circle",
"lasers/elly_toe_fermion",
@ -314,8 +318,6 @@ static void stage6_preload(void) {
"lasers/linear",
"lasers/maxwell",
"lasers/sine",
"stage6_sky",
"tower_wall",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,
"boss/elly",