windows-nt/Source/XPSP1/NT/drivers/video/ms/cirrus/disp/stripio.c
2020-09-26 16:20:57 +08:00

571 lines
14 KiB
C

/******************************************************************************\
*
* $Workfile: stripio.c $
*
* Do what you can with no line support.
*
* I implemented the horizontal and vertical strip functions using
* solid fills, and removed the usage of diagonal strips. With a little
* effort you could implement diagonal strips by doing solid fills while
* playing with lDelta. This is probably not worth the trouble.
*
* Copyright (c) 1992-1995 Microsoft Corporation
* Copyright (c) 1996 Cirrus Logic, Inc.
*
* $Log: S:/projects/drivers/ntsrc/display/stripio.c_v $
*
* Rev 1.1 Oct 10 1996 15:39:12 unknown
*
*
* Rev 1.1 12 Aug 1996 16:55:04 frido
* Removed unaccessed local variables.
*
\******************************************************************************/
#include "precomp.h"
#define IO_DRAW_HORZ_STRIP(xy, cx, lDelta, cBpp)\
{\
ULONG ulDstAddr;\
\
ulDstAddr = xy;\
\
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);\
CP_IO_XCNT(ppdev, pjPorts, (PELS_TO_BYTES(cx) - 1));\
CP_IO_YCNT(ppdev, pjPorts, 0);\
CP_IO_DST_ADDR(ppdev, pjPorts, ulDstAddr);\
CP_IO_START_BLT(ppdev, pjPorts);\
}
#define IO_DRAW_VERT_STRIP(xy, cy, lDelta, cBpp)\
{\
ULONG ulDstAddr;\
\
ulDstAddr = xy;\
\
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);\
CP_IO_XCNT(ppdev, pjPorts, (cBpp - 1));\
CP_IO_YCNT(ppdev, pjPorts, (cy - 1));\
CP_IO_DST_ADDR(ppdev, pjPorts, ulDstAddr);\
CP_IO_START_BLT(ppdev, pjPorts);\
}
#define IO_DRAW_VERT_STRIP_FLIPPED(xy, cy, lDelta, cBpp)\
{\
ULONG ulDstAddr;\
\
ulDstAddr = xy - ((cy - 1) * lDelta);\
\
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);\
CP_IO_XCNT(ppdev, pjPorts, (cBpp - 1));\
CP_IO_YCNT(ppdev, pjPorts, (cy - 1));\
CP_IO_DST_ADDR(ppdev, pjPorts, ulDstAddr);\
CP_IO_START_BLT(ppdev, pjPorts);\
}
/******************************Public*Routine******************************\
* VOID vIoSolidHorizontal
*
* Draws left-to-right x-major near-horizontal lines using solid fills.
*
* Assumes fgRop, BgRop, and Color are already set correctly.
*
\**************************************************************************/
VOID vIoSolidHorizontal(
PDEV* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
BYTE* pjPorts = ppdev->pjPorts;
LONG cBpp = ppdev->cBpp;
LONG lDelta = ppdev->lDelta;
LONG cStrips = pStrip->cStrips;
PLONG pStrips = pStrip->alStrips;
LONG x = pStrip->ptlStart.x;
LONG y = pStrip->ptlStart.y;
LONG xy = PELS_TO_BYTES(x) + (lDelta * y);
LONG yInc = 1;
LONG i;
DISPDBG((2,"vIoSolidHorizontal"));
if (!(pStrip->flFlips & FL_FLIP_V))
{
//
// Horizontal strips ->
// ->
//
for (i = 0; i < cStrips; i++)
{
IO_DRAW_HORZ_STRIP(xy, *pStrips, lDelta, cBpp);
x += *pStrips;
xy += PELS_TO_BYTES(*pStrips); // x+
xy += lDelta; // y+
pStrips++;
}
y += cStrips;
}
else
{
//
// ->
// Horizontal strips ->
//
for (i = 0; i < cStrips; i++)
{
IO_DRAW_HORZ_STRIP(xy, *pStrips, lDelta, cBpp);
x += *pStrips;
xy += PELS_TO_BYTES(*pStrips); // x+
xy -= lDelta; // y+
pStrips++;
}
y -= cStrips;
}
pStrip->ptlStart.x = x;
pStrip->ptlStart.y = y;
}
/******************************Public*Routine******************************\
* VOID vIoSolidVertical
*
* Draws left-to-right y-major near-vertical lines using solid fills.
*
\**************************************************************************/
VOID vIoSolidVertical(
PDEV* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
BYTE* pjPorts = ppdev->pjPorts;
LONG cBpp = ppdev->cBpp;
LONG lDelta = ppdev->lDelta;
LONG cStrips = pStrip->cStrips;
PLONG pStrips = pStrip->alStrips;
LONG x = pStrip->ptlStart.x;
LONG y = pStrip->ptlStart.y;
LONG xy = PELS_TO_BYTES(x) + (lDelta * y);
LONG i;
DISPDBG((2,"vIoSolidVertical"));
if (!(pStrip->flFlips & FL_FLIP_V))
{
//
// |
// Vertical strips v
// |
// v
//
for (i = 0; i < cStrips; i++)
{
IO_DRAW_VERT_STRIP(xy, *pStrips, lDelta, cBpp);
y += *pStrips;
xy += cBpp; // x+
xy += (*pStrips * lDelta); // y+
pStrips++;
}
}
else
{
//
// ^
// Vertical strips |
// ^
// |
//
for (i = 0; i < cStrips; i++)
{
IO_DRAW_VERT_STRIP_FLIPPED(xy, *pStrips, lDelta, cBpp);
y -= *pStrips;
xy += cBpp; // x+
xy -= (*pStrips * lDelta); // y-
pStrips++;
}
}
x += cStrips;
pStrip->ptlStart.x = x;
pStrip->ptlStart.y = y;
}
/******************************Public*Routine******************************\
* VOID vIoStyledHorizontal
*
* Takes the list of strips that define the pixels that would be lit for
* a solid line, and breaks them into styling chunks according to the
* styling information that is passed in.
*
* This particular routine handles x-major lines that run left-to-right,
* and are comprised of horizontal strips. It draws the dashes using
* short-stroke vectors.
*
* The performance of this routine could be improved significantly if
* anyone cared enough about styled lines improve it.
*
\**************************************************************************/
VOID vIoStyledHorizontal(
PDEV* ppdev,
STRIP* pstrip,
LINESTATE* pls)
{
BYTE* pjPorts = ppdev->pjPorts;
LONG cBpp = ppdev->cBpp;
LONG lDelta = ppdev->lDelta;
LONG x = pstrip->ptlStart.x; // x position of start of first strip
LONG y = pstrip->ptlStart.y; // y position of start of first strip
LONG xy = PELS_TO_BYTES(x) + (lDelta * y);
LONG* plStrip = pstrip->alStrips; // Points to current strip
LONG cStrips = pstrip->cStrips; // Total number of strips we'll do
LONG dy;
LONG dylDelta;
LONG cStyle;
LONG cStrip;
LONG cThis;
ULONG bIsGap;
if (pstrip->flFlips & FL_FLIP_V)
{
// The minor direction of the line is 90 degrees, and the major
// direction is 0 (it's a left-to-right x-major line going up):
dy = -1;
dylDelta = -lDelta;
}
else
{
// The minor direction of the line is 270 degrees, and the major
// direction is 0 (it's a left-to-right x-major line going down):
dy = 1;
dylDelta = lDelta;
}
cStrip = *plStrip; // Number of pels in first strip
cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
bIsGap = pls->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
// ulStyleMask is non-zero if we're in the middle of a 'gap',
// and zero if we're in the middle of a 'dash':
if (bIsGap)
goto SkipAGap;
else
goto OutputADash;
PrepareToSkipAGap:
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
bIsGap = ~bIsGap;
pls->psp++;
if (pls->psp > pls->pspEnd)
pls->psp = pls->pspStart;
cStyle = *pls->psp;
// If 'cStrip' is zero, we also need a new strip:
if (cStrip != 0)
goto SkipAGap;
// Here, we're in the middle of a 'gap' where we don't have to
// display anything. We simply cycle through all the strips
// we can, keeping track of the current position, until we run
// out of 'gap':
while (TRUE)
{
// Each time we loop, we move to a new scan and need a new strip:
y += dy;
xy += dylDelta;
plStrip++;
cStrips--;
if (cStrips == 0)
goto AllDone;
cStrip = *plStrip;
SkipAGap:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
x += cThis;
xy += PELS_TO_BYTES(cThis);
if (cStyle == 0)
goto PrepareToOutputADash;
}
PrepareToOutputADash:
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
bIsGap = ~bIsGap;
pls->psp++;
if (pls->psp > pls->pspEnd)
pls->psp = pls->pspStart;
cStyle = *pls->psp;
// If 'cStrip' is zero, we also need a new strip.
if (cStrip != 0)
{
// There's more to be done in the current strip:
goto OutputADash;
}
// We've finished with the current strip:
while (TRUE)
{
// Each time we loop, we move to a new scan and need a new strip:
y += dy;
xy += dylDelta;
plStrip++;
cStrips--;
if (cStrips == 0)
goto AllDone;
cStrip = *plStrip;
OutputADash:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
IO_DRAW_HORZ_STRIP(xy, cThis, lDelta, cBpp);
x += cThis;
xy += PELS_TO_BYTES(cThis); // x+
if (cStyle == 0)
goto PrepareToSkipAGap;
}
AllDone:
// Update our state variables so that the next line can continue
// where we left off:
pls->spRemaining = cStyle;
pls->ulStyleMask = bIsGap;
pstrip->ptlStart.x = x;
pstrip->ptlStart.y = y;
}
/******************************Public*Routine******************************\
* VOID vIoStyledVertical
*
* Takes the list of strips that define the pixels that would be lit for
* a solid line, and breaks them into styling chunks according to the
* styling information that is passed in.
*
* This particular routine handles y-major lines that run left-to-right,
* and are comprised of vertical strips. It draws the dashes using
* short-stroke vectors.
*
* The performance of this routine could be improved significantly if
* anyone cared enough about styled lines improve it.
*
\**************************************************************************/
VOID vIoStyledVertical(
PDEV* ppdev,
STRIP* pstrip,
LINESTATE* pls)
{
BYTE* pjPorts = ppdev->pjPorts;
LONG cBpp = ppdev->cBpp;
LONG lDelta = ppdev->lDelta;
LONG x = pstrip->ptlStart.x; // x position of start of first strip
LONG y = pstrip->ptlStart.y; // y position of start of first strip
LONG xy = PELS_TO_BYTES(x) + (lDelta * y);
LONG* plStrip = pstrip->alStrips; // Points to current strip
LONG cStrips = pstrip->cStrips; // Total number of strips we'll do
LONG dy;
LONG dylDelta;
LONG cStyle;
LONG cStrip;
LONG cThis;
ULONG bIsGap;
if (pstrip->flFlips & FL_FLIP_V)
{
// The minor direction of the line is 0 degrees, and the major
// direction is 90 (it's a left-to-right y-major line going up):
dy = -1;
dylDelta = -lDelta;
}
else
{
// The minor direction of the line is 0 degrees, and the major
// direction is 270 (it's a left-to-right y-major line going down):
dy = 1;
dylDelta = lDelta;
}
cStrip = *plStrip; // Number of pels in first strip
cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
bIsGap = pls->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
// ulStyleMask is non-zero if we're in the middle of a 'gap',
// and zero if we're in the middle of a 'dash':
if (bIsGap)
goto SkipAGap;
else
goto OutputADash;
PrepareToSkipAGap:
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
bIsGap = ~bIsGap;
pls->psp++;
if (pls->psp > pls->pspEnd)
pls->psp = pls->pspStart;
cStyle = *pls->psp;
// If 'cStrip' is zero, we also need a new strip:
if (cStrip != 0)
goto SkipAGap;
// Here, we're in the middle of a 'gap' where we don't have to
// display anything. We simply cycle through all the strips
// we can, keeping track of the current position, until we run
// out of 'gap':
while (TRUE)
{
// Each time we loop, we move to a new column and need a new strip:
xy += cBpp;
x++;
plStrip++;
cStrips--;
if (cStrips == 0)
goto AllDone;
cStrip = *plStrip;
SkipAGap:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
if (dy > 0)
{
y += cThis;
xy += (cThis * lDelta);
}
else
{
y -= cThis;
xy -= (cThis * lDelta);
}
if (cStyle == 0)
goto PrepareToOutputADash;
}
PrepareToOutputADash:
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
bIsGap = ~bIsGap;
pls->psp++;
if (pls->psp > pls->pspEnd)
pls->psp = pls->pspStart;
cStyle = *pls->psp;
// If 'cStrip' is zero, we also need a new strip.
if (cStrip != 0)
{
// There's more to be done in the current strip:
goto OutputADash;
}
// We've finished with the current strip:
while (TRUE)
{
// Each time we loop, we move to a new column and need a new strip:
xy += cBpp;
x++;
plStrip++;
cStrips--;
if (cStrips == 0)
goto AllDone;
cStrip = *plStrip;
OutputADash:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
if (dy <= 0)
{
IO_DRAW_VERT_STRIP_FLIPPED(xy, cThis, lDelta, cBpp);
y -= cThis; // y-
xy -= (cThis * lDelta); // y-
}
else
{
IO_DRAW_VERT_STRIP(xy, cThis, lDelta, cBpp);
y += cThis; // y+
xy += (cThis * lDelta); // y+
}
if (cStyle == 0)
goto PrepareToSkipAGap;
}
AllDone:
// Update our state variables so that the next line can continue
// where we left off:
pls->spRemaining = cStyle;
pls->ulStyleMask = bIsGap;
pstrip->ptlStart.x = x;
pstrip->ptlStart.y = y;
}