src/video/sdlgenblit.pl
author Sam Lantinga
Mon, 28 Aug 2006 03:17:39 +0000
changeset 1985 8055185ae4ed
child 1989 5b5f5de5433f
permissions -rwxr-xr-x
Added source color and alpha modulation support.
Added perl script to generate optimized render copy functions.
     1 #!/usr/bin/perl -w
     2 #
     3 # A script to generate optimized C blitters for Simple DirectMedia Layer
     4 # http://www.libsdl.org/
     5 
     6 use warnings;
     7 use strict;
     8 
     9 my %file;
    10 
    11 # The formats potentially supported by this script:
    12 # SDL_PIXELFORMAT_INDEX8
    13 # SDL_PIXELFORMAT_RGB332
    14 # SDL_PIXELFORMAT_RGB444
    15 # SDL_PIXELFORMAT_RGB555
    16 # SDL_PIXELFORMAT_ARGB4444
    17 # SDL_PIXELFORMAT_ARGB1555
    18 # SDL_PIXELFORMAT_RGB565
    19 # SDL_PIXELFORMAT_RGB24
    20 # SDL_PIXELFORMAT_BGR24
    21 # SDL_PIXELFORMAT_RGB888
    22 # SDL_PIXELFORMAT_BGR888
    23 # SDL_PIXELFORMAT_ARGB8888
    24 # SDL_PIXELFORMAT_RGBA8888
    25 # SDL_PIXELFORMAT_ABGR8888
    26 # SDL_PIXELFORMAT_BGRA8888
    27 # SDL_PIXELFORMAT_ARGB2101010
    28 
    29 # The formats we're actually creating blitters for:
    30 my @src_formats = (
    31     "RGB888",
    32     "BGR888",
    33     "ARGB8888",
    34     "RGBA8888",
    35     "ABGR8888",
    36     "BGRA8888",
    37 );
    38 my @dst_formats = (
    39     "RGB888",
    40     "BGR888",
    41 );
    42 
    43 my %format_size = (
    44     "RGB888" => 4,
    45     "BGR888" => 4,
    46     "ARGB8888" => 4,
    47     "RGBA8888" => 4,
    48     "ABGR8888" => 4,
    49     "BGRA8888" => 4,
    50 );
    51 
    52 my %format_type = (
    53     "RGB888" => "Uint32",
    54     "BGR888" => "Uint32",
    55     "ARGB8888" => "Uint32",
    56     "RGBA8888" => "Uint32",
    57     "ABGR8888" => "Uint32",
    58     "BGRA8888" => "Uint32",
    59 );
    60 
    61 my %get_rgba_string = (
    62     "RGB888" => "_R = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _B = (Uint8)_pixel; _A = 0xFF;",
    63     "BGR888" => "_B = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _R = (Uint8)_pixel; _A = 0xFF;",
    64     "ARGB8888" => "_A = (Uint8)(_pixel >> 24); _R = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _B = (Uint8)_pixel;",
    65     "RGBA8888" => "_R = (Uint8)(_pixel >> 24); _G = (Uint8)(_pixel >> 16); _B = (Uint8)(_pixel >> 8); _A = (Uint8)_pixel;",
    66     "ABGR8888" => "_A = (Uint8)(_pixel >> 24); _B = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _R = (Uint8)_pixel;",
    67     "BGRA8888" => "_B = (Uint8)(_pixel >> 24); _G = (Uint8)(_pixel >> 16); _R = (Uint8)(_pixel >> 8); _A = (Uint8)_pixel;",
    68 );
    69 
    70 my %set_rgba_string = (
    71     "RGB888" => "_pixel = ((Uint32)_R << 16) | ((Uint32)_G << 8) | _B;",
    72     "BGR888" => "_pixel = ((Uint32)_B << 16) | ((Uint32)_G << 8) | _R;",
    73 );
    74 
    75 sub open_file {
    76     my $name = shift;
    77     open(FILE, ">$name.new") || die "Cant' open $name.new: $!";
    78     print FILE <<__EOF__;
    79 /* DO NOT EDIT!  This file is generated by sdlgenblit.pl */
    80 /*
    81     SDL - Simple DirectMedia Layer
    82     Copyright (C) 1997-2006 Sam Lantinga
    83 
    84     This library is free software; you can redistribute it and/or
    85     modify it under the terms of the GNU Lesser General Public
    86     License as published by the Free Software Foundation; either
    87     version 2.1 of the License, or (at your option) any later version.
    88 
    89     This library is distributed in the hope that it will be useful,
    90     but WITHOUT ANY WARRANTY; without even the implied warranty of
    91     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    92     Lesser General Public License for more details.
    93 
    94     You should have received a copy of the GNU Lesser General Public
    95     License along with this library; if not, write to the Free Software
    96     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    97 
    98     Sam Lantinga
    99     slouken\@libsdl.org
   100 */
   101 #include "SDL_config.h"
   102 
   103 /* *INDENT-OFF* */
   104 
   105 __EOF__
   106 }
   107 
   108 sub close_file {
   109     my $name = shift;
   110     print FILE <<__EOF__;
   111 /* *INDENT-ON* */
   112 
   113 /* vi: set ts=4 sw=4 expandtab: */
   114 __EOF__
   115     close FILE;
   116     if ( ! -f $name || system("cmp -s $name $name.new") != 0 ) {
   117         rename("$name.new", "$name");
   118     } else {
   119         unlink("$name.new");
   120     }
   121 }
   122 
   123 sub output_copydefs
   124 {
   125     print FILE <<__EOF__;
   126 #define SDL_RENDERCOPY_MODULATE_COLOR   0x0001
   127 #define SDL_RENDERCOPY_MODULATE_ALPHA   0x0002
   128 #define SDL_RENDERCOPY_BLEND            0x0010
   129 #define SDL_RENDERCOPY_ADD              0x0020
   130 #define SDL_RENDERCOPY_MOD              0x0040
   131 #define SDL_RENDERCOPY_NEAREST          0x0100
   132 
   133 typedef struct {
   134     void *src;
   135     int src_w, src_h;
   136     int src_pitch;
   137     void *dst;
   138     int dst_w, dst_h;
   139     int dst_pitch;
   140     void *aux_data;
   141     int flags;
   142     Uint8 r, g, b, a;
   143 } SDL_RenderCopyData;
   144 
   145 typedef int (*SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
   146 
   147 extern SDL_RenderCopyFunc SDLCALL SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode);
   148 
   149 __EOF__
   150 }
   151 
   152 sub output_copyfuncname
   153 {
   154     my $prefix = shift;
   155     my $src = shift;
   156     my $dst = shift;
   157     my $modulate = shift;
   158     my $blend = shift;
   159     my $scale = shift;
   160     my $args = shift;
   161     my $suffix = shift;
   162 
   163     print FILE "$prefix SDL_RenderCopy_${src}_${dst}";
   164     if ( $modulate ) {
   165         print FILE "_Modulate";
   166     }
   167     if ( $blend ) {
   168         print FILE "_Blend";
   169     }
   170     if ( $scale ) {
   171         print FILE "_Scale";
   172     }
   173     if ( $args ) {
   174         print FILE "(SDL_RenderCopyData *data)";
   175     }
   176     print FILE "$suffix";
   177 }
   178 
   179 sub get_rgba
   180 {
   181     my $prefix = shift;
   182     my $format = shift;
   183     my $string = $get_rgba_string{$format};
   184     $string =~ s/_/$prefix/g;
   185     if ( $prefix ne "" ) {
   186         print FILE <<__EOF__;
   187             ${prefix}pixel = *$prefix;
   188 __EOF__
   189     } else {
   190         print FILE <<__EOF__;
   191             pixel = *src;
   192 __EOF__
   193     }
   194     print FILE <<__EOF__;
   195             $string
   196 __EOF__
   197 }
   198 
   199 sub set_rgba
   200 {
   201     my $prefix = shift;
   202     my $format = shift;
   203     my $string = $set_rgba_string{$format};
   204     $string =~ s/_/$prefix/g;
   205     print FILE <<__EOF__;
   206             $string
   207             *dst = ${prefix}pixel;
   208 __EOF__
   209 }
   210 
   211 sub output_copycore
   212 {
   213     my $src = shift;
   214     my $dst = shift;
   215     my $modulate = shift;
   216     my $blend = shift;
   217     if ( $modulate ) {
   218         print FILE <<__EOF__;
   219             if (flags & SDL_RENDERCOPY_MODULATE_COLOR) {
   220                 ${src}R = (${src}R * modulateR) / 255;
   221                 ${src}G = (${src}G * modulateG) / 255;
   222                 ${src}B = (${src}B * modulateB) / 255;
   223             }
   224 __EOF__
   225     }
   226     if ( $modulate && $blend ) {
   227         print FILE <<__EOF__;
   228             if (flags & SDL_RENDERCOPY_MODULATE_ALPHA) {
   229                 ${src}A = (${src}A * modulateA) / 255;
   230             }
   231 __EOF__
   232     }
   233     if ( $blend ) {
   234         print FILE <<__EOF__;
   235             if (flags & (SDL_RENDERCOPY_BLEND|SDL_RENDERCOPY_ADD)) {
   236                 /* This goes away if we ever use premultiplied alpha */
   237                 ${src}R = (${src}R * ${src}A) / 255;
   238                 ${src}G = (${src}G * ${src}A) / 255;
   239                 ${src}B = (${src}B * ${src}A) / 255;
   240             }
   241             switch (flags & (SDL_RENDERCOPY_BLEND|SDL_RENDERCOPY_ADD|SDL_RENDERCOPY_MOD)) {
   242             case SDL_RENDERCOPY_BLEND:
   243                 ${dst}R = ${src}R + ((255 - ${src}A) * ${dst}R) / 255;
   244                 ${dst}G = ${src}G + ((255 - ${src}A) * ${dst}G) / 255;
   245                 ${dst}B = ${src}B + ((255 - ${src}A) * ${dst}B) / 255;
   246                 break;
   247             case SDL_RENDERCOPY_ADD:
   248                 ${dst}R = ${src}R + ${dst}R; if (${dst}R > 255) ${dst}R = 255;
   249                 ${dst}G = ${src}G + ${dst}G; if (${dst}G > 255) ${dst}G = 255;
   250                 ${dst}B = ${src}B + ${dst}B; if (${dst}B > 255) ${dst}B = 255;
   251                 break;
   252             case SDL_RENDERCOPY_MOD:
   253                 ${dst}R = (${src}R * ${dst}R) / 255;
   254                 ${dst}G = (${src}G * ${dst}G) / 255;
   255                 ${dst}B = (${src}B * ${dst}B) / 255;
   256                 break;
   257             }
   258 __EOF__
   259     }
   260 }
   261 
   262 sub output_copyfunc
   263 {
   264     my $src = shift;
   265     my $dst = shift;
   266     my $modulate = shift;
   267     my $blend = shift;
   268     my $scale = shift;
   269 
   270     output_copyfuncname("int", $src, $dst, $modulate, $blend, $scale, 1, "\n");
   271     print FILE <<__EOF__;
   272 {
   273     const int flags = data->flags;
   274 __EOF__
   275     if ( $modulate ) {
   276         print FILE <<__EOF__;
   277     const Uint32 modulateR = data->r;
   278     const Uint32 modulateG = data->g;
   279     const Uint32 modulateB = data->b;
   280     const Uint32 modulateA = data->a;
   281 __EOF__
   282     }
   283     if ( $blend ) {
   284         print FILE <<__EOF__;
   285     Uint32 srcpixel;
   286     Uint32 srcR, srcG, srcB, srcA;
   287     Uint32 dstpixel;
   288     Uint32 dstR, dstG, dstB, dstA;
   289 __EOF__
   290     } elsif ( $modulate || $src ne $dst ) {
   291         print FILE <<__EOF__;
   292     Uint32 pixel;
   293     Uint32 R, G, B, A;
   294 __EOF__
   295     }
   296     if ( $scale ) {
   297         print FILE <<__EOF__;
   298     int srcy, srcx;
   299     int posy, posx;
   300     int incy, incx;
   301 
   302     srcy = 0;
   303     posy = 0;
   304     incy = (data->src_h << 16) / data->dst_h;
   305     incx = (data->src_w << 16) / data->dst_w;
   306 
   307     while (data->dst_h--) {
   308         $format_type{$src} *src;
   309         $format_type{$dst} *dst = ($format_type{$dst} *)data->dst;
   310         int n = data->dst_w;
   311         srcx = -1;
   312         posx = 0x10000L;
   313         while (posy >= 0x10000L) {
   314             ++srcy;
   315             posy -= 0x10000L;
   316         }
   317         while (n--) {
   318             if (posx >= 0x10000L) {
   319                 while (posx >= 0x10000L) {
   320                     ++srcx;
   321                     posx -= 0x10000L;
   322                 }
   323                 src = ($format_type{$src} *)(data->src + (srcy * data->src_pitch) + (srcx * $format_size{$src}));
   324 __EOF__
   325         print FILE <<__EOF__;
   326             }
   327 __EOF__
   328         if ( $blend ) {
   329             get_rgba("src", $src);
   330             get_rgba("dst", $dst);
   331             output_copycore("src", "dst", $modulate, $blend);
   332             set_rgba("dst", $dst);
   333         } elsif ( $modulate || $src ne $dst ) {
   334             get_rgba("", $src);
   335             output_copycore("", "", $modulate, $blend);
   336             set_rgba("", $dst);
   337         } else {
   338             print FILE <<__EOF__;
   339             *dst = *src;
   340 __EOF__
   341         }
   342         print FILE <<__EOF__;
   343             posx += incx;
   344             ++dst;
   345         }
   346         posy += incy;
   347         data->dst += data->dst_pitch;
   348     }
   349 __EOF__
   350     } else {
   351         print FILE <<__EOF__;
   352 
   353     while (data->dst_h--) {
   354         $format_type{$src} *src = ($format_type{$src} *)data->src;
   355         $format_type{$dst} *dst = ($format_type{$dst} *)data->dst;
   356         int n = data->dst_w;
   357         while (n--) {
   358 __EOF__
   359         if ( $blend ) {
   360             get_rgba("src", $src);
   361             get_rgba("dst", $dst);
   362             output_copycore("src", "dst", $modulate, $blend);
   363             set_rgba("dst", $dst);
   364         } elsif ( $modulate || $src ne $dst ) {
   365             get_rgba("", $src);
   366             output_copycore("", "", $modulate, $blend);
   367             set_rgba("", $dst);
   368         } else {
   369             print FILE <<__EOF__;
   370             *dst = *src;
   371 __EOF__
   372         }
   373         print FILE <<__EOF__;
   374             ++src;
   375             ++dst;
   376         }
   377         data->src += data->src_pitch;
   378         data->dst += data->dst_pitch;
   379     }
   380 __EOF__
   381     }
   382     print FILE <<__EOF__;
   383     return 0;
   384 }
   385 
   386 __EOF__
   387 }
   388 
   389 sub output_copyfunc_h
   390 {
   391     my $src = shift;
   392     my $dst = shift;
   393     for (my $modulate = 0; $modulate <= 1; ++$modulate) {
   394         for (my $blend = 0; $blend <= 1; ++$blend) {
   395             for (my $scale = 0; $scale <= 1; ++$scale) {
   396                 if ( $modulate != 0 || $blend != 0 || $scale != 0 || $src ne $dst ) {
   397                     output_copyfuncname("extern int SDLCALL", $src, $dst, $modulate, $blend, $scale, 1, ";\n");
   398                 }
   399             }
   400         }
   401     }
   402 }
   403 
   404 sub output_copyinc
   405 {
   406     print FILE <<__EOF__;
   407 #include "SDL_video.h"
   408 #include "SDL_rendercopy.h"
   409 
   410 __EOF__
   411 }
   412 
   413 sub output_copyfunctable
   414 {
   415     print FILE <<__EOF__;
   416 static struct {
   417     Uint32 src_format;
   418     Uint32 dst_format;
   419     int modMode;
   420     int blendMode;
   421     int scaleMode;
   422     SDL_RenderCopyFunc func;
   423 } SDL_RenderCopyFuncTable[] = {
   424 __EOF__
   425     for (my $i = 0; $i <= $#src_formats; ++$i) {
   426         my $src = $src_formats[$i];
   427         for (my $j = 0; $j <= $#dst_formats; ++$j) {
   428             my $dst = $dst_formats[$j];
   429             for (my $modulate = 0; $modulate <= 1; ++$modulate) {
   430                 for (my $blend = 0; $blend <= 1; ++$blend) {
   431                     for (my $scale = 0; $scale <= 1; ++$scale) {
   432                         if ( $modulate != 0 || $blend != 0 || $scale != 0 || $src ne $dst ) {
   433                             print FILE "    { SDL_PIXELFORMAT_$src, SDL_PIXELFORMAT_$dst, ";
   434                             if ( $modulate ) {
   435                                 print FILE "(SDL_TEXTUREMODULATE_COLOR | SDL_TEXTUREMODULATE_ALPHA), ";
   436                             } else {
   437                                 print FILE "0, ";
   438                             }
   439                             if ( $blend ) {
   440                                 print FILE "(SDL_TEXTUREBLENDMODE_MASK | SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD | SDL_TEXTUREBLENDMODE_MOD), ";
   441                             } else {
   442                                 print FILE "0, ";
   443                             }
   444                             if ( $scale ) {
   445                                 print FILE "SDL_TEXTURESCALEMODE_FAST, ";
   446                             } else {
   447                                 print FILE "0, ";
   448                             }
   449                             output_copyfuncname("", $src_formats[$i], $dst_formats[$j], $modulate, $blend, $scale, 0, " },\n");
   450                         }
   451                     }
   452                 }
   453             }
   454         }
   455     }
   456     print FILE <<__EOF__;
   457 };
   458 
   459 SDL_RenderCopyFunc SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode)
   460 {
   461     int i;
   462 
   463     for (i = 0; i < SDL_arraysize(SDL_RenderCopyFuncTable); ++i) {
   464         if (src_format != SDL_RenderCopyFuncTable[i].src_format) {
   465             continue;
   466         }
   467         if (dst_format != SDL_RenderCopyFuncTable[i].dst_format) {
   468             continue;
   469         }
   470         if ((modMode & SDL_RenderCopyFuncTable[i].modMode) != modMode) {
   471             continue;
   472         }
   473         if ((blendMode & SDL_RenderCopyFuncTable[i].blendMode) != blendMode) {
   474             continue;
   475         }
   476         if ((scaleMode & SDL_RenderCopyFuncTable[i].scaleMode) != scaleMode) {
   477             continue;
   478         }
   479         return SDL_RenderCopyFuncTable[i].func;
   480     }
   481     return NULL;
   482 }
   483 
   484 __EOF__
   485 }
   486 
   487 sub output_copyfunc_c
   488 {
   489     my $src = shift;
   490     my $dst = shift;
   491 
   492     for (my $modulate = 0; $modulate <= 1; ++$modulate) {
   493         for (my $blend = 0; $blend <= 1; ++$blend) {
   494             for (my $scale = 0; $scale <= 1; ++$scale) {
   495                 if ( $modulate != 0 || $blend != 0 || $scale != 0 || $src ne $dst ) {
   496                     output_copyfunc($src, $dst, $modulate, $blend, $scale);
   497                 }
   498             }
   499         }
   500     }
   501 }
   502 
   503 open_file("SDL_rendercopy.h");
   504 output_copydefs();
   505 for (my $i = 0; $i <= $#src_formats; ++$i) {
   506     for (my $j = 0; $j <= $#dst_formats; ++$j) {
   507         output_copyfunc_h($src_formats[$i], $dst_formats[$j]);
   508     }
   509 }
   510 print FILE "\n";
   511 close_file("SDL_rendercopy.h");
   512 
   513 open_file("SDL_rendercopy.c");
   514 output_copyinc();
   515 output_copyfunctable();
   516 for (my $i = 0; $i <= $#src_formats; ++$i) {
   517     for (my $j = 0; $j <= $#dst_formats; ++$j) {
   518         output_copyfunc_c($src_formats[$i], $dst_formats[$j]);
   519     }
   520 }
   521 close_file("SDL_rendercopy.c");