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

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