performance improvements
* no more freezes because of file IO from hard disk, now we cache sound/spr file buffers * more opengl painter tweaks
This commit is contained in:
parent
ee664657fb
commit
9aa12acc22
|
@ -28,6 +28,7 @@ FileStream::FileStream(const std::string& name, PHYSFS_File *fileHandle)
|
|||
{
|
||||
m_name = name;
|
||||
m_fileHandle = fileHandle;
|
||||
m_cacheReadPos = 0;
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
|
@ -35,6 +36,24 @@ FileStream::~FileStream()
|
|||
close();
|
||||
}
|
||||
|
||||
void FileStream::cache()
|
||||
{
|
||||
if(!m_fileHandle)
|
||||
logTraceError("no file handle to cache");
|
||||
|
||||
// cache entire file into cache buffer
|
||||
m_cacheReadPos = PHYSFS_tell(m_fileHandle);
|
||||
PHYSFS_seek(m_fileHandle, 0);
|
||||
int size = PHYSFS_fileLength(m_fileHandle);
|
||||
m_cacheBuffer.resize(size);
|
||||
int res = PHYSFS_read(m_fileHandle, &m_cacheBuffer[0], size, 1);
|
||||
if(res == -1)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
|
||||
PHYSFS_close(m_fileHandle);
|
||||
m_fileHandle = nullptr;
|
||||
}
|
||||
|
||||
bool FileStream::close()
|
||||
{
|
||||
if(m_fileHandle) {
|
||||
|
@ -43,12 +62,18 @@ bool FileStream::close()
|
|||
|
||||
m_fileHandle = nullptr;
|
||||
return true;
|
||||
} else {
|
||||
m_cacheBuffer.clear();
|
||||
m_cacheReadPos = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileStream::flush()
|
||||
{
|
||||
if(!m_fileHandle)
|
||||
return false;
|
||||
|
||||
if(PHYSFS_flush(m_fileHandle) == 0) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return false;
|
||||
|
@ -58,71 +83,143 @@ bool FileStream::flush()
|
|||
|
||||
int FileStream::read(void *buffer, int size, int nmemb)
|
||||
{
|
||||
int res = PHYSFS_read(m_fileHandle, buffer, size, nmemb);
|
||||
if(res == -1) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return 0;
|
||||
if(m_fileHandle) {
|
||||
int res = PHYSFS_read(m_fileHandle, buffer, size, nmemb);
|
||||
if(res == -1) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
uint maxReadPos = m_cacheBuffer.size()-1;
|
||||
int writePos = 0;
|
||||
uint8 *outBuffer = (uint8*)buffer;
|
||||
for(int i=0;i<nmemb;++i) {
|
||||
if(m_cacheReadPos+size > maxReadPos)
|
||||
return i;
|
||||
|
||||
for(int j=0;j<size;++j)
|
||||
outBuffer[writePos++] = m_cacheBuffer[m_cacheReadPos++];
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileStream::write(void *buffer, int count)
|
||||
{
|
||||
if(!m_fileHandle)
|
||||
return false;
|
||||
|
||||
if(PHYSFS_write(m_fileHandle, buffer, 1, count) != count) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileStream::seek(int pos)
|
||||
{
|
||||
if(PHYSFS_seek(m_fileHandle, pos) == 0) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return false;
|
||||
if(m_fileHandle) {
|
||||
if(PHYSFS_seek(m_fileHandle, pos) == 0) {
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(pos > (int)m_cacheBuffer.size() || pos < 0) {
|
||||
logTraceError("operation failed on '", m_name, "': seek pos cannot be greater than file length");
|
||||
return false;
|
||||
}
|
||||
m_cacheReadPos = pos;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int FileStream::size()
|
||||
{
|
||||
return PHYSFS_fileLength(m_fileHandle);
|
||||
if(m_fileHandle)
|
||||
return PHYSFS_fileLength(m_fileHandle);
|
||||
else
|
||||
return m_cacheBuffer.size();
|
||||
}
|
||||
|
||||
int FileStream::tell()
|
||||
{
|
||||
return PHYSFS_tell(m_fileHandle);
|
||||
if(m_fileHandle)
|
||||
return PHYSFS_tell(m_fileHandle);
|
||||
else
|
||||
return m_cacheReadPos;
|
||||
}
|
||||
|
||||
uint8 FileStream::getU8()
|
||||
{
|
||||
uint8 v = 0;
|
||||
if(PHYSFS_read(m_fileHandle, &v, 1, 1) != 1)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
if(m_fileHandle) {
|
||||
if(PHYSFS_read(m_fileHandle, &v, 1, 1) != 1)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
} else {
|
||||
if(m_cacheReadPos+1 >= m_cacheBuffer.size()) {
|
||||
logTraceError("operation failed on '", m_name, "': reached file eof");
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = m_cacheBuffer[m_cacheReadPos];
|
||||
m_cacheReadPos += 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
uint16 FileStream::getU16()
|
||||
{
|
||||
uint16 v = 0;
|
||||
if(PHYSFS_readULE16(m_fileHandle, &v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
if(m_fileHandle) {
|
||||
if(PHYSFS_readULE16(m_fileHandle, &v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
} else {
|
||||
if(m_cacheReadPos+2 >= m_cacheBuffer.size()) {
|
||||
logTraceError("operation failed on '", m_name, "': reached file eof");
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = Fw::readLE16(&m_cacheBuffer[m_cacheReadPos]);
|
||||
m_cacheReadPos += 2;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
uint32 FileStream::getU32()
|
||||
{
|
||||
uint32 v = 0;
|
||||
if(PHYSFS_readULE32(m_fileHandle, &v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
if(m_fileHandle) {
|
||||
if(PHYSFS_readULE32(m_fileHandle, &v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
} else {
|
||||
if(m_cacheReadPos+4 >= m_cacheBuffer.size()) {
|
||||
logTraceError("operation failed on '", m_name, "': reached file eof");
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = Fw::readLE32(&m_cacheBuffer[m_cacheReadPos]);
|
||||
m_cacheReadPos += 4;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
uint64 FileStream::getU64()
|
||||
{
|
||||
uint64 v = 0;
|
||||
if(PHYSFS_readULE64(m_fileHandle, (PHYSFS_uint64*)&v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
if(m_fileHandle) {
|
||||
if(PHYSFS_readULE64(m_fileHandle, (PHYSFS_uint64*)&v) == 0)
|
||||
logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError());
|
||||
} else {
|
||||
if(m_cacheReadPos+8 >= m_cacheBuffer.size()) {
|
||||
logTraceError("operation failed on '", m_name, "': reached file eof");
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = Fw::readLE64(&m_cacheBuffer[m_cacheReadPos]);
|
||||
m_cacheReadPos += 8;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ protected:
|
|||
public:
|
||||
~FileStream();
|
||||
|
||||
void cache();
|
||||
bool close();
|
||||
bool flush();
|
||||
bool write(void *buffer, int count);
|
||||
|
@ -60,6 +61,9 @@ public:
|
|||
private:
|
||||
std::string m_name;
|
||||
PHYSFS_File *m_fileHandle;
|
||||
|
||||
std::vector<uint8_t> m_cacheBuffer;
|
||||
uint m_cacheReadPos;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -100,7 +100,13 @@ void CoordsBuffer::updateCaches()
|
|||
if(!m_hardwareCaching || m_hardwareCached)
|
||||
return;
|
||||
|
||||
if(m_vertexArray.vertexCount() > 0) {
|
||||
int vertexCount = m_vertexArray.vertexCount();
|
||||
|
||||
// there is only performance improvement when caching a lot of vertices
|
||||
if(vertexCount < CACHE_MIN_VERTICES_COUNT)
|
||||
return;
|
||||
|
||||
if(vertexCount > 0) {
|
||||
if(!m_hardwareVertexArray && m_vertexArray.vertexCount() > 0)
|
||||
m_hardwareVertexArray = new HardwareBuffer(HardwareBuffer::VertexBuffer);
|
||||
m_hardwareVertexArray->bind();
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
|
||||
class CoordsBuffer
|
||||
{
|
||||
enum {
|
||||
CACHE_MIN_VERTICES_COUNT = 48
|
||||
};
|
||||
public:
|
||||
CoordsBuffer();
|
||||
~CoordsBuffer();
|
||||
|
|
|
@ -104,25 +104,27 @@ void Painter::setTexture(Texture* texture)
|
|||
|
||||
m_texture = texture;
|
||||
|
||||
GLuint glTextureId;
|
||||
if(texture) {
|
||||
setTextureMatrix(texture->getTransformMatrix());
|
||||
glTextureId = texture->getId();
|
||||
} else
|
||||
glTextureId = 0;
|
||||
|
||||
GLuint glTextureId = texture->getId();
|
||||
if(glTextureId != m_glTextureId) {
|
||||
m_glTextureId = glTextureId;
|
||||
updateGlTexture();
|
||||
}
|
||||
if(m_glTextureId != glTextureId) {
|
||||
m_glTextureId = glTextureId;
|
||||
updateGlTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::updateGlTexture()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_glTextureId);
|
||||
if(m_glTextureId != 0)
|
||||
glBindTexture(GL_TEXTURE_2D, m_glTextureId);
|
||||
}
|
||||
|
||||
void Painter::updateGlCompositionMode()
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
switch(m_compositionMode) {
|
||||
case CompositionMode_Normal:
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
|
|
@ -62,7 +62,12 @@ void PainterOGL1::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode)
|
|||
if(vertexCount == 0)
|
||||
return;
|
||||
|
||||
bool textured = coordsBuffer.getTextureCoordCount() != 0;
|
||||
bool textured = coordsBuffer.getTextureCoordCount() != 0 && m_texture;
|
||||
|
||||
// skip drawing of empty textures
|
||||
if(textured && m_texture->isEmpty())
|
||||
return;
|
||||
|
||||
if(textured != m_textureEnabled) {
|
||||
if(textured)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
@ -121,7 +126,7 @@ void PainterOGL1::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode)
|
|||
|
||||
void PainterOGL1::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture)
|
||||
{
|
||||
if(!texture->getId())
|
||||
if(texture->isEmpty())
|
||||
return;
|
||||
|
||||
setTexture(texture.get());
|
||||
|
@ -130,7 +135,7 @@ void PainterOGL1::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr
|
|||
|
||||
void PainterOGL1::drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
|
||||
{
|
||||
if(dest.isEmpty() || src.isEmpty() || !texture->getId())
|
||||
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
|
||||
return;
|
||||
|
||||
setTexture(texture.get());
|
||||
|
@ -142,7 +147,7 @@ void PainterOGL1::drawTexturedRect(const Rect& dest, const TexturePtr& texture,
|
|||
|
||||
void PainterOGL1::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
|
||||
{
|
||||
if(dest.isEmpty() || src.isEmpty() || !texture->getId())
|
||||
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
|
||||
return;
|
||||
|
||||
setTexture(texture.get());
|
||||
|
|
|
@ -62,7 +62,11 @@ void PainterOGL2::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode)
|
|||
if(vertexCount == 0)
|
||||
return;
|
||||
|
||||
bool textured = coordsBuffer.getTextureCoordCount() > 0;
|
||||
bool textured = coordsBuffer.getTextureCoordCount() > 0 && m_texture;
|
||||
|
||||
// skip drawing of empty textures
|
||||
if(textured && m_texture->isEmpty())
|
||||
return;
|
||||
|
||||
// update shader with the current painter state
|
||||
m_drawProgram->bind();
|
||||
|
@ -100,7 +104,7 @@ void PainterOGL2::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode)
|
|||
|
||||
void PainterOGL2::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture)
|
||||
{
|
||||
if(!texture->getId())
|
||||
if(texture->isEmpty())
|
||||
return;
|
||||
|
||||
setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get());
|
||||
|
@ -110,7 +114,7 @@ void PainterOGL2::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr
|
|||
|
||||
void PainterOGL2::drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
|
||||
{
|
||||
if(dest.isEmpty() || src.isEmpty() || !texture->getId())
|
||||
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
|
||||
return;
|
||||
|
||||
setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get());
|
||||
|
@ -123,7 +127,7 @@ void PainterOGL2::drawTexturedRect(const Rect& dest, const TexturePtr& texture,
|
|||
|
||||
void PainterOGL2::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
|
||||
{
|
||||
if(dest.isEmpty() || src.isEmpty() || !texture->getId())
|
||||
if(dest.isEmpty() || src.isEmpty() || texture->isEmpty())
|
||||
return;
|
||||
|
||||
setDrawProgram(m_shaderProgram ? m_shaderProgram : g_shaders.getDrawTexturedProgram().get());
|
||||
|
|
|
@ -179,10 +179,12 @@ void Texture::generateSoftwareMipmaps(std::vector<uint8> inPixels)
|
|||
|
||||
Size inSize = getSize();
|
||||
Size outSize = inSize / 2;
|
||||
std::vector<uint8> outPixels(outSize.area()*4);
|
||||
std::vector<uint8> outPixels;
|
||||
|
||||
int mipmap = 1;
|
||||
while(true) {
|
||||
outPixels.resize(outSize.area()*4);
|
||||
|
||||
// this is a simple bilinear filtering algorithm, it combines every 4 pixels in one pixel
|
||||
for(int x=0;x<outSize.width();++x) {
|
||||
for(int y=0;y<outSize.height();++y) {
|
||||
|
|
|
@ -60,7 +60,9 @@ TexturePtr TextureManager::getTexture(const std::string& fileName)
|
|||
logError("unable to load texture '", fileName, "': ", e.what());
|
||||
texture = g_graphics.getEmptyTexture();
|
||||
}
|
||||
m_textures[filePath] = texture;
|
||||
|
||||
if(texture)
|
||||
m_textures[filePath] = texture;
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
|
|
@ -37,6 +37,9 @@ SoundFilePtr SoundFile::loadSoundFile(const std::string& filename)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// cache file buffer to avoid lags from hard drive
|
||||
file->cache();
|
||||
|
||||
char magic[4];
|
||||
file->read(magic, 4);
|
||||
file->seek(0);
|
||||
|
|
|
@ -41,6 +41,9 @@ bool SpriteManager::load(const std::string& file)
|
|||
if(!m_spritesFile)
|
||||
return false;
|
||||
|
||||
// cache file buffer to avoid lags from hard drive
|
||||
m_spritesFile->cache();
|
||||
|
||||
m_signature = m_spritesFile->getU32();
|
||||
m_spritesCount = m_spritesFile->getU16();
|
||||
m_sprites.resize(m_spritesCount);
|
||||
|
|
Loading…
Reference in New Issue