Repository: mamedev/mame
Pull request #13400: konamigx_v.cpp, konamigx.h: implement brightness for layers
Author: login: FredYeye
Created: 2025-02-22T19:24:56Z | Merged: 2025-03-01T18:19:33Z

This applies the K054338 brightness level registers / K055555 brightness index registers when drawing layers A-D. This affects many games since it's commonly used for screen transitions, though a more striking example is of course the `mmaulers` intro.

This works by updating the palette contrast every time a layer wants to use a different brightness than the current brightness when getting drawn.

---

I don't know if the `m_palette->set_pen_contrast()` loop is the best way to do this. It could be terrible for all I know! It works though, so it can be improved from here if necessary.

Also, I suppose this could be applied to the sub layers (and sprites) as well? My understanding of those is a bit flaky though. I'm slowly learning as I go. 😂

I'll go ahead and mark this as a draft for now - I'll freely admit that in my excitement, I created this PR right after making the changes and only testing a few games, haha. I'll get to testing more.


Diff:
diff --git a/src/mame/konami/konamigx.h b/src/mame/konami/konamigx.h
index 7336d7ba96320..e877cf2985bc8 100644
--- a/src/mame/konami/konamigx.h
+++ b/src/mame/konami/konamigx.h
@@ -144,6 +144,7 @@ class konamigx_state : public driver_device
 	void konamigx_precache_registers(void);
 
 	void wipezbuf(int noshadow);
+	void set_brightness(int layer);
 
 	void dmastart_callback(int data);
 
@@ -247,6 +248,9 @@ class konamigx_state : public driver_device
 	uint16_t *m_gx_spriteram = nullptr;
 	std::unique_ptr<uint16_t[]> m_gx_spriteram_alloc;
 
+	u8 m_current_brightness = 0xff;
+	u8 m_brightness[3]{};
+
 	// mirrored K054338 settings
 	int *m_K054338_shdRGB = nullptr;
 
diff --git a/src/mame/konami/konamigx_m.cpp b/src/mame/konami/konamigx_m.cpp
index 26bf5f14ab928..0727f446efdb8 100644
--- a/src/mame/konami/konamigx_m.cpp
+++ b/src/mame/konami/konamigx_m.cpp
@@ -53,8 +53,8 @@ uint16_t konamigx_state::K055550_word_r(offs_t offset)
 void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_mask)
 {
 	auto &mspace = m_maincpu->space(AS_PROGRAM);
-	uint32_t adr, bsize, count, i, lim;
-	int src, tgt, srcend, tgtend, skip, cx1, sx1, wx1, cy1, sy1, wy1, cz1, sz1, wz1, c2, s2, w2;
+	uint32_t adr, bsize, count, i, lim, src, dst;
+	int tgt, srcend, tgtend, skip, cx1, sx1, wx1, cy1, sy1, wy1, cz1, sz1, wz1, c2, s2, w2;
 	int dx, dy, angle;
 
 	COMBINE_DATA(m_prot_data+offset);
@@ -71,10 +71,25 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 				count = (m_prot_data[0] & 0xff) + 1;
 
 				lim = adr+bsize*count;
-				for(i=adr; i<lim; i+=2)
+				for (i = adr; i < lim; i += 2)
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				src = (m_prot_data[2] << 16) | m_prot_data[3];
+				count = (m_prot_data[10] << 16 | m_prot_data[11]) >> 2;
+
+				for (int x = 0; x < count; ++x)
+				{
+					const u32 src_data = mspace.read_dword(src + x * 8);
+					mspace.write_dword(dst + x * 4, src_data);
+				}
+			break;
+
 			// WARNING: The following cases are speculation based with questionable accuracy!(AAT)
 
 			case 0x87: // unknown memory write (Violent Storm at 0x00b6ea)
@@ -101,7 +116,7 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 				tgtend = srcend + bsize;
 
 				// let's hope GCC will inline the mem24bew calls
-				for (src=adr; src<srcend; src+=bsize)
+				for (src = adr; src < srcend; src += bsize)
 				{
 					cx1 = (short)mspace.read_word(src);
 					sx1 = (short)mspace.read_word(src + 2);
@@ -118,24 +133,24 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					count = i = src + skip;
 					tgt = src + bsize;
 
-					for (; count<tgt; count++) mspace.write_byte(count, 0);
+					for (; count < tgt; count++) mspace.write_byte(count, 0);
 
-					for (; tgt<tgtend; i++, tgt+=bsize)
+					for (; tgt < tgtend; i++, tgt += bsize)
 					{
 						c2 = (short)mspace.read_word(tgt);
 						s2 = (short)mspace.read_word(tgt + 2);
 						w2 = (short)mspace.read_word(tgt + 4);
-						if (abs((cx1+sx1)-(c2+s2))>=wx1+w2) continue; // X rejection
+						if (abs((cx1 + sx1) - (c2 + s2)) >= wx1 + w2) continue; // X rejection
 
 						c2 = (short)mspace.read_word(tgt + 6);
 						s2 = (short)mspace.read_word(tgt + 8);
 						w2 = (short)mspace.read_word(tgt +10);
-						if (abs((cy1+sy1)-(c2+s2))>=wy1+w2) continue; // Y rejection
+						if (abs((cy1 + sy1) - (c2 + s2)) >= wy1 + w2) continue; // Y rejection
 
 						c2 = (short)mspace.read_word(tgt +12);
 						s2 = (short)mspace.read_word(tgt +14);
 						w2 = (short)mspace.read_word(tgt +16);
-						if (abs((cz1+sz1)-(c2+s2))>=wz1+w2) continue; // Z rejection
+						if (abs((cz1 + sz1) - (c2 + s2)) >= wz1 + w2) continue; // Z rejection
 
 						mspace.write_byte(i, 0x80); // collision confirmed
 					}
@@ -211,13 +226,13 @@ void konamigx_state::K053990_martchmp_word_w(offs_t offset, uint16_t data, uint1
 				dst_skip += element_size;
 
 				if (element_size == 1)
-				for (i=src_count; i; i--)
+				for (i = src_count; i; i--)
 				{
 					mspace.write_byte(dst_addr, mspace.read_byte(src_addr));
 					src_addr += src_skip;
 					dst_addr += dst_skip;
 				}
-				else for (i=src_count; i; i--)
+				else for (i = src_count; i; i--)
 				{
 					mspace.write_word(dst_addr, mspace.read_word(src_addr));
 					src_addr += src_skip;
@@ -387,7 +402,7 @@ if((data1=obj[0])&0x80000000)\
 				case 0x11010010: i = 5; vmask = 0x1ff; break;
 				case 0x01111018: i = 4; break;
 				case 0x10010011: i = 3;
-					if ((srcbase[0x1c75]&0xff)==32) m_k055555->K055555_write_reg(K55_BLEND_ENABLES,36); // (TEMPORARY)
+					if ((srcbase[0x1c75] & 0xff) == 32) m_k055555->K055555_write_reg(K55_BLEND_ENABLES,36); // (TEMPORARY)
 				break;
 				case 0x11010811: i = 2; break;
 				case 0x10000010: i = 1; break;
@@ -424,8 +439,8 @@ if((data1=obj[0])&0x80000000)\
 		// decode Lord British (the designer must be a Richard Garriot fan too:)
 		if (srcbase[0x0848/4] & 0x0000ffff)
 		{
-			hoffs = srcbase[0x08b0/4]>>16;
-			voffs = srcbase[0x08b4/4]>>16;
+			hoffs = srcbase[0x08b0/4] >> 16;
+			voffs = srcbase[0x08b4/4] >> 16;
 			hoffs -= hcorr;
 			voffs -= vcorr;
 			obj = &srcbase[0x084c/4];
@@ -445,8 +460,8 @@ if((data1=obj[0])&0x80000000)\
 			i = src[7] & 0xf;
 			if (!i) continue; // reject retired or zero-element groups
 			i <<= 2;
-			hoffs = src[5]>>16;
-			voffs = src[6]>>16;
+			hoffs = src[5] >> 16;
+			voffs = src[6] >> 16;
 			hoffs -= hcorr;
 			voffs -= vcorr;
 			obj = src + 8;
@@ -456,9 +471,9 @@ if((data1=obj[0])&0x80000000)\
 			{
 				EXTRACT_EVEN
 			}
-			while ((obj+=4)<objend);
+			while ((obj += 4) < objend);
 		}
-		while ((src+=0x30)<srcend);
+		while ((src += 0x30) < srcend);
 
 		// clear residual data
 		if (j) do { *dst = 0; dst += 8; } while (--j);
@@ -480,7 +495,7 @@ void konamigx_state::fantjour_dma_w(offs_t offset, uint32_t data, uint32_t mem_m
 {
 	auto &mspace = m_maincpu->space(AS_PROGRAM);
 	COMBINE_DATA(m_fantjour_dma + offset);
-	if(!offset && ACCESSING_BITS_24_31) {
+	if (!offset && ACCESSING_BITS_24_31) {
 		uint32_t sa = m_fantjour_dma[1];
 		//      uint16_t ss = (m_fantjour_dma[2] & 0xffff0000) >> 16;
 		//      uint32_t sb = ((m_fantjour_dma[2] & 0xffff) << 16) | ((m_fantjour_dma[3] & 0xffff0000) >> 16);
@@ -496,16 +511,18 @@ void konamigx_state::fantjour_dma_w(offs_t offset, uint32_t data, uint32_t mem_m
 		uint32_t x   = m_fantjour_dma[6];
 		uint32_t i1, i2;
 
-		if(mode == 0x93)
-			for(i1=0; i1 <= sz2; i1++)
-				for(i2=0; i2 < db; i2+=4) {
+		if (mode == 0x93)
+			for (i1 = 0; i1 <= sz2; i1++)
+				for (i2 = 0; i2 < db; i2 += 4)
+				{
 					mspace.write_dword(da, mspace.read_dword(sa) ^ x);
 					da += 4;
 					sa += 4;
 				}
-		else if(mode == 0x8f)
-			for(i1=0; i1 <= sz2; i1++)
-				for(i2=0; i2 < db; i2+=4) {
+		else if (mode == 0x8f)
+			for (i1 = 0; i1 <= sz2; i1++)
+				for (i2 = 0; i2 < db; i2 += 4)
+				{
 					mspace.write_dword(da, x);
 					da += 4;
 				}
diff --git a/src/mame/konami/konamigx_v.cpp b/src/mame/konami/konamigx_v.cpp
index 2f1cf7a07c1de..cdde3894abf93 100644
--- a/src/mame/konami/konamigx_v.cpp
+++ b/src/mame/konami/konamigx_v.cpp
@@ -54,6 +54,10 @@ void konamigx_state::konamigx_precache_registers(void)
 	m_vmixon   = m_k055555->K055555_read_register(K55_VINMIX_ON);
 	m_osinmix  = m_k055555->K055555_read_register(K55_OSBLEND_ENABLES);
 	m_osmixon  = m_k055555->K055555_read_register(K55_OSBLEND_ON);
+
+	m_brightness[0] = u8(m_k054338->register_r(K338_REG_BRI3));
+	m_brightness[1] = u8(m_k054338->register_r(K338_REG_BRI3 + 1) >> 8);
+	m_brightness[2] = u8(m_k054338->register_r(K338_REG_BRI3 + 1));
 }
 
 inline int konamigx_state::K053247GX_combine_c18(int attrib) // (see p.46)
@@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = bri_mode ? m_brightness[bri_mode - 1] : 0xff;
+
+	if (m_current_brightness != new_brightness)
+	{
+		m_current_brightness = new_brightness;
+		for (int x = 0; x < m_palette->entries(); ++x)
+		{
+			m_palette->set_pen_contrast(x, m_current_brightness / 255.0);
+		}
+	}
+}
+
 /*
  * Sprite Format
  * ------------------
@@ -664,6 +684,8 @@ void konamigx_state::gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32
 	int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
 	if (disp & (1<<code))
 	{
+		set_brightness(code);
+
 		if (j == GXMIX_BLEND_NONE)  { temp1 = 0xff; temp2 = temp3 = 0; } else
 		if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>(i+16); temp3 = 3; }
 		else
@@ -1135,6 +1157,8 @@ void konamigx_state::common_init()
 	save_item(NAME(m_vmixon));
 	save_item(NAME(m_osinmix));
 	save_item(NAME(m_osmixon));
+	save_item(NAME(m_current_brightness));
+	save_item(NAME(m_brightness));
 
 	m_gx_tilemode = 0;
 


Reviews:
user: login: cuavas
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T12:55:25Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T13:34:26Z
user: login: cuavas
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T13:35:59Z
user: login: angelosa
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T13:39:37Z
user: login: angelosa
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T13:41:11Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T13:53:36Z
user: login: happppp
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T13:58:31Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T14:01:44Z
user: login: happppp
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T14:03:25Z
user: login: angelosa
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-26T14:07:15Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T14:35:13Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T20:24:23Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T20:24:32Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T20:24:46Z
user: login: happppp
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-01T13:14:51Z
user: login: FredYeye
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-01T18:17:25Z

Review comments:
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: cuavas
body: Aren’t these shadowing other locals in the function with the same names?  I’d rather you avoid that.
created_at: 2025-02-26T12:52:29Z
author_association: MEMBER
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = (bri_mode) ? m_brightness[bri_mode - 1] : 0xff;
+
+	if (m_current_brightness != new_brightness)
+	{
+		m_current_brightness = new_brightness;
+		for (int y = 0; y < 2048; ++y)
+		{
+			m_palette->set_pen_contrast(y,m_current_brightness / 255.0);
+		}
path: src/mame/konami/konamigx_v.cpp
user: login: cuavas
body: Missing space after the first comma.
created_at: 2025-02-26T12:54:34Z
author_association: MEMBER
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = (bri_mode) ? m_brightness[bri_mode - 1] : 0xff;
path: src/mame/konami/konamigx_v.cpp
user: login: cuavas
body: Extraneous parentheses here – it’s not like `bri_mode` is a macro argument that can expand to something non-trivial.
created_at: 2025-02-26T12:55:14Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: FredYeye
body: Right, would you prefer I reuse those variables or simply rename these?
created_at: 2025-02-26T13:34:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: cuavas
body: If you’re only updating this op, just use the ones declared outside the `switch` to make it uniform with the other ops.
created_at: 2025-02-26T13:35:59Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: angelosa
body: Reuse, also those specifically should be `u32` not `int` on top being inherently bus transfers.
created_at: 2025-02-26T13:39:37Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: angelosa
body: Also the math for count is a bit off: is `m_prot_data[10]` just zeroed for now and this is really expecting byte transfers?
created_at: 2025-02-26T13:41:11Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: FredYeye
body: Yes... I'm not at all convinced this is the correct count variable, or at least not used like this. The problem is that this is the only use of the 0x98 "mode" i can find, so it's hard to know for sure what the writes mean. There are several things i could do here i guess, one is to hard code all the unknowns... i'll gladly take suggestions here
created_at: 2025-02-26T13:53:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: happppp
body: Does this make more sense? const u32 count = (m_prot_data[10] << 16 | m_prot_data[11]) >> 2; Note the added parentheses.
It looks like byte count, and your implementation transfers dwords.
created_at: 2025-02-26T13:58:31Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: FredYeye
body: I made the loop transfer dwords, as the data it's sending is 32 bit color data. I suppose this doesn't have to mean it's transferring in 32 bit chunks though, words might be more realistic?
created_at: 2025-02-26T14:01:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: happppp
body: I mean: x = byte count, x >> 2 divides by 4 and is dword count.
Right now: y+(x/4)
Makes more sense: (y+x)/4
created_at: 2025-02-26T14:03:25Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: angelosa
body: The function itself could do with a `logmacro.h` filtered logging when triggering these functions (I don't expect you to do it in this PR), beyond that I presume it's using a setting bit for the different source increment, another one for enabling byte transfers. If you have more than two blanks compared to any other command then yeah, it's simply not feasible for now.
created_at: 2025-02-26T14:07:15Z
author_association: MEMBER
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: FredYeye
body: > I mean: x = byte count, x >> 2 divides by 4 and is dword count. Right now: y+(x/4) Makes more sense: (y+x)/4

Ah, yes... i didn't think about the parens, i see what you mean now.

---

> beyond that I presume it's using a setting bit for the different source increment, another one for enabling byte transfers. If you have more than two blanks compared to any other command then yeah, it's simply not feasible for now.

Yeah, there has to be some flags that set increments and such. I'm not sure I can figure this out at the moment.
Logging is probably a good idea too.

---

I can do a few things here:
1. hardcode register usage that isn't guaranteed to be correct (remove `count` variable, hardcode loop count).
2. use `count = (m_prot_data[10] << 16 | m_prot_data[11]) >> 2` (maybe incorrect usage)
3. hold off on these changes and see if i can come up witrh anything better at a later time.
created_at: 2025-02-26T14:35:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,23 @@ void konamigx_state::K055550_word_w(offs_t offset, uint16_t data, uint16_t mem_m
 					mspace.write_word(i, m_prot_data[0x1a/2]);
 			break;
 
+			case 0x98: // memcpy of some kind. incomplete
+			{
+				// known use cases:
+				// viostorm: transfer "color check" palette
+
+				const u32 dst = (m_prot_data[7] << 16) | m_prot_data[8];
+				const u32 src = (m_prot_data[2] << 16) | m_prot_data[3];
+				const u32 count = m_prot_data[10] << 16 | m_prot_data[11] >> 2;
path: src/mame/konami/konamigx_m.cpp
user: login: FredYeye
body: i've now changed it to use variables outside the switch case. also fixed the calculation of the count variable.
created_at: 2025-02-26T20:24:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = (bri_mode) ? m_brightness[bri_mode - 1] : 0xff;
+
+	if (m_current_brightness != new_brightness)
+	{
+		m_current_brightness = new_brightness;
+		for (int y = 0; y < 2048; ++y)
+		{
+			m_palette->set_pen_contrast(y,m_current_brightness / 255.0);
+		}
path: src/mame/konami/konamigx_v.cpp
user: login: FredYeye
body: Fixed.
created_at: 2025-02-26T20:24:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = (bri_mode) ? m_brightness[bri_mode - 1] : 0xff;
path: src/mame/konami/konamigx_v.cpp
user: login: FredYeye
body: Fixed.
created_at: 2025-02-26T20:24:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = bri_mode ? m_brightness[bri_mode - 1] : 0xff;
+
+	if (m_current_brightness != new_brightness)
+	{
+		m_current_brightness = new_brightness;
+		for (int y = 0; y < 2048; ++y)
path: src/mame/konami/konamigx_v.cpp
user: login: happppp
body: Is this 2048 number m_palette->entries()? Then better use that.
created_at: 2025-03-01T13:14:51Z
author_association: MEMBER
diff_hunk: @@ -243,6 +247,22 @@ void konamigx_state::wipezbuf(int noshadow)
 	}
 }
 
+void konamigx_state::set_brightness(int layer)
+{
+	const u8 bri_mode = (m_k055555->K055555_read_register(K55_VBRI) >> layer * 2) & 0b11;
+
+	const u8 new_brightness = bri_mode ? m_brightness[bri_mode - 1] : 0xff;
+
+	if (m_current_brightness != new_brightness)
+	{
+		m_current_brightness = new_brightness;
+		for (int y = 0; y < 2048; ++y)
path: src/mame/konami/konamigx_v.cpp
user: login: FredYeye
body: Convenient, thank you!
created_at: 2025-03-01T18:17:25Z
author_association: CONTRIBUTOR

PR comments:
user: login: TheCoolPup
created_at: 2025-02-22T21:35:10Z
body: If I'm correct this may help with the title screen bug on mystic warriors, will test when the windows build is available
author_association: NONE
user: login: TheCoolPup
created_at: 2025-02-22T21:58:03Z
body: ok so did some testing, violent storm benefited from this fix since it transitions nicely to the first stage now but it seems some of the other transition bugs are something else entirely, same goes along with mystic warriors
author_association: NONE
user: login: FredYeye
created_at: 2025-02-23T10:31:46Z
body: Alright, I tested more games and it *seems* to be working as intended. I think I need to quiz Galibert about some of the K055555 regs before applying this on the sub layers, but the current changes make a nice difference already.
author_association: CONTRIBUTOR
user: login: TheCoolPup
created_at: 2025-02-23T13:39:28Z
body: With this fix, I think the video emulation is around 90% there, only missing is just a few transitions and then we are golden, thank you again for putting in the time and effort to fix these decade old bugs!
author_association: NONE
user: login: FredYeye
created_at: 2025-02-24T00:22:15Z
body: I went ahead and added an incomplete but working implementation of some type of memcpy on the 55550, I hope it's fine to add to this PR I've already opened. It makes the `viostorm` color check palette transfer properly.

Not at all confident about what is supposed to be the size parameter, but cases 0x97 / 0x9F uses the same register as a byte count, so there's that.  0x80 and 0x40 could somehow be related to the step size too, I'd really need another test case to confirm.

See https://github.com/mamedev/mame/issues/13394 for more details.
author_association: CONTRIBUTOR
user: login: JimCarlTay
created_at: 2025-02-24T11:53:48Z
body: > With this fix, I think the video emulation is around 90% there, only missing is just a few transitions and then we are golden, thank you again for putting in the time and effort to fix these decade old bugs!

The few ones left (from what I saw on the mystwarr driver) are the missing background color change on the Mystic Warriors title screen (from white to black, with the game logo text changing from black to red and the crescent moon appearing on a night sky), and the missing Konami wordmark and copyright text on the Metamorphic Force title screen.

Also, recent nightlies (probably originating from a previous pull request by FredYeye on some blending fixes) have improved the background blending on the shot with Athena and the animals during the opening of Metamorphic Force, but it looks like it could use some improvement somehow, with some stray differently shaded blocks and lines on display as opposed to the blending being cleanly rendered on real hardware.

![0000](https://github.com/user-attachments/assets/60487beb-7820-40c4-9fc4-f5c9e14492ec)
author_association: CONTRIBUTOR
user: login: FredYeye
created_at: 2025-02-24T13:04:11Z
body: Yeah, I've seen those lines too! I have an idea why that happens (stacked transparent sprites). I will see if I can figure out a solution eventually.
author_association: CONTRIBUTOR
user: login: FredYeye
created_at: 2025-02-24T16:03:16Z
body: Maybe TMI, but I slipped on the ice today and dislocated my shoulder. I'm okay, but i'll be on a break from researching and coding for a while. I can handle the reviews for this PR though.
author_association: CONTRIBUTOR
user: login: TheCoolPup
created_at: 2025-02-24T18:20:04Z
body: 
OOF, hope you get better, again thank you for the whole heap of fixes
author_association: NONE
user: login: TheCoolPup
created_at: 2025-02-24T18:22:32Z
body: Also i have noticed some of the fixes also helps games like gaiapolis and violent storm, but gaiapolis has those black squares on the map so I'm wondering if that's some kind of transparency issue
author_association: NONE
user: login: cuavas
created_at: 2025-02-26T12:55:44Z
body: @galibert what’s your opinion on this?
author_association: MEMBER
user: login: happppp
created_at: 2025-03-01T13:22:47Z
body: For the 2 variables you added, could you add save_item to konamigx_state::common_init()?
author_association: MEMBER
user: login: FredYeye
created_at: 2025-03-01T18:19:34Z
body: > For the 2 variables you added, could you add save_item to konamigx_state::common_init()?

Ok! I added them.
author_association: CONTRIBUTOR