Search
lxdream.org :: lxdream/src/util.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/util.c
changeset 1239:be3121267597
prev1148:8e75fab17be8
author nkeynes
date Fri Mar 02 23:49:10 2012 +1000 (8 years ago)
permissions -rw-r--r--
last change Android WIP:
* Rename gui_jni.c to gui_android.c - now quite android specific.
* Implement generic EGL driver with very minimal Java wrapper
* Run emulation in separate thread, and implement simple queue for
inter-thread communication.
* Add menu/action-bar items for start + reset
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Miscellaneous utility functions.
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #define HAVE_EXECINFO_H 1
    21 #include <assert.h>
    22 #include <ctype.h>
    23 #include <stdarg.h>
    24 #include <stdio.h>
    25 #include <stdlib.h>
    26 #include <unistd.h>
    27 #include <signal.h>
    28 #include <time.h>
    29 #include <zlib.h>
    30 #include <glib.h>
    31 #include <png.h>
    32 #include "dream.h"
    33 #include "display.h"
    34 #include "dreamcast.h"
    35 #include "gui.h"
    36 #include "sh4/sh4.h"
    38 #ifdef __ANDROID__
    39 #include <android/log.h>
    40 static int android_log_levels[] = {ANDROID_LOG_FATAL, ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE};
    41 #endif
    43 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
    44 int global_msg_level = EMIT_WARN;
    46 static void report_crash( int signo, siginfo_t *info, void *ptr )
    47 {
    48     char buf[128];
    50     fprintf( stderr, "--- Aborting with signal %d ---\n", signo );
    51     sh4_crashdump();
    52     // Get gdb to print a nice backtrace for us
    53 #ifdef APPLE_BUILD
    54     snprintf( buf, 128, "echo bt | gdb --quiet --pid=%d", getpid() );
    55 #else
    56     snprintf( buf, 128, "gdb -batch -f --quiet --pid=%d -ex bt", getpid() );
    57 #endif
    58     system(buf);
    60     abort();
    61 }
    63 void install_crash_handler(void)
    64 {
    65     struct sigaction sa;
    67     sa.sa_sigaction = report_crash;
    68     sigemptyset(&sa.sa_mask);
    69     sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
    70     sigaction( SIGSEGV, &sa, NULL );
    71     sigaction( SIGILL, &sa, NULL );
    72     sigaction( SIGBUS, &sa, NULL );
    73 }
    76 void fwrite_string( const char *s, FILE *f )
    77 {
    78     uint32_t len = 0;
    79     if( s == NULL ) {
    80         fwrite( &len, sizeof(len), 1, f );
    81     } else {
    82         len = strlen(s)+1;
    83         fwrite( &len, sizeof(len), 1, f );
    84         fwrite( s, len, 1, f );
    85     }
    86 }
    88 int fread_string( char *s, int maxlen, FILE *f ) 
    89 {
    90     uint32_t len;
    91     fread( &len, sizeof(len), 1, f );
    92     if( len != 0 ) {
    93         fread( s, len > maxlen ? maxlen : len, 1, f );
    94     }
    95     return len;
    96 }
    98 int fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )
    99 {
   100     uLongf size = sz*count;
   101     uLongf csize = ((int)(size*1.001))+13;
   102     unsigned char *tmp = g_malloc0( csize );
   103     int status = compress( tmp, &csize, p, size );
   104     assert( status == Z_OK );
   105     uint32_t wsize = (uint32_t)csize;
   106     fwrite( &wsize, sizeof(wsize), 1, f );
   107     int written = fwrite( tmp, csize, 1, f );
   108     g_free(tmp);
   110     /* Could be finer-grained, but this is enough to know it succeeded/failed */
   111     if( written == 1 ) {
   112         return count;
   113     } else {
   114         return 0;
   115     }
   116 }
   118 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
   119 {
   120     uLongf size = sz*count;
   121     uint32_t csize;
   122     unsigned char *tmp;
   124     fread( &csize, sizeof(csize), 1, f );
   125     assert( csize <= (size*2) );
   126     tmp = g_malloc0( csize );
   127     fread( tmp, csize, 1, f );
   128     int status = uncompress( p, &size, tmp, csize );
   129     g_free(tmp);
   130     if( status == Z_OK ) {
   131         return count;
   132     } else {
   133         fprintf( stderr, "Error reading compressed data\n" );
   134         return 0;
   135     }
   136 }
   138 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f ) 
   139 {
   140     unsigned int i, j;
   141     for( i =0; i<length; i+=16 ) {
   142         fprintf( f, "%08X:", i);
   143         for( j=i; j<i+16; j++ ) {
   144             if( (j % 4) == 0 )
   145                 fprintf( f, " " );
   146             if( j < length )
   147                 fprintf( f, " %02X", (unsigned int)(data[j]) );
   148             else
   149                 fprintf( f, "   " );
   150         }
   151         fprintf( f, "  " );
   152         for( j=i; j<i+16 && j<length; j++ ) {
   153             fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
   154         }
   155         fprintf( f, "\n" );
   156     }
   157 }
   159 void fwrite_dump32( unsigned int *data, unsigned int length, FILE *f ) 
   160 {
   161     fwrite_dump32v( data, length, 8, f );
   162 }
   164 void fwrite_dump32v( unsigned int *data, unsigned int length, int wordsPerLine, FILE *f ) 
   165 {
   166     unsigned int i, j;
   167     for( i =0; i<length>>2; i+=wordsPerLine ) {
   168         fprintf( f, "%08X:", i);
   169         for( j=i; j<i+wordsPerLine; j++ ) {
   170             if( j < length )
   171                 fprintf( f, " %08X", (unsigned int)(data[j]) );
   172             else
   173                 fprintf( f, "         " );
   174         }
   175         fprintf( f, "\n" );
   176     }
   177 }
   179 gboolean write_png_to_stream( FILE *f, frame_buffer_t buffer )
   180 {
   181     int coltype, i;
   182     png_bytep p;
   183     png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   184     if (!png_ptr) {
   185         return FALSE;
   186     }
   188     png_infop info_ptr = png_create_info_struct(png_ptr);
   189     if (!info_ptr) {
   190         png_destroy_write_struct(&png_ptr, NULL);
   191         return FALSE;
   192     }
   194     if( setjmp(png_jmpbuf(png_ptr)) ) {
   195         png_destroy_write_struct(&png_ptr, &info_ptr);
   196         return FALSE;
   197     }
   198     png_init_io( png_ptr, f );
   199     switch( buffer->colour_format ) {
   200     case COLFMT_BGR888:
   201         coltype = PNG_COLOR_TYPE_RGB;
   202         break;
   203     case COLFMT_BGRA8888:
   204         coltype = PNG_COLOR_TYPE_RGB_ALPHA;
   205         break;
   206     case COLFMT_BGR0888:
   207         coltype = PNG_COLOR_TYPE_RGB;
   208         break;
   209     default:
   210         coltype = PNG_COLOR_TYPE_RGB;
   211     }
   212     png_set_IHDR(png_ptr, info_ptr, buffer->width, buffer->height,
   213                  8, coltype, PNG_INTERLACE_NONE, 
   214                  PNG_COMPRESSION_TYPE_DEFAULT, 
   215                  PNG_FILTER_TYPE_DEFAULT );
   216     png_write_info(png_ptr, info_ptr);
   217     if( buffer->colour_format == COLFMT_BGR0888 ) {
   218         png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
   219     }
   220     png_set_bgr(png_ptr);
   221     if( buffer->inverted ) {
   222         p = (png_bytep)(buffer->data + (buffer->height*buffer->rowstride) - buffer->rowstride);
   223         for(i=0; i<buffer->height; i++ ) {
   224             png_write_row(png_ptr, p);
   225             p-=buffer->rowstride;
   226         }
   227     } else {
   228         p = (png_bytep)buffer->data;
   229         for(i=0; i<buffer->height; i++ ) {
   230             png_write_row(png_ptr, p);
   231             p+=buffer->rowstride;
   232         }
   233     }
   234     png_write_end(png_ptr, info_ptr);
   235     png_destroy_write_struct(&png_ptr, &info_ptr);
   236     return TRUE;
   237 }
   239 frame_buffer_t read_png_from_stream( FILE *f )
   240 {
   241     png_bytep p;
   242     int i;
   243     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 
   244             NULL, NULL, NULL);
   245     if (!png_ptr) {
   246         return NULL;
   247     }
   249     png_infop info_ptr = png_create_info_struct(png_ptr);
   250     if (!info_ptr) {
   251         png_destroy_read_struct(&png_ptr, NULL, NULL);
   252         return NULL;
   253     }
   255     png_infop end_info = png_create_info_struct(png_ptr);
   256     if (!end_info) {
   257         png_destroy_read_struct(&png_ptr, &info_ptr, NULL );
   258         return NULL;
   259     }
   261     if( setjmp(png_jmpbuf(png_ptr)) ) {
   262         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
   263         return NULL;
   264     }
   266     png_init_io(png_ptr, f);
   267     png_read_info(png_ptr, info_ptr);
   269     png_uint_32 width, height;
   270     int bit_depth, color_type, interlace_type,
   271     compression_type, filter_method;
   272     png_get_IHDR(png_ptr, info_ptr, &width, &height,
   273                  &bit_depth, &color_type, &interlace_type,
   274                  &compression_type, &filter_method);
   275     assert( interlace_type == PNG_INTERLACE_NONE );
   276     int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
   277     int channels = png_get_channels(png_ptr, info_ptr);
   278     frame_buffer_t buffer = g_malloc( sizeof(struct frame_buffer) + rowbytes*height );
   279     buffer->data = (unsigned char *)(buffer+1);
   280     buffer->width = width;
   281     buffer->height = height;
   282     buffer->rowstride = rowbytes;
   283     buffer->address = -1;
   284     buffer->size = rowbytes*height;
   285     buffer->inverted = FALSE;
   286     if( channels == 4 ) {
   287         buffer->colour_format = COLFMT_BGRA8888;
   288     } else if( channels == 3 ) {
   289         buffer->colour_format = COLFMT_RGB888;
   290     }
   292     p = (png_bytep)buffer->data;
   293     for( i=0; i<height; i++ ) {
   294         png_read_row(png_ptr, p, NULL );
   295         p += rowbytes;
   296     }
   298     png_read_end(png_ptr, end_info);
   299     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
   300     return buffer;
   301 }
   303 int get_log_level_from_string( const gchar *str )
   304 {
   305     switch( tolower(str[0]) ) {
   306     case 'd': return EMIT_DEBUG;
   307     case 'e': return EMIT_ERR;
   308     case 'f': return EMIT_FATAL;
   309     case 'i': return EMIT_INFO;
   310     case 't': return EMIT_TRACE;
   311     case 'w': return EMIT_WARN;
   312     default: return -1;
   313     }
   314 }
   316 gboolean set_global_log_level( const gchar *str ) 
   317 {
   318     int l = get_log_level_from_string(str);
   319     if( l == -1 ) {
   320         return FALSE;
   321     } else {
   322         global_msg_level = l;
   323         return TRUE;
   324     }
   325 }
   327 void log_message( void *ptr, int level, const gchar *source, const char *msg, ... )
   328 {
   329     char buf[20];
   330     time_t tm = time(NULL);
   331     va_list ap;
   333     if( level > global_msg_level ) {
   334         return; // ignored
   335     }
   337     va_start(ap, msg);
   338     gchar *text = g_strdup_vprintf( msg, ap );
   339     va_end(ap);
   341     if( level <= EMIT_ERR ) {
   342         if( gui_error_dialog( text ) ) {
   343             g_free(text);
   344             // If we're running, halt on error to avoid potentially flooding
   345             // the user with error messages.
   346             if( dreamcast_is_running() ) {
   347                 dreamcast_stop();
   348             }
   349             return;
   350         }
   351     }
   353     strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
   354 #ifdef __ANDROID__
   355     __android_log_print(android_log_levels[level], "lxdream", "%s %08X %s\n", buf, sh4r.pc, text );
   356 #else
   357     fprintf( stderr, "%s %08X %-5s %s\n", buf, sh4r.pc, msg_levels[level], text );
   358 #endif
   359     g_free(text);
   360 }
.