comparison src/video/dga/SDL_dgavideo.c @ 101:825b2fa28e2e

DGA video driver is now thread-safe Improved DGA hardware acceleration code
author Sam Lantinga <slouken@lokigames.com>
date Thu, 12 Jul 2001 20:42:22 +0000
parents e85e03f195b4
children 9162d62280b5
comparison
equal deleted inserted replaced
100:a1c973c35fef 101:825b2fa28e2e
56 SDL_Color *colors); 56 SDL_Color *colors);
57 static int DGA_SetGammaRamp(_THIS, Uint16 *ramp); 57 static int DGA_SetGammaRamp(_THIS, Uint16 *ramp);
58 static void DGA_VideoQuit(_THIS); 58 static void DGA_VideoQuit(_THIS);
59 59
60 /* Hardware surface functions */ 60 /* Hardware surface functions */
61 static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size); 61 static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size);
62 static void DGA_FreeHWSurfaces(_THIS); 62 static void DGA_FreeHWSurfaces(_THIS);
63 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface); 63 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface);
64 static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color); 64 static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
65 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst); 65 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst);
66 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface); 66 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface);
407 SDL_SetError("Unable to create lock mutex"); 407 SDL_SetError("Unable to create lock mutex");
408 DGA_VideoQuit(this); 408 DGA_VideoQuit(this);
409 return(-1); 409 return(-1);
410 } 410 }
411 411
412 #ifdef LOCK_DGA_DISPLAY
413 /* Create the event lock so we're thread-safe.. :-/ */
414 event_lock = SDL_CreateMutex();
415 #endif /* LOCK_DGA_DISPLAY */
416
412 /* We're done! */ 417 /* We're done! */
413 return(0); 418 return(0);
414 } 419 }
415 420
416 SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 421 SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
533 /* Allocate memory tracking for hardware surfaces */ 538 /* Allocate memory tracking for hardware surfaces */
534 DGA_FreeHWSurfaces(this); 539 DGA_FreeHWSurfaces(this);
535 if ( surfaces_len < 0 ) { 540 if ( surfaces_len < 0 ) {
536 surfaces_len = 0; 541 surfaces_len = 0;
537 } 542 }
538 DGA_InitHWSurfaces(this, surfaces_mem, surfaces_len); 543 DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
539 544
540 /* Set the update rectangle function */ 545 /* Set the update rectangle function */
541 this->UpdateRects = DGA_DirectUpdate; 546 this->UpdateRects = DGA_DirectUpdate;
542 547
543 /* Enable mouse and keyboard support */ 548 /* Enable mouse and keyboard support */
579 } 584 }
580 printf("\n"); 585 printf("\n");
581 } 586 }
582 #endif 587 #endif
583 588
584 static int DGA_InitHWSurfaces(_THIS, Uint8 *base, int size) 589 static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size)
585 { 590 {
586 surfaces.prev = NULL; 591 vidmem_bucket *bucket;
587 surfaces.used = 0; 592
588 surfaces.base = base;
589 surfaces.size = size;
590 surfaces.next = NULL;
591 surfaces_memtotal = size; 593 surfaces_memtotal = size;
592 surfaces_memleft = size; 594 surfaces_memleft = size;
595
596 if ( surfaces_memleft > 0 ) {
597 bucket = (vidmem_bucket *)malloc(sizeof(*bucket));
598 if ( bucket == NULL ) {
599 SDL_OutOfMemory();
600 return(-1);
601 }
602 bucket->prev = &surfaces;
603 bucket->used = 0;
604 bucket->dirty = 0;
605 bucket->base = base;
606 bucket->size = size;
607 bucket->next = NULL;
608 } else {
609 bucket = NULL;
610 }
611
612 surfaces.prev = NULL;
613 surfaces.used = 1;
614 surfaces.dirty = 0;
615 surfaces.base = screen->pixels;
616 surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
617 surfaces.next = bucket;
618 screen->hwdata = (struct private_hwdata *)&surfaces;
593 return(0); 619 return(0);
594 } 620 }
595 static void DGA_FreeHWSurfaces(_THIS) 621 static void DGA_FreeHWSurfaces(_THIS)
596 { 622 {
597 vidmem_bucket *bucket, *freeable; 623 vidmem_bucket *bucket, *freeable;
603 free(freeable); 629 free(freeable);
604 } 630 }
605 surfaces.next = NULL; 631 surfaces.next = NULL;
606 } 632 }
607 633
634 static __inline__ void DGA_AddDirtySurface(SDL_Surface *surface)
635 {
636 ((vidmem_bucket *)surface->hwdata)->dirty = 1;
637 }
638
639 static __inline__ int DGA_IsSurfaceDirty(SDL_Surface *surface)
640 {
641 return ((vidmem_bucket *)surface->hwdata)->dirty;
642 }
643
644 static __inline__ void DGA_WaitDirtySurfaces(_THIS)
645 {
646 vidmem_bucket *bucket;
647
648 /* Wait for graphic operations to complete */
649 XDGASync(DGA_Display, DGA_Screen);
650
651 /* Clear all surface dirty bits */
652 for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
653 bucket->dirty = 0;
654 }
655 }
656
608 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface) 657 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface)
609 { 658 {
610 vidmem_bucket *bucket; 659 vidmem_bucket *bucket;
611 int size; 660 int size;
612 int extra; 661 int extra;
662 int retval = 0;
613 663
614 /* Temporarily, we only allow surfaces the same width as display. 664 /* Temporarily, we only allow surfaces the same width as display.
615 Some blitters require the pitch between two hardware surfaces 665 Some blitters require the pitch between two hardware surfaces
616 to be the same. Others have interesting alignment restrictions. 666 to be the same. Others have interesting alignment restrictions.
617 */ 667 */
622 surface->pitch = SDL_VideoSurface->pitch; 672 surface->pitch = SDL_VideoSurface->pitch;
623 size = surface->h * surface->pitch; 673 size = surface->h * surface->pitch;
624 #ifdef DGA_DEBUG 674 #ifdef DGA_DEBUG
625 fprintf(stderr, "Allocating bucket of %d bytes\n", size); 675 fprintf(stderr, "Allocating bucket of %d bytes\n", size);
626 #endif 676 #endif
677 LOCK_DISPLAY();
627 678
628 /* Quick check for available mem */ 679 /* Quick check for available mem */
629 if ( size > surfaces_memleft ) { 680 if ( size > surfaces_memleft ) {
630 SDL_SetError("Not enough video memory"); 681 SDL_SetError("Not enough video memory");
631 return(-1); 682 retval = -1;
683 goto done;
632 } 684 }
633 685
634 /* Search for an empty bucket big enough */ 686 /* Search for an empty bucket big enough */
635 for ( bucket=&surfaces; bucket; bucket=bucket->next ) { 687 for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
636 if ( ! bucket->used && (size <= bucket->size) ) { 688 if ( ! bucket->used && (size <= bucket->size) ) {
637 break; 689 break;
638 } 690 }
639 } 691 }
640 if ( bucket == NULL ) { 692 if ( bucket == NULL ) {
641 SDL_SetError("Video memory too fragmented"); 693 SDL_SetError("Video memory too fragmented");
642 return(-1); 694 retval = -1;
695 goto done;
643 } 696 }
644 697
645 /* Create a new bucket for left-over memory */ 698 /* Create a new bucket for left-over memory */
646 extra = (bucket->size - size); 699 extra = (bucket->size - size);
647 if ( extra ) { 700 if ( extra ) {
651 fprintf(stderr, "Adding new free bucket of %d bytes\n", extra); 704 fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
652 #endif 705 #endif
653 newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket)); 706 newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
654 if ( newbucket == NULL ) { 707 if ( newbucket == NULL ) {
655 SDL_OutOfMemory(); 708 SDL_OutOfMemory();
656 return(-1); 709 retval = -1;
710 goto done;
657 } 711 }
658 newbucket->prev = bucket; 712 newbucket->prev = bucket;
659 newbucket->used = 0; 713 newbucket->used = 0;
660 newbucket->base = bucket->base+size; 714 newbucket->base = bucket->base+size;
661 newbucket->size = extra; 715 newbucket->size = extra;
667 } 721 }
668 722
669 /* Set the current bucket values and return it! */ 723 /* Set the current bucket values and return it! */
670 bucket->used = 1; 724 bucket->used = 1;
671 bucket->size = size; 725 bucket->size = size;
726 bucket->dirty = 0;
672 #ifdef DGA_DEBUG 727 #ifdef DGA_DEBUG
673 fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base); 728 fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
674 #endif 729 #endif
675 surfaces_memleft -= size; 730 surfaces_memleft -= size;
676 surface->flags |= SDL_HWSURFACE; 731 surface->flags |= SDL_HWSURFACE;
677 surface->pixels = bucket->base; 732 surface->pixels = bucket->base;
678 return(0); 733 surface->hwdata = (struct private_hwdata *)bucket;
734 done:
735 UNLOCK_DISPLAY();
736 return(retval);
679 } 737 }
680 static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface) 738 static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface)
681 { 739 {
682 vidmem_bucket *bucket, *freeable; 740 vidmem_bucket *bucket, *freeable;
683 741
684 /* Look for the bucket in the current list */ 742 /* Look for the bucket in the current list */
685 for ( bucket=&surfaces; bucket; bucket=bucket->next ) { 743 bucket = (vidmem_bucket *)surface->hwdata;
686 if ( bucket->base == (Uint8 *)surface->pixels ) {
687 break;
688 }
689 }
690 if ( (bucket == NULL) || ! bucket->used ) { 744 if ( (bucket == NULL) || ! bucket->used ) {
691 return; 745 return;
692 } 746 }
693 747
694 /* Add the memory back to the total */ 748 /* Add the memory back to the total */
722 bucket->next->prev = bucket->prev; 776 bucket->next->prev = bucket->prev;
723 } 777 }
724 free(freeable); 778 free(freeable);
725 } 779 }
726 surface->pixels = NULL; 780 surface->pixels = NULL;
781 surface->hwdata = NULL;
727 } 782 }
728 783
729 static __inline__ void dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y) 784 static __inline__ void dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
730 { 785 {
731 *x = (long)((Uint8 *)dst->pixels - memory_base)%memory_pitch; 786 *x = (long)((Uint8 *)dst->pixels - memory_base)%memory_pitch;
740 { 795 {
741 int x, y; 796 int x, y;
742 unsigned int w, h; 797 unsigned int w, h;
743 798
744 /* Don't fill the visible part of the screen, wait until flipped */ 799 /* Don't fill the visible part of the screen, wait until flipped */
800 LOCK_DISPLAY();
745 if ( was_flipped && (dst == this->screen) ) { 801 if ( was_flipped && (dst == this->screen) ) {
746 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) 802 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
747 /* Keep waiting for the hardware ... */ ; 803 /* Keep waiting for the hardware ... */ ;
748 was_flipped = 0; 804 was_flipped = 0;
749 } 805 }
754 h = rect->h; 810 h = rect->h;
755 #if 0 811 #if 0
756 printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y); 812 printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y);
757 #endif 813 #endif
758 XDGAFillRectangle(DGA_Display, DGA_Screen, x, y, w, h, color); 814 XDGAFillRectangle(DGA_Display, DGA_Screen, x, y, w, h, color);
759 sync_needed++;
760 XFlush(DGA_Display); 815 XFlush(DGA_Display);
816 DGA_AddDirtySurface(dst);
817 UNLOCK_DISPLAY();
761 return(0); 818 return(0);
762 } 819 }
763 820
764 static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, 821 static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
765 SDL_Surface *dst, SDL_Rect *dstrect) 822 SDL_Surface *dst, SDL_Rect *dstrect)
769 int dstx, dsty; 826 int dstx, dsty;
770 unsigned int w, h; 827 unsigned int w, h;
771 828
772 this = current_video; 829 this = current_video;
773 /* Don't blit to the visible part of the screen, wait until flipped */ 830 /* Don't blit to the visible part of the screen, wait until flipped */
831 LOCK_DISPLAY();
774 if ( was_flipped && (dst == this->screen) ) { 832 if ( was_flipped && (dst == this->screen) ) {
775 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) 833 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
776 /* Keep waiting for the hardware ... */ ; 834 /* Keep waiting for the hardware ... */ ;
777 was_flipped = 0; 835 was_flipped = 0;
778 } 836 }
792 srcx, srcy, w, h, dstx, dsty, src->format->colorkey); 850 srcx, srcy, w, h, dstx, dsty, src->format->colorkey);
793 } else { 851 } else {
794 XDGACopyArea(DGA_Display, DGA_Screen, 852 XDGACopyArea(DGA_Display, DGA_Screen,
795 srcx, srcy, w, h, dstx, dsty); 853 srcx, srcy, w, h, dstx, dsty);
796 } 854 }
797 sync_needed++;
798 XFlush(DGA_Display); 855 XFlush(DGA_Display);
856 DGA_AddDirtySurface(src);
857 DGA_AddDirtySurface(dst);
858 UNLOCK_DISPLAY();
799 return(0); 859 return(0);
800 } 860 }
801 861
802 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst) 862 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
803 { 863 {
824 src->map->hw_blit = HWAccelBlit; 884 src->map->hw_blit = HWAccelBlit;
825 } 885 }
826 return(accelerated); 886 return(accelerated);
827 } 887 }
828 888
829 static __inline__ void DGA_WaitHardware(_THIS) 889 static __inline__ void DGA_WaitFlip(_THIS)
830 { 890 {
831 if ( sync_needed ) {
832 XDGASync(DGA_Display, DGA_Screen);
833 sync_needed = 0;
834 }
835 if ( was_flipped ) { 891 if ( was_flipped ) {
836 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) ) 892 while ( XDGAGetViewportStatus(DGA_Display, DGA_Screen) )
837 /* Keep waiting for the hardware ... */ ; 893 /* Keep waiting for the hardware ... */ ;
838 was_flipped = 0; 894 was_flipped = 0;
839 } 895 }
840 } 896 }
841 897
842 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface) 898 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface)
843 { 899 {
844 if ( surface == SDL_VideoSurface ) { 900 if ( surface == this->screen ) {
845 SDL_mutexP(hw_lock); 901 SDL_mutexP(hw_lock);
846 DGA_WaitHardware(this); 902 LOCK_DISPLAY();
903 if ( DGA_IsSurfaceDirty(surface) ) {
904 DGA_WaitDirtySurfaces(this);
905 }
906 DGA_WaitFlip(this);
907 UNLOCK_DISPLAY();
908 } else {
909 if ( DGA_IsSurfaceDirty(surface) ) {
910 LOCK_DISPLAY();
911 DGA_WaitDirtySurfaces(this);
912 UNLOCK_DISPLAY();
913 }
847 } 914 }
848 return(0); 915 return(0);
849 } 916 }
850 static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface) 917 static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
851 { 918 {
852 if ( surface == SDL_VideoSurface ) { 919 if ( surface == this->screen ) {
853 SDL_mutexV(hw_lock); 920 SDL_mutexV(hw_lock);
854 } 921 }
855 } 922 }
856 923
857 static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface) 924 static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface)
858 { 925 {
859 /* Wait for vertical retrace and then flip display */ 926 /* Wait for vertical retrace and then flip display */
860 DGA_WaitHardware(this); 927 LOCK_DISPLAY();
928 if ( DGA_IsSurfaceDirty(this->screen) ) {
929 DGA_WaitDirtySurfaces(this);
930 }
931 DGA_WaitFlip(this);
861 XDGASetViewport(DGA_Display, DGA_Screen, 932 XDGASetViewport(DGA_Display, DGA_Screen,
862 0, flip_yoffset[flip_page], XDGAFlipRetrace); 933 0, flip_yoffset[flip_page], XDGAFlipRetrace);
863 XFlush(DGA_Display); 934 XFlush(DGA_Display);
935 UNLOCK_DISPLAY();
864 was_flipped = 1; 936 was_flipped = 1;
865 flip_page = !flip_page; 937 flip_page = !flip_page;
866 938
867 surface->pixels = flip_address[flip_page]; 939 surface->pixels = flip_address[flip_page];
868 return(0); 940 return(0);
889 xcmap[i].red = (colors[i].r<<8)|colors[i].r; 961 xcmap[i].red = (colors[i].r<<8)|colors[i].r;
890 xcmap[i].green = (colors[i].g<<8)|colors[i].g; 962 xcmap[i].green = (colors[i].g<<8)|colors[i].g;
891 xcmap[i].blue = (colors[i].b<<8)|colors[i].b; 963 xcmap[i].blue = (colors[i].b<<8)|colors[i].b;
892 xcmap[i].flags = (DoRed|DoGreen|DoBlue); 964 xcmap[i].flags = (DoRed|DoGreen|DoBlue);
893 } 965 }
966 LOCK_DISPLAY();
894 XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors); 967 XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
895 XSync(DGA_Display, False); 968 XSync(DGA_Display, False);
969 UNLOCK_DISPLAY();
896 970
897 /* That was easy. :) */ 971 /* That was easy. :) */
898 return(1); 972 return(1);
899 } 973 }
900 974
921 xcmap[i].red = ramp[0*256+c]; 995 xcmap[i].red = ramp[0*256+c];
922 xcmap[i].green = ramp[1*256+c]; 996 xcmap[i].green = ramp[1*256+c];
923 xcmap[i].blue = ramp[2*256+c]; 997 xcmap[i].blue = ramp[2*256+c];
924 xcmap[i].flags = (DoRed|DoGreen|DoBlue); 998 xcmap[i].flags = (DoRed|DoGreen|DoBlue);
925 } 999 }
1000 LOCK_DISPLAY();
926 XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors); 1001 XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
927 XSync(DGA_Display, False); 1002 XSync(DGA_Display, False);
1003 UNLOCK_DISPLAY();
928 return(0); 1004 return(0);
929 } 1005 }
930 1006
931 void DGA_VideoQuit(_THIS) 1007 void DGA_VideoQuit(_THIS)
932 { 1008 {
950 /* Clear the lock mutex */ 1026 /* Clear the lock mutex */
951 if ( hw_lock != NULL ) { 1027 if ( hw_lock != NULL ) {
952 SDL_DestroyMutex(hw_lock); 1028 SDL_DestroyMutex(hw_lock);
953 hw_lock = NULL; 1029 hw_lock = NULL;
954 } 1030 }
1031 #ifdef LOCK_DGA_DISPLAY
1032 if ( event_lock != NULL ) {
1033 SDL_DestroyMutex(event_lock);
1034 event_lock = NULL;
1035 }
1036 #endif /* LOCK_DGA_DISPLAY */
1037
955 1038
956 /* Clean up defined video modes */ 1039 /* Clean up defined video modes */
957 for ( i=0; i<NUM_MODELISTS; ++i ) { 1040 for ( i=0; i<NUM_MODELISTS; ++i ) {
958 if ( SDL_modelist[i] != NULL ) { 1041 if ( SDL_modelist[i] != NULL ) {
959 for ( j=0; SDL_modelist[i][j]; ++j ) { 1042 for ( j=0; SDL_modelist[i][j]; ++j ) {