6 * - Video Driver Helper Functions
10 #include <api_drv_video.h>
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);
25 tDrvUtil_Video_2DHandlers gDrvUtil_Stub_2DFunctions = {
27 DrvUtil_Video_2D_Fill,
30 tVideo_IOCtl_Bitmap gDrvUtil_TextModeCursor = {
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
54 // --- Video Driver Helpers ---
55 int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
56 tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
58 const Uint8 *stream = Buffer;
70 if(op > NUM_VIDEO_2DOPS) {
71 Log_Warning("DrvUtil",
72 "DrvUtil_Video_2DStream: Unknown operation %i",
77 if(op*sizeof(void*) > SizeofHandlers) {
78 Log_Warning("DrvUtil",
79 "DrvUtil_Video_2DStream: Driver does not support op %i",
86 case VIDEO_2DOP_NOP: break;
89 if(rem < 12) return Length-rem;
90 memcpy(tmp, stream, 6*2);
93 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
94 " does not support VIDEO_2DOP_FILL");
100 tmp[0], tmp[1], tmp[2], tmp[3],
101 tmp[4] | ((Uint32)tmp[5] << 16)
108 case VIDEO_2DOP_BLIT:
109 if(rem < 12) return Length-rem;
110 memcpy(tmp, stream, 6*2);
112 if(!Handlers->Blit) {
113 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
114 " does not support VIDEO_2DOP_BLIT");
120 tmp[0], tmp[1], tmp[2], tmp[3],
133 int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
136 const Uint32 *src = Buffer;
139 int bytes_per_px = (FBInfo->Depth + 7) / 8;
141 ENTER("pFBInfo xOffset xLength pBuffer",
142 FBInfo, Offset, Length, Buffer);
144 csr_x = FBInfo->CursorX;
145 csr_y = FBInfo->CursorY;
147 if( FBInfo->BackBuffer )
148 dest = FBInfo->BackBuffer;
150 dest = FBInfo->Framebuffer;
152 DrvUtil_Video_RemoveCursor(FBInfo);
154 switch( FBInfo->BufferFormat )
156 case VIDEO_BUFFMT_TEXT:
158 const tVT_Char *chars = Buffer;
159 int widthInChars = FBInfo->Width/giVT_CharWidth;
160 int heightInChars = FBInfo->Height/giVT_CharHeight;
163 LOG("bytes_per_px = %i", bytes_per_px);
164 LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
166 Length /= sizeof(tVT_Char); Offset /= sizeof(tVT_Char);
168 x = Offset % widthInChars; y = Offset / widthInChars;
169 LOG("x = %i, y = %i", x, y);
172 if(Offset > heightInChars * widthInChars) LEAVE_RET('i', 0);
173 if(y >= heightInChars) LEAVE_RET('i', 0);
175 if( Offset + Length > heightInChars*widthInChars )
177 Length = heightInChars*widthInChars - Offset;
180 LOG("dest = %p", dest);
181 ofs = y * giVT_CharHeight * FBInfo->Pitch;
184 for( i = 0; i < Length; i++ )
186 if( y >= heightInChars )
188 Log_Notice("DrvUtil", "Stopped at %i", i);
194 dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
195 VT_Colour12toN(chars->BGCol, FBInfo->Depth),
196 VT_Colour12toN(chars->FGCol, FBInfo->Depth)
201 if( x >= widthInChars )
205 dest += FBInfo->Pitch*giVT_CharHeight;
206 LOG("dest = %p", dest);
210 dest += FBInfo->Pitch*giVT_CharHeight;
211 Length = i * sizeof(tVT_Char);
215 case VIDEO_BUFFMT_FRAMEBUFFER:
216 if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
218 Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
222 switch(FBInfo->Depth)
226 Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
230 x = Offset % FBInfo->Width;
231 y = Offset / FBInfo->Width;
232 ofs = y*FBInfo->Pitch;
234 for( ; Length >= 4; Length -= 4 )
236 dest[x*3+0] = *src & 0xFF;
237 dest[x*3+1] = (*src >> 8) & 0xFF;
238 dest[x*3+2] = (*src >> 16) & 0xFF;
240 if(x == FBInfo->Width) {
241 dest += FBInfo->Pitch;
247 // Copy to Frambuffer
248 if( FBInfo->Pitch != FBInfo->Width*4 )
251 // Pitch isn't 4*Width
252 x = Offset % FBInfo->Width;
253 y = Offset / FBInfo->Height;
255 ofs = y*FBInfo->Pitch;
259 for( ; Length >= 4; Length -= 4 )
262 if( x == FBInfo->Width ) {
264 dest += FBInfo->Pitch;
269 dest += FBInfo->Pitch;
276 memcpy(dest, Buffer, Length);
281 Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depth %i", FBInfo->Depth);
287 case VIDEO_BUFFMT_2DSTREAM:
288 Length = DrvUtil_Video_2DStream(
289 FBInfo, Buffer, Length,
290 &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
299 if( FBInfo->BackBuffer && dest ) {
300 void *_dst = (char*)FBInfo->Framebuffer + ofs;
301 void *_src = (char*)FBInfo->BackBuffer + ofs;
302 size_t len = ((tVAddr)dest - (tVAddr)FBInfo->BackBuffer) - ofs;
303 // Log_Debug("DrvUtil", "Copy from BB %p to FB %p 0x%x bytes", _src, _dst, len);
304 memcpy(_dst, _src, len);
307 DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
313 int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
315 int csrX = Buf->CursorX, csrY = Buf->CursorY;
318 ENTER("pBuf pBitmap", Buf, Bitmap);
321 if( Buf->CursorBitmap )
323 LOG("Clearing old cursor");
324 DrvUtil_Video_RemoveCursor(Buf);
325 if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
327 free( Buf->CursorSaveBuf );
328 Buf->CursorSaveBuf = NULL;
330 if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
331 free(Buf->CursorBitmap);
332 Buf->CursorBitmap = NULL;
335 // If the new bitmap is null, disable drawing
344 // Sanity check the bitmap
345 LOG("Sanity checking plox");
346 if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
348 Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
353 ASSERTCR(Bitmap->W, >, 0, -1);
354 ASSERTCR(Bitmap->H, >, 0, -1);
355 ASSERTCR(Bitmap->XOfs, <, Bitmap->W, -1);
356 ASSERTCR(Bitmap->XOfs, >, -Bitmap->W, -1);
357 ASSERTCR(Bitmap->YOfs, <, Bitmap->H, -1);
358 ASSERTCR(Bitmap->YOfs, >, -Bitmap->H, -1);
360 // Don't take a copy of the DrvUtil provided cursor
361 if( Bitmap == &gDrvUtil_TextModeCursor )
363 LOG("No copy (provided cursor)");
364 Buf->CursorBitmap = Bitmap;
369 size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
372 Buf->CursorBitmap = malloc( size );
373 memcpy(Buf->CursorBitmap, Bitmap, size);
376 // Restore cursor position
378 DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
383 void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
385 int render_ox=0, render_oy=0, render_w, render_h;
387 ENTER("pBuf iX iY", Buf, X, Y);
388 DrvUtil_Video_RemoveCursor(Buf);
390 // X < 0 disables the cursor
398 if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
403 // Ensure the cursor is enabled
404 if( !Buf->CursorBitmap ) {
409 // Save cursor position (for changing the bitmap)
410 Buf->CursorX = X; Buf->CursorY = Y;
411 // Apply cursor's center offset
412 X -= Buf->CursorBitmap->XOfs;
413 Y -= Buf->CursorBitmap->YOfs;
415 // Get the width of the cursor on screen (clipping to right/bottom edges)
416 ASSERTC(Buf->Width, >, 0);
417 ASSERTC(Buf->Height, >, 0);
418 ASSERTC(Buf->CursorBitmap->W, >, 0);
419 ASSERTC(Buf->CursorBitmap->H, >, 0);
421 render_w = MIN(Buf->Width - X, Buf->CursorBitmap->W);
422 render_h = MIN(Buf->Height - Y, Buf->CursorBitmap->H);
423 //render_w = X > Buf->Width - Buf->CursorBitmap->W ? Buf->Width - X : Buf->CursorBitmap->W;
424 //render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
426 ASSERTC(render_w, >=, 0);
427 ASSERTC(render_h, >=, 0);
429 // Clipp to left/top edges
430 if(X < 0) { render_ox = -X; X = 0; }
431 if(Y < 0) { render_oy = -Y; Y = 0; }
434 Buf->CursorRenderW = render_w; Buf->CursorRenderH = render_h;
435 Buf->CursorDestX = X; Buf->CursorDestY = Y;
436 Buf->CursorReadX = render_ox; Buf->CursorReadY = render_oy;
438 LOG("%ix%i at %i,%i offset %i,%i",
439 render_w, render_h, X, Y, render_ox, render_oy);
441 // Call render routine
442 DrvUtil_Video_RenderCursor(Buf);
446 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
448 int src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
449 int render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
450 int dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
451 int bytes_per_px = (Buf->Depth + 7) / 8;
452 int save_pitch = Buf->CursorBitmap->W * bytes_per_px;
457 dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
458 src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
460 LOG("dest = %p, src = %p", dest, src);
462 // Allocate save buffer if not already
463 if( !Buf->CursorSaveBuf )
464 Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
466 ASSERTC(render_w, >=, 0);
467 ASSERTC(render_h, >=, 0);
470 // Save behind the cursor
471 for( y = 0; y < render_h; y ++ )
473 (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
474 (Uint8*)dest + y*Buf->Pitch,
475 render_w*bytes_per_px
483 //Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
484 //Proc_PrintBacktrace();
487 LOG("24-bit render");
488 for( y = 0; y < render_h; y ++ )
492 for(x = 0; x < render_w; x ++, px += 3)
494 Uint32 value = src[x];
495 // TODO: Should I implement alpha blending?
496 if(value & 0xFF000000)
498 px[0] = value & 0xFF;
499 px[1] = (value >> 8) & 0xFF;
500 px[2] = (value >> 16) & 0xFF;
505 src += Buf->CursorBitmap->W;
506 dest = (Uint8*)dest + Buf->Pitch;
510 LOG("32-bit render");
511 for( y = 0; y < render_h; y ++ )
515 for(x = 0; x < render_w; x ++, px ++)
517 Uint32 value = src[x];
518 // TODO: Should I implement alpha blending?
519 if(value & 0xFF000000)
522 ; // NOP, completely transparent
524 LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
525 src += Buf->CursorBitmap->W;
526 dest = (Uint8*)dest + Buf->Pitch;
530 Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
536 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
538 int bytes_per_px = (Buf->Depth + 7) / 8;
540 // Just a little sanity
541 if( !Buf->CursorBitmap || Buf->CursorX == -1 ) return ;
542 if( !Buf->CursorSaveBuf ) return ;
544 // Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
547 size_t save_pitch = Buf->CursorBitmap->W * bytes_per_px;
548 Uint8 *dst = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
549 const Uint8 *src = Buf->CursorSaveBuf;
551 ASSERT(Buf->Framebuffer);
553 ASSERT(CheckMem(dst, Buf->CursorRenderH*Buf->Pitch));
554 ASSERT(CheckMem(src, Buf->CursorRenderH*save_pitch));
556 // Copy each line back
557 for( int y = 0; y < Buf->CursorRenderH; y ++ )
559 memcpy( dst, src, Buf->CursorRenderW * bytes_per_px );
564 // Set the cursor as removed
568 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
570 tDrvUtil_Video_BufInfo *FBInfo = Ent;
572 switch( FBInfo->Depth )
575 // TODO: Be less hacky
576 size_t pitch = FBInfo->Pitch/4;
577 size_t ofs = Y*pitch + X;
578 Uint32 *buf = (Uint32*)FBInfo->Framebuffer + ofs;
580 if( FBInfo->BackBuffer )
581 cbuf = (Uint32*)FBInfo->BackBuffer + ofs;
586 for(int i = W; i--; line++)
591 for(int i = W; i--; line++ )
598 // TODO: Handle non-32bit modes
599 Log_Warning("DrvUtil", "TODO: <32bpp _Fill");
604 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
606 tDrvUtil_Video_BufInfo *FBInfo = Ent;
607 int scrnpitch = FBInfo->Pitch;
608 int bytes_per_px = (FBInfo->Depth + 7) / 8;
609 int dst = DstY*scrnpitch + DstX;
610 int src = SrcY*scrnpitch + SrcX;
612 Uint8 *framebuffer = FBInfo->Framebuffer;
613 Uint8 *backbuffer = FBInfo->BackBuffer;
614 Uint8 *sourcebuffer = (FBInfo->BackBuffer ? FBInfo->BackBuffer : FBInfo->Framebuffer);
616 //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
617 // Ent, DstX, DstY, SrcX, SrcY, W, H);
619 if(SrcX + W > FBInfo->Width) W = FBInfo->Width - SrcX;
620 if(DstX + W > FBInfo->Width) W = FBInfo->Width - DstX;
621 if(SrcY + H > FBInfo->Height) H = FBInfo->Height - SrcY;
622 if(DstY + H > FBInfo->Height) H = FBInfo->Height - DstY;
624 //Debug("W = %i, H = %i", W, H);
626 if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px)
628 memmove(framebuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
630 memmove(backbuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
641 tmp = W*bytes_per_px;
642 for( tmp = W; tmp --; )
644 size_t src_o = src + tmp;
645 size_t dst_o = src + tmp;
646 framebuffer[dst_o] = sourcebuffer[src_o];
648 backbuffer[dst_o] = sourcebuffer[src_o];
656 memcpy(framebuffer + dst, sourcebuffer + src, W*bytes_per_px);
658 memcpy(backbuffer + dst, sourcebuffer + src, W*bytes_per_px);
663 //Log("Vesa_2D_Blit: RETURN");