Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2012 Red Hat Inc.
  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.  * Authors: Ben Skeggs
  23.  *
  24.  */
  25.  
  26. #include "nouveau/nv_object.xml.h"
  27. #include "nv30-40_3d.xml.h"
  28. #include "nv30_screen.h"
  29. #include "nv30_context.h"
  30.  
  31. #define LIST_FIRST_ENTRY(__type, __item, __field) \
  32.    LIST_ENTRY(__type, (__item)->next, __field)
  33.  
  34. struct nv30_query_object {
  35.    struct list_head list;
  36.    struct nouveau_heap *hw;
  37. };
  38.  
  39. static volatile void *
  40. nv30_ntfy(struct nv30_screen *screen, struct nv30_query_object *qo)
  41. {
  42.    struct nv04_notify *query = screen->query->data;
  43.    struct nouveau_bo *notify = screen->notify;
  44.    volatile void *ntfy = NULL;
  45.  
  46.    if (qo && qo->hw)
  47.       ntfy = (char *)notify->map + query->offset + qo->hw->start;
  48.  
  49.    return ntfy;
  50. }
  51.  
  52. static void
  53. nv30_query_object_del(struct nv30_screen *screen, struct nv30_query_object **po)
  54. {
  55.    struct nv30_query_object *qo = *po; *po = NULL;
  56.    if (qo) {
  57.       volatile uint32_t *ntfy = nv30_ntfy(screen, qo);
  58.       while (ntfy[3] & 0xff000000) {
  59.       }
  60.       nouveau_heap_free(&qo->hw);
  61.       LIST_DEL(&qo->list);
  62.       FREE(qo);
  63.    }
  64. }
  65.  
  66. static struct nv30_query_object *
  67. nv30_query_object_new(struct nv30_screen *screen)
  68. {
  69.    struct nv30_query_object *oq, *qo = CALLOC_STRUCT(nv30_query_object);
  70.    volatile uint32_t *ntfy;
  71.  
  72.    if (!qo)
  73.       return NULL;
  74.  
  75.    /* allocate a new hw query object, if no hw objects left we need to
  76.     * spin waiting for one to become free
  77.     */
  78.    while (nouveau_heap_alloc(screen->query_heap, 32, NULL, &qo->hw)) {
  79.       oq = LIST_FIRST_ENTRY(struct nv30_query_object, &screen->queries, list);
  80.       nv30_query_object_del(screen, &oq);
  81.    }
  82.  
  83.    LIST_ADDTAIL(&qo->list, &screen->queries);
  84.  
  85.    ntfy = nv30_ntfy(screen, qo);
  86.    ntfy[0] = 0x00000000;
  87.    ntfy[1] = 0x00000000;
  88.    ntfy[2] = 0x00000000;
  89.    ntfy[3] = 0x01000000;
  90.    return qo;
  91. }
  92.  
  93. struct nv30_query {
  94.    struct nv30_query_object *qo[2];
  95.    unsigned type;
  96.    uint32_t report;
  97.    uint32_t enable;
  98.    uint64_t result;
  99. };
  100.  
  101. static INLINE struct nv30_query *
  102. nv30_query(struct pipe_query *pipe)
  103. {
  104.    return (struct nv30_query *)pipe;
  105. }
  106.  
  107. static struct pipe_query *
  108. nv30_query_create(struct pipe_context *pipe, unsigned type)
  109. {
  110.    struct nv30_query *q = CALLOC_STRUCT(nv30_query);
  111.    if (!q)
  112.       return NULL;
  113.  
  114.    q->type = type;
  115.  
  116.    switch (q->type) {
  117.    case PIPE_QUERY_TIMESTAMP:
  118.    case PIPE_QUERY_TIME_ELAPSED:
  119.       q->enable = 0x0000;
  120.       q->report = 1;
  121.       break;
  122.    case PIPE_QUERY_OCCLUSION_COUNTER:
  123.       q->enable = NV30_3D_QUERY_ENABLE;
  124.       q->report = 1;
  125.       break;
  126.    case NV30_QUERY_ZCULL_0:
  127.    case NV30_QUERY_ZCULL_1:
  128.    case NV30_QUERY_ZCULL_2:
  129.    case NV30_QUERY_ZCULL_3:
  130.       q->enable = 0x1804;
  131.       q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
  132.       break;
  133.    default:
  134.       FREE(q);
  135.       return NULL;
  136.    }
  137.  
  138.    return (struct pipe_query *)q;
  139. }
  140.  
  141. static void
  142. nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
  143. {
  144.    FREE(pq);
  145. }
  146.  
  147. static void
  148. nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
  149. {
  150.    struct nv30_context *nv30 = nv30_context(pipe);
  151.    struct nv30_query *q = nv30_query(pq);
  152.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  153.  
  154.    switch (q->type) {
  155.    case PIPE_QUERY_TIME_ELAPSED:
  156.       q->qo[0] = nv30_query_object_new(nv30->screen);
  157.       if (q->qo[0]) {
  158.          BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
  159.          PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start);
  160.       }
  161.       break;
  162.    case PIPE_QUERY_TIMESTAMP:
  163.       return;
  164.    default:
  165.       BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1);
  166.       PUSH_DATA (push, q->report);
  167.       break;
  168.    }
  169.  
  170.    if (q->enable) {
  171.       BEGIN_NV04(push, SUBC_3D(q->enable), 1);
  172.       PUSH_DATA (push, 1);
  173.    }
  174. }
  175.  
  176. static void
  177. nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
  178. {
  179.    struct nv30_context *nv30 = nv30_context(pipe);
  180.    struct nv30_screen *screen = nv30->screen;
  181.    struct nv30_query *q = nv30_query(pq);
  182.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  183.  
  184.    q->qo[1] = nv30_query_object_new(screen);
  185.    if (q->qo[1]) {
  186.       BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
  187.       PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
  188.    }
  189.  
  190.    if (q->enable) {
  191.       BEGIN_NV04(push, SUBC_3D(q->enable), 1);
  192.       PUSH_DATA (push, 0);
  193.    }
  194.    PUSH_KICK (push);
  195. }
  196.  
  197. static boolean
  198. nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
  199.                   boolean wait, union pipe_query_result *result)
  200. {
  201.    struct nv30_screen *screen = nv30_screen(pipe->screen);
  202.    struct nv30_query *q = nv30_query(pq);
  203.    volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
  204.    volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
  205.    uint64_t *res64 = &result->u64;
  206.  
  207.    if (ntfy1) {
  208.       while (ntfy1[3] & 0xff000000) {
  209.          if (!wait)
  210.             return FALSE;
  211.       }
  212.  
  213.       switch (q->type) {
  214.       case PIPE_QUERY_TIMESTAMP:
  215.          q->result = *(uint64_t *)&ntfy1[0];
  216.          break;
  217.       case PIPE_QUERY_TIME_ELAPSED:
  218.          q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
  219.          break;
  220.       default:
  221.          q->result = ntfy1[2];
  222.          break;
  223.       }
  224.  
  225.       nv30_query_object_del(screen, &q->qo[0]);
  226.       nv30_query_object_del(screen, &q->qo[1]);
  227.    }
  228.  
  229.    *res64 = q->result;
  230.    return TRUE;
  231. }
  232.  
  233. static void
  234. nv40_query_render_condition(struct pipe_context *pipe,
  235.                             struct pipe_query *pq,
  236.                             boolean condition, uint mode)
  237. {
  238.    struct nv30_context *nv30 = nv30_context(pipe);
  239.    struct nv30_query *q = nv30_query(pq);
  240.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  241.  
  242.    nv30->render_cond_query = pq;
  243.    nv30->render_cond_mode = mode;
  244.    nv30->render_cond_cond = condition;
  245.  
  246.    if (!pq) {
  247.       BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
  248.       PUSH_DATA (push, 0x01000000);
  249.       return;
  250.    }
  251.  
  252.    if (mode == PIPE_RENDER_COND_WAIT ||
  253.        mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
  254.       BEGIN_NV04(push, SUBC_3D(0x0110), 1);
  255.       PUSH_DATA (push, 0);
  256.    }
  257.  
  258.    BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
  259.    PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
  260. }
  261.  
  262. void
  263. nv30_query_init(struct pipe_context *pipe)
  264. {
  265.    struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
  266.  
  267.    pipe->create_query = nv30_query_create;
  268.    pipe->destroy_query = nv30_query_destroy;
  269.    pipe->begin_query = nv30_query_begin;
  270.    pipe->end_query = nv30_query_end;
  271.    pipe->get_query_result = nv30_query_result;
  272.    if (eng3d->oclass >= NV40_3D_CLASS)
  273.       pipe->render_condition = nv40_query_render_condition;
  274. }
  275.