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. | 
