From f549cf9661e13614b1bcb3b6f44256bcebcf465e Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 3 Jul 2011 21:52:33 +0000 Subject: [PATCH] Removed some 'throw(...)' declarations, which are deprecated in the latest version of the C++ standard. Fixed bug when using snprintf; we must use BSPF_snprintf, since the function has different names in different OS's. Optimized loading of PNG images in the RomInfoWidget so that memory allocations aren't continuously being done. Basically, memory is allocated once and then only re-allocated if a new image is larger than all previous ones. This can increase memory use slightly, as the image data stays around between image loads, and it remembers the largest image loaded. But if you images are all mostly the same size, it should hurt memory usage too much. And it really helps on certain systems where repeated (re)-allocations can cause problems. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2261 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- src/common/PNGLibrary.cxx | 110 ++++++++++++++++++++++++------------ src/common/PNGLibrary.hxx | 50 ++++++++++------ src/debugger/Debugger.cxx | 16 +++--- src/emucore/Thumbulator.cxx | 4 +- src/emucore/Thumbulator.hxx | 14 +++-- src/gui/RomInfoWidget.cxx | 3 +- src/gui/RomInfoWidget.hxx | 4 ++ 7 files changed, 129 insertions(+), 72 deletions(-) diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index 3c7608101..191d5bb76 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -25,32 +25,32 @@ #include "PNGLibrary.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PNGLibrary::PNGLibrary(const string& filename) - : myFilename(filename) +PNGLibrary::PNGLibrary() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::~PNGLibrary() { + delete[] ReadInfo.buffer; + delete[] ReadInfo.line; + delete[] ReadInfo.row_pointers; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PNGLibrary::readImage(const FrameBuffer& fb, FBSurface& surface) - throw(const char*) +bool PNGLibrary::readImage(const string& filename, + const FrameBuffer& fb, FBSurface& surface) { #define readImageERROR(s) { err_message = s; goto done; } png_structp png_ptr = NULL; png_infop info_ptr = NULL; - png_bytep* row_pointers = NULL; - png_uint_32 iwidth, iheight, ipitch; - uInt8* buffer = NULL; + png_uint_32 iwidth, iheight; int bit_depth, color_type, interlace_type; const char* err_message = NULL; - ifstream* in = new ifstream(myFilename.c_str(), ios_base::binary); - if(!in || !in->is_open()) + ifstream in(filename.c_str(), ios_base::binary); + if(!in.is_open()) readImageERROR("No image found"); // Create the PNG loading context structure @@ -65,7 +65,7 @@ bool PNGLibrary::readImage(const FrameBuffer& fb, FBSurface& surface) readImageERROR("Couldn't create image information for PNG file"); // Set up the input control - png_set_read_fn(png_ptr, in, png_read_data); + png_set_read_fn(png_ptr, &in, png_read_data); // Read PNG header info png_read_info(png_ptr, info_ptr); @@ -97,34 +97,27 @@ bool PNGLibrary::readImage(const FrameBuffer& fb, FBSurface& surface) readImageERROR("Unknown format in PNG image"); } - // Create space for the entire image (3 bytes per pixel in RGB format) - ipitch = iwidth * 3; - buffer = new uInt8[ipitch * iheight]; - if(buffer == NULL) + // Create/initialize storage area for the current image + if(!allocateStorage(iwidth, iheight)) readImageERROR("Not enough memory to read PNG file"); // The PNG read function expects an array of rows, not a single 1-D array - row_pointers = new png_bytep[iheight]; - for(uInt32 irow = 0, offset = 0; irow < iheight; ++irow, offset += ipitch) - row_pointers[irow] = (png_bytep) (uInt8*)buffer + offset; + for(uInt32 irow = 0, offset = 0; irow < ReadInfo.height; ++irow, offset += ReadInfo.pitch) + ReadInfo.row_pointers[irow] = (png_bytep) (uInt8*)ReadInfo.buffer + offset; // Read the entire image in one go - png_read_image(png_ptr, row_pointers); - delete[] row_pointers; + png_read_image(png_ptr, ReadInfo.row_pointers); // We're finished reading png_read_end(png_ptr, info_ptr); // Scale image to surface dimensions - scaleImagetoSurface(iwidth, iheight, buffer, fb, surface); + scaleImagetoSurface(fb, surface); // Cleanup done: if(png_ptr) png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0, (png_infopp)0); - if(in) - in->close(); - delete[] buffer; if(err_message) throw err_message; @@ -133,8 +126,49 @@ done: } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PNGLibrary::scaleImagetoSurface(uInt32 iwidth, uInt32 iheight, uInt8* buffer, - const FrameBuffer& fb, FBSurface& surface) +bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h) +{ + // Create space for the entire image (3 bytes per pixel in RGB format) + uInt32 req_buffer_size = w * h * 3; + if(req_buffer_size > ReadInfo.buffer_size) + { + delete[] ReadInfo.buffer; + ReadInfo.buffer = new uInt8[req_buffer_size]; + if(ReadInfo.buffer == NULL) + return false; + + ReadInfo.buffer_size = req_buffer_size; + } + uInt32 req_line_size = w * 3; + if(req_line_size > ReadInfo.line_size) + { + delete[] ReadInfo.line; + ReadInfo.line = new uInt32[req_line_size]; + if(ReadInfo.line == NULL) + return false; + + ReadInfo.line_size = req_line_size; + } + uInt32 req_row_size = h; + if(req_row_size > ReadInfo.row_size) + { + delete[] ReadInfo.row_pointers; + ReadInfo.row_pointers = new png_bytep[req_row_size]; + if(ReadInfo.row_pointers == NULL) + return false; + + ReadInfo.row_size = req_row_size; + } + + ReadInfo.width = w; + ReadInfo.height = h; + ReadInfo.pitch = w * 3; + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface) { // Figure out the original zoom level of the snapshot // All snapshots generated by Stella are at most some multiple of 320 @@ -144,34 +178,32 @@ void PNGLibrary::scaleImagetoSurface(uInt32 iwidth, uInt32 iheight, uInt8* buffe // The following calculation will work up to approx. 16x zoom level, // but since Stella only generates snapshots at up to 10x, we should // be fine for a while ... - uInt32 izoom = uInt32(ceil(iwidth/320.0)), + uInt32 izoom = uInt32(ceil(ReadInfo.width/320.0)), szoom = surface.getWidth()/320; - uInt32 sw = iwidth / izoom * szoom, - sh = iheight / izoom * szoom; + uInt32 sw = ReadInfo.width / izoom * szoom, + sh = ReadInfo.height / izoom * szoom; sw = BSPF_min(sw, surface.getWidth()); sh = BSPF_min(sh, surface.getHeight()); surface.setWidth(sw); surface.setHeight(sh); // Decompress the image, and scale it correctly - uInt32 ipitch = iwidth * 3; // bytes per line of the actual PNG image - uInt32* line = new uInt32[ipitch]; - - uInt32 buf_offset = ipitch * izoom; + uInt32 buf_offset = ReadInfo.pitch * izoom; uInt32 i_offset = 3 * izoom; // We can only scan at most the height of the image to the constraints of // the surface height (some multiple of 256) - iheight = BSPF_min(iheight, izoom * 256); + uInt32 iheight = BSPF_min((uInt32)ReadInfo.height, izoom * 256); // Grab each non-duplicate row of data from the image + uInt8* buffer = ReadInfo.buffer; for(uInt32 irow = 0, srow = 0; irow < iheight; irow += izoom, buffer += buf_offset) { // Scale the image data into the temporary line buffer uInt8* i_ptr = buffer; - uInt32* l_ptr = line; - for(uInt32 icol = 0; icol < iwidth; icol += izoom, i_ptr += i_offset) + uInt32* l_ptr = ReadInfo.line; + for(uInt32 icol = 0; icol < ReadInfo.width; icol += izoom, i_ptr += i_offset) { uInt32 pixel = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2)); uInt32 xstride = szoom; @@ -182,9 +214,8 @@ void PNGLibrary::scaleImagetoSurface(uInt32 iwidth, uInt32 iheight, uInt8* buffe // Then fill the surface with those bytes uInt32 ystride = szoom; while(ystride--) - surface.drawPixels(line, 0, srow++, sw); + surface.drawPixels(ReadInfo.line, 0, srow++, sw); } - delete[] line; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -219,3 +250,8 @@ void PNGLibrary::png_user_error(png_structp ctx, png_const_charp str) { cout << "PNGLibrary error: " << str << endl; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PNGLibrary::ReadInfoType PNGLibrary::ReadInfo = { + NULL, NULL, 0, 0, 0, NULL, 0, 0, 0 +}; diff --git a/src/common/PNGLibrary.hxx b/src/common/PNGLibrary.hxx index 6cfbe5af6..a6c4ec271 100644 --- a/src/common/PNGLibrary.hxx +++ b/src/common/PNGLibrary.hxx @@ -37,44 +37,60 @@ class FBSurface; class PNGLibrary { public: - /** Access a PNG image with the given filename. */ - PNGLibrary(const string& filename); + PNGLibrary(); ~PNGLibrary(); /** - Read a PNG image from the previously specified file into a - FBSurface structure, scaling the image to the surface bounds. + Read a PNG image from the specified file into a FBSurface structure, + scaling the image to the surface bounds. - @param fb The main framebuffer of the application - @param surface The FBSurface into which to place the PNG data + @param filename The filename to load from + @param fb The main framebuffer of the application + @param surface The FBSurface into which to place the PNG data @return On success, the FBSurface containing image data and a - result of true, otherwise an exception is thrown. + result of true, otherwise a const char* exception is thrown + containing a more detailed error message. */ - bool readImage(const FrameBuffer& fb, FBSurface& surface) throw(const char*); + bool readImage(const string& filename, const FrameBuffer& fb, FBSurface& surface); private: + // The following data remains between invocations of allocateStorage, + // and is only changed when absolutely necessary. + typedef struct { + uInt8* buffer; + png_bytep* row_pointers; + png_uint_32 width, height, pitch; + uInt32* line; + uInt32 buffer_size, line_size, row_size; + } ReadInfoType; + static ReadInfoType ReadInfo; + /** - Scale the PNG data from 'buffer' into the FBSurface. For now, scaling + Allocate memory for PNG read operations. This is used to provide a + basic memory manager, so that we don't constantly allocate and deallocate + memory for each image loaded. + + The method fills the 'ReadInfo' struct with valid memory locations + dependent on the given dimensions. If memory has been previously + allocated and it can accommodate the given dimensions, it is used directly. + */ + bool allocateStorage(png_uint_32 iwidth, png_uint_32 iheight); + + /** + Scale the PNG data from 'ReadInfo' into the FBSurface. For now, scaling is done on integer boundaries only (ie, 1x, 2x, etc up or down). - @param iwidth Width of the PNG data (3 bytes per pixel) - @param iheight Number of row of PNG data - @param buffer The PNG data @param fb The main framebuffer of the application @param surface The FBSurface into which to place the PNG data */ - static void scaleImagetoSurface(uInt32 iwidth, uInt32 iheight, uInt8* buffer, - const FrameBuffer& fb, FBSurface& surface); + void scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface); static void png_read_data(png_structp ctx, png_bytep area, png_size_t size); static void png_write_data(png_structp ctx, png_bytep area, png_size_t size); static void png_io_flush(png_structp ctx); static void png_user_warn(png_structp ctx, png_const_charp str); static void png_user_error(png_structp ctx, png_const_charp str); - - private: - string myFilename; }; #endif diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index a74645920..d92fbb0e1 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -320,29 +320,29 @@ string Debugger::valueToString(int value, BaseFormat outputBase) const case kBASE_10: // base 10: 3 or 5 bytes (depending on value) if(value < 0x100) - snprintf(vToS_buf, 4, "%3d", value); + BSPF_snprintf(vToS_buf, 4, "%3d", value); else - snprintf(vToS_buf, 6, "%5d", value); + BSPF_snprintf(vToS_buf, 6, "%5d", value); break; case kBASE_16_1: // base 16: 1 byte wide - snprintf(vToS_buf, 2, "%1X", value); + BSPF_snprintf(vToS_buf, 2, "%1X", value); break; case kBASE_16_2: // base 16: 2 bytes wide - snprintf(vToS_buf, 3, "%02X", value); + BSPF_snprintf(vToS_buf, 3, "%02X", value); break; case kBASE_16_4: // base 16: 4 bytes wide - snprintf(vToS_buf, 5, "%04X", value); + BSPF_snprintf(vToS_buf, 5, "%04X", value); break; case kBASE_16: // base 16: 2, 4, 8 bytes (depending on value) default: if(value < 0x100) - snprintf(vToS_buf, 3, "%02X", value); + BSPF_snprintf(vToS_buf, 3, "%02X", value); else if(value < 0x10000) - snprintf(vToS_buf, 5, "%04X", value); + BSPF_snprintf(vToS_buf, 5, "%04X", value); else - snprintf(vToS_buf, 9, "%08X", value); + BSPF_snprintf(vToS_buf, 9, "%08X", value); break; } diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index 3d1490d53..0b688993c 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -46,7 +46,7 @@ Thumbulator::~Thumbulator() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Thumbulator::run( void ) throw(const string&) +string Thumbulator::run( void ) { reset(); for(;;) @@ -70,7 +70,6 @@ string Thumbulator::run( void ) throw(const string&) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg) - throw(const string&) { statusMsg << "Thumb ARM emulation fatal error: " << endl << opcode << "(" << HEX8 << v1 << "), " << msg << endl; @@ -81,7 +80,6 @@ inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* ms // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg) - throw(const string&) { statusMsg << "Thumb ARM emulation fatal error: " << endl << opcode << "(" << HEX8 << v1 << "," << v2 << "), " << msg << endl; diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index 6642223d3..592161b75 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -66,14 +66,14 @@ class Thumbulator ~Thumbulator(); /** - Run the ARM code, and return when finished. An exception is thrown - in case of any fatal errors/aborts, containing the actual error, + Run the ARM code, and return when finished. A string exception is + thrown in case of any fatal errors/aborts, containing the actual error, and the contents of the registers at that point in time. @return The results of any debugging output (if enabled), otherwise an empty string */ - string run() throw(const string&); + string run(); private: uInt32 read_register ( uInt32 reg ); @@ -93,8 +93,12 @@ class Thumbulator void do_cflag_bit ( uInt32 x ); void do_vflag_bit ( uInt32 x ); - int fatalError(const char* opcode, uInt32 v1, const char* msg) throw(const string&); - int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg) throw(const string&); + // Throw a string exception containing an error referencing the given + // message and variables + // Note that the return value is never used in these methods + int fatalError(const char* opcode, uInt32 v1, const char* msg); + int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg); + void dump_counters ( void ); void dump_regs( void ); int execute ( void ); diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index bfb5dd182..1918a8510 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -115,9 +115,8 @@ void RomInfoWidget::parseProperties() // Read the PNG file try { - PNGLibrary png(filename); mySurfaceIsValid = - png.readImage(instance().frameBuffer(), *mySurface); + myPNGLib.readImage(filename, instance().frameBuffer(), *mySurface); } catch(const char* msg) { diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index 376ff5220..500fcd2a9 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -26,6 +26,7 @@ #include "Widget.hxx" #include "Command.hxx" #include "StringList.hxx" +#include "PNGLibrary.hxx" #include "bspf.hxx" @@ -51,6 +52,9 @@ class RomInfoWidget : public Widget FBSurface* mySurface; int mySurfaceID; + // PNG object responsible for actually loading the PNG image + PNGLibrary myPNGLib; + // How much to zoom the PNG image int myZoomLevel;