094f0b1a7479e4b58b41f66d2d2390f5b7cdbffb
[tpg/acess2.git] / KernelLand / Kernel / drvutil_video.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge
4  *
5  * drvutil.c
6  * - Video Driver Helper Functions
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <api_drv_video.h>
11
12 // === TYPES ===
13
14 // === PROTOTYPES ===
15 //int   DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
16 //size_t        DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
17 //void  DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
18 //void  DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
19 void    DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
20 //void  DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
21 void    DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
22 void    DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
23
24 // === GLOBALS ===
25 tDrvUtil_Video_2DHandlers       gDrvUtil_Stub_2DFunctions = {
26         NULL,
27         DrvUtil_Video_2D_Fill,
28         DrvUtil_Video_2D_Blit
29 };
30 tVideo_IOCtl_Bitmap     gDrvUtil_TextModeCursor = {
31         8, 16,
32         0, 0,
33         {
34                 0, 0, 0         , 0, 0, 0, 0, 0,
35                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
36                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
37                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
38                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
39                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
40                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
41                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
42                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
43                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
44                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
45                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
46                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
47                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
48                 0, 0, 0         , 0, 0, 0, 0, 0,
49                 0, 0, 0         , 0, 0, 0, 0, 0
50         }
51 };
52
53 // === CODE ===
54 // --- Video Driver Helpers ---
55 int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
56         tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
57 {
58         const Uint8     *stream = Buffer;
59          int    rem = Length;
60          int    op;
61
62         Uint16  tmp[6];
63
64         while( rem )
65         {
66                 rem --;
67                 op = *stream;
68                 stream ++;
69                 
70                 if(op > NUM_VIDEO_2DOPS) {
71                         Log_Warning("DrvUtil",
72                                 "DrvUtil_Video_2DStream: Unknown operation %i",
73                                 op);
74                         return Length-rem;
75                 }
76                 
77                 if(op*sizeof(void*) > SizeofHandlers) {
78                         Log_Warning("DrvUtil",
79                                 "DrvUtil_Video_2DStream: Driver does not support op %i",
80                                 op);
81                         return Length-rem;
82                 }
83                 
84                 switch(op)
85                 {
86                 case VIDEO_2DOP_NOP:    break;
87                 
88                 case VIDEO_2DOP_FILL:
89                         if(rem < 12)    return Length-rem;
90                         memcpy(tmp, stream, 6*2);
91                         
92                         if(!Handlers->Fill) {
93                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
94                                         " does not support VIDEO_2DOP_FILL");
95                                 return Length-rem;
96                         }
97                         
98                         Handlers->Fill(
99                                 Ent, 
100                                 tmp[0], tmp[1], tmp[2], tmp[3],
101                                 tmp[4] | ((Uint32)tmp[5] << 16)
102                                 );
103                         
104                         rem -= 12;
105                         stream += 12;
106                         break;
107                 
108                 case VIDEO_2DOP_BLIT:
109                         if(rem < 12)    return Length-rem;
110                         memcpy(tmp, stream, 6*2);
111                         
112                         if(!Handlers->Blit) {
113                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
114                                         " does not support VIDEO_2DOP_BLIT");
115                                 return Length-rem;
116                         }
117                         
118                         Handlers->Blit(
119                                 Ent,
120                                 tmp[0], tmp[1], tmp[2], tmp[3],
121                                 tmp[4], tmp[5]
122                                 );
123                         
124                         rem -= 12;
125                         stream += 12;
126                         break;
127                 
128                 }
129         }
130         return 0;
131 }
132
133 int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
134 {
135         Uint8   *dest;
136         const Uint32    *src = Buffer;
137          int    csr_x, csr_y;
138          int    x, y;
139          int    bytes_per_px = (FBInfo->Depth + 7) / 8;
140         ENTER("pFBInfo xOffset xLength pBuffer",
141                 FBInfo, Offset, Length, Buffer);
142
143         csr_x = FBInfo->CursorX;
144         csr_y = FBInfo->CursorY;
145
146         DrvUtil_Video_RemoveCursor(FBInfo);
147
148         switch( FBInfo->BufferFormat )
149         {
150         case VIDEO_BUFFMT_TEXT:
151                 {
152                 const tVT_Char  *chars = Buffer;
153                  int    widthInChars = FBInfo->Width/giVT_CharWidth;
154                  int    heightInChars = FBInfo->Height/giVT_CharHeight;
155                  int    i;
156         
157                 LOG("bytes_per_px = %i", bytes_per_px);
158                 LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
159         
160                 Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
161                 
162                 x = Offset % widthInChars;      y = Offset / widthInChars;
163                 LOG("x = %i, y = %i", x, y);    
164         
165                 // Sanity Check
166                 if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
167                 if(y >= heightInChars)  LEAVE_RET('i', 0);
168                 
169                 if( Offset + Length > heightInChars*widthInChars )
170                 {
171                         Length = heightInChars*widthInChars - Offset;
172                 }
173                 
174                 dest = FBInfo->Framebuffer;
175                 LOG("dest = %p", dest);
176                 dest += y * giVT_CharHeight * FBInfo->Pitch;
177                 LOG("dest = %p", dest);
178                 
179                 for( i = 0; i < Length; i++ )
180                 {
181                         if( y >= heightInChars )
182                         {
183                                 Log_Notice("DrvUtil", "Stopped at %i", i);
184                                 break;
185                         }
186
187                         VT_Font_Render(
188                                 chars->Ch,
189                                 dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
190                                 VT_Colour12toN(chars->BGCol, FBInfo->Depth),
191                                 VT_Colour12toN(chars->FGCol, FBInfo->Depth)
192                                 );
193                         
194                         chars ++;
195                         x ++;
196                         if( x >= widthInChars )
197                         {
198                                 x = 0;
199                                 y ++;
200                                 dest += FBInfo->Pitch*giVT_CharHeight;
201                                 LOG("dest = %p", dest);
202                         }
203                 }
204                 Length = i * sizeof(tVT_Char);
205                 }
206                 break;
207         
208         case VIDEO_BUFFMT_FRAMEBUFFER:
209                 if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
210                 {
211                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
212                         return 0;
213                 }
214                 
215                 switch(FBInfo->Depth)
216                 {
217                 case 15:
218                 case 16:
219                         Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
220                         break;
221                 case 24:
222                         x = Offset % FBInfo->Width;
223                         y = Offset / FBInfo->Width;
224                         dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
225                         for( ; Length >= 4; Length -= 4 )
226                         {
227                                 dest[x*3+0] = *src & 0xFF;
228                                 dest[x*3+1] = (*src >> 8) & 0xFF;
229                                 dest[x*3+2] = (*src >> 16) & 0xFF;
230                                 x ++;
231                                 if(x == FBInfo->Width) {
232                                         dest += FBInfo->Pitch;
233                                         x = 0;
234                                 }
235                         }
236                         break;
237                 case 32:
238                         // Copy to Frambuffer
239                         if( FBInfo->Pitch != FBInfo->Width*4 )
240                         {
241                                 Uint32  *px;
242                                 // Pitch isn't 4*Width
243                                 x = Offset % FBInfo->Width;
244                                 y = Offset / FBInfo->Height;
245                                 
246                                 px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
247
248                                 for( ; Length >= 4; Length -= 4, x )
249                                 {
250                                         px[x++] = *src ++;
251                                         if( x == FBInfo->Width ) {
252                                                 x = 0;
253                                                 px += FBInfo->Pitch;
254                                         }
255                                 }
256                         }
257                         else
258                         {
259                                 dest = (Uint8 *)FBInfo->Framebuffer + Offset;
260                                 memcpy(dest, Buffer, Length);
261                         }
262                         break;
263                 default:
264                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
265                         break;
266                 }
267                 break;
268         
269         case VIDEO_BUFFMT_2DSTREAM:
270                 Length = DrvUtil_Video_2DStream(
271                         FBInfo, Buffer, Length,
272                         &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
273                         );
274                 break;
275         
276         default:
277                 LEAVE('i', -1);
278                 return -1;
279         }
280
281         DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
282
283         LEAVE('x', Length);
284         return Length;
285 }
286
287 int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
288 {
289          int    csrX = Buf->CursorX, csrY = Buf->CursorY;
290         size_t  size;
291
292         ENTER("pBuf pBitmap", Buf, Bitmap);
293
294         // Clear old bitmap
295         if( Buf->CursorBitmap )
296         {
297                 LOG("Clearing old cursor");
298                 DrvUtil_Video_RemoveCursor(Buf);
299                 if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
300                 {
301                         free( Buf->CursorSaveBuf );
302                         Buf->CursorSaveBuf = NULL;
303                 }
304                 if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
305                         free(Buf->CursorBitmap);
306                 Buf->CursorBitmap = NULL;
307         }
308         
309         // If the new bitmap is null, disable drawing
310         if( !Bitmap )
311         {
312                 Buf->CursorX = -1;
313                 Buf->CursorY = -1;
314                 LEAVE('i', 0);
315                 return 0;
316         }
317
318         // Sanity check the bitmap
319         LOG("Sanity checking plox");
320         if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
321         {
322                 Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
323                 errno = -EINVAL;
324                 LEAVE('i', -1);
325                 return -1;
326         }
327
328         // Don't take a copy of the DrvUtil provided cursor
329         if( Bitmap == &gDrvUtil_TextModeCursor )
330         {
331                 LOG("No copy (provided cursor)");
332                 Buf->CursorBitmap = Bitmap;
333         }
334         else
335         {
336                 LOG("Make copy");
337                 size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
338                 
339                 // Take a copy
340                 Buf->CursorBitmap = malloc( size );
341                 memcpy(Buf->CursorBitmap, Bitmap, size);
342         }
343         
344         // Restore cursor position
345         LOG("Drawing");
346         DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
347         LEAVE('i', 0);
348         return 0;
349 }
350
351 void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
352 {
353          int    render_ox=0, render_oy=0, render_w, render_h;
354
355         ENTER("pBuf iX iY", Buf, X, Y);
356         DrvUtil_Video_RemoveCursor(Buf);
357
358         // X < 0 disables the cursor
359         if( X < 0 ) {
360                 Buf->CursorX = -1;
361                 LEAVE('-');
362                 return ;
363         }
364
365         // Sanity checking
366         if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
367                 LEAVE('-');
368                 return ;
369         }
370
371         // Ensure the cursor is enabled
372         if( !Buf->CursorBitmap ) {
373                 LEAVE('-');
374                 return ;
375         }
376         
377         // Save cursor position (for changing the bitmap)
378         Buf->CursorX = X;       Buf->CursorY = Y;
379         // Apply cursor's center offset
380         X -= Buf->CursorBitmap->XOfs;
381         Y -= Buf->CursorBitmap->YOfs;
382         
383         // Get the width of the cursor on screen (clipping to right/bottom edges)
384         render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
385         render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
386
387         // Clipp to left/top edges
388         if(X < 0) {     render_ox = -X; X = 0;  }
389         if(Y < 0) {     render_oy = -Y; Y = 0;  }
390
391         // Save values
392         Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
393         Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
394         Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
395
396         LOG("%ix%i at %i,%i offset %i,%i",
397                 render_w, render_h, X, Y, render_ox, render_oy);
398
399         // Call render routine
400         DrvUtil_Video_RenderCursor(Buf);
401         LEAVE('-');
402 }
403
404 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
405 {
406          int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
407          int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
408          int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
409          int    bytes_per_px = (Buf->Depth + 7) / 8;
410          int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
411         void    *dest;
412         Uint32  *src;
413          int    x, y;
414
415         dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
416         src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
417         
418         LOG("dest = %p, src = %p", dest, src);
419
420         // Allocate save buffer if not already
421         if( !Buf->CursorSaveBuf )
422                 Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
423
424         LOG("Saving back");
425         // Save behind the cursor
426         for( y = 0; y < render_h; y ++ )
427                 memcpy(
428                         (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
429                         (Uint8*)dest + y*Buf->Pitch,
430                         render_w*bytes_per_px
431                         );
432
433         // Draw the cursor
434         switch(Buf->Depth)
435         {
436         case 15:
437         case 16:
438                 Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
439                 break;
440         case 24:
441                 LOG("24-bit render");
442                 for( y = 0; y < render_h; y ++ )
443                 {
444                         Uint8   *px;
445                         px = dest;
446                         for(x = 0; x < render_w; x ++, px += 3)
447                         {
448                                 Uint32  value = src[x];
449                                 // TODO: Should I implement alpha blending?
450                                 if(value & 0xFF000000)
451                                 {
452                                         px[0] = value & 0xFF;
453                                         px[1] = (value >> 8) & 0xFF;
454                                         px[2] = (value >> 16) & 0xFF;
455                                 }
456                                 else
457                                         ;
458                         }
459                         src += Buf->CursorBitmap->W;
460                         dest = (Uint8*)dest + Buf->Pitch;
461                 }
462                 break;
463         case 32:
464                 LOG("32-bit render");
465                 for( y = 0; y < render_h; y ++ )
466                 {
467                         Uint32  *px;
468                         px = dest;
469                         for(x = 0; x < render_w; x ++, px ++)
470                         {
471                                 Uint32  value = src[x];
472                                 // TODO: Should I implement alpha blending?
473                                 if(value & 0xFF000000)
474                                         *px = value;
475                                 else
476                                         ;       // NOP, completely transparent
477                         }
478                         LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
479                         src += Buf->CursorBitmap->W;
480                         dest = (Uint8*)dest + Buf->Pitch;
481                 }
482                 break;
483         default:
484                 Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
485                 Buf->CursorX = -1;
486                 break;
487         }
488 }
489
490 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
491 {
492          int    bytes_per_px = (Buf->Depth + 7) / 8;
493          int    y, save_pitch;
494         Uint8   *dest, *src;
495
496         // Just a little sanity
497         if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
498         if( !Buf->CursorSaveBuf )       return ;
499
500 //      Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
501
502         // Set up
503         save_pitch = Buf->CursorBitmap->W * bytes_per_px;
504         dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
505         src = Buf->CursorSaveBuf;
506         
507         // Copy each line back
508         for( y = 0; y < Buf->CursorRenderH; y ++ )
509         {
510                 memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
511                 src += save_pitch;
512                 dest += Buf->Pitch;
513         }
514         
515         // Set the cursor as removed
516         Buf->CursorX = -1;
517 }
518
519 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
520 {
521         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
522
523         // TODO: Handle non-32bit modes
524         if( FBInfo->Depth != 32 )       return;
525
526         // TODO: Be less hacky
527          int    pitch = FBInfo->Pitch/4;
528         Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
529         while( H -- ) {
530                 Uint32 *tmp;
531                  int    i;
532                 tmp = buf;
533                 for(i=W;i--;tmp++)      *tmp = Colour;
534                 buf += pitch;
535         }
536 }
537
538 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
539 {
540         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
541          int    scrnpitch = FBInfo->Pitch;
542          int    bytes_per_px = (FBInfo->Depth + 7) / 8;
543          int    dst = DstY*scrnpitch + DstX;
544          int    src = SrcY*scrnpitch + SrcX;
545          int    tmp;
546         
547         //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
548         //      Ent, DstX, DstY, SrcX, SrcY, W, H);
549         
550         if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
551         if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
552         if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
553         if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
554         
555         //Debug("W = %i, H = %i", W, H);
556         
557         if( dst > src ) {
558                 // Reverse copy
559                 dst += H*scrnpitch;
560                 src += H*scrnpitch;
561                 while( H -- ) {
562                         dst -= scrnpitch;
563                         src -= scrnpitch;
564                         tmp = W*bytes_per_px;
565                         for( tmp = W; tmp --; ) {
566                                 *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
567                         }
568                 }
569         }
570         else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
571                 memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
572         }
573         else {
574                 // Normal copy is OK
575                 while( H -- ) {
576                         memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
577                         dst += scrnpitch;
578                         src += scrnpitch;
579                 }
580         }
581         //Log("Vesa_2D_Blit: RETURN");
582 }
583         
584

UCC git Repository :: git.ucc.asn.au