Performance improvements

The old texture code was being bottle necked by the texture reads. We mirrored the real3d texture memory directly, including the mipmaps in a single large texture. I *think* most h/w has some sort of texture cache for a 2x2 or 4x4 block of pixels for a texture. What we were doing was reading the base texture, then reading the mipmap data from a totally separate part of the same texture which I can only assume flushed this cache. What I did was to create mipmap chains for the texture sheet, then copy the mipmap data there. Doing this basically doubles performance.
This commit is contained in:
Ian Curtis 2024-06-13 13:36:30 +01:00
parent a6466b353d
commit edb11dc223
14 changed files with 198 additions and 113 deletions

View file

@ -114,6 +114,7 @@ SRC_FILES = \
Src/Graphics/New3D/R3DShader.cpp \ Src/Graphics/New3D/R3DShader.cpp \
Src/Graphics/New3D/R3DFloat.cpp \ Src/Graphics/New3D/R3DFloat.cpp \
Src/Graphics/New3D/R3DScrollFog.cpp \ Src/Graphics/New3D/R3DScrollFog.cpp \
Src/Graphics/New3D/TextureBank.cpp \
Src/Graphics/FBO.cpp \ Src/Graphics/FBO.cpp \
Src/Graphics/Render2D.cpp \ Src/Graphics/Render2D.cpp \
Src/Graphics/SuperAA.cpp \ Src/Graphics/SuperAA.cpp \

View file

@ -128,10 +128,16 @@ struct Mesh
enum TexWrapMode : int { repeat = 0, repeatClamp, mirror, mirrorClamp }; enum TexWrapMode : int { repeat = 0, repeatClamp, mirror, mirrorClamp };
// texture // texture
int format, x, y, width, height = 0; int format = 0;
int x = 0;
int y = 0;
int width = 0;
int height = 0;
int page = 0;
bool inverted = false;
TexWrapMode wrapModeU; TexWrapMode wrapModeU;
TexWrapMode wrapModeV; TexWrapMode wrapModeV;
bool inverted = false;
// microtexture // microtexture
bool microTexture = false; bool microTexture = false;

View file

@ -21,7 +21,6 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) :
m_r3dShader(config), m_r3dShader(config),
m_r3dScrollFog(config), m_r3dScrollFog(config),
m_gameName(gameName), m_gameName(gameName),
m_textureBuffer(0),
m_vao(0), m_vao(0),
m_aaTarget(0) m_aaTarget(0)
{ {
@ -43,16 +42,6 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) :
m_r3dShader.LoadShader(); m_r3dShader.LoadShader();
glUseProgram(0); glUseProgram(0);
// setup our texture memory
glGenTextures(1, &m_textureBuffer);
glBindTexture(GL_TEXTURE_2D, m_textureBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 2048, 2048, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, nullptr); // allocate storage
// setup up our vertex buffer memory // setup up our vertex buffer memory
glGenVertexArrays(1, &m_vao); glGenVertexArrays(1, &m_vao);
@ -87,11 +76,6 @@ CNew3D::~CNew3D()
m_vao = 0; m_vao = 0;
} }
if (m_textureBuffer) {
glDeleteTextures(1, &m_textureBuffer);
m_textureBuffer = 0;
}
m_r3dShader.UnloadShader(); m_r3dShader.UnloadShader();
} }
@ -102,6 +86,9 @@ void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRA
m_polyRAM = polyRAMPtr; m_polyRAM = polyRAMPtr;
m_vrom = vromPtr; m_vrom = vromPtr;
m_textureRAM = textureRAMPtr; m_textureRAM = textureRAMPtr;
m_textureBank[0].AttachMemory(textureRAMPtr);
m_textureBank[1].AttachMemory(textureRAMPtr + (2048*1024));
} }
void CNew3D::SetStepping(int stepping) void CNew3D::SetStepping(int stepping)
@ -143,12 +130,28 @@ bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yR
void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height) void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height)
{ {
glBindTexture(GL_TEXTURE_2D, m_textureBuffer); // handle case of entire sheet invalidation
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); if (width == 2048 && height == 2048) {
for (unsigned i = 0; i < height; i++) { height = 1024;
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y + i, width, 1, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_textureRAM + ((y + i) * 2048) + x);
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
for (int i = 0; i < m_textureBank[0].GetNumberOfLevels(); i++) {
m_textureBank[0].UploadTextures(i, mipXBase[i], mipYBase[i], width, height);
m_textureBank[1].UploadTextures(i, mipXBase[i], mipYBase[i], width, height);
width = (width > 1) ? width / 2 : 1;
height = (height > 1) ? height / 2 : 1;
} }
return;
}
int page;
TranslateTexture(x, y, width, height, page);
m_textureBank[page].UploadTextures(level, x, y, width, height);
} }
void CNew3D::DrawScrollFog() void CNew3D::DrawScrollFog()
@ -280,7 +283,10 @@ void CNew3D::DrawAmbientFog()
bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer) bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textureBuffer); m_textureBank[0].Bind();
glActiveTexture(GL_TEXTURE1);
m_textureBank[1].Bind();
glActiveTexture(GL_TEXTURE0);
bool hasOverlay = false; // (high priority polys) bool hasOverlay = false; // (high priority polys)
@ -1249,6 +1255,7 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
currentMesh->height = ph.TexHeight(); currentMesh->height = ph.TexHeight();
currentMesh->microTexture = ph.MicroTexture(); currentMesh->microTexture = ph.MicroTexture();
currentMesh->inverted = ph.TranslatorMapOffset() == 2; currentMesh->inverted = ph.TranslatorMapOffset() == 2;
currentMesh->page = ph.Page();
{ {
bool smoothU = ph.TexSmoothU(); bool smoothU = ph.TexSmoothU();
@ -1592,6 +1599,14 @@ void CNew3D::CalcViewport(Viewport* vp)
} }
} }
void CNew3D::TranslateTexture(unsigned& x, unsigned& y, int width, int height, int& page)
{
page = y / 1024;
// remove page from y coordinate
y -= (page * 1024);
}
void CNew3D::SetSunClamp(bool enable) void CNew3D::SetSunClamp(bool enable)
{ {
m_sunClamp = enable; m_sunClamp = enable;

View file

@ -43,6 +43,7 @@
#include "PolyHeader.h" #include "PolyHeader.h"
#include "R3DFrameBuffers.h" #include "R3DFrameBuffers.h"
#include <mutex> #include <mutex>
#include "TextureBank.h"
namespace New3D { namespace New3D {
@ -224,6 +225,7 @@ private:
void TranslateLosPosition(int inX, int inY, int& outX, int& outY); void TranslateLosPosition(int inX, int inY, int& outX, int& outY);
bool ProcessLos(int priority); bool ProcessLos(int priority);
void CalcViewport(Viewport* vp); void CalcViewport(Viewport* vp);
void TranslateTexture(unsigned& x, unsigned& y, int width, int height, int& page);
/* /*
* Data * Data
@ -261,7 +263,6 @@ private:
UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM
LODBlendTable* m_LODBlendTable; LODBlendTable* m_LODBlendTable;
GLuint m_textureBuffer;
NodeAttributes m_nodeAttribs; NodeAttributes m_nodeAttribs;
Mat4 m_modelMat; // current modelview matrix Mat4 m_modelMat; // current modelview matrix
@ -281,6 +282,7 @@ private:
std::vector<FVertex> m_polyBufferRam; // dynamic polys std::vector<FVertex> m_polyBufferRam; // dynamic polys
std::vector<FVertex> m_polyBufferRom; // rom polys std::vector<FVertex> m_polyBufferRom; // rom polys
std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
TextureBank m_textureBank[2];
GLuint m_vao; GLuint m_vao;
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow

View file

@ -296,19 +296,11 @@ int PolyHeader::X()
int PolyHeader::Y() int PolyHeader::Y()
{ {
//======= //====
int y; int y;
int page; //====
//=======
if (Page()) { y = 32 * (header[5] & 0x1F); // if we hit 2nd page add 1024 to y coordinate
page = 1024;
}
else {
page = 0;
}
y = (32 * (header[5] & 0x1F) + page); // if we hit 2nd page add 1024 to y coordinate
y &= 2047; y &= 2047;
return y; return y;

View file

@ -38,6 +38,7 @@ void R3DShader::Start()
m_specularValue = 0; m_specularValue = 0;
m_microTexScale = 0; m_microTexScale = 0;
m_microTexID = -1; m_microTexID = -1;
m_texturePage = -1;
m_baseTexInfo[0] = -1; m_baseTexInfo[0] = -1;
m_baseTexInfo[1] = -1; m_baseTexInfo[1] = -1;
@ -100,7 +101,9 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
PrintProgramResult(m_shaderProgram); PrintProgramResult(m_shaderProgram);
m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1"); m_locTextureBank[0] = glGetUniformLocation(m_shaderProgram, "textureBank[0]");
m_locTextureBank[1] = glGetUniformLocation(m_shaderProgram, "textureBank[1]");
m_locTexturePage = glGetUniformLocation(m_shaderProgram, "texturePage");
m_locTexture1Enabled = glGetUniformLocation(m_shaderProgram, "textureEnabled"); m_locTexture1Enabled = glGetUniformLocation(m_shaderProgram, "textureEnabled");
m_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture"); m_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture");
m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha"); m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha");
@ -202,7 +205,8 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
} }
if (m_dirtyMesh) { if (m_dirtyMesh) {
glUniform1i(m_locTexture1, 0); glUniform1i(m_locTextureBank[0], 0);
glUniform1i(m_locTextureBank[1], 1);
} }
if (m_dirtyMesh || m->textured != m_textured1) { if (m_dirtyMesh || m->textured != m_textured1) {
@ -215,6 +219,11 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
m_textured2 = m->microTexture; m_textured2 = m->microTexture;
} }
if (m_dirtyMesh || (m->page ^ m_transPage) != m_texturePage) {
glUniform1i(m_locTexturePage, m->page ^ m_transPage);
m_texturePage = (m->page ^ m_transPage);
}
if (m_dirtyMesh || m->microTextureScale != m_microTexScale) { if (m_dirtyMesh || m->microTextureScale != m_microTexScale) {
glUniform1f(m_locMicroTexScale, m->microTextureScale); glUniform1f(m_locMicroTexScale, m->microTextureScale);
m_microTexScale = m->microTextureScale; m_microTexScale = m->microTextureScale;
@ -232,10 +241,7 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
m_baseTexInfo[2] = m->width; m_baseTexInfo[2] = m->width;
m_baseTexInfo[3] = m->height; m_baseTexInfo[3] = m->height;
int translatedX, translatedY; glUniform4i(m_locBaseTexInfo, (m->x + m_transX), (m->y + m_transY), m->width, m->height);
CalcTexOffset(m_transX, m_transY, m_transPage, m->x, m->y, translatedX, translatedY); // need to apply model translation
glUniform4i(m_locBaseTexInfo, translatedX, translatedY, m->width, m->height);
} }
if (m_dirtyMesh || m_baseTexType != m->format) { if (m_dirtyMesh || m_baseTexType != m->format) {
@ -426,21 +432,4 @@ void R3DShader::PrintProgramResult(GLuint program)
} }
} }
void R3DShader::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
{
newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required
int oldPage = y / 1024;
y -= (oldPage * 1024); // remove page from tex y
// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
newY = (y + offY) & 1023;
// add page to Y
newY += ((oldPage + page) & 1) * 1024; // max page 0-1
}
} // New3D } // New3D

View file

@ -30,8 +30,6 @@ private:
void PrintShaderResult(GLuint shader); void PrintShaderResult(GLuint shader);
void PrintProgramResult(GLuint program); void PrintProgramResult(GLuint program);
void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);
// run-time config // run-time config
const Util::Config::Node &m_config; const Util::Config::Node &m_config;
@ -42,9 +40,10 @@ private:
GLuint m_fragmentShader; GLuint m_fragmentShader;
// mesh uniform locations // mesh uniform locations
GLint m_locTexture1; GLint m_locTextureBank[2]; // 2 banks
GLint m_locTexture1Enabled; GLint m_locTexture1Enabled; // base texture
GLint m_locTexture2Enabled; GLint m_locTexture2Enabled; // micro texture
GLint m_locTexturePage;
GLint m_locTextureAlpha; GLint m_locTextureAlpha;
GLint m_locAlphaTest; GLint m_locAlphaTest;
GLint m_locMicroTexScale; GLint m_locMicroTexScale;
@ -70,6 +69,7 @@ private:
bool m_fixedShading; bool m_fixedShading;
bool m_translatorMap; bool m_translatorMap;
bool m_polyAlpha; bool m_polyAlpha;
int m_texturePage;
bool m_layered; bool m_layered;
bool m_noLosReturn; bool m_noLosReturn;

View file

@ -82,36 +82,13 @@ vec4 ExtractColour(int type, uint value)
return c; return c;
} }
int GetPage(int yCoord)
{
return yCoord / 1024;
}
int GetNextPage(int yCoord)
{
return (GetPage(yCoord) + 1) & 1;
}
int GetNextPageOffset(int yCoord)
{
return GetNextPage(yCoord) * 1024;
}
// wrapping tex coords would be super easy but we combined tex sheets so have to handle wrap around between sheets
// hardware testing would be useful because i don't know exactly what happens if you try to read outside the texture sheet // hardware testing would be useful because i don't know exactly what happens if you try to read outside the texture sheet
// wrap around is a good guess // wrap around is a good guess
ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate) ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate, int level)
{ {
ivec2 newCoord; ivec2 newCoord;
newCoord.x = coordinate.x & (2047 >> level);
newCoord.x = coordinate.x & 2047; newCoord.y = coordinate.y & (1023 >> level);
newCoord.y = coordinate.y;
int page = GetPage(pos.y);
newCoord.y -= (page * 1024); // remove page
newCoord.y &= 1023; // wrap around in the same sheet
newCoord.y += (page * 1024); // add page back
return newCoord; return newCoord;
} }
@ -125,19 +102,11 @@ ivec2 GetTextureSize(int level, ivec2 size)
ivec2 GetTexturePosition(int level, ivec2 pos) ivec2 GetTexturePosition(int level, ivec2 pos)
{ {
const int mipXBase[] = int[](0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047);
const int mipYBase[] = int[](0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023);
int mipDivisor = 1 << level; int mipDivisor = 1 << level;
int page = pos.y / 1024;
pos.y -= (page * 1024); // remove page from tex y
ivec2 retPos; ivec2 retPos;
retPos.x = mipXBase[level] + (pos.x / mipDivisor); retPos.x = pos.x / mipDivisor;
retPos.y = mipYBase[level] + (pos.y / mipDivisor); retPos.y = pos.y / mipDivisor;
retPos.y += (page * 1024); // add page back to tex y
return retPos; return retPos;
} }
@ -206,16 +175,16 @@ float LinearTexLocations(int wrapMode, float size, float u, out float u0, out fl
} }
} }
vec4 texBiLinear(usampler2D texSampler, ivec2 wrapMode, vec2 texSize, ivec2 texPos, vec2 texCoord) vec4 texBiLinear(usampler2D texSampler, ivec2 wrapMode, vec2 texSize, ivec2 texPos, vec2 texCoord, int level)
{ {
float tx[2], ty[2]; float tx[2], ty[2];
float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]); float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]);
float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]); float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]);
vec4 p0q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[0]) * texSize + texPos)), 0).r); vec4 p0q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[0]) * texSize + texPos),level), level).r);
vec4 p1q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[0]) * texSize + texPos)), 0).r); vec4 p1q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[0]) * texSize + texPos),level), level).r);
vec4 p0q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[1]) * texSize + texPos)), 0).r); vec4 p0q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[1]) * texSize + texPos),level), level).r);
vec4 p1q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[1]) * texSize + texPos)), 0).r); vec4 p1q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[1]) * texSize + texPos),level), level).r);
if(alphaTest) { if(alphaTest) {
if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; } if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; }
@ -254,15 +223,15 @@ vec4 textureR3D(usampler2D texSampler, ivec2 wrapMode, ivec2 texSize, ivec2 texP
ivec2 texSize0 = GetTextureSize(iLevel, texSize); ivec2 texSize0 = GetTextureSize(iLevel, texSize);
ivec2 texSize1 = GetTextureSize(iLevel+1, texSize); ivec2 texSize1 = GetTextureSize(iLevel+1, texSize);
vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord); vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord, iLevel);
vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord); vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord, iLevel+1);
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
} }
vec4 GetTextureValue() vec4 GetTextureValue()
{ {
vec4 tex1Data = textureR3D(tex1, textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord); vec4 tex1Data = textureR3D(textureBank[texturePage], textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord);
if(textureInverted) { if(textureInverted) {
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb); tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
@ -272,10 +241,7 @@ vec4 GetTextureValue()
vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale; vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale;
ivec2 pos = GetMicroTexturePos(microTextureID); ivec2 pos = GetMicroTexturePos(microTextureID);
// add page offset to microtexture position vec4 tex2Data = textureR3D(textureBank[(texturePage+1)&1], ivec2(0), ivec2(128), pos, fsTexCoord * scale);
pos.y += GetNextPageOffset(baseTexInfo.y);
vec4 tex2Data = textureR3D(tex1, ivec2(0), ivec2(128), pos, fsTexCoord * scale);
float lod = mip_map_level(fsTexCoord * scale * vec2(128.0)); float lod = mip_map_level(fsTexCoord * scale * vec2(128.0));

View file

@ -175,7 +175,7 @@ static const char *fragmentShaderR3DQuads = R"glsl(
#version 450 core #version 450 core
uniform usampler2D tex1; // entire texture sheet uniform usampler2D textureBank[2]; // entire texture sheet
// texturing // texturing
uniform bool textureEnabled; uniform bool textureEnabled;
@ -189,6 +189,7 @@ uniform bool textureAlpha;
uniform bool alphaTest; uniform bool alphaTest;
uniform bool discardAlpha; uniform bool discardAlpha;
uniform ivec2 textureWrapMode; uniform ivec2 textureWrapMode;
uniform int texturePage;
// general // general
uniform vec3 fogColour; uniform vec3 fogColour;

View file

@ -66,7 +66,7 @@ static const char *fragmentShaderR3D = R"glsl(
#version 410 core #version 410 core
uniform usampler2D tex1; // entire texture sheet uniform usampler2D textureBank[2]; // entire texture sheet
// texturing // texturing
uniform bool textureEnabled; uniform bool textureEnabled;
@ -80,6 +80,7 @@ uniform bool textureAlpha;
uniform bool alphaTest; uniform bool alphaTest;
uniform bool discardAlpha; uniform bool discardAlpha;
uniform ivec2 textureWrapMode; uniform ivec2 textureWrapMode;
uniform int texturePage;
// general // general
uniform vec3 fogColour; uniform vec3 fogColour;

View file

@ -0,0 +1,71 @@
#include "TextureBank.h"
New3D::TextureBank::TextureBank()
{
glGenTextures(1, &m_texID);
glBindTexture(GL_TEXTURE_2D, m_texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
int width = 2048;
int height = 1024;
int level = 0;
while (width>=1 && height>=1) {
glTexImage2D(GL_TEXTURE_2D, level, GL_R16UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, nullptr); // allocate storage
width = (width > 1) ? width / 2 : 1;
height = (height > 1) ? height / 2 : 1;
level++;
if (width == 1 && height == 1) {
glTexImage2D(GL_TEXTURE_2D, level, GL_R16UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, nullptr); // allocate storage
break;
}
}
m_numLevels = level;
}
New3D::TextureBank::~TextureBank()
{
if (m_texID) {
glDeleteTextures(1, &m_texID);
m_texID = 0;
}
}
void New3D::TextureBank::AttachMemory(const UINT16* textureRam)
{
m_textureRam = textureRam;
}
void New3D::TextureBank::Bind()
{
glBindTexture(GL_TEXTURE_2D, m_texID);
}
void New3D::TextureBank::UploadTextures(int level, int x, int y, int width, int height)
{
glBindTexture(GL_TEXTURE_2D, m_texID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
int subX = x - mipXBase[level];
int subY = y - mipYBase[level];
for (unsigned i = 0; i < height; i++) {
glTexSubImage2D(GL_TEXTURE_2D, level, subX, subY + i, width, 1, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_textureRam + ((y + i) * 2048) + x);
}
}
int New3D::TextureBank::GetNumberOfLevels()
{
return m_numLevels;
}

View file

@ -0,0 +1,33 @@
#pragma once
#ifndef _TEXTUREBANK_H_
#define _TEXTUREBANK_H_
#include "Types.h"
#include <GL/glew.h>
// texture banks are a fixed size
// 2048x1024 pixels, each pixel is 16bits in size
namespace New3D {
class TextureBank
{
public:
TextureBank();
~TextureBank();
void AttachMemory(const UINT16* textureRam);
void Bind();
void UploadTextures(int level, int x, int y, int width, int height);
int GetNumberOfLevels();
private:
GLuint m_texID = 0;
const UINT16* m_textureRam = nullptr;
int m_numLevels = 0;
};
}
#endif

View file

@ -324,6 +324,7 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets"</Command>
<ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DScrollFog.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DScrollFog.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\TextureBank.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\VBO.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\VBO.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Vec.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\Vec.cpp" />
<ClCompile Include="..\Src\Graphics\Render2D.cpp" /> <ClCompile Include="..\Src\Graphics\Render2D.cpp" />
@ -503,6 +504,7 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets"</Command>
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderCommon.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderCommon.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h" />
<ClInclude Include="..\Src\Graphics\New3D\TextureBank.h" />
<ClInclude Include="..\Src\Graphics\New3D\VBO.h" /> <ClInclude Include="..\Src\Graphics\New3D\VBO.h" />
<ClInclude Include="..\Src\Graphics\New3D\Vec.h" /> <ClInclude Include="..\Src\Graphics\New3D\Vec.h" />
<ClInclude Include="..\Src\Graphics\Render2D.h" /> <ClInclude Include="..\Src\Graphics\Render2D.h" />

View file

@ -473,6 +473,9 @@
<ClCompile Include="..\Src\Graphics\SuperAA.cpp"> <ClCompile Include="..\Src\Graphics\SuperAA.cpp">
<Filter>Source Files\Graphics</Filter> <Filter>Source Files\Graphics</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\TextureBank.cpp">
<Filter>Source Files\Graphics\New</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MASM Include="..\Src\CPU\68K\Turbo68K\Turbo68K.asm"> <MASM Include="..\Src\CPU\68K\Turbo68K\Turbo68K.asm">
@ -862,6 +865,9 @@
<ClInclude Include="..\Src\Graphics\SuperAA.h"> <ClInclude Include="..\Src\Graphics\SuperAA.h">
<Filter>Header Files\Graphics</Filter> <Filter>Header Files\Graphics</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\TextureBank.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\Src\Debugger\ReadMe.txt"> <CustomBuild Include="..\Src\Debugger\ReadMe.txt">