diff options
author | Einar Johan Trøan Sømåen | 2012-08-07 16:04:47 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2012-08-07 16:05:36 +0200 |
commit | 8883a9ffd587de0cfca9a42925d2f1071d4ccb35 (patch) | |
tree | 6ac8097a1497559dbde5007710b4a70d42fe01e1 | |
parent | 3abccb2e339144191553555756e3ff43222c3a36 (diff) | |
download | scummvm-rg350-8883a9ffd587de0cfca9a42925d2f1071d4ccb35.tar.gz scummvm-rg350-8883a9ffd587de0cfca9a42925d2f1071d4ccb35.tar.bz2 scummvm-rg350-8883a9ffd587de0cfca9a42925d2f1071d4ccb35.zip |
WINTERMUTE: Optimize blitting (Do opaque blits for opaque images, and do fill with memcpy)
5 files changed, 74 insertions, 16 deletions
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index f12478f7b3..3ec04b1ab1 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -40,8 +40,8 @@ namespace WinterMute {
-RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY) : _owner(owner),
- _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(true) {
+RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) : _owner(owner),
+ _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(!disableAlpha) {
_colorMod = 0;
_mirror = TransparentSurface::FLIP_NONE;
if (mirrorX) {
@@ -97,6 +97,7 @@ BaseRenderer *makeOSystemRenderer(BaseGame *inGame) { //////////////////////////////////////////////////////////////////////////
BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {
_renderSurface = new Graphics::Surface();
+ _blankSurface = new Graphics::Surface();
_drawNum = 1;
_needsFlip = true;
@@ -111,6 +112,8 @@ BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) { BaseRenderOSystem::~BaseRenderOSystem() {
_renderSurface->free();
delete _renderSurface;
+ _blankSurface->free();
+ delete _blankSurface;
}
//////////////////////////////////////////////////////////////////////////
@@ -166,6 +169,8 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) { g_system->showMouse(false);
_renderSurface->create(g_system->getWidth(), g_system->getHeight(), g_system->getScreenFormat());
+ _blankSurface->create(g_system->getWidth(), g_system->getHeight(), g_system->getScreenFormat());
+ _blankSurface->fillRect(Common::Rect(0, 0, g_system->getHeight(), g_system->getWidth()), _blankSurface->format.ARGBToColor(255, 0, 0, 0));
_active = true;
_clearColor = _renderSurface->format.ARGBToColor(255, 0, 0, 0);
@@ -217,6 +222,11 @@ bool BaseRenderOSystem::fill(byte r, byte g, byte b, Common::Rect *rect) { return STATUS_OK;
}
if (!rect) {
+ if (r == 0 && g == 0 && b == 0) {
+ // Simply memcpy from the buffered black-surface, way faster than Surface::fillRect.
+ memcpy(_renderSurface->pixels, _blankSurface->pixels, _renderSurface->pitch * _renderSurface->h);
+ return STATUS_OK;
+ }
rect = &_renderRect;
}
// TODO: This doesn't work with dirty rects
@@ -281,12 +291,12 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const { return _renderSurface->format;
}
-void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY) {
+void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha) {
if (_disableDirtyRects) {
- RenderTicket renderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY);
+ RenderTicket renderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
// HINT: The surface-data contains other info than it should.
// drawFromSurface(renderTicket._surface, srcRect, dstRect, NULL, mirrorX, mirrorY);
- drawFromSurface(renderTicket.getSurface(), &renderTicket._srcRect, &renderTicket._dstRect, NULL, renderTicket._mirror);
+ drawFromSurface(&renderTicket, NULL);
return;
}
// Skip rects that are completely outside the screen:
@@ -295,7 +305,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S }
if (owner) { // Fade-tickets are owner-less
- RenderTicket compare(owner, NULL, srcRect, dstRect, mirrorX, mirrorY);
+ RenderTicket compare(owner, NULL, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
compare._colorMod = _colorMod;
RenderQueueIterator it;
for (it = _renderQueue.begin(); it != _renderQueue.end(); it++) {
@@ -306,7 +316,7 @@ void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::S }
}
}
- RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY);
+ RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY, disableAlpha);
ticket->_colorMod = _colorMod;
drawFromTicket(ticket);
}
@@ -445,6 +455,22 @@ void BaseRenderOSystem::drawTickets() { }
// Replacement for SDL2's SDL_RenderCopy
+void BaseRenderOSystem::drawFromSurface(RenderTicket *ticket, Common::Rect *clipRect) {
+ TransparentSurface src(*ticket->getSurface(), false);
+ bool doDelete = false;
+ if (!clipRect) {
+ doDelete = true;
+ clipRect = new Common::Rect();
+ clipRect->setWidth(ticket->getSurface()->w);
+ clipRect->setHeight(ticket->getSurface()->h);
+ }
+
+ src._enableAlphaBlit = ticket->_hasAlpha;
+ src.blit(*_renderSurface, ticket->_dstRect.left, ticket->_dstRect.top, ticket->_mirror, clipRect, _colorMod, clipRect->width(), clipRect->height());
+ if (doDelete) {
+ delete clipRect;
+ }
+}
void BaseRenderOSystem::drawFromSurface(const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Common::Rect *clipRect, uint32 mirror) {
TransparentSurface src(*surf, false);
bool doDelete = false;
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index 08fd6cf9ab..070ddf9241 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -39,7 +39,7 @@ class BaseSurfaceOSystem; class RenderTicket {
Graphics::Surface *_surface;
public:
- RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false);
+ RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false, bool disableAlpha = false);
RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0) {}
~RenderTicket();
const Graphics::Surface *getSurface() { return _surface; }
@@ -97,11 +97,12 @@ public: return _ratioY;
}
- void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY);
+ void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY, bool disableAlpha = false);
BaseSurface *createSurface();
private:
void addDirtyRect(const Common::Rect &rect);
void drawTickets();
+ void drawFromSurface(RenderTicket *ticket, Common::Rect *clipRect);
void drawFromSurface(const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Common::Rect *clipRect, uint32 mirror);
typedef Common::List<RenderTicket *>::iterator RenderQueueIterator;
Common::Rect *_dirtyRect;
@@ -110,6 +111,7 @@ private: uint32 _drawNum;
Common::Rect _renderRect;
Graphics::Surface *_renderSurface;
+ Graphics::Surface *_blankSurface;
int _borderLeft;
int _borderTop;
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index 9f0e605f39..7845390871 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -396,17 +396,17 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, flo // But no checking is in place for that yet.
// TODO: Optimize by not doing alpha-blits if we lack or disable alpha
-/* bool hasAlpha;
+ bool hasAlpha;
if (_hasAlpha && !alphaDisable) {
hasAlpha = true;
} else {
hasAlpha = false;
- }*/
+ }
if (alphaDisable) {
warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored");
}
- renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY);
+ renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY, !hasAlpha);
return STATUS_OK;
}
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index 49deafa7e6..5faf313207 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -29,9 +29,9 @@ namespace WinterMute { -TransparentSurface::TransparentSurface() : Surface() {} +TransparentSurface::TransparentSurface() : Surface(), _enableAlphaBlit(true) {} -TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface() { +TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _enableAlphaBlit(true) { if (copyData) { copyFrom(surf); } else { @@ -43,7 +43,31 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur } } -void doBlit(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void doBlitOpaque(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { + byte *in, *out; + +#ifdef SCUMM_LITTLE_ENDIAN + const int aIndex = 3; +#else + const int aIndex = 0; +#endif + + for (uint32 i = 0; i < height; i++) { + out = outo; + in = ino; + for (uint32 j = 0; j < width; j++) { + uint32 pix = *(uint32 *)in; + in += inStep; + *(uint32*)out = pix; + out[aIndex] = 0xFF; + out += 4; + } + outo += pitch; + ino += inoStep; + } +} + +void doBlitAlpha(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; #ifdef SCUMM_LITTLE_ENDIAN @@ -246,7 +270,11 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p const int rShiftTarget = 16;//target.format.rShift; if (ca == 255 && cb == 255 && cg == 255 && cr == 255) { - doBlit(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); + if (_enableAlphaBlit) { + doBlitAlpha(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); + } else { + doBlitOpaque(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); + } } else { for (int i = 0; i < img->h; i++) { out = outo; diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index 79637037db..20fd3c434e 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -66,6 +66,8 @@ struct TransparentSurface : public Graphics::Surface { FLIP_VH = FLIP_H | FLIP_V }; + bool _enableAlphaBlit; + /** @brief renders the surface to another surface @param pDest a pointer to the target image. In most cases this is the framebuffer. |