- rsc->status |= status;
-
- /* TODO resources can actually be shared across contexts,
- * so I'm not sure a single list-head will do the trick? */
- debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx);
- list_delinit(&rsc->list);
- list_addtail(&rsc->list, &ctx->used_resources);
- rsc->pending_ctx = ctx;
+again:
+ mtx_lock(&rsc->lock);
+
+ set_foreach(rsc->pending_ctx, entry) {
+ struct etna_context *extctx = (struct etna_context *)entry->key;
+ struct pipe_context *pctx = &extctx->base;
+ bool need_flush = false;
+
+ if (mtx_trylock(&extctx->lock) != thrd_success) {
+ /*
+ * The other context could be locked in etna_flush() and
+ * stuck waiting for the resource lock, so release the
+ * resource lock here, let etna_flush() finish, and try
+ * again.
+ */
+ mtx_unlock(&rsc->lock);
+ thrd_yield();
+ goto again;
+ }
+
+ set_foreach(extctx->used_resources_read, entry2) {
+ struct etna_resource *rsc2 = (struct etna_resource *)entry2->key;
+ if (ctx == extctx || rsc2 != rsc)
+ continue;
+
+ if (status & ETNA_PENDING_WRITE) {
+ need_flush = true;
+ break;
+ }
+ }
+
+ if (need_flush) {
+ pctx->flush(pctx, NULL, 0);
+ mtx_unlock(&extctx->lock);
+ continue;
+ }
+
+ set_foreach(extctx->used_resources_write, entry2) {
+ struct etna_resource *rsc2 = (struct etna_resource *)entry2->key;
+ if (ctx == extctx || rsc2 != rsc)
+ continue;
+
+ need_flush = true;
+ break;
+ }
+
+ if (need_flush)
+ pctx->flush(pctx, NULL, 0);
+
+ mtx_unlock(&extctx->lock);
+ }
+
+ rsc->status = status;
+
+ if (!_mesa_set_search(rsc->pending_ctx, ctx)) {
+ pipe_resource_reference(&referenced, prsc);
+ _mesa_set_add((status & ETNA_PENDING_READ) ?
+ ctx->used_resources_read : ctx->used_resources_write, rsc);
+ _mesa_set_add(rsc->pending_ctx, ctx);
+ }
+
+ mtx_unlock(&rsc->lock);
+ mtx_unlock(&ctx->lock);
+}
+
+bool
+etna_resource_has_valid_ts(struct etna_resource *rsc)
+{
+ if (!rsc->ts_bo)
+ return false;
+
+ for (int level = 0; level <= rsc->base.last_level; level++)
+ if (rsc->levels[level].ts_valid)
+ return true;
+
+ return false;