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 "draw/draw_context.h" 27#include "tgsi/tgsi_parse.h" 28#include "nir/nir_to_tgsi.h" 29 30#include "nv_object.xml.h" 31#include "nv30/nv30-40_3d.xml.h" 32#include "nv30/nv30_context.h" 33#include "nv30/nvfx_shader.h" 34 35static void 36nv30_fragprog_upload(struct nv30_context *nv30) 37{ 38 struct nouveau_context *nv = &nv30->base; 39 struct nv30_fragprog *fp = nv30->fragprog.program; 40 struct pipe_context *pipe = &nv30->base.pipe; 41 42 if (unlikely(!fp->buffer)) 43 fp->buffer = pipe_buffer_create(pipe->screen, 0, 0, fp->insn_len * 4); 44 45#if !UTIL_ARCH_BIG_ENDIAN 46 pipe_buffer_write(pipe, fp->buffer, 0, fp->insn_len * 4, fp->insn); 47#else 48 { 49 struct pipe_transfer *transfer; 50 uint32_t *map; 51 int i; 52 53 map = pipe_buffer_map(pipe, fp->buffer, 54 PIPE_MAP_WRITE | PIPE_MAP_DISCARD_WHOLE_RESOURCE, 55 &transfer); 56 for (i = 0; i < fp->insn_len; i++) 57 *map++ = (fp->insn[i] >> 16) | (fp->insn[i] << 16); 58 pipe_buffer_unmap(pipe, transfer); 59 } 60#endif 61 62 if (nv04_resource(fp->buffer)->domain != NOUVEAU_BO_VRAM) 63 nouveau_buffer_migrate(nv, nv04_resource(fp->buffer), NOUVEAU_BO_VRAM); 64} 65 66void 67nv30_fragprog_validate(struct nv30_context *nv30) 68{ 69 struct nouveau_pushbuf *push = nv30->base.pushbuf; 70 struct nouveau_object *eng3d = nv30->screen->eng3d; 71 struct nv30_fragprog *fp = nv30->fragprog.program; 72 bool upload = false; 73 int i; 74 75 if (!fp->translated) { 76 _nvfx_fragprog_translate(eng3d->oclass, fp); 77 if (!fp->translated) 78 return; 79 80 upload = true; 81 } 82 83 /* update constants, also needs to be done on every fp switch as we 84 * have no idea whether the constbuf changed in the meantime 85 */ 86 if (nv30->fragprog.constbuf) { 87 struct pipe_resource *constbuf = nv30->fragprog.constbuf; 88 uint32_t *cbuf = (uint32_t *)nv04_resource(constbuf)->data; 89 90 for (i = 0; i < fp->nr_consts; i++) { 91 unsigned off = fp->consts[i].offset; 92 unsigned idx = fp->consts[i].index * 4; 93 94 if (!memcmp(&fp->insn[off], &cbuf[idx], 4 * 4)) 95 continue; 96 memcpy(&fp->insn[off], &cbuf[idx], 4 * 4); 97 upload = true; 98 } 99 } 100 101 if (upload) 102 nv30_fragprog_upload(nv30); 103 104 /* FP_ACTIVE_PROGRAM needs to be done again even if only the consts 105 * were updated. TEX_CACHE_CTL magic is not enough to convince the 106 * GPU that it should re-read the fragprog from VRAM... sigh. 107 */ 108 if (nv30->state.fragprog != fp || upload) { 109 struct nv04_resource *r = nv04_resource(fp->buffer); 110 111 if (!PUSH_SPACE(push, 8)) 112 return; 113 PUSH_RESET(push, BUFCTX_FRAGPROG); 114 115 BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1); 116 PUSH_RESRC(push, NV30_3D(FP_ACTIVE_PROGRAM), BUFCTX_FRAGPROG, r, 0, 117 NOUVEAU_BO_LOW | NOUVEAU_BO_RD | NOUVEAU_BO_OR, 118 NV30_3D_FP_ACTIVE_PROGRAM_DMA0, 119 NV30_3D_FP_ACTIVE_PROGRAM_DMA1); 120 BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1); 121 PUSH_DATA (push, fp->fp_control); 122 if (eng3d->oclass < NV40_3D_CLASS) { 123 BEGIN_NV04(push, NV30_3D(FP_REG_CONTROL), 1); 124 PUSH_DATA (push, 0x00010004); 125 BEGIN_NV04(push, NV30_3D(TEX_UNITS_ENABLE), 1); 126 PUSH_DATA (push, fp->texcoords); 127 } else { 128 BEGIN_NV04(push, SUBC_3D(0x0b40), 1); 129 PUSH_DATA (push, 0x00000000); 130 } 131 132 nv30->state.fragprog = fp; 133 } 134} 135 136static void * 137nv30_fp_state_create(struct pipe_context *pipe, 138 const struct pipe_shader_state *cso) 139{ 140 struct nv30_fragprog *fp = CALLOC_STRUCT(nv30_fragprog); 141 if (!fp) 142 return NULL; 143 144 if (cso->type == PIPE_SHADER_IR_NIR) { 145 fp->pipe.tokens = nir_to_tgsi(cso->ir.nir, pipe->screen); 146 } else { 147 assert(cso->type == PIPE_SHADER_IR_TGSI); 148 /* we need to keep a local copy of the tokens */ 149 fp->pipe.tokens = tgsi_dup_tokens(cso->tokens); 150 } 151 152 tgsi_scan_shader(fp->pipe.tokens, &fp->info); 153 return fp; 154} 155 156static void 157nv30_fp_state_delete(struct pipe_context *pipe, void *hwcso) 158{ 159 struct nv30_fragprog *fp = hwcso; 160 161 pipe_resource_reference(&fp->buffer, NULL); 162 163 if (fp->draw) 164 draw_delete_fragment_shader(nv30_context(pipe)->draw, fp->draw); 165 166 FREE((void *)fp->pipe.tokens); 167 FREE(fp->insn); 168 FREE(fp->consts); 169 FREE(fp); 170} 171 172static void 173nv30_fp_state_bind(struct pipe_context *pipe, void *hwcso) 174{ 175 struct nv30_context *nv30 = nv30_context(pipe); 176 struct nv30_fragprog *fp = hwcso; 177 178 /* reset the bucftx so that we don't keep a dangling reference to the fp 179 * code 180 */ 181 if (fp != nv30->state.fragprog) 182 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FRAGPROG); 183 184 nv30->fragprog.program = fp; 185 nv30->dirty |= NV30_NEW_FRAGPROG; 186} 187 188void 189nv30_fragprog_init(struct pipe_context *pipe) 190{ 191 pipe->create_fs_state = nv30_fp_state_create; 192 pipe->bind_fs_state = nv30_fp_state_bind; 193 pipe->delete_fs_state = nv30_fp_state_delete; 194} 195