1000+% performance increase in 1bpp dib -> 1bpp dib blitting.
[reactos.git] / reactos / subsys / win32k / dib / dib1bpp.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: dib1bpp.c,v 1.15 2004/03/21 04:17:33 royce Exp $ */
20
21 #undef WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #include <stdlib.h>
24 #include <win32k/bitmaps.h>
25 #include <win32k/debug.h>
26 #include <debug.h>
27 #include <ddk/winddi.h>
28 #include "../eng/objects.h"
29 #include "dib.h"
30
31 VOID
32 DIB_1BPP_PutPixel(PSURFOBJ SurfObj, LONG x, LONG y, ULONG c)
33 {
34 PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
35
36 if ( !c )
37 *addr &= ~MASK1BPP(x);
38 else
39 *addr |= MASK1BPP(x);
40 }
41
42 ULONG
43 DIB_1BPP_GetPixel(PSURFOBJ SurfObj, LONG x, LONG y)
44 {
45 PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
46
47 return (*addr & MASK1BPP(x) ? 1 : 0);
48 }
49
50 VOID
51 DIB_1BPP_HLine(PSURFOBJ SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
52 {
53 while(x1 < x2) {
54 DIB_1BPP_PutPixel(SurfObj, x1, y, c);
55 x1++;
56 }
57 }
58
59 VOID
60 DIB_1BPP_VLine(PSURFOBJ SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
61 {
62 while(y1 < y2) {
63 DIB_1BPP_PutPixel(SurfObj, x, y1, c);
64 y1++;
65 }
66 }
67
68 static
69 void
70 DIB_1BPP_BitBltSrcCopy_From1BPP (
71 SURFOBJ* DestSurf, SURFOBJ* SourceSurf,
72 PRECTL DestRect, POINTL *SourcePoint )
73 {
74 // the 'window' in this sense is the x-position that corresponds
75 // to the left-edge of the 8-pixel byte we are currently working with.
76 // dwx is current x-window, dwx2 is the 'last' window we need to process
77 int dwx, dwx2; // destination window x-position
78 int swx; // source window y-position
79
80 // left and right edges of source and dest rectangles
81 int dl = DestRect->left; // dest left
82 int dr = DestRect->right-1; // dest right (inclusive)
83 int sl = SourcePoint->x; // source left
84 int sr = sl + dr - dl; // source right (inclusive)
85
86 // which direction are we going?
87 int xinc;
88 int yinc;
89
90 // following 4 variables are used for the y-sweep
91 int dy; // dest y
92 int dy1; // dest y start
93 int dy2; // dest y end
94 int sy1; // src y start
95
96 int shift;
97 BYTE srcmask, dstmask;
98
99 // 'd' and 's' are the dest & src buffer pointers that I use on my x-sweep
100 // 'pd' and 'ps' are the dest & src buffer pointers used on the inner y-sweep
101 PBYTE d, pd; // dest ptrs
102 PBYTE s, ps; // src ptrs
103
104 shift = (dl-sl)&7;
105
106 if ( DestRect->top <= SourcePoint->y )
107 {
108 // moving up ( scan top -> bottom )
109 dy1 = DestRect->top;
110 dy2 = DestRect->bottom - 1;
111 sy1 = SourcePoint->y;
112 yinc = 1;
113 }
114 else
115 {
116 // moving down ( scan bottom -> top )
117 dy1 = DestRect->bottom - 1;
118 dy2 = DestRect->top;
119 sy1 = SourcePoint->y + dy1 - dy2;
120 yinc = -1;
121 }
122 if ( DestRect->left <= SourcePoint->x )
123 {
124 // moving left ( scan left->right )
125 dwx = dl&~7;
126 swx = (sl-(dl&7))&~7;
127 dwx2 = dr&~7;
128 xinc = 1;
129 }
130 else
131 {
132 // moving right ( scan right->left )
133 dwx = dr&~7;
134 swx = (sr-(dr&7))&~7; //(sr-7)&~7; // we need the left edge of this block... thus the -7
135 dwx2 = dl&~7;
136 xinc = -1;
137 }
138 d = &(((PBYTE)DestSurf->pvScan0)[dy1*DestSurf->lDelta + (dwx>>3)]);
139 s = &(((PBYTE)SourceSurf->pvScan0)[sy1*SourceSurf->lDelta + (swx>>3)]);
140 for ( ;; )
141 {
142 dy = dy1;
143 pd = d;
144 ps = s;
145 srcmask = 0xff;
146 int dx = dwx; /* dest x for this pass */
147 if ( dwx < dl )
148 {
149 int diff = dl-dwx;
150 srcmask &= (1<<(8-diff))-1;
151 dx = dl;
152 }
153 if ( dwx+7 > dr )
154 {
155 int diff = dr-dwx+1;
156 srcmask &= ~((1<<(8-diff))-1);
157 }
158 dstmask = ~srcmask;
159
160 // we unfortunately *must* have 5 different versions of the inner
161 // loop to be certain we don't try to read from memory that is not
162 // needed and may in fact be invalid
163 if ( !shift )
164 {
165 for ( ;; )
166 {
167 *pd = (BYTE)((*pd & dstmask) | (*ps & srcmask));
168
169 // this *must* be here, because we could be going up *or* down...
170 if ( dy == dy2 )
171 break;
172 dy += yinc;
173 pd += yinc * DestSurf->lDelta;
174 ps += yinc * SourceSurf->lDelta;
175 }
176 }
177 else if ( !(0xFF00 & (srcmask<<shift) ) ) // check if ps[0] not needed...
178 {
179 for ( ;; )
180 {
181 *pd = (BYTE)((*pd & dstmask)
182 | ( ( ps[1] >> shift ) & srcmask ));
183
184 // this *must* be here, because we could be going up *or* down...
185 if ( dy == dy2 )
186 break;
187 dy += yinc;
188 pd += yinc * DestSurf->lDelta;
189 ps += yinc * SourceSurf->lDelta;
190 }
191 }
192 else if ( !(0xFF & (srcmask<<shift) ) ) // check if ps[1] not needed...
193 {
194 for ( ;; )
195 {
196 *pd = (*pd & dstmask)
197 | ( ( ps[0] << ( 8 - shift ) ) & srcmask );
198
199 // this *must* be here, because we could be going up *or* down...
200 if ( dy == dy2 )
201 break;
202 dy += yinc;
203 pd += yinc * DestSurf->lDelta;
204 ps += yinc * SourceSurf->lDelta;
205 }
206 }
207 else // both ps[0] and ps[1] are needed
208 {
209 for ( ;; )
210 {
211 *pd = (*pd & dstmask)
212 | ( ( ( (ps[1])|(ps[0]<<8) ) >> shift ) & srcmask );
213
214 // this *must* be here, because we could be going up *or* down...
215 if ( dy == dy2 )
216 break;
217 dy += yinc;
218 pd += yinc * DestSurf->lDelta;
219 ps += yinc * SourceSurf->lDelta;
220 }
221 }
222
223 // this *must* be here, because we could be going right *or* left...
224 if ( dwx == dwx2 )
225 break;
226 d += xinc;
227 s += xinc;
228 dwx += xinc<<3;
229 swx += xinc<<3;
230 }
231 }
232
233 BOOLEAN
234 DIB_1BPP_BitBltSrcCopy(
235 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
236 SURFGDI *DestGDI, SURFGDI *SourceGDI,
237 PRECTL DestRect, POINTL *SourcePoint,
238 XLATEOBJ *ColorTranslation)
239 {
240 LONG i, j, sx, sy = SourcePoint->y;
241
242 switch ( SourceGDI->BitsPerPixel )
243 {
244 case 1:
245 DIB_1BPP_BitBltSrcCopy_From1BPP ( DestSurf, SourceSurf, DestRect, SourcePoint );
246 break;
247
248 case 4:
249 for (j=DestRect->top; j<DestRect->bottom; j++)
250 {
251 sx = SourcePoint->x;
252 for (i=DestRect->left; i<DestRect->right; i++)
253 {
254 if(XLATEOBJ_iXlate(ColorTranslation, DIB_4BPP_GetPixel(SourceSurf, sx, sy)) == 0)
255 {
256 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
257 } else {
258 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
259 }
260 sx++;
261 }
262 sy++;
263 }
264 break;
265
266 case 8:
267 for (j=DestRect->top; j<DestRect->bottom; j++)
268 {
269 sx = SourcePoint->x;
270 for (i=DestRect->left; i<DestRect->right; i++)
271 {
272 if(XLATEOBJ_iXlate(ColorTranslation, DIB_8BPP_GetPixel(SourceSurf, sx, sy)) == 0)
273 {
274 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
275 } else {
276 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
277 }
278 sx++;
279 }
280 sy++;
281 }
282 break;
283
284 case 16:
285 for (j=DestRect->top; j<DestRect->bottom; j++)
286 {
287 sx = SourcePoint->x;
288 for (i=DestRect->left; i<DestRect->right; i++)
289 {
290 if(XLATEOBJ_iXlate(ColorTranslation, DIB_16BPP_GetPixel(SourceSurf, sx, sy)) == 0)
291 {
292 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
293 } else {
294 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
295 }
296 sx++;
297 }
298 sy++;
299 }
300 break;
301
302 case 24:
303 for (j=DestRect->top; j<DestRect->bottom; j++)
304 {
305 sx = SourcePoint->x;
306 for (i=DestRect->left; i<DestRect->right; i++)
307 {
308 if(XLATEOBJ_iXlate(ColorTranslation, DIB_24BPP_GetPixel(SourceSurf, sx, sy)) == 0)
309 {
310 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
311 } else {
312 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
313 }
314 sx++;
315 }
316 sy++;
317 }
318 break;
319
320 case 32:
321 for (j=DestRect->top; j<DestRect->bottom; j++)
322 {
323 sx = SourcePoint->x;
324 for (i=DestRect->left; i<DestRect->right; i++)
325 {
326 if(XLATEOBJ_iXlate(ColorTranslation, DIB_32BPP_GetPixel(SourceSurf, sx, sy)) == 0)
327 {
328 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
329 } else {
330 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
331 }
332 sx++;
333 }
334 sy++;
335 }
336 break;
337
338 default:
339 DbgPrint("DIB_1BPP_BitBlt: Unhandled Source BPP: %u\n", SourceGDI->BitsPerPixel);
340 return FALSE;
341 }
342
343 return TRUE;
344 }
345
346 BOOLEAN
347 DIB_1BPP_BitBlt(
348 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
349 SURFGDI *DestGDI, SURFGDI *SourceGDI,
350 PRECTL DestRect, POINTL *SourcePoint,
351 PBRUSHOBJ Brush, PPOINTL BrushOrigin,
352 XLATEOBJ *ColorTranslation, ULONG Rop4)
353 {
354 LONG i, j, k, sx, sy;
355 ULONG Dest, Source, Pattern;
356 PULONG DestBits;
357 BOOL UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
358 BOOL UsesPattern = ((Rop4 & 0xF00000) >> 4) != (Rop4 & 0x0F0000);
359 LONG RoundedRight = DestRect->right - ((DestRect->right - DestRect->left) & 0x7);
360
361 if (Rop4 == SRCCOPY)
362 {
363 return(DIB_1BPP_BitBltSrcCopy(DestSurf, SourceSurf, DestGDI, SourceGDI, DestRect, SourcePoint, ColorTranslation));
364 }
365 else
366 {
367 sy = SourcePoint->y;
368
369 for (j=DestRect->top; j<DestRect->bottom; j++)
370 {
371 sx = SourcePoint->x;
372 DestBits = (PULONG)(DestSurf->pvScan0 + (DestRect->left>>3) + j * DestSurf->lDelta);
373 for (i=DestRect->left; i<RoundedRight; i+=32, DestBits++)
374 {
375 Dest = *DestBits;
376 if (UsesSource)
377 {
378 Source = 0;
379 for (k = 0; k < 32; k++)
380 {
381 Source |= (DIB_GetSource(SourceSurf, SourceGDI, sx + (i - DestRect->left) + k, sy, ColorTranslation) << k);
382 }
383 }
384 if (UsesPattern)
385 {
386 /* FIXME: No support for pattern brushes. */
387 Pattern = Brush->iSolidColor ? 0xFFFFFFFF : 0x00000000;
388 }
389 *DestBits = DIB_DoRop(Rop4, Dest, Source, Pattern);
390 }
391 if (i < DestRect->right)
392 {
393 Dest = *DestBits;
394 for (; i < DestRect->right; i++)
395 {
396 if (UsesSource)
397 {
398 Source = DIB_GetSource(SourceSurf, SourceGDI, sx + (i - DestRect->left), sy, ColorTranslation);
399 }
400 if (UsesPattern)
401 {
402 /* FIXME: No support for pattern brushes. */
403 Pattern = Brush->iSolidColor ? 0xFFFFFFFF : 0x00000000;
404 }
405 DIB_1BPP_PutPixel(DestSurf, i, j, DIB_DoRop(Rop4, Dest, Source, Pattern) & 0xF);
406 Dest >>= 1;
407 }
408 }
409 sy++;
410 }
411 }
412 return TRUE;
413 }
414
415 BOOLEAN
416 DIB_1BPP_StretchBlt (
417 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
418 SURFGDI *DestGDI, SURFGDI *SourceGDI,
419 RECTL* DestRect, RECTL *SourceRect,
420 POINTL* MaskOrigin, POINTL* BrushOrigin,
421 XLATEOBJ *ColorTranslation, ULONG Mode)
422 {
423 DbgPrint("DIB_1BPP_StretchBlt: Source BPP: %u\n", SourceGDI->BitsPerPixel);
424 return FALSE;
425 }
426
427 /* EOF */