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