[WIN32K]
[reactos.git] / subsystems / win32 / win32k / dib / dib24bpp.c
1 /*
2 * PROJECT: Win32 subsystem
3 * LICENSE: See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/dib/dib24bpp.c
5 * PURPOSE: Device Independant Bitmap functions, 24bpp
6 * PROGRAMMERS: Jason Filby
7 * Thomas Bluemel
8 * Gregor Anich
9 */
10
11 #include <win32k.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 VOID
17 DIB_24BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
18 {
19 PBYTE addr = (PBYTE)SurfObj->pvScan0 + (y * SurfObj->lDelta) + (x << 1) + x;
20 *(PUSHORT)(addr) = c & 0xFFFF;
21 *(addr + 2) = (c >> 16) & 0xFF;
22 }
23
24 ULONG
25 DIB_24BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
26 {
27 PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x << 1) + x;
28 return *(PUSHORT)(addr) + (*(addr + 2) << 16);
29 }
30
31
32
33 VOID
34 DIB_24BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
35 {
36 PBYTE addr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta + (x << 1) + x;
37 LONG lDelta = SurfObj->lDelta;
38
39 c &= 0xFFFFFF;
40 while(y1++ < y2)
41 {
42 *(PUSHORT)(addr) = c & 0xFFFF;
43 *(addr + 2) = c >> 16;
44
45 addr += lDelta;
46 }
47 }
48
49 BOOLEAN
50 DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
51 {
52 LONG i, j, sx, sy, xColor, f1;
53 PBYTE SourceBits, DestBits, SourceLine, DestLine;
54 PBYTE SourceBits_4BPP, SourceLine_4BPP;
55 PWORD SourceBits_16BPP, SourceLine_16BPP;
56
57 DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left * 3;
58
59 switch(BltInfo->SourceSurface->iBitmapFormat)
60 {
61 case BMF_1BPP:
62 sx = BltInfo->SourcePoint.x;
63 sy = BltInfo->SourcePoint.y;
64
65 for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
66 {
67 sx = BltInfo->SourcePoint.x;
68 for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
69 {
70 if(DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
71 {
72 DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
73 } else {
74 DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
75 }
76 sx++;
77 }
78 sy++;
79 }
80 break;
81
82 case BMF_4BPP:
83 SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
84
85 for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
86 {
87 SourceLine_4BPP = SourceBits_4BPP;
88 DestLine = DestBits;
89 sx = BltInfo->SourcePoint.x;
90 f1 = sx & 1;
91
92 for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
93 {
94 xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
95 (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
96 *DestLine++ = xColor & 0xff;
97 *(PWORD)DestLine = xColor >> 8;
98 DestLine += 2;
99 if(f1 == 1) { SourceLine_4BPP++; f1 = 0; } else { f1 = 1; }
100 sx++;
101 }
102
103 SourceBits_4BPP += BltInfo->SourceSurface->lDelta;
104 DestBits += BltInfo->DestSurface->lDelta;
105 }
106 break;
107
108 case BMF_8BPP:
109 SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
110 DestLine = DestBits;
111
112 for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
113 {
114 SourceBits = SourceLine;
115 DestBits = DestLine;
116
117 for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
118 {
119 xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceBits);
120 *DestBits = xColor & 0xff;
121 *(PWORD)(DestBits + 1) = xColor >> 8;
122 SourceBits += 1;
123 DestBits += 3;
124 }
125
126 SourceLine += BltInfo->SourceSurface->lDelta;
127 DestLine += BltInfo->DestSurface->lDelta;
128 }
129 break;
130
131 case BMF_16BPP:
132 SourceBits_16BPP = (PWORD)((PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x);
133
134 for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
135 {
136 SourceLine_16BPP = SourceBits_16BPP;
137 DestLine = DestBits;
138
139 for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
140 {
141 xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceLine_16BPP);
142 *DestLine++ = xColor & 0xff;
143 *(PWORD)DestLine = xColor >> 8;
144 DestLine += 2;
145 SourceLine_16BPP++;
146 }
147
148 SourceBits_16BPP = (PWORD)((PBYTE)SourceBits_16BPP + BltInfo->SourceSurface->lDelta);
149 DestBits += BltInfo->DestSurface->lDelta;
150 }
151 break;
152
153 case BMF_24BPP:
154 if (NULL == BltInfo->XlateSourceToDest || 0 != (BltInfo->XlateSourceToDest->flXlate & XO_TRIVIAL))
155 {
156 if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
157 {
158 SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
159 for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
160 {
161 RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
162 SourceBits += BltInfo->SourceSurface->lDelta;
163 DestBits += BltInfo->DestSurface->lDelta;
164 }
165 }
166 else
167 {
168 SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
169 DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + 3 * BltInfo->DestRect.left;
170 for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
171 {
172 RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
173 SourceBits -= BltInfo->SourceSurface->lDelta;
174 DestBits -= BltInfo->DestSurface->lDelta;
175 }
176 }
177 }
178 else
179 {
180 sx = BltInfo->SourcePoint.x;
181 sy = BltInfo->SourcePoint.y;
182
183 for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
184 {
185 sx = BltInfo->SourcePoint.x;
186 for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
187 {
188 DWORD pixel = DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy);
189 DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, pixel));
190 sx++;
191 }
192 sy++;
193 }
194 }
195 break;
196
197 case BMF_32BPP:
198 SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
199 DestLine = DestBits;
200
201 for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
202 {
203 SourceBits = SourceLine;
204 DestBits = DestLine;
205
206 for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
207 {
208 xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *((PDWORD) SourceBits));
209 *DestBits = xColor & 0xff;
210 *(PWORD)(DestBits + 1) = xColor >> 8;
211 SourceBits += 4;
212 DestBits += 3;
213 }
214
215 SourceLine += BltInfo->SourceSurface->lDelta;
216 DestLine += BltInfo->DestSurface->lDelta;
217 }
218 break;
219
220 default:
221 DbgPrint("DIB_24BPP_Bitblt: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
222 return FALSE;
223 }
224
225 return TRUE;
226 }
227
228 BOOLEAN
229 DIB_24BPP_BitBlt(PBLTINFO BltInfo)
230 {
231 ULONG DestX, DestY;
232 ULONG SourceX, SourceY;
233 ULONG PatternY = 0;
234 ULONG Dest, Source = 0, Pattern = 0;
235 BOOL UsesSource;
236 BOOL UsesPattern;
237 PBYTE DestBits;
238
239 UsesSource = ROP4_USES_SOURCE(BltInfo->Rop4);
240 UsesPattern = ROP4_USES_PATTERN(BltInfo->Rop4);
241
242 SourceY = BltInfo->SourcePoint.y;
243 DestBits = (PBYTE)(
244 (PBYTE)BltInfo->DestSurface->pvScan0 +
245 (BltInfo->DestRect.left << 1) + BltInfo->DestRect.left +
246 BltInfo->DestRect.top * BltInfo->DestSurface->lDelta);
247
248 if (UsesPattern)
249 {
250 if (BltInfo->PatternSurface)
251 {
252 PatternY = (BltInfo->DestRect.top - BltInfo->BrushOrigin.y) %
253 BltInfo->PatternSurface->sizlBitmap.cy;
254 }
255 else
256 {
257 if (BltInfo->Brush)
258 Pattern = BltInfo->Brush->iSolidColor;
259 }
260 }
261
262 for (DestY = BltInfo->DestRect.top; DestY < BltInfo->DestRect.bottom; DestY++)
263 {
264 SourceX = BltInfo->SourcePoint.x;
265
266 for (DestX = BltInfo->DestRect.left; DestX < BltInfo->DestRect.right; DestX++, DestBits += 3, SourceX++)
267 {
268 Dest = *((PUSHORT)DestBits) + (*(DestBits + 2) << 16);
269
270 if (UsesSource)
271 {
272 Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);
273 }
274
275 if (BltInfo->PatternSurface)
276 {
277 Pattern = DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX - BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY);
278 }
279
280 Dest = DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern) & 0xFFFFFF;
281 *(PUSHORT)(DestBits) = Dest & 0xFFFF;
282 *(DestBits + 2) = Dest >> 16;
283 }
284
285 SourceY++;
286 if (BltInfo->PatternSurface)
287 {
288 PatternY++;
289 PatternY %= BltInfo->PatternSurface->sizlBitmap.cy;
290 }
291 DestBits -= (BltInfo->DestRect.right - BltInfo->DestRect.left) * 3;
292 DestBits += BltInfo->DestSurface->lDelta;
293 }
294
295 return TRUE;
296 }
297
298 /* BitBlt Optimize */
299 BOOLEAN
300 DIB_24BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
301 {
302 ULONG DestY;
303
304 #if defined(_M_IX86) && !defined(_MSC_VER)
305 PBYTE xaddr = (PBYTE)DestSurface->pvScan0 + DestRect->top * DestSurface->lDelta + (DestRect->left << 1) + DestRect->left;
306 PBYTE addr;
307 ULONG Count;
308 ULONG xCount=DestRect->right - DestRect->left;
309
310 for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
311 {
312 Count = xCount;
313 addr = xaddr;
314 xaddr = (PBYTE)((ULONG_PTR)addr + DestSurface->lDelta);
315
316 if (Count < 8)
317 {
318 /* For small fills, don't bother doing anything fancy */
319 while (Count--)
320 {
321 *(PUSHORT)(addr) = color;
322 addr += 2;
323 *(addr) = color >> 16;
324 addr += 1;
325 }
326 }
327 else
328 {
329 /* Align to 4-byte address */
330 while (0 != ((ULONG_PTR) addr & 0x3))
331 {
332 *(PUSHORT)(addr) = color;
333 addr += 2;
334 *(addr) = color >> 16;
335 addr += 1;
336 Count--;
337 }
338 /* If the color we need to fill with is 0ABC, then the final mem pattern
339 * (note little-endianness) would be:
340 *
341 * |C.B.A|C.B.A|C.B.A|C.B.A| <- pixel borders
342 * |C.B.A.C|B.A.C.B|A.C.B.A| <- ULONG borders
343 *
344 * So, taking endianness into account again, we need to fill with these
345 * ULONGs: CABC BCAB ABCA */
346
347 /* This is about 30% faster than the generic C code below */
348 __asm__ __volatile__ (
349 " movl %1, %%ecx\n"
350 " andl $0xffffff, %%ecx\n" /* 0ABC */
351 " movl %%ecx, %%ebx\n" /* Construct BCAB in ebx */
352 " shrl $8, %%ebx\n"
353 " movl %%ecx, %%eax\n"
354 " shll $16, %%eax\n"
355 " orl %%eax, %%ebx\n"
356 " movl %%ecx, %%edx\n" /* Construct ABCA in edx */
357 " shll $8, %%edx\n"
358 " movl %%ecx, %%eax\n"
359 " shrl $16, %%eax\n"
360 " orl %%eax, %%edx\n"
361 " movl %%ecx, %%eax\n" /* Construct CABC in eax */
362 " shll $24, %%eax\n"
363 " orl %%ecx, %%eax\n"
364 " movl %2, %%ecx\n" /* Load count */
365 " shr $2, %%ecx\n"
366 " movl %3, %%edi\n" /* Load dest */
367 ".FL1:\n"
368 " movl %%eax, (%%edi)\n" /* Store 4 pixels, 12 bytes */
369 " movl %%ebx, 4(%%edi)\n"
370 " movl %%edx, 8(%%edi)\n"
371 " addl $12, %%edi\n"
372 " dec %%ecx\n"
373 " jnz .FL1\n"
374 " movl %%edi, %0\n"
375 : "=m"(addr)
376 : "m"(color), "m"(Count), "m"(addr)
377 : "%eax", "%ebx", "%ecx", "%edx", "%edi");
378 Count = Count & 0x03;
379 while (0 != Count--)
380 {
381 *(PUSHORT)(addr) = color;
382 addr += 2;
383 *(addr) = color >> 16;
384 addr += 1;
385 }
386 }
387 }
388 #else
389
390 for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
391 {
392 DIB_24BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);
393 }
394 #endif
395 return TRUE;
396 }
397
398 BOOLEAN
399 DIB_24BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
400 RECTL* DestRect, RECTL *SourceRect,
401 XLATEOBJ *ColorTranslation, ULONG iTransColor)
402 {
403 ULONG X, Y, SourceX, SourceY = 0, Source = 0, wd, Dest;
404 BYTE *DestBits;
405
406 LONG DstHeight;
407 LONG DstWidth;
408 LONG SrcHeight;
409 LONG SrcWidth;
410
411 DstHeight = DestRect->bottom - DestRect->top;
412 DstWidth = DestRect->right - DestRect->left;
413 SrcHeight = SourceRect->bottom - SourceRect->top;
414 SrcWidth = SourceRect->right - SourceRect->left;
415
416 DestBits = (BYTE*)((PBYTE)DestSurf->pvScan0 +
417 (DestRect->left * 3) +
418 DestRect->top * DestSurf->lDelta);
419 wd = DestSurf->lDelta - ((DestRect->right - DestRect->left) * 3);
420
421 for(Y = DestRect->top; Y < DestRect->bottom; Y++)
422 {
423 SourceY = SourceRect->top+(Y - DestRect->top) * SrcHeight / DstHeight;
424 for(X = DestRect->left; X < DestRect->right; X++, DestBits += 3)
425 {
426 SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
427 if (SourceX >= 0 && SourceY >= 0 &&
428 SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
429 {
430 Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
431 if(Source != iTransColor)
432 {
433 Dest = XLATEOBJ_iXlate(ColorTranslation, Source) & 0xFFFFFF;
434 *(PUSHORT)(DestBits) = Dest & 0xFFFF;
435 *(DestBits + 2) = Dest >> 16;
436 }
437 }
438 }
439
440 DestBits = (BYTE*)((ULONG_PTR)DestBits + wd);
441 }
442
443 return TRUE;
444 }
445
446 typedef union {
447 ULONG ul;
448 struct {
449 UCHAR red;
450 UCHAR green;
451 UCHAR blue;
452 UCHAR alpha;
453 } col;
454 } NICEPIXEL32;
455
456 static __inline UCHAR
457 Clamp8(ULONG val)
458 {
459 return (val > 255) ? 255 : val;
460 }
461
462 BOOLEAN
463 DIB_24BPP_AlphaBlend(SURFOBJ* Dest, SURFOBJ* Source, RECTL* DestRect,
464 RECTL* SourceRect, CLIPOBJ* ClipRegion,
465 XLATEOBJ* ColorTranslation, BLENDOBJ* BlendObj)
466 {
467 INT Rows, Cols, SrcX, SrcY;
468 register PUCHAR Dst;
469 BLENDFUNCTION BlendFunc;
470 register NICEPIXEL32 DstPixel, SrcPixel;
471 UCHAR Alpha, SrcBpp;
472
473 DPRINT("DIB_24BPP_AlphaBlend: srcRect: (%d,%d)-(%d,%d), dstRect: (%d,%d)-(%d,%d)\n",
474 SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
475 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
476
477 BlendFunc = BlendObj->BlendFunction;
478 if (BlendFunc.BlendOp != AC_SRC_OVER)
479 {
480 DPRINT1("BlendOp != AC_SRC_OVER\n");
481 return FALSE;
482 }
483 if (BlendFunc.BlendFlags != 0)
484 {
485 DPRINT1("BlendFlags != 0\n");
486 return FALSE;
487 }
488 if ((BlendFunc.AlphaFormat & ~AC_SRC_ALPHA) != 0)
489 {
490 DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendFunc.AlphaFormat);
491 return FALSE;
492 }
493 if ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0 &&
494 BitsPerFormat(Source->iBitmapFormat) != 32)
495 {
496 DPRINT1("Source bitmap must be 32bpp when AC_SRC_ALPHA is set\n");
497 return FALSE;
498 }
499
500 Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + (DestRect->top * Dest->lDelta) +
501 (DestRect->left * 3));
502 SrcBpp = BitsPerFormat(Source->iBitmapFormat);
503
504 Rows = 0;
505 SrcY = SourceRect->top;
506 while (++Rows <= DestRect->bottom - DestRect->top)
507 {
508 Cols = 0;
509 SrcX = SourceRect->left;
510 while (++Cols <= DestRect->right - DestRect->left)
511 {
512 if (!(BlendFunc.AlphaFormat & AC_SRC_ALPHA))
513 {
514 SrcPixel.ul = DIB_GetSource(Source, SrcX, SrcY, ColorTranslation);
515 SrcPixel.col.red *= BlendFunc.SourceConstantAlpha / 255;
516 SrcPixel.col.green *= BlendFunc.SourceConstantAlpha / 255;
517 SrcPixel.col.blue *= BlendFunc.SourceConstantAlpha / 255;
518 Alpha = BlendFunc.SourceConstantAlpha ;
519 }
520 else
521 {
522 SrcPixel.ul = DIB_GetSourceIndex(Source, SrcX, SrcY);
523 SrcPixel.col.red *= BlendFunc.SourceConstantAlpha / 255;
524 SrcPixel.col.green *= BlendFunc.SourceConstantAlpha / 255;
525 SrcPixel.col.blue *= BlendFunc.SourceConstantAlpha / 255;
526 SrcPixel.col.alpha *= BlendFunc.SourceConstantAlpha / 255;
527
528 Alpha = SrcPixel.col.alpha;
529 }
530
531 DstPixel.col.red = (*Dst) * (255 - Alpha) / 255 + SrcPixel.col.red ;
532 DstPixel.col.green = *(Dst+1) * (255 - Alpha) / 255 + SrcPixel.col.green ;
533 DstPixel.col.blue = *(Dst+2) * (255 - Alpha) / 255 + SrcPixel.col.blue ;
534 *Dst++ = DstPixel.col.red;
535 *Dst++ = DstPixel.col.green;
536 *Dst++ = DstPixel.col.blue;
537 SrcX = SourceRect->left + (Cols*(SourceRect->right - SourceRect->left))/(DestRect->right - DestRect->left);
538 }
539 Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + ((DestRect->top + Rows) * Dest->lDelta) +
540 (DestRect->left*3));
541 SrcY = SourceRect->top + (Rows*(SourceRect->bottom - SourceRect->top))/(DestRect->bottom - DestRect->top);
542 }
543
544 return TRUE;
545 }
546
547 /* EOF */