diff options
author | Rob Clark <robdclark@gmail.com> | 2017-01-30 13:10:36 -0500 |
---|---|---|
committer | Jose Fonseca <jfonseca@vmware.com> | 2017-03-13 16:23:06 +0000 |
commit | d4bf220581782f74dd75b281ddc4d2d7955cd75c (patch) | |
tree | 98001760e0b35bf52c5fc27854f17cc7bb3e7bf6 | |
parent | b4daabd6aa0f377213b70b2558181aef9900637a (diff) |
retrace: support for dumping multiple snapshots (v3)windows-xp
Usually if an app is using MRT, we want to dump (and diff) *all* the
render targets to track down where things are going wrong. Also dumps
depth and stencil buffers.
When the --mrt (or -m) argument is specified, all render targets plus
depth and/or stencil are dumped, with the suffix -mrtN/-z/-s. Otherwise
the behavior is as before, only mrt0 is dumped with no suffix.
Only implemented for GLDumper, since I don't know anything about D3D.
-rw-r--r-- | cli/cli_dump_images.cpp | 10 | ||||
-rw-r--r-- | retrace/d3dretrace.hpp | 9 | ||||
-rwxr-xr-x | retrace/glretrace_main.cpp | 12 | ||||
-rw-r--r-- | retrace/glstate.hpp | 5 | ||||
-rw-r--r-- | retrace/glstate_images.cpp | 51 | ||||
-rw-r--r-- | retrace/retrace.hpp | 10 | ||||
-rw-r--r-- | retrace/retrace_main.cpp | 59 |
7 files changed, 128 insertions, 28 deletions
diff --git a/cli/cli_dump_images.cpp b/cli/cli_dump_images.cpp index bf3dc566..2c20c981 100644 --- a/cli/cli_dump_images.cpp +++ b/cli/cli_dump_images.cpp @@ -52,6 +52,7 @@ usage(void) " which dumps an image for each frame)\n" " --call-nos[=BOOL] use call numbers in image filenames,\n" " otherwise use sequental numbers (default=yes)\n" + " -m, --mrt dump all MRTs and depth/stencil\n" " -o, --output=PREFIX prefix to use in naming output files\n" " (default is trace filename without extension)\n" "\n"; @@ -63,13 +64,14 @@ enum { }; const static char * -shortOptions = "ho:"; +shortOptions = "hmo:"; const static struct option longOptions[] = { {"help", no_argument, 0, 'h'}, {"calls", required_argument, 0, CALLS_OPT}, {"call-nos", optional_argument, 0, CALL_NOS_OPT}, + {"mrt", no_argument, 0, 'm'}, {"output", required_argument, 0, 'o'}, {0, 0, 0, 0} }; @@ -82,6 +84,7 @@ command(int argc, char *argv[]) const char *traceName = NULL; const char *output = NULL; std::string call_nos; + bool mrt = false; int opt; while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) { @@ -96,6 +99,9 @@ command(int argc, char *argv[]) call_nos = "--call-nos="; call_nos.append(optarg); break; + case 'm': + mrt = true; + break; case 'o': output = optarg; break; @@ -140,6 +146,8 @@ command(int argc, char *argv[]) if (!call_nos.empty()) { opts.push_back(call_nos.c_str()); } + if (mrt) + opts.push_back("-m"); return executeRetrace(opts, traceName); } diff --git a/retrace/d3dretrace.hpp b/retrace/d3dretrace.hpp index d0be5773..d5fc848f 100644 --- a/retrace/d3dretrace.hpp +++ b/retrace/d3dretrace.hpp @@ -50,9 +50,14 @@ public: pLastDevice(NULL) {} + int + getSnapshotCount(void) override { + return 1; + } + image::Image * - getSnapshot(void) { - if (!pLastDevice) { + getSnapshot(int n) { + if ((n != 0) || !pLastDevice) { return NULL; } return d3dstate::getRenderTargetImage(pLastDevice); diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp index 829fbc87..8d015542 100755 --- a/retrace/glretrace_main.cpp +++ b/retrace/glretrace_main.cpp @@ -797,12 +797,20 @@ debugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, class GLDumper : public retrace::Dumper { public: + int + getSnapshotCount(void) override { + if (!glretrace::getCurrentContext()) { + return 0; + } + return glstate::getDrawBufferImageCount(); + } + image::Image * - getSnapshot(void) override { + getSnapshot(int n) override { if (!glretrace::getCurrentContext()) { return NULL; } - return glstate::getDrawBufferImage(); + return glstate::getDrawBufferImage(n); } bool diff --git a/retrace/glstate.hpp b/retrace/glstate.hpp index 417a0328..b6eb73aa 100644 --- a/retrace/glstate.hpp +++ b/retrace/glstate.hpp @@ -64,8 +64,11 @@ dumpCurrentContext(StateWriter &writer); bool getDrawableBounds(GLint *width, GLint *height); +int +getDrawBufferImageCount(void); + image::Image * -getDrawBufferImage(void); +getDrawBufferImage(int n); } /* namespace glstate */ diff --git a/retrace/glstate_images.cpp b/retrace/glstate_images.cpp index 13cddb17..a74a5b86 100644 --- a/retrace/glstate_images.cpp +++ b/retrace/glstate_images.cpp @@ -959,9 +959,25 @@ getFramebufferAttachmentDesc(Context &context, GLenum target, GLenum attachment, } +int +getDrawBufferImageCount() +{ + Context context; + GLint count; + + if (context.framebuffer_object) { + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &count); + flushErrors(); + } else { + return 0; + } + + return count; +} + image::Image * -getDrawBufferImage() +getDrawBufferImage(int n) { Context context; @@ -979,23 +995,42 @@ getDrawBufferImage() glGetIntegerv(framebuffer_binding, &draw_framebuffer); } + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + if (context.ES) { + format = GL_RGBA; + if ((n < 0) && !context.NV_read_depth_stencil) { + return NULL; + } + } + + if (n == -2) { + /* read stencil */ + format = GL_STENCIL_INDEX; + n = 0; + } else if (n == -1) { + /* read depth */ + format = GL_DEPTH_COMPONENT; + n = 0; + } + GLint draw_buffer = GL_NONE; ImageDesc desc; if (draw_framebuffer) { if (context.ARB_draw_buffers) { - glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer); + glGetIntegerv(GL_DRAW_BUFFER0 + n, &draw_buffer); if (draw_buffer == GL_NONE) { return NULL; } } else { // GL_COLOR_ATTACHMENT0 is implied - draw_buffer = GL_COLOR_ATTACHMENT0; + draw_buffer = GL_COLOR_ATTACHMENT0 + n; } if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) { return NULL; } - } else { + } else if (n == 0) { if (context.ES) { // XXX: Draw buffer is always FRONT for single buffer context, BACK // for double buffered contexts. There is no way to know which (as @@ -1014,12 +1049,8 @@ getDrawBufferImage() } desc.depth = 1; - } - - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - if (context.ES) { - format = GL_RGBA; + } else { + return NULL; } GLint channels = _gl_format_channels(format); diff --git a/retrace/retrace.hpp b/retrace/retrace.hpp index 356ad316..d753036c 100644 --- a/retrace/retrace.hpp +++ b/retrace/retrace.hpp @@ -119,6 +119,11 @@ extern unsigned debug; extern bool markers; /** + * Snapshot all render targets plus depth/stencil. + */ +extern bool snapshotMRT; + +/** * Whether to force windowed. Recommeded, as there is no guarantee that the * original display mode is available. */ @@ -223,8 +228,11 @@ public: class Dumper { public: + virtual int + getSnapshotCount(void) = 0; + virtual image::Image * - getSnapshot(void) = 0; + getSnapshot(int n) = 0; virtual bool canDump(void) = 0; diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp index fc24d385..2c3ba9d2 100644 --- a/retrace/retrace_main.cpp +++ b/retrace/retrace_main.cpp @@ -76,6 +76,7 @@ trace::Profiler profiler; int verbosity = 0; unsigned debug = 1; bool markers = false; +bool snapshotMRT = false; bool forceWindowed = true; bool dumpingState = false; bool dumpingSnapshots = false; @@ -126,8 +127,13 @@ frameComplete(trace::Call &call) { class DefaultDumper: public Dumper { public: + int + getSnapshotCount(void) override { + return 0; + } + image::Image * - getSnapshot(void) override { + getSnapshot(int n) override { return NULL; } @@ -159,15 +165,16 @@ static Snapshotter *snapshotter; * Take snapshots. */ static void -takeSnapshot(unsigned call_no) { - static unsigned snapshot_no = 0; +takeSnapshot(unsigned call_no, int mrt, unsigned snapshot_no) { assert(dumpingSnapshots); assert(snapshotPrefix); - std::unique_ptr<image::Image> src(dumper->getSnapshot()); + std::unique_ptr<image::Image> src(dumper->getSnapshot(mrt)); if (!src) { - std::cerr << call_no << ": warning: failed to get snapshot\n"; + /* TODO for mrt>0 we probably don't want to treat this as an error: */ + if (mrt == 0) + std::cerr << call_no << ": warning: failed to get snapshot\n"; return; } @@ -193,9 +200,21 @@ takeSnapshot(unsigned call_no) { break; } } else { - os::String filename = os::String::format("%s%010u.png", - snapshotPrefix, - useCallNos ? call_no : snapshot_no); + os::String filename; + unsigned no = useCallNos ? call_no : snapshot_no; + + if (!retrace::snapshotMRT) { + assert(mrt == 0); + filename = os::String::format("%s%010u.png", snapshotPrefix, no); + } else if (mrt == -2) { + /* stencil */ + filename = os::String::format("%s%010u-s.png", snapshotPrefix, no); + } else if (mrt == -1) { + /* depth */ + filename = os::String::format("%s%010u-z.png", snapshotPrefix, no); + } else { + filename = os::String::format("%s%010u-mrt%u.png", snapshotPrefix, no, mrt); + } // Here we release our ownership on the Image, it is now the // responsibility of the snapshotter to delete it. @@ -203,11 +222,24 @@ takeSnapshot(unsigned call_no) { } } - snapshot_no++; - return; } +static void +takeSnapshot(unsigned call_no) { + static unsigned snapshot_no = 0; + int cnt = dumper->getSnapshotCount(); + + if (retrace::snapshotMRT) { + for (int mrt = -2; mrt < cnt; mrt++) { + takeSnapshot(call_no, mrt, snapshot_no); + } + } else { + takeSnapshot(call_no, 0, snapshot_no); + } + + snapshot_no++; +} /** * Retrace one call. @@ -620,6 +652,7 @@ usage(const char *argv0) { " --fullscreen allow fullscreen\n" " --headless don't show windows\n" " --sb use a single buffer visual\n" + " -m, --mrt dump all MRTs and depth/stencil\n" " -s, --snapshot-prefix=PREFIX take snapshots; `-` for PNM stdout output\n" " --snapshot-format=FMT use (PNM, RGB, or MD5; default is PNM) when writing to stdout output\n" " -S, --snapshot=CALLSET calls to snapshot (default is every frame)\n" @@ -660,7 +693,7 @@ enum { }; const static char * -shortOptions = "bdD:hs:S:vwt"; +shortOptions = "bdD:hms:S:vwt"; const static struct option longOptions[] = { @@ -677,6 +710,7 @@ longOptions[] = { {"fullscreen", no_argument, 0, FULLSCREEN_OPT}, {"headless", no_argument, 0, HEADLESS_OPT}, {"help", no_argument, 0, 'h'}, + {"mrt", no_argument, 0, 'm'}, {"pcpu", no_argument, 0, PCPU_OPT}, {"pgpu", no_argument, 0, PGPU_OPT}, {"ppd", no_argument, 0, PPD_OPT}, @@ -782,6 +816,9 @@ int main(int argc, char **argv) case HEADLESS_OPT: ws::headless = true; break; + case 'm': + retrace::snapshotMRT = true; + break; case SB_OPT: retrace::doubleBuffer = false; break; |