Mercurial > sdl-ios-xcode
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 ) { |