vgavideo.c

来自「一个类似windows」· C语言 代码 · 共 1,029 行 · 第 1/2 页

C
1,029
字号
#define _WINBASE_
#define _WINDOWS_H
#include <stdarg.h>
#include <windef.h>
#include <guiddef.h>
#include <wingdi.h>
#include <winddi.h>
#include <winioctl.h>
#include <ntddvdeo.h>
#include <stdlib.h>
#include "vgavideo.h"

#define DDKAPI __stdcall
#define DDKFASTAPI __fastcall
#define FASTCALL __fastcall
#define DDKCDECLAPI __cdecl

VOID DDKAPI WRITE_PORT_UCHAR(IN PUCHAR  Port, IN UCHAR  Value);
VOID DDKAPI WRITE_PORT_USHORT(IN PUSHORT  Port, IN USHORT  Value);

UCHAR PreCalcReverseByte[256];
int maskbit[640];
int y80[480];
int xconv[640];
int bit8[640];
int startmasks[8];
int endmasks[8];
PBYTE vidmem;
static ULONG UnpackPixel[256];

static unsigned char leftMask;
static int byteCounter;
static unsigned char rightMask;

#define READ_REGISTER_UCHAR(p) (*((volatile UCHAR *)(p)))
#define WRITE_REGISTER_UCHAR(p,c) (*((volatile CHAR *)(p))) = (c)


/*int mod(int num, int denom)
{
  div_t dvt = div(num, denom);
  return dvt.rem;
}*/

BYTE bytesPerPixel(ULONG Format)
{
  // This function is taken from /subsys/win32k/eng/surface.c
  // FIXME: GDI bitmaps are supposed to be pixel-packed. Right now if the
  // pixel size if < 1 byte we expand it to 1 byte for simplicities sake

  switch ( Format )
  {
  case BMF_1BPP:
    return 1;

  case BMF_4BPP:
  case BMF_4RLE:
    return 1;

  case BMF_8BPP:
  case BMF_8RLE:
    return 1;

  case BMF_16BPP:
    return 2;

  case BMF_24BPP:
    return 3;

  case BMF_32BPP:
    return 4;

  default:
    return 0;
  }
}

VOID vgaPreCalc()
{
  ULONG j;

  startmasks[0] = 255;
  startmasks[1] = 1;
  startmasks[2] = 3;
  startmasks[3] = 7;
  startmasks[4] = 15;
  startmasks[5] = 31;
  startmasks[6] = 63;
  startmasks[7] = 127;

  endmasks[0] = 0;
  endmasks[1] = 128;
  endmasks[2] = 192;
  endmasks[3] = 224;
  endmasks[4] = 240;
  endmasks[5] = 248;
  endmasks[6] = 252;
  endmasks[7] = 254;

  for(j=0; j<80; j++)
  {
    maskbit[j*8]   = 128;
    maskbit[j*8+1] = 64;
    maskbit[j*8+2] = 32;
    maskbit[j*8+3] = 16;
    maskbit[j*8+4] = 8;
    maskbit[j*8+5] = 4;
    maskbit[j*8+6] = 2;
    maskbit[j*8+7] = 1;

    bit8[j*8]   = 7;
    bit8[j*8+1] = 6;
    bit8[j*8+2] = 5;
    bit8[j*8+3] = 4;
    bit8[j*8+4] = 3;
    bit8[j*8+5] = 2;
    bit8[j*8+6] = 1;
    bit8[j*8+7] = 0;
  }
  for(j=0; j<480; j++)
  {
    y80[j]  = j*80;
  }
  for(j=0; j<640; j++)
  {
    xconv[j] = j >> 3;
  }

  for (j = 0; j < 256; j++)
    {
      PreCalcReverseByte[j] =
	(((j >> 0) & 0x1) << 7) |
	(((j >> 1) & 0x1) << 6) |
	(((j >> 2) & 0x1) << 5) |
	(((j >> 3) & 0x1) << 4) |
	(((j >> 4) & 0x1) << 3) |
	(((j >> 5) & 0x1) << 2) |
	(((j >> 6) & 0x1) << 1) |
	(((j >> 7) & 0x1) << 0);
    }

  for (j = 0; j < 256; j++)
    {
      UnpackPixel[j] =
	(((j >> 0) & 0x1) << 4) |
	(((j >> 1) & 0x1) << 0) |
	(((j >> 2) & 0x1) << 12) |
	(((j >> 3) & 0x1) << 8) |
	(((j >> 4) & 0x1) << 20) |
	(((j >> 5) & 0x1) << 16) |
	(((j >> 6) & 0x1) << 28) |
	(((j >> 7) & 0x1) << 24);
    }
}

void
get_masks(int x, int w)
{
  register int tmp;

  leftMask = rightMask = 0;
  byteCounter = w;
  /* right margin */
  tmp = (x+w) & 7;
  if (tmp) {
    byteCounter -= tmp;
    rightMask = (unsigned char)(0xff00 >> tmp);
  }
  /* left margin */
  tmp = x & 7;
  if (tmp) {
    byteCounter -= (8 - tmp);
    leftMask = (0xff >> tmp);
  }
  /* too small ? */
  if (byteCounter < 0) {
    leftMask &= rightMask;
    rightMask = 0;
    byteCounter = 0;
  }
  byteCounter /= 8;
}

VOID vgaPutPixel(INT x, INT y, UCHAR c)
{
  ULONG offset;
  UCHAR a;

  offset = xconv[x]+y80[y];

  WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
  WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);

  a = READ_REGISTER_UCHAR(vidmem + offset);
  WRITE_REGISTER_UCHAR(vidmem + offset, c);
}

VOID vgaPutByte(INT x, INT y, UCHAR c)
{
  ULONG offset;

  offset = xconv[x]+y80[y];

  // Set the write mode
  WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
  WRITE_PORT_UCHAR((PUCHAR)GRA_D,0xff);

  WRITE_REGISTER_UCHAR(vidmem + offset, c);
}

VOID vgaGetByte(ULONG offset,
                UCHAR *b, UCHAR *g,
                UCHAR *r, UCHAR *i)
{
  WRITE_PORT_USHORT((PUSHORT)GRA_I, 0x0304);
  *i = READ_REGISTER_UCHAR(vidmem + offset);
  WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
  *r = READ_REGISTER_UCHAR(vidmem + offset);
  WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x01);
  *g = READ_REGISTER_UCHAR(vidmem + offset);
  WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
  *b = READ_REGISTER_UCHAR(vidmem + offset);
}

INT vgaGetPixel(INT x, INT y)
{
  UCHAR mask, b, g, r, i;
  ULONG offset;

  offset = xconv[x]+y80[y];
  vgaGetByte(offset, &b, &g, &r, &i);

  mask=maskbit[x];
  b=b&mask;
  g=g&mask;
  r=r&mask;
  i=i&mask;

  mask=bit8[x];
  g=g>>mask;
  b=b>>mask;
  r=r>>mask;
  i=i>>mask;

  return(b+2*g+4*r+8*i);
}

BOOL vgaHLine(INT x, INT y, INT len, UCHAR c)
{
  UCHAR a;
  ULONG pre1;
  ULONG orgpre1, orgx, midpre1;
  LONG ileftpix, imidpix, irightpix;

  orgx = x;

  /*if ( len < 8 )
  {
    for (i = x; i < x+len; i++ )
      vgaPutPixel ( i, y, c );

    return TRUE;
  }*/

  // Calculate the left mask pixels, middle bytes and right mask pixel
  ileftpix = 7 - mod8(x-1);
  irightpix = mod8(x+len);
  imidpix = (len-ileftpix-irightpix) / 8;

  pre1 = xconv[(x-1)&~7] + y80[y];
  orgpre1=pre1;

  // check for overlap ( very short line )
  if ( (ileftpix+irightpix) > len )
  {
    int mask = startmasks[ileftpix] & endmasks[irightpix];
    // Write left pixels
    WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask
    WRITE_PORT_UCHAR((PUCHAR)GRA_D,mask);

    a = READ_REGISTER_UCHAR(vidmem + pre1);
    WRITE_REGISTER_UCHAR(vidmem + pre1, c);

    return TRUE;
  }

  // Left
  if ( ileftpix > 0 )
  {
    // Write left pixels
    WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask
    WRITE_PORT_UCHAR((PUCHAR)GRA_D,startmasks[ileftpix]);

    a = READ_REGISTER_UCHAR(vidmem + pre1);
    WRITE_REGISTER_UCHAR(vidmem + pre1, c);

    // Prepare new x for the middle
    x = orgx + 8;
  }

  if ( imidpix > 0 )
  {
    midpre1 = xconv[x] + y80[y];

    // Set mask to all pixels in byte
    WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
    WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xff);
    memset(vidmem+midpre1, c, imidpix); // write middle pixels, no need to read in latch because of the width
  }

  if ( irightpix > 0 )
  {
    x = orgx + len - irightpix;
    pre1 = xconv[x] + y80[y];

    // Write right pixels
    WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask bits
    WRITE_PORT_UCHAR((PUCHAR)GRA_D, endmasks[irightpix]);
    a = READ_REGISTER_UCHAR(vidmem + pre1);
    WRITE_REGISTER_UCHAR(vidmem + pre1, c);
  }

  return TRUE;
}

BOOL vgaVLine(INT x, INT y, INT len, UCHAR c)
{
  INT offset, i;
  UCHAR a;

  offset = xconv[x]+y80[y];

#ifdef VGA_PERF
  vgaSetBitMaskRegister ( maskbit[x] );
#else
  WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);       // set the mask
  WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);
#endif

  for(i=y; i<y+len; i++)
  {
    a = READ_REGISTER_UCHAR(vidmem + offset);
    WRITE_REGISTER_UCHAR(vidmem + offset, c);
    offset+=80;
  }

  return TRUE;
}

static const RECTL rclEmpty = { 0, 0, 0, 0 };

BOOL VGADDIIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
{
  prcDst->left  = max(prcSrc1->left, prcSrc2->left);
  prcDst->right = min(prcSrc1->right, prcSrc2->right);

  if (prcDst->left < prcDst->right) {
      prcDst->top = max(prcSrc1->top, prcSrc2->top);
      prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);

     if (prcDst->top < prcDst->bottom)
     {
       return TRUE;
     }
  }

  *prcDst = rclEmpty;

  return FALSE;
}

void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
{
  ULONG plane;
  ULONG left = x >> 3;
  ULONG shift = x - (x & ~0x7);
  UCHAR pixel, nextpixel;
  LONG rightcount;
  INT i, j;
  LONG stride = w >> 3;

  /* Calculate the number of rightmost bytes not in a dword block. */
  if (w >= 8)
    {
      rightcount = w % 8;
    }
  else
    {
      stride = 0;
      rightcount = w;
    }

  /* Reset the destination. */
  for (j = 0; j < h; j++)
    {
      memset((PVOID)((ULONG_PTR)b + (j * Dest_lDelta)), 0, abs(Dest_lDelta));
    }

  for (plane = 0; plane < 4; plane++)
    {
      PUCHAR dest = b;

      /* Select the plane we are reading in this iteration. */
      WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);
      WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);

      for (j = 0; j < h; j++)
	{
	  PULONG destline = (PULONG)dest;
	  PUCHAR src = vidmem + (y + j) * SCREEN_STRIDE + left;
	  /* Read the data for one plane for an eight aligned pixel block. */
	  nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src)];
	  for (i = 0; i < stride; i++, src++, destline++)
	    {
	      /* Form the data for one plane for an aligned block in the destination. */
	      pixel = nextpixel;
	      pixel >>= shift;

	      nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
	      pixel |= (nextpixel << (8 - shift));

	      /* Expand the plane data to 'chunky' format and store. */
	      *destline |= (UnpackPixel[pixel] << plane);
	    }
	  /* Handle any pixels not falling into a full block. */
	  if (rightcount != 0)
	    {
	      ULONG row;

	      /* Form the data for a complete block. */
	      pixel = nextpixel;
	      pixel >>= shift;

	      nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
	      pixel |= (nextpixel << (8 - shift));

	      row = UnpackPixel[pixel] << plane;

	      /* Store the data for each pixel in the destination. */
	      for (i = 0; i < rightcount; i++)
		{
		  ((PUCHAR)destline)[i] |= (row & 0xFF);
		  row >>= 8;
		}
	    }
	  dest += Dest_lDelta;
	}
    }

#ifdef VGA_VERIFY
  for (j = 0; j < h; j++)
    {
      for (i = 0; i < w; i+=2)
	{
	  UCHAR c1, c2;
	  ULONG mask = (i < (w - 1)) ? 0xFF : 0xF0;

	  c1 = (vgaGetPixel(x + i, y + j) << 4) | (vgaGetPixel(x + i + 1, y + j));
	  c2 = ((PUCHAR)b)[(j * Dest_lDelta) + (i >> 1)];
	  if ((c1 & mask) != (c2 & mask))
	    {
	      __asm__("int $3\n\t" : /* no outputs */ : /* no inputs */);
	    }
	}
    }
#endif /* VGA_VERIFY */
}

#if 0
void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
//  DIB blt from the VGA.
//  For now we just do slow reads -- pixel by pixel, packing each one into the correct 4BPP format.
{
  PBYTE  pb = b, opb = b;
  BOOLEAN  edgePixel = FALSE;
  ULONG  i, j;
  ULONG  x2 = x + w;
  ULONG  y2 = y + h;
  BYTE  b1, b2;

  // Check if the width is odd
  if(mod2(w)>0)
  {
    edgePixel = TRUE;
    x2 -= 1;
  }

  for (j=y; j<y2; j++)
  {
    for (i=x; i<x2; i+=2)
    {
      b1 = vgaGetPixel(i,  j);
      b2 = vgaGetPixel(i+1,  j);
      *pb = b2 | (b1 << 4);
      pb++;
    }

    if(edgePixel == TRUE)
    {
      b1 = vgaGetPixel(x2, j);
      *pb = b1 << 4;
      pb++;
    }

    opb += Dest_lDelta; // new test code
    pb = opb; // new test code
  }
}
#endif

/* DIB blt to the VGA. */
void DIB_BltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, int StartMod)
{
  PBYTE pb, opb = b;
  LONG i, j;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?