[IPHONE] Memory optimizations on textures.

This commit is contained in:
rachytski 2010-12-08 01:19:15 +02:00 committed by Alex Zolotarev
parent 0d76ea0ed6
commit 9bf70d00d3
9 changed files with 158 additions and 115 deletions

View file

@ -15,6 +15,7 @@ SOURCES += base.cpp \
string_utils.cpp \
profiler.cpp \
commands_queue.cpp \
shared_buffer_manager.cpp
HEADERS += SRC_FIRST.hpp \
assert.hpp \
@ -51,4 +52,5 @@ HEADERS += SRC_FIRST.hpp \
commands_queue.hpp \
ptr_utils.hpp \
stats.hpp \
monitor.hpp
monitor.hpp \
shared_buffer_manager.hpp

View file

@ -0,0 +1,33 @@
#include "../base/SRC_FIRST.hpp"
#include "shared_buffer_manager.hpp"
#include "ptr_utils.hpp"
SharedBufferManager & SharedBufferManager::instance()
{
static SharedBufferManager i;
return i;
}
SharedBufferManager::shared_buffer_ptr_t SharedBufferManager::reserveSharedBuffer(size_t s)
{
threads::MutexGuard g(m_mutex);
shared_buffer_ptr_list_t l = m_sharedBuffers[s];
if (l.empty())
l.push_back(make_shared_ptr(new shared_buffer_t(s)));
shared_buffer_ptr_t res = l.front();
l.pop_front();
return res;
}
void SharedBufferManager::freeSharedBuffer(size_t s, shared_buffer_ptr_t buf)
{
threads::MutexGuard g(m_mutex);
shared_buffer_ptr_list_t l = m_sharedBuffers[s];
l.push_back(buf);
}

View file

@ -0,0 +1,26 @@
#pragma once
#include "../base/mutex.hpp"
#include "../std/vector.hpp"
#include "../std/shared_ptr.hpp"
#include "../std/list.hpp"
#include "../std/map.hpp"
class SharedBufferManager
{
public:
typedef vector<unsigned char> shared_buffer_t;
typedef shared_ptr<shared_buffer_t> shared_buffer_ptr_t;
typedef list<shared_buffer_ptr_t> shared_buffer_ptr_list_t;
typedef map<size_t, shared_buffer_ptr_list_t> shared_buffers_t;
private:
threads::Mutex m_mutex;
shared_buffers_t m_sharedBuffers;
public:
static SharedBufferManager & instance();
shared_buffer_ptr_t reserveSharedBuffer(size_t s);
void freeSharedBuffer(size_t s, shared_buffer_ptr_t buf);
};

View file

@ -2,48 +2,39 @@
#include "internal/opengl.hpp"
#include "managed_texture.hpp"
#include "../base/shared_buffer_manager.hpp"
namespace yg
{
namespace gl
{
ManagedTexture::ManagedTexture(unsigned width, unsigned height)
: BaseTexture(width, height), m_isLocked(false)
ManagedTexture::ManagedTexture(unsigned width, unsigned height, size_t pixelSize)
: BaseTexture(width, height), m_imageSize(width * height * pixelSize), m_isLocked(false)
{}
ManagedTexture::ManagedTexture(m2::PointU const & size)
: BaseTexture(size.x, size.y), m_isLocked(false)
ManagedTexture::ManagedTexture(m2::PointU const & size, size_t pixelSize)
: BaseTexture(size.x, size.y), m_imageSize(size.x * size.y * pixelSize), m_isLocked(false)
{}
void ManagedTexture::addDirtyRect(m2::RectU const & r)
{
if (m_isLocked)
{
if (!m_isDirty && (r.SizeX() != 0) && (r.SizeY() != 0))
{
m_dirtyRect = r;
m_isDirty = true;
}
else
m_dirtyRect.Add(r);
}
}
void ManagedTexture::lock()
{
m_isLocked = true;
m_isDirty = false;
m_auxData = SharedBufferManager::instance().reserveSharedBuffer(m_imageSize);
}
void ManagedTexture::unlock()
{
m_isLocked = false;
SharedBufferManager::instance().freeSharedBuffer(m_imageSize, m_auxData);
if (m_isDirty)
{
updateDirty(m_dirtyRect);
m_isDirty = false;
}
m_auxData.reset();
m_isLocked = false;
}
void * ManagedTexture::auxData()
{
ASSERT(m_isLocked, ("texture is unlocked"));
return &(*m_auxData)[0];
}
}
}

View file

@ -3,6 +3,8 @@
#include "../geometry/rect2d.hpp"
#include "../geometry/point2d.hpp"
#include "base_texture.hpp"
#include "../std/vector.hpp"
#include "../std/shared_ptr.hpp"
namespace yg
{
@ -11,27 +13,31 @@ namespace yg
class ManagedTexture : public BaseTexture
{
private:
/// do we have a data to be updated on unlock?
bool m_isDirty;
/// cumulative dirty rect.
m2::RectU m_dirtyRect;
/// size of the allocated shared buffers
size_t m_imageSize;
protected:
/// is the texture locked
bool m_isLocked;
virtual void updateDirty(m2::RectU const & r) = 0;
virtual void upload() = 0;
virtual void upload(void * data) = 0;
virtual void upload(void * data, m2::RectU const & r) = 0;
/// system memory buffer for the purpose of correct working of glTexSubImage2D.
/// in OpenGL ES 1.1 there are no way to specify GL_UNPACK_ROW_LENGTH so
/// the data supplied to glTexSubImage2D should be continous.
shared_ptr<vector<unsigned char> > m_auxData;
public:
ManagedTexture(m2::PointU const & size);
ManagedTexture(unsigned width, unsigned height);
ManagedTexture(m2::PointU const & size, size_t pixelSize);
ManagedTexture(unsigned width, unsigned height, size_t pixelSize);
void lock();
void addDirtyRect(m2::RectU const & r);
void unlock();
void * auxData();
};
}
}

View file

@ -203,14 +203,9 @@ namespace yg
yg::PenInfo const & penInfo = m_penUploadCommands[i].m_penInfo;
m2::RectU const & rect = m_penUploadCommands[i].m_rect;
TDynamicTexture::view_t v = gil::subimage_view
(
static_cast<TDynamicTexture*>(m_texture.get())->view(),
rect.minX(), rect.minY(),
rect.maxX(), rect.maxY()
);
TDynamicTexture * dynTexture = static_cast<TDynamicTexture*>(m_texture.get());
static_cast<gl::ManagedTexture*>(m_texture.get())->addDirtyRect(rect);
TDynamicTexture::view_t v = dynTexture->view(rect.SizeX(), rect.SizeY());
yg::Color penInfoColor = penInfo.m_color;
@ -272,6 +267,8 @@ namespace yg
curLen += penInfo.m_pat[i];
}
}
dynTexture->upload(&v(0, 0), rect);
}
m_penUploadCommands.clear();
}
@ -290,12 +287,15 @@ namespace yg
c.a /= 16;
#endif
for (size_t y = r.minY(); y < r.maxY(); ++y)
for (size_t x = r.minX(); x < r.maxX(); ++x)
static_cast<TDynamicTexture*>(m_texture.get())->view()(x, y) =
TDynamicTexture::pixel_t(gil::rgba8_pixel_t(c.r, c.g, c.b, c.a));
TDynamicTexture * dynTexture = static_cast<TDynamicTexture*>(m_texture.get());
static_cast<gl::ManagedTexture*>(m_texture.get())->addDirtyRect(r);
TDynamicTexture::view_t v = dynTexture->view(r.SizeX(), r.SizeY());
for (size_t y = 0; y < r.SizeY(); ++y)
for (size_t x = 0; x < r.SizeX(); ++x)
v(x, y) = TDynamicTexture::pixel_t(gil::rgba8_pixel_t(c.r, c.g, c.b, c.a));
dynTexture->upload(&v(0, 0), r);
}
m_colorUploadCommands.clear();
}

View file

@ -11,11 +11,9 @@
#include "../platform/platform.hpp"
#include "../coding/lodepng_io.hpp"
#include "../std/iostream.hpp"
namespace gil = boost::gil;
namespace mpl = boost::mpl;
namespace yg
{
namespace gl
@ -148,18 +146,13 @@ namespace yg
private:
/// system memory copy of texture data
image_t m_image;
/// system memory buffer for the purpose of correct working of glTexSubImage2D.
/// in OpenGL ES 1.1 there are no way to specify GL_UNPACK_ROW_LENGTH so
/// the data supplied to glTexSubImage2D should be continous.
vector<pixel_t> m_auxData;
void upload();
void updateDirty(m2::RectU const & r);
public:
void upload(void * data);
void upload(void * data, m2::RectU const & r);
/// Create the texture loading it from file
Texture(string const & fileName);
/// Create the texture with the predefined dimensions
@ -167,10 +160,10 @@ namespace yg
Texture(m2::RectU const & r);
/// You can call this anytime, regardless the locking status of the texture.
const_view_t const_view() const;
/// const_view_t const_view() const;
/// You can call this on locked texture only. All your changess to this view's data will be
/// uploaded to the video memory on unlock()
view_t view();
view_t view(size_t width, size_t height);
void fill(yg::Color const & c);
@ -191,45 +184,48 @@ namespace yg
template <typename Traits>
Texture<Traits, true>::Texture(const m2::RectU &r)
: ManagedTexture(r.SizeX(), r.SizeY()), m_image(r.SizeX(), r.SizeY())
: ManagedTexture(r.SizeX(), r.SizeY(), sizeof(pixel_t))
{
upload();
m_auxData.resize(width * height);
upload(0);
}
template <typename Traits>
Texture<Traits, true>::Texture(size_t width, size_t height)
: ManagedTexture(width, height), m_image(width, height)
: ManagedTexture(width, height, sizeof(pixel_t))
{
upload();
m_auxData.resize(width * height);
upload(0);
}
template <typename Traits>
Texture<Traits, true>::Texture(string const & fileName) : ManagedTexture(GetDimensions(fileName))
Texture<Traits, true>::Texture(string const & fileName) : ManagedTexture(GetDimensions(fileName), sizeof(pixel_t))
{
lock();
gil::lodepng_read_and_convert_image(GetPlatform().ReadPathForFile(fileName).c_str(), m_image, typename Traits::color_converter());
view_t v = view(width(), height());
gil::lodepng_read_and_convert_view((GetPlatform().ResourcesDir() + fileName).c_str(), v, typename Traits::color_converter());
upload(&v(0, 0));
unlock();
upload();
m_image.recreate(0, 0);
}
template <typename Traits>
typename Texture<Traits, true>::view_t Texture<Traits, true>::view()
typename Texture<Traits, true>::view_t Texture<Traits, true>::view(size_t w, size_t h)
{
ASSERT(m_isLocked, ("non const access to unlocked texture!"));
return gil::view(m_image);
return gil::interleaved_view(
w,
h,
(pixel_t*)auxData(),
w * sizeof(pixel_t));
}
template <typename Traits>
/* template <typename Traits>
typename Texture<Traits, true>::const_view_t Texture<Traits, true>::const_view() const
{
return gil::const_view(m_image);
}
*/
template <typename Traits>
void Texture<Traits, true>::upload()
void Texture<Traits, true>::upload(void * data)
{
makeCurrent();
@ -241,40 +237,25 @@ namespace yg
height(),
0,
GL_RGBA,
Traits::gl_pixel_data_type,
&gil::const_view(m_image)(0, 0)));
gl_pixel_data_type,
data));
}
template <typename Traits>
void Texture<Traits, true>::updateDirty(m2::RectU const & r)
void Texture<Traits, true>::upload(void * data, m2::RectU const & r)
{
makeCurrent();
// m_auxData.resize(r.SizeX() * r.SizeY());
view_t auxView = gil::interleaved_view(
r.SizeX(), r.SizeY(),
(pixel_t*)&m_auxData[0],
r.SizeX() * sizeof(pixel_t));
gil::copy_pixels(
gil::subimage_view(gil::const_view(m_image),
r.minX(), r.minY(),
r.SizeX(), r.SizeY()),
auxView);
/// Uploading texture data
OGLCHECK(glTexSubImage2D(
GL_TEXTURE_2D,
0,
r.minX(),
r.minY(),
r.SizeX(),
r.SizeY(),
GL_RGBA,
Traits::gl_pixel_data_type,
&m_auxData[0]
));
GL_TEXTURE_2D,
0,
r.minX(),
r.minY(),
r.SizeX(),
r.SizeY(),
GL_RGBA,
gl_pixel_data_type,
data));
}
template <typename Traits>
@ -282,21 +263,20 @@ namespace yg
{
makeCurrent();
lock();
view_t v = view();
view_t v = view(width(), height());
for (size_t y = 0; y < height(); ++y)
for (size_t x = 0; x < width(); ++x)
v(x, y) = pixel_t(rand() % maxChannelVal, rand() % maxChannelVal, rand() % maxChannelVal, maxChannelVal);
addDirtyRect(m2::RectU(0, 0, width(), height()));
upload(&v(0, 0), m2::RectU(0, 0, width(), height()));
unlock();
}
template <typename Traits>
void Texture<Traits, true>::readback()
{
makeCurrent();
/* makeCurrent();
#ifndef OMIM_GL_ES
OGLCHECK(glGetTexImage(
GL_TEXTURE_2D,
@ -306,7 +286,7 @@ namespace yg
&gil::view(m_image)(0, 0)));
#else
ASSERT(false, ("no glGetTexImage function in OpenGL ES"));
#endif
#endif*/
}
template <typename Traits>
@ -315,14 +295,14 @@ namespace yg
readback();
std::string const fullPath = GetPlatform().WritablePathForFile(fileName);
#ifndef OMIM_GL_ES
boost::gil::lodepng_write_view(fullPath, gil::const_view(m_image));
boost::gil::lodepng_write_view(fullPath.c_str(), gil::const_view(m_image));
#endif
}
template <typename Traits>
void Texture<Traits, true>::fill(yg::Color const & c)
{
makeCurrent();
/* makeCurrent();
lock();
view_t v = view();
@ -337,6 +317,7 @@ namespace yg
addDirtyRect(m2::RectU(0, 0, width(), height()));
unlock();
*/
}
}
}

View file

@ -113,14 +113,18 @@ namespace
vector<m2::PointD> points;
vector<double> pattern;
int count = 20;
int columns = 30;
int rows = 6;
for (size_t i = 0; i < count; ++i)
for (size_t j = 0; j < rows; ++j)
{
points.clear();
points.push_back(m2::PointD(10, i * 15 + 20));
points.push_back(m2::PointD(100, i * 15 + 20));
AddTest(points, pattern, yg::Color(0, 0, 128 + 128 / count * i, 255), 10);
for (size_t i = 0; i < columns; ++i)
{
points.clear();
points.push_back(m2::PointD(100 * j + 10, i * 15 + 20));
points.push_back(m2::PointD(100 * j + 100, i * 15 + 20));
AddTest(points, pattern, yg::Color(128 + 128 / columns * i, 128 + 128 / rows * j, 0, 255), rand() % 15);
}
}
}
};

View file

@ -10,7 +10,7 @@ UNIT_TEST(TextureTest_Main)
yg::gl::RGBA8Texture texture(256, 256);
texture.makeCurrent();
texture.lock();
yg::gl::RGBA8Texture::view_t view = texture.view();
yg::gl::RGBA8Texture::view_t view = texture.view(256, 256);
for (size_t i = 0; i < texture.height(); ++i)
for (size_t j = 0; j < texture.width(); ++j)
{