From edb11dc2230f1fdfcb571eccb19be0732f13585d Mon Sep 17 00:00:00 2001 From: Ian Curtis Date: Thu, 13 Jun 2024 13:36:30 +0100 Subject: [PATCH] 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. --- Makefiles/Rules.inc | 1 + Src/Graphics/New3D/Model.h | 10 +++- Src/Graphics/New3D/New3D.cpp | 57 ++++++++++++-------- Src/Graphics/New3D/New3D.h | 4 +- Src/Graphics/New3D/PolyHeader.cpp | 14 ++--- Src/Graphics/New3D/R3DShader.cpp | 35 +++++------- Src/Graphics/New3D/R3DShader.h | 10 ++-- Src/Graphics/New3D/R3DShaderCommon.h | 62 +++++---------------- Src/Graphics/New3D/R3DShaderQuads.h | 3 +- Src/Graphics/New3D/R3DShaderTriangles.h | 3 +- Src/Graphics/New3D/TextureBank.cpp | 71 +++++++++++++++++++++++++ Src/Graphics/New3D/TextureBank.h | 33 ++++++++++++ VS2008/Supermodel.vcxproj | 2 + VS2008/Supermodel.vcxproj.filters | 6 +++ 14 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 Src/Graphics/New3D/TextureBank.cpp create mode 100644 Src/Graphics/New3D/TextureBank.h diff --git a/Makefiles/Rules.inc b/Makefiles/Rules.inc index 0a815c1..377d814 100644 --- a/Makefiles/Rules.inc +++ b/Makefiles/Rules.inc @@ -114,6 +114,7 @@ SRC_FILES = \ Src/Graphics/New3D/R3DShader.cpp \ Src/Graphics/New3D/R3DFloat.cpp \ Src/Graphics/New3D/R3DScrollFog.cpp \ + Src/Graphics/New3D/TextureBank.cpp \ Src/Graphics/FBO.cpp \ Src/Graphics/Render2D.cpp \ Src/Graphics/SuperAA.cpp \ diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index 12ee33b..6707733 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -128,10 +128,16 @@ struct Mesh enum TexWrapMode : int { repeat = 0, repeatClamp, mirror, mirrorClamp }; // 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 wrapModeV; - bool inverted = false; // microtexture bool microTexture = false; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 7319525..6abe615 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -21,7 +21,6 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) : m_r3dShader(config), m_r3dScrollFog(config), m_gameName(gameName), - m_textureBuffer(0), m_vao(0), m_aaTarget(0) { @@ -43,16 +42,6 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) : m_r3dShader.LoadShader(); 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 glGenVertexArrays(1, &m_vao); @@ -87,11 +76,6 @@ CNew3D::~CNew3D() m_vao = 0; } - if (m_textureBuffer) { - glDeleteTextures(1, &m_textureBuffer); - m_textureBuffer = 0; - } - m_r3dShader.UnloadShader(); } @@ -102,6 +86,9 @@ void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRA m_polyRAM = polyRAMPtr; m_vrom = vromPtr; m_textureRAM = textureRAMPtr; + + m_textureBank[0].AttachMemory(textureRAMPtr); + m_textureBank[1].AttachMemory(textureRAMPtr + (2048*1024)); } 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) { - glBindTexture(GL_TEXTURE_2D, m_textureBuffer); - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + // handle case of entire sheet invalidation + if (width == 2048 && height == 2048) { - for (unsigned i = 0; i < height; i++) { - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y + i, width, 1, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_textureRAM + ((y + i) * 2048) + x); + height = 1024; + + 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() @@ -280,7 +283,10 @@ void CNew3D::DrawAmbientFog() bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer) { 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) @@ -1249,6 +1255,7 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph) currentMesh->height = ph.TexHeight(); currentMesh->microTexture = ph.MicroTexture(); currentMesh->inverted = ph.TranslatorMapOffset() == 2; + currentMesh->page = ph.Page(); { 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) { m_sunClamp = enable; diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h index 1b63273..90f4065 100644 --- a/Src/Graphics/New3D/New3D.h +++ b/Src/Graphics/New3D/New3D.h @@ -43,6 +43,7 @@ #include "PolyHeader.h" #include "R3DFrameBuffers.h" #include +#include "TextureBank.h" namespace New3D { @@ -224,6 +225,7 @@ private: void TranslateLosPosition(int inX, int inY, int& outX, int& outY); bool ProcessLos(int priority); void CalcViewport(Viewport* vp); + void TranslateTexture(unsigned& x, unsigned& y, int width, int height, int& page); /* * Data @@ -261,7 +263,6 @@ private: UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM LODBlendTable* m_LODBlendTable; - GLuint m_textureBuffer; NodeAttributes m_nodeAttribs; Mat4 m_modelMat; // current modelview matrix @@ -281,6 +282,7 @@ private: std::vector m_polyBufferRam; // dynamic polys std::vector m_polyBufferRom; // rom polys std::unordered_map>> 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; VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow diff --git a/Src/Graphics/New3D/PolyHeader.cpp b/Src/Graphics/New3D/PolyHeader.cpp index 2287932..543e9c1 100644 --- a/Src/Graphics/New3D/PolyHeader.cpp +++ b/Src/Graphics/New3D/PolyHeader.cpp @@ -296,19 +296,11 @@ int PolyHeader::X() int PolyHeader::Y() { - //======= + //==== int y; - int page; - //======= + //==== - if (Page()) { - page = 1024; - } - else { - page = 0; - } - - y = (32 * (header[5] & 0x1F) + page); // if we hit 2nd page add 1024 to y coordinate + y = 32 * (header[5] & 0x1F); // if we hit 2nd page add 1024 to y coordinate y &= 2047; return y; diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index 2c4c9e0..fe7c302 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -38,6 +38,7 @@ void R3DShader::Start() m_specularValue = 0; m_microTexScale = 0; m_microTexID = -1; + m_texturePage = -1; m_baseTexInfo[0] = -1; m_baseTexInfo[1] = -1; @@ -100,7 +101,9 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) 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_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture"); m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha"); @@ -202,7 +205,8 @@ void R3DShader::SetMeshUniforms(const Mesh* m) } if (m_dirtyMesh) { - glUniform1i(m_locTexture1, 0); + glUniform1i(m_locTextureBank[0], 0); + glUniform1i(m_locTextureBank[1], 1); } if (m_dirtyMesh || m->textured != m_textured1) { @@ -215,6 +219,11 @@ void R3DShader::SetMeshUniforms(const Mesh* m) 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) { glUniform1f(m_locMicroTexScale, m->microTextureScale); m_microTexScale = m->microTextureScale; @@ -232,10 +241,7 @@ void R3DShader::SetMeshUniforms(const Mesh* m) m_baseTexInfo[2] = m->width; m_baseTexInfo[3] = m->height; - int translatedX, translatedY; - 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); + glUniform4i(m_locBaseTexInfo, (m->x + m_transX), (m->y + m_transY), m->width, m->height); } 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 diff --git a/Src/Graphics/New3D/R3DShader.h b/Src/Graphics/New3D/R3DShader.h index 84ca182..ac849fb 100644 --- a/Src/Graphics/New3D/R3DShader.h +++ b/Src/Graphics/New3D/R3DShader.h @@ -30,8 +30,6 @@ private: void PrintShaderResult(GLuint shader); void PrintProgramResult(GLuint program); - void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY); - // run-time config const Util::Config::Node &m_config; @@ -42,9 +40,10 @@ private: GLuint m_fragmentShader; // mesh uniform locations - GLint m_locTexture1; - GLint m_locTexture1Enabled; - GLint m_locTexture2Enabled; + GLint m_locTextureBank[2]; // 2 banks + GLint m_locTexture1Enabled; // base texture + GLint m_locTexture2Enabled; // micro texture + GLint m_locTexturePage; GLint m_locTextureAlpha; GLint m_locAlphaTest; GLint m_locMicroTexScale; @@ -70,6 +69,7 @@ private: bool m_fixedShading; bool m_translatorMap; bool m_polyAlpha; + int m_texturePage; bool m_layered; bool m_noLosReturn; diff --git a/Src/Graphics/New3D/R3DShaderCommon.h b/Src/Graphics/New3D/R3DShaderCommon.h index df12c1b..929994e 100644 --- a/Src/Graphics/New3D/R3DShaderCommon.h +++ b/Src/Graphics/New3D/R3DShaderCommon.h @@ -82,36 +82,13 @@ vec4 ExtractColour(int type, uint value) 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 // wrap around is a good guess -ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate) +ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate, int level) { ivec2 newCoord; - - newCoord.x = coordinate.x & 2047; - 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 + newCoord.x = coordinate.x & (2047 >> level); + newCoord.y = coordinate.y & (1023 >> level); return newCoord; } @@ -125,19 +102,11 @@ ivec2 GetTextureSize(int level, ivec2 size) 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 page = pos.y / 1024; - pos.y -= (page * 1024); // remove page from tex y - ivec2 retPos; - retPos.x = mipXBase[level] + (pos.x / mipDivisor); - retPos.y = mipYBase[level] + (pos.y / mipDivisor); - - retPos.y += (page * 1024); // add page back to tex y + retPos.x = pos.x / mipDivisor; + retPos.y = pos.y / mipDivisor; 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 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]); - vec4 p0q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[0]) * texSize + texPos)), 0).r); - vec4 p1q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[0]) * texSize + texPos)), 0).r); - vec4 p0q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[1]) * texSize + texPos)), 0).r); - vec4 p1q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[1]) * 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),level), level).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),level), level).r); if(alphaTest) { 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 texSize1 = GetTextureSize(iLevel+1, texSize); - vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord); - vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord); + vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord, iLevel); + vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord, iLevel+1); return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels } 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) { tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb); @@ -271,11 +240,8 @@ vec4 GetTextureValue() if (microTexture) { vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale; ivec2 pos = GetMicroTexturePos(microTextureID); - - // add page offset to microtexture position - pos.y += GetNextPageOffset(baseTexInfo.y); - vec4 tex2Data = textureR3D(tex1, ivec2(0), ivec2(128), pos, fsTexCoord * scale); + vec4 tex2Data = textureR3D(textureBank[(texturePage+1)&1], ivec2(0), ivec2(128), pos, fsTexCoord * scale); float lod = mip_map_level(fsTexCoord * scale * vec2(128.0)); diff --git a/Src/Graphics/New3D/R3DShaderQuads.h b/Src/Graphics/New3D/R3DShaderQuads.h index 5a81d49..5ae1dee 100644 --- a/Src/Graphics/New3D/R3DShaderQuads.h +++ b/Src/Graphics/New3D/R3DShaderQuads.h @@ -175,7 +175,7 @@ static const char *fragmentShaderR3DQuads = R"glsl( #version 450 core -uniform usampler2D tex1; // entire texture sheet +uniform usampler2D textureBank[2]; // entire texture sheet // texturing uniform bool textureEnabled; @@ -189,6 +189,7 @@ uniform bool textureAlpha; uniform bool alphaTest; uniform bool discardAlpha; uniform ivec2 textureWrapMode; +uniform int texturePage; // general uniform vec3 fogColour; diff --git a/Src/Graphics/New3D/R3DShaderTriangles.h b/Src/Graphics/New3D/R3DShaderTriangles.h index b28ac24..f8971bd 100644 --- a/Src/Graphics/New3D/R3DShaderTriangles.h +++ b/Src/Graphics/New3D/R3DShaderTriangles.h @@ -66,7 +66,7 @@ static const char *fragmentShaderR3D = R"glsl( #version 410 core -uniform usampler2D tex1; // entire texture sheet +uniform usampler2D textureBank[2]; // entire texture sheet // texturing uniform bool textureEnabled; @@ -80,6 +80,7 @@ uniform bool textureAlpha; uniform bool alphaTest; uniform bool discardAlpha; uniform ivec2 textureWrapMode; +uniform int texturePage; // general uniform vec3 fogColour; diff --git a/Src/Graphics/New3D/TextureBank.cpp b/Src/Graphics/New3D/TextureBank.cpp new file mode 100644 index 0000000..a4f3717 --- /dev/null +++ b/Src/Graphics/New3D/TextureBank.cpp @@ -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; +} diff --git a/Src/Graphics/New3D/TextureBank.h b/Src/Graphics/New3D/TextureBank.h new file mode 100644 index 0000000..905d575 --- /dev/null +++ b/Src/Graphics/New3D/TextureBank.h @@ -0,0 +1,33 @@ +#pragma once + +#ifndef _TEXTUREBANK_H_ +#define _TEXTUREBANK_H_ + +#include "Types.h" +#include + +// 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 diff --git a/VS2008/Supermodel.vcxproj b/VS2008/Supermodel.vcxproj index e4abddc..cfff9af 100644 --- a/VS2008/Supermodel.vcxproj +++ b/VS2008/Supermodel.vcxproj @@ -324,6 +324,7 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets" + @@ -503,6 +504,7 @@ xcopy /D /Y "$(ProjectDir)..\Assets\*" "$(TargetDir)Assets" + diff --git a/VS2008/Supermodel.vcxproj.filters b/VS2008/Supermodel.vcxproj.filters index acebf72..7562eb3 100644 --- a/VS2008/Supermodel.vcxproj.filters +++ b/VS2008/Supermodel.vcxproj.filters @@ -473,6 +473,9 @@ Source Files\Graphics + + Source Files\Graphics\New + @@ -862,6 +865,9 @@ Header Files\Graphics + + Header Files\Graphics\New +