summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2017-01-30 13:10:36 -0500
committerJose Fonseca <jfonseca@vmware.com>2017-03-13 16:23:06 +0000
commitd4bf220581782f74dd75b281ddc4d2d7955cd75c (patch)
tree98001760e0b35bf52c5fc27854f17cc7bb3e7bf6
parentb4daabd6aa0f377213b70b2558181aef9900637a (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.cpp10
-rw-r--r--retrace/d3dretrace.hpp9
-rwxr-xr-xretrace/glretrace_main.cpp12
-rw-r--r--retrace/glstate.hpp5
-rw-r--r--retrace/glstate_images.cpp51
-rw-r--r--retrace/retrace.hpp10
-rw-r--r--retrace/retrace_main.cpp59
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;