[ros-dev] DIB code generator

Ge van Geldorp gvg at reactos.com
Fri Jun 10 13:03:15 CEST 2005


One of the things which has bothered me a bit is the code duplication we
have in our DIB engine (subsys/win32k/dib). Most of the BitBlt routines in
there are very similar. With the recent interest in optimizations a bunch of
new (almost identical) routines were added. Don't get me wrong, I'm not
saying that adding those optimizations was a bad idea, I'm just pointing out
that we have a lot of code duplication.

There are 256 possible ROP codes, we support 1bpp, 4bpp, 8bpp, 16bpp, 24bpp
and 32bpp, so in theory there could be 1536 routines with basically the same
structure. I've been playing around with the idea to write a code generator
which would generate the source code for those routines. That would cut down
on the duplicated source code and associated maintenance problems (you only
need to change the code generator) while still allowing optimized code for
each individual ROP code.

Just to give you an idea what such a code generator would look like, I've
attached my first attempt. Please note that it doesn't really try to
optimize the generated code yet, it's just to give an impression. The code
generated (16bpp only atm) is rather large, you can get it from
ftp://ftp.geldorp.nl/pub/ReactOS/dib16gen.c if you like (or compile the code
generator ("gcc -o gendib gendib.c") and run it).

A possible problem is that the generated code is quite large. When using the
generated 16bpp code, size of win32k.sys increases by about 350kb.
Extrapolating this for all bpps, it would mean that win32k.sys would triple
in size.

So, I'm wondering what you guys are thinking. Should we basically trade
memory for speed? Problem is that I can't quantify the speed increase at the
moment.

Gé van Geldorp.
-------------- next part --------------
#include <stdio.h>

#define USES_DEST(RopCode)    ((((RopCode) & 0xaa) >> 1) != ((RopCode) & 0x55))
#define USES_SOURCE(RopCode)  ((((RopCode) & 0xcc) >> 2) != ((RopCode) & 0x33))
#define USES_PATTERN(RopCode) ((((RopCode) & 0xf0) >> 4) != ((RopCode) & 0x0f))

static void
PrintRoutineName(FILE *Out, unsigned Bpp, unsigned RopCode)
{
  static struct
    {
      unsigned RopCode;
      char *Name;
    }
  KnownCodes[] =
    {
      { 0x00, "BLACKNESS" },
      { 0x11, "NOTSRCERASE" },
      { 0x33, "NOTSRCCOPY" },
      { 0x44, "SRCERASE" },
      { 0x55, "DSTINVERT" },
      { 0x5a, "PATINVERT" },
      { 0x66, "SRCINVERT" },
      { 0x88, "SRCAND" },
      { 0xbb, "MERGEPAINT" },
      { 0xc0, "MERGECOPY" },
      { 0xcc, "SRCCOPY" },
      { 0xee, "SRCPAINT" },
      { 0xf0, "PATCOPY" },
      { 0xfb, "PATPAINT" },
      { 0xff, "WHITENESS" }
    };
  unsigned Index;

  for (Index = 0; Index < sizeof(KnownCodes) / sizeof(KnownCodes[0]); Index++)
    {
      if (RopCode == KnownCodes[Index].RopCode)
        {
          fprintf(Out, "DIB_%uBPP_BitBlt_%s", Bpp, KnownCodes[Index].Name);
          return;
        }
    }
  fprintf(Out, "DIB_%uBPP_BitBlt_%02x", Bpp, RopCode);
}

static void
CreatePrimitive(FILE *Out, unsigned Bpp, unsigned RopCode)
{
  int UsesSource;
  int UsesPattern;
  int UsesDest;

  UsesSource = USES_SOURCE(RopCode);
  UsesPattern = USES_PATTERN(RopCode);
  UsesDest = USES_DEST(RopCode);

  fprintf(Out, "\n");
  fprintf(Out, "static void\n");
  PrintRoutineName(Out, Bpp, RopCode);
  fprintf(Out, "(PBLTINFO BltInfo)\n");
  fprintf(Out, "{\n");
  fprintf(Out, "  ULONG DestX, DestY;\n");
  if (UsesSource)
    {
      fprintf(Out, "  ULONG SourceX, SourceY;\n");
    }
  if (UsesPattern)
    {
      fprintf(Out, "  ULONG PatternY = 0;\n");
    }
  fprintf(Out, "  ULONG Dest = 0, Source = 0, Pattern = 0;\n");
  fprintf(Out, "  PULONG DestBits;\n");
  fprintf(Out, "  ULONG RoundedRight;\n");
  fprintf(Out, "\n");
  fprintf(Out, "  RoundedRight = BltInfo->DestRect.right -\n");
  fprintf(Out, "                 ((BltInfo->DestRect.right - BltInfo->DestRect.left) & 0x1);\n");
  if (UsesSource)
    {
      fprintf(Out, "  SourceY = BltInfo->SourcePoint.y;\n");
    }
  fprintf(Out, "  DestBits = (PULONG)(\n");
  fprintf(Out, "     BltInfo->DestSurface->pvScan0 +\n");
  fprintf(Out, "     (BltInfo->DestRect.left << 1) +\n");
  fprintf(Out, "     BltInfo->DestRect.top * BltInfo->DestSurface->lDelta);\n");
  fprintf(Out, "\n");
  if (UsesPattern)
    {
      fprintf(Out, "  if (BltInfo->PatternSurface)\n");
      fprintf(Out, "    {\n");
      fprintf(Out, "      PatternY = (BltInfo->DestRect.top + BltInfo->BrushOrigin.y) %\n");
      fprintf(Out, "                 BltInfo->PatternSurface->sizlBitmap.cy;\n");
      fprintf(Out, "    }\n");
      fprintf(Out, "  else\n");
      fprintf(Out, "    {\n");
      fprintf(Out, "      Pattern = BltInfo->Brush->iSolidColor |\n");
      fprintf(Out, "                (BltInfo->Brush->iSolidColor << 16);\n");
      fprintf(Out, "    }\n");
    }
  fprintf(Out, "\n");
  fprintf(Out, "  for (DestY = BltInfo->DestRect.top; DestY < BltInfo->DestRect.bottom; DestY++)\n");
  fprintf(Out, "    {\n");
  if (UsesSource)
    {
      fprintf(Out, "      SourceX = BltInfo->SourcePoint.x;\n");
      fprintf(Out, "\n");
    }
  fprintf(Out, "      for (DestX = BltInfo->DestRect.left; DestX < RoundedRight; DestX += 2, DestBits++");
  if (UsesSource)
    {
      fprintf(Out, ", SourceX += 2");
    }
  fprintf(Out, ")\n");
  fprintf(Out, "        {\n");
  if (UsesDest)
    {
      fprintf(Out, "          Dest = *DestBits;\n");
      fprintf(Out, "\n");
    }
  if (UsesSource)
    {
      fprintf(Out, "          Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);\n");
      fprintf(Out, "          Source |= DIB_GetSource(BltInfo->SourceSurface, SourceX + 1, SourceY, BltInfo->XlateSourceToDest) << 16;\n");
      fprintf(Out, "\n");
    }
  if (UsesPattern)
    {
      fprintf(Out, "          if (BltInfo->PatternSurface)\n");
      fprintf(Out, "            {\n");
      fprintf(Out, "              Pattern = DIB_GetSource(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY, BltInfo->XlatePatternToDest);\n");
      fprintf(Out, "              Pattern |= DIB_GetSource(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x + 1) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY, BltInfo->XlatePatternToDest) << 16;\n");
      fprintf(Out, "            }\n");
      fprintf(Out, "\n");
    }
  fprintf(Out, "          *DestBits = DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern);\n");
  fprintf(Out, "        }\n");
  fprintf(Out, "\n");
  fprintf(Out, "      if (DestX < BltInfo->DestRect.right)\n");
  fprintf(Out, "        {\n");
  if (UsesDest)
    {
      fprintf(Out, "          Dest = *((PUSHORT)DestBits);\n");
      fprintf(Out, "\n");
    }
  if (UsesSource)
    {
      fprintf(Out, "          Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);\n");
    }
  if (UsesPattern)
    {
      fprintf(Out, "          if (BltInfo->PatternSurface)\n");
      fprintf(Out, "            {\n");
      fprintf(Out, "              Pattern = DIB_GetSource(BltInfo->PatternSurface, (DestX + BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY, BltInfo->XlatePatternToDest);\n");
      fprintf(Out, "            }\n");
      fprintf(Out, "\n");
    }
  fprintf(Out, "          DIB_16BPP_PutPixel(BltInfo->DestSurface, DestX, DestY, DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern) & 0xFFFF);\n");
  fprintf(Out, "          DestBits = (PULONG)((ULONG_PTR)DestBits + 2);\n");
  fprintf(Out, "        }\n");
  fprintf(Out, "\n");
  if (UsesSource)
    {
      fprintf(Out, "      SourceY++;\n");
    }
  if (UsesPattern)
    {
      fprintf(Out, "      if (BltInfo->PatternSurface)\n");
      fprintf(Out, "        {\n");
      fprintf(Out, "          PatternY++;\n");
      fprintf(Out, "          PatternY %= BltInfo->PatternSurface->sizlBitmap.cy;\n");
      fprintf(Out, "        }\n");
    }
  fprintf(Out, "      DestBits = (PULONG)(\n");
  fprintf(Out, "         (ULONG_PTR)DestBits -\n");
  fprintf(Out, "         ((BltInfo->DestRect.right - BltInfo->DestRect.left) << 1) +\n");
  fprintf(Out, "         BltInfo->DestSurface->lDelta);\n");
  fprintf(Out, "    }\n");
  fprintf(Out, "}\n");
}

static void
CreateTable(FILE *Out, unsigned Bpp)
{
  unsigned RopCode;

  fprintf(Out, "\n");
  fprintf(Out, "static void (*PrimitivesTable[256])(PBLTINFO) =\n");
  fprintf(Out, "  {\n");
  for (RopCode = 0; RopCode < 256; RopCode++)
    {
      fprintf(Out, "    ");
      PrintRoutineName(Out, Bpp, RopCode);
      if (RopCode < 255)
        {
          putc(',', Out);
        }
      putc('\n', Out);
    }
  fprintf(Out, "  };\n");
}

static void
CreateBitBlt(FILE *Out, unsigned Bpp)
{
  fprintf(Out, "\n");
  fprintf(Out, "BOOLEAN\n");
  fprintf(Out, "DIB_%uBPP_BitBlt(PBLTINFO BltInfo)\n", Bpp);
  fprintf(Out, "{\n");
  fprintf(Out, "  PrimitivesTable[BltInfo->Rop4 & 0xff](BltInfo);\n");
  fprintf(Out, "\n");
  fprintf(Out, "  return TRUE;\n");
  fprintf(Out, "}\n");
}

int
main(int argc, char *argv[])
{
  FILE *Out;
  unsigned RopCode;
  unsigned Bpp;

  Bpp = 16;
  Out = fopen("dib16gen.c", "w");
  if (NULL == Out)
    {
      perror("Error opening output file");
      exit(1);
    }

  fprintf(Out, "/* This is a generated file. Please do not edit */\n");
  fprintf(Out, "\n");
  fprintf(Out, "#include \"w32k.h\"\n");

  for (RopCode = 0; RopCode < 256; RopCode++)
    {
      CreatePrimitive(Out, Bpp, RopCode);
    }
  CreateTable(Out, Bpp);
  CreateBitBlt(Out, Bpp);

  fclose(Out);

  return 0;
}


More information about the Ros-dev mailing list