ANDROID: Buffer 16bit texture contents

Same issue as in the last commit: glTexSubImage2D is slow, so cache
all copyRect*() calls in a buffer, and update the dirty rect once
when drawing. Reduces CPU usage on 16bit games significantly.
Also, lockScreen() returns now pixel data for non-CLUT8 games instead
of asserting.
This commit is contained in:
dhewg
2011-03-13 16:50:47 +01:00
parent a93229cae5
commit 2721e287e5
5 changed files with 159 additions and 112 deletions
+1 -1
View File
@@ -488,7 +488,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) {
} else {
// Touchscreen events need to be converted
// from device to game coords first.
const GLESTexture *tex;
const GLESBaseTexture *tex;
if (_show_overlay)
tex = _overlay_texture;
else
+3 -3
View File
@@ -103,7 +103,7 @@ private:
bool _force_redraw;
// Game layer
GLESTexture *_game_texture;
GLESBaseTexture *_game_texture;
int _shake_offset;
Common::Rect _focus_rect;
@@ -112,7 +112,7 @@ private:
bool _show_overlay;
// Mouse layer
GLESTexture *_mouse_texture;
GLESBaseTexture *_mouse_texture;
GLESPaletteTexture *_mouse_texture_palette;
GLES5551Texture *_mouse_texture_rgb;
Common::Point _mouse_hotspot;
@@ -151,7 +151,7 @@ private:
#ifdef USE_RGB_COLOR
Common::String getPixelFormatName(const Graphics::PixelFormat &format) const;
void initTexture(GLESTexture **texture, uint width, uint height,
void initTexture(GLESBaseTexture **texture, uint width, uint height,
const Graphics::PixelFormat *format);
#endif
+1 -2
View File
@@ -97,7 +97,7 @@ Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat &
8 - format.aLoss);
}
void OSystem_Android::initTexture(GLESTexture **texture,
void OSystem_Android::initTexture(GLESBaseTexture **texture,
uint width, uint height,
const Graphics::PixelFormat *format) {
assert(texture);
@@ -438,7 +438,6 @@ Graphics::Surface *OSystem_Android::lockScreen() {
GLTHREADCHECK;
// TODO this doesn't return any pixel data for non CLUT8
Graphics::Surface *surface = _game_texture->surface();
assert(surface->pixels);
+118 -95
View File
@@ -36,9 +36,6 @@
#include "backends/platform/android/texture.h"
#include "backends/platform/android/android.h"
// Unfortunately, Android devices are too varied to make broad assumptions :/
#define TEXSUBIMAGE_IS_EXPENSIVE 0
// Supported GL extensions
static bool npot_supported = false;
#ifdef GL_OES_draw_texture
@@ -62,7 +59,7 @@ static T nextHigher2(T k) {
return k + 1;
}
void GLESTexture::initGLExtensions() {
void GLESBaseTexture::initGLExtensions() {
const char *ext_string =
reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
@@ -82,8 +79,8 @@ void GLESTexture::initGLExtensions() {
}
}
GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat) :
GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat) :
_glFormat(glFormat),
_glType(glType),
_texture_name(0),
@@ -98,16 +95,16 @@ GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
GLCALL(glGenTextures(1, &_texture_name));
}
GLESTexture::~GLESTexture() {
GLESBaseTexture::~GLESBaseTexture() {
release();
}
void GLESTexture::release() {
debug("Destroying texture %u", _texture_name);
void GLESBaseTexture::release() {
LOGD("Destroying texture %u", _texture_name);
GLCALL(glDeleteTextures(1, &_texture_name));
}
void GLESTexture::reinit() {
void GLESBaseTexture::reinit() {
GLCALL(glGenTextures(1, &_texture_name));
if (hasPalette()) {
@@ -124,7 +121,7 @@ void GLESTexture::reinit() {
setDirty();
}
void GLESTexture::initSize() {
void GLESBaseTexture::initSize() {
// Allocate room for the texture now, but pixel data gets uploaded
// later (perhaps with multiple TexSubImage2D operations).
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
@@ -138,7 +135,7 @@ void GLESTexture::initSize() {
0, _glFormat, _glType, 0));
}
void GLESTexture::allocBuffer(GLuint w, GLuint h) {
void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
_surface.w = w;
_surface.h = h;
_surface.bytesPerPixel = _pixelFormat.bytesPerPixel;
@@ -155,85 +152,10 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
_texture_height = nextHigher2(_surface.h);
}
_surface.pitch = _texture_width * _pixelFormat.bytesPerPixel;
initSize();
}
void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
const void *buf, int pitch_buf) {
ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch_buf);
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
setDirtyRect(Common::Rect(x, y, x + w, y + h));
if (static_cast<int>(w) * _pixelFormat.bytesPerPixel == pitch_buf) {
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
_glFormat, _glType, buf));
} else {
// GLES removed the ability to specify pitch, so we
// have to do this ourselves.
#if TEXSUBIMAGE_IS_EXPENSIVE
byte *tmp = new byte[w * h * _pixelFormat.bytesPerPixel];
assert(tmp);
const byte *src = static_cast<const byte *>(buf);
byte *dst = tmp;
GLuint count = h;
do {
memcpy(dst, src, w * _pixelFormat.bytesPerPixel);
dst += w * _pixelFormat.bytesPerPixel;
src += pitch_buf;
} while (--count);
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
_glFormat, _glType, tmp));
delete[] tmp;
#else
// This version avoids the intermediate copy at the expense of
// repeat glTexSubImage2D calls. On some devices this is worse.
const byte *src = static_cast<const byte *>(buf);
do {
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
w, 1, _glFormat, _glType, src));
++y;
src += pitch_buf;
} while (--h);
#endif
}
}
void GLESTexture::fillBuffer(uint32 color) {
uint rowbytes = _surface.w * _pixelFormat.bytesPerPixel;
byte *tmp = new byte[rowbytes];
assert(tmp);
if (_pixelFormat.bytesPerPixel == 1 ||
((color & 0xff) == ((color >> 8) & 0xff))) {
memset(tmp, color & 0xff, rowbytes);
} else {
uint16 *p = (uint16 *)tmp;
Common::set_to(p, p + _surface.w, (uint16)color);
}
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
for (GLuint y = 0; y < _surface.h; ++y)
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, _surface.w, 1,
_glFormat, _glType, tmp));
delete[] tmp;
setDirty();
}
void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
#ifdef GL_OES_draw_texture
@@ -279,10 +201,110 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
clearDirty();
}
const Graphics::PixelFormat &GLESTexture::getPixelFormat() const {
const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
return _pixelFormat;
}
GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat) :
GLESBaseTexture(glFormat, glType, pixelFormat),
_pixels(0),
_buf(0) {
}
GLESTexture::~GLESTexture() {
delete[] _buf;
delete[] _pixels;
}
void GLESTexture::allocBuffer(GLuint w, GLuint h) {
GLESBaseTexture::allocBuffer(w, h);
delete[] _buf;
delete[] _pixels;
_pixels = new byte[w * h * _surface.bytesPerPixel];
assert(_pixels);
_surface.pixels = _pixels;
_surface.pitch = w * _pixelFormat.bytesPerPixel;
_buf = new byte[w * h * _surface.bytesPerPixel];
assert(_buf);
}
void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
const void *buf, int pitch_buf) {
setDirtyRect(Common::Rect(x, y, x + w, y + h));
const byte *src = (const byte *)buf;
byte *dst = _pixels + y * _surface.pitch + x * _surface.bytesPerPixel;
do {
memcpy(dst, src, w * _surface.bytesPerPixel);
dst += _surface.pitch;
src += pitch_buf;
} while (--h);
}
void GLESTexture::fillBuffer(uint32 color) {
assert(_surface.pixels);
if (_pixelFormat.bytesPerPixel == 1 ||
((color & 0xff) == ((color >> 8) & 0xff)))
memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
else
Common::set_to(_pixels, _pixels + _surface.pitch * _surface.h,
(uint16)color);
setDirty();
}
void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
if (_all_dirty) {
_dirty_rect.top = 0;
_dirty_rect.left = 0;
_dirty_rect.bottom = _surface.h;
_dirty_rect.right = _surface.w;
_all_dirty = false;
}
if (!_dirty_rect.isEmpty()) {
byte *_tex;
int16 dwidth = _dirty_rect.width();
int16 dheight = _dirty_rect.height();
if (dwidth == _surface.w) {
_tex = _pixels + _dirty_rect.top * _surface.pitch;
} else {
_tex = _buf;
byte *src = _pixels + _dirty_rect.top * _surface.pitch +
_dirty_rect.left * _surface.bytesPerPixel;
byte *dst = _buf;
uint16 l = dwidth * _surface.bytesPerPixel;
for (uint16 i = 0; i < dheight; ++i) {
memcpy(dst, src, l);
src += _surface.pitch;
dst += l;
}
}
GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
_dirty_rect.left, _dirty_rect.top,
dwidth, dheight, _glFormat, _glType, _tex));
}
GLESBaseTexture::drawTexture(x, y, w, h);
}
GLES4444Texture::GLES4444Texture() :
GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) {
}
@@ -306,7 +328,7 @@ GLES565Texture::~GLES565Texture() {
GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat palettePixelFormat) :
GLESTexture(glFormat, glType,
GLESBaseTexture(glFormat, glType,
Graphics::PixelFormat::createFormatCLUT8()),
_texture(0)
{
@@ -319,7 +341,7 @@ GLESPaletteTexture::~GLESPaletteTexture() {
}
void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
GLESTexture::allocBuffer(w, h);
GLESBaseTexture::allocBuffer(w, h);
// Texture gets uploaded later (from drawTexture())
@@ -335,6 +357,7 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
_texture = new_buffer;
_surface.pixels = _texture + _paletteSize;
_surface.pitch = _texture_width;
}
void GLESPaletteTexture::fillBuffer(uint32 color) {
@@ -370,7 +393,7 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
0, texture_size, _texture));
}
GLESTexture::drawTexture(x, y, w, h);
GLESBaseTexture::drawTexture(x, y, w, h);
}
GLESPalette888Texture::GLESPalette888Texture() :
@@ -415,7 +438,7 @@ GLESPalette5551Texture::~GLESPalette5551Texture() {
GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat) :
GLESTexture(glFormat, glType, pixelFormat),
GLESBaseTexture(glFormat, glType, pixelFormat),
_palette(0),
_pixels(0),
_buf(0)
@@ -434,7 +457,7 @@ GLESFakePaletteTexture::~GLESFakePaletteTexture() {
}
void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
GLESTexture::allocBuffer(w, h);
GLESBaseTexture::allocBuffer(w, h);
delete[] _buf;
delete[] _pixels;
@@ -505,7 +528,7 @@ void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
dwidth, dheight, _glFormat, _glType, _buf));
}
GLESTexture::drawTexture(x, y, w, h);
GLESBaseTexture::drawTexture(x, y, w, h);
}
const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
+36 -11
View File
@@ -36,26 +36,26 @@
#include "common/rect.h"
#include "common/array.h"
class GLESTexture {
class GLESBaseTexture {
public:
static void initGLExtensions();
protected:
GLESTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat);
GLESBaseTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat);
public:
virtual ~GLESTexture();
virtual ~GLESBaseTexture();
void release();
void reinit();
void initSize();
virtual void allocBuffer(GLuint width, GLuint height);
virtual void allocBuffer(GLuint w, GLuint h);
virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);
const void *buf, int pitch_buf) = 0;
virtual void fillBuffer(uint32 color) = 0;
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
@@ -144,6 +144,31 @@ protected:
Graphics::PixelFormat _palettePixelFormat;
};
class GLESTexture : public GLESBaseTexture {
protected:
GLESTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat);
public:
virtual ~GLESTexture();
virtual void allocBuffer(GLuint w, GLuint h);
virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);
virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
inline void drawTexture() {
drawTexture(0, 0, _surface.w, _surface.h);
}
protected:
byte *_pixels;
byte *_buf;
};
// RGBA4444 texture
class GLES4444Texture : public GLESTexture {
public:
@@ -177,7 +202,7 @@ public:
}
};
class GLESPaletteTexture : public GLESTexture {
class GLESPaletteTexture : public GLESBaseTexture {
protected:
GLESPaletteTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat palettePixelFormat);
@@ -185,7 +210,7 @@ protected:
public:
virtual ~GLESPaletteTexture();
virtual void allocBuffer(GLuint width, GLuint height);
virtual void allocBuffer(GLuint w, GLuint h);
virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);
@@ -245,7 +270,7 @@ public:
virtual ~GLESPalette5551Texture();
};
class GLESFakePaletteTexture : public GLESTexture {
class GLESFakePaletteTexture : public GLESBaseTexture {
protected:
GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
Graphics::PixelFormat pixelFormat);
@@ -253,7 +278,7 @@ protected:
public:
virtual ~GLESFakePaletteTexture();
virtual void allocBuffer(GLuint width, GLuint height);
virtual void allocBuffer(GLuint w, GLuint h);
virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
const void *buf, int pitch_buf);
virtual void fillBuffer(uint32 color);