Use GDI Batch for PatBlt
[reactos.git] / win32ss / gdi / ntgdi / gdibatch.c
1
2 #include <win32k.h>
3
4 #define NDEBUG
5 #include <debug.h>
6
7 BOOL FASTCALL IntPatBlt( PDC,INT,INT,INT,INT,DWORD,PEBRUSHOBJ);
8
9 //
10 // Gdi Batch Flush support functions.
11 //
12
13 //
14 // DoDeviceSync
15 //
16 // based on IntEngEnter from eng/engmisc.c
17 //
18 VOID
19 FASTCALL
20 DoDeviceSync( SURFOBJ *Surface, PRECTL Rect, FLONG fl)
21 {
22 PPDEVOBJ Device = (PDEVOBJ*)Surface->hdev;
23 // No punting and "Handle to a surface, provided that the surface is device-managed.
24 // Otherwise, dhsurf is zero".
25 if (!(Device->flFlags & PDEV_DRIVER_PUNTED_CALL) && (Surface->dhsurf))
26 {
27 if (Device->DriverFunctions.SynchronizeSurface)
28 {
29 Device->DriverFunctions.SynchronizeSurface(Surface, Rect, fl);
30 }
31 else
32 {
33 if (Device->DriverFunctions.Synchronize)
34 {
35 Device->DriverFunctions.Synchronize(Surface->dhpdev, Rect);
36 }
37 }
38 }
39 }
40
41 VOID
42 FASTCALL
43 SynchonizeDriver(FLONG Flags)
44 {
45 SURFOBJ *SurfObj;
46 //PPDEVOBJ Device;
47
48 if (Flags & GCAPS2_SYNCFLUSH)
49 Flags = DSS_FLUSH_EVENT;
50 if (Flags & GCAPS2_SYNCTIMER)
51 Flags = DSS_TIMER_EVENT;
52
53 //Device = IntEnumHDev();
54 // UNIMPLEMENTED;
55 //ASSERT(FALSE);
56 SurfObj = 0;// EngLockSurface( Device->pSurface );
57 if(!SurfObj) return;
58 DoDeviceSync( SurfObj, NULL, Flags);
59 EngUnlockSurface(SurfObj);
60 return;
61 }
62
63 //
64 // Process the batch.
65 //
66 ULONG
67 FASTCALL
68 GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
69 {
70 ULONG Cmd = 0, Size = 0;
71 PDC_ATTR pdcattr = NULL;
72
73 if (dc)
74 {
75 pdcattr = dc->pdcattr;
76 }
77
78 _SEH2_TRY
79 {
80 Cmd = pHdr->Cmd;
81 Size = pHdr->Size; // Return the full size of the structure.
82 }
83 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
84 {
85 DPRINT1("WARNING! GdiBatch Fault!\n");
86 _SEH2_YIELD(return 0;)
87 }
88 _SEH2_END;
89
90 switch(Cmd)
91 {
92 case GdiBCPatBlt:
93 {
94 PGDIBSPATBLT pgDPB;
95 DWORD dwRop, flags;
96 HBRUSH hOrgBrush;
97 COLORREF crColor, crBkColor, crBrushClr;
98 ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
99 if (!dc) break;
100 pgDPB = (PGDIBSPATBLT) pHdr;
101 /* Convert the ROP3 to a ROP4 */
102 dwRop = pgDPB->dwRop;
103 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
104 /* Check if the rop uses a source */
105 if (WIN32_ROP4_USES_SOURCE(dwRop))
106 {
107 /* This is not possible */
108 break;
109 }
110 /* Check if the DC has no surface (empty mem or info DC) */
111 if (dc->dclevel.pSurface == NULL)
112 {
113 /* Nothing to do */
114 break;
115 }
116 // Save current attributes and flags
117 crColor = dc->pdcattr->crForegroundClr;
118 crBkColor = dc->pdcattr->ulBackgroundClr;
119 crBrushClr = dc->pdcattr->crBrushClr;
120 ulForegroundClr = dc->pdcattr->ulForegroundClr;
121 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
122 ulBrushClr = dc->pdcattr->ulBrushClr;
123 hOrgBrush = dc->pdcattr->hbrush;
124 flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
125 // Set the attribute snapshot
126 dc->pdcattr->hbrush = pgDPB->hbrush;
127 dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
128 dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
129 dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
130 dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
131 dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
132 dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
133 // Process dirty attributes if any
134 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
135 DC_vUpdateFillBrush(dc);
136 if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
137 DC_vUpdateTextBrush(dc);
138 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
139 DC_vUpdateBackgroundBrush(dc);
140 /* Call the internal function */
141 IntPatBlt(dc, pgDPB->nXLeft, pgDPB->nYLeft, pgDPB->nWidth, pgDPB->nHeight, dwRop, &dc->eboFill);
142 // Restore attributes and flags
143 dc->pdcattr->hbrush = hOrgBrush;
144 dc->pdcattr->crForegroundClr = crColor;
145 dc->pdcattr->crBackgroundClr = crBkColor;
146 dc->pdcattr->crBrushClr = crBrushClr;
147 dc->pdcattr->ulForegroundClr = ulForegroundClr;
148 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
149 dc->pdcattr->ulBrushClr = ulBrushClr;
150 dc->pdcattr->ulDirty_ |= flags;
151 break;
152 }
153
154 case GdiBCPolyPatBlt:
155 {
156 PGDIBSPPATBLT pgDPB;
157 EBRUSHOBJ eboFill;
158 PBRUSH pbrush;
159 PPATRECT pRects;
160 INT cRects, i;
161 DWORD dwRop, flags;
162 COLORREF crColor, crBkColor, crBrushClr;
163 ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
164 if (!dc) break;
165 pgDPB = (PGDIBSPPATBLT) pHdr;
166 /* Convert the ROP3 to a ROP4 */
167 dwRop = pgDPB->rop4;
168 dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
169 /* Check if the rop uses a source */
170 if (WIN32_ROP4_USES_SOURCE(dwRop))
171 {
172 /* This is not possible */
173 break;
174 }
175 /* Check if the DC has no surface (empty mem or info DC) */
176 if (dc->dclevel.pSurface == NULL)
177 {
178 /* Nothing to do */
179 break;
180 }
181 // Save current attributes and flags
182 crColor = dc->pdcattr->crForegroundClr;
183 crBkColor = dc->pdcattr->ulBackgroundClr;
184 crBrushClr = dc->pdcattr->crBrushClr;
185 ulForegroundClr = dc->pdcattr->ulForegroundClr;
186 ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
187 ulBrushClr = dc->pdcattr->ulBrushClr;
188 flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
189 // Set the attribute snapshot
190 dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
191 dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
192 dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
193 dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
194 dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
195 dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
196 // Process dirty attributes if any
197 if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
198 DC_vUpdateTextBrush(dc);
199 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
200 DC_vUpdateBackgroundBrush(dc);
201
202 DPRINT1("GdiBCPolyPatBlt Testing\n");
203 pRects = pgDPB->pRect;
204 cRects = pgDPB->Count;
205
206 for (i = 0; i < cRects; i++)
207 {
208 pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
209
210 /* Check if we could lock the brush */
211 if (pbrush != NULL)
212 {
213 /* Initialize a brush object */
214 EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, dc);
215
216 IntPatBlt(
217 dc,
218 pRects->r.left,
219 pRects->r.top,
220 pRects->r.right,
221 pRects->r.bottom,
222 dwRop,
223 &eboFill);
224
225 /* Cleanup the brush object and unlock the brush */
226 EBRUSHOBJ_vCleanup(&eboFill);
227 BRUSH_ShareUnlockBrush(pbrush);
228 }
229 pRects++;
230 }
231
232 // Restore attributes and flags
233 dc->pdcattr->crForegroundClr = crColor;
234 dc->pdcattr->crBackgroundClr = crBkColor;
235 dc->pdcattr->crBrushClr = crBrushClr;
236 dc->pdcattr->ulForegroundClr = ulForegroundClr;
237 dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
238 dc->pdcattr->ulBrushClr = ulBrushClr;
239 dc->pdcattr->ulDirty_ |= flags;
240 break;
241 }
242 case GdiBCTextOut:
243 break;
244
245 case GdiBCExtTextOut:
246 {
247 //GreExtTextOutW( hDC,
248 // XStart,
249 // YStart,
250 // fuOptions,
251 // &SafeRect,
252 // SafeString,
253 // Count,
254 // SafeDx,
255 // dwCodePage );
256 break;
257 }
258
259 case GdiBCSetBrushOrg:
260 {
261 PGDIBSSETBRHORG pgSBO;
262 if (!dc) break;
263 pgSBO = (PGDIBSSETBRHORG) pHdr;
264 pdcattr->ptlBrushOrigin = pgSBO->ptlBrushOrigin;
265 DC_vSetBrushOrigin(dc, pgSBO->ptlBrushOrigin.x, pgSBO->ptlBrushOrigin.y);
266 break;
267 }
268
269 case GdiBCExtSelClipRgn:
270 break;
271
272 case GdiBCSelObj:
273 {
274 PGDIBSOBJECT pgO;
275
276 if (!dc) break;
277 pgO = (PGDIBSOBJECT) pHdr;
278
279 DC_hSelectFont(dc, (HFONT)pgO->hgdiobj);
280 break;
281 }
282
283 case GdiBCDelRgn:
284 DPRINT("Delete Region Object!\n");
285 /* Fall through */
286 case GdiBCDelObj:
287 {
288 PGDIBSOBJECT pgO = (PGDIBSOBJECT) pHdr;
289 GreDeleteObject( pgO->hgdiobj );
290 break;
291 }
292
293 default:
294 break;
295 }
296
297 return Size;
298 }
299
300 /*
301 * NtGdiFlush
302 *
303 * Flushes the calling thread's current batch.
304 */
305 __kernel_entry
306 NTSTATUS
307 APIENTRY
308 NtGdiFlush(
309 VOID)
310 {
311 SynchonizeDriver(GCAPS2_SYNCFLUSH);
312 return STATUS_SUCCESS;
313 }
314
315 /*
316 * NtGdiFlushUserBatch
317 *
318 * Callback for thread batch flush routine.
319 *
320 * Think small & fast!
321 */
322 NTSTATUS
323 APIENTRY
324 NtGdiFlushUserBatch(VOID)
325 {
326 PTEB pTeb = NtCurrentTeb();
327 ULONG GdiBatchCount = pTeb->GdiBatchCount;
328
329 if( (GdiBatchCount > 0) && (GdiBatchCount <= (GDIBATCHBUFSIZE/4)))
330 {
331 HDC hDC = (HDC) pTeb->GdiTebBatch.HDC;
332
333 /* If hDC is zero and the buffer fills up with delete objects we need
334 to run anyway.
335 */
336 if (hDC || GdiBatchCount)
337 {
338 PCHAR pHdr = (PCHAR)&pTeb->GdiTebBatch.Buffer[0];
339 PDC pDC = NULL;
340
341 if (GDI_HANDLE_GET_TYPE(hDC) == GDILoObjType_LO_DC_TYPE && GreIsHandleValid(hDC))
342 {
343 pDC = DC_LockDc(hDC);
344 }
345
346 // No need to init anything, just go!
347 for (; GdiBatchCount > 0; GdiBatchCount--)
348 {
349 ULONG Size;
350 // Process Gdi Batch!
351 Size = GdiFlushUserBatch(pDC, (PGDIBATCHHDR) pHdr);
352 if (!Size) break;
353 pHdr += Size;
354 }
355
356 if (pDC)
357 {
358 DC_UnlockDc(pDC);
359 }
360
361 // Exit and clear out for the next round.
362 pTeb->GdiTebBatch.Offset = 0;
363 pTeb->GdiBatchCount = 0;
364 pTeb->GdiTebBatch.HDC = 0;
365 }
366 }
367
368 // FIXME: On Windows XP the function returns &pTeb->RealClientId, maybe VOID?
369 return STATUS_SUCCESS;
370 }
371
372