Problems in bitblt (in x11drv)

David Albrecht davidca at writeme.com
Wed Jun 8 01:00:35 CDT 2005


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




More information about the wine-devel mailing list