diff options
Diffstat (limited to 'src/mesa/drivers/dri/nouveau/nouveau_shader_2.c')
-rw-r--r-- | src/mesa/drivers/dri/nouveau/nouveau_shader_2.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/nouveau/nouveau_shader_2.c b/src/mesa/drivers/dri/nouveau/nouveau_shader_2.c new file mode 100644 index 0000000000..b39f4668b9 --- /dev/null +++ b/src/mesa/drivers/dri/nouveau/nouveau_shader_2.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2006 Ben Skeggs. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * Authors: + * Ben Skeggs <darktama@iinet.net.au> + */ + +#include "glheader.h" +#include "macros.h" +#include "enums.h" + +#include "program.h" + +#include "nouveau_shader.h" + +struct pass2_rec { + /* Map nvsRegister temp ID onto hw temp ID */ + unsigned int temps[NVS_MAX_TEMPS]; + /* Track free hw registers */ + unsigned int hw_temps[NVS_MAX_TEMPS]; +}; + +static int +pass2_alloc_hw_temp(nvsPtr nvs) +{ + struct pass2_rec *rec = nvs->pass_rec; + int i; + + for (i=0; i<nvs->func->MaxTemp; i++) { + /* This is a *horrible* hack.. R0 is both temp0 and result.color + * in NV30/40 fragprogs, we can use R0 as a temp before result is + * written however.. + */ + if (nvs->mesa.vp.Base.Target == GL_FRAGMENT_PROGRAM_ARB && i==0) + continue; + + if (rec->hw_temps[i] == 0) { + rec->hw_temps[i] = 1; + return i; + } + } + return -1; +} + +static void +pass2_free_hw_temp(nvsPtr nvs, int reg) +{ + struct pass2_rec *rec = nvs->pass_rec; + rec->hw_temps[reg] = 0; +} + +static nvsRegister +pass2_mangle_reg(nvsPtr nvs, nvsInstruction *inst, nvsRegister reg) +{ + struct pass2_rec *rec = nvs->pass_rec; + + if (reg.file == NVS_FILE_TEMP) { + int hwidx; + + if (rec->temps[reg.index] == -1) + rec->temps[reg.index] = pass2_alloc_hw_temp(nvs); + hwidx = rec->temps[reg.index]; + + if (nvs->temps[reg.index].last_use <= inst->header.position) + pass2_free_hw_temp(nvs, hwidx); + + reg.index = hwidx; + } + + return reg; +} + +static void +pass2_add_instruction(nvsPtr nvs, nvsInstruction *inst, + struct _op_xlat *op, int slot) +{ + nvsSwzComp default_swz[4] = { NVS_SWZ_X, NVS_SWZ_Y, NVS_SWZ_Z, NVS_SWZ_W }; + nvsFunc *shader = nvs->func; + nvsRegister reg; + int i; + + shader->SetOpcode(shader, op->NV, slot); + if (inst->saturate ) shader->SetSaturate(shader); + if (inst->cond_update) shader->SetCCUpdate(shader); + if (inst->cond_test ) shader->SetCondition(shader, 1, inst->cond, + inst->cond_reg, + inst->cond_swizzle); + else shader->SetCondition(shader, 0, NVS_COND_TR, + 0, + default_swz); + switch (inst->op) { + case NVS_OP_TEX: + case NVS_OP_TXB: + case NVS_OP_TXL: + case NVS_OP_TXP: + case NVS_OP_TXD: + shader->SetTexImageUnit(shader, inst->tex_unit); + break; + default: + break; + } + + for (i = 0; i < 3; i++) { + if (op->srcpos[i] != -1) { + reg = pass2_mangle_reg(nvs, inst, inst->src[i]); + if (reg.file == NVS_FILE_ATTRIB) + nvs->inputs_read |= (1 << reg.index); + shader->SetSource(shader, ®, op->srcpos[i]); + if (reg.file == NVS_FILE_CONST && shader->GetSourceConstVal) { + int idx_slot = nvs->params[reg.index].hw_index_cnt++; + nvs->params[reg.index].hw_index = realloc( + nvs->params[reg.index].hw_index, sizeof(int) * idx_slot+1); + nvs->params[reg.index].hw_index[idx_slot] = nvs->program_current + 4; + } + } + } + + reg = pass2_mangle_reg(nvs, inst, inst->dest); + if (reg.file == NVS_FILE_RESULT) + nvs->outputs_written |= (1 << reg.index); + shader->SetResult(shader, ®, inst->mask, slot); +} + +static int +pass2_assemble_instruction(nvsPtr nvs, nvsInstruction *inst, int last) +{ + nvsFunc *shader = nvs->func; + struct _op_xlat *op; + unsigned int hw_inst[8]; + int slot; + int instsz; + int i; + + shader->inst = hw_inst; + + /* Assemble this instruction */ + if (!(op = shader->GetOPTXFromSOP(inst->op, &slot))) + return 0; + shader->InitInstruction(shader); + pass2_add_instruction(nvs, inst, op, slot); + if (last) + shader->SetLastInst(shader); + + instsz = shader->GetOffsetNext(nvs->func); + if (nvs->program_size + instsz >= nvs->program_alloc_size) { + nvs->program_alloc_size *= 2; + nvs->program = realloc(nvs->program, + nvs->program_alloc_size * sizeof(uint32_t)); + } + + for (i=0; i<instsz; i++) + nvs->program[nvs->program_current++] = hw_inst[i]; + nvs->program_size = nvs->program_current; + return 1; +} + +/* Translate program into hardware format */ +GLboolean +nouveau_shader_pass2(nvsPtr nvs) +{ + nvsFragmentList *list = nvs->list_head; + struct pass2_rec *rec; + int i; + + rec = calloc(1, sizeof(struct pass2_rec)); + for (i=0; i<NVS_MAX_TEMPS; i++) + rec->temps[i] = -1; + nvs->pass_rec = rec; + + /* Start off with allocating 4 uint32_t's for each inst, will be grown + * if necessary.. + */ + nvs->program_alloc_size = nvs->inst_count * 4; + nvs->program = calloc(nvs->program_alloc_size, sizeof(uint32_t)); + nvs->program_size = 0; + nvs->program_current = 0; + + while (list) { + assert(list->fragment->type == NVS_INSTRUCTION); + + if (!pass2_assemble_instruction(nvs, (nvsInstruction *)list->fragment, list->next ? 0 : 1)) { + free(nvs->program); + nvs->program = NULL; + return GL_FALSE; + } + + list = list->next; + } + + /* Shrink allocated memory to only what we need */ + nvs->program = realloc(nvs->program, nvs->program_size * sizeof(uint32_t)); + nvs->program_alloc_size = nvs->program_size; + + nvs->translated = 1; + nvs->on_hardware = 0; + +#if 1 + fflush(stdout); fflush(stderr); + fprintf(stderr, "----------------MESA PROGRAM\n"); + fflush(stdout); fflush(stderr); + _mesa_print_program(&nvs->mesa.vp.Base); + fflush(stdout); fflush(stderr); + fprintf(stderr, "^^^^^^^^^^^^^^^^MESA PROGRAM\n"); + fflush(stdout); fflush(stderr); + fprintf(stderr, "----------------NV40 PROGRAM\n"); + fflush(stdout); fflush(stderr); + nvsDisasmHWShader(nvs); + fflush(stdout); fflush(stderr); + fprintf(stderr, "^^^^^^^^^^^^^^^^NV40 PROGRAM\n"); + fflush(stdout); fflush(stderr); +#endif + + return GL_TRUE; +} + |