Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 "util/u_double_list.h"
  24.  
  25. #include "nouveau_screen.h"
  26. #include "nouveau_winsys.h"
  27. #include "nouveau_fence.h"
  28.  
  29. #ifdef PIPE_OS_UNIX
  30. #include <sched.h>
  31. #endif
  32.  
  33. boolean
  34. nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence,
  35.                   boolean emit)
  36. {
  37.    *fence = CALLOC_STRUCT(nouveau_fence);
  38.    if (!*fence)
  39.       return FALSE;
  40.  
  41.    (*fence)->screen = screen;
  42.    (*fence)->ref = 1;
  43.    LIST_INITHEAD(&(*fence)->work);
  44.  
  45.    if (emit)
  46.       nouveau_fence_emit(*fence);
  47.  
  48.    return TRUE;
  49. }
  50.  
  51. static void
  52. nouveau_fence_trigger_work(struct nouveau_fence *fence)
  53. {
  54.    struct nouveau_fence_work *work, *tmp;
  55.  
  56.    LIST_FOR_EACH_ENTRY_SAFE(work, tmp, &fence->work, list) {
  57.       work->func(work->data);
  58.       LIST_DEL(&work->list);
  59.       FREE(work);
  60.    }
  61. }
  62.  
  63. boolean
  64. nouveau_fence_work(struct nouveau_fence *fence,
  65.                    void (*func)(void *), void *data)
  66. {
  67.    struct nouveau_fence_work *work;
  68.  
  69.    if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
  70.       func(data);
  71.       return TRUE;
  72.    }
  73.  
  74.    work = CALLOC_STRUCT(nouveau_fence_work);
  75.    if (!work)
  76.       return FALSE;
  77.    work->func = func;
  78.    work->data = data;
  79.    LIST_ADD(&work->list, &fence->work);
  80.    return TRUE;
  81. }
  82.  
  83. void
  84. nouveau_fence_emit(struct nouveau_fence *fence)
  85. {
  86.    struct nouveau_screen *screen = fence->screen;
  87.  
  88.    assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE);
  89.  
  90.    /* set this now, so that if fence.emit triggers a flush we don't recurse */
  91.    fence->state = NOUVEAU_FENCE_STATE_EMITTING;
  92.  
  93.    ++fence->ref;
  94.  
  95.    if (screen->fence.tail)
  96.       screen->fence.tail->next = fence;
  97.    else
  98.       screen->fence.head = fence;
  99.  
  100.    screen->fence.tail = fence;
  101.  
  102.    screen->fence.emit(&screen->base, &fence->sequence);
  103.  
  104.    assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
  105.    fence->state = NOUVEAU_FENCE_STATE_EMITTED;
  106. }
  107.  
  108. void
  109. nouveau_fence_del(struct nouveau_fence *fence)
  110. {
  111.    struct nouveau_fence *it;
  112.    struct nouveau_screen *screen = fence->screen;
  113.  
  114.    if (fence->state == NOUVEAU_FENCE_STATE_EMITTED ||
  115.        fence->state == NOUVEAU_FENCE_STATE_FLUSHED) {
  116.       if (fence == screen->fence.head) {
  117.          screen->fence.head = fence->next;
  118.          if (!screen->fence.head)
  119.             screen->fence.tail = NULL;
  120.       } else {
  121.          for (it = screen->fence.head; it && it->next != fence; it = it->next);
  122.          it->next = fence->next;
  123.          if (screen->fence.tail == fence)
  124.             screen->fence.tail = it;
  125.       }
  126.    }
  127.  
  128.    if (!LIST_IS_EMPTY(&fence->work)) {
  129.       debug_printf("WARNING: deleting fence with work still pending !\n");
  130.       nouveau_fence_trigger_work(fence);
  131.    }
  132.  
  133.    FREE(fence);
  134. }
  135.  
  136. void
  137. nouveau_fence_update(struct nouveau_screen *screen, boolean flushed)
  138. {
  139.    struct nouveau_fence *fence;
  140.    struct nouveau_fence *next = NULL;
  141.    u32 sequence = screen->fence.update(&screen->base);
  142.  
  143.    if (screen->fence.sequence_ack == sequence)
  144.       return;
  145.    screen->fence.sequence_ack = sequence;
  146.  
  147.    for (fence = screen->fence.head; fence; fence = next) {
  148.       next = fence->next;
  149.       sequence = fence->sequence;
  150.  
  151.       fence->state = NOUVEAU_FENCE_STATE_SIGNALLED;
  152.  
  153.       nouveau_fence_trigger_work(fence);
  154.       nouveau_fence_ref(NULL, &fence);
  155.  
  156.       if (sequence == screen->fence.sequence_ack)
  157.          break;
  158.    }
  159.    screen->fence.head = next;
  160.    if (!next)
  161.       screen->fence.tail = NULL;
  162.  
  163.    if (flushed) {
  164.       for (fence = next; fence; fence = fence->next)
  165.          if (fence->state == NOUVEAU_FENCE_STATE_EMITTED)
  166.             fence->state = NOUVEAU_FENCE_STATE_FLUSHED;
  167.    }
  168. }
  169.  
  170. #define NOUVEAU_FENCE_MAX_SPINS (1 << 31)
  171.  
  172. boolean
  173. nouveau_fence_signalled(struct nouveau_fence *fence)
  174. {
  175.    struct nouveau_screen *screen = fence->screen;
  176.  
  177.    if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED)
  178.       nouveau_fence_update(screen, FALSE);
  179.  
  180.    return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
  181. }
  182.  
  183. boolean
  184. nouveau_fence_wait(struct nouveau_fence *fence)
  185. {
  186.    struct nouveau_screen *screen = fence->screen;
  187.    uint32_t spins = 0;
  188.  
  189.    /* wtf, someone is waiting on a fence in flush_notify handler? */
  190.    assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
  191.  
  192.    if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) {
  193.       nouveau_fence_emit(fence);
  194.  
  195.       if (fence == screen->fence.current)
  196.          nouveau_fence_new(screen, &screen->fence.current, FALSE);
  197.    }
  198.    if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED) {
  199.       if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
  200.          return FALSE;
  201.    }
  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.