summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiarhei Siamashka <siarhei.siamashka@gmail.com>2013-12-09 03:44:36 +0400
committerSiarhei Siamashka <siarhei.siamashka@gmail.com>2013-12-09 04:10:07 +0400
commiteed17d5586c3b4dfcf0b5976e8b947b171d4897c (patch)
treeeb34031d10010c14e06f28f758280b0c00c8a6b0
parent9808a58d33192032d63ddc0cc730c2e14272481c (diff)
downloadxf86-video-fbturbo-eed17d5586c3b4dfcf0b5976e8b947b171d4897c.tar.xz
mali: detect and workaround mismatch between back and front buffers
After window creation or resize, the mali blob on the client side requests two dri2 buffers (for back and front) from the ddx. The problem is that the 'swap' and 'get_buffer' operations are executed out of order relative to each other and we may have different possible patterns of dri2 communication: 1. swap swap swap swap get_buffer swap get_buffer swap swap ... 2. swap swap swap get_buffer swap swap get_buffer swap swap ... A major annoyance is that both mali blob on the client side and the ddx driver in xserver need have the same idea about which one of there two buffers goes to front and which goes to back. Older commit https://github.com/ssvb/xf86-video-fbturbo/commit/30b4ca27d1c4 tried to address this problem in a mostly empirical way and managed to solve it at least for the synthetic test gles-rgb-cycle-demo and for most of the real programs (such as Qt5 applications, etc.) However appears that this heuristics is not 100% reliable in all cases. The Extreme Tux Racer game run in glshim manages to trigger the back and front buffers mismatch. Which manifests itself as erratic penguin movement. This patch adds a special check, which now randomly samples certain bytes from the dri2 buffers to see which one of them has been modified by the client application between buffer swaps. If we see that the rendering actually happens to the front buffer instead of the back buffer, then we just change the roles of these buffers. Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
-rw-r--r--src/sunxi_mali_ump_dri2.c140
-rw-r--r--src/sunxi_mali_ump_dri2.h9
2 files changed, 149 insertions, 0 deletions
diff --git a/src/sunxi_mali_ump_dri2.c b/src/sunxi_mali_ump_dri2.c
index 37e754e..fa621dd 100644
--- a/src/sunxi_mali_ump_dri2.c
+++ b/src/sunxi_mali_ump_dri2.c
@@ -48,6 +48,89 @@
#include "sunxi_disp_ioctl.h"
#include "sunxi_mali_ump_dri2.h"
+static const uint32_t crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+ 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+ 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+ 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+ 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+ 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+ 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+ 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+ 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+ 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+ 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+ 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+ 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+ 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+ 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+ 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+ 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+ 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+static inline uint32_t
+crc32_byte(uint32_t crc32, uint8_t data)
+{
+ crc32 ^= 0xFFFFFFFF;
+ crc32 = (crc32 >> 8) ^ crc32_table[(crc32 ^ data) & 0xFF];
+ return crc32 ^ 0xFFFFFFFF;
+}
+
+static uint32_t calc_ump_checksum(UMPBufferInfoPtr umpbuf, uint32_t seed)
+{
+ int i;
+ uint8_t *buf = umpbuf->addr + umpbuf->offs;
+ uint32_t result = 0;
+ uint32_t hi, lo;
+ for (i = 0; i < RANDOM_SAMPLES_COUNT; i++) {
+ /* LCG pseudorandom number generation */
+ seed = seed * 1103515245 + 12345;
+ hi = seed & 0xFFFF0000;
+ seed = seed * 1103515245 + 12345;
+ lo = seed >> 16;
+ result = crc32_byte(result, buf[(hi | lo) % umpbuf->size]);
+ }
+ return result;
+}
+
+static void save_ump_checksum(UMPBufferInfoPtr umpbuf, uint32_t seed)
+{
+ umpbuf->has_checksum = TRUE;
+ umpbuf->checksum_seed = seed;
+ umpbuf->checksum = calc_ump_checksum(umpbuf, seed);
+}
+
+static Bool test_ump_checksum(UMPBufferInfoPtr umpbuf)
+{
+ return calc_ump_checksum(umpbuf, umpbuf->checksum_seed) == umpbuf->checksum;
+}
+
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#endif
@@ -638,6 +721,45 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw,
umpbuf = umpbuf_fetch_from_queue(window_state);
/*
+ * In the case if the queue of incoming buffers is already empty and
+ * we are just swapping two allocated DRI2 buffers, we can do an extra
+ * sanity check. The normal behaviour is that the back buffer may change,
+ * and the front buffer may not. But if this is not the case, we need to
+ * take some corrective actions here.
+ */
+ if (!umpbuf && window_state->ump_front_buffer_ptr &&
+ window_state->ump_front_buffer_ptr->addr &&
+ window_state->ump_back_buffer_ptr &&
+ window_state->ump_back_buffer_ptr->addr &&
+ window_state->ump_front_buffer_ptr != window_state->ump_back_buffer_ptr) {
+
+ UMPBufferInfoPtr ump_front = window_state->ump_front_buffer_ptr;
+ UMPBufferInfoPtr ump_back = window_state->ump_back_buffer_ptr;
+
+ Bool front_modified = ump_front->has_checksum && !test_ump_checksum(ump_front);
+ Bool back_modified = ump_back->has_checksum && !test_ump_checksum(ump_back);
+
+ ump_front->has_checksum = FALSE;
+ ump_back->has_checksum = FALSE;
+
+ if (back_modified && !front_modified) {
+ /* That's normal, we have successfully passed this check */
+ ump_back->extra_flags |= UMPBUF_PASSED_ORDER_CHECK;
+ ump_front->extra_flags |= UMPBUF_PASSED_ORDER_CHECK;
+ }
+ else if (front_modified) {
+ /* That's bad, the order of buffers is messed up, but we can exchange them */
+ UMPBufferInfoPtr tmp = window_state->ump_back_buffer_ptr;
+ window_state->ump_back_buffer_ptr = window_state->ump_front_buffer_ptr;
+ window_state->ump_front_buffer_ptr = tmp;
+ DebugMsg("Unexpected modification of the front buffer detected.\n");
+ }
+ else {
+ /* Not enough information to make a decision yet */
+ }
+ }
+
+ /*
* Swap back and front buffers. But also ensure that the buffer
* flags UMPBUF_MUST_BE_ODD_FRAME and UMPBUF_MUST_BE_EVEN_FRAME
* are respected. In the case if swapping the buffers would result
@@ -675,6 +797,24 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw,
check_rgb_pattern(window_state, umpbuf);
#endif
+ /*
+ * Here we can calculate checksums over randomly sampled bytes from UMP
+ * buffers in order to check later whether they had been modified. This
+ * is skipped if the buffers have UMPBUF_PASSED_ORDER_CHECK flag set.
+ */
+ if (window_state->ump_front_buffer_ptr && window_state->ump_front_buffer_ptr->addr &&
+ window_state->ump_back_buffer_ptr && window_state->ump_back_buffer_ptr->addr &&
+ window_state->ump_front_buffer_ptr != window_state->ump_back_buffer_ptr) {
+
+ UMPBufferInfoPtr ump_front = window_state->ump_front_buffer_ptr;
+ UMPBufferInfoPtr ump_back = window_state->ump_back_buffer_ptr;
+
+ if (!(ump_front->extra_flags & UMPBUF_PASSED_ORDER_CHECK))
+ save_ump_checksum(ump_front, window_state->buf_swap_cnt);
+ if (!(ump_back->extra_flags & UMPBUF_PASSED_ORDER_CHECK))
+ save_ump_checksum(ump_back, window_state->buf_swap_cnt);
+ }
+
UpdateOverlay(pScreen);
if (!mali->bOverlayWinEnabled || umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
diff --git a/src/sunxi_mali_ump_dri2.h b/src/sunxi_mali_ump_dri2.h
index c8ee50b..fff2955 100644
--- a/src/sunxi_mali_ump_dri2.h
+++ b/src/sunxi_mali_ump_dri2.h
@@ -31,6 +31,10 @@
#define UMPBUF_MUST_BE_ODD_FRAME 1
#define UMPBUF_MUST_BE_EVEN_FRAME 2
+#define UMPBUF_PASSED_ORDER_CHECK 4
+
+/* The number of bytes randomly sampled from UMP buffer to detect its change */
+#define RANDOM_SAMPLES_COUNT 64
/* Data structure with the information about an UMP buffer */
typedef struct
@@ -54,6 +58,11 @@ typedef struct
unsigned int pitch;
unsigned int cpp;
unsigned int offs;
+
+ /* This allows us to track buffer modifications */
+ Bool has_checksum;
+ uint32_t checksum;
+ uint32_t checksum_seed;
} UMPBufferInfoRec, *UMPBufferInfoPtr;
/*