Commit eed17d55 authored by Siarhei Siamashka's avatar Siarhei Siamashka
Browse files

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: default avatarSiarhei Siamashka <siarhei.siamashka@gmail.com>
parent 9808a58d
...@@ -48,6 +48,89 @@ ...@@ -48,6 +48,89 @@
#include "sunxi_disp_ioctl.h" #include "sunxi_disp_ioctl.h"
#include "sunxi_mali_ump_dri2.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 #ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) #define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#endif #endif
...@@ -637,6 +720,45 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw, ...@@ -637,6 +720,45 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw,
/* Try to fetch a new UMP buffer from the queue */ /* Try to fetch a new UMP buffer from the queue */
umpbuf = umpbuf_fetch_from_queue(window_state); 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 * Swap back and front buffers. But also ensure that the buffer
* flags UMPBUF_MUST_BE_ODD_FRAME and UMPBUF_MUST_BE_EVEN_FRAME * flags UMPBUF_MUST_BE_ODD_FRAME and UMPBUF_MUST_BE_EVEN_FRAME
...@@ -675,6 +797,24 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw, ...@@ -675,6 +797,24 @@ static void MaliDRI2CopyRegion(DrawablePtr pDraw,
check_rgb_pattern(window_state, umpbuf); check_rgb_pattern(window_state, umpbuf);
#endif #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); UpdateOverlay(pScreen);
if (!mali->bOverlayWinEnabled || umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) { if (!mali->bOverlayWinEnabled || umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
......
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#define UMPBUF_MUST_BE_ODD_FRAME 1 #define UMPBUF_MUST_BE_ODD_FRAME 1
#define UMPBUF_MUST_BE_EVEN_FRAME 2 #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 */ /* Data structure with the information about an UMP buffer */
typedef struct typedef struct
...@@ -54,6 +58,11 @@ typedef struct ...@@ -54,6 +58,11 @@ typedef struct
unsigned int pitch; unsigned int pitch;
unsigned int cpp; unsigned int cpp;
unsigned int offs; unsigned int offs;
/* This allows us to track buffer modifications */
Bool has_checksum;
uint32_t checksum;
uint32_t checksum_seed;
} UMPBufferInfoRec, *UMPBufferInfoPtr; } UMPBufferInfoRec, *UMPBufferInfoPtr;
/* /*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment