Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2010 Christoph Bumiller
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20.  * OTHER DEALINGS IN THE SOFTWARE.
  21.  */
  22.  
  23. #include "nouveau_screen.h"
  24. #include "nouveau_winsys.h"
  25. #include "nouveau_fence.h"
  26.  
  27. #ifdef PIPE_OS_UNIX
  28. #include <sched.h>
  29. #endif
  30.  
  31. boolean
  32. nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence,
  33.                   boolean emit)
  34. {
  35.    *fence = CALLOC_STRUCT(nouveau_fence);
  36.    if (!*fence)
  37.       return FALSE;
  38.  
  39.    (*fence)->screen = screen;
  40.    (*fence)->ref = 1;
  41.    LIST_INITHEAD(&(*fence)->work);
  42.  
  43.    if (emit)
  44.       nouveau_fence_emit(*fence);
  45.  
  46.    return TRUE;
  47. }
  48.  
  49. static void
  50. nouveau_fence_trigger_work(struct nouveau_fence *fence)
  51. {
  52.    struct nouveau_fence_work *work, *tmp;
  53.  
  54.    LIST_FOR_EACH_ENTRY_SAFE(work, tmp, &fence->work, list) {
  55.       work->func(work->data);
  56.       LIST_DEL(&work->list);
  57.       FREE(work);
  58.    }
  59. }
  60.  
  61. boolean
  62. nouveau_fence_work(struct nouveau_fence *fence,
  63.                    void (*func)(void *), void *data)
  64. {
  65.    struct nouveau_fence_work *work;
  66.  
  67.    if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
  68.       func(data);
  69.       return TRUE;
  70.    }
  71.  
  72.    work = CALLOC_STRUCT(nouveau_fence_work);
  73.    if (!work)
  74.       return FALSE;
  75.    work->func = func;
  76.    work->data = data;
  77.    LIST_ADD(&work->list, &fence->work);
  78.    return TRUE;
  79. }
  80.  
  81. void
  82. nouveau_fence_emit(struct nouveau_fence *fence)
  83. {
  84.    struct nouveau_screen *screen = fence->screen;
  85.  
  86.    assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE);
  87.  
  88.    /* set this now, so that if fence.emit triggers a flush we don't recurse */
  89.    fence->state = NOUVEAU_FENCE_STATE_EMITTING;
  90.  
  91.    ++fence->ref;
  92.  
  93.    if (screen->fence.tail)
  94.       screen->fence.tail->next = fence;
  95.    else
  96.       screen->fence.head = fence;
  97.  
  98.    screen->fence.tail = fence;
  99.  
  100.    screen->fence.emit(&screen->base, &fence->sequence);
  101.  
  102.    assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
  103.    fence->state = NOUVEAU_FENCE_STATE_EMITTED;
  104. }
  105.  
  106. void
  107. nouveau_fence_del(struct nouveau_fence *fence)
  108. {
  109.    struct nouveau_fence *it;
  110.    struct nouveau_screen *screen = fence->screen;
  111.  
  112.    if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
  113.        fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
  114.       if (fence == screen->fence.head) {
  115.          screen->fence.head = fence->next;
  116.          if (!screen->fence.head)
  117.             screen->fence.tail = NULL;
  118.       } else {
  119.          for (it = screen->fence.head; it && it->next != fence; it = it->next);
  120.          it->next = fence->next;
  121.          if (screen->fence.tail == fence)
  122.             screen->fence.tail = it;
  123.       }
  124.    }
  125.  
  126.    if (!LIST_IS_EMPTY(&fence->work)) {
  127.       debug_printf("WARNING: deleting fence with work still pending !\n");
  128.       nouveau_fence_trigger_work(fence);
  129.    }
  130.  
  131.    FREE(fence);
  132. }
  133.  
  134. void
  135. nouveau_fence_update(struct nouveau_screen *screen, boolean flushed)
  136. {
  137.    struct nouveau_fence *fence;
  138.    struct nouveau_fence *next = NULL;
  139.    u32 sequence = screen->fence.update(&screen->base);
  140.  
  141.    if (screen->fence.sequence_ack == sequence)
  142.       return;
  143.    screen->fence.sequence_ack = sequence;
  144.  
  145.    for (fence = screen->fence.head; fence; fence = next) {
  146.       next = fence->next;
  147.       sequence = fence->sequence;
  148.  
  149.       fence->state = NOUVEAU_FENCE_STATE_SIGNALLED;
  150.  
  151.       nouveau_fence_trigger_work(fence);
  152.       nouveau_fence_ref(NULL, &fence);
  153.  
  154.       if (sequence == screen->fence.sequence_ack)
  155.          break;
  156.    }
  157.    screen->fence.head = next;
  158.    if (!next)
  159.       screen->fence.tail = NULL;
  160.  
  161.    if (flushed) {
  162.       for (fence = next; fence; fence = fence->next)
  163.          if (fence->state == NOUVEAU_FENCE_STATE_EMITTED)
  164.             fence->state = NOUVEAU_FENCE_STATE_FLUSHED;
  165.    }
  166. }
  167.  
  168. #define NOUVEAU_FENCE_MAX_SPINS (1 << 31)
  169.  
  170. boolean
  171. nouveau_fence_signalled(struct nouveau_fence *fence)
  172. {
  173.    struct nouveau_screen *screen = fence->screen;
  174.  
  175.    if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
  176.       return TRUE;
  177.  
  178.    if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED)
  179.       nouveau_fence_update(screen, FALSE);
  180.  
  181.    return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
  182. }
  183.  
  184. boolean
  185. nouveau_fence_wait(struct nouveau_fence *fence)
  186. {
  187.    struct nouveau_screen *screen = fence->screen;
  188.    uint32_t spins = 0;
  189.  
  190.    /* wtf, someone is waiting on a fence in flush_notify handler? */
  191.    assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
  192.  
  193.    if (fence->state < NOUVEAU_FENCE_STATE_EMITTED)
  194.       nouveau_fence_emit(fence);
  195.  
  196.    if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED)
  197.       if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
  198.          return FALSE;
  199.  
  200.    if (fence == screen->fence.current)
  201.       nouveau_fence_next(screen);
  202.  
  203.    do {
  204.       nouveau_fence_update(screen, FALSE);
  205.  
  206.       if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
  207.          return TRUE;
  208.       if (!spins)
  209.          NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1);
  210.       spins++;
  211. #ifdef PIPE_OS_UNIX
  212.       if (!(spins % 8)) /* donate a few cycles */
  213.          sched_yield();
  214. #endif
  215.    } while (spins < NOUVEAU_FENCE_MAX_SPINS);
  216.  
  217.    debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
  218.                 fence->sequence,
  219.                 screen->fence.sequence_ack, screen->fence.sequence);
  220.  
  221.    return FALSE;
  222. }
  223.  
  224. void
  225. nouveau_fence_next(struct nouveau_screen *screen)
  226. {
  227.    if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING)
  228.       nouveau_fence_emit(screen->fence.current);
  229.  
  230.    nouveau_fence_ref(NULL, &screen->fence.current);
  231.  
  232.    nouveau_fence_new(screen, &screen->fence.current, FALSE);
  233. }
  234.