<div dir="ltr">Hi Rob,<div><br></div><div>Sorry for the delay. I'm finally looking into this. I'm going to rename the options from -f/--full to -m/--mrt, because I believe mrt is a more self describing option and the initial `m` is less common compared with `f` (e.g, full-xxx, force-xxx, etc.) Otherwise I'll commit as is. Thanks.</div><div><br></div><div>Jose</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Feb 12, 2017 at 11:21 PM, Rob Clark <span dir="ltr"><<a href="mailto:robdclark@gmail.com" target="_blank">robdclark@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Thanks.. not that urgent, just want to make sure that it wasn't<br>
forgotten (or assumed that I could push myself)..<br>
<br>
And congrats :-)<br>
<br>
BR,<br>
-R<br>
<div class="HOEnZb"><div class="h5"><br>
On Sun, Feb 12, 2017 at 7:30 AM, José Fonseca <<a href="mailto:jose.r.fonseca@gmail.com">jose.r.fonseca@gmail.com</a>> wrote:<br>
> Sorry for the silence, Rob.<br>
><br>
> I'm on a 2 week paternity leave. I'll take a look at the patches when I'm<br>
> back to work, on the week of Feb 20th.<br>
><br>
> Jose<br>
><br>
><br>
> On Sat, Feb 11, 2017 at 2:59 PM, Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>> wrote:<br>
>><br>
>> On Mon, Jan 30, 2017 at 1:10 PM, Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>> wrote:<br>
>> > Usually if an app is using MRT, we want to dump (and diff) *all* the<br>
>> > render targets to track down where things are going wrong. Also dumps<br>
>> > depth and stencil buffers.<br>
>> ><br>
>> > When the --full (or -f) argument is specified, all render targets plus<br>
>> > depth and/or stencil are dumped, with the suffix -mrtN/-z/-s. Otherwise<br>
>> > the behavior is as before, only mrt0 is dumped with no suffix.<br>
>> ><br>
>> > Only implemented for GLDumper, since I don't know anything about D3D.<br>
>><br>
>><br>
>> btw, is everyone happy with this version? If so, could someone push it?<br>
>><br>
>> BR,<br>
>> -R<br>
>><br>
>> > ---<br>
>> > cli/cli_dump_images.cpp | 10 +++++++-<br>
>> > retrace/d3dretrace.hpp | 9 +++++--<br>
>> > retrace/glretrace_main.cpp | 12 ++++++++--<br>
>> > retrace/glstate.hpp | 5 +++-<br>
>> > retrace/glstate_images.cpp | 51 ++++++++++++++++++++++++++++++<wbr>+--------<br>
>> > retrace/retrace.hpp | 10 +++++++-<br>
>> > retrace/retrace_main.cpp | 59<br>
>> > ++++++++++++++++++++++++++++++<wbr>+++++++---------<br>
>> > 7 files changed, 128 insertions(+), 28 deletions(-)<br>
>> ><br>
>> > diff --git a/cli/cli_dump_images.cpp b/cli/cli_dump_images.cpp<br>
>> > index bf3dc56..ee9f416 100644<br>
>> > --- a/cli/cli_dump_images.cpp<br>
>> > +++ b/cli/cli_dump_images.cpp<br>
>> > @@ -54,6 +54,7 @@ usage(void)<br>
>> > " otherwise use sequental numbers<br>
>> > (default=yes)\n"<br>
>> > " -o, --output=PREFIX prefix to use in naming output<br>
>> > files\n"<br>
>> > " (default is trace filename without<br>
>> > extension)\n"<br>
>> > + " -f, --full dump all MRTs and depth/stencil\n"<br>
>> > "\n";<br>
>> > }<br>
>> ><br>
>> > @@ -63,7 +64,7 @@ enum {<br>
>> > };<br>
>> ><br>
>> > const static char *<br>
>> > -shortOptions = "ho:";<br>
>> > +shortOptions = "ho:f";<br>
>> ><br>
>> > const static struct option<br>
>> > longOptions[] = {<br>
>> > @@ -71,6 +72,7 @@ longOptions[] = {<br>
>> > {"calls", required_argument, 0, CALLS_OPT},<br>
>> > {"call-nos", optional_argument, 0, CALL_NOS_OPT},<br>
>> > {"output", required_argument, 0, 'o'},<br>
>> > + {"full", no_argument, 0, 'f'},<br>
>> > {0, 0, 0, 0}<br>
>> > };<br>
>> ><br>
>> > @@ -82,6 +84,7 @@ command(int argc, char *argv[])<br>
>> > const char *traceName = NULL;<br>
>> > const char *output = NULL;<br>
>> > std::string call_nos;<br>
>> > + bool full = false;<br>
>> ><br>
>> > int opt;<br>
>> > while ((opt = getopt_long(argc, argv, shortOptions, longOptions,<br>
>> > NULL)) != -1) {<br>
>> > @@ -99,6 +102,9 @@ command(int argc, char *argv[])<br>
>> > case 'o':<br>
>> > output = optarg;<br>
>> > break;<br>
>> > + case 'f':<br>
>> > + full = true;<br>
>> > + break;<br>
>> > default:<br>
>> > std::cerr << "error: unexpected option `" << (char)opt <<<br>
>> > "`\n";<br>
>> > usage();<br>
>> > @@ -140,6 +146,8 @@ command(int argc, char *argv[])<br>
>> > if (!call_nos.empty()) {<br>
>> > opts.push_back(call_nos.c_str(<wbr>));<br>
>> > }<br>
>> > + if (full)<br>
>> > + opts.push_back("-f");<br>
>> ><br>
>> > return executeRetrace(opts, traceName);<br>
>> > }<br>
>> > diff --git a/retrace/d3dretrace.hpp b/retrace/d3dretrace.hpp<br>
>> > index d0be577..d5fc848 100644<br>
>> > --- a/retrace/d3dretrace.hpp<br>
>> > +++ b/retrace/d3dretrace.hpp<br>
>> > @@ -50,9 +50,14 @@ public:<br>
>> > pLastDevice(NULL)<br>
>> > {}<br>
>> ><br>
>> > + int<br>
>> > + getSnapshotCount(void) override {<br>
>> > + return 1;<br>
>> > + }<br>
>> > +<br>
>> > image::Image *<br>
>> > - getSnapshot(void) {<br>
>> > - if (!pLastDevice) {<br>
>> > + getSnapshot(int n) {<br>
>> > + if ((n != 0) || !pLastDevice) {<br>
>> > return NULL;<br>
>> > }<br>
>> > return d3dstate::<wbr>getRenderTargetImage(<wbr>pLastDevice);<br>
>> > diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp<br>
>> > index db94ce6..681a268 100755<br>
>> > --- a/retrace/glretrace_main.cpp<br>
>> > +++ b/retrace/glretrace_main.cpp<br>
>> > @@ -817,12 +817,20 @@ debugOutputCallback(GLenum source, GLenum type,<br>
>> > GLuint id, GLenum severity,<br>
>> ><br>
>> > class GLDumper : public retrace::Dumper {<br>
>> > public:<br>
>> > + int<br>
>> > + getSnapshotCount(void) override {<br>
>> > + if (!glretrace::<wbr>getCurrentContext()) {<br>
>> > + return 0;<br>
>> > + }<br>
>> > + return glstate::<wbr>getDrawBufferImageCount();<br>
>> > + }<br>
>> > +<br>
>> > image::Image *<br>
>> > - getSnapshot(void) override {<br>
>> > + getSnapshot(int n) override {<br>
>> > if (!glretrace::<wbr>getCurrentContext()) {<br>
>> > return NULL;<br>
>> > }<br>
>> > - return glstate::getDrawBufferImage();<br>
>> > + return glstate::getDrawBufferImage(n)<wbr>;<br>
>> > }<br>
>> ><br>
>> > bool<br>
>> > diff --git a/retrace/glstate.hpp b/retrace/glstate.hpp<br>
>> > index 417a032..b6eb73a 100644<br>
>> > --- a/retrace/glstate.hpp<br>
>> > +++ b/retrace/glstate.hpp<br>
>> > @@ -64,8 +64,11 @@ dumpCurrentContext(StateWriter &writer);<br>
>> > bool<br>
>> > getDrawableBounds(GLint *width, GLint *height);<br>
>> ><br>
>> > +int<br>
>> > +getDrawBufferImageCount(void)<wbr>;<br>
>> > +<br>
>> > image::Image *<br>
>> > -getDrawBufferImage(void);<br>
>> > +getDrawBufferImage(int n);<br>
>> ><br>
>> ><br>
>> > } /* namespace glstate */<br>
>> > diff --git a/retrace/glstate_images.cpp b/retrace/glstate_images.cpp<br>
>> > index 13cddb1..a74a5b8 100644<br>
>> > --- a/retrace/glstate_images.cpp<br>
>> > +++ b/retrace/glstate_images.cpp<br>
>> > @@ -959,9 +959,25 @@ getFramebufferAttachmentDesc(<wbr>Context &context,<br>
>> > GLenum target, GLenum attachment,<br>
>> > }<br>
>> ><br>
>> ><br>
>> > +int<br>
>> > +getDrawBufferImageCount()<br>
>> > +{<br>
>> > + Context context;<br>
>> > + GLint count;<br>
>> > +<br>
>> > + if (context.framebuffer_object) {<br>
>> > + glGetIntegerv(GL_MAX_DRAW_<wbr>BUFFERS, &count);<br>
>> > + flushErrors();<br>
>> > + } else {<br>
>> > + return 0;<br>
>> > + }<br>
>> > +<br>
>> > + return count;<br>
>> > +}<br>
>> > +<br>
>> ><br>
>> > image::Image *<br>
>> > -getDrawBufferImage()<br>
>> > +getDrawBufferImage(int n)<br>
>> > {<br>
>> > Context context;<br>
>> ><br>
>> > @@ -979,23 +995,42 @@ getDrawBufferImage()<br>
>> > glGetIntegerv(framebuffer_<wbr>binding, &draw_framebuffer);<br>
>> > }<br>
>> ><br>
>> > + GLenum format = GL_RGB;<br>
>> > + GLenum type = GL_UNSIGNED_BYTE;<br>
>> > + if (context.ES) {<br>
>> > + format = GL_RGBA;<br>
>> > + if ((n < 0) && !context.NV_read_depth_<wbr>stencil) {<br>
>> > + return NULL;<br>
>> > + }<br>
>> > + }<br>
>> > +<br>
>> > + if (n == -2) {<br>
>> > + /* read stencil */<br>
>> > + format = GL_STENCIL_INDEX;<br>
>> > + n = 0;<br>
>> > + } else if (n == -1) {<br>
>> > + /* read depth */<br>
>> > + format = GL_DEPTH_COMPONENT;<br>
>> > + n = 0;<br>
>> > + }<br>
>> > +<br>
>> > GLint draw_buffer = GL_NONE;<br>
>> > ImageDesc desc;<br>
>> > if (draw_framebuffer) {<br>
>> > if (context.ARB_draw_buffers) {<br>
>> > - glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);<br>
>> > + glGetIntegerv(GL_DRAW_BUFFER0 + n, &draw_buffer);<br>
>> > if (draw_buffer == GL_NONE) {<br>
>> > return NULL;<br>
>> > }<br>
>> > } else {<br>
>> > // GL_COLOR_ATTACHMENT0 is implied<br>
>> > - draw_buffer = GL_COLOR_ATTACHMENT0;<br>
>> > + draw_buffer = GL_COLOR_ATTACHMENT0 + n;<br>
>> > }<br>
>> ><br>
>> > if (!<wbr>getFramebufferAttachmentDesc(<wbr>context, framebuffer_target,<br>
>> > draw_buffer, desc)) {<br>
>> > return NULL;<br>
>> > }<br>
>> > - } else {<br>
>> > + } else if (n == 0) {<br>
>> > if (context.ES) {<br>
>> > // XXX: Draw buffer is always FRONT for single buffer<br>
>> > context, BACK<br>
>> > // for double buffered contexts. There is no way to know<br>
>> > which (as<br>
>> > @@ -1014,12 +1049,8 @@ getDrawBufferImage()<br>
>> > }<br>
>> ><br>
>> > desc.depth = 1;<br>
>> > - }<br>
>> > -<br>
>> > - GLenum format = GL_RGB;<br>
>> > - GLenum type = GL_UNSIGNED_BYTE;<br>
>> > - if (context.ES) {<br>
>> > - format = GL_RGBA;<br>
>> > + } else {<br>
>> > + return NULL;<br>
>> > }<br>
>> ><br>
>> > GLint channels = _gl_format_channels(format);<br>
>> > diff --git a/retrace/retrace.hpp b/retrace/retrace.hpp<br>
>> > index 356ad31..a0f3442 100644<br>
>> > --- a/retrace/retrace.hpp<br>
>> > +++ b/retrace/retrace.hpp<br>
>> > @@ -119,6 +119,11 @@ extern unsigned debug;<br>
>> > extern bool markers;<br>
>> ><br>
>> > /**<br>
>> > + * Snapshot all render targets plus depth/stencil.<br>
>> > + */<br>
>> > +extern bool snapshotFull;<br>
>> > +<br>
>> > +/**<br>
>> > * Whether to force windowed. Recommeded, as there is no guarantee that<br>
>> > the<br>
>> > * original display mode is available.<br>
>> > */<br>
>> > @@ -223,8 +228,11 @@ public:<br>
>> > class Dumper<br>
>> > {<br>
>> > public:<br>
>> > + virtual int<br>
>> > + getSnapshotCount(void) = 0;<br>
>> > +<br>
>> > virtual image::Image *<br>
>> > - getSnapshot(void) = 0;<br>
>> > + getSnapshot(int n) = 0;<br>
>> ><br>
>> > virtual bool<br>
>> > canDump(void) = 0;<br>
>> > diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp<br>
>> > index 83b43ca..7c91a6b 100644<br>
>> > --- a/retrace/retrace_main.cpp<br>
>> > +++ b/retrace/retrace_main.cpp<br>
>> > @@ -76,6 +76,7 @@ trace::Profiler profiler;<br>
>> > int verbosity = 0;<br>
>> > unsigned debug = 1;<br>
>> > bool markers = false;<br>
>> > +bool snapshotFull = false;<br>
>> > bool forceWindowed = true;<br>
>> > bool dumpingState = false;<br>
>> > bool dumpingSnapshots = false;<br>
>> > @@ -133,8 +134,13 @@ frameComplete(trace::Call &call) {<br>
>> > class DefaultDumper: public Dumper<br>
>> > {<br>
>> > public:<br>
>> > + int<br>
>> > + getSnapshotCount(void) override {<br>
>> > + return 0;<br>
>> > + }<br>
>> > +<br>
>> > image::Image *<br>
>> > - getSnapshot(void) override {<br>
>> > + getSnapshot(int n) override {<br>
>> > return NULL;<br>
>> > }<br>
>> ><br>
>> > @@ -166,15 +172,16 @@ static Snapshotter *snapshotter;<br>
>> > * Take snapshots.<br>
>> > */<br>
>> > static void<br>
>> > -takeSnapshot(unsigned call_no) {<br>
>> > - static unsigned snapshot_no = 0;<br>
>> > +takeSnapshot(unsigned call_no, int mrt, unsigned snapshot_no) {<br>
>> ><br>
>> > assert(dumpingSnapshots);<br>
>> > assert(snapshotPrefix);<br>
>> ><br>
>> > - std::unique_ptr<image::Image> src(dumper->getSnapshot());<br>
>> > + std::unique_ptr<image::Image> src(dumper->getSnapshot(mrt));<br>
>> > if (!src) {<br>
>> > - std::cerr << call_no << ": warning: failed to get snapshot\n";<br>
>> > + /* TODO for mrt>0 we probably don't want to treat this as an<br>
>> > error: */<br>
>> > + if (mrt == 0)<br>
>> > + std::cerr << call_no << ": warning: failed to get<br>
>> > snapshot\n";<br>
>> > return;<br>
>> > }<br>
>> ><br>
>> > @@ -200,9 +207,21 @@ takeSnapshot(unsigned call_no) {<br>
>> > break;<br>
>> > }<br>
>> > } else {<br>
>> > - os::String filename = os::String::format("%s%010u.<wbr>png",<br>
>> > - snapshotPrefix,<br>
>> > - useCallNos ?<br>
>> > call_no : snapshot_no);<br>
>> > + os::String filename;<br>
>> > + unsigned no = useCallNos ? call_no : snapshot_no;<br>
>> > +<br>
>> > + if (!retrace::snapshotFull) {<br>
>> > + assert(mrt == 0);<br>
>> > + filename = os::String::format("%s%010u.<wbr>png",<br>
>> > snapshotPrefix, no);<br>
>> > + } else if (mrt == -2) {<br>
>> > + /* stencil */<br>
>> > + filename = os::String::format("%s%010u-s.<wbr>png",<br>
>> > snapshotPrefix, no);<br>
>> > + } else if (mrt == -1) {<br>
>> > + /* depth */<br>
>> > + filename = os::String::format("%s%010u-z.<wbr>png",<br>
>> > snapshotPrefix, no);<br>
>> > + } else {<br>
>> > + filename = os::String::format("%s%010u-<wbr>mrt%u.png",<br>
>> > snapshotPrefix, no, mrt);<br>
>> > + }<br>
>> ><br>
>> > // Here we release our ownership on the Image, it is now<br>
>> > the<br>
>> > // responsibility of the snapshotter to delete it.<br>
>> > @@ -210,11 +229,24 @@ takeSnapshot(unsigned call_no) {<br>
>> > }<br>
>> > }<br>
>> ><br>
>> > - snapshot_no++;<br>
>> > -<br>
>> > return;<br>
>> > }<br>
>> ><br>
>> > +static void<br>
>> > +takeSnapshot(unsigned call_no) {<br>
>> > + static unsigned snapshot_no = 0;<br>
>> > + int cnt = dumper->getSnapshotCount();<br>
>> > +<br>
>> > + if (retrace::snapshotFull) {<br>
>> > + for (int mrt = -2; mrt < cnt; mrt++) {<br>
>> > + takeSnapshot(call_no, mrt, snapshot_no);<br>
>> > + }<br>
>> > + } else {<br>
>> > + takeSnapshot(call_no, 0, snapshot_no);<br>
>> > + }<br>
>> > +<br>
>> > + snapshot_no++;<br>
>> > +}<br>
>> ><br>
>> > /**<br>
>> > * Retrace one call.<br>
>> > @@ -632,6 +664,7 @@ usage(const char *argv0) {<br>
>> > " -S, --snapshot=CALLSET calls to snapshot (default is every<br>
>> > frame)\n"<br>
>> > " --snapshot-interval=N specify a frame interval when<br>
>> > generating snaphots (default is 0)\n"<br>
>> > " -t, --snapshot-threaded encode screenshots on multiple<br>
>> > threads\n"<br>
>> > + " -f, --full dump all MRTs and depth/stencil\n"<br>
>> > " -v, --verbose increase output verbosity\n"<br>
>> > " -D, --dump-state=CALL dump state at specific call no\n"<br>
>> > " --dump-format=FORMAT dump state format (`json` or<br>
>> > `ubjson`)\n"<br>
>> > @@ -668,7 +701,7 @@ enum {<br>
>> > };<br>
>> ><br>
>> > const static char *<br>
>> > -shortOptions = "bdD:hs:S:vwt";<br>
>> > +shortOptions = "bdD:hs:S:fvwt";<br>
>> ><br>
>> > const static struct option<br>
>> > longOptions[] = {<br>
>> > @@ -701,6 +734,7 @@ longOptions[] = {<br>
>> > {"snapshot", required_argument, 0, 'S'},<br>
>> > {"snapshot-interval", required_argument, 0, SNAPSHOT_INTERVAL_OPT},<br>
>> > {"snapshot-threaded", no_argument, 0, 't'},<br>
>> > + {"full", no_argument, 0, 'f'},<br>
>> > {"verbose", no_argument, 0, 'v'},<br>
>> > {"wait", no_argument, 0, 'w'},<br>
>> > {"loop", optional_argument, 0, LOOP_OPT},<br>
>> > @@ -843,6 +877,9 @@ int main(int argc, char **argv)<br>
>> > case 't':<br>
>> > snapshotThreaded = true;<br>
>> > break;<br>
>> > + case 'f':<br>
>> > + retrace::snapshotFull = true;<br>
>> > + break;<br>
>> > case 'v':<br>
>> > ++retrace::verbosity;<br>
>> > break;<br>
>> > --<br>
>> > 2.9.3<br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div>