[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

apitrace: Changes to 'upstream'



 0 files changed

New commits:
commit b2754af2a0257ef8a7649fd76b7c0bc034e52c89
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Mon Jun 19 14:22:55 2017 +0100

    d3dretrace: Swizzle RowPitch in ID3D10*::Map.
    
    A bit of an hack, but still better than no swizlling what so ever.

diff --git a/retrace/dxgiretrace.py b/retrace/dxgiretrace.py
index 789cefe..8432994 100755
--- a/retrace/dxgiretrace.py
+++ b/retrace/dxgiretrace.py
@@ -361,7 +361,6 @@ class D3DRetracer(Retracer):
                 print '        _normalizeMap(pResource, pMappedResource);'
             else:
                 print '        _pbData = _MapDesc.pData;'
-                self.checkPitchMismatch(method)
             print '    } else {'
             print '        return;'
             print '    }'
@@ -397,23 +396,43 @@ class D3DRetracer(Retracer):
         Retracer.retraceInterfaceMethodBody(self, interface, method)
 
         # Add pitch swizzling information to the region
-        if interface.name.startswith('ID3D11DeviceContext') and method.name == 'Map':
-            outArg = method.getArgByName('pMappedResource')
-            print r'    if (_pbData && pMappedResource->RowPitch != 0) {'
+        if method.name == 'Map' and interface.name not in ('ID3D10Buffer', 'ID3D10Texture1D'):
+            if interface.name.startswith('ID3D11DeviceContext'):
+                outArg = method.getArgByName('pMappedResource')
+                memberNames = ('pData', 'RowPitch', 'DepthPitch')
+            elif interface.name.startswith('ID3D10'):
+                outArg = method.args[-1]
+                memberNames = ('pData', 'RowPitch', 'DepthPitch')
+            elif interface.name == 'IDXGISurface':
+                outArg = method.getArgByName('pLockedRect')
+                memberNames = ('pBits', 'Pitch', None)
+            else:
+                raise NotImplementedError
+            struct = outArg.type.type
+            dataMemberName, rowPitchMemberName, depthPitchMemberName = memberNames
+            dataMemberIndex = struct.getMemberByName(dataMemberName)
+            rowPitchMemberIndex = struct.getMemberByName(rowPitchMemberName)
+            print r'    if (_pbData && %s->%s != 0) {' % (outArg.name, rowPitchMemberName)
             print r'        const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index)
             print r'        if (%s) {' % outArg.name
             print r'            const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name)
             print r'            if (_struct) {'
-            struct = outArg.type.type
-            print r'                unsigned long long traceAddress = _struct->members[%u]->toUIntPtr();' % struct.getMemberByName('pData')
-            print r'                int traceRowPitch = _struct->members[%u]->toSInt();' % struct.getMemberByName('RowPitch')
-            print r'                int realRowPitch = pMappedResource->RowPitch;'
+            print r'                unsigned long long traceAddress = _struct->members[%u]->toUIntPtr();' % dataMemberIndex
+            print r'                int traceRowPitch = _struct->members[%u]->toSInt();' % rowPitchMemberIndex
+            print r'                int realRowPitch = %s->%s;' % (outArg.name, rowPitchMemberName)
             print r'                if (realRowPitch && traceRowPitch != realRowPitch) {'
             print r'                    retrace::setRegionPitch(traceAddress, 2, traceRowPitch, realRowPitch);'
-            print r'                    if (pMappedResource->DepthPitch) {'
-            print r'                        retrace::checkMismatch(call, "DepthPitch", _struct->members[%u], pMappedResource->DepthPitch);' % (struct.getMemberByName('DepthPitch'))
-            print r'                    }'
             print r'                }'
+            try:
+                depthPitchMemberIndex = struct.getMemberByName(depthPitchMemberName)
+            except ValueError:
+                assert len(struct.members) < 3
+                pass
+            else:
+                assert depthPitchMemberName == 'DepthPitch'
+                print r'                if (%s->DepthPitch) {' % outArg.name
+                print r'                    retrace::checkMismatch(call, "DepthPitch", _struct->members[%u], %s->DepthPitch);' % (struct.getMemberByName('DepthPitch'), outArg.name)
+                print r'                }'
             print r'            }'
             print r'        }'
             print r'    }'

commit 37f769f2a85e690913390ede3ae202e1a94deb65
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Fri Jun 16 17:57:39 2017 +0100

    d3dretrace: Swizzle RowPitch in ID3D11DeviceContext::Map.

diff --git a/retrace/dxgiretrace.py b/retrace/dxgiretrace.py
index 97d2b59..789cefe 100755
--- a/retrace/dxgiretrace.py
+++ b/retrace/dxgiretrace.py
@@ -359,7 +359,6 @@ class D3DRetracer(Retracer):
                 # Prevent false warnings on 1D and 2D resources, since the
                 # pitches are often junk there...
                 print '        _normalizeMap(pResource, pMappedResource);'
-                self.checkPitchMismatch(method)
             else:
                 print '        _pbData = _MapDesc.pData;'
                 self.checkPitchMismatch(method)
@@ -394,6 +393,32 @@ class D3DRetracer(Retracer):
             print r'        (*%s)->SetPrivateData(d3dstate::GUID_D3DSTATE, BytecodeLength, pShaderBytecode);' % ppShader.name
             print r'    }'
 
+    def retraceInterfaceMethodBody(self, interface, method):
+        Retracer.retraceInterfaceMethodBody(self, interface, method)
+
+        # Add pitch swizzling information to the region
+        if interface.name.startswith('ID3D11DeviceContext') and method.name == 'Map':
+            outArg = method.getArgByName('pMappedResource')
+            print r'    if (_pbData && pMappedResource->RowPitch != 0) {'
+            print r'        const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index)
+            print r'        if (%s) {' % outArg.name
+            print r'            const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name)
+            print r'            if (_struct) {'
+            struct = outArg.type.type
+            print r'                unsigned long long traceAddress = _struct->members[%u]->toUIntPtr();' % struct.getMemberByName('pData')
+            print r'                int traceRowPitch = _struct->members[%u]->toSInt();' % struct.getMemberByName('RowPitch')
+            print r'                int realRowPitch = pMappedResource->RowPitch;'
+            print r'                if (realRowPitch && traceRowPitch != realRowPitch) {'
+            print r'                    retrace::setRegionPitch(traceAddress, 2, traceRowPitch, realRowPitch);'
+            print r'                    if (pMappedResource->DepthPitch) {'
+            print r'                        retrace::checkMismatch(call, "DepthPitch", _struct->members[%u], pMappedResource->DepthPitch);' % (struct.getMemberByName('DepthPitch'))
+            print r'                    }'
+            print r'                }'
+            print r'            }'
+            print r'        }'
+            print r'    }'
+
+
     def extractArg(self, function, arg, arg_type, lvalue, rvalue):
         # Set object names
         if function.name == 'SetPrivateData' and arg.name == 'pData':
diff --git a/retrace/retrace_stdc.cpp b/retrace/retrace_stdc.cpp
index 2a57ef0..a2ce3f3 100644
--- a/retrace/retrace_stdc.cpp
+++ b/retrace/retrace_stdc.cpp
@@ -52,33 +52,68 @@ static void retrace_malloc(trace::Call &call) {
 }
 
 
-static void retrace_memcpy(trace::Call &call) {
-    void * destPtr;
-    size_t destLen;
-    retrace::toRange(call.arg(0), destPtr, destLen);
+static void
+retrace_memcpy(trace::Call &call)
+{
+    retrace::Range destRange;
+    retrace::toRange(call.arg(0), destRange);
 
-    void * srcPtr;
-    size_t srcLen;
-    retrace::toRange(call.arg(1), srcPtr, srcLen);
+    retrace::Range srcRange;
+    retrace::toRange(call.arg(1), srcRange);
 
     size_t n = call.arg(2).toUInt();
 
-    if (!destPtr || !srcPtr || !n) {
+    if (!destRange.ptr || !srcRange.ptr || !n) {
         return;
     }
 
-    if (n > destLen) {
-        retrace::warning(call) << "dest buffer overflow of " << n - destLen << " bytes\n";
+    // We don't support sources with swizzled pitches
+    assert(srcRange.dims == 0);
+
+    assert(destRange.dims <= 2);
+    if (destRange.dims == 2 &&
+        destRange.tracePitch != destRange.realPitch) {
+        int srcPitch = destRange.tracePitch;
+        int destPitch = destRange.realPitch;
+
+        if (0) {
+            retrace::warning(call) << "swizzling pitch from " << srcPitch << " to " << destPitch << "\n";
+        }
+
+        int destOffset = 0;
+        int srcOffset = 0;
+        int width = std::min(destPitch, srcPitch);
+        while (destOffset + width <= destRange.len &&
+               srcOffset + width <= srcRange.len) {
+            memcpy((char *)destRange.ptr + destOffset,
+                   (char *)srcRange.ptr + srcOffset, width);
+            destOffset += destPitch;
+            srcOffset += srcPitch;
+        }
+
+        if (destOffset < destRange.len &&
+            srcOffset < srcRange.len) {
+            width = std::min(destRange.len - destOffset, srcRange.len - srcOffset);
+            memcpy((char *)destRange.ptr + destOffset,
+                   (char *)srcRange.ptr + srcOffset, width);
+        }
+
+        return;
+    }
+
+
+    if (n > destRange.len) {
+        retrace::warning(call) << "dest buffer overflow of " << n - destRange.len << " bytes\n";
     }
 
-    if (n > srcLen) {
-        retrace::warning(call) << "src buffer overflow of " << n - srcLen << " bytes\n";
+    if (n > srcRange.len) {
+        retrace::warning(call) << "src buffer overflow of " << n - srcRange.len << " bytes\n";
     }
 
-    n = std::min(n, destLen);
-    n = std::min(n, srcLen);
+    n = std::min(n, destRange.len);
+    n = std::min(n, srcRange.len);
 
-    memcpy(destPtr, srcPtr, n);
+    memcpy(destRange.ptr, srcRange.ptr, n);
 }
 
 
diff --git a/retrace/retrace_swizzle.cpp b/retrace/retrace_swizzle.cpp
index c308334..e27af7e 100644
--- a/retrace/retrace_swizzle.cpp
+++ b/retrace/retrace_swizzle.cpp
@@ -37,8 +37,11 @@ namespace retrace {
 
 struct Region
 {
-    void *buffer;
-    unsigned long long size;
+    void *buffer = nullptr;
+    unsigned long long size = 0;
+    unsigned dimensions = 0;
+    int tracePitch = 0;
+    int realPitch = 0;
 };
 
 typedef std::map<unsigned long long, Region> RegionMap;
@@ -114,7 +117,7 @@ addRegion(trace::Call &call, unsigned long long address, void *buffer, unsigned
 
     if (!address) {
         // Ignore NULL pointer
-        assert(!buffer);
+        assert(buffer == nullptr);
         return;
     }
 
@@ -168,6 +171,19 @@ lookupRegion(unsigned long long address) {
 }
 
 void
+setRegionPitch(unsigned long long address, unsigned dimensions, int tracePitch, int realPitch) {
+    RegionMap::iterator it = lookupRegion(address);
+    if (it != regionMap.end()) {
+        Region &region = it->second;
+        region.dimensions = dimensions;
+        region.tracePitch = tracePitch;
+        region.realPitch = realPitch;
+    } else {
+        assert(0);
+    }
+}
+
+void
 delRegion(unsigned long long address) {
     RegionMap::iterator it = lookupRegion(address);
     if (it != regionMap.end()) {
@@ -190,14 +206,18 @@ delRegionByPointer(void *ptr) {
 }
 
 static void
-lookupAddress(unsigned long long address, void * & ptr, size_t & len) {
-    RegionMap::iterator it = lookupRegion(address);
+lookupAddress(unsigned long long address, Range &range) {
+    RegionMap::const_iterator it = lookupRegion(address);
     if (it != regionMap.end()) {
+        const Region & region = it->second;
         unsigned long long offset = address - it->first;
-        assert(offset < it->second.size);
+        assert(offset < region.size);
 
-        ptr = (char *)it->second.buffer + offset;
-        len = it->second.size - offset;
+        range.ptr = (char *)region.buffer + offset;
+        range.len = region.size - offset;
+        range.dims = region.dimensions;
+        range.tracePitch = region.tracePitch;
+        range.realPitch = region.realPitch;
 
         if (retrace::verbosity >= 2) {
             std::cout
@@ -205,7 +225,7 @@ lookupAddress(unsigned long long address, void * & ptr, size_t & len) {
                 << std::hex
                 << "0x" << address
                 << " <- "
-                << "0x" << (uintptr_t)ptr
+                << "0x" << (uintptr_t)range.ptr
                 << std::dec
                 << "\n";
         }
@@ -218,8 +238,8 @@ lookupAddress(unsigned long long address, void * & ptr, size_t & len) {
         std::cerr << "warning: passing high address 0x" << std::hex << address << std::dec << " as uintptr_t\n";
     }
 
-    ptr = (void *)(uintptr_t)address;
-    len = 0;
+    range.ptr = (void *)(uintptr_t)address;
+    range.len = 0;
 }
 
 
@@ -228,53 +248,54 @@ class Translator : protected trace::Visitor
 protected:
     const bool bind;
 
-    void *ptr;
-    size_t len;
+    Range &range;
 
 protected:
     void visit(trace::Null *) override {
-        ptr = NULL;
-        len = 0;
+        range.ptr = nullptr;
+        range.len = 0;
+        range.dims = 0;
     }
 
     void visit(trace::Blob *blob) override {
-        ptr = blob->toPointer(bind);
-        len = blob->size;
+        range.ptr = blob->toPointer(bind);
+        range.len = blob->size;
+        range.dims = 0;
     }
 
     void visit(trace::Pointer *p) override {
-        lookupAddress(p->value, ptr, len);
+        lookupAddress(p->value, range);
     }
 
 public:
-    Translator(bool _bind) :
+    Translator(bool _bind, Range &_range) :
         bind(_bind),
-        ptr(NULL),
-        len(0)
-    {}
+        range(_range)
+    {
+        range.ptr = nullptr;
+        range.len = 0;
+        range.dims = 0;
+    }
 
     void
-    operator() (trace::Value *node, void * & _ptr, size_t & _len) {
+    apply(trace::Value *node) {
         _visit(node);
-        _ptr = ptr;
-        _len = len;
     }
 };
 
 
 void
-toRange(trace::Value &value, void * & ptr, size_t & len) {
-    Translator(false) (&value, ptr, len);
+toRange(trace::Value &value, Range &range)
+{
+    Translator(false, range).apply(&value);
 }
 
 void *
-toPointer(trace::Value &value, bool bind) {
-    void * ptr;
-    size_t len;
-    Translator translator(bind);
-    translator(&value, ptr, len);
-    (void)len;
-    return ptr;
+toPointer(trace::Value &value, bool bind)
+{
+    Range range;
+    Translator(bind, range).apply(&value);
+    return range.ptr;
 }
 
 
@@ -323,7 +344,7 @@ toObjPointer(trace::Call &call, trace::Value &value) {
             warning(call) << "unknown object 0x" << std::hex << address << std::dec << "\n";
         }
     } else {
-        obj = NULL;
+        obj = nullptr;
     }
 
     if (retrace::verbosity >= 2) {
diff --git a/retrace/retrace_swizzle.hpp b/retrace/retrace_swizzle.hpp
index 7458971..5b87cd2 100644
--- a/retrace/retrace_swizzle.hpp
+++ b/retrace/retrace_swizzle.hpp
@@ -110,10 +110,22 @@ void
 addRegion(trace::Call &call, unsigned long long address, void *buffer, unsigned long long size);
 
 void
+setRegionPitch(unsigned long long address, unsigned dimensions, int tracePitch, int realPitch);
+
+void
 delRegionByPointer(void *ptr);
 
+struct Range
+{
+    void * ptr;
+    size_t len;
+    unsigned dims;
+    int tracePitch;
+    int realPitch;
+};
+
 void
-toRange(trace::Value &value, void * & ptr, size_t & len);
+toRange(trace::Value &value, Range & range);
 
 void *
 toPointer(trace::Value &value, bool bind = false);
diff --git a/specs/stdapi.py b/specs/stdapi.py
index 50d3e80..52bbb98 100644
--- a/specs/stdapi.py
+++ b/specs/stdapi.py
@@ -335,6 +335,10 @@ class Struct(Type):
     def visit(self, visitor, *args, **kwargs):
         return visitor.visitStruct(self, *args, **kwargs)
 
+    def getMemberByName(self, name):
+        memberNames = [memberName for memberType, memberName in self.members]
+        return memberNames.index(name)
+
 
 def Union(kindExpr, kindTypes, contextLess=True):
     switchTypes = []

commit dbb01afdc52f5ca5e4a69457037b489aaad0d8b3
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Fri Jun 16 11:45:19 2017 +0100

    d3dretrace: Use D3DCREATE_SOFTWARE_VERTEXPROCESSING for --driver=sw.
    
    Ideally we'd use the WARP, but I failed to find a way to use WARP on
    demand for D3D9.  (The only solution is to disable the  GPU driver,
    or to use a Windows 8.x/10 VM without any virtual GPU, but neither is
    practical.)

diff --git a/retrace/d3d9retrace.py b/retrace/d3d9retrace.py
index 93a3ec4..40e9a44 100644
--- a/retrace/d3d9retrace.py
+++ b/retrace/d3d9retrace.py
@@ -147,6 +147,10 @@ class D3DRetracer(Retracer):
             print r'        DeviceType = D3DDEVTYPE_HAL;'
             print r'        break;'
             print r'    case retrace::DRIVER_SOFTWARE:'
+            print r'        BehaviorFlags &= ~D3DCREATE_PUREDEVICE;'
+            print r'        BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;'
+            print r'        BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;'
+            print r'        break;'
             print r'    case retrace::DRIVER_REFERENCE:'
             print r'        DeviceType = D3DDEVTYPE_REF;'
             print r'        break;'

commit bac0ea039e15c219d243f2ffea40fe9b6181ce32
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Fri Jun 9 15:23:37 2017 +0100

    Revert "memtrace: Align blocks to 64 bytes."
    
    This reverts commit f1977beca436a1f8902052bee8ec81d3eccb22fb.
    
    It's incorrect to align to anything other than BLOCK_SIZE, otherwise we
    can start touching the following page, which might not exist.

diff --git a/wrappers/memtrace.cpp b/wrappers/memtrace.cpp
index feb2019..fc89a8d 100644
--- a/wrappers/memtrace.cpp
+++ b/wrappers/memtrace.cpp
@@ -60,7 +60,6 @@
 #endif
 
 
-#define BLOCK_ALIGN 64
 #define BLOCK_SIZE 512
 
 
@@ -121,7 +120,7 @@ mm_crc32_u32(uint32_t crc, uint32_t current)
 uint32_t
 hashBlock(const void *p)
 {
-    assert(lAlignPtr(p, BLOCK_ALIGN) == p);
+    assert((intptr_t)p % BLOCK_SIZE == 0);
 
     uint32_t crc;
 
@@ -187,33 +186,29 @@ void MemoryShadow::cover(void *_ptr, size_t _size, bool _discard)
 {
     assert(_ptr);
 
-    const uint8_t *ptr = static_cast<const uint8_t *>(_ptr);
-    const uint8_t *basePtr = lAlignPtr(ptr, BLOCK_ALIGN);
-
     if (_size != size) {
-        static_assert(BLOCK_SIZE % BLOCK_ALIGN == 0, "inconsistent block align/size");
-        nBlocks = (ptr + _size - basePtr + BLOCK_SIZE - 1)/BLOCK_SIZE;
+        nBlocks = ((intptr_t)_ptr + _size + BLOCK_SIZE - 1)/BLOCK_SIZE - (intptr_t)_ptr/BLOCK_SIZE;
 
         hashPtr = (uint32_t *)realloc(hashPtr, nBlocks * sizeof *hashPtr);
         size = _size;
     }
 
-    realPtr = ptr;
+    realPtr = (const uint8_t *)_ptr;
 
     if (_discard) {
         zero(_ptr, size);
     }
 
-    const uint8_t *blockPtr = basePtr;
+    const uint8_t *p = lAlignPtr((const uint8_t *)_ptr, BLOCK_SIZE);
     if (_discard) {
-        hashPtr[0] = hashBlock(blockPtr);
+        hashPtr[0] = hashBlock(p);
         for (size_t i = 1; i < nBlocks; ++i) {
             hashPtr[i] = hashPtr[0];
         }
     } else {
         for (size_t i = 0; i < nBlocks; ++i) {
-            hashPtr[i] = hashBlock(blockPtr);
-            blockPtr += BLOCK_SIZE;
+            hashPtr[i] = hashBlock(p);
+            p += BLOCK_SIZE;
         }
     }
 }
@@ -224,14 +219,14 @@ void MemoryShadow::update(Callback callback) const
     const uint8_t *realStart   = realPtr   + size;
     const uint8_t *realStop    = realPtr;
 
-    const uint8_t *blockPtr = lAlignPtr(realPtr, BLOCK_ALIGN);
+    const uint8_t *p = lAlignPtr(realPtr, BLOCK_SIZE);
     for (size_t i = 0; i < nBlocks; ++i) {
-        uint32_t crc = hashBlock(blockPtr);
+        uint32_t crc = hashBlock(p);
         if (crc != hashPtr[i]) {
-            realStart = std::min(realStart, blockPtr);
-            realStop  = std::max(realStop,  blockPtr + BLOCK_SIZE);
+            realStart = std::min(realStart, p);
+            realStop  = std::max(realStop,  p + BLOCK_SIZE);
         }
-        blockPtr += BLOCK_SIZE;
+        p += BLOCK_SIZE;
     }
 
     realStart = std::max(realStart, realPtr);

commit 19acdbb158cd8516f615f0945a120cdbca3455d3
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Fri Jun 9 14:26:58 2017 +0100

    highlight: Use ANSI escape codes on Windows 10.

diff --git a/lib/highlight/highlight.cpp b/lib/highlight/highlight.cpp
index f3555f3..c5a8925 100644
--- a/lib/highlight/highlight.cpp
+++ b/lib/highlight/highlight.cpp
@@ -30,6 +30,8 @@
 
 #ifdef _WIN32
 
+#define DEFINE_CONSOLEV2_PROPERTIES
+
 #include <windows.h>
 #include <io.h> // _isatty
 #include <stdio.h> // _fileno
@@ -62,6 +64,10 @@
 #define COMMON_LVB_UNDERSCORE      0x8000
 #endif
 
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
 #else /* !_WIN32 */
 
 #include <unistd.h> // isatty
@@ -97,6 +103,8 @@ public:
 static const PlainHighlighter plainHighlighter;
 
 
+#define CSI "\33["
+
 class AnsiAttribute : public Attribute {
 protected:
     const char *escape;
@@ -107,18 +115,27 @@ public:
     {}
 
     void apply(std::ostream& os) const override {
-        os << "\33[" << escape;
+        os << escape;
     }
 };
 
-static const AnsiAttribute ansiNormal("0m");
-static const AnsiAttribute ansiBold("1m");
-static const AnsiAttribute ansiItalic("3m");
-static const AnsiAttribute ansiStrike("9m");
-static const AnsiAttribute ansiRed("31m");
-static const AnsiAttribute ansiGreen("32m");
-static const AnsiAttribute ansiBlue("34m");
-static const AnsiAttribute ansiGray("37m");
+static const AnsiAttribute ansiNormal(CSI "0m");
+static const AnsiAttribute ansiBold  (CSI "1m");
+static const AnsiAttribute ansiItalic(CSI "3m");
+static const AnsiAttribute ansiStrike(CSI "9m");
+#ifdef _WIN32
+// Brighter colors on Windows to contrast with the background, and match the
+// colors from SetConsoleTextAttribute
+static const AnsiAttribute ansiRed   (CSI "91m");
+static const AnsiAttribute ansiGreen (CSI "92m");
+static const AnsiAttribute ansiBlue  (CSI "94m");
+static const AnsiAttribute ansiGray  (CSI "37m");
+#else
+static const AnsiAttribute ansiRed   (CSI "31m");
+static const AnsiAttribute ansiGreen (CSI "32m");
+static const AnsiAttribute ansiBlue  (CSI "34m");
+static const AnsiAttribute ansiGray  (CSI "37m");
+#endif
 
 
 /**
@@ -230,16 +247,13 @@ haveAnsi(void)
     static bool result = false;
 
     if (!checked) {
-        // https://conemu.github.io/en/ConEmuEnvironment.html
-        // XXX: Didn't quite work for me
-        if (0) {
-            const char *conEmuANSI = getenv("ConEmuANSI");
-            if (conEmuANSI &&
-                strcmp(conEmuANSI, "ON") == 0) {
-                result = true;
-                checked = true;
-                return result;
-            }
+        checked = true;
+
+        // http://wiki.winehq.org/DeveloperFaq#detect-wine
+        HMODULE hNtDll = GetModuleHandleA("ntdll");
+        if (hNtDll &&
+            GetProcAddress(hNtDll, "wine_get_version") != nullptr) {
+            return result = true;
         }
 
         // Cygwin shell
@@ -247,19 +261,30 @@ haveAnsi(void)
             const char *term = getenv("TERM");
             if (term &&
                 strcmp(term, "xterm") == 0) {
-                result = true;
-                checked = true;
-                return result;
+                return result = true;
             }
         }
 
-        // http://wiki.winehq.org/DeveloperFaq#detect-wine
-        HMODULE hNtDll = GetModuleHandleA("ntdll");
-        if (hNtDll) {
-            result = GetProcAddress(hNtDll, "wine_get_version") != NULL;
+        // Set output mode to handle virtual terminal sequences
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032.aspx
+        // TODO: Use CONOUT$
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075.aspx
+        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+        if (hOut == INVALID_HANDLE_VALUE) {
+            return false;
         }
 
-        checked = true;
+        DWORD dwMode = 0;
+        if (!GetConsoleMode(hOut, &dwMode)) {
+            return false;
+        }
+
+        dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+        if (SetConsoleMode(hOut, dwMode)) {
+            return result = true;
+        } else {
+            return false;
+        }
     }
 
     return result;

commit 60e6514671d4bf23683933c697a85d8a40c6fed3
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Fri Jun 9 13:06:32 2017 +0100

    dxgiretrace: Replay query GetData methods.
    
    Prevents all spurious debug layer warnings about query being reused
    without data being read.

diff --git a/retrace/dxgiretrace.py b/retrace/dxgiretrace.py
index 77874cc..97d2b59 100755
--- a/retrace/dxgiretrace.py
+++ b/retrace/dxgiretrace.py
@@ -320,6 +320,15 @@ class D3DRetracer(Retracer):
             print r'        return;'
             print r'    }'
 
+        if method.name == 'GetData':
+            print r'    pData = _allocator.alloc(DataSize);'
+            print r'    do {'
+            self.doInvokeInterfaceMethod(interface, method)
+            print r'        GetDataFlags = 0; // Prevent infinite loop'
+            print r'    } while (_result == S_FALSE);'
+            self.checkResult(interface, method)
+            print r'    return;'
+
         Retracer.invokeInterfaceMethod(self, interface, method)
 
         if method.name in ('AcquireSync', 'ReleaseSync'):
diff --git a/specs/d3d10.py b/specs/d3d10.py
index 2161a5f..2d8f485 100644
--- a/specs/d3d10.py
+++ b/specs/d3d10.py
@@ -837,7 +837,7 @@ ID3D10SamplerState.methods += [
 ID3D10Asynchronous.methods += [
     StdMethod(Void, "Begin", []),
     StdMethod(Void, "End", []),
-    StdMethod(HRESULT, "GetData", [Out(D3D10_QUERY_DATA, "pData"), (UINT, "DataSize"), (D3D10_ASYNC_GETDATA_FLAG, "GetDataFlags")], sideeffects=False),
+    StdMethod(HRESULT, "GetData", [Out(D3D10_QUERY_DATA, "pData"), (UINT, "DataSize"), (D3D10_ASYNC_GETDATA_FLAG, "GetDataFlags")]),
     StdMethod(UINT, "GetDataSize", [], sideeffects=False),
 ]
 
diff --git a/specs/d3d11.py b/specs/d3d11.py
index 2fc2771..8596189 100644
--- a/specs/d3d11.py
+++ b/specs/d3d11.py
@@ -1278,7 +1278,7 @@ ID3D11DeviceContext.methods += [
     StdMethod(Void, "VSSetSamplers", [(UINT, "StartSlot"), (UINT, "NumSamplers"), (Array(Const(ObjPointer(ID3D11SamplerState)), "NumSamplers"), "ppSamplers")]),
     StdMethod(Void, "Begin", [(ObjPointer(ID3D11Asynchronous), "pAsync")]),
     StdMethod(Void, "End", [(ObjPointer(ID3D11Asynchronous), "pAsync")]),
-    StdMethod(HRESULT, "GetData", [(ObjPointer(ID3D11Asynchronous), "pAsync"), Out(D3D11_QUERY_DATA, "pData"), (UINT, "DataSize"), (D3D11_ASYNC_GETDATA_FLAG, "GetDataFlags")], sideeffects=False),
+    StdMethod(HRESULT, "GetData", [(ObjPointer(ID3D11Asynchronous), "pAsync"), Out(D3D11_QUERY_DATA, "pData"), (UINT, "DataSize"), (D3D11_ASYNC_GETDATA_FLAG, "GetDataFlags")]),
     StdMethod(Void, "SetPredication", [(ObjPointer(ID3D11Predicate), "pPredicate"), (BOOL, "PredicateValue")]),
     StdMethod(Void, "GSSetShaderResources", [(UINT, "StartSlot"), (UINT, "NumViews"), (Array(Const(ObjPointer(ID3D11ShaderResourceView)), "NumViews"), "ppShaderResourceViews")]),
     StdMethod(Void, "GSSetSamplers", [(UINT, "StartSlot"), (UINT, "NumSamplers"), (Array(Const(ObjPointer(ID3D11SamplerState)), "NumSamplers"), "ppSamplers")]),

commit 2264546d148be8f7c46790a2f91b83ab8c7ff663
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Sat Jun 3 21:59:09 2017 +0100

    Refer lack of Android support to issue #521.
    
    Instead of mailing list.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f5e51e..4827926 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,7 +44,7 @@ option (ENABLE_ASAN "Enable Address Sanitizer" OFF)
 option (ENABLE_TESTS "Enable additional tests" OFF)
 
 if (ANDROID)
-    message (FATAL_ERROR "Android is no longer supported (https://goo.gl/yQEXFd)")
+    message (FATAL_ERROR "Android is no longer supported (https://git.io/vH2gW)")
 endif ()
 
 # Proprietary Linux games often ship their own libraries (zlib, libstdc++,
diff --git a/docs/INSTALL.markdown b/docs/INSTALL.markdown
index 013877f..64ae639 100644
--- a/docs/INSTALL.markdown
+++ b/docs/INSTALL.markdown
@@ -82,9 +82,7 @@ Build as:
 
 # Android #
 
-Android is no longer supported.  See https://goo.gl/yQEXFd for the reason why.
-If you need Android support, your best bet is to try an old release (search for
-android branch upstream.)
+Android is no longer supported.  See https://git.io/vH2gW for more information.
 
 
 # Windows #

commit 63194b2573176ef34efce1a5c8b08e624b8dddf5
Author: George Kyriazis <george.kyriazis@intel.com>
Date:   Thu Jun 1 16:23:16 2017 +0100

    dispatch: dlopen libGL.so with RTLD_DEEPBIND.
    
    According to the dlopen() docs, a deep bind will resolve unresolved
    symbols inside the dlopen()-ed library, within the library itself first.
    This way the symbols in the Mesa's GLX_functions array will get resolved
    inside Mesa, and not with apitrace symbols.

diff --git a/dispatch/glproc_egl.cpp b/dispatch/glproc_egl.cpp
index 07714ae..bc6156e 100644
--- a/dispatch/glproc_egl.cpp
+++ b/dispatch/glproc_egl.cpp
@@ -89,7 +89,7 @@ _getPublicProcAddress(const char *procName)
     if (procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') {
         static void *libEGL = NULL;
         if (!libEGL) {
-            libEGL = _dlopen("libEGL.so", RTLD_LOCAL | RTLD_LAZY);
+            libEGL = _dlopen("libEGL.so", RTLD_LOCAL | RTLD_LAZY | RTLD_DEEPBIND);
             if (!libEGL) {
                 return NULL;
             }
@@ -132,7 +132,7 @@ _getPublicProcAddress(const char *procName)
 
         static void *libGLESv2 = NULL;
         if (!libGLESv2) {
-            libGLESv2 = _dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY);
+            libGLESv2 = _dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY | RTLD_DEEPBIND);
         }
         if (libGLESv2) {
             proc = dlsym(libGLESv2, procName);
@@ -143,7 +143,7 @@ _getPublicProcAddress(const char *procName)
 
         static void *libGLESv1 = NULL;
         if (!libGLESv1) {
-            libGLESv1 = _dlopen("libGLESv1_CM.so", RTLD_LOCAL | RTLD_LAZY);
+            libGLESv1 = _dlopen("libGLESv1_CM.so", RTLD_LOCAL | RTLD_LAZY | RTLD_DEEPBIND);
         }
         if (libGLESv1) {
             proc = dlsym(libGLESv1, procName);
diff --git a/dispatch/glproc_gl.cpp b/dispatch/glproc_gl.cpp
index 3d963fb..5d7903a 100644
--- a/dispatch/glproc_gl.cpp
+++ b/dispatch/glproc_gl.cpp
@@ -200,7 +200,7 @@ void * _libgl_sym(const char *symbol)
          * exposes symbols to it.
          */
 
-        _libGlHandle = _dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY);
+        _libGlHandle = _dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND);
         if (!_libGlHandle) {
             os::log("apitrace: error: couldn't find libGL.so\n");
             return NULL;

commit cbb48c56b67a3a1948d7ec8b958c8d13c2c85b57
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Thu Jun 1 14:37:12 2017 +0100

    cmake: Allow to build additional tests simultanously.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e479cb..3f5e51e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,8 @@ option (ENABLE_FRAME_POINTER "Disable frame pointer omission" ON)
 
 option (ENABLE_ASAN "Enable Address Sanitizer" OFF)
 
+option (ENABLE_TESTS "Enable additional tests" OFF)
+
 if (ANDROID)
     message (FATAL_ERROR "Android is no longer supported (https://goo.gl/yQEXFd)")
 endif ()
@@ -549,7 +551,21 @@ endif ()
 # GUI
 
 if (ENABLE_GUI AND Qt5Widgets_FOUND AND Qt5Network_FOUND)
-  add_subdirectory(gui)
+  add_subdirectory (gui)
+endif ()
+
+
+##############################################################################
+# Additional tests
+
+if (ENABLE_TESTS)
+    if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
+        message (EMIT_ERROR
+                 "tests/CMakeLists.txt is missing, please do\n"
+                 "  git clone https://github.com/apitrace/apitrace-tests tests")
+    else ()
+        add_subdirectory (tests)
+    endif ()
 endif ()
 
 

commit b423de11db06def038650410950fc3969eae467c
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Thu Jun 1 14:36:14 2017 +0100

    d3dretrace: Handle overlapping IDirect3DCubeTexture9 locks on different faces.

diff --git a/retrace/d3d9retrace.py b/retrace/d3d9retrace.py
index 8d0f315..93a3ec4 100644
--- a/retrace/d3d9retrace.py
+++ b/retrace/d3d9retrace.py
@@ -233,13 +233,17 @@ class D3DRetracer(Retracer):
             print r'    d3dretrace::processEvents();'
 
         def mapping_subkey():
-            if 'Level' in method.argNames():
+            # A single texture object might have multiple mappings.  This key
+            # allows to tell them apart.
+            if 'FaceType' in method.argNames():
+                return ('static_cast<UINT>(FaceType) + Level*6',)
+            elif 'Level' in method.argNames():
                 return ('Level',)
             else:
                 return ('0',)
 
         if method.name in ('Lock', 'LockRect', 'LockBox'):
-            print '    VOID *_pbData = NULL;'
+            print '    VOID *_pbData = nullptr;'
             print '    size_t _MappedSize = 0;'
             if method.name == 'Lock':
                 # Ignore D3DLOCK_READONLY for buffers.
@@ -257,12 +261,12 @@ class D3DRetracer(Retracer):
             print '    }'
         
         if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'):
-            print '    VOID *_pbData = 0;'
+            print '    VOID *_pbData = nullptr;'
             print '    MappingKey _mappingKey(_this, %s);' % mapping_subkey()
             print '    _pbData = _maps[_mappingKey];'
             print '    if (_pbData) {'
             print '        retrace::delRegionByPointer(_pbData);'
-            print '        _maps[_mappingKey] = 0;'
+            print '        _maps[_mappingKey] = nullptr;'
             print '    }'
 
         if interface.name == 'IDirectXVideoDecoder':
@@ -275,7 +279,7 @@ class D3DRetracer(Retracer):
                 print '    void *_pBuffer = _maps[_mappingKey];'
                 print '    if (_pBuffer) {'
                 print '        retrace::delRegionByPointer(_pBuffer);'
-                print '        _maps[_mappingKey] = 0;'
+                print '        _maps[_mappingKey] = nullptr;'
                 print '    }'
 
     def handleFailure(self, interface, methodOrFunction):

commit a0cd097d4fc82c5faccf16bad24288ef15028c54
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Thu Jun 1 13:29:35 2017 +0100

    d3d9trace: Handle overlapping IDirect3DCubeTexture9 locks on different faces.

diff --git a/wrappers/d3d9trace.py b/wrappers/d3d9trace.py
index 5b966cb..92da8c0 100644
--- a/wrappers/d3d9trace.py
+++ b/wrappers/d3d9trace.py
@@ -78,7 +78,11 @@ class D3D9Tracer(DllTracer):
         if method.name in ('Unlock', 'UnlockRect', 'UnlockBox'):
             if interface.base.name == 'IDirect3DBaseTexture9':
                 assert method.getArgByName('Level') is not None
-                print '    std::map<UINT, std::pair<size_t, VOID *> >::iterator it = _MappedData.find(Level);'
+                if method.getArgByName('FaceType'):
+                    print r'   UINT _Key = static_cast<UINT>(FaceType) + Level*6;'
+                else:
+                    print r'   UINT _Key = Level;'
+                print '    std::map<UINT, std::pair<size_t, VOID *> >::iterator it = _MappedData.find(_Key);'
                 print '    if (it != _MappedData.end()) {'
                 self.emit_memcpy('(LPBYTE)it->second.second', 'it->second.first')
                 print '        _MappedData.erase(it);'
@@ -101,13 +105,17 @@ class D3D9Tracer(DllTracer):
         if method.name in ('Lock', 'LockRect', 'LockBox'):
             if interface.base.name == 'IDirect3DBaseTexture9':
                 assert method.getArgByName('Level') is not None
+                if method.getArgByName('FaceType'):
+                    print r'   UINT _Key = static_cast<UINT>(FaceType) + Level*6;'
+                else:
+                    print r'   UINT _Key = Level;'
                 print '    if (SUCCEEDED(_result) && !(Flags & D3DLOCK_READONLY)) {'
                 print '        size_t mappedSize;'
                 print '        VOID * pbData;'
                 print '        _getMapInfo(_this, %s, pbData, mappedSize);' % ', '.join(method.argNames()[:-1])
-                print '        _MappedData[Level] = std::make_pair(mappedSize, pbData);'
+                print '        _MappedData[_Key] = std::make_pair(mappedSize, pbData);'
                 print '    } else {'
-                print '        _MappedData.erase(Level);'
+                print '        _MappedData.erase(_Key);'
                 print '    }'
             else:
                 # FIXME: handle recursive locks

commit d0094a2813fde0df4dfe36bd551c060694a0cb13
Author: Jose Fonseca <jfonseca@vmware.com>
Date:   Tue May 30 12:31:37 2017 +0100

    d3dretrace: Abort on D3DERR_DEVICELOST.
    
    Like we already did for DXGI_ERROR_DEVICE_REMOVED.
    
    To do this, separate checking result, from handling failure.



Reply to: