1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/*
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright 2012 Red Hat Inc.
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining a
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * copy of this software and associated documentation files (the "Software"),
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * to deal in the Software without restriction, including without limitation
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * and/or sell copies of the Software, and to permit persons to whom the
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Software is furnished to do so, subject to the following conditions:
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice shall be included in
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * all copies or substantial portions of the Software.
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * SOFTWARE.
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Authors: Ben Skeggs
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "tgsi/tgsi_parse.h"
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nouveau/nv_object.xml.h"
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nv30-40_3d.xml.h"
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nv30_context.h"
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nvfx_shader.h"
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fragprog_upload(struct nv30_context *nv30)
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_context *nv = &nv30->base;
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nv30_fragprog *fp = nv30->fragprog.program;
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct pipe_context *pipe = &nv30->base.pipe;
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct pipe_transfer *transfer;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint32_t *map;
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i; (void)i;
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (unlikely(!fp->buffer)) {
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      fp->buffer = pipe_buffer_create(pipe->screen, 0, 0, fp->insn_len * 4);
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   map = pipe_buffer_map(pipe, fp->buffer, PIPE_TRANSFER_WRITE, &transfer);
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef PIPE_ARCH_BIG_ENDIAN
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   memcpy(map, fp->insn, fp->insn_len * 4);
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#else
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < fp->insn_len; i++)
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      *map++ = (fp->insn[i] >> 16) | (fp->insn[i] << 16);
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_buffer_unmap(pipe, transfer);
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (nv04_resource(fp->buffer)->domain != NOUVEAU_BO_VRAM)
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nouveau_buffer_migrate(nv, nv04_resource(fp->buffer), NOUVEAU_BO_VRAM);
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fragprog_validate(struct nv30_context *nv30)
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_pushbuf *push = nv30->base.pushbuf;
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_object *eng3d = nv30->screen->eng3d;
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nv30_fragprog *fp = nv30->fragprog.program;
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   boolean upload = FALSE;
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i;
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!fp->translated) {
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      _nvfx_fragprog_translate(nv30, fp, FALSE);
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (!fp->translated)
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return;
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      upload = TRUE;
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* update constants, also needs to be done on every fp switch as we
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * have no idea whether the constbuf changed in the meantime
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    */
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (nv30->fragprog.constbuf) {
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      struct pipe_resource *constbuf = nv30->fragprog.constbuf;
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      uint32_t *cbuf = (uint32_t *)nv04_resource(constbuf)->data;
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      for (i = 0; i < fp->nr_consts; i++) {
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         unsigned off = fp->consts[i].offset;
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         unsigned idx = fp->consts[i].index * 4;
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (!memcmp(&fp->insn[off], &cbuf[idx], 4 * 4))
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            continue;
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         memcpy(&fp->insn[off], &cbuf[idx], 4 * 4);
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         upload = TRUE;
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (upload)
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nv30_fragprog_upload(nv30);
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* FP_ACTIVE_PROGRAM needs to be done again even if only the consts
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * were updated.  TEX_CACHE_CTL magic is not enough to convince the
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * GPU that it should re-read the fragprog from VRAM... sigh.
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    */
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (nv30->state.fragprog != fp || upload) {
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      struct nv04_resource *r = nv04_resource(fp->buffer);
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (!PUSH_SPACE(push, 8))
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return;
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      PUSH_RESET(push, BUFCTX_FRAGPROG);
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1);
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      PUSH_RESRC(push, NV30_3D(FP_ACTIVE_PROGRAM), BUFCTX_FRAGPROG, r, 0,
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       NOUVEAU_BO_LOW | NOUVEAU_BO_RD | NOUVEAU_BO_OR,
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       NV30_3D_FP_ACTIVE_PROGRAM_DMA0,
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       NV30_3D_FP_ACTIVE_PROGRAM_DMA1);
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1);
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      PUSH_DATA (push, fp->fp_control);
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (eng3d->oclass < NV40_3D_CLASS) {
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         BEGIN_NV04(push, NV30_3D(FP_REG_CONTROL), 1);
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         PUSH_DATA (push, 0x00010004);
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         BEGIN_NV04(push, NV30_3D(TEX_UNITS_ENABLE), 1);
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         PUSH_DATA (push, fp->texcoords);
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else {
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         BEGIN_NV04(push, SUBC_3D(0x0b40), 1);
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         PUSH_DATA (push, 0x00000000);
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nv30->state.fragprog = fp;
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void *
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fp_state_create(struct pipe_context *pipe,
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     const struct pipe_shader_state *cso)
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nv30_fragprog *fp = CALLOC_STRUCT(nv30_fragprog);
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!fp)
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   fp->pipe.tokens = tgsi_dup_tokens(cso->tokens);
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   tgsi_scan_shader(fp->pipe.tokens, &fp->info);
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return fp;
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fp_state_delete(struct pipe_context *pipe, void *hwcso)
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nv30_fragprog *fp = hwcso;
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_resource_reference(&fp->buffer, NULL);
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE((void *)fp->pipe.tokens);
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(fp->insn);
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(fp);
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fp_state_bind(struct pipe_context *pipe, void *hwcso)
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nv30_context *nv30 = nv30_context(pipe);
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   nv30->fragprog.program = hwcso;
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   nv30->dirty |= NV30_NEW_FRAGPROG;
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnv30_fragprog_init(struct pipe_context *pipe)
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe->create_fs_state = nv30_fp_state_create;
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe->bind_fs_state = nv30_fp_state_bind;
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe->delete_fs_state = nv30_fp_state_delete;
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
171