1848b8605Smrg/* 2848b8605Smrg * Copyright 2010 Christoph Bumiller 3848b8605Smrg * 4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5848b8605Smrg * copy of this software and associated documentation files (the "Software"), 6848b8605Smrg * to deal in the Software without restriction, including without limitation 7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 9848b8605Smrg * Software is furnished to do so, subject to the following conditions: 10848b8605Smrg * 11848b8605Smrg * The above copyright notice and this permission notice shall be included in 12848b8605Smrg * all copies or substantial portions of the Software. 13848b8605Smrg * 14848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 21848b8605Smrg */ 22848b8605Smrg 23848b8605Smrg#include "nouveau_screen.h" 24848b8605Smrg#include "nouveau_winsys.h" 25848b8605Smrg#include "nouveau_fence.h" 26b8e80941Smrg#include "util/os_time.h" 27848b8605Smrg 28848b8605Smrg#ifdef PIPE_OS_UNIX 29848b8605Smrg#include <sched.h> 30848b8605Smrg#endif 31848b8605Smrg 32b8e80941Smrgbool 33b8e80941Smrgnouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence) 34848b8605Smrg{ 35848b8605Smrg *fence = CALLOC_STRUCT(nouveau_fence); 36848b8605Smrg if (!*fence) 37b8e80941Smrg return false; 38848b8605Smrg 39848b8605Smrg (*fence)->screen = screen; 40848b8605Smrg (*fence)->ref = 1; 41848b8605Smrg LIST_INITHEAD(&(*fence)->work); 42848b8605Smrg 43b8e80941Smrg return true; 44848b8605Smrg} 45848b8605Smrg 46848b8605Smrgstatic void 47848b8605Smrgnouveau_fence_trigger_work(struct nouveau_fence *fence) 48848b8605Smrg{ 49848b8605Smrg struct nouveau_fence_work *work, *tmp; 50848b8605Smrg 51848b8605Smrg LIST_FOR_EACH_ENTRY_SAFE(work, tmp, &fence->work, list) { 52848b8605Smrg work->func(work->data); 53848b8605Smrg LIST_DEL(&work->list); 54848b8605Smrg FREE(work); 55848b8605Smrg } 56848b8605Smrg} 57848b8605Smrg 58848b8605Smrgvoid 59848b8605Smrgnouveau_fence_emit(struct nouveau_fence *fence) 60848b8605Smrg{ 61848b8605Smrg struct nouveau_screen *screen = fence->screen; 62848b8605Smrg 63848b8605Smrg assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE); 64848b8605Smrg 65848b8605Smrg /* set this now, so that if fence.emit triggers a flush we don't recurse */ 66848b8605Smrg fence->state = NOUVEAU_FENCE_STATE_EMITTING; 67848b8605Smrg 68848b8605Smrg ++fence->ref; 69848b8605Smrg 70848b8605Smrg if (screen->fence.tail) 71848b8605Smrg screen->fence.tail->next = fence; 72848b8605Smrg else 73848b8605Smrg screen->fence.head = fence; 74848b8605Smrg 75848b8605Smrg screen->fence.tail = fence; 76848b8605Smrg 77848b8605Smrg screen->fence.emit(&screen->base, &fence->sequence); 78848b8605Smrg 79848b8605Smrg assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING); 80848b8605Smrg fence->state = NOUVEAU_FENCE_STATE_EMITTED; 81848b8605Smrg} 82848b8605Smrg 83848b8605Smrgvoid 84848b8605Smrgnouveau_fence_del(struct nouveau_fence *fence) 85848b8605Smrg{ 86848b8605Smrg struct nouveau_fence *it; 87848b8605Smrg struct nouveau_screen *screen = fence->screen; 88848b8605Smrg 89848b8605Smrg if (fence->state == NOUVEAU_FENCE_STATE_EMITTED || 90848b8605Smrg fence->state == NOUVEAU_FENCE_STATE_FLUSHED) { 91848b8605Smrg if (fence == screen->fence.head) { 92848b8605Smrg screen->fence.head = fence->next; 93848b8605Smrg if (!screen->fence.head) 94848b8605Smrg screen->fence.tail = NULL; 95848b8605Smrg } else { 96848b8605Smrg for (it = screen->fence.head; it && it->next != fence; it = it->next); 97848b8605Smrg it->next = fence->next; 98848b8605Smrg if (screen->fence.tail == fence) 99848b8605Smrg screen->fence.tail = it; 100848b8605Smrg } 101848b8605Smrg } 102848b8605Smrg 103848b8605Smrg if (!LIST_IS_EMPTY(&fence->work)) { 104848b8605Smrg debug_printf("WARNING: deleting fence with work still pending !\n"); 105848b8605Smrg nouveau_fence_trigger_work(fence); 106848b8605Smrg } 107848b8605Smrg 108848b8605Smrg FREE(fence); 109848b8605Smrg} 110848b8605Smrg 111848b8605Smrgvoid 112b8e80941Smrgnouveau_fence_update(struct nouveau_screen *screen, bool flushed) 113848b8605Smrg{ 114848b8605Smrg struct nouveau_fence *fence; 115848b8605Smrg struct nouveau_fence *next = NULL; 116848b8605Smrg u32 sequence = screen->fence.update(&screen->base); 117848b8605Smrg 118848b8605Smrg if (screen->fence.sequence_ack == sequence) 119848b8605Smrg return; 120848b8605Smrg screen->fence.sequence_ack = sequence; 121848b8605Smrg 122848b8605Smrg for (fence = screen->fence.head; fence; fence = next) { 123848b8605Smrg next = fence->next; 124848b8605Smrg sequence = fence->sequence; 125848b8605Smrg 126848b8605Smrg fence->state = NOUVEAU_FENCE_STATE_SIGNALLED; 127848b8605Smrg 128848b8605Smrg nouveau_fence_trigger_work(fence); 129848b8605Smrg nouveau_fence_ref(NULL, &fence); 130848b8605Smrg 131848b8605Smrg if (sequence == screen->fence.sequence_ack) 132848b8605Smrg break; 133848b8605Smrg } 134848b8605Smrg screen->fence.head = next; 135848b8605Smrg if (!next) 136848b8605Smrg screen->fence.tail = NULL; 137848b8605Smrg 138848b8605Smrg if (flushed) { 139848b8605Smrg for (fence = next; fence; fence = fence->next) 140848b8605Smrg if (fence->state == NOUVEAU_FENCE_STATE_EMITTED) 141848b8605Smrg fence->state = NOUVEAU_FENCE_STATE_FLUSHED; 142848b8605Smrg } 143848b8605Smrg} 144848b8605Smrg 145848b8605Smrg#define NOUVEAU_FENCE_MAX_SPINS (1 << 31) 146848b8605Smrg 147b8e80941Smrgbool 148848b8605Smrgnouveau_fence_signalled(struct nouveau_fence *fence) 149848b8605Smrg{ 150848b8605Smrg struct nouveau_screen *screen = fence->screen; 151848b8605Smrg 152848b8605Smrg if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) 153b8e80941Smrg return true; 154848b8605Smrg 155848b8605Smrg if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED) 156b8e80941Smrg nouveau_fence_update(screen, false); 157848b8605Smrg 158848b8605Smrg return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED; 159848b8605Smrg} 160848b8605Smrg 161b8e80941Smrgstatic bool 162b8e80941Smrgnouveau_fence_kick(struct nouveau_fence *fence) 163848b8605Smrg{ 164848b8605Smrg struct nouveau_screen *screen = fence->screen; 165848b8605Smrg 166848b8605Smrg /* wtf, someone is waiting on a fence in flush_notify handler? */ 167848b8605Smrg assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING); 168848b8605Smrg 169b8e80941Smrg if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) { 170b8e80941Smrg PUSH_SPACE(screen->pushbuf, 8); 171b8e80941Smrg /* The space allocation might trigger a flush, which could emit the 172b8e80941Smrg * current fence. So check again. 173b8e80941Smrg */ 174b8e80941Smrg if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) 175b8e80941Smrg nouveau_fence_emit(fence); 176b8e80941Smrg } 177848b8605Smrg 178848b8605Smrg if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED) 179848b8605Smrg if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel)) 180b8e80941Smrg return false; 181848b8605Smrg 182848b8605Smrg if (fence == screen->fence.current) 183848b8605Smrg nouveau_fence_next(screen); 184848b8605Smrg 185b8e80941Smrg nouveau_fence_update(screen, false); 186b8e80941Smrg 187b8e80941Smrg return true; 188b8e80941Smrg} 189b8e80941Smrg 190b8e80941Smrgbool 191b8e80941Smrgnouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debug) 192b8e80941Smrg{ 193b8e80941Smrg struct nouveau_screen *screen = fence->screen; 194b8e80941Smrg uint32_t spins = 0; 195b8e80941Smrg int64_t start = 0; 196848b8605Smrg 197b8e80941Smrg if (debug && debug->debug_message) 198b8e80941Smrg start = os_time_get_nano(); 199b8e80941Smrg 200b8e80941Smrg if (!nouveau_fence_kick(fence)) 201b8e80941Smrg return false; 202b8e80941Smrg 203b8e80941Smrg do { 204b8e80941Smrg if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) { 205b8e80941Smrg if (debug && debug->debug_message) 206b8e80941Smrg pipe_debug_message(debug, PERF_INFO, 207b8e80941Smrg "stalled %.3f ms waiting for fence", 208b8e80941Smrg (os_time_get_nano() - start) / 1000000.f); 209b8e80941Smrg return true; 210b8e80941Smrg } 211848b8605Smrg if (!spins) 212848b8605Smrg NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1); 213848b8605Smrg spins++; 214848b8605Smrg#ifdef PIPE_OS_UNIX 215848b8605Smrg if (!(spins % 8)) /* donate a few cycles */ 216848b8605Smrg sched_yield(); 217848b8605Smrg#endif 218b8e80941Smrg 219b8e80941Smrg nouveau_fence_update(screen, false); 220848b8605Smrg } while (spins < NOUVEAU_FENCE_MAX_SPINS); 221848b8605Smrg 222848b8605Smrg debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n", 223848b8605Smrg fence->sequence, 224848b8605Smrg screen->fence.sequence_ack, screen->fence.sequence); 225848b8605Smrg 226b8e80941Smrg return false; 227848b8605Smrg} 228848b8605Smrg 229848b8605Smrgvoid 230848b8605Smrgnouveau_fence_next(struct nouveau_screen *screen) 231848b8605Smrg{ 232b8e80941Smrg if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING) { 233b8e80941Smrg if (screen->fence.current->ref > 1) 234b8e80941Smrg nouveau_fence_emit(screen->fence.current); 235b8e80941Smrg else 236b8e80941Smrg return; 237b8e80941Smrg } 238848b8605Smrg 239848b8605Smrg nouveau_fence_ref(NULL, &screen->fence.current); 240848b8605Smrg 241b8e80941Smrg nouveau_fence_new(screen, &screen->fence.current); 242b8e80941Smrg} 243b8e80941Smrg 244b8e80941Smrgvoid 245b8e80941Smrgnouveau_fence_unref_bo(void *data) 246b8e80941Smrg{ 247b8e80941Smrg struct nouveau_bo *bo = data; 248b8e80941Smrg 249b8e80941Smrg nouveau_bo_ref(NULL, &bo); 250b8e80941Smrg} 251b8e80941Smrg 252b8e80941Smrgbool 253b8e80941Smrgnouveau_fence_work(struct nouveau_fence *fence, 254b8e80941Smrg void (*func)(void *), void *data) 255b8e80941Smrg{ 256b8e80941Smrg struct nouveau_fence_work *work; 257b8e80941Smrg 258b8e80941Smrg if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) { 259b8e80941Smrg func(data); 260b8e80941Smrg return true; 261b8e80941Smrg } 262b8e80941Smrg 263b8e80941Smrg work = CALLOC_STRUCT(nouveau_fence_work); 264b8e80941Smrg if (!work) 265b8e80941Smrg return false; 266b8e80941Smrg work->func = func; 267b8e80941Smrg work->data = data; 268b8e80941Smrg LIST_ADD(&work->list, &fence->work); 269b8e80941Smrg p_atomic_inc(&fence->work_count); 270b8e80941Smrg if (fence->work_count > 64) 271b8e80941Smrg nouveau_fence_kick(fence); 272b8e80941Smrg return true; 273848b8605Smrg} 274