filename | src/util.c |
changeset | 1148:8e75fab17be8 |
prev | 1092:7c4ffe27e7b5 |
next | 1239:be3121267597 |
author | nkeynes |
date | Wed Nov 10 08:37:42 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Add chain pointer to the xlat cache, so that we can maintain multiple blocks for the same address. This prevents thrashing in cases where we would other keep retranslating the same blocks over and over again due to varying xlat_sh4_mode values |
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 <signal.h>
27 #include <time.h>
28 #include <zlib.h>
29 #include <glib.h>
30 #include <png.h>
31 #include "dream.h"
32 #include "display.h"
33 #include "dreamcast.h"
34 #include "gui.h"
35 #include "sh4/sh4.h"
37 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
38 int global_msg_level = EMIT_WARN;
40 static void report_crash( int signo, siginfo_t *info, void *ptr )
41 {
42 char buf[128];
44 fprintf( stderr, "--- Aborting with signal %d ---\n", signo );
45 sh4_crashdump();
46 // Get gdb to print a nice backtrace for us
47 #ifdef APPLE_BUILD
48 snprintf( buf, 128, "echo bt | gdb --quiet --pid=%d", getpid() );
49 #else
50 snprintf( buf, 128, "gdb -batch -f --quiet --pid=%d -ex bt", getpid() );
51 #endif
52 system(buf);
54 abort();
55 }
57 void install_crash_handler(void)
58 {
59 struct sigaction sa;
61 sa.sa_sigaction = report_crash;
62 sigemptyset(&sa.sa_mask);
63 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
64 sigaction( SIGSEGV, &sa, NULL );
65 sigaction( SIGILL, &sa, NULL );
66 sigaction( SIGBUS, &sa, NULL );
67 }
70 void fwrite_string( const char *s, FILE *f )
71 {
72 uint32_t len = 0;
73 if( s == NULL ) {
74 fwrite( &len, sizeof(len), 1, f );
75 } else {
76 len = strlen(s)+1;
77 fwrite( &len, sizeof(len), 1, f );
78 fwrite( s, len, 1, f );
79 }
80 }
82 int fread_string( char *s, int maxlen, FILE *f )
83 {
84 uint32_t len;
85 fread( &len, sizeof(len), 1, f );
86 if( len != 0 ) {
87 fread( s, len > maxlen ? maxlen : len, 1, f );
88 }
89 return len;
90 }
92 int fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )
93 {
94 uLongf size = sz*count;
95 uLongf csize = ((int)(size*1.001))+13;
96 unsigned char *tmp = g_malloc0( csize );
97 int status = compress( tmp, &csize, p, size );
98 assert( status == Z_OK );
99 uint32_t wsize = (uint32_t)csize;
100 fwrite( &wsize, sizeof(wsize), 1, f );
101 int written = fwrite( tmp, csize, 1, f );
102 g_free(tmp);
104 /* Could be finer-grained, but this is enough to know it succeeded/failed */
105 if( written == 1 ) {
106 return count;
107 } else {
108 return 0;
109 }
110 }
112 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
113 {
114 uLongf size = sz*count;
115 uint32_t csize;
116 unsigned char *tmp;
118 fread( &csize, sizeof(csize), 1, f );
119 assert( csize <= (size*2) );
120 tmp = g_malloc0( csize );
121 fread( tmp, csize, 1, f );
122 int status = uncompress( p, &size, tmp, csize );
123 g_free(tmp);
124 if( status == Z_OK ) {
125 return count;
126 } else {
127 fprintf( stderr, "Error reading compressed data\n" );
128 return 0;
129 }
130 }
132 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
133 {
134 unsigned int i, j;
135 for( i =0; i<length; i+=16 ) {
136 fprintf( f, "%08X:", i);
137 for( j=i; j<i+16; j++ ) {
138 if( (j % 4) == 0 )
139 fprintf( f, " " );
140 if( j < length )
141 fprintf( f, " %02X", (unsigned int)(data[j]) );
142 else
143 fprintf( f, " " );
144 }
145 fprintf( f, " " );
146 for( j=i; j<i+16 && j<length; j++ ) {
147 fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
148 }
149 fprintf( f, "\n" );
150 }
151 }
153 void fwrite_dump32( unsigned int *data, unsigned int length, FILE *f )
154 {
155 fwrite_dump32v( data, length, 8, f );
156 }
158 void fwrite_dump32v( unsigned int *data, unsigned int length, int wordsPerLine, FILE *f )
159 {
160 unsigned int i, j;
161 for( i =0; i<length>>2; i+=wordsPerLine ) {
162 fprintf( f, "%08X:", i);
163 for( j=i; j<i+wordsPerLine; j++ ) {
164 if( j < length )
165 fprintf( f, " %08X", (unsigned int)(data[j]) );
166 else
167 fprintf( f, " " );
168 }
169 fprintf( f, "\n" );
170 }
171 }
173 gboolean write_png_to_stream( FILE *f, frame_buffer_t buffer )
174 {
175 int coltype, i;
176 png_bytep p;
177 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
178 if (!png_ptr) {
179 return FALSE;
180 }
182 png_infop info_ptr = png_create_info_struct(png_ptr);
183 if (!info_ptr) {
184 png_destroy_write_struct(&png_ptr, NULL);
185 return FALSE;
186 }
188 if( setjmp(png_jmpbuf(png_ptr)) ) {
189 png_destroy_write_struct(&png_ptr, &info_ptr);
190 return FALSE;
191 }
192 png_init_io( png_ptr, f );
193 switch( buffer->colour_format ) {
194 case COLFMT_BGR888:
195 coltype = PNG_COLOR_TYPE_RGB;
196 break;
197 case COLFMT_BGRA8888:
198 coltype = PNG_COLOR_TYPE_RGB_ALPHA;
199 break;
200 case COLFMT_BGR0888:
201 coltype = PNG_COLOR_TYPE_RGB;
202 break;
203 default:
204 coltype = PNG_COLOR_TYPE_RGB;
205 }
206 png_set_IHDR(png_ptr, info_ptr, buffer->width, buffer->height,
207 8, coltype, PNG_INTERLACE_NONE,
208 PNG_COMPRESSION_TYPE_DEFAULT,
209 PNG_FILTER_TYPE_DEFAULT );
210 png_write_info(png_ptr, info_ptr);
211 if( buffer->colour_format == COLFMT_BGR0888 ) {
212 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
213 }
214 png_set_bgr(png_ptr);
215 if( buffer->inverted ) {
216 p = (png_bytep)(buffer->data + (buffer->height*buffer->rowstride) - buffer->rowstride);
217 for(i=0; i<buffer->height; i++ ) {
218 png_write_row(png_ptr, p);
219 p-=buffer->rowstride;
220 }
221 } else {
222 p = (png_bytep)buffer->data;
223 for(i=0; i<buffer->height; i++ ) {
224 png_write_row(png_ptr, p);
225 p+=buffer->rowstride;
226 }
227 }
228 png_write_end(png_ptr, info_ptr);
229 png_destroy_write_struct(&png_ptr, &info_ptr);
230 return TRUE;
231 }
233 frame_buffer_t read_png_from_stream( FILE *f )
234 {
235 png_bytep p;
236 int i;
237 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
238 NULL, NULL, NULL);
239 if (!png_ptr) {
240 return NULL;
241 }
243 png_infop info_ptr = png_create_info_struct(png_ptr);
244 if (!info_ptr) {
245 png_destroy_read_struct(&png_ptr, NULL, NULL);
246 return NULL;
247 }
249 png_infop end_info = png_create_info_struct(png_ptr);
250 if (!end_info) {
251 png_destroy_read_struct(&png_ptr, &info_ptr, NULL );
252 return NULL;
253 }
255 if( setjmp(png_jmpbuf(png_ptr)) ) {
256 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
257 return NULL;
258 }
260 png_init_io(png_ptr, f);
261 png_read_info(png_ptr, info_ptr);
263 png_uint_32 width, height;
264 int bit_depth, color_type, interlace_type,
265 compression_type, filter_method;
266 png_get_IHDR(png_ptr, info_ptr, &width, &height,
267 &bit_depth, &color_type, &interlace_type,
268 &compression_type, &filter_method);
269 assert( interlace_type == PNG_INTERLACE_NONE );
270 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
271 int channels = png_get_channels(png_ptr, info_ptr);
272 frame_buffer_t buffer = g_malloc( sizeof(struct frame_buffer) + rowbytes*height );
273 buffer->data = (unsigned char *)(buffer+1);
274 buffer->width = width;
275 buffer->height = height;
276 buffer->rowstride = rowbytes;
277 buffer->address = -1;
278 buffer->size = rowbytes*height;
279 buffer->inverted = FALSE;
280 if( channels == 4 ) {
281 buffer->colour_format = COLFMT_BGRA8888;
282 } else if( channels == 3 ) {
283 buffer->colour_format = COLFMT_RGB888;
284 }
286 p = (png_bytep)buffer->data;
287 for( i=0; i<height; i++ ) {
288 png_read_row(png_ptr, p, NULL );
289 p += rowbytes;
290 }
292 png_read_end(png_ptr, end_info);
293 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
294 return buffer;
295 }
297 int get_log_level_from_string( const gchar *str )
298 {
299 switch( tolower(str[0]) ) {
300 case 'd': return EMIT_DEBUG;
301 case 'e': return EMIT_ERR;
302 case 'f': return EMIT_FATAL;
303 case 'i': return EMIT_INFO;
304 case 't': return EMIT_TRACE;
305 case 'w': return EMIT_WARN;
306 default: return -1;
307 }
308 }
310 gboolean set_global_log_level( const gchar *str )
311 {
312 int l = get_log_level_from_string(str);
313 if( l == -1 ) {
314 return FALSE;
315 } else {
316 global_msg_level = l;
317 return TRUE;
318 }
319 }
321 void log_message( void *ptr, int level, const gchar *source, const char *msg, ... )
322 {
323 char buf[20];
324 time_t tm = time(NULL);
325 va_list ap;
327 if( level > global_msg_level ) {
328 return; // ignored
329 }
331 va_start(ap, msg);
332 gchar *text = g_strdup_vprintf( msg, ap );
333 va_end(ap);
335 if( level <= EMIT_ERR ) {
336 if( gui_error_dialog( text ) ) {
337 g_free(text);
338 // If we're running, halt on error to avoid potentially flooding
339 // the user with error messages.
340 if( dreamcast_is_running() ) {
341 dreamcast_stop();
342 }
343 return;
344 }
345 }
348 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
349 fprintf( stderr, "%s %08X %-5s %s\n", buf, sh4r.pc, msg_levels[level], text );
350 g_free(text);
351 }
.