added a fallback system in case a graphic card don't support the texture3D size we need for the tilesets. closes #1888

This commit is contained in:
oy 2018-12-17 17:04:45 +01:00
parent 4373ab0784
commit 7ff37cb9b9
5 changed files with 89 additions and 34 deletions

View file

@ -176,7 +176,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
else if(State.m_Dimension == 3 && (m_aTextures[State.m_Texture].m_State&CTexture::STATE_TEX3D))
{
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D);
glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D[State.m_TextureArrayIndex]);
}
else
dbg_msg("render", "invalid texture %d %d %d\n", State.m_Texture, State.m_Dimension, m_aTextures[State.m_Texture].m_State);
@ -249,6 +249,13 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
{
m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_Max3DTexSize);
dbg_msg("render", "opengl max texture sizes: %d, %d(3D)", m_MaxTexSize, m_Max3DTexSize);
if(m_Max3DTexSize < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION)
dbg_msg("render", "*** warning *** max 3D texture size is too low - using the fallback system");
m_TextureArraySize = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
*pCommand->m_pTextureArraySize = m_TextureArraySize;
}
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
@ -267,7 +274,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer:
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX2D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex2D);
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX3D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D);
{
for(int i = 0; i < m_TextureArraySize; ++i)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D[i]);
}
*m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize;
m_aTextures[pCommand->m_Slot].m_State = CTexture::STATE_EMPTY;
m_aTextures[pCommand->m_Slot].m_MemSize = 0;
@ -283,16 +293,13 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
// resample if needed
if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB)
{
int MaxTexSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexSize);
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D)
int MaxTexSize = m_MaxTexSize;
if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{
int Max3DTexSize;
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Max3DTexSize);
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE2D)
MaxTexSize = min(MaxTexSize, Max3DTexSize*16);
MaxTexSize = min(MaxTexSize, m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION);
else
MaxTexSize = Max3DTexSize*16;
MaxTexSize = m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION;
}
if(Width > MaxTexSize || Height > MaxTexSize)
{
@ -307,7 +314,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
mem_free(pTexData);
pTexData = pTmpData;
}
else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
else if(Width > IGraphics::NUMTILES_DIMENSION && Height > IGraphics::NUMTILES_DIMENSION && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
{
Width>>=1;
Height>>=1;
@ -382,42 +389,45 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
}
// 3D texture
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D)
if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{
Width /= 16;
Height /= 16;
Depth = 256;
Width /= IGraphics::NUMTILES_DIMENSION;
Height /= IGraphics::NUMTILES_DIMENSION;
Depth = min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
// copy and reorder texture data
int MemSize = Width*Height*Depth*pCommand->m_PixelSize;
int MemSize = Width*Height*IGraphics::NUMTILES_DIMENSION*IGraphics::NUMTILES_DIMENSION*pCommand->m_PixelSize;
char *pTmpData = (char *)mem_alloc(MemSize, sizeof(void*));
const int TileSize = (Height * Width) * pCommand->m_PixelSize;
const int TileRowSize = Width * pCommand->m_PixelSize;
const int ImagePitch = Width*16 * pCommand->m_PixelSize;
const int ImagePitch = Width * IGraphics::NUMTILES_DIMENSION * pCommand->m_PixelSize;
mem_zero(pTmpData, MemSize);
for(int i = 0; i < 256; i++)
for(int i = 0; i < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION; i++)
{
const int px = (i%16) * Width;
const int py = (i/16) * Height;
const char *pTileData = (const char *)pTexData + (py * Width*16 + px) * pCommand->m_PixelSize;
const int px = (i%IGraphics::NUMTILES_DIMENSION) * Width;
const int py = (i/IGraphics::NUMTILES_DIMENSION) * Height;
const char *pTileData = (const char *)pTexData + (py * Width * IGraphics::NUMTILES_DIMENSION + px) * pCommand->m_PixelSize;
for(int y = 0; y < Height; y++)
mem_copy(pTmpData + i*TileSize + y*TileRowSize, pTileData + y * ImagePitch, TileRowSize);
}
mem_free(pTexData);
pTexData = pTmpData;
//
glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D);
glGenTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D);
m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D;
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D);
for(int i = 0; i < m_TextureArraySize; ++i)
{
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D[i]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
pTexData = pTmpData+i*(Width*Height*Depth*pCommand->m_PixelSize);
glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
}
pTexData = pTmpData;
}
*m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize;
@ -756,13 +766,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
// issue init commands for OpenGL and SDL
CCommandBuffer CmdBuffer(1024, 512);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdBuffer.AddCommand(CmdOpenGL);
CCommandProcessorFragment_SDL::SCommand_Init CmdSDL;
CmdSDL.m_pWindow = m_pWindow;
CmdSDL.m_GLContext = m_GLContext;
CmdBuffer.AddCommand(CmdSDL);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdOpenGL.m_pTextureArraySize = &m_TextureArraySize;
CmdBuffer.AddCommand(CmdOpenGL);
RunBuffer(&CmdBuffer);
WaitForIdle();

View file

@ -91,15 +91,21 @@ class CCommandProcessorFragment_OpenGL
STATE_EMPTY = 0,
STATE_TEX2D = 1,
STATE_TEX3D = 2,
MIN_GL_MAX_3D_TEXTURE_SIZE = 64, // GL_MAX_3D_TEXTURE_SIZE must be at least 64 according to the standard
MAX_ARRAYSIZE_TEX3D = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / MIN_GL_MAX_3D_TEXTURE_SIZE, // = 4
};
GLuint m_Tex2D;
GLuint m_Tex3D;
GLuint m_Tex3D[MAX_ARRAYSIZE_TEX3D];
int m_State;
int m_Format;
int m_MemSize;
};
CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES];
volatile int *m_pTextureMemoryUsage;
int m_MaxTexSize;
int m_Max3DTexSize;
int m_TextureArraySize;
public:
enum
@ -111,6 +117,7 @@ public:
{
SCommand_Init() : SCommand(CMD_INIT) {}
volatile int *m_pTextureMemoryUsage;
int *m_pTextureArraySize;
};
private:
@ -189,11 +196,13 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
ICommandProcessor *m_pProcessor;
volatile int m_TextureMemoryUsage;
int m_NumScreens;
int m_TextureArraySize;
public:
virtual int Init(const char *pName, int *Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight);
virtual int Shutdown();
virtual int MemoryUsage() const;
virtual int GetTextureArraySize() const { return m_TextureArraySize; }
virtual int GetNumScreens() const { return m_NumScreens; }

View file

@ -373,6 +373,9 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
//
m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result
KickCommandBuffer();
WaitForIdle();
return CreateTextureHandle(Tex);
}
@ -522,6 +525,7 @@ void CGraphics_Threaded::QuadsBegin()
QuadsSetSubset(0,0,1,1,-1);
QuadsSetRotation(0);
SetColor(1,1,1,1);
m_TextureArrayIndex = m_pBackend->GetTextureArraySize() > 1 ? -1 : 0;
}
void CGraphics_Threaded::QuadsEnd()
@ -572,17 +576,36 @@ void CGraphics_Threaded::SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft,
SetColorVertex(Array, 4);
}
void CGraphics_Threaded::TilesetFallbackSystem(int TextureIndex)
{
int NewTextureArrayIndex = TextureIndex / (256 / m_pBackend->GetTextureArraySize());
if(m_TextureArrayIndex == -1)
m_TextureArrayIndex = NewTextureArrayIndex;
else if(m_TextureArrayIndex != NewTextureArrayIndex)
{
// have to switch the texture index
FlushVertices();
m_TextureArrayIndex = NewTextureArrayIndex;
}
}
void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex)
{
dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin");
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = TlU; m_aTexture[1].u = BrU;
m_aTexture[0].v = TlV; m_aTexture[1].v = TlV;
m_aTexture[3].u = TlU; m_aTexture[2].u = BrU;
m_aTexture[3].v = BrV; m_aTexture[2].v = BrV;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
}
@ -590,12 +613,18 @@ void CGraphics_Threaded::QuadsSetSubsetFree(
float x0, float y0, float x1, float y1,
float x2, float y2, float x3, float y3, int TextureIndex)
{
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = x0; m_aTexture[0].v = y0;
m_aTexture[1].u = x1; m_aTexture[1].v = y1;
m_aTexture[2].u = x2; m_aTexture[2].v = y2;
m_aTexture[3].u = x3; m_aTexture[3].v = y3;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
}

View file

@ -143,6 +143,7 @@ public:
int m_WrapModeU;
int m_WrapModeV;
int m_Texture;
int m_TextureArrayIndex;
int m_Dimension;
SPoint m_ScreenTL;
SPoint m_ScreenBR;
@ -316,6 +317,7 @@ public:
virtual int Shutdown() = 0;
virtual int MemoryUsage() const = 0;
virtual int GetTextureArraySize() const = 0;
virtual int GetNumScreens() const = 0;
@ -372,6 +374,7 @@ class CGraphics_Threaded : public IEngineGraphics
CTextureHandle m_InvalidTexture;
int m_TextureArrayIndex;
int m_aTextureIndices[MAX_TEXTURES];
int m_FirstFreeTexture;
int m_TextureMemoryUsage;
@ -429,6 +432,7 @@ public:
virtual void SetColor(float r, float g, float b, float a);
virtual void SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, vec4 BottomRight);
void TilesetFallbackSystem(int TextureIndex);
virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex = -1);
virtual void QuadsSetSubsetFree(
float x0, float y0, float x1, float y1,

View file

@ -70,6 +70,8 @@ public:
TEXLOAD_ARRAY_256 = 4,
TEXLOAD_MULTI_DIMENSION = 8,
TEXLOAD_LINEARMIPMAPS = 16,
NUMTILES_DIMENSION = 16, // number of tiles in each dimension within a texture
};
/* Constants: Wrap Modes */