1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-02 09:03:37 +00:00

Rewrite mip-maps load:

* load all but the first mip-map tiles as 1D texture atlas, that is array of texels.
  all tiles loaded as rgba32.
  first 8 texels contain information about tile's width, height and offset, 1 texel per tile.
* mipmap shader corrected to fetch texels from the atlas.

All hacks, which were necessary to load N64 mip-maps into OpenGL texture are removed.
This commit is contained in:
Sergey Lipskiy 2021-08-22 00:00:51 +07:00
parent 576c82185b
commit 539e3b0ad4
4 changed files with 156 additions and 99 deletions

View File

@ -2122,32 +2122,75 @@ public:
else {
if (config.texture.bilinearMode == BILINEAR_3POINT)
m_part =
"#define READ_TEX_MIPMAP(name, tex, tcData, lod) \\\n"
"{ \\\n"
" lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n"
" lowp vec2 lod_scale = vec2(textureSize(tex,int(lod))) / vec2(textureSize(tex,0)); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]*lod_scale), int(lod)); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]*lod_scale), int(lod)); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]*lod_scale), int(lod)); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]*lod_scale), int(lod)); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n"
" lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n"
" name = c0 + bottomRightTri * (c1-c0); \\\n"
"} \n"
"#define READ_TEX0_MIPMAP(name, tex, tcData, lod) \\\n"
"{ \\\n"
" lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n"
" lowp vec2 lod_scale = vec2(textureSize(tex,int(lod))) / vec2(textureSize(tex,0)); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]*lod_scale), int(lod)); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]*lod_scale), int(lod)); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]*lod_scale), int(lod)); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]*lod_scale), int(lod)); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n"
" lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n"
" name = c0 + bottomRightTri * (c1-c0); \\\n"
"} \n"
"#define READ_TEX1_MIPMAP(name, tex, tcData, tile) \\\n"
"{ \\\n"
// Fetch from texture atlas
// First 8 texels contain info about tile size and offset, 1 texel per tile
" mediump vec4 texWdthAndOff0 = 255.0 * texelFetch(tex, ivec2(0, 0), 0); \\\n"
" mediump vec4 texWdthAndOff = 255.0 * texelFetch(tex, ivec2(int(tile), 0), 0); \\\n"
" mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \\\n"
" mediump int offset = int(texWdthAndOff.r) + int(texWdthAndOff.g) * 256; \\\n"
" mediump int width = int(texWdthAndOff.b); \\\n"
" mediump ivec2 iCoords00 = ivec2(tcData[0] * lod_scale); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(offset + width * iCoords00.t + iCoords00.s, 0), 0); \\\n"
" mediump ivec2 iCoords01 = ivec2(tcData[1] * lod_scale); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(offset + width * iCoords01.t + iCoords01.s, 0), 0); \\\n"
" mediump ivec2 iCoords10 = ivec2(tcData[2] * lod_scale); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(offset + width * iCoords10.t + iCoords10.s, 0), 0); \\\n"
" mediump ivec2 iCoords11 = ivec2(tcData[3] * lod_scale); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(offset + width * iCoords11.t + iCoords11.s, 0), 0); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n"
" lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n"
" lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n"
" name = c0 + bottomRightTri * (c1-c0); \\\n"
"} \n"
;
else
m_part =
"#define READ_TEX_MIPMAP(name, tex, tcData, lod) \\\n"
"{ \\\n"
" lowp vec2 lod_scale = vec2(textureSize(tex,int(lod))) / vec2(textureSize(tex,0)); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]*lod_scale), int(lod)); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]*lod_scale), int(lod)); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]*lod_scale), int(lod)); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]*lod_scale), int(lod)); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n"
" lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n"
" name = c0 + tcData[4].t * (c1-c0); \\\n"
"} \n"
"#define READ_TEX0_MIPMAP(name, tex, tcData, lod) \\\n"
"{ \\\n"
" lowp vec2 lod_scale = vec2(textureSize(tex,int(lod))) / vec2(textureSize(tex,0)); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]*lod_scale), int(lod)); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]*lod_scale), int(lod)); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]*lod_scale), int(lod)); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]*lod_scale), int(lod)); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n"
" lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n"
" name = c0 + tcData[4].t * (c1-c0); \\\n"
"} \n"
"#define READ_TEX1_MIPMAP(name, tex, tcData, tile) \\\n"
"{ \\\n"
// Fetch from texture atlas
// First 8 texels contain info about tile size and offset, 1 texel per tile
" mediump vec4 texWdthAndOff0 = 255.0 * texelFetch(tex, ivec2(0, 0), 0); \\\n"
" mediump vec4 texWdthAndOff = 255.0 * texelFetch(tex, ivec2(int(tile), 0), 0); \\\n"
" mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \\\n"
" mediump int offset = int(texWdthAndOff.r) + int(texWdthAndOff.g) * 256; \\\n"
" mediump int width = int(texWdthAndOff.b); \\\n"
" mediump ivec2 iCoords00 = ivec2(tcData[0] * lod_scale); \\\n"
" lowp vec4 c00 = texelFetch(tex, ivec2(offset + width * iCoords00.t + iCoords00.s, 0), 0); \\\n"
" mediump ivec2 iCoords01 = ivec2(tcData[1] * lod_scale); \\\n"
" lowp vec4 c01 = texelFetch(tex, ivec2(offset + width * iCoords01.t + iCoords01.s, 0), 0); \\\n"
" mediump ivec2 iCoords10 = ivec2(tcData[2] * lod_scale); \\\n"
" lowp vec4 c10 = texelFetch(tex, ivec2(offset + width * iCoords10.t + iCoords10.s, 0), 0); \\\n"
" mediump ivec2 iCoords11 = ivec2(tcData[3] * lod_scale); \\\n"
" lowp vec4 c11 = texelFetch(tex, ivec2(offset + width * iCoords11.t + iCoords11.s, 0), 0); \\\n"
" lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n"
" lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n"
" name = c0 + tcData[4].t * (c1-c0); \\\n"
"} \n"
;
if (config.generalEmulation.enableLOD == 0) {
// Fake mipmap
@ -2156,8 +2199,8 @@ public:
"uniform mediump float uMinLod; \n"
" \n"
"mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n"
" READ_TEX_MIPMAP(readtex0, uTex0, tcData0, 0); \n"
" READ_TEX_MIPMAP(readtex1, uTex1, tcData1, 0); \n"
" READ_TEX_MIPMAP0(readtex0, uTex0, tcData0, 0); \n"
" READ_TEX_MIPMAP0(readtex1, uTex1, tcData1, 0); \n"
" if (uMaxTile == 0) return 1.0; \n"
" return uMinLod; \n"
"} \n"
@ -2170,13 +2213,14 @@ public:
"uniform lowp int uTextureDetail; \n"
" \n"
"mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n"
" READ_TEX_MIPMAP(readtex0, uTex0, tcData0, 0); \n"
" READ_TEX_MIPMAP(readtex1, uTex1, tcData1, 0); \n"
" READ_TEX0_MIPMAP(readtex0, uTex0, tcData0, 0) \n"
" if (uMaxTile > 1) READ_TEX1_MIPMAP(readtex1, uTex1, tcData1, 0) \n"
" else READ_TEX0_MIPMAP(readtex1, uTex1, tcData1, 0) \n"
" \n"
" mediump float fMaxTile = float(uMaxTile); \n"
" mediump vec2 dx = abs(dFdx(vLodTexCoord)); \n"
" dx *= uScreenScale; \n"
" mediump float lod = max(dx.x, dx.y); \n"
" mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n"
" mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n"
" mediump float lod = max(max(dx.x, dx.y), max(dy.x, dy.y)); \n"
" bool magnify = lod < 1.0; \n"
" mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n"
" bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n"
@ -2201,9 +2245,9 @@ public:
" lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n"
" lowp float lod_tile_p1 = min(fMaxTile - 1.0, lod_tile + 1.0); \n"
" lowp vec4 lodT, lodT_m1, lodT_p1; \n"
" READ_TEX_MIPMAP(lodT, uTex1, tcData1, lod_tile); \n"
" READ_TEX_MIPMAP(lodT_m1, uTex1, tcData1, lod_tile_m1); \n"
" READ_TEX_MIPMAP(lodT_p1, uTex1, tcData1, lod_tile_p1); \n"
" READ_TEX1_MIPMAP(lodT, uTex1, tcData1, lod_tile); \n"
" READ_TEX1_MIPMAP(lodT_m1, uTex1, tcData1, lod_tile_m1); \n"
" READ_TEX1_MIPMAP(lodT_p1, uTex1, tcData1, lod_tile_p1); \n"
" if (lod_tile < 1.0) { \n"
" if (magnify) { \n"
// !sharpen && !detail

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include <cmath>
#include <Config.h>
#include "glsl_CombinerProgramUniformFactory.h"
@ -15,6 +16,10 @@
#include <gDP.h>
#include <VI.h>
#ifdef min
#undef min
#endif
namespace glsl {
/*---------------Uniform-------------*/
@ -588,7 +593,11 @@ public:
void update(bool _force) override
{
uMinLod.set(gDP.primColor.m, _force);
uMaxTile.set(gSP.texture.level, _force);
const CachedTexture * _pTexture = textureCache().current[1];
if (_pTexture == nullptr)
uMaxTile.set(gSP.texture.level, _force);
else
uMaxTile.set(_pTexture->max_level > 0 ? gSP.texture.level : std::min(gSP.texture.level, 1u), _force);
}
private:

View File

@ -20,7 +20,7 @@ namespace glsl {
bool _saveCombinerKeys(const graphics::Combiners & _combiners) const;
bool _loadFromCombinerKeys(graphics::Combiners & _combiners);
const u32 m_formatVersion = 0x36U;
const u32 m_formatVersion = 0x37U;
const u32 m_keysFormatVersion = 0x05;
const opengl::GLInfo & m_glinfo;
opengl::CachedUseProgram * m_useProgram;

View File

@ -1106,27 +1106,14 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
if (_loadHiresTexture(_tile, _pTexture, ricecrc))
return;
s32 mipLevel = 0;
bool force32bitFormat = false;
_pTexture->max_level = 0;
if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1) {
if (_tile == 0) {
_pTexture->max_level = 0;
} else {
_pTexture->max_level = static_cast<u8>(gSP.texture.level - 1);
const u16 dim = std::max(_pTexture->width, _pTexture->height);
while (dim < static_cast<u16>(1 << _pTexture->max_level))
--_pTexture->max_level;
auto texFormat = gDP.tiles[gSP.texture.tile + 1].format;
auto texSize = gDP.tiles[gSP.texture.tile + 1].size;
u32 tileMipLevel = gSP.texture.tile + 2;
while (!force32bitFormat && (tileMipLevel < gSP.texture.tile + gSP.texture.level)) {
gDPTile const& mipTile = gDP.tiles[tileMipLevel++];
force32bitFormat = texFormat != mipTile.format || texSize != mipTile.size;
}
}
if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1 && _tile > 0) {
_pTexture->max_level = gDP.otherMode.textureDetail == G_TD_DETAIL ?
static_cast<u8>(gSP.texture.level) :
static_cast<u8>(gSP.texture.level - 1);
force32bitFormat = _pTexture->max_level > 0;
}
u32 sizeShift = 1;
@ -1158,7 +1145,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
}
private:
u32 *pData = NULL;
} texData(_pTexture->textureBytes);
} texData((_pTexture->textureBytes + 8*sizeof(u32)) * (_pTexture->max_level + 1));
GetTexelFunc GetTexel;
InternalColorFormatParam glInternalFormat;
@ -1183,32 +1170,71 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
CachedTexture tmptex = *_pTexture;
u16 line = tmptex.line;
while (true) {
getLoadParams(tmptex.format, tmptex.size);
if (_pTexture->max_level > 0)
{
u32 mipLevel = 0;
u32 texDataOffset = 8; // number of gDP.tiles
// Load all tiles into one 1D texture atlas.
while (true)
{
const u32 tileSizePacked = texDataOffset | (tmptex.width << 16) | (tmptex.height << 24);
texData.get()[mipLevel] = tileSizePacked;
getLoadParams(tmptex.format, tmptex.size);
_getTextureDestData(tmptex, texData.get() + texDataOffset, glInternalFormat, GetTexel, &line);
if (m_toggleDumpTex &&
config.textureFilter.txHiresEnable != 0 &&
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
txfilter_dmptx((u8*)texData.get() + texDataOffset, tmptex.width, tmptex.height,
tmptex.width, (u16)u32(glInternalFormat),
(unsigned short)(_pTexture->format << 8 | _pTexture->size),
ricecrc);
}
texDataOffset += tmptex.width * tmptex.height;
if (mipLevel == _pTexture->max_level)
break;
++mipLevel;
const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;
gDPTile & mipTile = gDP.tiles[tileMipLevel];
if (tmptex.max_level > 1 &&
tmptex.width == (mipTile.lrs - mipTile.uls + 1) * 2 &&
tmptex.height == (mipTile.lrt - mipTile.ult + 1) * 2)
{
// Special case for Southern Swamp grass texture, Zelda MM. See #2315
const u16 texWidth = tmptex.width;
const u16 texHeight = tmptex.height;
tmptex.width = mipTile.lrs - mipTile.uls + 1;
tmptex.height = mipTile.lrt - mipTile.ult + 1;
_getTextureDestData(tmptex, texData.get(), glInternalFormat, GetTexel, &line);
if (sizeShift == 2)
doubleTexture<u32>(texData.get(), tmptex.width, tmptex.height);
else
doubleTexture<u16>((u16*)texData.get(), tmptex.width, tmptex.height);
tmptex.width = texWidth;
tmptex.height = texHeight;
} else {
_getTextureDestData(tmptex, texData.get(), glInternalFormat, GetTexel, &line);
}
gDPTile & prevMipTile = gDP.tiles[tileMipLevel - 1];
line = mipTile.line;
tmptex.tMem = mipTile.tmem;
tmptex.palette = mipTile.palette;
tmptex.maskS = mipTile.masks;
tmptex.maskT = mipTile.maskt;
tmptex.format = mipTile.format;
tmptex.size = mipTile.size;
TileSizes sizes;
_calcTileSizes(tileMipLevel, sizes, nullptr);
tmptex.width = sizes.width;
tmptex.height = sizes.height;
tmptex.clampWidth = sizes.clampWidth;
tmptex.clampHeight = sizes.clampHeight;
_pTexture->textureBytes += (tmptex.width * tmptex.height) << sizeShift;
}
Context::InitTextureParams params;
params.handle = _pTexture->name;
params.textureUnitIndex = textureIndices::Tex[_tile];
params.mipMapLevel = 0;
params.mipMapLevels =1;
params.msaaLevel = 0;
params.width = texDataOffset;
params.height = 1;
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat));
params.format = colorFormat::RGBA;
params.dataType = glType;
params.data = texData.get();
gfxContext.init2DTexture(params);
}
else
{
getLoadParams(tmptex.format, tmptex.size);
_getTextureDestData(tmptex, texData.get(), glInternalFormat, GetTexel, &line);
if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) {
_loadDepthTexture(_pTexture, (u16*)texData.get());
return;
@ -1276,8 +1302,8 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
Context::InitTextureParams params;
params.handle = _pTexture->name;
params.textureUnitIndex = textureIndices::Tex[_tile];
params.mipMapLevel = mipLevel;
params.mipMapLevels = _pTexture->max_level + 1;
params.mipMapLevel = 0;
params.mipMapLevels = 1;
params.msaaLevel = 0;
params.width = tmptex.width;
params.height = tmptex.height;
@ -1287,28 +1313,6 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
params.data = texData.get();
gfxContext.init2DTexture(params);
}
if (mipLevel == _pTexture->max_level)
break;
++mipLevel;
const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;
gDPTile & mipTile = gDP.tiles[tileMipLevel];
line = mipTile.line;
tmptex.tMem = mipTile.tmem;
tmptex.palette = mipTile.palette;
tmptex.maskS = mipTile.masks;
tmptex.maskT = mipTile.maskt;
tmptex.format = mipTile.format;
tmptex.size = mipTile.size;
TileSizes sizes;
_calcTileSizes(tileMipLevel, sizes, nullptr);
tmptex.clampWidth = sizes.clampWidth;
tmptex.clampHeight = sizes.clampHeight;
// Insure mip-map levels size consistency.
if (tmptex.width > 1)
tmptex.width >>= 1;
if (tmptex.height > 1)
tmptex.height >>= 1;
_pTexture->textureBytes += (tmptex.width * tmptex.height) << sizeShift;
}
if (m_curUnpackAlignment > 1)
gfxContext.setTextureUnpackAlignment(m_curUnpackAlignment);