mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
Reference in New Issue
Block a user