Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

329 lines
9.3 KiB

/**************************************************************************
*
* Copyright (c) 2000 Microsoft Corporation
*
* Module Name:
*
* Software rasterizer code for drawing a CachedBitmap
*
* Created:
*
* 05/18/2000 asecchia
* Created it.
*
**************************************************************************/
#include "precomp.hpp"
// Class to output a clipped span for a CachedBitmap
class DpOutputCachedBitmapSpan : public DpOutputSpan
{
EpScanRecord *InputBuffer;
DpScanBuffer *Scan;
INT XOff, YOff; // coordinates of the top left corner.
INT PixelSize;
public:
DpOutputCachedBitmapSpan(
DpScanBuffer *scan,
INT x,
INT y
)
{
Scan = scan;
InputBuffer = NULL;
XOff = x;
YOff = y;
}
virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
{
// Can't draw anything if the buffer hasn't been set correctly.
ASSERT(InputBuffer != NULL);
ASSERT(YOff + InputBuffer->Y == y);
ASSERT(xMax-xMin <= InputBuffer->Width);
// Get an output buffer.
void *buffer;
buffer = Scan->NextBuffer(
xMin, y,
xMax-xMin,
InputBuffer->BlenderNum
);
// Get a pointer to the start of the scanline.
void *ib = InputBuffer->GetColorBuffer();
INT pixelSize = PixelSize;
// InputBuffer->X + XOff is the x starting position on the screen.
// Make sure we're not trying to draw off to the left of our data.
ASSERT(xMin >= (InputBuffer->X+XOff));
ib = (void *) ( (BYTE *)(ib) +
(xMin - (InputBuffer->X+XOff))*pixelSize);
// Copy the input buffer to the output buffer.
GpMemcpy(buffer, ib, (xMax-xMin)*pixelSize);
// Cannot fail this routine.
return Ok;
}
// Initialize the class with a new scan record.
// This is used when we want to start processing a new batch record.
void SetInputBuffer(
EpScanRecord *ib,
INT pixelSize
)
{
InputBuffer = ib;
PixelSize = pixelSize;
}
// We're always valid.
virtual int IsValid() const {return TRUE;}
};
/**************************************************************************
*
* Function Description:
*
* Software Rasterizer code for drawing a DpCachedBitmap
*
* Arguments:
*
* context - the graphics context.
* src - the DpCachedBitmap to draw from
* dst - where the output goes
* x, y - offset - position to draw the top left corner of the CachedBitmap.
*
* Return Value:
*
* GpStatus.
*
* Notes:
*
* This driver entry point expects the input to be in device coordinates
* so the caller has to pre compute the world to device transform.
* This is contrary to how most of our driver entry points work.
*
* Created:
*
* 05/18/2000 asecchia
* Created it.
*
**************************************************************************/
GpStatus
DpDriver::DrawCachedBitmap(
DpContext *context,
DpCachedBitmap *src,
DpBitmap *dst,
INT x, INT y // Device coordinates!
)
{
ASSERT(context);
ASSERT(src);
ASSERT(dst);
// Let's go make sure the Surface pixel format and the CachedBitmap
// opaque format match.
// The exception is for 32bppRGB which can draw onto anything.
// This format is used in the multi-mon case where the individual
// screen devices can be in multiple formats.
// When 64bpp formats become first class citizens, we may want to
// update this condition.
if((dst->PixelFormat != src->OpaqueFormat) &&
(src->OpaqueFormat != PixelFormat32bppRGB))
{
return WrongState;
}
// Ignore the world to device transform - this driver entry point is
// somewhat unique in that it expects device coordinates.
// Initialize the DpScanBuffer.
// This hooks us up to the appropriate DpScanXXX class for outputting our
// data to the destination device.
DpScanBuffer scanBuffer(
dst->Scan,
this,
context,
dst,
FALSE,
EpScanTypeBlend,
src->SemiTransparentFormat,
src->OpaqueFormat
);
if(!scanBuffer.IsValid())
{
return(GenericError);
}
// Set up the clipping.
DpRegion::Visibility visibility = DpRegion::TotallyVisible;
DpClipRegion *clipRegion = NULL;
if(context->VisibleClip.GetRectVisibility(
x, y,
x+src->Width,
y+src->Height
) != DpRegion::TotallyVisible
)
{
clipRegion = &(context->VisibleClip);
}
GpRect clippedRect;
if(clipRegion)
{
visibility = clipRegion->GetRectVisibility(
x, y,
x+src->Width,
y+src->Height,
&clippedRect
);
}
// Decide on our clipping strategy.
switch (visibility)
{
case DpRegion::TotallyVisible: // no clipping is needed
{
// Copy the scanlines to the destination buffer
// ProcessBatch requests that the DpScan class handle the entire
// batch as a single block. If it can't it will return FALSE and
// we fall through into the general purpose code below.
BOOL batchSupported = scanBuffer.ProcessBatch(
src->RecordStart,
src->RecordEnd,
x,
y,
x+src->Width,
y+src->Height
);
if(batchSupported)
{
// The scanBuffer supports ProcessBatch; we're done.
break;
}
// The scanBuffer doesn't support the ProcessBatch routine.
// Lets manually enumerate the batch structure into the destination.
// Fall through into the manual enumeration code:
}
// !!! PERF [asecchia] We have a perf problem when there is no clipping
// except the standard surface bounds. DCI/GDI would be able to clip
// this directly, but we aren't sure how to robustly detect this
// optimization and ignore the clip rectangle. This does not impact
// the fully visible case. Also it's not appropriate to make this
// optimization unless we're using DpScanGdiDci as our output device.
case DpRegion::ClippedVisible:
case DpRegion::PartiallyVisible: // some clipping is needed
{
// Create the OutputSpan class for the CachedBitmap.
// Create this on the stack because it has very little storage
// and we can avoid a malloc. It gets cleaned up when we go out
// of scope.
DpOutputCachedBitmapSpan output(
&scanBuffer,
x,
y
);
// Initialize the clipper to point to the clip region and
// create the clpping chain by tacking the output created above
// on to the end of the list.
DpOutputSpan *clipper;
if(clipRegion)
{
clipper = clipRegion;
clipRegion->InitClipping(&output, y);
}
else
{
// no clipping required - possible due to the fallthrough case
// in the fully visible codepath.
clipper = &output;
}
// Lets manually enumerate the batch structure into the destination
// taking into account clipping
// First set up the running record pointer to the beginning of the
// batch and a sentinel for the end.
EpScanRecord *record = src->RecordStart;
EpScanRecord *batchEnd = src->RecordEnd;
// For all the batch records, Draw them on the destination.
while(record < batchEnd)
{
PixelFormatID format;
if (record->BlenderNum == 0)
{
format = src->SemiTransparentFormat;
}
else
{
ASSERT(record->BlenderNum == 1);
format = src->OpaqueFormat;
}
INT pixelSize = GetPixelFormatSize(format) >> 3;
// Set the output span buffer
output.SetInputBuffer(record, pixelSize);
// Draw this span
INT x1 = x+record->X;
INT x2 = x+record->X+record->Width;
clipper->OutputSpan(y+record->Y, x1, x2);
// Advance to the next record:
record = record->NextScanRecord(pixelSize);
}
}
break;
case DpRegion::Invisible: // nothing on screen - quit
break;
}
return Ok;
}