Home | History | Annotate | Download | only in nv30
      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 "nv_object.xml.h"
     27 #include "nv30/nv30-40_3d.xml.h"
     28 #include "nv30/nv30_screen.h"
     29 #include "nv30/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, unsigned index)
    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    case PIPE_QUERY_OCCLUSION_PREDICATE:
    124    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
    125       q->enable = NV30_3D_QUERY_ENABLE;
    126       q->report = 1;
    127       break;
    128    case NV30_QUERY_ZCULL_0:
    129    case NV30_QUERY_ZCULL_1:
    130    case NV30_QUERY_ZCULL_2:
    131    case NV30_QUERY_ZCULL_3:
    132       q->enable = 0x1804;
    133       q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
    134       break;
    135    default:
    136       FREE(q);
    137       return NULL;
    138    }
    139 
    140    return (struct pipe_query *)q;
    141 }
    142 
    143 static void
    144 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
    145 {
    146    FREE(pq);
    147 }
    148 
    149 static boolean
    150 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
    151 {
    152    struct nv30_context *nv30 = nv30_context(pipe);
    153    struct nv30_query *q = nv30_query(pq);
    154    struct nouveau_pushbuf *push = nv30->base.pushbuf;
    155 
    156    switch (q->type) {
    157    case PIPE_QUERY_TIME_ELAPSED:
    158       q->qo[0] = nv30_query_object_new(nv30->screen);
    159       if (q->qo[0]) {
    160          BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
    161          PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start);
    162       }
    163       break;
    164    case PIPE_QUERY_TIMESTAMP:
    165       return true;
    166    default:
    167       BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1);
    168       PUSH_DATA (push, q->report);
    169       break;
    170    }
    171 
    172    if (q->enable) {
    173       BEGIN_NV04(push, SUBC_3D(q->enable), 1);
    174       PUSH_DATA (push, 1);
    175    }
    176    return true;
    177 }
    178 
    179 static bool
    180 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
    181 {
    182    struct nv30_context *nv30 = nv30_context(pipe);
    183    struct nv30_screen *screen = nv30->screen;
    184    struct nv30_query *q = nv30_query(pq);
    185    struct nouveau_pushbuf *push = nv30->base.pushbuf;
    186 
    187    q->qo[1] = nv30_query_object_new(screen);
    188    if (q->qo[1]) {
    189       BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
    190       PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
    191    }
    192 
    193    if (q->enable) {
    194       BEGIN_NV04(push, SUBC_3D(q->enable), 1);
    195       PUSH_DATA (push, 0);
    196    }
    197    PUSH_KICK (push);
    198    return true;
    199 }
    200 
    201 static boolean
    202 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
    203                   boolean wait, union pipe_query_result *result)
    204 {
    205    struct nv30_screen *screen = nv30_screen(pipe->screen);
    206    struct nv30_query *q = nv30_query(pq);
    207    volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
    208    volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
    209 
    210    if (ntfy1) {
    211       while (ntfy1[3] & 0xff000000) {
    212          if (!wait)
    213             return false;
    214       }
    215 
    216       switch (q->type) {
    217       case PIPE_QUERY_TIMESTAMP:
    218          q->result = *(uint64_t *)&ntfy1[0];
    219          break;
    220       case PIPE_QUERY_TIME_ELAPSED:
    221          q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
    222          break;
    223       default:
    224          q->result = ntfy1[2];
    225          break;
    226       }
    227 
    228       nv30_query_object_del(screen, &q->qo[0]);
    229       nv30_query_object_del(screen, &q->qo[1]);
    230    }
    231 
    232    if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE ||
    233        q->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE)
    234       result->b = !!q->result;
    235    else
    236       result->u64 = q->result;
    237    return true;
    238 }
    239 
    240 static void
    241 nv40_query_render_condition(struct pipe_context *pipe,
    242                             struct pipe_query *pq,
    243                             boolean condition, enum pipe_render_cond_flag mode)
    244 {
    245    struct nv30_context *nv30 = nv30_context(pipe);
    246    struct nv30_query *q = nv30_query(pq);
    247    struct nouveau_pushbuf *push = nv30->base.pushbuf;
    248 
    249    nv30->render_cond_query = pq;
    250    nv30->render_cond_mode = mode;
    251    nv30->render_cond_cond = condition;
    252 
    253    if (!pq) {
    254       BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
    255       PUSH_DATA (push, 0x01000000);
    256       return;
    257    }
    258 
    259    if (mode == PIPE_RENDER_COND_WAIT ||
    260        mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
    261       BEGIN_NV04(push, SUBC_3D(0x0110), 1);
    262       PUSH_DATA (push, 0);
    263    }
    264 
    265    BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
    266    PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
    267 }
    268 
    269 static void
    270 nv30_set_active_query_state(struct pipe_context *pipe, boolean enable)
    271 {
    272 }
    273 
    274 void
    275 nv30_query_init(struct pipe_context *pipe)
    276 {
    277    struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
    278 
    279    pipe->create_query = nv30_query_create;
    280    pipe->destroy_query = nv30_query_destroy;
    281    pipe->begin_query = nv30_query_begin;
    282    pipe->end_query = nv30_query_end;
    283    pipe->get_query_result = nv30_query_result;
    284    pipe->set_active_query_state = nv30_set_active_query_state;
    285    if (eng3d->oclass >= NV40_3D_CLASS)
    286       pipe->render_condition = nv40_query_render_condition;
    287 }
    288