Sorry about the resend, but I used an old copy of the source inadvertently.
I'm new to wine and relatively new to windows programming being mostly a unix hack. Just for yucks I thought I'd get a relatively simple app emu48 to work. Turns out emu48 is not so simple (multi-threaded, etc.). First task towards functionality is to get the boot up display to look right and a BitBlt didn't seem to be functioning correctly.
Much investigation later it turns out that in the file dib.c:
/* if the source bitmap is 8bpp or less, we're supposed to use the * DC's palette for color conversion (not the DIB color table) */
is NOT true at least not for my case where the DC containing the bitmap has one palette and the colormap for the bitmap is not the same. If I disable the hPalette tests as I did below and always use the DIB colormap it boots up with the correct display otherwise the color mapping doesn't match the DIB bits and I get garbage.
if (dib.dsBm.bmBitsPixel <= 8) { HPALETTE hPalette = GetCurrentObject( physDevSrc->hdc, OBJ_PAL ); if (/*!hPalette || (hPalette == GetStockObject(DEFAULT_PALETTE))*/1) { /* HACK: no palette has been set in the source DC, * use the DIB colormap instead - this is necessary in some * cases since we need to do depth conversion in some places * where real Windows can just copy data straight over */ colorMap = physBitmap->colorMap; nColorMap = physBitmap->nColorMap;
} else { colorMap = X11DRV_DIB_BuildColorMap( physDevSrc, (WORD)-1, dib.dsBm.bmBitsPixel, (BITMAPINFO*)&dib.dsBmih, &nColorMap ); if (colorMap) aColorMap = TRUE; } }
Not knowing the full ramifications of this code I thought I'd pass this along so that someone more familiar with it can reassess it.
The DC and bitmap are created thusly (nLcdDoubled == 2):
#define B 0x00000000 #define W 0x00FFFFFF #define I 0xFFFFFFFF static struct { BITMAPINFOHEADER Lcd_bmih; DWORD dwColor[64]; } bmiLcd = { {0x28,0/*x*/,0/*y*/,1,8,BI_RGB,0,0,0,64,0}, { W,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I } }; VOID CreateLcdBitmap(VOID) { // create LCD bitmap _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); bmiLcd.Lcd_bmih.biWidth = LCD1_ROW * nLcdDoubled; bmiLcd.Lcd_bmih.biHeight = -64 * nLcdDoubled; hLcdDC = CreateCompatibleDC(hWindowDC); _ASSERT(hLcdDC != NULL); hLcdBitmap = CreateDIBSection(hLcdDC, (BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS, (LPVOID*)&pbyLcd, NULL, 0); _ASSERT(hLcdBitmap != NULL); hOldLcdBitmap = SelectObject(hLcdDC, hLcdBitmap); _ASSERT(hPalette != NULL); SelectPalette(hLcdDC, hPalette, FALSE); // set palette for LCD DC RealizePalette(hLcdDC); // realize palette UpdateContrast(Chipset.contrast); } In the new source update contrast doesn't do a SetDIBColorTable it just plays with the pattern used to write to the dib. static DWORD Pattern[16];
VOID UpdateContrast(BYTE byContrast) { DWORD c = byContrast; DWORD b = byContrast + 0x20; if (bmiLcd.dwColor[b] == 0xFFFFFFFF) b = 0;
_ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4);
if (nLcdDoubled == 1) { WORD i,j; for (i=0; i<16; ++i) { Pattern[i] = 0; for (j=8; j>0; j>>=1) { Pattern[i] = (Pattern[i] << 8) | ((i&j) ? c : b); } } return; }
c = (c<<8) | c; b = (b<<8) | b;
if (nLcdDoubled == 2) { Pattern[0] = (b<<16)|b; Pattern[1] = (b<<16)|c; Pattern[2] = (c<<16)|b; Pattern[3] = (c<<16)|c; return; }
c = (c<<16) | c; b = (b<<16) | b;
if (nLcdDoubled == 4) { Pattern[0] = b; Pattern[1] = c; } return; } The BitBlt: static BYTE Buf[36];
VOID UpdateMainDisplay(VOID) { UINT x, y, nLines; DWORD d = Chipset.start1; BYTE *p = pbyLcd;
#if defined DEBUG_DISPLAY { TCHAR buffer[256]; wsprintf(buffer,_T("%.5lx: Update Main Display\n"),Chipset.pc); OutputDebugString(buffer); } #endif
_ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); if (!Chipset.dispon) { nLines = 64; ZeroMemory(pbyLcd, LCD1_ROW * nLcdDoubled * nLines * nLcdDoubled); } else { nLines = LINES(Chipset.lcounter); // main display lines if (nLcdDoubled == 4) { for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) { *(((DWORD*)p)++)=Pattern[Buf[x]&1]; *(((DWORD*)p)++)=Pattern[(Buf[x]>>1) & 1]; *(((DWORD*)p)++)=Pattern[(Buf[x]>>2) & 1]; *(((DWORD*)p)++)=Pattern[(Buf[x]>>3) & 1]; } CopyMemory(p, p-LCD3_ROW, LCD3_ROW); p+=LCD3_ROW; CopyMemory(p, p-LCD3_ROW*2, LCD3_ROW*2); p+=LCD3_ROW*2; d+=Chipset.width; } } if (nLcdDoubled == 2) { for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) { *(((DWORD*)p)++)=Pattern[Buf[x]&3]; *(((DWORD*)p)++)=Pattern[Buf[x]>>2]; } CopyMemory(p, p-LCD2_ROW, LCD2_ROW); p+=LCD2_ROW; d+=Chipset.width; } } if (nLcdDoubled == 1) { for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) *(((DWORD*)p)++)=Pattern[Buf[x]]; d+=Chipset.width; } } } EnterCriticalSection(&csGDILock); // solving NT GDI problems { BitBlt(hWindowDC, nLcdX, nLcdY, 131*nLcdDoubled, nLines*nLcdDoubled, hLcdDC, Chipset.boffset*nLcdDoubled, 0, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); return; }
As emu48 still doesn't work I'll probably have more things I find in likely much different areas later.
Dave
tir, 07,.06.2005 kl. 23.00 -0700, skrev David Albrecht:
VOID CreateLcdBitmap(VOID) { // create LCD bitmap _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); bmiLcd.Lcd_bmih.biWidth = LCD1_ROW * nLcdDoubled; bmiLcd.Lcd_bmih.biHeight = -64 * nLcdDoubled; hLcdDC = CreateCompatibleDC(hWindowDC); _ASSERT(hLcdDC != NULL); hLcdBitmap = CreateDIBSection(hLcdDC, (BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS, (LPVOID*)&pbyLcd, NULL, 0); _ASSERT(hLcdBitmap != NULL); hOldLcdBitmap = SelectObject(hLcdDC, hLcdBitmap); _ASSERT(hPalette != NULL); SelectPalette(hLcdDC, hPalette, FALSE); // set palette for LCD DC RealizePalette(hLcdDC); // realize palette UpdateContrast(Chipset.contrast); }
When creating a memory DC for an 8-bit DIB section, it is normal to create a palette matching the DIB color table, then just selecting it into that DC. In such usage, RealizePalette is not used. Perhaps there's an explanation to be found in that direction.
MSDN says, for example:
"The RealizePalette function modifies the palette for the device associated with the specified device context. If the device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device context is a display DC, the physical palette for that device is modified."
This suggests that RealizePalette should set the DIB color table from the palette, something Wine might not do properly. Although this is the opposite of your hack, it does make the palette and the DIB color table identical again, so perhaps it would still work for you.
This code only does RealisePalette once when it creates the device context but it updates the color table whenever the calculator contrast gets updated in the latest code, followed by a SetDIBColorTable. Maybe the problem is there or maybe there is some condition for going to the color map rather than the palette that the test in dib.c doesn't currently capture. I'll do some monkeying around with the MinGW version under windows and look at the palette vs. the color map to see if windows keeps them in sync. I downloaded the very latest version (1.36) and it behaves much better. The lcd display palette is still mucked up but it is a legible black and white and everything else I tried works. If I do my little hack in dib.c with regards to the palette then even the lcd display looks right so its already on the working list and if I can figure out the right answer it will be on the fully working list. Cool!
Dave Dave At 07:04 PM 6/8/2005, you wrote:
tir, 07,.06.2005 kl. 23.00 -0700, skrev David Albrecht:
VOID CreateLcdBitmap(VOID) { // create LCD bitmap _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); bmiLcd.Lcd_bmih.biWidth = LCD1_ROW * nLcdDoubled; bmiLcd.Lcd_bmih.biHeight = -64 * nLcdDoubled; hLcdDC = CreateCompatibleDC(hWindowDC); _ASSERT(hLcdDC != NULL); hLcdBitmap = CreateDIBSection(hLcdDC, (BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS, (LPVOID*)&pbyLcd, NULL, 0); _ASSERT(hLcdBitmap != NULL); hOldLcdBitmap = SelectObject(hLcdDC, hLcdBitmap); _ASSERT(hPalette != NULL); SelectPalette(hLcdDC, hPalette, FALSE); // set palette for LCD DC RealizePalette(hLcdDC); //
realize palette
UpdateContrast(Chipset.contrast);
}
When creating a memory DC for an 8-bit DIB section, it is normal to create a palette matching the DIB color table, then just selecting it into that DC. In such usage, RealizePalette is not used. Perhaps there's an explanation to be found in that direction.
MSDN says, for example:
"The RealizePalette function modifies the palette for the device associated with the specified device context. If the device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device context is a display DC, the physical palette for that device is modified."
This suggests that RealizePalette should set the DIB color table from the palette, something Wine might not do properly. Although this is the opposite of your hack, it does make the palette and the DIB color table identical again, so perhaps it would still work for you.