Permalink
Browse files

Add support for REGAL_FRAME_LIMIT to limit the number of frames drawn.

Add support for REGAL_FRAME_TIME to log the elapsed time, per frame to the info log.
Initial implementation of RGBA color buffer saving to .png file, per frame.
REGAL_NO_PNG=1 for Android build, for now.
Disabled in Makefile build, for now.
  • Loading branch information...
1 parent feb2b2b commit 75ed0196284b9a5294d3ba7c8096175ffb5ef0f4 @nigels-com nigels-com committed Oct 2, 2012
View
4 Makefile
@@ -89,6 +89,8 @@ ifeq ($(filter -DREGAL_NO_MD5%,$(CFLAGS)),)
LIB.SRCS += src/md5/src/md5.c
endif
+CFLAGS += -DREGAL_NO_PNG
+
LIB.INCLUDE += -Isrc/mongoose
LIB.INCLUDE += -Isrc/md5/include
@@ -432,7 +434,7 @@ tmp/$(SYSTEM)/glut/shared/%.o: src/glut/src/%.c
$(CCACHE) $(CC) $(CFLAGS) $(PICFLAG) $(GLUT.CFLAGS) $(CFLAGS.SO) -o $@ -c $<
lib/$(GLUT.SHARED): $(GLUT.OBJS) lib/$(GLU.SHARED) lib/$(LIB.SHARED)
- $(CCACHE) $(LD) $(LDFLAGS.EXTRA) $(LDFLAGS.DYNAMIC) -o $@ $^ $(GLUT.LIBS)
+ $(CCACHE) $(LD) $(LDFLAGS.EXTRA) $(LDFLAGS.DYNAMIC) -o $@ $(GLUT.OBJS) $(GLUT.LIBS)
ifneq ($(STRIP),)
$(STRIP) -x $@
endif
View
2 build/android/Regal/Android.mk
@@ -13,7 +13,7 @@ ifndef REGAL_FORCE_REBUILD
endif
endif
-regal_cflags := -DANDROID=1 -Werror
+regal_cflags := -DANDROID=1 -DREGAL_NO_PNG=1 -Werror
regal_path := $(LOCAL_PATH)/../../..
View
7 scripts/regal/RegalContext.py
@@ -65,6 +65,7 @@
REGAL_GLOBAL_BEGIN
+#include "RegalTimer.h"
#include "RegalPrivate.h"
#include "RegalDispatcher.h"
#include "RegalDispatchError.h"
@@ -110,6 +111,10 @@
// Per-frame state and configuration
size_t frame;
+ Timer frameTimer;
+
+ size_t frameSamples;
+ Timer frameSimpleTimeout;
// State tracked via EmuContextState.py / Regal.cpp
@@ -159,6 +164,7 @@
thread(0),
logCallback(NULL),
frame(0),
+ frameSamples(0),
depthBeginEnd(0),
depthPushAttrib(0)
{
@@ -167,6 +173,7 @@
dbg = new DebugInfo();
dbg->Init(this);
}
+ frameTimer.restart();
}
void
View
9 src/regal/RegalConfig.cpp
@@ -63,10 +63,12 @@ bool enableEmuIff = REGAL_EMU_IFF;
bool enableEmuVao = REGAL_EMU_VAO;
bool enableEmuFilter = REGAL_EMU_FILTER;
+int frameLimit = 0; // Unlimited
+
bool frameMd5Color = false;
bool frameMd5Stencil = false;
bool frameMd5Depth = false;
-
+
bool frameSaveColor = false;
bool frameSaveStencil = false;
bool frameSaveDepth = false;
@@ -156,6 +158,9 @@ void Init()
tmp = GetEnv( "REGAL_EMU_FILTER" );
if (tmp) enableEmuFilter = atoi(tmp)!=0;
+ tmp = GetEnv( "REGAL_FRAME_LIMIT" );
+ if (tmp) frameLimit = atoi(tmp);
+
tmp = GetEnv( "REGAL_MD5_COLOR" );
if (tmp) frameMd5Color = atoi(tmp)!=0;
@@ -199,6 +204,8 @@ void Init()
Info("REGAL_EMU_VAO ", enableEmuVao ? "enabled" : "disabled");
Info("REGAL_EMU_FILTER ", enableEmuFilter ? "enabled" : "disabled");
+ Info("REGAL_FRAME_LIMIT ", frameLimit );
+
Info("REGAL_MD5_COLOR ", frameMd5Color ? "enabled" : "disabled");
Info("REGAL_MD5_STENCIL ", frameMd5Stencil ? "enabled" : "disabled");
Info("REGAL_MD5_DEPTH ", frameMd5Depth ? "enabled" : "disabled");
View
8 src/regal/RegalConfig.h
@@ -64,13 +64,15 @@ namespace Config
extern bool enableEmuIff;
extern bool enableEmuVao;
extern bool enableEmuFilter;
-
+
// Initial context configuration
-
+
+ extern int frameLimit; // Maximum number of frames
+
extern bool frameMd5Color; // Log md5 hash of color buffer
extern bool frameMd5Stencil;
extern bool frameMd5Depth;
-
+
extern bool frameSaveColor; // Save color buffer to PNG file
extern bool frameSaveStencil;
extern bool frameSaveDepth;
View
2 src/regal/RegalContext.cpp
@@ -81,6 +81,7 @@ RegalContext::RegalContext()
thread(0),
logCallback(NULL),
frame(0),
+ frameSamples(0),
depthBeginEnd(0),
depthPushAttrib(0)
{
@@ -89,6 +90,7 @@ RegalContext::RegalContext()
dbg = new DebugInfo();
dbg->Init(this);
}
+ frameTimer.restart();
}
void
View
5 src/regal/RegalContext.h
@@ -39,6 +39,7 @@
REGAL_GLOBAL_BEGIN
+#include "RegalTimer.h"
#include "RegalPrivate.h"
#include "RegalDispatcher.h"
#include "RegalDispatchError.h"
@@ -102,6 +103,10 @@ struct RegalContext
// Per-frame state and configuration
size_t frame;
+ Timer frameTimer;
+
+ size_t frameSamples;
+ Timer frameSimpleTimeout;
// State tracked via EmuContextState.py / Regal.cpp
View
2 src/regal/RegalDispatcher.h
@@ -77,7 +77,7 @@ struct Dispatcher
{
table._enabled = true;
}
-
+
inline void
disable(DispatchTable &table)
{
View
2 src/regal/RegalHttp.cpp
@@ -269,7 +269,7 @@ namespace Http
// Currently there is a problem with shutting down mongoose
// on Windows - so just skip the cleanup for now.
-
+
#ifndef REGAL_SYS_WGL
mg_stop(ctx);
#endif
View
9 src/regal/RegalLog.cpp
@@ -85,9 +85,9 @@ namespace Logging {
bool enableInternal = false;
bool enableHttp = true;
- int maxLines = (REGAL_LOG_MAX_LINES);
-
- bool callback = (REGAL_LOG_CALLBACK);
+ int maxLines = (REGAL_LOG_MAX_LINES);
+ bool frameTime = false;
+ bool callback = (REGAL_LOG_CALLBACK);
bool log = (REGAL_LOG);
std::string logFilename = "stdout";
@@ -137,6 +137,9 @@ namespace Logging {
const char *ml = GetEnv("REGAL_LOG_MAX_LINES");
if (ml) maxLines = atoi(ml);
+ const char *tmp = GetEnv("REGAL_FRAME_TIME");
+ if (tmp) frameTime = atoi(tmp)!=0;
+
const char *cb = GetEnv("REGAL_LOG_CALLBACK");
if (cb) callback = atoi(cb)!=0;
View
2 src/regal/RegalLog.h
@@ -145,6 +145,8 @@ namespace Logging
extern int maxLines;
+ extern bool frameTime; // Per-frame elapsed time to info log
+
// Callback output
extern bool callback;
View
94 src/regal/RegalMarker.cpp
@@ -36,6 +36,15 @@ REGAL_GLOBAL_BEGIN
#include "md5.h"
+#ifndef REGAL_NO_PNG
+#include <zlib.h>
+#include <png.h>
+#include <string>
+#include <boost/print/print_string.hpp>
+using namespace ::std;
+using ::boost::print::print_string;
+#endif
+
#include "RegalMarker.h"
#include "RegalPrivate.h"
#include "RegalDispatcher.h"
@@ -48,6 +57,12 @@ void Marker::FrameTerminator(RegalContext &context)
{
Internal("Regal::Marker::FrameTerminator ",&context);
+ if (Logging::frameTime)
+ {
+ Timer::Value elapsed = context.frameTimer.restart();
+ Info("Frame ",context.frame,' ',elapsed/1000," msec, ",1000000.0/elapsed," FPS.");
+ }
+
if
(
Config::frameMd5Color ||
@@ -84,27 +99,72 @@ void Marker::FrameTerminator(RegalContext &context)
// Do once we have the pixels, could we do the rest in another
// thread?
- // Compute pixel md5sum
-
- MD5Context md5c;
- MD5Init(&md5c);
- MD5Update(&md5c, buffer, bufferSize);
-
- unsigned char digest[16];
- MD5Final(digest, &md5c);
-
+ if (Config::frameMd5Color)
+ {
+ // Compute pixel md5sum
+
+ MD5Context md5c;
+ MD5Init(&md5c);
+ MD5Update(&md5c, buffer, bufferSize);
+
+ unsigned char digest[16];
+ MD5Final(digest, &md5c);
+
+ // Convert md5sum to string
+
+ char md5sum[sizeof(digest)*2+1];
+ for (size_t i=0; i<sizeof(digest); ++i)
+ sprintf(md5sum+i*2,"%02x",digest[i]);
+
+ Info("Color md5sum ",md5sum);
+ }
+
+#ifndef REGAL_NO_PNG
+ if (Config::frameSaveColor)
+ {
+ const static png_color_8 pngSBIT = {8, 8, 8, 0, 8};
+
+ string filename = print_string("color_",boost::print::right(context.frame,3,'0'),".png");
+ FILE *fp = fopen(filename.c_str(), "wb");
+ if (fp)
+ {
+ png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
+ if (pngPtr)
+ {
+ png_infop pngInfo = png_create_info_struct(pngPtr);
+ if (pngInfo)
+ {
+ png_init_io(pngPtr, fp);
+
+ // Z_NO_COMPRESSION, Z_BEST_SPEED, Z_BEST_COMPRESSION,
+ // Z_DEFAULT_COMPRESSION
+
+ png_set_compression_level(pngPtr, Z_BEST_COMPRESSION);
+ png_set_IHDR(pngPtr, pngInfo, width, height,
+ 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_pHYs(pngPtr, pngInfo, 72 * 40, 72 * 40, PNG_RESOLUTION_METER);
+ png_set_sBIT(pngPtr, pngInfo, &pngSBIT);
+ png_write_info(pngPtr, pngInfo);
+ for (int y = height; y--; )
+ png_write_row(pngPtr, reinterpret_cast<png_byte *>(buffer + y * width * 4));
+ png_write_end(pngPtr, pngInfo);
+ }
+ png_destroy_write_struct(&pngPtr, &pngInfo);
+ }
+ fclose(fp);
+ }
+ }
+#endif
free(buffer);
-
- // Convert md5sum to string
-
- char md5sum[sizeof(digest)*2+1];
- for (size_t i=0; i<sizeof(digest); ++i)
- sprintf(md5sum+i*2,"%02x",digest[i]);
-
- Info("Color md5sum ",md5sum);
}
}
}
+
+ // Exit from the application if Config::frameLimit is reached.
+
+ if ( Config::frameLimit>0 && context.frame>=size_t(Config::frameLimit))
+ exit(0);
}
REGAL_NAMESPACE_END
View
12 src/regal/RegalTimer.h
@@ -50,13 +50,13 @@ struct Timer
{
typedef unsigned long long Value;
- Timer();
- ~Timer() {}
+ inline Timer();
+ inline ~Timer() {}
- void restart() { _start = now(); }
+ inline Timer::Value restart() { Timer::Value end = _start; _start = now(); return _start - end; }
- Timer::Value now(); /* Time in micro-seconds */
- Timer::Value elapsed() { return now() - _start; }
+ inline Timer::Value now(); /* Time in micro-seconds */
+ inline Timer::Value elapsed() { return now() - _start; }
Timer::Value _freq;
Timer::Value _start; /* Zero by default */
@@ -73,6 +73,7 @@ Timer::Timer()
_freq = Timer::Value(f);
}
+inline
Timer::Value Timer::now()
{
signed long long time;
@@ -89,6 +90,7 @@ Timer::Timer()
{
}
+inline
Timer::Value Timer::now()
{
struct timeval val;
View
14 src/regal/RegalUtil.cpp
@@ -112,7 +112,7 @@ const char *libraryLocation(const char *lib)
{
// This string will be leaked, but needs to remain
// valid until we're completely shut down.
-
+
char *tmp = (char *) calloc(strlen(ret)+23,1);
assert(tmp);
if (tmp)
@@ -175,24 +175,24 @@ void *GetProcAddress( const char *entry )
{
// this chdir business is a hacky solution to avoid recursion
// when using libRegal as libGL via symlink and DYLD_LIBRARY_PATH=.
-
+
char *oldCwd = getcwd(NULL,0);
chdir("/");
-
+
// CGL entry points are in OpenGL framework
-
+
if (!lib_OpenGL) {
lib_OpenGL = dlopen(lib_OpenGL_filename , RTLD_LAZY);
Info("Loading OpenGL from ",lib_OpenGL_filename,lib_OpenGL ? " succeeded." : " failed.");
}
-
+
// GL entry point are in libGL.dylib
-
+
if (!lib_GL) {
lib_GL = dlopen(lib_GL_filename, RTLD_LAZY);
Info("Loading OpenGL from ",lib_GL_filename,lib_GL ? " succeeded." : " failed.");
}
-
+
chdir(oldCwd);
free(oldCwd);
}

0 comments on commit 75ed019

Please sign in to comment.