[Scummvm-git-logs] scummvm master -> 78de93126f6b4f84502fa5f561992d8a1b38eab1

athrxx athrxx at scummvm.org
Mon May 24 01:36:25 UTC 2021


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
78de93126f SCUMM: (FM-TOWNS) - optimize drawing code


Commit: 78de93126f6b4f84502fa5f561992d8a1b38eab1
    https://github.com/scummvm/scummvm/commit/78de93126f6b4f84502fa5f561992d8a1b38eab1
Author: athrxx (athrxx at scummvm.org)
Date: 2021-05-24T03:34:49+02:00

Commit Message:
SCUMM: (FM-TOWNS) - optimize drawing code

 ("drawing" in this case means the data conversion and transfer from the gfx layers to the screen buffer)

>From my measuring experiments in the MSVC debugger this speeds up the drawing 2 - 3 times. Not sure about release builds, whether these profit even more.

Changed paths:
    engines/scumm/gfx.h
    engines/scumm/gfx_towns.cpp
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h
index 6b3194d4cc..b2ed6bd1a2 100644
--- a/engines/scumm/gfx.h
+++ b/engines/scumm/gfx.h
@@ -470,7 +470,7 @@ public:
 // Helper class for FM-Towns output (required for specific hardware effects like switching graphics layers on and off).
 class TownsScreen {
 public:
-	TownsScreen(OSystem *system, int width, int height, Graphics::PixelFormat &format);
+	TownsScreen(OSystem *system);
 	~TownsScreen();
 
 	void setupLayer(int layer, int width, int height, int scaleW, int scaleH, int numCol, void *srcPal = 0);
@@ -491,17 +491,12 @@ public:
 	int getLayerScaleH(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].scaleH : 0; }
 
 private:
-	void updateOutputBuffer();
-	void outputToScreen();
-	uint16 calc16BitColor(const uint8 *palEntry);
-
 	struct TownsScreenLayer {
 		uint8 *pixels;
 		uint8 *palette;
 		int pitch;
 		int width;
 		int height;
-		int modW;
 		int bpp;
 		int numCol;
 		int hScroll;
@@ -511,12 +506,16 @@ private:
 		bool enabled;
 		bool ready;
 
-		uint16 *bltInternX;
-		uint8 **bltInternY;
 		uint16 *bltTmpPal;
 	} _layers[2];
 
-	uint8 *_outBuffer;
+	template<typename dstPixelType, typename srcPixelType, int scaleW, int scaleH, bool col4bit> void transferRect(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+	template<typename dstPixelType> void updateScreenBuffer();
+
+#ifdef USE_RGB_COLOR
+	void update16BitPalette();
+	uint16 calc16BitColor(const uint8 *palEntry);
+#endif
 
 	int _height;
 	int _width;
diff --git a/engines/scumm/gfx_towns.cpp b/engines/scumm/gfx_towns.cpp
index d573c1f4e9..8a046052ad 100644
--- a/engines/scumm/gfx_towns.cpp
+++ b/engines/scumm/gfx_towns.cpp
@@ -315,31 +315,27 @@ const uint8 ScummEngine::_townsLayer2Mask[] = {
 	0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-#define DIRTY_RECTS_MAX 20
-#define FULL_REDRAW (DIRTY_RECTS_MAX + 1)
+#define FMTOWNS_DIRTY_RECTS_MAX 20
+#define FMTOWNS_FULL_REDRAW (FMTOWNS_DIRTY_RECTS_MAX + 1)
 
-TownsScreen::TownsScreen(OSystem *system, int width, int height, Graphics::PixelFormat &format) :
-	_system(system), _width(width), _height(height), _pixelFormat(format), _pitch(width * format.bytesPerPixel), _scrollOffset(0), _scrollRemainder(0) {
+TownsScreen::TownsScreen(OSystem *system) :	_system(system), _width(0), _height(0), _pitch(0), _pixelFormat(system->getScreenFormat()), _scrollOffset(0), _scrollRemainder(0), _numDirtyRects(0) {
 	memset(&_layers[0], 0, sizeof(TownsScreenLayer));
 	memset(&_layers[1], 0, sizeof(TownsScreenLayer));
-	_outBuffer = new byte[_pitch * _height];
-	memset(_outBuffer, 0, _pitch * _height);
 
-	setupLayer(0, width, height, 1, 1, 256);
+	Graphics::Surface *s = _system->lockScreen();
+	_width = s->w;
+	_height = s->h;
+	_pitch = s->pitch;
+	_system->unlockScreen();
 
-	_numDirtyRects = 0;
+	setupLayer(0, _width, _height, 1, 1, 256);
 }
 
 TownsScreen::~TownsScreen() {
 	delete[] _layers[0].pixels;
 	delete[] _layers[1].pixels;
-	delete[] _layers[0].bltInternX;
-	delete[] _layers[1].bltInternX;
-	delete[] _layers[0].bltInternY;
-	delete[] _layers[1].bltInternY;
 	delete[] _layers[0].bltTmpPal;
 	delete[] _layers[1].bltTmpPal;
-	delete[] _outBuffer;
 	_dirtyRects.clear();
 }
 
@@ -359,7 +355,6 @@ void TownsScreen::setupLayer(int layer, int width, int height, int scaleW, int s
 	l->height = height;
 	l->scaleW = scaleW;
 	l->scaleH = scaleH;
-	l->modW = width * scaleW;
 	l->numCol = numCol;
 	l->bpp = ((numCol - 1) & 0xff00) ? 2 : 1;
 	l->pitch = width * l->bpp;
@@ -374,19 +369,6 @@ void TownsScreen::setupLayer(int layer, int width, int height, int scaleW, int s
 	assert(l->pixels);
 	memset(l->pixels, 0, l->pitch * l->height);
 
-	// build offset tables to speed up merging/scaling layers
-	delete[] l->bltInternX;
-	width = MAX<int>(_width, l->modW);
-	l->bltInternX = new uint16[width];
-	for (int i = 0; i < width; ++i)
-		l->bltInternX[i] = (i / l->scaleW) * l->bpp;
-
-	delete[] l->bltInternY;
-	height = MAX<int>(_height, l->modW);
-	l->bltInternY = new uint8*[height];
-	for (int i = 0; i < height; ++i)
-		l->bltInternY[i] = l->pixels + (i / l->scaleH) * l->pitch;
-
 	delete[] l->bltTmpPal;
 	l->bltTmpPal = (l->bpp == 1 && _pixelFormat.bytesPerPixel == 2) ? new uint16[l->numCol] : 0;
 
@@ -406,7 +388,7 @@ void TownsScreen::clearLayer(int layer) {
 
 	memset(l->pixels, 0, l->pitch * l->height);
 	_dirtyRects.push_back(Common::Rect(_width - 1, _height - 1));
-	_numDirtyRects = FULL_REDRAW;
+	_numDirtyRects = FMTOWNS_FULL_REDRAW;
 }
 
 
@@ -449,10 +431,10 @@ uint8 *TownsScreen::getLayerPixels(int layer, int x, int y) const {
 }
 
 void TownsScreen::addDirtyRect(int x, int y, int w, int h) {
-	if (w <= 0 || h <= 0 || _numDirtyRects > DIRTY_RECTS_MAX)
+	if (w <= 0 || h <= 0 || _numDirtyRects > FMTOWNS_DIRTY_RECTS_MAX)
 		return;
 
-	if (_numDirtyRects == DIRTY_RECTS_MAX) {
+	if (_numDirtyRects == FMTOWNS_DIRTY_RECTS_MAX) {
 		// full redraw
 		_dirtyRects.clear();
 		_dirtyRects.push_back(Common::Rect(_width - 1, _height - 1));
@@ -519,9 +501,12 @@ void TownsScreen::toggleLayers(int flags) {
 
 	_dirtyRects.clear();
 	_dirtyRects.push_back(Common::Rect(_width - 1, _height - 1));
-	_numDirtyRects = FULL_REDRAW;
+	_numDirtyRects = FMTOWNS_FULL_REDRAW;
 
-	memset(_outBuffer, 0, _pitch * _height);
+	Graphics::Surface *s = _system->lockScreen();
+	assert(s);
+	memset(s->getPixels(), 0, _pitch * _height);
+	_system->unlockScreen();
 	update();
 
 	_system->updateScreen();
@@ -539,98 +524,194 @@ void TownsScreen::scrollLayers(int flags, int offset) {
 
 	_dirtyRects.clear();
 	_dirtyRects.push_back(Common::Rect(_width - 1, _height - 1));
-	_numDirtyRects = FULL_REDRAW;
+	_numDirtyRects = FMTOWNS_FULL_REDRAW;
 
 	for (int i = 0; i < 2; ++i) {
 		if (!(flags & (1 << i)))
 			continue;
 		TownsScreenLayer *l = &_layers[i];
 		if (l->ready)
-			l->hScroll = (_scrollOffset * l->scaleH) % l->modW;
+			l->hScroll = _scrollOffset % l->width;
 	}
 }
 
 void TownsScreen::update() {
-	updateOutputBuffer();
-	outputToScreen();
+#ifdef USE_RGB_COLOR
+	update16BitPalette();
+	updateScreenBuffer<uint16>();
+#else
+	updateScreenBuffer<uint8>();
+#endif
 }
 
-void TownsScreen::updateOutputBuffer() {
-	for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r) {
-		for (int i = 0; i < 2; i++) {
-			TownsScreenLayer *l = &_layers[i];
-			if (!l->enabled || !l->ready)
-				continue;
-
-			uint8 *dst = _outBuffer + r->top * _pitch + r->left * _pixelFormat.bytesPerPixel;
-			int pitch2 = _pitch - (r->right - r->left + 1) * _pixelFormat.bytesPerPixel;
-
-			if (_pixelFormat.bytesPerPixel == 2 && l->bpp == 1) {
-				if (!l->palette)
-					error("void TownsScreen::updateOutputBuffer(): No palette assigned to 8 bit layer %d", i);
-				for (int ic = 0; ic < l->numCol; ic++)
-					l->bltTmpPal[ic] = calc16BitColor(&l->palette[ic * 3]);
-			}
+#ifdef USE_RGB_COLOR
+void TownsScreen::update16BitPalette() {
+	for (int i = 0; i < 2; i++) {
+		TownsScreenLayer *l = &_layers[i];
+		if (!l->enabled || !l->ready)
+			continue;
 
-			for (int y = r->top; y <= r->bottom; ++y) {
-				if (l->bpp == _pixelFormat.bytesPerPixel && l->scaleW == 1 && l->onBottom && l->numCol & 0xff00 && + !l->hScroll) {
-					memcpy(dst, &l->bltInternY[y][l->bltInternX[r->left]], (r->right + 1 - r->left) * _pixelFormat.bytesPerPixel);
-					dst += _pitch;
-
-				} else if (_pixelFormat.bytesPerPixel == 2) {
-					uint16 *dst2 = (uint16*)dst;
-					int x = (r->left + l->hScroll) % l->modW;
-					if (l->bpp == 1) {
-						for (int w = r->right - r->left; w >= 0; --w) {
-							uint8 col = l->bltInternY[y][l->bltInternX[x]];
-							if (col || l->onBottom) {
-								if (l->numCol == 16)
-									col = (col >> 4) & (col & 0x0f);
-								*dst2 = l->bltTmpPal[col];
-							}
-							dst2++;
-							x = (x + 1) % l->modW;
-						}
-					} else {
-						for (int w = r->right - r->left; w >= 0; --w) {
-							*dst2++ = *(uint16*)&l->bltInternY[y][l->bltInternX[x]];
-							x = (x + 1) % l->modW;
-						}
-					}
-					dst += _pitch;
+		if (_pixelFormat.bytesPerPixel == 2 && l->bpp == 1) {
+			if (!l->palette)
+				error("void TownsScreen::update16BitPalette(): No palette assigned to 8 bit layer %d", i);
+			for (int ic = 0; ic < l->numCol; ic++)
+				l->bltTmpPal[ic] = calc16BitColor(&l->palette[ic * 3]);
+		}
+	}
+}
 
-				} else {
-					int x = (r->left + l->hScroll) % l->modW;
-					for (int w = r->right - r->left; w >= 0; --w) {
-						uint8 col = l->bltInternY[y][l->bltInternX[x]];
-						if (col || l->onBottom) {
-							if (l->numCol == 16)
-								col = (col >> 4) & (col & 0x0f);
-							*dst = col;
-						}
-						dst++;
-						x = (x + 1) % l->modW;
+uint16 TownsScreen::calc16BitColor(const uint8 *palEntry) {
+	return _pixelFormat.RGBToColor(palEntry[0], palEntry[1], palEntry[2]);
+}
+#endif
+
+template<typename dstPixelType, typename srcPixelType, int scaleW, int scaleH, bool srcCol4bit> void TownsScreen::transferRect(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h) {
+	uint8 *dst10 = dst + y * _pitch * scaleH + x * sizeof(dstPixelType) * scaleW;
+	uint8 *dst20 = (scaleH == 2) ? dst10 + _pitch : 0;
+	int pitch = _pitch * scaleH;
+
+	int x0 = (x + l->hScroll) % l->width;
+	const uint8 *in0 = l->pixels + y * l->pitch + x0 * sizeof(srcPixelType);
+
+	while (h-- >= 0) {
+		const srcPixelType *in = (const srcPixelType*)in0;
+		dstPixelType *dst10a = (dstPixelType*)dst10;
+		dstPixelType *dst20a = (dstPixelType*)dst20;
+		int x1 = x0;
+
+		for (int w1 = w; w1 >= 0; w1--) {
+			srcPixelType col = *in++;
+			if (sizeof(dstPixelType) == 2) {
+				if (sizeof(srcPixelType) == 1) {
+					if (col || l->onBottom) {
+						if (srcCol4bit)
+							col = (col >> 4) & (col & 0x0f);
+						dstPixelType col2 = l->bltTmpPal[col];
+						*dst10a = col2;
+						if (scaleW == 2)
+							*++dst10a = col2;
+						if (scaleH == 2)
+							*dst20a = col2;
+						if (scaleW == 2 && scaleH == 2)
+							*++dst20a = col2;
 					}
-					dst += pitch2;
+					dst10a++;
+					if (scaleH == 2)
+						dst20a++;
+				} else {
+					*dst10a++ = col;
+					if (scaleW == 2)
+						*dst10a++ = col;
+					if (scaleH == 2)
+						*dst20a++ = col;
+					if (scaleW == 2 && scaleH == 2)
+						*dst20a++ = col;
 				}
+			} else {
+				if (col || l->onBottom) {
+					if (srcCol4bit)
+						col = (col >> 4) & (col & 0x0f);
+					*dst10a = col;
+					if (scaleW == 2)
+						*++dst10a = col;
+					if (scaleH == 2)
+						*dst20a = col;
+					if (scaleW == 2 && scaleH == 2)
+						*++dst20a = col;
+				}
+				dst10a++;
+				if (scaleH == 2)
+					dst20a++;
+			}
+			if (++x1 == l->width) {
+				in -= l->width;
+				x1 -= l->width;
 			}
 		}
+		in0 += l->pitch;
+		dst10 += pitch;
+		if (scaleH == 2)
+			dst20 += pitch;
 	}
 }
 
-void TownsScreen::outputToScreen() {
-	for (Common::List<Common::Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i)
-		_system->copyRectToScreen(_outBuffer + i->top * _pitch + i->left * _pixelFormat.bytesPerPixel, _pitch, i->left, i->top, i->right - i->left + 1, i->bottom - i->top + 1);
+#ifdef USE_RGB_COLOR
+template void TownsScreen::transferRect<uint16, uint16, 1, 1, false>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+template void TownsScreen::transferRect<uint16, uint16, 2, 2, false>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+template void TownsScreen::transferRect<uint16, uint8, 1, 1, true>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+#else
+template void TownsScreen::transferRect<uint8, uint8, 2, 2, false>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+template void TownsScreen::transferRect<uint8, uint8, 1, 1, false>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+template void TownsScreen::transferRect<uint8, uint8, 1, 1, true>(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h);
+#endif
+
+template<typename dstPixelType> void TownsScreen::updateScreenBuffer() {
+	Graphics::Surface *s = _system->lockScreen();
+	if (!s)
+		error("TownsScreen::updateOutputBuffer(): Failed to allocate screen buffer");
+	uint8 *dst = (uint8*)s->getPixels();
+
+	for (int i = 0; i < 2; i++) {
+		TownsScreenLayer *l = &_layers[i];
+		if (!l->enabled || !l->ready)
+			continue;
+#ifdef USE_RGB_COLOR
+		if (l->bpp == 2) {
+			if (l->scaleH == 2 && l->scaleW == 2) {
+				for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+					transferRect<dstPixelType, uint16, 2, 2, false>(dst, l, r->left >> 1, r->top >> 1, (r->right - r->left) >> 1, (r->bottom - r->top) >> 1);
+			} else if (l->scaleH == 1 && l->scaleW == 1) {
+				for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+					transferRect<dstPixelType, uint16, 1, 1, false>(dst, l, r->left, r->top, r->right - r->left, r->bottom - r->top);
+			} else {
+				error("TownsScreen::updateOutputBuffer(): Unsupported scale mode");
+			}
+		} else
+
+		if (l->bpp == 1) {
+#else
+			if (l->numCol == 16) {
+				if (l->scaleH == 2 && l->scaleW == 2) {
+					for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+						transferRect<dstPixelType, uint8, 2, 2, true>(dst, l, r->left, r->top, r->right - r->left, r->bottom - r->top);
+				} else
+#endif
+				if (l->scaleH == 1 && l->scaleW == 1) {
+					for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+						transferRect<dstPixelType, uint8, 1, 1, true>(dst, l, r->left, r->top, r->right - r->left, r->bottom - r->top);
+				} else {
+					error("TownsScreen::updateOutputBuffer(): Unsupported scale mode");
+				}
+#ifndef USE_RGB_COLOR
+			} else {
+				if (l->scaleH == 2 && l->scaleW == 2) {
+					for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+						transferRect<dstPixelType, uint8, 2, 2, false>(dst, l, r->left, r->top, r->right - r->left, r->bottom - r->top);
+				} else if (l->scaleH == 1 && l->scaleW == 1) {
+					for (Common::List<Common::Rect>::iterator r = _dirtyRects.begin(); r != _dirtyRects.end(); ++r)
+						transferRect<dstPixelType, uint8, 1, 1, false>(dst, l, r->left, r->top, r->right - r->left, r->bottom - r->top);
+				}
+			}
+#else
+		} else {
+			error("TownsScreen::updateOutputBuffer(): Unsupported pixel format");
+		}
+#endif
+	}
+
+	_system->unlockScreen();
 	_dirtyRects.clear();
 	_numDirtyRects = 0;
 }
 
-uint16 TownsScreen::calc16BitColor(const uint8 *palEntry) {
-	return _pixelFormat.RGBToColor(palEntry[0], palEntry[1], palEntry[2]);
-}
+#ifdef USE_RGB_COLOR
+template void TownsScreen::updateScreenBuffer<uint16>();
+#else
+template void TownsScreen::updateScreenBuffer<uint8>();
+#endif
 
-#undef DIRTY_RECTS_MAX
-#undef FULL_REDRAW
+#undef FMTOWNS_DIRTY_RECTS_MAX
+#undef FMTOWNS_FULL_REDRAW
 
 } // End of namespace Scumm
 
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index a95891ab40..bdbec74b2a 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1657,7 +1657,7 @@ void ScummEngine::resetScumm() {
 		delete _townsScreen;
 		_scrollRequest = _scrollDeltaAdjust = 0;
 		_scrollDestOffset = _scrollTimer = 0;
-		_townsScreen = new TownsScreen(_system, _screenWidth * _textSurfaceMultiplier, _screenHeight * _textSurfaceMultiplier, _outputPixelFormat);
+		_townsScreen = new TownsScreen(_system);
 		_townsScreen->setupLayer(0, 512, _screenHeight, _textSurfaceMultiplier, _textSurfaceMultiplier, (_outputPixelFormat.bytesPerPixel == 2) ? 32767 : 256);
 		_townsScreen->setupLayer(1, _screenWidth * _textSurfaceMultiplier, _screenHeight * _textSurfaceMultiplier, 1, 1, 16, _textPalette);
 	}




More information about the Scummvm-git-logs mailing list