From e357336da956ec1379eda0c365cb1028144e78df Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Sat, 23 Nov 2024 10:37:57 +0300 Subject: [PATCH] Add environment variable to select accuracy vs speed We might have more cases in the future, where we can choose between an accurate software implemenation and a faster but non-standard GPU implementation. Let's create a mechanism through which the client can select the features which can be sped up at the cost of correct rendering. This is currently exposed as an environment variable, and not as an API, because if it turns out to be a bad idea we can remove it without breaking the public API. --- src/gc_gl.c | 17 +++++++++++++++++ src/state.h | 8 ++++++++ src/texture_gen_sw.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/gc_gl.c b/src/gc_gl.c index d339fff..4413c40 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -195,11 +195,28 @@ int ogx_prepare_swap_buffers() return glparamstate.render_mode == GL_RENDER ? 0 : -1; } +static int parse_hints() +{ + OgxHints hints = OGX_HINT_NONE; + + /* comma separated list of operations for which a faster (but inaccurate) + * implementation is to be preferred over a more standard-compliant one. + * By default, we always prefer standard-compliance over speed. */ + const char *env = getenv("OPENGX_FAST_OPS"); + if (env) { + if (strstr(env, "sphere_map") != NULL) + hints |= OGX_HINT_FAST_SPHERE_MAP; + } + + glparamstate.hints = hints; +} + void ogx_initialize() { _ogx_log_init(); _ogx_gpu_resources_init(); + parse_hints(); glparamstate.current_call_list.index = -1; GX_SetDispCopyGamma(GX_GM_1_0); diff --git a/src/state.h b/src/state.h index 0b7f70b..180533b 100644 --- a/src/state.h +++ b/src/state.h @@ -63,6 +63,12 @@ extern "C" { * opengx when stencil is enabled. */ #define MAX_TEXTURE_UNITS 4 +typedef enum { + OGX_HINT_NONE = 0, + /* Enables fast (but wrong) GPU-accelerated GL_SPHERE_MAP */ + OGX_HINT_FAST_SPHERE_MAP = 1 << 0, +} OgxHints; + typedef struct { Pos3f pos; Norm3f norm; @@ -131,6 +137,8 @@ typedef struct glparams_ int viewport[4]; + OgxHints hints; + unsigned char srcblend, dstblend; unsigned char blendenabled; unsigned char zwrite, ztest, zfunc; diff --git a/src/texture_gen_sw.c b/src/texture_gen_sw.c index ee0846b..609f115 100644 --- a/src/texture_gen_sw.c +++ b/src/texture_gen_sw.c @@ -37,11 +37,35 @@ POSSIBILITY OF SUCH DAMAGE. bool _ogx_texture_gen_sw_enabled(uint8_t unit) { const OgxTextureUnit *tu = &glparamstate.texture_unit[unit]; + OgxHints hint = OGX_HINT_NONE; + bool needs_normals = false; - if (tu->gen_mode != GL_SPHERE_MAP) return false; + switch (tu->gen_mode) { + case GL_SPHERE_MAP: + hint = OGX_HINT_FAST_SPHERE_MAP; + needs_normals = true; + break; + case GL_REFLECTION_MAP: + /* We don't support a standard-compiant generation of the reflection + * map yet, because its output should consist of three float + * components, whereas the TEV only supports two components for + * GX_VA_TEX*. One way to implement it would be to (ab)use the + * GX_VA_NBT format: storing the computed texture generated coordinates + * into the binormal part of the array, and then use them in the TEV as + * GX_TG_BINRM. + * But this requires yet one more refactoring of the array classes, to + * let the normals array switch between GX_VA_NRM and GX_VA_NBT + * depending on whether GL_REFLECTION_MAP is enabled. Let's leave this + * as a TODO. + */ + default: + return false; + } - /* We need normal coordinates to be there */ - if (!glparamstate.cs.normal_enabled) return false; + /* If the client prefers the inaccurate GPU implementation, let it be */ + if (hint != OGX_HINT_NONE && (glparamstate.hints & hint)) return false; + + if (needs_normals && !glparamstate.cs.normal_enabled) return false; return true; }