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

  1. /**************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Software rasterizer code for drawing a CachedBitmap
  8. *
  9. * Created:
  10. *
  11. * 05/18/2000 asecchia
  12. * Created it.
  13. *
  14. **************************************************************************/
  15. #include "precomp.hpp"
  16. // Class to output a clipped span for a CachedBitmap
  17. class DpOutputCachedBitmapSpan : public DpOutputSpan
  18. {
  19. EpScanRecord *InputBuffer;
  20. DpScanBuffer *Scan;
  21. INT XOff, YOff; // coordinates of the top left corner.
  22. INT PixelSize;
  23. public:
  24. DpOutputCachedBitmapSpan(
  25. DpScanBuffer *scan,
  26. INT x,
  27. INT y
  28. )
  29. {
  30. Scan = scan;
  31. InputBuffer = NULL;
  32. XOff = x;
  33. YOff = y;
  34. }
  35. virtual GpStatus OutputSpan(INT y, INT xMin, INT xMax)
  36. {
  37. // Can't draw anything if the buffer hasn't been set correctly.
  38. ASSERT(InputBuffer != NULL);
  39. ASSERT(YOff + InputBuffer->Y == y);
  40. ASSERT(xMax-xMin <= InputBuffer->Width);
  41. // Get an output buffer.
  42. void *buffer;
  43. buffer = Scan->NextBuffer(
  44. xMin, y,
  45. xMax-xMin,
  46. InputBuffer->BlenderNum
  47. );
  48. // Get a pointer to the start of the scanline.
  49. void *ib = InputBuffer->GetColorBuffer();
  50. INT pixelSize = PixelSize;
  51. // InputBuffer->X + XOff is the x starting position on the screen.
  52. // Make sure we're not trying to draw off to the left of our data.
  53. ASSERT(xMin >= (InputBuffer->X+XOff));
  54. ib = (void *) ( (BYTE *)(ib) +
  55. (xMin - (InputBuffer->X+XOff))*pixelSize);
  56. // Copy the input buffer to the output buffer.
  57. GpMemcpy(buffer, ib, (xMax-xMin)*pixelSize);
  58. // Cannot fail this routine.
  59. return Ok;
  60. }
  61. // Initialize the class with a new scan record.
  62. // This is used when we want to start processing a new batch record.
  63. void SetInputBuffer(
  64. EpScanRecord *ib,
  65. INT pixelSize
  66. )
  67. {
  68. InputBuffer = ib;
  69. PixelSize = pixelSize;
  70. }
  71. // We're always valid.
  72. virtual int IsValid() const {return TRUE;}
  73. };
  74. /**************************************************************************
  75. *
  76. * Function Description:
  77. *
  78. * Software Rasterizer code for drawing a DpCachedBitmap
  79. *
  80. * Arguments:
  81. *
  82. * context - the graphics context.
  83. * src - the DpCachedBitmap to draw from
  84. * dst - where the output goes
  85. * x, y - offset - position to draw the top left corner of the CachedBitmap.
  86. *
  87. * Return Value:
  88. *
  89. * GpStatus.
  90. *
  91. * Notes:
  92. *
  93. * This driver entry point expects the input to be in device coordinates
  94. * so the caller has to pre compute the world to device transform.
  95. * This is contrary to how most of our driver entry points work.
  96. *
  97. * Created:
  98. *
  99. * 05/18/2000 asecchia
  100. * Created it.
  101. *
  102. **************************************************************************/
  103. GpStatus
  104. DpDriver::DrawCachedBitmap(
  105. DpContext *context,
  106. DpCachedBitmap *src,
  107. DpBitmap *dst,
  108. INT x, INT y // Device coordinates!
  109. )
  110. {
  111. ASSERT(context);
  112. ASSERT(src);
  113. ASSERT(dst);
  114. // Let's go make sure the Surface pixel format and the CachedBitmap
  115. // opaque format match.
  116. // The exception is for 32bppRGB which can draw onto anything.
  117. // This format is used in the multi-mon case where the individual
  118. // screen devices can be in multiple formats.
  119. // When 64bpp formats become first class citizens, we may want to
  120. // update this condition.
  121. if((dst->PixelFormat != src->OpaqueFormat) &&
  122. (src->OpaqueFormat != PixelFormat32bppRGB))
  123. {
  124. return WrongState;
  125. }
  126. // Ignore the world to device transform - this driver entry point is
  127. // somewhat unique in that it expects device coordinates.
  128. // Initialize the DpScanBuffer.
  129. // This hooks us up to the appropriate DpScanXXX class for outputting our
  130. // data to the destination device.
  131. DpScanBuffer scanBuffer(
  132. dst->Scan,
  133. this,
  134. context,
  135. dst,
  136. FALSE,
  137. EpScanTypeBlend,
  138. src->SemiTransparentFormat,
  139. src->OpaqueFormat
  140. );
  141. if(!scanBuffer.IsValid())
  142. {
  143. return(GenericError);
  144. }
  145. // Set up the clipping.
  146. DpRegion::Visibility visibility = DpRegion::TotallyVisible;
  147. DpClipRegion *clipRegion = NULL;
  148. if(context->VisibleClip.GetRectVisibility(
  149. x, y,
  150. x+src->Width,
  151. y+src->Height
  152. ) != DpRegion::TotallyVisible
  153. )
  154. {
  155. clipRegion = &(context->VisibleClip);
  156. }
  157. GpRect clippedRect;
  158. if(clipRegion)
  159. {
  160. visibility = clipRegion->GetRectVisibility(
  161. x, y,
  162. x+src->Width,
  163. y+src->Height,
  164. &clippedRect
  165. );
  166. }
  167. // Decide on our clipping strategy.
  168. switch (visibility)
  169. {
  170. case DpRegion::TotallyVisible: // no clipping is needed
  171. {
  172. // Copy the scanlines to the destination buffer
  173. // ProcessBatch requests that the DpScan class handle the entire
  174. // batch as a single block. If it can't it will return FALSE and
  175. // we fall through into the general purpose code below.
  176. BOOL batchSupported = scanBuffer.ProcessBatch(
  177. src->RecordStart,
  178. src->RecordEnd,
  179. x,
  180. y,
  181. x+src->Width,
  182. y+src->Height
  183. );
  184. if(batchSupported)
  185. {
  186. // The scanBuffer supports ProcessBatch; we're done.
  187. break;
  188. }
  189. // The scanBuffer doesn't support the ProcessBatch routine.
  190. // Lets manually enumerate the batch structure into the destination.
  191. // Fall through into the manual enumeration code:
  192. }
  193. // !!! PERF [asecchia] We have a perf problem when there is no clipping
  194. // except the standard surface bounds. DCI/GDI would be able to clip
  195. // this directly, but we aren't sure how to robustly detect this
  196. // optimization and ignore the clip rectangle. This does not impact
  197. // the fully visible case. Also it's not appropriate to make this
  198. // optimization unless we're using DpScanGdiDci as our output device.
  199. case DpRegion::ClippedVisible:
  200. case DpRegion::PartiallyVisible: // some clipping is needed
  201. {
  202. // Create the OutputSpan class for the CachedBitmap.
  203. // Create this on the stack because it has very little storage
  204. // and we can avoid a malloc. It gets cleaned up when we go out
  205. // of scope.
  206. DpOutputCachedBitmapSpan output(
  207. &scanBuffer,
  208. x,
  209. y
  210. );
  211. // Initialize the clipper to point to the clip region and
  212. // create the clpping chain by tacking the output created above
  213. // on to the end of the list.
  214. DpOutputSpan *clipper;
  215. if(clipRegion)
  216. {
  217. clipper = clipRegion;
  218. clipRegion->InitClipping(&output, y);
  219. }
  220. else
  221. {
  222. // no clipping required - possible due to the fallthrough case
  223. // in the fully visible codepath.
  224. clipper = &output;
  225. }
  226. // Lets manually enumerate the batch structure into the destination
  227. // taking into account clipping
  228. // First set up the running record pointer to the beginning of the
  229. // batch and a sentinel for the end.
  230. EpScanRecord *record = src->RecordStart;
  231. EpScanRecord *batchEnd = src->RecordEnd;
  232. // For all the batch records, Draw them on the destination.
  233. while(record < batchEnd)
  234. {
  235. PixelFormatID format;
  236. if (record->BlenderNum == 0)
  237. {
  238. format = src->SemiTransparentFormat;
  239. }
  240. else
  241. {
  242. ASSERT(record->BlenderNum == 1);
  243. format = src->OpaqueFormat;
  244. }
  245. INT pixelSize = GetPixelFormatSize(format) >> 3;
  246. // Set the output span buffer
  247. output.SetInputBuffer(record, pixelSize);
  248. // Draw this span
  249. INT x1 = x+record->X;
  250. INT x2 = x+record->X+record->Width;
  251. clipper->OutputSpan(y+record->Y, x1, x2);
  252. // Advance to the next record:
  253. record = record->NextScanRecord(pixelSize);
  254. }
  255. }
  256. break;
  257. case DpRegion::Invisible: // nothing on screen - quit
  258. break;
  259. }
  260. return Ok;
  261. }