[Scummvm-git-logs] scummvm master -> 5f3e0cc9b4e37f49cfe4187b50cde55a5e23990f

bluegr noreply at scummvm.org
Sun Jun 22 11:09:48 UTC 2025


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

Summary:
aebd8c7346 GRAPHICS: Add a ManagedSurface function for filling surfaces with blending
5f3e0cc9b4 WINTERMUTE: Make use of ManagedSurface::blendFillRect


Commit: aebd8c73463c5a81f4c4cfad86f19eb21abcbac8
    https://github.com/scummvm/scummvm/commit/aebd8c73463c5a81f4c4cfad86f19eb21abcbac8
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-06-22T14:09:44+03:00

Commit Message:
GRAPHICS: Add a ManagedSurface function for filling surfaces with blending

Changed paths:
    graphics/blit.h
    graphics/blit/blit-alpha.cpp
    graphics/blit/blit-alpha.h
    graphics/blit/blit-generic.cpp
    graphics/managed_surface.cpp
    graphics/managed_surface.h


diff --git a/graphics/blit.h b/graphics/blit.h
index 49fd1f65dc6..126e790804b 100644
--- a/graphics/blit.h
+++ b/graphics/blit.h
@@ -290,10 +290,17 @@ private:
 	static void blitGeneric(Args &args, const TSpriteBlendMode &blendMode, const AlphaType &alphaType);
 	template<class T>
 	static void blitT(Args &args, const TSpriteBlendMode &blendMode, const AlphaType &alphaType);
-#undef LOGIC_FUNCS_EXT
 
 	typedef void(*BlitFunc)(Args &, const TSpriteBlendMode &, const AlphaType &);
 	static BlitFunc blitFunc;
+
+	static void fillGeneric(Args &args, const TSpriteBlendMode &blendMode);
+	template<class T>
+	static void fillT(Args &args, const TSpriteBlendMode &blendMode);
+
+	typedef void(*FillFunc)(Args &, const TSpriteBlendMode &);
+	static FillFunc fillFunc;
+
 	friend class ::BlendBlitUnfilteredTestSuite;
 	friend class BlendBlitImpl_Default;
 	friend class BlendBlitImpl_NEON;
@@ -373,6 +380,21 @@ public:
 			  const TSpriteBlendMode blendMode,
 			  const AlphaType alphaType);
 
+	/**
+	 * Optimized version of doFill to be used with alpha blended fills
+	 * NOTE: Can only be used with BlendBlit::getSupportedPixelFormat format
+	 * @param dst a pointer to the destination buffer (can be offseted by pixels)
+	 * @param dstPitch destination pitch
+	 * @param width width of the input surface
+	 * @param height height of the input surface
+	 * @param colorMod the color to multiply by. (0xffffffff does no multiplication and has 0 overhead usually)
+	 * @param blendMode the blending mode to be used
+	 */
+	static void fill(byte *dst, const uint dstPitch,
+			  const uint width, const uint height,
+			  const uint32 colorMod,
+			  const TSpriteBlendMode blendMode);
+
 }; // End of class BlendBlit
 
 /** @} */
diff --git a/graphics/blit/blit-alpha.cpp b/graphics/blit/blit-alpha.cpp
index b37edd2e712..e399b9da553 100644
--- a/graphics/blit/blit-alpha.cpp
+++ b/graphics/blit/blit-alpha.cpp
@@ -203,8 +203,9 @@ BlendBlit::Args::Args(byte *dst, const byte *src,
 	outo = dst + posY * _dstPitch + posX * 4;
 }
 
-// Initialize this to nullptr at the start
+// Initialize these to nullptr at the start
 BlendBlit::BlitFunc BlendBlit::blitFunc = nullptr;
+BlendBlit::FillFunc BlendBlit::fillFunc = nullptr;
 
 // Only blits to and from 32bpp images
 // So this function is just here to jump to whatever function is in
@@ -240,4 +241,25 @@ void BlendBlit::blit(byte *dst, const byte *src,
 	blitFunc(args, blendMode, alphaType);
 }
 
+// Only fills 32bpp images
+// So this function is just here to jump to whatever function is in
+// BlendBlit::fillFunc. This way, we can detect at runtime whether or not
+// the cpu has certain SIMD feature enabled or not.
+void BlendBlit::fill(byte *dst, const uint dstPitch,
+					 const uint width, const uint height,
+					 const uint32 colorMod,
+					 const TSpriteBlendMode blendMode) {
+	if (width == 0 || height == 0) return;
+
+	// If no function has been selected yet, detect and select
+	if (!fillFunc) {
+		// Get the correct blit function
+		// TODO: Add SIMD variants
+		fillFunc = fillGeneric;
+	}
+
+	Args args(dst, nullptr, dstPitch, 0, 0, 0, width, height, 0, 0, 0, 0, colorMod, 0);
+	fillFunc(args, blendMode);
+}
+
 } // End of namespace Graphics
diff --git a/graphics/blit/blit-alpha.h b/graphics/blit/blit-alpha.h
index 2ebe959c82d..1aa4cb52075 100644
--- a/graphics/blit/blit-alpha.h
+++ b/graphics/blit/blit-alpha.h
@@ -85,6 +85,41 @@ public:
 		}
 
 	}
+
+	inline void fill(byte *out) const {
+		uint32 ina = this->ca;
+
+		/* if (ina == 255) {
+			if (rgbmod) {
+				out[BlendBlit::kAIndex] = 255;
+				out[BlendBlit::kBIndex] = this->cb;
+				out[BlendBlit::kGIndex] = this->cg;
+				out[BlendBlit::kRIndex] = this->cr;
+			} else {
+				out[BlendBlit::kAIndex] = 255;
+				out[BlendBlit::kBIndex] = 255;
+				out[BlendBlit::kGIndex] = 255;
+				out[BlendBlit::kRIndex] = 255;
+			}
+		} else if (ina != 0) */ {
+			if (rgbmod) {
+				const uint outb = (out[BlendBlit::kBIndex] * (255 - ina) >> 8);
+				const uint outg = (out[BlendBlit::kGIndex] * (255 - ina) >> 8);
+				const uint outr = (out[BlendBlit::kRIndex] * (255 - ina) >> 8);
+
+				out[BlendBlit::kAIndex] = 255;
+				out[BlendBlit::kBIndex] = outb + (255 * ina * this->cb >> 16);
+				out[BlendBlit::kGIndex] = outg + (255 * ina * this->cg >> 16);
+				out[BlendBlit::kRIndex] = outr + (255 * ina * this->cr >> 16);
+			} else {
+				out[BlendBlit::kAIndex] = 255;
+				out[BlendBlit::kBIndex] = (out[BlendBlit::kBIndex] * (255 - ina) + 255 * ina) >> 8;
+				out[BlendBlit::kGIndex] = (out[BlendBlit::kGIndex] * (255 - ina) + 255 * ina) >> 8;
+				out[BlendBlit::kRIndex] = (out[BlendBlit::kRIndex] * (255 - ina) + 255 * ina) >> 8;
+			}
+		}
+
+	}
 };
 
 template<bool rgbmod, bool alphamod>
@@ -123,6 +158,28 @@ public:
 			}
 		}
 	}
+
+	inline void fill(byte *out) const {
+		uint32 ina = this->ca;
+
+		if (ina == 255) {
+			if (rgbmod) {
+				out[BlendBlit::kBIndex] = (out[BlendBlit::kBIndex] * this->cb) >> 8;
+				out[BlendBlit::kGIndex] = (out[BlendBlit::kGIndex] * this->cg) >> 8;
+				out[BlendBlit::kRIndex] = (out[BlendBlit::kRIndex] * this->cr) >> 8;
+			}
+		} else if (ina != 0) {
+			if (rgbmod) {
+				out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * ((this->cb * ina) >> 8) >> 8;
+				out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * ((this->cg * ina) >> 8) >> 8;
+				out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * ((this->cr * ina) >> 8) >> 8;
+			} else {
+				out[BlendBlit::kBIndex] = (out[BlendBlit::kBIndex] * ina) >> 8;
+				out[BlendBlit::kGIndex] = (out[BlendBlit::kGIndex] * ina) >> 8;
+				out[BlendBlit::kRIndex] = (out[BlendBlit::kRIndex] * ina) >> 8;
+			}
+		}
+	}
 };
 
 template<bool rgbmod, bool alphamod>
@@ -186,6 +243,32 @@ public:
 			}
 		}
 	}
+
+	inline void fill(byte *out) const {
+		uint32 ina = this->ca;
+
+		if (ina == 255) {
+			if (rgbmod) {
+				out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + this->cb;
+				out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + this->cg;
+				out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + this->cr;
+			} else {
+				out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + 255;
+				out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + 255;
+				out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + 255;
+			}
+		} else if (ina != 0) {
+			if (rgbmod) {
+				out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ((this->cb * ina) >> 8);
+				out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ((this->cg * ina) >> 8);
+				out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ((this->cr * ina) >> 8);
+			} else {
+				out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ina;
+				out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ina;
+				out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ina;
+			}
+		}
+	}
 };
 
 template<bool rgbmod, bool alphamod>
@@ -219,6 +302,20 @@ public:
 			}
 		}
 	}
+
+	inline void fill(byte *out) const {
+		out[BlendBlit::kAIndex] = 255;
+
+		if (rgbmod) {
+			out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((this->cb * out[BlendBlit::kBIndex]) >> 8), 0);
+			out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((this->cg * out[BlendBlit::kGIndex]) >> 8), 0);
+			out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((this->cr * out[BlendBlit::kRIndex]) >> 8), 0);
+		} else {
+			out[BlendBlit::kBIndex] = 0;
+			out[BlendBlit::kGIndex] = 0;
+			out[BlendBlit::kRIndex] = 0;
+		}
+	}
 };
 
 }; // End of class BlendBlitImpl_Base
@@ -344,4 +441,61 @@ void BlendBlit::blitT(Args &args, const TSpriteBlendMode &blendMode, const Alpha
 	}
 }
 
+template<class T>
+void BlendBlit::fillT(Args &args, const TSpriteBlendMode &blendMode) {
+	bool rgbmod   = ((args.color & kRGBModMask) != kRGBModMask);
+	bool alphamod = ((args.color & kAModMask)   != kAModMask);
+
+	if (blendMode == BLEND_ADDITIVE) {
+		if (rgbmod) {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template AdditiveBlend, true, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template AdditiveBlend, true, false>(args);
+			}
+		} else {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template AdditiveBlend, false, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template AdditiveBlend, false, false>(args);
+			}
+		}
+	} else if (blendMode == BLEND_SUBTRACTIVE) {
+		if (rgbmod) {
+			T::template fillInnerLoop<T::template SubtractiveBlend, true, false>(args);
+		} else {
+			T::template fillInnerLoop<T::template SubtractiveBlend, false, false>(args);
+		}
+	} else if (blendMode == BLEND_MULTIPLY) {
+		if (rgbmod) {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template MultiplyBlend, true, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template MultiplyBlend, true, false>(args);
+			}
+		} else {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template MultiplyBlend, false, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template MultiplyBlend, false, false>(args);
+			}
+		}
+	} else {
+		assert(blendMode == BLEND_NORMAL);
+		if (rgbmod) {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template AlphaBlend, true, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template AlphaBlend, true, false>(args);
+			}
+		} else {
+			if (alphamod) {
+				T::template fillInnerLoop<T::template AlphaBlend, false, true>(args);
+			} else {
+				T::template fillInnerLoop<T::template AlphaBlend, false, false>(args);
+			}
+		}
+	}
+}
+
 } // End of namespace Graphics
diff --git a/graphics/blit/blit-generic.cpp b/graphics/blit/blit-generic.cpp
index bbdbc062f28..4fae045cd53 100644
--- a/graphics/blit/blit-generic.cpp
+++ b/graphics/blit/blit-generic.cpp
@@ -68,10 +68,32 @@ static inline void blitInnerLoop(BlendBlit::Args &args) {
 	}
 }
 
+template<template <bool RGBMOD, bool ALPHAMOD> class PixelFunc, bool rgbmod, bool alphamod>
+static inline void fillInnerLoop(BlendBlit::Args &args) {
+	byte *out;
+
+	const PixelFunc<rgbmod, alphamod> pixelFunc(args.color);
+
+	for (uint32 i = 0; i < args.height; i++) {
+		out = args.outo;
+
+		for (uint32 j = 0; j < args.width; j++) {
+			pixelFunc.fill(out);
+
+			out += 4;
+		}
+		args.outo += args.dstPitch;
+	}
+}
+
 }; // end of class BlendBlitImpl_Default
 
 void BlendBlit::blitGeneric(Args &args, const TSpriteBlendMode &blendMode, const AlphaType &alphaType) {
 	blitT<BlendBlitImpl_Default>(args, blendMode, alphaType);
 }
 
+void BlendBlit::fillGeneric(Args &args, const TSpriteBlendMode &blendMode) {
+	fillT<BlendBlitImpl_Default>(args, blendMode);
+}
+
 } // End of namespace Graphics
diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp
index 3a90fd66063..5582661ff71 100644
--- a/graphics/managed_surface.cpp
+++ b/graphics/managed_surface.cpp
@@ -1100,6 +1100,37 @@ Common::Rect ManagedSurface::blendBlitTo(Surface &target,
 	else return Common::Rect(0, 0, dstArea.width(), dstArea.height());
 }
 
+void ManagedSurface::blendFillRect(Common::Rect r,
+		const uint colorMod, const TSpriteBlendMode blend) {
+	if (!isBlendBlitPixelFormatSupported(format, format)) {
+		warning("ManagedSurface::blendFillRect only accepts RGBA32!");
+		return;
+	}
+
+	// Alpha is zero
+	if ((colorMod & MS_ARGB(255, 0, 0, 0)) == 0) return;
+
+	// Use faster memory fills where possible
+	if (blend == BLEND_NORMAL &&
+	    (colorMod & MS_ARGB(255, 0, 0, 0)) == MS_ARGB(255, 0, 0, 0)) {
+		fillRect(r, colorMod);
+		return;
+	}
+
+	r.clip(w, h);
+
+	if (!r.isValidRect())
+		return;
+
+	BlendBlit::fill(
+		(byte *)getBasePtr(0, 0), pitch,
+		r.width(), r.height(),
+		colorMod, blend);
+
+	// Mark the affected area
+	addDirtyRect(r);
+}
+
 void ManagedSurface::markAllDirty() {
 	addDirtyRect(Common::Rect(0, 0, this->w, this->h));
 }
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
index 23831d07e83..d899e3fc2e1 100644
--- a/graphics/managed_surface.h
+++ b/graphics/managed_surface.h
@@ -767,6 +767,15 @@ public:
 							 const TSpriteBlendMode blend = BLEND_NORMAL,
 							 const AlphaType alphaType = ALPHA_FULL);
 
+	/**
+	 * Fill a rect with a given color and blending mode.
+	 *
+	 * @param r      The rectangle to fill.
+	 * @param color  The color to fill the rect with.
+	 * @param blend 		The blending mode to use.
+	 */
+	void blendFillRect(const Common::Rect r, const uint colorMod, const TSpriteBlendMode blend);
+
 	/**
 	 * Clear the entire surface.
 	 */


Commit: 5f3e0cc9b4e37f49cfe4187b50cde55a5e23990f
    https://github.com/scummvm/scummvm/commit/5f3e0cc9b4e37f49cfe4187b50cde55a5e23990f
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-06-22T14:09:44+03:00

Commit Message:
WINTERMUTE: Make use of ManagedSurface::blendFillRect

Changed paths:
    engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
    engines/wintermute/base/gfx/osystem/render_ticket.cpp


diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index c4068a3b5cc..a9f67bd1198 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -242,17 +242,11 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) {
 
 	modTargetRect(&fillRect);
 
-	uint32 col = _renderSurface->format.ARGBToColor(a, r, g, b);
-
-	Graphics::Surface surf;
-	surf.create((uint16)fillRect.width(), (uint16)fillRect.height(), _renderSurface->format);
-	Common::Rect sizeRect(fillRect);
-	sizeRect.translate(-fillRect.top, -fillRect.left);
-	surf.fillRect(fillRect, col);
+	Common::Rect sizeRect(fillRect.width(), fillRect.height());
 	Graphics::TransformStruct temp = Graphics::TransformStruct();
-	temp._alphaDisable = false;
-	drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp);
-	surf.free();
+	temp._rgbaMod = MS_ARGB(a, r, g, b);
+	temp._alphaDisable = (a == 0xff);
+	drawSurface(nullptr, nullptr, &sizeRect, &fillRect, temp);
 }
 
 Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
index ad633f5770f..a0fed8a9269 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
@@ -93,6 +93,11 @@ bool RenderTicket::operator==(const RenderTicket &t) const {
 
 // Replacement for SDL2's SDL_RenderCopy
 void RenderTicket::drawToSurface(Graphics::ManagedSurface *_targetSurface) const {
+	if (!getSurface()) {
+		_targetSurface->blendFillRect(_dstRect, _transform._rgbaMod, Graphics::BLEND_NORMAL);
+		return;
+	}
+
 	Common::Rect clipRect;
 	clipRect.setWidth(getSurface()->w);
 	clipRect.setHeight(getSurface()->h);
@@ -125,6 +130,11 @@ void RenderTicket::drawToSurface(Graphics::ManagedSurface *_targetSurface) const
 }
 
 void RenderTicket::drawToSurface(Graphics::ManagedSurface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {
+	if (!getSurface()) {
+		_targetSurface->blendFillRect(*dstRect, _transform._rgbaMod, _transform._blendMode);
+		return;
+	}
+
 	bool doDelete = false;
 	if (!clipRect) {
 		doDelete = true;




More information about the Scummvm-git-logs mailing list