Mercurial > sdl-ios-xcode
comparison src/render/SDL_render.c @ 5159:307ccc9c135e
Made it possible to create a texture of any format, even if not supported by the renderer.
This allows me to reduce the set of formats supported by the renderers to the most optimal set, for a nice speed boost.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 03 Feb 2011 00:19:40 -0800 |
parents | fb424691cfc7 |
children | 657543cc92f9 |
comparison
equal
deleted
inserted
replaced
5158:f3ebd1950442 | 5159:307ccc9c135e |
---|---|
150 | 150 |
151 *info = renderer->info; | 151 *info = renderer->info; |
152 return 0; | 152 return 0; |
153 } | 153 } |
154 | 154 |
155 static SDL_bool | |
156 IsSupportedFormat(SDL_Renderer * renderer, Uint32 format) | |
157 { | |
158 Uint32 i; | |
159 | |
160 for (i = 0; i < renderer->info.num_texture_formats; ++i) { | |
161 if (renderer->info.texture_formats[i] == format) { | |
162 return SDL_TRUE; | |
163 } | |
164 } | |
165 return SDL_FALSE; | |
166 } | |
167 | |
168 static Uint32 | |
169 GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format) | |
170 { | |
171 Uint32 i; | |
172 SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format); | |
173 | |
174 /* We just want to match the first format that has the same channels */ | |
175 for (i = 0; i < renderer->info.num_texture_formats; ++i) { | |
176 if (SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) { | |
177 return renderer->info.texture_formats[i]; | |
178 } | |
179 } | |
180 return renderer->info.texture_formats[0]; | |
181 } | |
182 | |
155 SDL_Texture * | 183 SDL_Texture * |
156 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) | 184 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) |
157 { | 185 { |
158 SDL_Texture *texture; | 186 SDL_Texture *texture; |
159 | 187 |
160 CHECK_RENDERER_MAGIC(renderer, NULL); | 188 CHECK_RENDERER_MAGIC(renderer, NULL); |
161 | 189 |
190 if (SDL_ISPIXELFORMAT_INDEXED(format)) { | |
191 SDL_SetError("Palettized textures are not supported"); | |
192 return NULL; | |
193 } | |
162 if (w <= 0 || h <= 0) { | 194 if (w <= 0 || h <= 0) { |
163 SDL_SetError("Texture dimensions can't be 0"); | 195 SDL_SetError("Texture dimensions can't be 0"); |
164 return 0; | 196 return NULL; |
165 } | 197 } |
166 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); | 198 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); |
167 if (!texture) { | 199 if (!texture) { |
168 SDL_OutOfMemory(); | 200 SDL_OutOfMemory(); |
169 return 0; | 201 return NULL; |
170 } | 202 } |
171 texture->magic = &texture_magic; | 203 texture->magic = &texture_magic; |
172 texture->format = format; | 204 texture->format = format; |
173 texture->access = access; | 205 texture->access = access; |
174 texture->w = w; | 206 texture->w = w; |
182 if (renderer->textures) { | 214 if (renderer->textures) { |
183 renderer->textures->prev = texture; | 215 renderer->textures->prev = texture; |
184 } | 216 } |
185 renderer->textures = texture; | 217 renderer->textures = texture; |
186 | 218 |
187 if (renderer->CreateTexture(renderer, texture) < 0) { | 219 if (IsSupportedFormat(renderer, format)) { |
188 SDL_DestroyTexture(texture); | 220 if (renderer->CreateTexture(renderer, texture) < 0) { |
189 return 0; | 221 SDL_DestroyTexture(texture); |
222 return 0; | |
223 } | |
224 } else { | |
225 texture->native = SDL_CreateTexture(renderer, | |
226 GetClosestSupportedFormat(renderer, format), | |
227 access, w, h); | |
228 if (!texture->native) { | |
229 SDL_DestroyTexture(texture); | |
230 return NULL; | |
231 } | |
232 | |
233 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { | |
234 texture->yuv = SDL_SW_CreateYUVTexture(format, w, h); | |
235 if (!texture->yuv) { | |
236 SDL_DestroyTexture(texture); | |
237 return NULL; | |
238 } | |
239 } else if (access == SDL_TEXTUREACCESS_STREAMING) { | |
240 /* The pitch is 4 byte aligned */ | |
241 texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); | |
242 texture->pixels = SDL_malloc(texture->pitch * h); | |
243 if (!texture->pixels) { | |
244 SDL_DestroyTexture(texture); | |
245 return NULL; | |
246 } | |
247 } | |
190 } | 248 } |
191 return texture; | 249 return texture; |
192 } | 250 } |
193 | 251 |
194 SDL_Texture * | 252 SDL_Texture * |
499 } | 557 } |
500 return 0; | 558 return 0; |
501 } | 559 } |
502 | 560 |
503 int | 561 int |
504 SDL_QueryTexturePixels(SDL_Texture * texture, void **pixels, int *pitch) | |
505 { | |
506 SDL_Renderer *renderer; | |
507 | |
508 CHECK_TEXTURE_MAGIC(texture, -1); | |
509 | |
510 renderer = texture->renderer; | |
511 if (!renderer->QueryTexturePixels) { | |
512 SDL_Unsupported(); | |
513 return -1; | |
514 } | |
515 return renderer->QueryTexturePixels(renderer, texture, pixels, pitch); | |
516 } | |
517 | |
518 int | |
519 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b) | 562 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b) |
520 { | 563 { |
521 SDL_Renderer *renderer; | 564 SDL_Renderer *renderer; |
522 | 565 |
523 CHECK_TEXTURE_MAGIC(texture, -1); | 566 CHECK_TEXTURE_MAGIC(texture, -1); |
529 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR; | 572 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR; |
530 } | 573 } |
531 texture->r = r; | 574 texture->r = r; |
532 texture->g = g; | 575 texture->g = g; |
533 texture->b = b; | 576 texture->b = b; |
534 if (renderer->SetTextureColorMod) { | 577 if (texture->native) { |
578 return SDL_SetTextureColorMod(texture->native, r, g, b); | |
579 } else if (renderer->SetTextureColorMod) { | |
535 return renderer->SetTextureColorMod(renderer, texture); | 580 return renderer->SetTextureColorMod(renderer, texture); |
536 } else { | 581 } else { |
537 return 0; | 582 return 0; |
538 } | 583 } |
539 } | 584 } |
571 texture->modMode |= SDL_TEXTUREMODULATE_ALPHA; | 616 texture->modMode |= SDL_TEXTUREMODULATE_ALPHA; |
572 } else { | 617 } else { |
573 texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA; | 618 texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA; |
574 } | 619 } |
575 texture->a = alpha; | 620 texture->a = alpha; |
576 if (renderer->SetTextureAlphaMod) { | 621 if (texture->native) { |
622 return SDL_SetTextureAlphaMod(texture->native, alpha); | |
623 } else if (renderer->SetTextureAlphaMod) { | |
577 return renderer->SetTextureAlphaMod(renderer, texture); | 624 return renderer->SetTextureAlphaMod(renderer, texture); |
578 } else { | 625 } else { |
579 return 0; | 626 return 0; |
580 } | 627 } |
581 } | 628 } |
598 | 645 |
599 CHECK_TEXTURE_MAGIC(texture, -1); | 646 CHECK_TEXTURE_MAGIC(texture, -1); |
600 | 647 |
601 renderer = texture->renderer; | 648 renderer = texture->renderer; |
602 texture->blendMode = blendMode; | 649 texture->blendMode = blendMode; |
603 if (renderer->SetTextureBlendMode) { | 650 if (texture->native) { |
651 return SDL_SetTextureBlendMode(texture, blendMode); | |
652 } else if (renderer->SetTextureBlendMode) { | |
604 return renderer->SetTextureBlendMode(renderer, texture); | 653 return renderer->SetTextureBlendMode(renderer, texture); |
605 } else { | 654 } else { |
606 return 0; | 655 return 0; |
607 } | 656 } |
608 } | 657 } |
616 *blendMode = texture->blendMode; | 665 *blendMode = texture->blendMode; |
617 } | 666 } |
618 return 0; | 667 return 0; |
619 } | 668 } |
620 | 669 |
670 static int | |
671 SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, | |
672 const void *pixels, int pitch) | |
673 { | |
674 SDL_Texture *native = texture->native; | |
675 SDL_Rect full_rect; | |
676 | |
677 if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) { | |
678 return -1; | |
679 } | |
680 | |
681 full_rect.x = 0; | |
682 full_rect.y = 0; | |
683 full_rect.w = texture->w; | |
684 full_rect.h = texture->h; | |
685 rect = &full_rect; | |
686 | |
687 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { | |
688 /* We can lock the texture and copy to it */ | |
689 void *native_pixels; | |
690 int native_pitch; | |
691 | |
692 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { | |
693 return -1; | |
694 } | |
695 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, | |
696 rect->w, rect->h, native_pixels, native_pitch); | |
697 SDL_UnlockTexture(native); | |
698 } else { | |
699 /* Use a temporary buffer for updating */ | |
700 void *temp_pixels; | |
701 int temp_pitch; | |
702 | |
703 temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); | |
704 temp_pixels = SDL_malloc(rect->h * temp_pitch); | |
705 if (!temp_pixels) { | |
706 SDL_OutOfMemory(); | |
707 return -1; | |
708 } | |
709 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, | |
710 rect->w, rect->h, temp_pixels, temp_pitch); | |
711 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); | |
712 SDL_free(temp_pixels); | |
713 } | |
714 return 0; | |
715 } | |
716 | |
717 static int | |
718 SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect, | |
719 const void *pixels, int pitch) | |
720 { | |
721 SDL_Texture *native = texture->native; | |
722 | |
723 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { | |
724 /* We can lock the texture and copy to it */ | |
725 void *native_pixels; | |
726 int native_pitch; | |
727 | |
728 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { | |
729 return -1; | |
730 } | |
731 SDL_ConvertPixels(rect->w, rect->h, | |
732 texture->format, pixels, pitch, | |
733 native->format, native_pixels, native_pitch); | |
734 SDL_UnlockTexture(native); | |
735 } else { | |
736 /* Use a temporary buffer for updating */ | |
737 void *temp_pixels; | |
738 int temp_pitch; | |
739 | |
740 temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); | |
741 temp_pixels = SDL_malloc(rect->h * temp_pitch); | |
742 if (!temp_pixels) { | |
743 SDL_OutOfMemory(); | |
744 return -1; | |
745 } | |
746 SDL_ConvertPixels(rect->w, rect->h, | |
747 texture->format, pixels, pitch, | |
748 native->format, temp_pixels, temp_pitch); | |
749 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); | |
750 SDL_free(temp_pixels); | |
751 } | |
752 return 0; | |
753 } | |
754 | |
621 int | 755 int |
622 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, | 756 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, |
623 const void *pixels, int pitch) | 757 const void *pixels, int pitch) |
624 { | 758 { |
625 SDL_Renderer *renderer; | 759 SDL_Renderer *renderer; |
626 SDL_Rect full_rect; | 760 SDL_Rect full_rect; |
627 | 761 |
628 CHECK_TEXTURE_MAGIC(texture, -1); | 762 CHECK_TEXTURE_MAGIC(texture, -1); |
629 | 763 |
630 renderer = texture->renderer; | |
631 if (!renderer->UpdateTexture) { | |
632 SDL_Unsupported(); | |
633 return -1; | |
634 } | |
635 if (!rect) { | 764 if (!rect) { |
636 full_rect.x = 0; | 765 full_rect.x = 0; |
637 full_rect.y = 0; | 766 full_rect.y = 0; |
638 full_rect.w = texture->w; | 767 full_rect.w = texture->w; |
639 full_rect.h = texture->h; | 768 full_rect.h = texture->h; |
640 rect = &full_rect; | 769 rect = &full_rect; |
641 } | 770 } |
642 return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); | 771 |
643 } | 772 if (texture->yuv) { |
644 | 773 return SDL_UpdateTextureYUV(texture, rect, pixels, pitch); |
645 int | 774 } else if (texture->native) { |
646 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, int markDirty, | 775 return SDL_UpdateTextureNative(texture, rect, pixels, pitch); |
776 } else { | |
777 renderer = texture->renderer; | |
778 return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); | |
779 } | |
780 } | |
781 | |
782 static int | |
783 SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, | |
784 void **pixels, int *pitch) | |
785 { | |
786 return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch); | |
787 } | |
788 | |
789 static int | |
790 SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect, | |
791 void **pixels, int *pitch) | |
792 { | |
793 texture->locked_rect = *rect; | |
794 *pixels = (void *) ((Uint8 *) texture->pixels + | |
795 rect->y * texture->pitch + | |
796 rect->x * SDL_BYTESPERPIXEL(texture->format)); | |
797 *pitch = texture->pitch; | |
798 return 0; | |
799 } | |
800 | |
801 int | |
802 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, | |
647 void **pixels, int *pitch) | 803 void **pixels, int *pitch) |
648 { | 804 { |
649 SDL_Renderer *renderer; | 805 SDL_Renderer *renderer; |
650 SDL_Rect full_rect; | 806 SDL_Rect full_rect; |
651 | 807 |
653 | 809 |
654 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { | 810 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { |
655 SDL_SetError("SDL_LockTexture(): texture must be streaming"); | 811 SDL_SetError("SDL_LockTexture(): texture must be streaming"); |
656 return -1; | 812 return -1; |
657 } | 813 } |
658 renderer = texture->renderer; | 814 |
659 if (!renderer->LockTexture) { | |
660 SDL_Unsupported(); | |
661 return -1; | |
662 } | |
663 if (!rect) { | 815 if (!rect) { |
664 full_rect.x = 0; | 816 full_rect.x = 0; |
665 full_rect.y = 0; | 817 full_rect.y = 0; |
666 full_rect.w = texture->w; | 818 full_rect.w = texture->w; |
667 full_rect.h = texture->h; | 819 full_rect.h = texture->h; |
668 rect = &full_rect; | 820 rect = &full_rect; |
669 } | 821 } |
670 return renderer->LockTexture(renderer, texture, rect, markDirty, pixels, | 822 |
671 pitch); | 823 if (texture->yuv) { |
824 return SDL_LockTextureYUV(texture, rect, pixels, pitch); | |
825 } else if (texture->native) { | |
826 return SDL_LockTextureNative(texture, rect, pixels, pitch); | |
827 } else { | |
828 renderer = texture->renderer; | |
829 return renderer->LockTexture(renderer, texture, rect, pixels, pitch); | |
830 } | |
831 } | |
832 | |
833 static void | |
834 SDL_UnlockTextureYUV(SDL_Texture * texture) | |
835 { | |
836 SDL_Texture *native = texture->native; | |
837 void *native_pixels; | |
838 int native_pitch; | |
839 SDL_Rect rect; | |
840 | |
841 rect.x = 0; | |
842 rect.y = 0; | |
843 rect.w = texture->w; | |
844 rect.h = texture->h; | |
845 | |
846 if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) { | |
847 return; | |
848 } | |
849 SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format, | |
850 rect.w, rect.h, native_pixels, native_pitch); | |
851 SDL_UnlockTexture(native); | |
852 } | |
853 | |
854 void | |
855 SDL_UnlockTextureNative(SDL_Texture * texture) | |
856 { | |
857 SDL_Texture *native = texture->native; | |
858 void *native_pixels; | |
859 int native_pitch; | |
860 const SDL_Rect *rect = &texture->locked_rect; | |
861 const void* pixels = (void *) ((Uint8 *) texture->pixels + | |
862 rect->y * texture->pitch + | |
863 rect->x * SDL_BYTESPERPIXEL(texture->format)); | |
864 int pitch = texture->pitch; | |
865 | |
866 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { | |
867 return; | |
868 } | |
869 SDL_ConvertPixels(rect->w, rect->h, | |
870 texture->format, pixels, pitch, | |
871 native->format, native_pixels, native_pitch); | |
872 SDL_UnlockTexture(native); | |
672 } | 873 } |
673 | 874 |
674 void | 875 void |
675 SDL_UnlockTexture(SDL_Texture * texture) | 876 SDL_UnlockTexture(SDL_Texture * texture) |
676 { | 877 { |
679 CHECK_TEXTURE_MAGIC(texture, ); | 880 CHECK_TEXTURE_MAGIC(texture, ); |
680 | 881 |
681 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { | 882 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { |
682 return; | 883 return; |
683 } | 884 } |
684 renderer = texture->renderer; | 885 if (texture->yuv) { |
685 if (!renderer->UnlockTexture) { | 886 SDL_UnlockTextureYUV(texture); |
686 return; | 887 } else if (texture->native) { |
687 } | 888 SDL_UnlockTextureNative(texture); |
688 renderer->UnlockTexture(renderer, texture); | 889 } else { |
689 } | 890 renderer = texture->renderer; |
690 | 891 renderer->UnlockTexture(renderer, texture); |
691 void | 892 } |
692 SDL_DirtyTexture(SDL_Texture * texture, int numrects, | |
693 const SDL_Rect * rects) | |
694 { | |
695 SDL_Renderer *renderer; | |
696 | |
697 CHECK_TEXTURE_MAGIC(texture, ); | |
698 | |
699 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { | |
700 return; | |
701 } | |
702 renderer = texture->renderer; | |
703 if (!renderer->DirtyTexture) { | |
704 return; | |
705 } | |
706 renderer->DirtyTexture(renderer, texture, numrects, rects); | |
707 } | 893 } |
708 | 894 |
709 int | 895 int |
710 SDL_SetRenderDrawColor(SDL_Renderer * renderer, | 896 SDL_SetRenderDrawColor(SDL_Renderer * renderer, |
711 Uint8 r, Uint8 g, Uint8 b, Uint8 a) | 897 Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
977 real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h; | 1163 real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h; |
978 real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h; | 1164 real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h; |
979 } | 1165 } |
980 } | 1166 } |
981 | 1167 |
1168 if (texture->native) { | |
1169 texture = texture->native; | |
1170 } | |
1171 | |
982 return renderer->RenderCopy(renderer, texture, &real_srcrect, | 1172 return renderer->RenderCopy(renderer, texture, &real_srcrect, |
983 &real_dstrect); | 1173 &real_dstrect); |
984 } | 1174 } |
985 | 1175 |
986 int | 1176 int |
1085 texture->prev->next = texture->next; | 1275 texture->prev->next = texture->next; |
1086 } else { | 1276 } else { |
1087 renderer->textures = texture->next; | 1277 renderer->textures = texture->next; |
1088 } | 1278 } |
1089 | 1279 |
1280 if (texture->native) { | |
1281 SDL_DestroyTexture(texture->native); | |
1282 } | |
1283 if (texture->yuv) { | |
1284 SDL_SW_DestroyYUVTexture(texture->yuv); | |
1285 } | |
1286 if (texture->pixels) { | |
1287 SDL_free(texture->pixels); | |
1288 } | |
1289 | |
1090 renderer->DestroyTexture(renderer, texture); | 1290 renderer->DestroyTexture(renderer, texture); |
1091 SDL_free(texture); | 1291 SDL_free(texture); |
1092 } | 1292 } |
1093 | 1293 |
1094 void | 1294 void |