+/*
+ * The SVGA_TRY_XX family of macros can be used to optionally replace a
+ * function call with an error value, the purpose is to trigger and test
+ * retry path handling.
+ */
+#ifdef DEBUG
+
+/*
+ * Optionally replace a function call with a PIPE_ERROR_OUT_OF_MEMORY
+ * return value
+ */
+#define SVGA_TRY(_func) \
+ ((SVGA_DEBUG & DEBUG_RETRY) ? PIPE_ERROR_OUT_OF_MEMORY : (_func))
+
+/* Optionally replace a function call with a NULL return value */
+#define SVGA_TRY_PTR(_func) \
+ ((SVGA_DEBUG & DEBUG_RETRY) ? NULL : (_func))
+
+/*
+ * Optionally replace a function call with a NULL return value, and set
+ * the _retry parameter to TRUE.
+ */
+#define SVGA_TRY_MAP(_func, _retry) \
+ ((SVGA_DEBUG & DEBUG_RETRY) ? (_retry) = TRUE, NULL : (_func))
+#else
+
+#define SVGA_TRY(_func) (_func)
+
+#define SVGA_TRY_PTR(_func) (_func)
+
+#define SVGA_TRY_MAP(_func, _retry) (_func)
+#endif
+
+/**
+ * Enter retry processing after hitting out-of-command space
+ */
+static inline void
+svga_retry_enter(struct svga_context *svga)
+{
+ /* We shouldn't nest retries, but currently we do. */
+ if ((SVGA_DEBUG & DEBUG_RETRY) && svga->swc->in_retry) {
+ debug_printf("WARNING: Recursive retry. Level: %u.\n",
+ svga->swc->in_retry);
+ }
+ svga->swc->in_retry++;
+}
+
+/**
+ * Exit retry processing after hitting out-of-command space
+ */
+static inline void
+svga_retry_exit(struct svga_context *svga)
+{
+ assert(svga->swc->in_retry > 0);
+ svga->swc->in_retry--;
+}
+
+/**
+ * Perform a function call, and on failure flush the context and retry,
+ * asserting that the retry succeeded. On return, the boolean argument
+ * _retried indicates whether the function call was retried or not.
+ */
+#define SVGA_RETRY_CHECK(_svga, _func, _retried) \
+ do { \
+ enum pipe_error ret; \
+ \
+ ret = SVGA_TRY(_func); \
+ (_retried) = (ret != PIPE_OK); \
+ if (_retried) { \
+ svga_retry_enter(_svga); \
+ svga_context_flush(_svga, NULL); \
+ ret = (_func); \
+ assert(ret == PIPE_OK); \
+ svga_retry_exit(_svga); \
+ } \
+ } while(0)
+
+/**
+ * Perform a function call, and on failure flush the context and retry,
+ * asserting that the retry succeeded.
+ */
+#define SVGA_RETRY(_svga, _func) \
+ do { \
+ UNUSED boolean retried; \
+ \
+ SVGA_RETRY_CHECK(_svga, _func, retried); \
+ } while(0)
+
+/**
+ * Perform a function call, and on out-of-memory, flush the context and
+ * retry. The retry return value is stored in _ret for reuse.
+ */
+#define SVGA_RETRY_OOM(_svga, _ret, _func) \
+ do { \
+ (_ret) = SVGA_TRY(_func); \
+ if ((_ret) == PIPE_ERROR_OUT_OF_MEMORY) { \
+ svga_retry_enter(_svga); \
+ svga_context_flush(_svga, NULL); \
+ (_ret) = (_func); \
+ svga_retry_exit(_svga); \
+ } \
+ } while (0);