6 * - Common Driver/Filesystem Helper Functions
10 #include <api_drv_disk.h>
11 #include <api_drv_video.h>
16 //int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
17 //size_t DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
18 //void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
19 //void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
20 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
21 //void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
22 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
23 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
26 tDrvUtil_Video_2DHandlers gDrvUtil_Stub_2DFunctions = {
28 DrvUtil_Video_2D_Fill,
33 // --- Video Driver Helpers ---
34 int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
35 tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
37 void *stream = Buffer;
44 stream = (void*)((tVAddr)stream + 1);
46 if(op > NUM_VIDEO_2DOPS) {
47 Log_Warning("DrvUtil",
48 "DrvUtil_Video_2DStream: Unknown operation %i",
53 if(op*sizeof(void*) > SizeofHandlers) {
54 Log_Warning("DrvUtil",
55 "DrvUtil_Video_2DStream: Driver does not support op %i",
62 case VIDEO_2DOP_NOP: break;
65 if(rem < 12) return Length-rem;
68 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
69 " does not support VIDEO_2DOP_FILL");
75 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
76 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
81 stream = (void*)((tVAddr)stream + 12);
85 if(rem < 12) return Length-rem;
88 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
89 " does not support VIDEO_2DOP_BLIT");
95 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
96 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
97 ((Uint16*)stream)[4], ((Uint16*)stream)[5]
101 stream = (void*)((tVAddr)stream + 12);
109 int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Buffer)
112 ENTER("pFBInfo xOffset xLength pBuffer",
113 Mode, FBInfo, Offset, Length, Buffer);
114 switch( FBInfo->BufferFormat )
116 case VIDEO_BUFFMT_TEXT:
118 tVT_Char *chars = Buffer;
119 int bytes_per_px = (FBInfo->Depth + 7) / 8;
120 int widthInChars = FBInfo->Width/giVT_CharWidth;
121 int heightInChars = FBInfo->Height/giVT_CharHeight;
124 LOG("bytes_per_px = %i", bytes_per_px);
125 LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
127 Length /= sizeof(tVT_Char); Offset /= sizeof(tVT_Char);
129 x = Offset % widthInChars; y = Offset / widthInChars;
130 LOG("x = %i, y = %i", x, y);
133 if(Offset > heightInChars * widthInChars) LEAVE_RET('i', 0);
134 if(y >= heightInChars) LEAVE_RET('i', 0);
136 if( Offset + Length > heightInChars*widthInChars )
138 Length = heightInChars*widthInChars - Offset;
141 dest = FBInfo->Framebuffer;
142 LOG("dest = %p", dest);
143 dest += y * giVT_CharHeight * FBInfo->Pitch;
144 LOG("dest = %p", dest);
146 for( i = 0; i < Length; i++ )
148 if( y >= heightInChars )
150 Log_Notice("DrvUtil", "Stopped at %i", i);
156 dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
157 VT_Colour12toN(chars->BGCol, FBInfo->Depth),
158 VT_Colour12toN(chars->FGCol, FBInfo->Depth)
163 if( x >= widthInChars )
167 dest += FBInfo->Pitch*giVT_CharHeight;
168 LOG("dest = %p", dest);
171 Length = i * sizeof(tVT_Char);
175 case VIDEO_BUFFMT_FRAMEBUFFER:
176 if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
178 Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
182 //TODO: Handle non 32-bpp framebuffer modes
183 if( FBInfo->Depth != 32 ) {
184 Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Don't support non 32-bpp FB mode");
189 //TODO: Handle pitch != Width*BytesPerPixel
190 // Copy to Frambuffer
191 dest = (Uint8 *)FBInfo->Framebuffer + Offset;
192 memcpy(dest, Buffer, Length);
195 case VIDEO_BUFFMT_2DSTREAM:
196 Length = DrvUtil_Video_2DStream(
197 FBInfo, Buffer, Length,
198 &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
210 void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
212 int csrX = Buf->CursorX, csrY = Buf->CursorY;
216 if( Buf->CursorBitmap )
218 DrvUtil_Video_RemoveCursor(Buf);
219 if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
221 free( Buf->CursorSaveBuf );
222 Buf->CursorSaveBuf = NULL;
224 free(Buf->CursorBitmap);
225 Buf->CursorBitmap = NULL;
228 // If the new bitmap is null, disable drawing
236 // Check the new bitmap is valid
237 size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
238 if( !CheckMem(Bitmap, size) ) {
239 Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
244 Buf->CursorBitmap = malloc( size );
245 memcpy(Buf->CursorBitmap, Bitmap, size);
247 // Restore cursor position
248 DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
251 void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
253 int render_ox=0, render_oy=0, render_w, render_h;
255 // X < 0 disables the cursor
257 Render->CursorX = -1;
262 if( X < 0 || Y < 0 ) return;
263 if( X >= Buf->Width || Y >= Buf->Height ) return;
265 // Ensure the cursor is enabled
266 if( !Buf->CursorBitmap ) return ;
268 // Save cursor position (for changing the bitmap)
269 Buf->CursorX = X; Buf->CursorY = Y;
271 // Apply cursor's center offset
272 X -= Buf->CursorBitmap->XOfs;
273 Y -= Buf->CursorBitmap->YOfs;
275 // Get the width of the cursor on screen (clipping to right/bottom edges)
276 render_w = X > Buf->Width - Buf->CursorBitmap->W ? Buf->Width - X : Buf->CursorBitmap->W;
277 render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
279 // Clipp to left/top edges
280 if(X < 0) { render_ox = -X; X = 0; }
281 if(Y < 0) { render_oy = -Y; Y = 0; }
284 Buf->CursorRenderW = render_w; Buf->CursorRenderH = render_h;
285 Buf->CursorDestX = X; Buf->CursorDestY = Y;
286 Buf->CursorReadX = render_ox; Buf->CursorReadY = render_oy;
288 // Call render routine
289 DrvUtil_Video_RenderCursor(Buf);
292 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
294 int src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
295 int render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
296 int dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
297 int bytes_per_px = (Buf->Depth + 7) / 8;
298 int save_pitch = Buf->CursorBitmap->W * bytes_per_px;
303 dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
304 src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
306 // Allocate save buffer if not already
307 if( !Buf->CursorSaveBuf )
308 Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
310 // Save behind the cursor
311 for( y = 0; y < render_h; y ++ )
313 (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
314 (Uint8*)dest + y*Buf->Pitch,
315 render_w*bytes_per_px
321 for( y = 0; y < render_h; y ++ )
323 for(x = 0; x < render_w; x ++ )
325 // TODO: Should I implement alpha blending?
326 if(src[x] & 0xFF000000)
327 ((Uint32*)dest)[x] = src[x];
329 ; // NOP, completely transparent
331 src += Buf->CursorBitmap->W;
332 dest = (Uint8*)dest + Buf->Pitch;
336 Log_Error("DrvUtil", "TODO: Implement non 32-bpp cursor");
341 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
343 int bytes_per_px = (Buf->Depth + 7) / 8;
347 // Just a little sanity
348 if( !Buf->CursorBitmap || Buf->CursorX == -1 ) return ;
349 if( !Buf->CursorSaveBuf ) return ;
352 save_pitch = Buf->CursorBitmap->W * bytes_per_px;
353 dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
354 src = Buf->CursorSaveBuf;
356 // Copy each line back
357 for( y = 0; y < Buf->CursorRenderH; y ++ )
359 memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
364 // Set the cursor as removed
368 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
370 tDrvUtil_Video_BufInfo *FBInfo = Ent;
372 // TODO: Handle non-32bit modes
373 if( FBInfo->Depth != 32 ) return;
375 // TODO: Be less hacky
376 int pitch = FBInfo->Pitch/4;
377 Uint32 *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
382 for(i=W;i--;tmp++) *tmp = Colour;
387 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
389 tDrvUtil_Video_BufInfo *FBInfo = Ent;
390 int scrnpitch = FBInfo->Pitch;
391 int bytes_per_px = (FBInfo->Depth + 7) / 8;
392 int dst = DstY*scrnpitch + DstX;
393 int src = SrcY*scrnpitch + SrcX;
396 //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
397 // Ent, DstX, DstY, SrcX, SrcY, W, H);
399 if(SrcX + W > FBInfo->Width) W = FBInfo->Width - SrcX;
400 if(DstX + W > FBInfo->Width) W = FBInfo->Width - DstX;
401 if(SrcY + H > FBInfo->Height) H = FBInfo->Height - SrcY;
402 if(DstY + H > FBInfo->Height) H = FBInfo->Height - DstY;
404 //Debug("W = %i, H = %i", W, H);
413 tmp = W*bytes_per_px;
414 for( tmp = W; tmp --; ) {
415 *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
422 memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
427 //Log("Vesa_2D_Blit: RETURN");
431 // --- Disk Driver Helpers ---
432 Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
433 tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
435 Uint8 tmp[BlockSize]; // C99
436 Uint64 block = Start / BlockSize;
437 int offset = Start - block * BlockSize;
438 int leading = BlockSize - offset;
443 ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
444 Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
446 // Non aligned start, let's fix that!
449 if(leading > Length) leading = Length;
450 LOG("Reading %i bytes from Block1+%i", leading, offset);
451 ret = ReadBlocks(block, 1, tmp, Argument);
456 memcpy( Buffer, &tmp[offset], leading );
458 if(leading == Length) {
463 Buffer = (Uint8*)Buffer + leading;
465 num = ( Length - leading ) / BlockSize;
466 tailings = Length - num * BlockSize - leading;
469 num = Length / BlockSize;
470 tailings = Length % BlockSize;
473 // Read central blocks
476 LOG("Reading %i blocks", num);
477 ret = ReadBlocks(block, num, Buffer, Argument);
479 LEAVE('X', leading + ret * BlockSize);
480 return leading + ret * BlockSize;
484 // Read last tailing block
487 LOG("Reading %i bytes from last block", tailings);
489 Buffer = (Uint8*)Buffer + num * BlockSize;
490 ret = ReadBlocks(block, 1, tmp, Argument);
492 LEAVE('X', leading + num * BlockSize);
493 return leading + num * BlockSize;
495 memcpy( Buffer, tmp, tailings );
502 Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,
503 tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,
504 Uint64 BlockSize, Uint Argument)
506 Uint8 tmp[BlockSize]; // C99
507 Uint64 block = Start / BlockSize;
508 int offset = Start - block * BlockSize;
509 int leading = BlockSize - offset;
514 ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
515 Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
517 // Non aligned start, let's fix that!
520 if(leading > Length) leading = Length;
521 LOG("Writing %i bytes to Block1+%i", leading, offset);
522 // Read a copy of the block
523 ret = ReadBlocks(block, 1, tmp, Argument);
529 memcpy( &tmp[offset], Buffer, leading );
531 ret = WriteBlocks(block, 1, tmp, Argument);
537 if(leading == Length) {
542 Buffer = (Uint8*)Buffer + leading;
544 num = ( Length - leading ) / BlockSize;
545 tailings = Length - num * BlockSize - leading;
548 num = Length / BlockSize;
549 tailings = Length % BlockSize;
552 // Read central blocks
555 LOG("Writing %i blocks", num);
556 ret = WriteBlocks(block, num, Buffer, Argument);
558 LEAVE('X', leading + ret * BlockSize);
559 return leading + ret * BlockSize;
563 // Read last tailing block
566 LOG("Writing %i bytes to last block", tailings);
568 Buffer = (Uint8*)Buffer + num * BlockSize;
570 ret = ReadBlocks(block, 1, tmp, Argument);
572 LEAVE('X', leading + num * BlockSize);
573 return leading + num * BlockSize;
576 memcpy( tmp, Buffer, tailings );
578 ret = WriteBlocks(block, 1, tmp, Argument);
580 LEAVE('X', leading + num * BlockSize);
581 return leading + num * BlockSize;