summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/xbox_nv2a.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/xbox_nv2a.cpp')
-rw-r--r--src/mame/video/xbox_nv2a.cpp5134
1 files changed, 0 insertions, 5134 deletions
diff --git a/src/mame/video/xbox_nv2a.cpp b/src/mame/video/xbox_nv2a.cpp
deleted file mode 100644
index 1354cf2382c..00000000000
--- a/src/mame/video/xbox_nv2a.cpp
+++ /dev/null
@@ -1,5134 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Samuele Zannoli
-#include "emu.h"
-#include "video/poly.h"
-#include "bitmap.h"
-#include "includes/xbox_nv2a.h"
-#include <bitset>
-#include <cfloat>
-
-//#define LOG_NV2A
-#define DEBUG_CHECKS // enable for debugging
-
-char const *const vertex_program_disassembler::srctypes[] = { "??", "Rn", "Vn", "Cn" };
-char const *const vertex_program_disassembler::scaops[] = { "NOP", "IMV", "RCP", "RCC", "RSQ", "EXP", "LOG", "LIT", "???", "???", "???", "???", "???", "???", "???", "???", "???" };
-int const vertex_program_disassembler::scapar2[] = { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-char const *const vertex_program_disassembler::vecops[] = { "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DPH", "DP4", "DST", "MIN", "MAX", "SLT", "SGE", "ARL", "???", "???", "???" };
-int const vertex_program_disassembler::vecpar2[] = { 0, 4, 6, 5, 7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 0, 0, 0 };
-char const *const vertex_program_disassembler::vecouts[] = { "oPos", "???", "???", "oD0", "oD1", "oFog", "oPts", "oB0", "oB1", "oT0", "oT1", "oT2", "oT3" };
-char const vertex_program_disassembler::compchar[] = { 'x', 'y', 'z', 'w' };
-
-/*
-Each vertex program instruction is a 128 bit word made of the fields:
-d f
-w b i
-o i e
-r t l
-d s d
-+-+-----+-------
-|0|31-0 |not used
-+-+-----+-------
-| |31-29|not used
-| +-----+-------
-| |28-25|scalar operation
-| +-----+-------
-| |24-21|vectorial operation
-| +-----+-------
-| |20-13|index for source constant C[]
-| +-----+-------
-| |12-9 |input vector index
-| +-----+-------
-|1| 8 |parameter A:sign
-| +-----+-------
-| | 7-6 |parameter A:swizzle x
-| +-----+-------
-| | 5-4 |parameter A:swizzle y
-| +-----+-------
-| | 3-2 |parameter A:swizzle z
-| +-----+-------
-| | 1-0 |parameter A:swizzle w
-|-+-----+-------
-| |31-28|parameter A:parameter Rn index
-| +-----+-------
-| |27-26|parameter A:input type 1:Rn 2:Vn 3:C[n]
-| +-----+-------
-| | 25 |parameter B:sign
-| +-----+-------
-| |24-23|parameter B:swizzle x
-| +-----+-------
-| |22-21|parameter B:swizzle y
-| +-----+-------
-| |20-19|parameter B:swizzle z
-| +-----+-------
-|2|18-17|parameter B:swizzle w
-| +-----+-------
-| |16-13|parameter B:parameter Rn index
-| +-----+-------
-| |12-11|parameter B:input type 1:Rn 2:Vn 3:C[n]
-| +-----+-------
-| | 10 |parameter C:sign
-| +-----+-------
-| | 9-8 |parameter C:swizzle x
-| +-----+-------
-| | 7-6 |parameter C:swizzle y
-| +-----+-------
-| | 5-4 |parameter C:swizzle z
-| +-----+-------
-| | 3-2 |parameter C:swizzle w
-| +-----+-------
-| | 1-0 |
-|-+ |parameter C:parameter Rn index
-| |31-30|
-| +-----+-------
-| |29-28|parameter C:input type 1:Rn 2:Vn 3:C[n]
-| +-----+-------
-| |27-24|output Rn mask from vectorial operation
-| +-----+-------
-| |23-20|output Rn index from vectorial operation
-| +-----+-------
-| |19-16|output Rn mask from scalar operation
-| +-----+-------
-|3|15-12|output vector write mask
-| +-----+-------
-| | 11 |1:output is output vector 0:output is constant C[]
-| +-----+-------
-| |10-3 |output vector/constant index
-| +-----+-------
-| | 2 |0:output Rn from vectorial operation 1:output Rn from scalar operation
-| +-----+-------
-| | 1 |1:add a0x to index for source constant C[]
-| +-----+-------
-| | 0 |1:end of program
-+-+-----+-------
-Each vertex program instruction can generate up to three destination values using up to three source values.
-The first possible destination is to Rn from a vectorial operation.
-The second possible destination is to a vertex shader output or C[n] from a vectorial or scalar operation.
-The third possible destination is to Rn from a scalar operation.
-*/
-void vertex_program_disassembler::decodefields(unsigned int *dwords, int offset, fields &decoded)
-{
- unsigned int srcbits[3];
- int a;
-
- srcbits[0] = ((dwords[1 + offset] & 0x1ff) << 6) | (dwords[2 + offset] >> 26);
- srcbits[1] = (dwords[2 + offset] >> 11) & 0x7fff;
- srcbits[2] = ((dwords[2 + offset] & 0x7ff) << 4) | (dwords[3 + offset] >> 28);
- decoded.ScaOperation = (int)(dwords[1 + offset] >> 25) & 0xf;
- decoded.VecOperation = (int)(dwords[1 + offset] >> 21) & 0xf;
- decoded.SourceConstantIndex = (int)(dwords[1 + offset] >> 13) & 0xff;
- decoded.InputIndex = (int)(dwords[1 + offset] >> 9) & 0xf;
- for (a = 0; a < 3; a++)
- {
- decoded.src[a].Sign = (int)(srcbits[a] >> 14) & 1;
- decoded.src[a].SwizzleX = (int)(srcbits[a] >> 12) & 3;
- decoded.src[a].SwizzleY = (int)(srcbits[a] >> 10) & 3;
- decoded.src[a].SwizzleZ = (int)(srcbits[a] >> 8) & 3;
- decoded.src[a].SwizzleW = (int)(srcbits[a] >> 6) & 3;
- decoded.src[a].TempIndex = (int)(srcbits[a] >> 2) & 0xf;
- decoded.src[a].ParameterType = (int)(srcbits[a] >> 0) & 3;
- }
-
- decoded.VecTempWriteMask = (int)(dwords[3 + offset] >> 24) & 0xf;
- decoded.VecTempIndex = (int)(dwords[3 + offset] >> 20) & 0xf;
- decoded.ScaTempWriteMask = (int)(dwords[3 + offset] >> 16) & 0xf;
- decoded.OutputWriteMask = (int)(dwords[3 + offset] >> 12) & 0xf;
- decoded.OutputSelect = (int)(dwords[3 + offset] >> 11) & 0x1;
- decoded.OutputIndex = (int)(dwords[3 + offset] >> 3) & 0xff;
- decoded.MultiplexerControl = (int)(dwords[3 + offset] >> 2) & 0x1;
- decoded.Usea0x = (int)(dwords[3 + offset] >> 1) & 0x1;
- decoded.EndOfProgram = (int)(dwords[3 + offset] >> 0) & 0x1;
-}
-
-int vertex_program_disassembler::disassemble_mask(int mask, char *s)
-{
- int l;
-
- *s = 0;
- if (mask == 15)
- return 0;
- s[0] = '.';
- l = 1;
- if ((mask & 8) != 0)
- {
- s[l] = 'x';
- l++;
- }
- if ((mask & 4) != 0)
- {
- s[l] = 'y';
- l++;
- }
- if ((mask & 2) != 0)
- {
- s[l] = 'z';
- l++;
- }
- if ((mask & 1) != 0)
- {
- s[l] = 'w';
- l++;
- }
- s[l] = 0;
- return l;
-}
-
-int vertex_program_disassembler::disassemble_swizzle(sourcefields f, char *s)
-{
- int t, l;
-
- t = 4;
- if (f.SwizzleW == 3)
- {
- t = t - 1;
- if (f.SwizzleZ == 2)
- {
- t = t - 1;
- if (f.SwizzleY == 1)
- {
- t = t - 1;
- if (f.SwizzleX == 0)
- {
- t = t - 1;
- }
- }
- }
- }
- *s = 0;
- if (t == 0)
- return 0;
- s[0] = '.';
- l = 1;
- if (t > 0)
- {
- s[l] = compchar[f.SwizzleX];
- l++;
- }
- if (t > 1)
- {
- s[l] = compchar[f.SwizzleY];
- l++;
- }
- if (t > 2)
- {
- s[l] = compchar[f.SwizzleZ];
- l++;
- }
- if (t > 3)
- {
- s[l] = compchar[f.SwizzleW];
- l++;
- }
- s[l] = 0;
- return l;
-}
-
-int vertex_program_disassembler::disassemble_source(sourcefields f, fields fi, char *s)
-{
- int l;
-
- if (f.ParameterType == 0) {
- strcpy(s, ",???");
- return 4;
- }
- l = 0;
- if (f.Sign != 0) {
- s[l] = '-';
- l++;
- }
- if (f.ParameterType == 1) {
- s[l] = 'r';
- l = l + 1 + sprintf(s + l + 1, "%d", f.TempIndex);
- }
- else if (f.ParameterType == 2){
- s[l] = 'v';
- l = l + 1 + sprintf(s + l + 1, "%d", fi.InputIndex);
- }
- else
- {
- if (fi.Usea0x != 0)
- {
- if (fi.SourceConstantIndex >= 96) {
- strcpy(s + l, "c[");
- l = l + 2;
- l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
- strcpy(s + l, "+a0.x]");
- l = l + 6;
- }
- else {
- strcpy(s + l, "c[a0.x");
- l = l + 6;
- l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
- s[l] = ']';
- l++;
- }
- }
- else {
- strcpy(s + l, "c[");
- l = l + 2;
- l = l + sprintf(s + l, "%d", fi.SourceConstantIndex - 96);
- s[l] = ']';
- l++;
- }
- }
- l = l + disassemble_swizzle(f, s + l);
- s[l] = 0;
- return l;
-}
-
-int vertex_program_disassembler::disassemble_output(fields f, char *s)
-{
- int l;
-
- if (f.OutputSelect == 1) {
- strcpy(s, vecouts[f.OutputIndex]);
- return strlen(s);
- }
- else {
- strcpy(s, "c[");
- l = 2;
- l = l + sprintf(s + l, "%d", f.OutputIndex - 96);
- s[l] = ']';
- l++;
- }
- s[l] = 0;
- return l;
-}
-
-int vertex_program_disassembler::output_types(fields f, int *o)
-{
- o[0] = o[1] = o[2] = o[3] = o[4] = o[5] = 0;
- if ((f.VecOperation > 0) && (f.VecTempWriteMask != 0))
- o[0] = 1;
- if ((f.VecOperation > 0) && (f.OutputWriteMask != 0) && (f.MultiplexerControl == 0))
- o[1] = 1;
- if ((f.ScaOperation > 0) && (f.OutputWriteMask != 0) && (f.MultiplexerControl == 1))
- o[2] = 1;
- if ((f.ScaOperation > 0) && (f.ScaTempWriteMask != 0))
- o[3] = 1;
- if (f.VecOperation == 13)
- o[4] = 1;
- if (f.EndOfProgram == 1)
- o[5] = 1;
- return o[0] + o[1] + o[2] + o[3] + o[4] + o[5];
-}
-
-int vertex_program_disassembler::disassemble(unsigned int *instruction, char *line)
-{
- int b, p;
- char *c;
-
- if (state == 0) {
- decodefields(instruction, 0, f);
- output_types(f, o);
- state = 1;
- }
- if (o[0] != 0)
- {
- o[0] = 0;
- c = line;
- strcpy(c, vecops[f.VecOperation]);
- c = c + strlen(c);
- strcpy(c, " r");
- c = c + 2;
- c = c + sprintf(c, "%d", f.VecTempIndex);
- c = c + disassemble_mask(f.VecTempWriteMask, c);
- b = 0;
- for (p = 4; p != 0; p = p >> 1)
- {
- if ((vecpar2[f.VecOperation] & p) != 0) {
- c[0] = ',';
- c++;
- c = c + disassemble_source(f.src[b], f, c);
- }
- b++;
- }
- *c = 0;
- return 1;
- }
- if (o[1] != 0)
- {
- o[1] = 0;
- c = line;
- strcpy(c, vecops[f.VecOperation]);
- c = c + strlen(c);
- *c = ' ';
- c++;
- c = c + disassemble_output(f, c);
- c = c + disassemble_mask(f.OutputWriteMask, c);
- b = 0;
- for (p = 4; p != 0; p = p >> 1)
- {
- if ((vecpar2[f.VecOperation] & p) != 0) {
- *c = ',';
- c++;
- c = c + disassemble_source(f.src[b], f, c);
- }
- b++;
- }
- *c = 0;
- return 1;
- }
- if (o[2] != 0)
- {
- o[2] = 0;
- c = line;
- strcpy(c, scaops[f.ScaOperation]);
- c = c + strlen(c);
- *c = ' ';
- c++;
- c = c + disassemble_output(f, c);
- c = c + disassemble_mask(f.OutputWriteMask, c);
- b = 0;
- for (p = 4; p != 0; p = p >> 1)
- {
- if ((scapar2[f.ScaOperation] & p) != 0) {
- *c = ',';
- c++;
- c = c + disassemble_source(f.src[b], f, c);
- }
- b++;
- }
- *c = 0;
- return 1;
- }
- if (o[3] != 0)
- {
- if (f.VecOperation > 0)
- b = 1;
- else
- b = f.VecTempIndex;
- o[3] = 0;
- c = line;
- strcpy(c, scaops[f.ScaOperation]);
- c = c + strlen(c);
- strcpy(c, " r");
- c = c + 2;
- c = c + sprintf(c, "%d", b);
- c = c + disassemble_mask(f.ScaTempWriteMask, c);
- b = 0;
- for (p = 4; p != 0; p = p >> 1)
- {
- if ((scapar2[f.ScaOperation] & p) != 0) {
- *c = ',';
- c++;
- c = c + disassemble_source(f.src[b], f, c);
- }
- b++;
- }
- *c = 0;
- return 1;
- }
- if (o[4] != 0)
- {
- o[4] = 0;
- c = line;
- c = c + sprintf(c, "MOV a0.x,");
- c = c + disassemble_source(f.src[0], f, c);
- *c = 0;
- return 1;
- }
- if (o[5] != 0)
- {
- o[5] = 0;
- strcpy(line, "END");
- return 1;
- }
- state = 0;
- return 0;
-}
-
-vertex_program_simulator::vertex_program_simulator()
-{
- for (auto & elem : op)
- elem.modified = 0;
- initialize_constants();
-}
-
-void vertex_program_simulator::set_data(vertex_nv *in, vertex_nv *out)
-{
- input = in;
- output = out;
-}
-
-void vertex_program_simulator::reset()
-{
- ip = 0;
- a0x = 0;
- initialize_outputs();
- initialize_temps();
-}
-
-void vertex_program_simulator::decode_instruction(int address)
-{
- instruction *i;
-
- i = &op[address];
- i->d.NegateA = i->i[1] & (1 << 8);
- i->d.ParameterTypeA = (i->i[2] >> 26) & 3;
- i->d.TempIndexA = (i->i[2] >> 28) & 15;
- i->d.SwizzleA[0] = (i->i[1] >> 6) & 3;
- i->d.SwizzleA[1] = (i->i[1] >> 4) & 3;
- i->d.SwizzleA[2] = (i->i[1] >> 2) & 3;
- i->d.SwizzleA[3] = (i->i[1] >> 0) & 3;
- i->d.NegateB = i->i[2] & (1 << 25);
- i->d.ParameterTypeB = (i->i[2] >> 11) & 3;
- i->d.TempIndexB = (i->i[2] >> 13) & 15;
- i->d.SwizzleB[0] = (i->i[2] >> 23) & 3;
- i->d.SwizzleB[1] = (i->i[2] >> 21) & 3;
- i->d.SwizzleB[2] = (i->i[2] >> 19) & 3;
- i->d.SwizzleB[3] = (i->i[2] >> 17) & 3;
- i->d.NegateC = i->i[2] & (1 << 10);
- i->d.ParameterTypeC = (i->i[3] >> 28) & 3;
- i->d.TempIndexC = ((i->i[2] & 3) << 2) + (i->i[3] >> 30);
- i->d.SwizzleC[0] = (i->i[2] >> 8) & 3;
- i->d.SwizzleC[1] = (i->i[2] >> 6) & 3;
- i->d.SwizzleC[2] = (i->i[2] >> 4) & 3;
- i->d.SwizzleC[3] = (i->i[2] >> 2) & 3;
- i->d.VecOperation = (VectorialOperation)((i->i[1] >> 21) & 15);
- i->d.ScaOperation = (ScalarOperation)((i->i[1] >> 25) & 15);
- i->d.OutputWriteMask = ((i->i[3] >> 12) & 15);
- i->d.MultiplexerControl = i->i[3] & 4; // 0 : output Rn from vectorial operation 4 : output Rn from scalar operation
- i->d.VecTempIndex = (i->i[3] >> 20) & 15;
- i->d.OutputIndex = (i->i[3] >> 3) & 255;
- i->d.OutputSelect = i->i[3] & 0x800;
- i->d.VecTempWriteMask = (i->i[3] >> 24) & 15;
- i->d.ScaTempWriteMask = (i->i[3] >> 16) & 15;
- i->d.InputIndex = (i->i[1] >> 9) & 15;
- i->d.SourceConstantIndex = (i->i[1] >> 13) & 255;
- i->d.Usea0x = i->i[3] & 2;
- i->d.EndOfProgram = i->i[3] & 1;
-}
-
-int vertex_program_simulator::step()
-{
- int p1, p2;
- float tmp[3 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- float tmpv[4] = { 0, 0, 0, 0};
- float tmps[4] = { 0, 0, 0, 0};
- instruction::decoded *d;
-
-#if 0 // useful while debugging to see what instrucion is being executed
- static int debugvpi = 0;
- char disbuffer[256];
- if (debugvpi) {
- char *pp;
- vertex_program_disassembler vdis;
-
- pp = disbuffer;
- while (vdis.disassemble(op[ip].i, pp) != 0) {
- pp = pp + strlen(pp);
- *pp = '\n';
- pp++;
- *pp = 0;
- printf("%s", disbuffer);
- }
- }
-#endif
-
- if (op[ip].modified)
- decode_instruction(ip);
- d = &(op[ip].d);
- // prepare inputs
- // input A
- generate_input(&tmp[0], d->NegateA, d->ParameterTypeA, d->TempIndexA, d->SwizzleA);
- // input B
- generate_input(&tmp[4], d->NegateB, d->ParameterTypeB, d->TempIndexB, d->SwizzleB);
- // input C
- generate_input(&tmp[8], d->NegateC, d->ParameterTypeC, d->TempIndexC, d->SwizzleC);
- // compute 2 instructions
- // vectorial
- compute_vectorial_operation(tmpv, d->VecOperation, tmp);
- // scalar
- compute_scalar_operation(tmps, d->ScaOperation, tmp);
- // assign destinations
- if (d->VecOperation != VecNOP) {
- if (d->VecOperation == VecARL)
- //o[4] = 1;
- a0x = (int)tmpv[0];
- else {
- if (d->VecTempWriteMask != 0) { // assign to Rn
- //o[0] = 1;
- assign_register(d->VecTempIndex, tmpv, d->VecTempWriteMask);
- }
- if ((d->OutputWriteMask != 0) && (d->MultiplexerControl == 0)) {
- //o[1] = 1;
- if (d->OutputSelect) { // assign to output
- assign_output(d->OutputIndex, tmpv, d->OutputWriteMask);
- // remeber, output position == r12
- if (d->OutputIndex == 0)
- for (p1 = 0; p1 < 4; p1++) {
- r_register[12].fv[p1] = output->attribute[d->OutputIndex].fv[p1];
- }
- }
- else { // assign to constant
- assign_constant(d->OutputIndex, tmpv, d->OutputWriteMask);
- }
- }
- }
- }
- if (d->ScaOperation != ScaNOP) {
- if (d->ScaTempWriteMask != 0) { // assign to Rn
- //o[3] = 1;
- if (d->VecOperation != VecNOP)
- p2 = 1;
- else
- p2 = d->VecTempIndex;
- assign_register(p2, tmps, d->ScaTempWriteMask);
- }
- if ((d->OutputWriteMask != 0) && (d->MultiplexerControl != 0)) { // assign to output
- //o[2] = 1;
- assign_output(d->OutputIndex, tmps, d->OutputWriteMask);
- // remeber, output position == r12
- if (d->OutputIndex == 0) {
- for (p1 = 0; p1 < 4; p1++) {
- r_register[12].fv[p1] = output->attribute[d->OutputIndex].fv[p1];
- }
- }
- }
- }
- return d->EndOfProgram;
-}
-
-void vertex_program_simulator::execute()
-{
- int c;
-
- c = 0;
- do {
- c = step();
- ip++;
- } while (c == 0);
-}
-
-void vertex_program_simulator::jump(int address)
-{
- ip = address;
-}
-
-void vertex_program_simulator::process(int address, vertex_nv *in, vertex_nv *out, int count)
-{
-#if 0 // useful while debugging to see what is being executed
- static int debugvps = 0;
- if (debugvps) {
- FILE *f;
- char *pp;
- vertex_program_disassembler vdis;
- char disbuffer[128];
-
- debugvps--;
- if ((f = fopen("vertexshader_debug.txt", "wb")) != nullptr) {
- jump(address);
- fprintf(f, "SHADER:\n");
- for (int t = 0; t < 128; t++) {
- pp = disbuffer;
- while (vdis.disassemble(op[ip + t].i, pp) != 0) {
- pp = pp + strlen(pp);
- *pp = '\n';
- pp++;
- *pp = 0;
- }
- fprintf(f, "%08X %08X %08X %s", op[ip + t].i[1], op[ip + t].i[2], op[ip + t].i[3], disbuffer);
- if (op[ip + t].i[3] & 1)
- break;
- }
- fprintf(f, "INPUTS:\n");
- for (int t = 0; t < 16; t++)
- fprintf(f, "v%d %f %f %f %f\n", t, in->attribute[t].fv[0], in->attribute[t].fv[1], in->attribute[t].fv[2], in->attribute[t].fv[3]);
- fprintf(f, "CONSTANTS:\n");
- for (int t = 0; t < 192; t++)
- fprintf(f, "c[%d] %f %f %f %f\n", t - 96, c_constant[t].fv[0], c_constant[t].fv[1], c_constant[t].fv[2], c_constant[t].fv[3]);
- fclose(f);
- }
- }
-#endif
- set_data(in, out);
- while (count > 0) {
- reset();
- jump(address);
- execute();
- input++;
- output++;
- count--;
- }
-}
-
-int vertex_program_simulator::status()
-{
- return ip;
-}
-
-void vertex_program_simulator::initialize_outputs()
-{
- for (int n = 0; n < 16; n++) {
- output->attribute[n].fv[0] = output->attribute[n].fv[1] = output->attribute[n].fv[2] = 0;
- output->attribute[n].fv[3] = 1;
- }
-}
-
-void vertex_program_simulator::initialize_temps()
-{
- for (auto & elem : r_register) {
- for (int m = 0; m < 4; m++)
- elem.fv[m] = 0;
- }
-}
-
-void vertex_program_simulator::initialize_constants()
-{
- for (auto & elem : c_constant) {
- for (int m = 0; m < 4;m++)
- elem.fv[m] = 0;
- }
-}
-
-void vertex_program_simulator::generate_input(float t[4], int sign, int type, int temp, int swizzle[4])
-{
- float sgn = 1;
-
- if (sign)
- sgn = -1;
- if (type == 1) {
- t[0] = sgn * r_register[temp].fv[swizzle[0]];
- t[1] = sgn * r_register[temp].fv[swizzle[1]];
- t[2] = sgn * r_register[temp].fv[swizzle[2]];
- t[3] = sgn * r_register[temp].fv[swizzle[3]];
- }
- else if (type == 2) {
- int InputIndex = op[ip].d.InputIndex;
- t[0] = sgn * input->attribute[InputIndex].fv[swizzle[0]];
- t[1] = sgn * input->attribute[InputIndex].fv[swizzle[1]];
- t[2] = sgn * input->attribute[InputIndex].fv[swizzle[2]];
- t[3] = sgn * input->attribute[InputIndex].fv[swizzle[3]];
- }
- else if (type == 3) {
- int SourceConstantIndex = op[ip].d.SourceConstantIndex;
- if (op[ip].d.Usea0x)
- SourceConstantIndex = SourceConstantIndex + a0x;
- t[0] = sgn * c_constant[SourceConstantIndex].fv[swizzle[0]];
- t[1] = sgn * c_constant[SourceConstantIndex].fv[swizzle[1]];
- t[2] = sgn * c_constant[SourceConstantIndex].fv[swizzle[2]];
- t[3] = sgn * c_constant[SourceConstantIndex].fv[swizzle[3]];
- }
-}
-
-void vertex_program_simulator::compute_vectorial_operation(float t_out[4], int instruction, float par_in[3 * 4])
-{
- const int p1_A = 0;
- const int p2_B = 4;
- const int p3_C = 8;
-
- // t_out <= instruction(par_in)
- switch (instruction) {
- case 0: // "NOP"
- break;
- case 1: // "MOV"
- t_out[0] = par_in[p1_A + 0];
- t_out[1] = par_in[p1_A + 1];
- t_out[2] = par_in[p1_A + 2];
- t_out[3] = par_in[p1_A + 3];
- break;
- case 2: // "MUL"
- t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0];
- t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1];
- t_out[2] = par_in[p1_A + 2] * par_in[p2_B + 2];
- t_out[3] = par_in[p1_A + 3] * par_in[p2_B + 3];
- break;
- case 3: // "ADD"
- t_out[0] = par_in[p1_A + 0] + par_in[p3_C + 0];
- t_out[1] = par_in[p1_A + 1] + par_in[p3_C + 1];
- t_out[2] = par_in[p1_A + 2] + par_in[p3_C + 2];
- t_out[3] = par_in[p1_A + 3] + par_in[p3_C + 3];
- break;
- case 4: // "MAD"
- t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p3_C + 0];
- t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p3_C + 1];
- t_out[2] = par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p3_C + 2];
- t_out[3] = par_in[p1_A + 3] * par_in[p2_B + 3] + par_in[p3_C + 3];
- break;
- case 5: // "DP3"
- t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2];
- t_out[1] = t_out[2] = t_out[3] = t_out[0];
- break;
- case 6: // "DPH"
- t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p2_B + 3];
- t_out[1] = t_out[2] = t_out[3] = t_out[0];
- break;
- case 7: // "DP4"
- t_out[0] = par_in[p1_A + 0] * par_in[p2_B + 0] + par_in[p1_A + 1] * par_in[p2_B + 1] + par_in[p1_A + 2] * par_in[p2_B + 2] + par_in[p1_A + 3] * par_in[p2_B + 3];
- t_out[1] = t_out[2] = t_out[3] = t_out[0];
- break;
- case 8: // "DST"
- t_out[0] = 1.0;
- t_out[1] = par_in[p1_A + 1] * par_in[p2_B + 1];
- t_out[2] = par_in[p1_A + 2];
- t_out[3] = par_in[p2_B + 3];
- break;
- case 9: // "MIN"
- t_out[0] = fmin(par_in[p1_A + 0], par_in[p2_B + 0]);
- t_out[1] = fmin(par_in[p1_A + 1], par_in[p2_B + 1]);
- t_out[2] = fmin(par_in[p1_A + 2], par_in[p2_B + 2]);
- t_out[3] = fmin(par_in[p1_A + 3], par_in[p2_B + 3]);
- break;
- case 10: // "MAX"
- t_out[0] = fmax(par_in[p1_A + 0], par_in[p2_B + 0]);
- t_out[1] = fmax(par_in[p1_A + 1], par_in[p2_B + 1]);
- t_out[2] = fmax(par_in[p1_A + 2], par_in[p2_B + 2]);
- t_out[3] = fmax(par_in[p1_A + 3], par_in[p2_B + 3]);
- break;
- case 11: // "SLT"
- t_out[0] = (par_in[p1_A + 0] < par_in[p2_B + 0]) ? 1.0 : 0;
- t_out[1] = (par_in[p1_A + 1] < par_in[p2_B + 1]) ? 1.0 : 0;
- t_out[2] = (par_in[p1_A + 2] < par_in[p2_B + 2]) ? 1.0 : 0;
- t_out[3] = (par_in[p1_A + 3] < par_in[p2_B + 3]) ? 1.0 : 0;
- break;
- case 12: // "SGE"
- t_out[0] = (par_in[p1_A + 0] >= par_in[p2_B + 0]) ? 1.0 : 0;
- t_out[1] = (par_in[p1_A + 1] >= par_in[p2_B + 1]) ? 1.0 : 0;
- t_out[2] = (par_in[p1_A + 2] >= par_in[p2_B + 2]) ? 1.0 : 0;
- t_out[3] = (par_in[p1_A + 3] >= par_in[p2_B + 3]) ? 1.0 : 0;
- break;
- case 13: // "ARL"
- t_out[0] = par_in[p1_A + 0];
- }
-}
-
-void vertex_program_simulator::compute_scalar_operation(float t_out[4], int instruction, float par_in[3 * 4])
-{
- //const int p1_A = 0;
- //const int p2_B = 4;
- const int p3_C = 8;
- union {
- float f;
- unsigned int i;
- } t;
- int e;
-
- // t_out <= instruction(par_in)
- switch (instruction) {
- case 0: // "NOP"
- break;
- case 1: // "IMV"
- t_out[0] = par_in[p3_C + 0];
- t_out[1] = par_in[p3_C + 1];
- t_out[2] = par_in[p3_C + 2];
- t_out[3] = par_in[p3_C + 3];
- break;
- case 2: // "RCP"
- if (par_in[p3_C + 0] == 0)
- t.f = std::numeric_limits<float>::infinity();
- else if (par_in[p3_C + 0] == 1.0f)
- t.f = 1.0f;
- else
- t.f = 1.0f / par_in[p3_C + 0];
- t_out[0] = t_out[1] = t_out[2] = t_out[3] = t.f;
- break;
- case 3: // "RCC"
- t.f = par_in[p3_C + 0];
- if ((t.f < 0) && (t.f > -5.42101e-20f))
- t.f = -5.42101e-20f;
- else if ((t.f >= 0) && (t.f < 5.42101e-20f))
- t.f = 5.42101e-20f;
- if (t.f != 1.0f)
- t.f = 1.0f / t.f;
- t_out[0] = t_out[1] = t_out[2] = t_out[3] = t.f;
- break;
- case 4: // "RSQ"
- t_out[0] = t_out[1] = t_out[2] = t_out[3] = 1.0f / sqrtf(fabsf(par_in[p3_C + 0]));
- break;
- case 5: // "EXP"
- t_out[0] = pow(2, floor(par_in[p3_C + 0]));
- t_out[1] = par_in[p3_C + 0] - floorf(par_in[p3_C + 0]);
- t.f = pow(2, par_in[p3_C + 0]);
- t.i = t.i & 0xffffff00;
- t_out[2] = t.f;
- t_out[3] = 1.0;
- break;
- case 6: // "LOG"
- t_out[1] = frexp(par_in[p3_C + 0], &e)*2.0; // frexp gives mantissa as 0.5....1
- t_out[0] = e - 1;
-#ifndef __OS2__
- t.f = log2(fabsf(par_in[p3_C + 0]));
-#else
- static double log_2 = 0.0;
- if (log_2 == 0.0)
- log_2 = log(2);
- t.f = log(abs(par_in[p3_C + 0])) / log_2;
-#endif
- t.i = t.i & 0xffffff00;
- t_out[2] = t.f;
- t_out[3] = 1.0;
- break;
- case 7: // "LIT"
- t_out[0] = 1.0;
- t_out[1] = fmax(0, fmin(par_in[p3_C + 0], 1.0f));
- t_out[2] = par_in[p3_C + 0] > 0 ? pow(fmax(par_in[p3_C + 1], 0), par_in[p3_C + 3]) : 0;
- t_out[3] = 1.0;
- break;
- }
-}
-
-void vertex_program_simulator::assign_output(int index, float t[4], int mask)
-{
- for (int p1 = 0; p1 < 4; p1++) {
- if (mask & 8)
- output->attribute[index].fv[p1] = t[p1];
- mask = mask << 1;
- }
-}
-
-void vertex_program_simulator::assign_register(int index, float t[4], int mask)
-{
- for (int p1 = 0; p1 < 4; p1++) {
- if (mask & 8)
- r_register[index].fv[p1] = t[p1];
- mask = mask << 1;
- }
-}
-
-void vertex_program_simulator::assign_constant(int index, float t[4], int mask)
-{
- for (int p1 = 0; p1 < 4; p1++) {
- if (mask & 8)
- c_constant[index].fv[p1] = t[p1];
- mask = mask << 1;
- }
-}
-
-/*
- * Graphics
- */
-
-uint32_t nv2a_renderer::dilate0(uint32_t value, int bits) // dilate first "bits" bits in "value"
-{
- uint32_t x, m1, m2, m3;
- int a;
-
- x = value;
- for (a = 0; a < bits; a++)
- {
- m2 = 1 << (a << 1);
- m1 = m2 - 1;
- m3 = (~m1) << 1;
- x = (x & m1) + (x & m2) + ((x & m3) << 1);
- }
- return x;
-}
-
-uint32_t nv2a_renderer::dilate1(uint32_t value, int bits) // dilate first "bits" bits in "value"
-{
- uint32_t x, m1, m2, m3;
- int a;
-
- x = value;
- for (a = 0; a < bits; a++)
- {
- m2 = 1 << (a << 1);
- m1 = m2 - 1;
- m3 = (~m1) << 1;
- x = (x & m1) + ((x & m2) << 1) + ((x & m3) << 1);
- }
- return x;
-}
-
-void nv2a_renderer::computedilated(void)
-{
- int a, b;
-
- for (b = 0; b < 16; b++)
- for (a = 0; a < 2048; a++) {
- dilated0[b][a] = dilate0(a, b);
- dilated1[b][a] = dilate1(a, b);
- }
- for (b = 0; b < 16; b++)
- for (a = 0; a < 16; a++)
- dilatechose[(b << 4) + a] = (a < b ? a : b);
-}
-
-inline uint8_t *nv2a_renderer::direct_access_ptr(offs_t address)
-{
-#ifdef DEBUG_CHECKS
- if (address >= 512*1024*1024)
- machine().logerror("Bad address in direct_access_ptr !\n");
-#endif
- return basemempointer + address;
-}
-
-nv2a_renderer::COMMAND nv2a_renderer::geforce_commandkind(uint32_t word)
-{
- if ((word & 0x00000003) == 0x00000002)
- return COMMAND::CALL;
- if ((word & 0x00000003) == 0x00000001)
- return COMMAND::JUMP;
- if ((word & 0xE0030003) == 0x40000000)
- return COMMAND::NON_INCREASING;
- if ((word & 0xE0000003) == 0x20000000)
- return COMMAND::OLD_JUMP;
- if ((word & 0xFFFF0003) == 0x00030000)
- return COMMAND::LONG_NON_INCREASING;
- if ((word & 0xFFFFFFFF) == 0x00020000)
- return COMMAND::RETURN;
- if ((word & 0xFFFF0003) == 0x00010000)
- return COMMAND::SLI_CONDITIONAL;
- if ((word & 0xE0030003) == 0x00000000)
- return COMMAND::INCREASING;
- return COMMAND::INVALID;
-}
-
-uint32_t nv2a_renderer::geforce_object_offset(uint32_t handle)
-{
- uint32_t h = ((((handle >> 11) ^ handle) >> 11) ^ handle) & 0x7ff;
- uint32_t o = (pfifo[0x210 / 4] & 0x1ff) << 8; // 0x1ff is not certain
- uint32_t e = o + h * 8; // at 0xfd000000+0x00700000
- uint32_t w;
-
- if (ramin[e / 4] != handle) {
- // this should never happen
- for (uint32_t aa = o / 4; aa < (sizeof(ramin) / 4); aa = aa + 2) {
- if (ramin[aa] == handle) {
- e = aa * 4;
- }
- }
- }
- w = ramin[e / 4 + 1];
- return (w & 0xffff) * 0x10; // 0xffff is not certain
-}
-
-void nv2a_renderer::geforce_read_dma_object(uint32_t handle, uint32_t &offset, uint32_t &size)
-{
- //uint32_t objclass,pt_present,pt_linear,access,target,rorw;
- uint32_t dma_adjust, dma_frame;
- uint32_t o = geforce_object_offset(handle);
-
- o = o / 4;
- //objclass=ramin[o] & 0xfff;
- //pt_present=(ramin[o] >> 12) & 1;
- //pt_linear=(ramin[o] >> 13) & 1;
- //access=(ramin[o] >> 14) & 3;
- //target=(ramin[o] >> 16) & 3;
- dma_adjust = (ramin[o] >> 20) & 0xfff;
- size = ramin[o + 1];
- //rorw=ramin[o+2] & 1;
- dma_frame = ramin[o + 2] & 0xfffff000;
- offset = dma_frame + dma_adjust;
-}
-
-/*void debug(uint32_t *bmp, int width, int eight, float x1, float y1, float x2, float y2, uint32_t color)
-{
-int xx1,yy1,xx2,yy2;
-
- xx1=x1;
- xx2=x2;
- yy1=y1;
- yy2=y2;
- if (xx1 == xx2) {
- if (yy1 > yy2) {
- int t=yy1;
- yy1=yy2;
- yy2=t;
- }
- for (int y=yy1;y <= yy2;y++) {
- *(bmp+y*width+xx1) = color;
- }
- } else if (yy1 == yy2) {
- if (xx1 > xx2) {
- int t=xx1;
- xx1=xx2;
- xx2=t;
- }
- for (int x=xx1;x <= xx2;x++)
- *(bmp+yy1*width+x) = color;
- }
-}*/
-
-inline uint32_t convert_a4r4g4b4_a8r8g8b8(uint32_t a4r4g4b4)
-{
- uint32_t a8r8g8b8;
- int ca, cr, cg, cb;
-
- cb = pal4bit(a4r4g4b4 & 0x000f);
- cg = pal4bit((a4r4g4b4 & 0x00f0) >> 4);
- cr = pal4bit((a4r4g4b4 & 0x0f00) >> 8);
- ca = pal4bit((a4r4g4b4 & 0xf000) >> 12);
- a8r8g8b8 = (ca << 24) | (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
- return a8r8g8b8;
-}
-
-inline uint32_t convert_a1r5g5b5_a8r8g8b8(uint32_t a1r5g5b5)
-{
- uint32_t a8r8g8b8;
- int ca, cr, cg, cb;
-
- cb = pal5bit(a1r5g5b5 & 0x001f);
- cg = pal5bit((a1r5g5b5 & 0x03e0) >> 5);
- cr = pal5bit((a1r5g5b5 & 0x7c00) >> 10);
- ca = a1r5g5b5 & 0x8000 ? 0xff : 0;
- a8r8g8b8 = (ca << 24) | (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
- return a8r8g8b8;
-}
-
-inline uint32_t convert_r5g6b5_r8g8b8(uint32_t r5g6b5)
-{
- uint32_t r8g8b8;
- int cr, cg, cb;
-
- cb = pal5bit(r5g6b5 & 0x001f);
- cg = pal6bit((r5g6b5 & 0x07e0) >> 5);
- cr = pal5bit((r5g6b5 & 0xf800) >> 11);
- r8g8b8 = (cr << 16) | (cg << 8) | (cb); // color converted to 8 bits per component
- return r8g8b8;
-}
-
-uint32_t nv2a_renderer::texture_get_texel(int number, int x, int y)
-{
- uint32_t to, s, c, sa, ca;
- uint32_t a4r4g4b4, a1r5g5b5, r5g6b5;
- int bx, by;
- int color0, color1, color0m2, color1m2, alpha0, alpha1;
- uint32_t codes;
- uint64_t alphas;
- int cr, cg, cb;
- int sizeu, sizev;
-
- if (texture[number].rectangle == false) {
- sizeu = texture[number].sizes;
- sizev = texture[number].sizet;
- }
- else {
- sizeu = texture[number].rectwidth;
- sizev = texture[number].rectheight;
- }
- switch (texture[number].addrmodes) {
- default:
- case 1: // wrap
- x = x % sizeu;
- if (x < 0)
- x = sizeu + x;
- break;
- case 3: // clamp
- if (x < 0)
- x = 0;
- if (x >= sizeu)
- x = sizeu - 1;
- break;
- }
- switch (texture[number].addrmodet) {
- default:
- case 1: // wrap
- y = y % sizev;
- if (y < 0)
- y = sizev + y;
- break;
- case 3: // clamp
- if (y < 0)
- y = 0;
- if (y >= sizev)
- y = sizev - 1;
- break;
- }
- switch (texture[number].format) {
- case NV2A_TEX_FORMAT::A8R8G8B8:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- return *(((uint32_t *)texture[number].buffer) + to); // get texel color
- case NV2A_TEX_FORMAT::X8R8G8B8:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- return 0xff000000 | (*(((uint32_t*)texture[number].buffer) + to) & 0xffffff); // get texel color
- case NV2A_TEX_FORMAT::DXT1:
- bx = x >> 2;
- by = y >> 2;
- x = x & 3;
- y = y & 3;
- to = bx + by*(sizeu >> 2);
- color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 0);
- color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
- codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
- s = (y << 3) + (x << 1);
- c = (codes >> s) & 3;
- c = c + (color0 > color1 ? 0 : 4);
- color0m2 = color0 << 1;
- color1m2 = color1 << 1;
- switch (c) {
- case 0:
- return 0xff000000 + convert_r5g6b5_r8g8b8(color0);
- case 1:
- return 0xff000000 + convert_r5g6b5_r8g8b8(color1);
- case 2:
- cb = pal5bit(((color0m2 & 0x003e) + (color1 & 0x001f)) / 3);
- cg = pal6bit(((color0m2 & 0x0fc0) + (color1 & 0x07e0)) / 3 >> 5);
- cr = pal5bit(((color0m2 & 0x1f000) + color1) / 3 >> 11);
- return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
- case 3:
- cb = pal5bit(((color1m2 & 0x003e) + (color0 & 0x001f)) / 3);
- cg = pal6bit(((color1m2 & 0x0fc0) + (color0 & 0x07e0)) / 3 >> 5);
- cr = pal5bit(((color1m2 & 0x1f000) + color0) / 3 >> 11);
- return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
- case 4:
- return 0xff000000 + convert_r5g6b5_r8g8b8(color0);
- case 5:
- return 0xff000000 + convert_r5g6b5_r8g8b8(color1);
- case 6:
- cb = pal5bit(((color0 & 0x001f) + (color1 & 0x001f)) / 2);
- cg = pal6bit(((color0 & 0x07e0) + (color1 & 0x07e0)) / 2 >> 5);
- cr = pal5bit(((color0 & 0xf800) + (color1 & 0xf800)) / 2 >> 11);
- return 0xff000000 | (cr << 16) | (cg << 8) | (cb);
- default:
- return 0xff000000;
- }
- case NV2A_TEX_FORMAT::DXT3:
- bx = x >> 2;
- by = y >> 2;
- x = x & 3;
- y = y & 3;
- to = (bx + by*(sizeu >> 2)) << 1;
- color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 4);
- color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 5);
- codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 3);
- alphas = *(((uint64_t *)texture[number].buffer) + to);
- s = (y << 3) + (x << 1);
- sa = ((y << 2) + x) << 2;
- c = (codes >> s) & 3;
- ca = (alphas >> sa) & 15;
- switch (c) {
- case 0:
- return ((ca + (ca << 4)) << 24) + convert_r5g6b5_r8g8b8(color0);
- case 1:
- return ((ca + (ca << 4)) << 24) + convert_r5g6b5_r8g8b8(color1);
- case 2:
- cb = pal5bit((2 * (color0 & 0x001f) + (color1 & 0x001f)) / 3);
- cg = pal6bit((2 * (color0 & 0x07e0) + (color1 & 0x07e0)) / 3 >> 5);
- cr = pal5bit((2 * (color0 & 0xf800) + (color1 & 0xf800)) / 3 >> 11);
- return ((ca + (ca << 4)) << 24) | (cr << 16) | (cg << 8) | (cb);
- default:
- cb = pal5bit(((color0 & 0x001f) + 2 * (color1 & 0x001f)) / 3);
- cg = pal6bit(((color0 & 0x07e0) + 2 * (color1 & 0x07e0)) / 3 >> 5);
- cr = pal5bit(((color0 & 0xf800) + 2 * (color1 & 0xf800)) / 3 >> 11);
- return ((ca + (ca << 4)) << 24) | (cr << 16) | (cg << 8) | (cb);
- }
- case NV2A_TEX_FORMAT::A4R4G4B4:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- a4r4g4b4 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
- return convert_a4r4g4b4_a8r8g8b8(a4r4g4b4);
- case NV2A_TEX_FORMAT::A8:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- c = *(((uint8_t*)texture[number].buffer) + to); // get texel color
- return c << 24;
- case NV2A_TEX_FORMAT::A1R5G5B5:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- a1r5g5b5 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
- return convert_a1r5g5b5_a8r8g8b8(a1r5g5b5);
- case NV2A_TEX_FORMAT::R5G6B5:
- to = dilated0[texture[number].dilate][x] + dilated1[texture[number].dilate][y]; // offset of texel in texture memory
- r5g6b5 = *(((uint16_t *)texture[number].buffer) + to); // get texel color
- return 0xff000000 + convert_r5g6b5_r8g8b8(r5g6b5);
- case NV2A_TEX_FORMAT::R8G8B8_RECT:
- to = texture[number].rectangle_pitch*y + (x << 2);
- return *((uint32_t *)(((uint8_t *)texture[number].buffer) + to));
- case NV2A_TEX_FORMAT::A8R8G8B8_RECT:
- to = texture[number].rectangle_pitch*y + (x << 2);
- return *((uint32_t *)(((uint8_t *)texture[number].buffer) + to));
- case NV2A_TEX_FORMAT::DXT5:
- bx = x >> 2;
- by = y >> 2;
- x = x & 3;
- y = y & 3;
- to = (bx + by*(sizeu >> 2)) << 1;
- color0 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 4);
- color1 = *((uint16_t *)(((uint64_t *)texture[number].buffer) + to) + 5);
- codes = *((uint32_t *)(((uint64_t *)texture[number].buffer) + to) + 3);
- alpha0 = *((uint8_t *)(((uint64_t *)texture[number].buffer) + to) + 0);
- alpha1 = *((uint8_t *)(((uint64_t *)texture[number].buffer) + to) + 1);
- alphas = *(((uint64_t *)texture[number].buffer) + to);
- s = (y << 3) + (x << 1);
- sa = ((y << 2) + x) * 3;
- c = (codes >> s) & 3;
- ca = (alphas >> sa) & 7;
- ca = ca + (alpha0 > alpha1 ? 0 : 8);
- switch (ca) {
- case 0:
- ca = alpha0;
- break;
- case 1:
- ca = alpha1;
- break;
- case 2:
- ca = (6 * alpha0 + 1 * alpha1) / 7;
- break;
- case 3:
- ca = (5 * alpha0 + 2 * alpha1) / 7;
- break;
- case 4:
- ca = (4 * alpha0 + 3 * alpha1) / 7;
- break;
- case 5:
- ca = (3 * alpha0 + 4 * alpha1) / 7;
- break;
- case 6:
- ca = (2 * alpha0 + 5 * alpha1) / 7;
- break;
- case 7:
- ca = (1 * alpha0 + 6 * alpha1) / 7;
- break;
- case 8:
- ca = alpha0;
- break;
- case 9:
- ca = alpha1;
- break;
- case 10:
- ca = (4 * alpha0 + 1 * alpha1) / 5;
- break;
- case 11:
- ca = (3 * alpha0 + 2 * alpha1) / 5;
- break;
- case 12:
- ca = (2 * alpha0 + 3 * alpha1) / 5;
- break;
- case 13:
- ca = (1 * alpha0 + 4 * alpha1) / 5;
- break;
- case 14:
- ca = 0;
- break;
- case 15:
- ca = 255;
- break;
- }
- switch (c) {
- case 0:
- return (ca << 24) + convert_r5g6b5_r8g8b8(color0);
- case 1:
- return (ca << 24) + convert_r5g6b5_r8g8b8(color1);
- case 2:
- cb = pal5bit((2 * (color0 & 0x001f) + (color1 & 0x001f)) / 3);
- cg = pal6bit((2 * (color0 & 0x07e0) + (color1 & 0x07e0)) / 3 >> 5);
- cr = pal5bit((2 * (color0 & 0xf800) + (color1 & 0xf800)) / 3 >> 11);
- return (ca << 24) | (cr << 16) | (cg << 8) | (cb);
- default:
- cb = pal5bit(((color0 & 0x001f) + 2 * (color1 & 0x001f)) / 3);
- cg = pal6bit(((color0 & 0x07e0) + 2 * (color1 & 0x07e0)) / 3 >> 5);
- cr = pal5bit(((color0 & 0xf800) + 2 * (color1 & 0xf800)) / 3 >> 11);
- return (ca << 24) | (cr << 16) | (cg << 8) | (cb);
- }
- default:
- return 0xff00ff00;
- }
-}
-
-inline uint8_t *nv2a_renderer::read_pixel(int x, int y, int32_t c[4])
-{
- uint32_t offset;
- uint32_t color;
- uint32_t *addr;
- uint16_t *addr16;
- uint8_t *addr8;
-
- if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
- offset = (dilated0[dilate_rendertarget][x] + dilated1[dilate_rendertarget][y]) * bytespixel_rendertarget;
- else // type_rendertarget == LINEAR
- offset = pitch_rendertarget * y + x * bytespixel_rendertarget;
-#ifdef DEBUG_CHECKS
- if (offset >= size_rendertarget)
- {
- machine().logerror("Bad offset computed in read_pixel !\n");
- offset = 0;
- }
-#endif
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- addr16 = (uint16_t *)((uint8_t *)rendertarget + offset);
- color = *addr16;
- c[3] = 0xff;
- c[2] = pal5bit((color & 0xf800) >> 11);
- c[1] = pal6bit((color & 0x07e0) >> 5);
- c[0] = pal5bit(color & 0x1f);
- return (uint8_t *)addr16;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- addr = (uint32_t *)((uint8_t *)rendertarget + offset);
- color = *addr;
-
- c[3] = 0xff;
- c[2] = (color >> 16) & 255;
- c[1] = (color >> 8) & 255;
- c[0] = color & 255;
- return (uint8_t *)addr;
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- addr = (uint32_t *)((uint8_t *)rendertarget + offset);
- color = *addr;
- c[3] = color >> 24;
- c[2] = (color >> 16) & 255;
- c[1] = (color >> 8) & 255;
- c[0] = color & 255;
- return (uint8_t *)addr;
- case NV2A_COLOR_FORMAT::B8:
- addr8 = (uint8_t *)rendertarget + offset;
- c[0] = *addr8;
- c[1] = c[2] = 0;
- c[3] = 0xff;
- return addr8;
- default:
- return nullptr;
- }
- return nullptr;
-}
-
-void nv2a_renderer::write_pixel(int x, int y, uint32_t color, int z)
-{
- uint8_t *addr;
- uint32_t *daddr32;
- uint16_t *daddr16;
- uint32_t depthandstencil;
- int32_t c[4], fb[4], s[4], d[4], cc[4];
- uint32_t depth, stencil, stenc, stenv;
- uint32_t udepth;
- bool stencil_passed;
- bool depth_passed;
-
- if ((z > 0xffffff) || (z < 0) || (x < 0))
- return;
- udepth = (uint32_t)z;
- fb[3] = fb[2] = fb[1] = fb[0] = 0;
- addr = nullptr;
- if (color_mask != 0)
- addr = read_pixel(x, y, fb);
- if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
-#ifdef DEBUG_CHECKS
- if (((pitch_depthbuffer / 4) * y + x) >= size_depthbuffer)
- {
- machine().logerror("Bad depthbuffer offset computed in write_pixel !\n");
- return;
- }
-#endif
- daddr32 = depthbuffer + (pitch_depthbuffer / 4) * y + x;
- depthandstencil = *daddr32;
- depth = depthandstencil >> 8;
- stencil = depthandstencil & 255;
- daddr16 = nullptr;
- }
- else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
-#ifdef DEBUG_CHECKS
- if (((pitch_depthbuffer / 2) * y + x) >= size_depthbuffer)
- {
- machine().logerror("Bad depthbuffer offset computed in write_pixel !\n");
- return;
- }
-#endif
- daddr16 = (uint16_t *)depthbuffer + (pitch_depthbuffer / 2) * y + x;
- depthandstencil = *daddr16;
- depth = (depthandstencil << 8) | 0xff;
- stencil = 0;
- daddr32 = nullptr;
- }
- else {
- daddr32 = nullptr;
- daddr16 = nullptr;
- depth = 0xffffff;
- stencil = 0;
- }
- c[3] = color >> 24;
- c[2] = (color >> 16) & 255;
- c[1] = (color >> 8) & 255;
- c[0] = color & 255;
- cc[3] = blend_color >> 24;
- cc[2] = (blend_color >> 16) & 255;
- cc[1] = (blend_color >> 8) & 255;
- cc[0] = blend_color & 255;
- // ownership test and scissor test not done
- // alpha test
- if (alpha_test_enabled) {
- switch (alpha_func) {
- case NV2A_COMPARISON_OP::NEVER:
- return;
- case NV2A_COMPARISON_OP::ALWAYS:
- default:
- break;
- case NV2A_COMPARISON_OP::LESS:
- if (c[3] >= alpha_reference)
- return;
- break;
- case NV2A_COMPARISON_OP::LEQUAL:
- if (c[3] > alpha_reference)
- return;
- break;
- case NV2A_COMPARISON_OP::EQUAL:
- if (c[3] != alpha_reference)
- return;
- break;
- case NV2A_COMPARISON_OP::GEQUAL:
- if (c[3] < alpha_reference)
- return;
- break;
- case NV2A_COMPARISON_OP::GREATER:
- if (c[3] <= alpha_reference)
- return;
- break;
- case NV2A_COMPARISON_OP::NOTEQUAL:
- if (c[3] == alpha_reference)
- return;
- break;
- }
- }
- // stencil test
- stencil_passed = true;
- if (stencil_test_enabled) {
- stenc=stencil_mask & stencil_ref;
- stenv=stencil_mask & stencil;
- switch (stencil_func) {
- case NV2A_COMPARISON_OP::NEVER:
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::LESS:
- if (stenc >= stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::EQUAL:
- if (stenc != stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::LEQUAL:
- if (stenc > stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::GREATER:
- if (stenc <= stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::NOTEQUAL:
- if (stenc == stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::GEQUAL:
- if (stenc < stenv)
- stencil_passed = false;
- break;
- case NV2A_COMPARISON_OP::ALWAYS:
- default:
- break;
- }
- if (stencil_passed == false) {
- switch (stencil_op_fail) {
- case NV2A_STENCIL_OP::ZEROOP:
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::INVERTOP:
- stencil = stencil ^ 255;
- break;
- case NV2A_STENCIL_OP::KEEP:
- default:
- break;
- case NV2A_STENCIL_OP::REPLACE:
- stencil = stencil_ref;
- break;
- case NV2A_STENCIL_OP::INCR:
- if (stencil < 255)
- stencil++;
- break;
- case NV2A_STENCIL_OP::DECR:
- if (stencil > 0)
- stencil--;
- break;
- case NV2A_STENCIL_OP::INCR_WRAP:
- if (stencil < 255)
- stencil++;
- else
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::DECR_WRAP:
- if (stencil > 0)
- stencil--;
- else
- stencil = 255;
- break;
- }
- if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
- depthandstencil = (depth << 8) | stencil;
- *daddr32 = depthandstencil;
- }
- else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
- depthandstencil = depth >> 8;
- *daddr16 = (uint16_t)depthandstencil;
- }
- return;
- }
- }
- // depth buffer test
- depth_passed = true;
- if (depth_test_enabled) {
- switch (depth_function) {
- case NV2A_COMPARISON_OP::NEVER:
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::LESS:
- if (udepth >= depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::EQUAL:
- if (udepth != depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::LEQUAL:
- if (udepth > depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::GREATER:
- if (udepth <= depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::NOTEQUAL:
- if (udepth == depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::GEQUAL:
- if (udepth < depth)
- depth_passed = false;
- break;
- case NV2A_COMPARISON_OP::ALWAYS:
- default:
- break;
- }
- if (depth_passed == false) {
- switch (stencil_op_zfail) {
- case NV2A_STENCIL_OP::ZEROOP:
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::INVERTOP:
- stencil = stencil ^ 255;
- break;
- case NV2A_STENCIL_OP::KEEP:
- default:
- break;
- case NV2A_STENCIL_OP::REPLACE:
- stencil = stencil_ref;
- break;
- case NV2A_STENCIL_OP::INCR:
- if (stencil < 255)
- stencil++;
- break;
- case NV2A_STENCIL_OP::DECR:
- if (stencil > 0)
- stencil--;
- break;
- case NV2A_STENCIL_OP::INCR_WRAP:
- if (stencil < 255)
- stencil++;
- else
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::DECR_WRAP:
- if (stencil > 0)
- stencil--;
- else
- stencil = 255;
- break;
- }
- if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
- depthandstencil = (depth << 8) | stencil;
- *daddr32 = depthandstencil;
- }
- else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
- depthandstencil = depth >> 8;
- *daddr16 = (uint16_t)depthandstencil;
- }
- return;
- }
- switch (stencil_op_zpass) {
- case NV2A_STENCIL_OP::ZEROOP:
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::INVERTOP:
- stencil = stencil ^ 255;
- break;
- case NV2A_STENCIL_OP::KEEP:
- default:
- break;
- case NV2A_STENCIL_OP::REPLACE:
- stencil = stencil_ref;
- break;
- case NV2A_STENCIL_OP::INCR:
- if (stencil < 255)
- stencil++;
- break;
- case NV2A_STENCIL_OP::DECR:
- if (stencil > 0)
- stencil--;
- break;
- case NV2A_STENCIL_OP::INCR_WRAP:
- if (stencil < 255)
- stencil++;
- else
- stencil = 0;
- break;
- case NV2A_STENCIL_OP::DECR_WRAP:
- if (stencil > 0)
- stencil--;
- else
- stencil = 255;
- break;
- }
- }
- // blending
- if (blending_enabled) {
- switch (blend_function_source) {
- case NV2A_BLEND_FACTOR::ZERO:
- s[3] = s[2] = s[1] = s[0] = 0;
- break;
- case NV2A_BLEND_FACTOR::ONE:
- default:
- s[3] = s[2] = s[1] = s[0] = 255;
- break;
- case NV2A_BLEND_FACTOR::DST_COLOR:
- s[3] = fb[3];
- s[2] = fb[2];
- s[1] = fb[1];
- s[0] = fb[0];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_DST_COLOR:
- s[3] = fb[3] ^ 255;
- s[2] = fb[2] ^ 255;
- s[1] = fb[1] ^ 255;
- s[0] = fb[0] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::SRC_ALPHA:
- s[3] = s[2] = s[1] = s[0] = c[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_ALPHA:
- s[3] = s[2] = s[1] = s[0] = c[3] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::DST_ALPHA:
- s[3] = s[2] = s[1] = s[0] = fb[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_DST_ALPHA:
- s[3] = s[2] = s[1] = s[0] = fb[3] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::CONSTANT_COLOR:
- s[3] = cc[3];
- s[2] = cc[2];
- s[1] = cc[1];
- s[0] = cc[0];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_COLOR:
- s[3] = cc[3] ^ 255;
- s[2] = cc[2] ^ 255;
- s[1] = cc[1] ^ 255;
- s[0] = cc[0] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::CONSTANT_ALPHA:
- s[3] = s[2] = s[1] = s[0] = cc[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_ALPHA:
- s[3] = s[2] = s[1] = s[0] = cc[3] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::SRC_ALPHA_SATURATE:
- s[3] = 255;
- if (c[3] < (fb[3] ^ 255))
- s[2] = c[3];
- else
- s[2] = fb[3];
- s[1] = s[0] = s[2];
- break;
- }
- switch (blend_function_destination) {
- case NV2A_BLEND_FACTOR::ZERO:
- default:
- d[3] = d[2] = d[1] = d[0] = 0;
- break;
- case NV2A_BLEND_FACTOR::ONE:
- d[3] = d[2] = d[1] = d[0] = 255;
- break;
- case NV2A_BLEND_FACTOR::SRC_COLOR:
- d[3] = c[3];
- d[2] = c[2];
- d[1] = c[1];
- d[0] = c[0];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_COLOR:
- d[3] = c[3] ^ 255;
- d[2] = c[2] ^ 255;
- d[1] = c[1] ^ 255;
- d[0] = c[0] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::SRC_ALPHA:
- d[3] = d[2] = d[1] = d[0] = c[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_SRC_ALPHA:
- d[3] = d[2] = d[1] = d[0] = c[3] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::DST_ALPHA:
- d[3] = d[2] = d[1] = d[0] = fb[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_DST_ALPHA:
- d[3] = d[2] = d[1] = d[0] = fb[3] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::CONSTANT_COLOR:
- d[3] = cc[3];
- d[2] = cc[2];
- d[1] = cc[1];
- d[0] = cc[0];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_COLOR:
- d[3] = cc[3] ^ 255;
- d[2] = cc[2] ^ 255;
- d[1] = cc[1] ^ 255;
- d[0] = cc[0] ^ 255;
- break;
- case NV2A_BLEND_FACTOR::CONSTANT_ALPHA:
- d[3] = d[2] = d[1] = d[0] = cc[3];
- break;
- case NV2A_BLEND_FACTOR::ONE_MINUS_CONSTANT_ALPHA:
- d[3] = d[2] = d[1] = d[0] = cc[3] ^ 255;
- break;
- }
- switch (blend_equation) {
- case NV2A_BLEND_EQUATION::FUNC_ADD:
- c[3] = (c[3] * s[3] + fb[3] * d[3]) / 255;
- if (c[3] > 255)
- c[3] = 255;
- c[2] = (c[2] * s[2] + fb[2] * d[2]) / 255;
- if (c[2] > 255)
- c[2] = 255;
- c[1] = (c[1] * s[1] + fb[1] * d[1]) / 255;
- if (c[1] > 255)
- c[1] = 255;
- c[0] = (c[0] * s[0] + fb[0] * d[0]) / 255;
- if (c[0] > 255)
- c[0] = 255;
- break;
- case NV2A_BLEND_EQUATION::FUNC_SUBTRACT:
- c[3] = (c[3] * s[3] - fb[3] * d[3]) / 255;
- if (c[3] < 0)
- c[3] = 255;
- c[2] = (c[2] * s[2] - fb[2] * d[2]) / 255;
- if (c[2] < 0)
- c[2] = 255;
- c[1] = (c[1] * s[1] - fb[1] * d[1]) / 255;
- if (c[1] < 0)
- c[1] = 255;
- c[0] = (c[0] * s[0] - fb[0] * d[0]) / 255;
- if (c[0] < 0)
- c[0] = 255;
- break;
- case NV2A_BLEND_EQUATION::FUNC_REVERSE_SUBTRACT:
- c[3] = (fb[3] * d[3] - c[3] * s[3]) / 255;
- if (c[3] < 0)
- c[3] = 255;
- c[2] = (fb[2] * d[2] - c[2] * s[2]) / 255;
- if (c[2] < 0)
- c[2] = 255;
- c[1] = (fb[1] * d[1] - c[1] * s[1]) / 255;
- if (c[1] < 0)
- c[1] = 255;
- c[0] = (fb[0] * d[0] - c[0] * s[0]) / 255;
- if (c[0] < 0)
- c[0] = 255;
- break;
- case NV2A_BLEND_EQUATION::MIN:
- c[3] = s[3];
- if (d[3] < c[3])
- c[3] = d[3];
- c[2] = s[2];
- if (d[2] < c[2])
- c[2] = d[2];
- c[1] = s[1];
- if (d[1] < c[1])
- c[1] = d[1];
- c[0] = s[0];
- if (d[0] < c[0])
- c[0] = d[0];
- break;
- case NV2A_BLEND_EQUATION::MAX:
- c[3] = s[3];
- if (d[3] > c[3])
- c[3] = d[3];
- c[2] = s[2];
- if (d[2] > c[2])
- c[2] = d[2];
- c[1] = s[1];
- if (d[1] > c[1])
- c[1] = d[1];
- c[0] = s[0];
- if (d[0] > c[0])
- c[0] = d[0];
- break;
- }
- }
- // dithering not done
- // logical operation
- if (logical_operation_enabled) {
- switch (logical_operation) {
- case NV2A_LOGIC_OP::CLEAR:
- c[3] = 0;
- c[2] = 0;
- c[1] = 0;
- c[0] = 0;
- break;
- case NV2A_LOGIC_OP::AND:
- c[3] = c[3] & fb[3];
- c[2] = c[2] & fb[2];
- c[1] = c[1] & fb[1];
- c[0] = c[0] & fb[0];
- break;
- case NV2A_LOGIC_OP::AND_REVERSE:
- c[3] = c[3] & (fb[3] ^ 255);
- c[2] = c[2] & (fb[2] ^ 255);
- c[1] = c[1] & (fb[1] ^ 255);
- c[0] = c[0] & (fb[0] ^ 255);
- break;
- case NV2A_LOGIC_OP::COPY:
- default:
- break;
- case NV2A_LOGIC_OP::AND_INVERTED:
- c[3] = (c[3] ^ 255) & fb[3];
- c[2] = (c[2] ^ 255) & fb[2];
- c[1] = (c[1] ^ 255) & fb[1];
- c[0] = (c[0] ^ 255) & fb[0];
- break;
- case NV2A_LOGIC_OP::NOOP:
- c[3] = fb[3];
- c[2] = fb[2];
- c[1] = fb[1];
- c[0] = fb[0];
- break;
- case NV2A_LOGIC_OP::XOR:
- c[3] = c[3] ^ fb[3];
- c[2] = c[2] ^ fb[2];
- c[1] = c[1] ^ fb[1];
- c[0] = c[0] ^ fb[0];
- break;
- case NV2A_LOGIC_OP::OR:
- c[3] = c[3] | fb[3];
- c[2] = c[2] | fb[2];
- c[1] = c[1] | fb[1];
- c[0] = c[0] | fb[0];
- break;
- case NV2A_LOGIC_OP::NOR:
- c[3] = (c[3] | fb[3]) ^ 255;
- c[2] = (c[2] | fb[2]) ^ 255;
- c[1] = (c[1] | fb[1]) ^ 255;
- c[0] = (c[0] | fb[0]) ^ 255;
- break;
- case NV2A_LOGIC_OP::EQUIV:
- c[3] = (c[3] ^ fb[3]) ^ 255;
- c[2] = (c[2] ^ fb[2]) ^ 255;
- c[1] = (c[1] ^ fb[1]) ^ 255;
- c[0] = (c[0] ^ fb[0]) ^ 255;
- break;
- case NV2A_LOGIC_OP::INVERT:
- c[3] = fb[3] ^ 255;
- c[2] = fb[2] ^ 255;
- c[1] = fb[1] ^ 255;
- c[0] = fb[0] ^ 255;
- break;
- case NV2A_LOGIC_OP::OR_REVERSE:
- c[3] = c[3] | (fb[3] ^ 255);
- c[2] = c[2] | (fb[2] ^ 255);
- c[1] = c[1] | (fb[1] ^ 255);
- c[0] = c[0] | (fb[0] ^ 255);
- break;
- case NV2A_LOGIC_OP::COPY_INVERTED:
- c[3] = c[3] ^ 255;
- c[2] = c[2] ^ 255;
- c[1] = c[1] ^ 255;
- c[0] = c[0] ^ 255;
- break;
- case NV2A_LOGIC_OP::OR_INVERTED:
- c[3] = (c[3] ^ 255) | fb[3];
- c[2] = (c[2] ^ 255) | fb[2];
- c[1] = (c[1] ^ 255) | fb[1];
- c[0] = (c[0] ^ 255) | fb[0];
- break;
- case NV2A_LOGIC_OP::NAND:
- c[3] = (c[3] & fb[3]) ^ 255;
- c[2] = (c[2] & fb[2]) ^ 255;
- c[1] = (c[1] & fb[1]) ^ 255;
- c[0] = (c[0] & fb[0]) ^ 255;
- break;
- case NV2A_LOGIC_OP::SET:
- c[3] = 255;
- c[2] = 255;
- c[1] = 255;
- c[0] = 255;
- break;
- }
- }
- if (color_mask != 0) {
- uint32_t ct,ft,w;
-
- ct = ((uint32_t)c[3] << 24) | ((uint32_t)c[2] << 16) | ((uint32_t)c[1] << 8) | (uint32_t)c[0];
- ft = ((uint32_t)fb[3] << 24) | ((uint32_t)fb[2] << 16) | ((uint32_t)fb[1] << 8) | (uint32_t)fb[0];
- w = (ft & ~color_mask) | (ct & color_mask);
-
-/* for debugging
- if (w == 0x94737d7b)
- x++;
-*/
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- w = ((w >> 8) & 0xf800) + ((w >> 5) & 0x7e0) + ((w >> 3) & 0x1f);
- *((uint16_t *)addr) = (uint16_t)w;
- break;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- *((uint32_t *)addr) = w;
- break;
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- *((uint32_t *)addr) = w;
- break;
- case NV2A_COLOR_FORMAT::B8:
- *addr = (uint8_t)w;
- break;
- default:
- return;
- }
- }
- if (depth_write_enabled)
- depth = udepth;
- if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z24S8) {
- depthandstencil = (depth << 8) | stencil;
- *daddr32 = depthandstencil;
- }
- else if (depthformat_rendertarget == NV2A_RT_DEPTH_FORMAT::Z16) {
- depthandstencil = depth >> 8;
- *daddr16 = (uint16_t)depthandstencil;
- }
-}
-
-void nv2a_renderer::render_color(int32_t scanline, const nv2a_rasterizer::extent_t &extent, const nvidia_object_data &objectdata, int threadid)
-{
- int x, lx;
-
- lx = limits_rendertarget.right();
- if ((extent.startx < 0) && (extent.stopx <= 0))
- return;
- if ((extent.startx > lx) && (extent.stopx > lx))
- return;
- x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
- if (extent.stopx > lx)
- x = x - (extent.stopx - lx - 1);
- x--;
- while (x >= 0) {
- double zf;
- uint32_t a8r8g8b8;
- int z;
- int ca, cr, cg, cb;
- int xp = extent.startx + x; // x coordinate of current pixel
-
- z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
- zf = (extent.param[(int)VERTEX_PARAMETER::PARAM_1W].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_1W].dpdx);
- zf = 1.0f / zf;
- cb = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].dpdx)) * zf * 255.0f;
- cg = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].dpdx)) * zf * 255.0f;
- cr = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].dpdx)) * zf * 255.0f;
- ca = ((extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].dpdx)) * zf * 255.0f;
- if (cb > 255)
- cb = 255;
- if (cb < 0)
- cb = 0;
- if (cg > 255)
- cg = 255;
- if (cg < 0)
- cg = 0;
- if (cr > 255)
- cr = 255;
- if (cr < 0)
- cr = 0;
- if (ca > 255)
- ca = 255;
- if (ca < 0)
- ca = 0;
- a8r8g8b8 = (ca << 24) | (cr << 16) | (cg << 8) | cb; // pixel color obtained by interpolating the colors of the vertices
- write_pixel(xp, scanline, a8r8g8b8, z);
- x--;
- }
-}
-
-void nv2a_renderer::render_texture_simple(int32_t scanline, const nv2a_rasterizer::extent_t &extent, const nvidia_object_data &objectdata, int threadid)
-{
- int x, lx;
- uint32_t a8r8g8b8;
-
- if (!objectdata.data->texture[0].enabled) {
- return;
- }
- lx = limits_rendertarget.right();
- if ((extent.startx < 0) && (extent.stopx <= 0))
- return;
- if ((extent.startx > lx) && (extent.stopx > lx))
- return;
- x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
- if (extent.stopx > lx)
- x = x - (extent.stopx - lx - 1);
- x--;
- while (x >= 0) {
- float zf;
- double spf, tpf;
- //double rpf, qpf; // disabled to remove "set but not used" warning
- int sp, tp;
- int z;
- int xp = extent.startx + x; // x coordinate of current pixel
-
- z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
- zf = (extent.param[(int)VERTEX_PARAMETER::PARAM_1W].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_1W].dpdx);
- zf = 1.0f / zf;
- spf = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S].dpdx) * zf;
- tpf = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T].dpdx) * zf;
- //rpf = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R].dpdx) * zf;
- //qpf = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q].dpdx) * zf;
- if (objectdata.data->texture[0].rectangle == false) {
- sp = spf * (double)(objectdata.data->texture[0].sizes - 1); // x coordinate of texel in texture
- tp = tpf * (double)(objectdata.data->texture[0].sizet - 1); // y coordinate of texel in texture
- }
- else {
- sp = spf;
- tp = tpf;
- }
- a8r8g8b8 = texture_get_texel(0, sp, tp);
- write_pixel(xp, scanline, a8r8g8b8, z);
- x--;
- }
-}
-
-void nv2a_renderer::render_register_combiners(int32_t scanline, const nv2a_rasterizer::extent_t &extent, const nvidia_object_data &objectdata, int threadid)
-{
- int x, lx, xp;
- int tc[4];
- float colorf[7][4];
- uint32_t color[6];
- uint32_t a8r8g8b8;
- int z;
- int n;
-
- color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0;
-
- lx = limits_rendertarget.right();
- if ((extent.startx < 0) && (extent.stopx <= 0))
- return;
- if ((extent.startx > lx) && (extent.stopx > lx))
- return;
- x = extent.stopx - extent.startx; // number of pixels to draw (start inclusive, end exclusive)
- if (extent.stopx > lx)
- x = x - (extent.stopx - lx - 1);
- x--;
- while (x >= 0) {
- float zf;
-
- xp = extent.startx + x;
- // 1: fetch data
- // 1.1: interpolated color from vertices
- z = (extent.param[(int)VERTEX_PARAMETER::PARAM_Z].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_Z].dpdx);
- zf = (extent.param[(int)VERTEX_PARAMETER::PARAM_1W].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_1W].dpdx);
- zf = 1.0f / zf;
- colorf[0][0] = (extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_R].dpdx) * zf;
- colorf[0][1] = (extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_G].dpdx) * zf;
- colorf[0][2] = (extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_B].dpdx) * zf;
- colorf[0][3] = (extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_COLOR_A].dpdx) * zf;
- colorf[1][0] = (extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_R].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_R].dpdx) * zf;
- colorf[1][1] = (extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_G].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_G].dpdx) * zf;
- colorf[1][2] = (extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_B].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_B].dpdx) * zf;
- colorf[1][3] = (extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_A].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_A].dpdx) * zf;
- // 1.2: coordinates for each of the 4 possible textures
- for (n = 0; n < 4; n++) {
- colorf[n + 2][0] = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S + n * 4].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S + n * 4].dpdx) * zf;
- colorf[n + 2][1] = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T + n * 4].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T + n * 4].dpdx) * zf;
- colorf[n + 2][2] = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R + n * 4].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R + n * 4].dpdx) * zf;
- colorf[n + 2][3] = (extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q + n * 4].start + (double)x * extent.param[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q + n * 4].dpdx) * zf;
- }
- // 1.3: fog
- combiner_argb8_float(fog_color, colorf[6]);
- colorf[6][3] = 1.0f; // should it be from the ofog output of the vertex shader ?
- // 1.4: colors from textures
- for (n = 0; n < 4; n++) {
- if (texture[n].mode == 1) {
- if (texture[n].rectangle == false) {
- tc[0] = colorf[n + 2][0] * (float)(objectdata.data->texture[n].sizes - 1);
- tc[1] = colorf[n + 2][1] * (float)(objectdata.data->texture[n].sizet - 1);
- }
- else {
- tc[0] = colorf[n + 2][0];
- tc[1] = colorf[n + 2][1];
- }
- a8r8g8b8 = texture_get_texel(n, tc[0], tc[1]);
- combiner_argb8_float(a8r8g8b8, colorf[n + 2]);
- }
- else if (texture[n].mode == 4)
- ; // nothing
- else
- combiner_argb8_float(0xff000000, colorf[n + 2]);
- }
- // 2: compute
- // 2.1: initialize
- combiner_initialize_registers(threadid, colorf);
- // 2.2: general cmbiner stages
- for (n = 0; n < combiner.setup.stages; n++) {
- // 2.2.1 initialize
- combiner_initialize_stage(threadid, n);
- // 2.2.2 map inputs
- combiner_map_stage_input(threadid, n);
- // 2.2.3 compute possible outputs
- combiner_compute_rgb_outputs(threadid, n);
- combiner_compute_alpha_outputs(threadid, n);
- // 2.2.4 map outputs to registers
- combiner_map_stage_output(threadid, n);
- }
- // 2.3: final cmbiner stage
- combiner_initialize_final(threadid);
- combiner_map_final_input(threadid);
- combiner_final_output(threadid);
- a8r8g8b8 = combiner_float_argb8(combiner.work[threadid].output);
- // 3: write pixel
- write_pixel(xp, scanline, a8r8g8b8, z);
- x--;
- }
-}
-
-#if 0
-const char *rc_mapping_str[] = {
- "UNSIGNED_IDENTITY",
- "UNSIGNED_INVERT",
- "EXPAND_NORMAL",
- "EXPAND_NEGATE",
- "HALF_BIAS_NORMAL",
- "HALF_BIAS_NEGATE",
- "SIGNED_IDENTITY",
- "SIGNED_NEGATE"
-};
-
-const char *rc_usage_rgb_str[] = {
- "RGB",
- "ALPHA"
-};
-
-const char *rc_usage_alpha_str[] = {
- "BLUE",
- "ALPHA"
-};
-
-const char *rc_variable_str[] = {
- "ZERO",
- "CONSTANT_COLOR0",
- "CONSTANT_COLOR1",
- "FOG",
- "PRIMARY_COLOR",
- "SECONDARY_COLOR",
- "???",
- "???",
- "TEXTURE0",
- "TEXTURE1",
- "TEXTURE2",
- "TEXTURE3",
- "SPARE0",
- "SPARE1",
- "SPARE0_PLUS_SECONDARY_COLOR",
- "E_TIMES_F"
-};
-
-const char *rc_bias_str[] = {
- "NONE",
- "BIAS_BY_NEGATIVE_ONE_HALF"
-};
-
-const char *rc_scale_str[] = {
- "NONE",
- "SCALE_BY_TWO",
- "SCALE_BY_FOUR",
- "SCALE_BY_ONE_HALF"
-};
-
-/* Dump the current setup of the register combiners */
-void dumpcombiners(uint32_t *m)
-{
- int a, b, n, v;
-
- n = m[0x1e60 / 4] & 0xf;
- printf("Combiners active: %d\n\r", n);
- for (a = 0; a < n; a++) {
- printf("Combiner %d\n\r", a + 1);
- printf(" RC_IN_ALPHA %08X\n\r", m[0x0260 / 4 + a]);
- for (b = 24; b >= 0; b = b - 8) {
- v = (m[0x0260 / 4 + a] >> b) & 0xf;
- printf(" %c_INPUT %s\n\r", 'A' + 3 - b / 8, rc_variable_str[v]);
- v = (m[0x0260 / 4 + a] >> (b + 4)) & 1;
- printf(" %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - b / 8, rc_usage_alpha_str[v]);
- v = (m[0x0260 / 4 + a] >> (b + 5)) & 7;
- printf(" %c_MAPPING %s\n\r", 'A' + 3 - b / 8, rc_mapping_str[v]);
- }
- printf(" RC_IN_RGB %08X\n\r", m[0x0ac0 / 4 + a]);
- for (b = 24; b >= 0; b = b - 8) {
- v = (m[0x0ac0 / 4 + a] >> b) & 0xf;
- printf(" %c_INPUT %s\n\r", 'A' + 3 - b / 8, rc_variable_str[v]);
- v = (m[0x0ac0 / 4 + a] >> (b + 4)) & 1;
- printf(" %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - b / 8, rc_usage_rgb_str[v]);
- v = (m[0x0ac0 / 4 + a] >> (b + 5)) & 7;
- printf(" %c_MAPPING %s\n\r", 'A' + 3 - b / 8, rc_mapping_str[v]);
- }
- printf(" RC_OUT_ALPHA %08X\n\r", m[0x0aa0 / 4 + a]);
- v = m[0x0aa0 / 4 + a] & 0xf;
- printf(" CD_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x0aa0 / 4 + a] >> 4) & 0xf;
- printf(" AB_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x0aa0 / 4 + a] >> 8) & 0xf;
- printf(" SUM_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x0aa0 / 4 + a] >> 12) & 1;
- printf(" CD_DOT_PRODUCT %d\n\r", v);
- v = (m[0x0aa0 / 4 + a] >> 13) & 1;
- printf(" AB_DOT_PRODUCT %d\n\r", v);
- v = (m[0x0aa0 / 4 + a] >> 14) & 1;
- printf(" MUX_SUM %d\n\r", v);
- v = (m[0x0aa0 / 4 + a] >> 15) & 1;
- printf(" BIAS %s\n\r", rc_bias_str[v]);
- v = (m[0x0aa0 / 4 + a] >> 16) & 3;
- printf(" SCALE %s\n\r", rc_scale_str[v]);
- //v=(m[0x0aa0/4+a] >> 27) & 7;
- printf(" RC_OUT_RGB %08X\n\r", m[0x1e40 / 4 + a]);
- v = m[0x1e40 / 4 + a] & 0xf;
- printf(" CD_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x1e40 / 4 + a] >> 4) & 0xf;
- printf(" AB_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x1e40 / 4 + a] >> 8) & 0xf;
- printf(" SUM_OUTPUT %s\n\r", rc_variable_str[v]);
- v = (m[0x1e40 / 4 + a] >> 12) & 1;
- printf(" CD_DOT_PRODUCT %d\n\r", v);
- v = (m[0x1e40 / 4 + a] >> 13) & 1;
- printf(" AB_DOT_PRODUCT %d\n\r", v);
- v = (m[0x1e40 / 4 + a] >> 14) & 1;
- printf(" MUX_SUM %d\n\r", v);
- v = (m[0x1e40 / 4 + a] >> 15) & 1;
- printf(" BIAS %s\n\r", rc_bias_str[v]);
- v = (m[0x1e40 / 4 + a] >> 16) & 3;
- printf(" SCALE %s\n\r", rc_scale_str[v]);
- //v=(m[0x1e40/4+a] >> 27) & 7;
- printf("\n\r");
- }
- printf("Combiner final %08X %08X\n\r", m[0x0288 / 4], m[0x028c / 4]);
- for (a = 24; a >= 0; a = a - 8) {
- n = (m[0x0288 / 4] >> a) & 0xf;
- printf(" %c_INPUT %s\n\r", 'A' + 3 - a / 8, rc_variable_str[n]);
- n = (m[0x0288 / 4] >> (a + 4)) & 1;
- printf(" %c_COMPONENT_USAGE %s\n\r", 'A' + 3 - a / 8, rc_usage_rgb_str[n]);
- n = (m[0x0288 / 4] >> (a + 5)) & 7;
- printf(" %c_MAPPING %s\n\r", 'A' + 3 - a / 8, rc_mapping_str[n]);
- }
- for (a = 24; a >= 8; a = a - 8) {
- n = (m[0x028c / 4] >> a) & 0xf;
- printf(" %c_INPUT %s\n\r", 'E' + 3 - a / 8, rc_variable_str[n]);
- n = (m[0x028c / 4] >> (a + 4)) & 1;
- printf(" %c_COMPONENT_USAGE %s\n\r", 'E' + 3 - a / 8, rc_usage_rgb_str[n]);
- n = (m[0x028c / 4] >> (a + 5)) & 7;
- printf(" %c_MAPPING %s\n\r", 'E' + 3 - a / 8, rc_mapping_str[n]);
- }
- n = (m[0x028c / 4] >> 7) & 1;
- printf(" color sum clamp: %d\n\r", n);
-}
-#endif
-
-void nv2a_renderer::extract_packed_float(uint32_t data, float &first, float &second, float &third)
-{
- float f1, f2, f3;
- int p1, p2, p3;
-
- p1 = data & 0x7ff;
- if (p1 & 0x400)
- f1 = (float)(p1 - 0x800) / 1023.0;
- else
- f1 = (float)p1 / 1023.0;
- p2 = (data >> 11) & 0x7ff;
- if (p2 & 0x400)
- f2 = (float)(p2 - 0x800) / 1023.0;
- else
- f2 = (float)p2 / 1023.0;
- p3 = (data >> 22) & 0x3ff;
- if (p3 & 0x200)
- f3 = (float)(p3 - 0x400) / 511.0;
- else
- f3 = (float)p3 / 511.0;
- first = f1;
- second = f2;
- third = f3;
-}
-
-void nv2a_renderer::read_vertex(address_space &space, offs_t address, vertex_nv &vertex, int attrib)
-{
- uint32_t u;
-
- switch (vertexbuffer.type[attrib])
- {
- case 0x02: // none
- return;
- case 0x12: // float1
- vertex.attribute[attrib].iv[0] = space.read_dword(address + 0);
- vertex.attribute[attrib].fv[1] = 0;
- vertex.attribute[attrib].fv[2] = 0;
- vertex.attribute[attrib].fv[3] = 1.0;
- break;
- case 0x16: // normpacked3
- u = space.read_dword(address + 0);
- extract_packed_float(u, vertex.attribute[attrib].fv[0], vertex.attribute[attrib].fv[1], vertex.attribute[attrib].fv[2]);
- vertex.attribute[attrib].fv[3] = 1.0;
- break;
- case 0x22: // float2
- vertex.attribute[attrib].iv[0] = space.read_dword(address + 0);
- vertex.attribute[attrib].iv[1] = space.read_dword(address + 4);
- vertex.attribute[attrib].fv[2] = 0;
- vertex.attribute[attrib].fv[3] = 1.0;
- break;
- case 0x32: // float3
- vertex.attribute[attrib].iv[0] = space.read_dword(address + 0);
- vertex.attribute[attrib].iv[1] = space.read_dword(address + 4);
- vertex.attribute[attrib].iv[2] = space.read_dword(address + 8);
- vertex.attribute[attrib].fv[3] = 1.0;
- break;
- case 0x40: // d3dcolor
- u = space.read_dword(address + 0);
- // aarrggbb -> (rr, gg, bb, aa)
- vertex.attribute[attrib].fv[2] = (u & 0xff) / 255.0;
- u = u >> 8;
- vertex.attribute[attrib].fv[1] = (u & 0xff) / 255.0;
- u = u >> 8;
- vertex.attribute[attrib].fv[0] = (u & 0xff) / 255.0;
- u = u >> 8;
- vertex.attribute[attrib].fv[3] = (u & 0xff) / 255.0;
- break;
- case 0x42: // float4
- vertex.attribute[attrib].iv[0] = space.read_dword(address + 0);
- vertex.attribute[attrib].iv[1] = space.read_dword(address + 4);
- vertex.attribute[attrib].iv[2] = space.read_dword(address + 8);
- vertex.attribute[attrib].iv[3] = space.read_dword(address + 12);
- break;
- default:
- machine().logerror("Yet unsupported vertex data type %x\n\r", vertexbuffer.type[attrib]);
- return;
- }
-}
-
-/* Read vertices data from system memory. Method 0x1800 and 0x1808 */
-int nv2a_renderer::read_vertices_0x180x(address_space &space, int destination, uint32_t address, int limit)
-{
- uint32_t m, n;
- int a, b;
-
- n = destination;
- for (m = 0; m < limit; m++) {
- memcpy(&vertex_software[n], &persistvertexattr, sizeof(persistvertexattr));
- b = vertexbuffer.enabled;
- for (a = 0; a < 16; a++) {
- if (b & 1) {
- read_vertex(space, vertexbuffer.address[a] + vertex_indexes[indexesleft_first] * vertexbuffer.stride[a], vertex_software[n], a);
- }
- b = b >> 1;
- }
- n = (n + 1) & 1023;
- indexesleft_first = (indexesleft_first + 1) & 1023;
- indexesleft_count--;
- }
- return limit;
-}
-
-/* Read vertices data from system memory. Method 0x1810 */
-int nv2a_renderer::read_vertices_0x1810(address_space &space, int destination, int offset, int limit)
-{
- uint32_t m, n;
- int a, b;
-
- n = destination;
- for (m = 0; m < limit; m++) {
- memcpy(&vertex_software[n], &persistvertexattr, sizeof(persistvertexattr));
- b = vertexbuffer.enabled;
- for (a = 0; a < 16; a++) {
- if (b & 1) {
- read_vertex(space, vertexbuffer.address[a] + (m + offset) * vertexbuffer.stride[a], vertex_software[n], a);
- }
- b = b >> 1;
- }
- n = (n + 1) & 1023;
- }
- return m;
-}
-
-/* Read vertices data from system memory. Method 0x1818 */
-int nv2a_renderer::read_vertices_0x1818(address_space &space, int destination, uint32_t address, int limit)
-{
- uint32_t m, n, vwords;
- int a, b;
-
- n = destination;
- vwords = vertexbuffer.offset[16];
- for (m = 0; m < limit; m++) {
- memcpy(&vertex_software[n], &persistvertexattr, sizeof(persistvertexattr));
- b = vertexbuffer.enabled;
- for (a = 0; a < 16; a++) {
- if (b & 1) {
- read_vertex(space, address + vertexbuffer.offset[a] * 4, vertex_software[n], a);
- }
- b = b >> 1;
- }
- n = (n + 1) & 1023;
- address = address + vwords * 4;
- }
- return (int)(m*vwords);
-}
-
-void nv2a_renderer::compute_supersample_factors(float &horizontal, float &vertical)
-{
- float mx, my;
-
- mx = 1;
- my = 1;
- switch (((antialias_control & 1) << 2) | antialiasing_rendertarget)
- {
- case 0:
- mx = my = 1;
- break;
- case 1:
- mx = 2; my = 1;
- break;
- case 2:
- mx = my = 2;
- break;
- case 4:
- mx = my = 1;
- break;
- case 5:
- mx = 2;
- my = 1;
- break;
- case 6:
- mx = 2;
- my = 2;
- break;
- default:
- mx = my = 1;
- }
- horizontal = mx;
- vertical = my;
-}
-
-void nv2a_renderer::convert_vertices(vertex_nv *source, nv2avertex_t *destination)
-{
- vertex_nv vert;
- int u;
- float v[4];
- double c;
-
- // take each vertex with its attributes and obtain data for drawing
- // should use either the vertex program or transformation matrices
- if (vertex_pipeline == 4) {
- // transformation matrices
- // this part needs more testing
- for (int i = 0; i < 4; i++) {
- v[i] = 0;
- for (int j = 0; j < 4; j++)
- v[i] += matrix.composite[i][j] * source->attribute[0].fv[j];
- };
- destination->w = v[3];
- destination->x = (v[0] / v[3]) * supersample_factor_x; // source->attribute[0].fv[0];
- destination->y = (v[1] / v[3]) * supersample_factor_y; // source->attribute[0].fv[1];
- c = v[3];
- if (c == 0)
- c = FLT_MIN;
- c = 1.0f / c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_1W] = c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_Z] = v[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_R] = source->attribute[3].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_G] = source->attribute[3].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_B] = source->attribute[3].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_A] = source->attribute[3].fv[3] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_R] = source->attribute[4].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_G] = source->attribute[4].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_B] = source->attribute[4].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_A] = source->attribute[4].fv[3] * c;
- for (u = 0; u < 4; u++) {
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S + u * 4] = source->attribute[9 + u].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T + u * 4] = source->attribute[9 + u].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R + u * 4] = source->attribute[9 + u].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q + u * 4] = source->attribute[9 + u].fv[3] * c;
- }
- }
- else {
- // vertex program
- // run vertex program
- vertexprogram.exec.process(vertexprogram.start_instruction, source, &vert, 1);
- // the output of the vertex program has the perspective divide, viewport scale and offset already applied
- // copy data for poly.h
- destination->w = vert.attribute[0].fv[3];
- destination->x = (vert.attribute[0].fv[0] - 0.53125f) * supersample_factor_x;
- destination->y = (vert.attribute[0].fv[1] - 0.53125f) * supersample_factor_y;
- c = destination->w;
- if (c == 0)
- c = FLT_MIN;
- c = 1.0f / c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_1W] = c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_Z] = vert.attribute[0].fv[2]; // already divided by w
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_R] = vert.attribute[3].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_G] = vert.attribute[3].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_B] = vert.attribute[3].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_COLOR_A] = vert.attribute[3].fv[3] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_R] = vert.attribute[4].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_G] = vert.attribute[4].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_B] = vert.attribute[4].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_SECONDARY_COLOR_A] = vert.attribute[4].fv[3] * c;
- for (u = 0; u < 4; u++) {
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_S + u * 4] = vert.attribute[9 + u].fv[0] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_T + u * 4] = vert.attribute[9 + u].fv[1] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_R + u * 4] = vert.attribute[9 + u].fv[2] * c;
- destination->p[(int)VERTEX_PARAMETER::PARAM_TEXTURE0_Q + u * 4] = vert.attribute[9 + u].fv[3] * c;
- }
- }
-}
-
-void nv2a_renderer::clear_render_target(int what, uint32_t value)
-{
- int xi, yi, xf, yf;
- int x, y;
- uint32_t color;
- uint8_t *addr;
- uint32_t mask;
- uint32_t offset;
-
- if (what == 0)
- return;
- mask = 0;
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- if (what & 1)
- mask = 0x1f;
- if (what & 2)
- mask = mask | 0x07e0;
- if (what & 4)
- mask = mask | 0xf800;
- break;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- for (x = 3; x >= 0; x--) {
- if (what & 8)
- mask = (mask << 8) | 255;
- what = what << 1;
- }
- break;
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- for (x = 3; x >= 0; x--) {
- if (what & 8)
- mask = (mask << 8) | 255;
- what = what << 1;
- }
- break;
- case NV2A_COLOR_FORMAT::B8:
- if (what & 1)
- mask = 255;
- break;
- default:
- return;
- }
- xi = clear_rendertarget.left()*supersample_factor_x;
- yi = clear_rendertarget.top()*supersample_factor_y;
- xf = clear_rendertarget.right()*supersample_factor_x;
- yf = clear_rendertarget.bottom()*supersample_factor_y;
- if ((xi < limits_rendertarget.left()) && (xf < limits_rendertarget.left()))
- return;
- if ((xi > limits_rendertarget.right()) && (xf > limits_rendertarget.right()))
- return;
- if ((yi < limits_rendertarget.top()) && (yf < limits_rendertarget.top()))
- return;
- if ((yi > limits_rendertarget.bottom()) && (yf > limits_rendertarget.bottom()))
- return;
- if (xi < limits_rendertarget.left())
- xi = limits_rendertarget.left();
- if (xf > limits_rendertarget.right())
- xf = limits_rendertarget.right();
- if (yi < limits_rendertarget.top())
- yi = limits_rendertarget.top();
- if (yf > limits_rendertarget.bottom())
- yf = limits_rendertarget.bottom();
- if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
- offset = (dilated0[dilate_rendertarget][xf] + dilated1[dilate_rendertarget][yf]) * bytespixel_rendertarget;
- else // type_rendertarget == LINEAR
- offset = pitch_rendertarget * yf + xf * bytespixel_rendertarget;
- addr = (uint8_t *)rendertarget + offset;
- if ((addr < basemempointer) || (addr > topmempointer))
- {
- machine().logerror("Bad memory pointer computed in clear_render_target !\n");
- return;
- }
-
- for (y = yi; y <= yf; y++)
- for (x = xi; x <= xf; x++) {
- if (type_rendertarget == NV2A_RT_TYPE::SWIZZLED)
- offset = (dilated0[dilate_rendertarget][x] + dilated1[dilate_rendertarget][y]) * bytespixel_rendertarget;
- else // type_rendertarget == LINEAR
- offset = pitch_rendertarget * y + x * bytespixel_rendertarget;
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- addr = (uint8_t *)rendertarget + offset;
- color = *((uint16_t *)addr);
- break;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- addr = (uint8_t *)rendertarget + offset;
- color = *((uint32_t *)addr);
- break;
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- addr = (uint8_t *)rendertarget + offset;
- color = *((uint32_t *)addr);
- break;
- case NV2A_COLOR_FORMAT::B8:
- addr = (uint8_t *)rendertarget + offset;
- color = *addr;
- break;
- default:
- return;
- }
- color = (color & ~mask) | (value & mask);
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- *((uint16_t *)addr) = color;
- break;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- *((uint32_t *)addr) = color;
- break;
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- *((uint32_t *)addr) = color;
- break;
- case NV2A_COLOR_FORMAT::B8:
- *addr = color;
- break;
- default:
- return;
- }
- }
-#ifdef LOG_NV2A
- printf("clearscreen\n\r");
-#endif
-}
-
-void nv2a_renderer::clear_depth_buffer(int what, uint32_t value)
-{
- int xi, yi, xf, yf;
- int x, y;
- uint32_t color;
- uint8_t *addr;
- uint32_t mask;
- uint32_t offset;
- uint32_t bpp;
-
- if (what == 0)
- return;
- mask = 0;
- switch (depthformat_rendertarget) {
- case NV2A_RT_DEPTH_FORMAT::Z24S8:
- if (what & 1)
- mask = 0xffffff00;
- if (what & 2)
- mask = mask | 0xff;
- bpp = 4;
- break;
- case NV2A_RT_DEPTH_FORMAT::Z16:
- if (what & 1)
- mask = 0xffff;
- bpp = 2;
- break;
- default:
- return;
- }
- xi = clear_rendertarget.left()*supersample_factor_x;
- yi = clear_rendertarget.top()*supersample_factor_y;
- xf = clear_rendertarget.right()*supersample_factor_x;
- yf = clear_rendertarget.bottom()*supersample_factor_y;
- if ((xi < limits_rendertarget.left()) && (xf < limits_rendertarget.left()))
- return;
- if ((xi > limits_rendertarget.right()) && (xf > limits_rendertarget.right()))
- return;
- if ((yi < limits_rendertarget.top()) && (yf < limits_rendertarget.top()))
- return;
- if ((yi > limits_rendertarget.bottom()) && (yf > limits_rendertarget.bottom()))
- return;
- if (xi < limits_rendertarget.left())
- xi = limits_rendertarget.left();
- if (xf > limits_rendertarget.right())
- xf = limits_rendertarget.right();
- if (yi < limits_rendertarget.top())
- yi = limits_rendertarget.top();
- if (yf > limits_rendertarget.bottom())
- yf = limits_rendertarget.bottom();
- offset = pitch_depthbuffer * yf + xf * bpp;
- addr = (uint8_t *)depthbuffer + offset;
- if ((addr < basemempointer) || (addr > topmempointer))
- {
- machine().logerror("Bad memory pointer computed in clear_depth_buffer !\n");
- return;
- }
-
- for (y = yi; y <= yf; y++)
- for (x = xi; x <= xf; x++) {
- offset = pitch_depthbuffer * y + x * bpp;
- switch (depthformat_rendertarget) {
- case NV2A_RT_DEPTH_FORMAT::Z16:
- addr = (uint8_t *)depthbuffer + offset;
- color = *((uint16_t *)addr);
- break;
- case NV2A_RT_DEPTH_FORMAT::Z24S8:
- addr = (uint8_t *)depthbuffer + offset;
- color = *((uint32_t *)addr);
- break;
- default:
- return;
- }
- color = (color & ~mask) | (value & mask);
- switch (depthformat_rendertarget) {
- case NV2A_RT_DEPTH_FORMAT::Z16:
- addr = (uint8_t *)depthbuffer + offset;
- *((uint16_t *)addr) = color;
- break;
- case NV2A_RT_DEPTH_FORMAT::Z24S8:
- addr = (uint8_t *)depthbuffer + offset;
- *((uint32_t *)addr) = color;
- break;
- default:
- return;
- }
- }
-}
-
-uint32_t nv2a_renderer::render_triangle_culling(const rectangle &cliprect, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3)
-{
- float areax2;
- NV2A_GL_CULL_FACE face = NV2A_GL_CULL_FACE::FRONT;
-
- if (backface_culling_enabled == false)
- return rasterizer.render_triangle<int(VERTEX_PARAMETER::ALL)>(cliprect, render_spans_callback, _v1, _v2, _v3);
- if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT_AND_BACK)
- {
- triangles_bfculled++;
- return 0;
- }
- areax2 = _v1.x*(_v2.y - _v3.y) + _v2.x*(_v3.y - _v1.y) + _v3.x*(_v1.y - _v2.y);
- if (areax2 == 0.0f) {
- triangles_bfculled++;
- return 0;
- }
- if (backface_culling_winding == NV2A_GL_FRONT_FACE::CCW)
- {
- if (-areax2 <= 0)
- face = NV2A_GL_CULL_FACE::BACK;
- else
- face = NV2A_GL_CULL_FACE::FRONT;
- } else
- {
- if (areax2 <= 0)
- face = NV2A_GL_CULL_FACE::BACK;
- else
- face = NV2A_GL_CULL_FACE::FRONT;
- }
- if (face == NV2A_GL_CULL_FACE::FRONT)
- if (backface_culling_culled == NV2A_GL_CULL_FACE::BACK)
- return rasterizer.render_triangle<int(VERTEX_PARAMETER::ALL)>(cliprect, render_spans_callback, _v1, _v2, _v3);
- if (face == NV2A_GL_CULL_FACE::BACK)
- if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT)
- return rasterizer.render_triangle<int(VERTEX_PARAMETER::ALL)>(cliprect, render_spans_callback, _v1, _v2, _v3);
- triangles_bfculled++;
- return 0;
-}
-
-int nv2a_renderer::clip_triangle_w(nv2avertex_t vi[3], nv2avertex_t *vo)
-{
- int idx_prev, idx_curr;
- int neg_prev, neg_curr;
- double tfactor;
- int idx;
- const double wthreshold = 0.000001;
-
- idx_prev = 2;
- idx_curr = 0;
- idx = 0;
- neg_prev = vi[idx_prev].w < wthreshold ? 1 : 0;
- while (idx_curr < 3)
- {
- neg_curr = vi[idx_curr].w < wthreshold ? 1 : 0;
- if (neg_curr ^ neg_prev)
- {
- tfactor = (wthreshold - vi[idx_prev].w) / (vi[idx_curr].w - vi[idx_prev].w);
- // compute values for the new intermediate point
- vo[idx].x = ((vi[idx_curr].x - vi[idx_prev].x) * tfactor) + vi[idx_prev].x;
- vo[idx].y = ((vi[idx_curr].y - vi[idx_prev].y) * tfactor) + vi[idx_prev].y;
- vo[idx].w = ((vi[idx_curr].w - vi[idx_prev].w) * tfactor) + vi[idx_prev].w;
- for (int n = 0; n < (int)VERTEX_PARAMETER::PARAM_Z; n++)
- vo[idx].p[n] = ((vi[idx_curr].p[n] - vi[idx_prev].p[n]) * tfactor) + vi[idx_prev].p[n];
- vo[idx].p[(int)VERTEX_PARAMETER::PARAM_Z] = ((vi[idx_curr].p[(int)VERTEX_PARAMETER::PARAM_Z] - vi[idx_prev].p[(int)VERTEX_PARAMETER::PARAM_Z]) * tfactor) + vi[idx_prev].p[(int)VERTEX_PARAMETER::PARAM_Z];
- vo[idx].p[(int)VERTEX_PARAMETER::PARAM_1W] = 1.0f / vo[idx].w;
- idx++;
- }
- if (neg_curr == 0)
- {
- vo[idx].x = vi[idx_curr].x;
- vo[idx].y = vi[idx_curr].y;
- vo[idx].w = vi[idx_curr].w;
- for (int n = 0; n < (int)VERTEX_PARAMETER::PARAM_Z; n++)
- vo[idx].p[n] = vi[idx_curr].p[n];
- vo[idx].p[(int)VERTEX_PARAMETER::PARAM_Z] = vi[idx_curr].p[(int)VERTEX_PARAMETER::PARAM_Z];
- vo[idx].p[(int)VERTEX_PARAMETER::PARAM_1W] = 1.0f / vo[idx].w;
- idx++;
- }
- neg_prev = neg_curr;
- idx_prev = idx_curr;
- idx_curr++;
- }
- return idx;
-}
-
-uint32_t nv2a_renderer::render_triangle_clipping(const rectangle &cliprect, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3)
-{
- nv2avertex_t *vp[3];
- nv2avertex_t vi[3];
- nv2avertex_t vo[8];
- int nv;
- double c;
-
- if ((_v1.w > 0) && (_v2.w > 0) && (_v3.w > 0))
- return render_triangle_culling(cliprect, _v1, _v2, _v3);
- if (enable_clipping_w == false)
- return 0;
- if ((_v1.w <= 0) && (_v2.w <= 0) && (_v3.w <= 0))
- return 0;
- // assign the elements of the pointer array
- vp[0] = &_v1;
- vp[1] = &_v2;
- vp[2] = &_v3;
- // go back to the state before perpective divide
- if (vertex_pipeline == 4)
- {
- for (int n = 0; n < 3; n++)
- {
- c = vp[n]->w;
- vi[n].w = c;
- vi[n].x = (vp[n]->x / (double)supersample_factor_x) * c;
- vi[n].y = (vp[n]->y / (double)supersample_factor_y) * c;
- for (int nn = 0; nn <= (int)VERTEX_PARAMETER::PARAM_Z; nn++)
- vi[n].p[nn] = vp[n]->p[nn] * c;
- }
- } else
- {
- for (int n = 0; n < 3; n++)
- {
- c = vp[n]->w;
- vi[n].w = c;
- // remove perspective correct interpolate
- for (int nn = 0; nn < (int)VERTEX_PARAMETER::PARAM_Z; nn++)
- vi[n].p[nn] = vp[n]->p[nn] * c;
- // remove supersample
- vi[n].x = (vp[n]->x / supersample_factor_x) + 0.53125f;
- vi[n].y = (vp[n]->y / supersample_factor_y) + 0.53125f;
- // remove translate
- vi[n].x = vi[n].x - matrix.translate[0];
- vi[n].y = vi[n].y - matrix.translate[1];
- vi[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vp[n]->p[(int)VERTEX_PARAMETER::PARAM_Z] - matrix.translate[2];
- // remove perspective divide
- vi[n].x = vi[n].x * c;
- vi[n].y = vi[n].y * c;
- vi[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vi[n].p[(int)VERTEX_PARAMETER::PARAM_Z] * c;
- }
- }
- // do the clipping
- nv = clip_triangle_w(vi, vo);
- // screen coordinates for the new points
- if (vertex_pipeline == 4)
- {
- for (int n = 0; n < nv; n++)
- {
- c = 1 / vo[n].w;
- vo[n].x = vo[n].x * (double)supersample_factor_x * c;
- vo[n].y = vo[n].y * (double)supersample_factor_y * c;
- for (int nn = 0; nn <= (int)VERTEX_PARAMETER::PARAM_Z; nn++)
- vo[n].p[nn] = vo[n].p[nn] * c;
- }
- } else
- {
- for (int n = 0; n < nv; n++)
- {
- c = 1 / vo[n].w;
- // apply perspective divide
- vo[n].x = vo[n].x * c;
- vo[n].y = vo[n].y * c;
- vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] * c;
- // apply translate
- vo[n].x = vo[n].x + matrix.translate[0];
- vo[n].y = vo[n].y + matrix.translate[1];
- vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] = vo[n].p[(int)VERTEX_PARAMETER::PARAM_Z] + matrix.translate[2];
- // apply supersample
- vo[n].x = (vo[n].x - 0.53125f) * supersample_factor_x;
- vo[n].y = (vo[n].y - 0.53125f) * supersample_factor_y;
- // apply perspective correct interpolate
- for (int nn = 0; nn < (int)VERTEX_PARAMETER::PARAM_Z; nn++)
- vo[n].p[nn] = vo[n].p[nn] * c;
- }
- }
- for (int n = 1; n <= (nv - 2); n++)
- render_triangle_culling(cliprect, vo[0], vo[n], vo[n + 1]);
- return 0;
-}
-
-void nv2a_renderer::assemble_primitive(int source, int count)
-{
- uint32_t pc = primitives_count;
- vertex_nv *v;
-
- for (; count > 0; count--) {
- v = &vertex_software[source];
- if (primitive_type == NV2A_BEGIN_END::QUADS) {
- convert_vertices(v, vertex_xy + ((vertex_count + vertex_accumulated) & 1023));
- vertex_accumulated++;
- if (vertex_accumulated == 4) {
- primitives_count++;
- vertex_accumulated = 0;
- render_triangle_clipping(limits_rendertarget, vertex_xy[vertex_count], vertex_xy[vertex_count + 1], vertex_xy[vertex_count + 2]);
- render_triangle_clipping(limits_rendertarget, vertex_xy[vertex_count], vertex_xy[vertex_count + 2], vertex_xy[vertex_count + 3]);
- vertex_count = (vertex_count + 4) & 1023;
- rasterizer.wait();
- }
- }
- else if (primitive_type == NV2A_BEGIN_END::TRIANGLES) {
- convert_vertices(v, vertex_xy + ((vertex_count + vertex_accumulated) & 1023));
- vertex_accumulated++;
- if (vertex_accumulated == 3) {
- primitives_count++;
- vertex_accumulated = 0;
- render_triangle_clipping(limits_rendertarget, vertex_xy[vertex_count], vertex_xy[(vertex_count + 1) & 1023], vertex_xy[(vertex_count + 2) & 1023]); // 4 rgba, 4 texture units 2 uv
- vertex_count = (vertex_count + 3) & 1023;
- rasterizer.wait();
- }
- }
- else if (primitive_type == NV2A_BEGIN_END::TRIANGLE_FAN) {
- if (vertex_accumulated == 0)
- {
- convert_vertices(v, vertex_xy + 1024);
- vertex_accumulated = 1;
- }
- else if (vertex_accumulated == 1)
- {
- convert_vertices(v, vertex_xy);
- vertex_accumulated = 2;
- vertex_count = 1;
- }
- else
- {
- primitives_count++;
- // if software sends the vertices 0 1 2 3 4 5 6
- // hardware will draw triangles made by (0,1,2) (0,2,3) (0,3,4) (0,4,5) (0,5,6)
- convert_vertices(v, vertex_xy + vertex_count);
- render_triangle_clipping(limits_rendertarget, vertex_xy[1024], vertex_xy[(vertex_count - 1) & 1023], vertex_xy[vertex_count]);
- vertex_count = (vertex_count + 1) & 1023;
- rasterizer.wait();
- }
- }
- else if (primitive_type == NV2A_BEGIN_END::TRIANGLE_STRIP) {
- if (vertex_accumulated == 0)
- {
- convert_vertices(v, vertex_xy);
- vertex_accumulated = 1;
- }
- else if (vertex_accumulated == 1)
- {
- convert_vertices(v, vertex_xy + 1);
- vertex_accumulated = 2;
- vertex_count = 2;
- }
- else
- {
- primitives_count++;
- // if software sends the vertices 0 1 2 3 4 5 6
- // hardware will draw triangles made by (0,1,2) (1,3,2) (2,3,4) (3,5,4) (4,5,6)
- convert_vertices(v, vertex_xy + vertex_count);
- if ((vertex_count & 1) == 0)
- render_triangle_clipping(limits_rendertarget, vertex_xy[(vertex_count - 2) & 1023], vertex_xy[(vertex_count - 1) & 1023], vertex_xy[vertex_count]);
- else
- render_triangle_clipping(limits_rendertarget, vertex_xy[(vertex_count - 2) & 1023], vertex_xy[vertex_count], vertex_xy[(vertex_count - 1) & 1023]);
- vertex_count = (vertex_count + 1) & 1023;
- rasterizer.wait();
- }
- }
- else if (primitive_type == NV2A_BEGIN_END::QUAD_STRIP) {
- if (vertex_accumulated == 0)
- {
- convert_vertices(v, vertex_xy);
- vertex_accumulated = 1;
- }
- else if (vertex_accumulated == 1)
- {
- convert_vertices(v, vertex_xy + 1);
- vertex_accumulated = 2;
- vertex_count = 0;
- }
- else
- {
- convert_vertices(v, vertex_xy + ((vertex_count + vertex_accumulated) & 1023));
- vertex_accumulated++;
- if (vertex_accumulated == 4)
- {
- primitives_count++;
- // if software sends the vertices 0 1 2 3 4 5 6 7
- // hardware will draw triangles made by (0,1,2) (2,1,3) (2,3,4) (4,3,5) (4,5,6) (6,5,7)
- render_triangle_clipping(limits_rendertarget, vertex_xy[vertex_count], vertex_xy[(vertex_count + 1) & 1023], vertex_xy[(vertex_count + 2) & 1023]);
- render_triangle_clipping(limits_rendertarget, vertex_xy[(vertex_count + 2) & 1023], vertex_xy[(vertex_count + 1) & 1023], vertex_xy[(vertex_count + 3) & 1023]);
- vertex_accumulated = 2;
- vertex_count = (vertex_count + 2) & 1023;
- rasterizer.wait();
- }
- }
- }
- else {
- if (vertex_count == 0)
- machine().logerror("Unsupported primitive %d\n", int(primitive_type));
- vertex_count++;
- }
- source = (source + 1) & 1023;
- }
- primitives_total_count += primitives_count - pc;
-}
-
-void nv2a_renderer::process_persistent_vertex()
-{
- memcpy(&vertex_software[1025], &persistvertexattr, sizeof(persistvertexattr));
- assemble_primitive(1025, 1);
-}
-
-void nv2a_renderer::compute_limits_rendertarget(uint32_t chanel, uint32_t subchannel)
-{
- uint32_t data;
- int x, w;
- int y, h;
-
- data = channel[chanel][subchannel].object.method[0x0200 / 4];
- x = data & 0xffff;
- w = (data >> 16) & 0xffff;
- x = x*supersample_factor_x;
- w = w*supersample_factor_x;
- limits_rendertarget.setx(x, x + w - 1);
- data = channel[chanel][subchannel].object.method[0x0204 / 4];
- y = data & 0xffff;
- h = (data >> 16) & 0xffff;
- y = y*supersample_factor_y;
- h = h*supersample_factor_y;
- limits_rendertarget.sety(y, y + h - 1);
-}
-
-void nv2a_renderer::compute_size_rendertarget(uint32_t chanel, uint32_t subchannel)
-{
- size_rendertarget = pitch_rendertarget*(limits_rendertarget.bottom() + 1);
- size_depthbuffer = pitch_depthbuffer*(limits_rendertarget.bottom() + 1);
-}
-
-int nv2a_renderer::execute_method(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t method, uint32_t address, int &countlen)
-{
- uint32_t data;
-
- data = space.read_dword(address);
- channel[chanel][subchannel].object.method[method / 4] = data;
-#ifdef LOG_NV2A
- //printf("A:%08X CH=%02d SCH=%02d MTHD:%08X D:%08X\n\r",address,chanel,subchannel,maddress,data);
-#endif
- if (channel[chanel][subchannel].object.objclass == 0x97)
- return execute_method_3d(space, chanel, subchannel, method, address, data, countlen);
- if (channel[chanel][subchannel].object.objclass == 0x39) // 0180
- return execute_method_m2mf(space, chanel, subchannel, method, address, data, countlen);
- if (channel[chanel][subchannel].object.objclass == 0x62) // 0184 0188
- return execute_method_surf2d(space, chanel, subchannel, method, address, data, countlen);
- if (channel[chanel][subchannel].object.objclass == 0x9f) // 019c 02fc
- return execute_method_blit(space, chanel, subchannel, method, address, data, countlen);
- return 0;
-}
-
-int nv2a_renderer::execute_method_3d(address_space& space, uint32_t chanel, uint32_t subchannel, uint32_t maddress, uint32_t address, uint32_t data, int &countlen)
-{
- if ((chanel != 0) || (subchannel != 0))
- return 0;
- if (maddress == 0x17fc) {
-#if 0 // useful while debugging to see what coordinates have been used
- static int debugvc = 0;
- if (debugvc)
- if (data == 0)
- {
- printf("%d %d\n\r", (int)primitive_type, vertex_first);
- for (int n = 0; n < vertex_first; n++)
- {
- if (indexesleft_count > 0)
- printf("%d i:%d ", n, vertex_indexes[n]);
- else
- printf("%d ", n);
- printf("X:%f Y:%f Z:%f W:%f x:%f y:%f\n\r", vertex_software[n].attribute[0].fv[0], vertex_software[n].attribute[0].fv[1], vertex_software[n].attribute[0].fv[2], vertex_software[n].attribute[0].fv[3], vertex_xy[n].x, vertex_xy[n].y);
- }
- }
-#endif
- vertex_count = 0;
- vertex_first = 0;
- vertex_accumulated = 0;
- indexesleft_count = 0;
- indexesleft_first = 0;
- primitives_count = 0;
- primitive_type = (NV2A_BEGIN_END)data;
- if (data == 0)
- primitives_batches_count++;
- else
- {
- if (((channel[chanel][subchannel].object.method[0x1e60 / 4] & 7) > 0) && (combiner.used != 0))
- render_spans_callback = nv2a_rasterizer::render_delegate(&nv2a_renderer::render_register_combiners, this);
- else if (texture[0].enabled)
- render_spans_callback = nv2a_rasterizer::render_delegate(&nv2a_renderer::render_texture_simple, this);
- else
- render_spans_callback = nv2a_rasterizer::render_delegate(&nv2a_renderer::render_color, this);
- }
- countlen--;
- }
- if (maddress == 0x1810) {
- // draw vertices
- int offset, count;
- uint32_t n;
-
- offset = data & 0xffffff;
- count = (data >> 24) & 0xff;
-#ifdef LOG_NV2A
- printf("vertex %d %d\n\r", offset, count);
-#endif
- for (n = 0; n <= count; n++) {
- read_vertices_0x1810(space, vertex_first, n + offset, 1);
- assemble_primitive(vertex_first, 1);
- vertex_first = (vertex_first + 1) & 1023;
- }
- countlen--;
- }
- if ((maddress == 0x1800) || (maddress == 0x1808)) {
- int mult;
-
- if (maddress == 0x1800)
- mult = 2;
- else
- mult = 1;
- // vertices are selected from the vertex buffer using an array of indexes
- // each dword after 1800 contains two 16 bit index values to select the vartices
- // each dword after 1808 contains a 32 bit index value to select the vartices
- while (countlen > 0) {
- int n;
-
- data = space.read_dword(address);
- n = indexesleft_first + indexesleft_count;
- if (mult == 2) {
- vertex_indexes[n & 1023] = data & 0xffff;
- vertex_indexes[(n + 1) & 1023] = (data >> 16) & 0xffff;
- indexesleft_count = indexesleft_count + 2;
- }
- else {
- vertex_indexes[n & 1023] = data;
- indexesleft_count = indexesleft_count + 1;
- }
- address += 4;
- countlen--;
- read_vertices_0x180x(space, vertex_first, address, mult);
- assemble_primitive(vertex_first, mult);
- vertex_first = (vertex_first + mult) & 1023;
- }
- }
- if (maddress == 0x1818) {
- if (countlen == 0)
- machine().logerror("Method 0x1818 with 0 vertices\n");
- // vertices are taken from the next words, not from a vertex buffer
- // first send primitive type with 17fc
- // then countlen number of dwords with 1818
- // end with 17fc primitive type 0
- // at 1760 16 words specify the vertex format:for each possible vertex attribute the number of components (0=not present) and type of each
- while (countlen > 0) {
- int c;
-
- c = read_vertices_0x1818(space, vertex_first, address, 1);
- countlen = countlen - c;
- if (countlen < 0) {
- machine().logerror("Method 0x1818 missing %d words\n", -countlen);
- countlen = 0;
- break;
- }
- address = address + c * 4;
- assemble_primitive(vertex_first, 1);
- vertex_first = (vertex_first + 1) & 1023;
- }
- }
- if ((maddress >= 0x1880) && (maddress < 0x1900))
- {
- int v = maddress - 0x1880; // 16 couples,2 float per couple,16*2*4=128
- int attr = v >> 3;
- int comp = (v >> 2) & 1;
-
- persistvertexattr.attribute[attr].iv[comp] = data;
- if (comp == 1)
- {
- persistvertexattr.attribute[attr].fv[2] = 0;
- persistvertexattr.attribute[attr].fv[3] = 1;
- if (attr == 0)
- process_persistent_vertex();
- }
- }
- if ((maddress >= 0x1900) && (maddress < 0x1940))
- {
- int v = maddress - 0x1900; // 16 dwords,2 values per dword
- int attr = v >> 2;
- uint16_t d1 = data & 0xffff;
- uint16_t d2 = data >> 16;
-
- persistvertexattr.attribute[attr].fv[0] = (float)((int16_t)d1);
- persistvertexattr.attribute[attr].fv[1] = (float)((int16_t)d2);
- persistvertexattr.attribute[attr].fv[2] = 0;
- persistvertexattr.attribute[attr].fv[3] = 1;
- if (attr == 0)
- process_persistent_vertex();
- }
- if ((maddress >= 0x1940) && (maddress < 0x1980))
- {
- int v = maddress - 0x1940; // 16 dwords,4 values per dword
- int attr = v >> 2;
- uint8_t d1 = data & 255;
- uint8_t d2 = (data >> 8) & 255;
- uint8_t d3 = (data >> 16) & 255;
- uint8_t d4 = data >> 24;
-
- // if sending color dword is aabbggrr
- persistvertexattr.attribute[attr].fv[0] = (float)d1 / 255.0;
- persistvertexattr.attribute[attr].fv[1] = (float)d2 / 255.0;
- persistvertexattr.attribute[attr].fv[2] = (float)d3 / 255.0;
- persistvertexattr.attribute[attr].fv[3] = (float)d4 / 255.0;
- if (attr == 0)
- process_persistent_vertex();
- }
- if ((maddress >= 0x1980) && (maddress < 0x1a00))
- {
- int v = maddress - 0x1980; // 16 couples,4 values per couple,16*2*4=128
- int attr = v >> 3;
- int comp = (v >> 1) & 2;
- uint16_t d1 = data & 0xffff;
- uint16_t d2 = data >> 16;
-
- persistvertexattr.attribute[attr].fv[comp] = (float)((int16_t)d1);
- persistvertexattr.attribute[attr].fv[comp+1] = (float)((int16_t)d2);
- if (comp == 2)
- if (attr == 0)
- process_persistent_vertex();
- }
- if ((maddress >= 0x1a00) && (maddress < 0x1b00))
- {
- int v = maddress - 0x1a00; // 16 groups,4 float per group
- int attr = v >> 4;
- int comp = (v >> 2) & 3;
-
- persistvertexattr.attribute[attr].iv[comp] = data;
- if (comp == 3)
- if (attr == 0)
- process_persistent_vertex();
- }
- if ((maddress >= 0x1518) && (maddress < 0x1528))
- {
- int v = maddress - 0x1518;
- int comp = v >> 2;
-
- persistvertexattr.attribute[(int)NV2A_VERTEX_ATTR::POS].iv[comp] = data;
- if (comp == 3)
- process_persistent_vertex();
- }
- else if ((maddress >= 0x1500) && (maddress < 0x1590))
- {
- machine().logerror("Yet unsupported method %x\n\r", maddress);
- }
- if ((maddress >= 0x1720) && (maddress < 0x1760)) {
- int bit = maddress / 4 - 0x1720 / 4;
-
- if (data & 0x80000000)
- vertexbuffer.address[bit] = (data & 0x0fffffff) + dma_offset[7];
- else
- vertexbuffer.address[bit] = (data & 0x0fffffff) + dma_offset[6];
- }
- if ((maddress >= 0x1760) && (maddress < 0x17A0)) {
- int bit = maddress / 4 - 0x1760 / 4;
-
- vertexbuffer.type[bit] = data & 255;
- vertexbuffer.stride[bit] = (data >> 8) & 255;
- switch (vertexbuffer.type[bit])
- {
- case 0x02: // none
- vertexbuffer.words[bit] = 0;
- break;
- case 0x12: // float1
- vertexbuffer.words[bit] = 1;
- break;
- case 0x16: // normpacked3
- vertexbuffer.words[bit] = 1;
- break;
- case 0x22: // float2
- vertexbuffer.words[bit] = 2;
- break;
- case 0x32: // float3
- vertexbuffer.words[bit] = 3;
- break;
- case 0x40: // d3dcolor
- vertexbuffer.words[bit] = 1;
- break;
- case 0x42: // float4
- vertexbuffer.words[bit] = 4;
- break;
- default:
- machine().logerror("Yet unsupported vertex data type %x\n\r", vertexbuffer.type[bit]);
- vertexbuffer.words[bit] = 0;
- }
- if (vertexbuffer.words[bit] > 0)
- vertexbuffer.enabled |= (1 << bit);
- else
- vertexbuffer.enabled &= ~(1 << bit);
- vertexbuffer.offset[0] = 0;
- for (int n = bit + 1; n <= 16; n++) {
- if ((vertexbuffer.enabled & (1 << (n - 1))) != 0)
- vertexbuffer.offset[n] = vertexbuffer.offset[n - 1] + vertexbuffer.words[n - 1];
- else
- vertexbuffer.offset[n] = vertexbuffer.offset[n - 1];
- }
- countlen--;
- }
- if ((maddress == 0x1d6c) || (maddress == 0x1a4))
- countlen--;
- if (maddress == 0x0308) {
- backface_culling_enabled = data != 0 ? true : false;
- }
- if (maddress == 0x03a0) {
- backface_culling_winding = (NV2A_GL_FRONT_FACE)data;
- }
- if (maddress == 0x039c) {
- backface_culling_culled = (NV2A_GL_CULL_FACE)data;
- }
- if (maddress == 0x0180) {
- geforce_read_dma_object(data, dma_offset[0], dma_size[0]);
- }
- if (maddress == 0x0184) {
- geforce_read_dma_object(data, dma_offset[1], dma_size[1]);
- }
- if (maddress == 0x0188) {
- geforce_read_dma_object(data, dma_offset[2], dma_size[2]);
- }
- if (maddress == 0x0190) {
- geforce_read_dma_object(data, dma_offset[3], dma_size[3]);
- }
- if (maddress == 0x0194) {
- geforce_read_dma_object(data, dma_offset[4], dma_size[4]);
- }
- if (maddress == 0x0198) {
- geforce_read_dma_object(data, dma_offset[5], dma_size[5]);
- }
- if (maddress == 0x019c) {
- geforce_read_dma_object(data, dma_offset[6], dma_size[6]);
- }
- if (maddress == 0x01a0) {
- geforce_read_dma_object(data, dma_offset[7], dma_size[7]);
- }
- if (maddress == 0x01a4) {
- geforce_read_dma_object(data, dma_offset[8], dma_size[8]);
- }
- if (maddress == 0x01a8) {
- geforce_read_dma_object(data, dma_offset[9], dma_size[9]);
- }
- if (maddress == 0x1d70) {
- // with 1d70 write the value at offest [1d6c] inside dma object [1a4]
- uint32_t offset, base;
- uint32_t dmahand, dmaoff, smasiz;
-
- offset = channel[chanel][subchannel].object.method[0x1d6c / 4];
- dmahand = channel[chanel][subchannel].object.method[0x1a4 / 4];
- geforce_read_dma_object(dmahand, dmaoff, smasiz);
- base = dmaoff;
- space.write_dword(base + offset, data);
- // software expects to find the parameter of this method at pgraph offset b10
- pgraph[0xb10 / 4] = data << 2;
- countlen--;
- }
- if (maddress == 0x1d7c) {
- antialias_control = data;
- compute_supersample_factors(supersample_factor_x, supersample_factor_y);
- compute_limits_rendertarget(chanel, subchannel);
- countlen--;
- }
- if (maddress == 0x1d98) {
- int x, w;
-
- x = data & 0xffff;
- w = (data >> 16) & 0xffff;
- clear_rendertarget.setx(x, w);
- countlen--;
- }
- if (maddress == 0x1d9c) {
- int y, h;
-
- y = data & 0xffff;
- h = (data >> 16) & 0xffff;
- clear_rendertarget.sety(y, h);
- countlen--;
- }
- if (maddress == 0x1d94) {
- // possible buffers: color, depth, stencil
- // clear framebuffer
- clear_render_target((data >> 4) & 15, channel[chanel][subchannel].object.method[0x1d90 / 4]);
- clear_depth_buffer(data & 3, channel[chanel][subchannel].object.method[0x1d8c / 4]);
- countlen--;
- }
- if ((maddress >= 0x02c0) && (maddress < 0x2e0)) {
- int x, w, i;
-
- i = (maddress - 0x2c0) / 4;
- x = data & 0xffff;
- w = (data >> 16) & 0xffff;
- clippingwindows[i].setx(x, x + w - 1);
- }
- if ((maddress >= 0x02e0) && (maddress < 0x300)) {
- int y, h, i;
-
- i = (maddress - 0x2e0) / 4;
- y = data & 0xffff;
- h = (data >> 16) & 0xffff;
- clippingwindows[i].sety(y, y + h - 1);
- }
- if (maddress == 0x0200) {
- compute_limits_rendertarget(chanel, subchannel);
- compute_size_rendertarget(chanel, subchannel);
- }
- if (maddress == 0x0204) {
- compute_limits_rendertarget(chanel, subchannel);
- compute_size_rendertarget(chanel, subchannel);
- }
- if (maddress == 0x0208) {
- log2height_rendertarget = (data >> 24) & 255;
- log2width_rendertarget = (data >> 16) & 255;
- antialiasing_rendertarget = (data >> 12) & 15;
- type_rendertarget = (NV2A_RT_TYPE)((data >> 8) & 15);
- depthformat_rendertarget = (NV2A_RT_DEPTH_FORMAT)((data >> 4) & 15);
- colorformat_rendertarget = (NV2A_COLOR_FORMAT)((data >> 0) & 15);
- compute_supersample_factors(supersample_factor_x, supersample_factor_y);
- compute_limits_rendertarget(chanel, subchannel);
- compute_size_rendertarget(chanel, subchannel);
-/* for debugging
- if (limits_rendertarget.max_x == 1023)
- type_rendertarget = NV2A_RT_TYPE::LINEAR;
-*/
- switch (colorformat_rendertarget) {
- case NV2A_COLOR_FORMAT::R5G6B5:
- bytespixel_rendertarget = 2;
- break;
- case NV2A_COLOR_FORMAT::X8R8G8B8_Z8R8G8B8:
- case NV2A_COLOR_FORMAT::X8R8G8B8_X8R8G8B8:
- case NV2A_COLOR_FORMAT::A8R8G8B8:
- bytespixel_rendertarget = 4;
- break;
- case NV2A_COLOR_FORMAT::B8:
- bytespixel_rendertarget = 1;
- break;
- default:
- machine().logerror("Unknown render target color format %d\n\r", int(colorformat_rendertarget));
- bytespixel_rendertarget = 4;
- break;
- }
- dilate_rendertarget = dilatechose[(log2width_rendertarget << 4) + log2height_rendertarget];
- }
- if (maddress == 0x020c) {
- pitch_rendertarget=data & 0xffff;
- pitch_depthbuffer=(data >> 16) & 0xffff;
- compute_size_rendertarget(chanel, subchannel);
-#ifdef LOG_NV2A
- printf("Pitch color %04X zbuffer %04X\n\r", pitch_rendertarget, pitch_depthbuffer);
-#endif
- countlen--;
- }
- if (maddress == 0x0100) {
- countlen--;
- if (data != 0) {
-#ifdef LOG_NV2A
- machine().logerror("Software method %04x\n", data);
-#endif
- pgraph[0x704 / 4] = 0x100 | (chanel << 20) | (subchannel << 16);
- pgraph[0x708 / 4] = data;
- pgraph[0x100 / 4] |= 1;
- pgraph[0x108 / 4] |= 1;
- if (update_interrupts() == true)
- irq_callback(1); // IRQ 3
- else
- irq_callback(0); // IRQ 3
- return 2;
- }
- else
- return 0;
- }
- if (maddress == 0x0130) {
- countlen--;
- if (enable_waitvblank == true)
- return 1; // block until next vblank
- else
- return 0;
- }
- if (maddress == 0x1d8c) {
- countlen--;
- // it is used to specify the clear value for the depth buffer (zbuffer)
- // but also as a parameter for interrupt routines
- pgraph[0x1a88 / 4] = data;
- }
- if (maddress == 0x1d90) {
- countlen--;
- // it is used to specify the clear value for the color buffer
- // but also as a parameter for interrupt routines
- pgraph[0x186c / 4] = data;
- }
- if (maddress == 0x0210) {
- // framebuffer offset
- old_rendertarget = rendertarget;
- // To see it with the image watch extension: @mem(0x000002d2263af060, UINT8, 4, 640, 480, 2560)
- rendertarget = (uint32_t *)direct_access_ptr(data);
-#ifdef LOG_NV2A
- printf("Render target at %08X\n\r", data);
-#endif
- countlen--;
- }
- if (maddress == 0x0214) {
- // zbuffer offset ?
- depthbuffer = (uint32_t *)direct_access_ptr(data);
-#ifdef LOG_NV2A
- printf("Depth buffer at %08X\n\r",data);
-#endif
- if ((data == 0) || (data > 0x7ffffffc))
- depth_write_enabled = false;
- else if (channel[chanel][subchannel].object.method[0x035c / 4] != 0)
- depth_write_enabled = true;
- else
- depth_write_enabled = false;
- countlen--;
- }
- if (maddress == 0x0300) {
- alpha_test_enabled = data != 0;
- }
- if (maddress == 0x033c) {
- alpha_func = (NV2A_COMPARISON_OP)data;
- }
- if (maddress == 0x0340) {
- alpha_reference = data;
- }
- if (maddress == 0x0304) {
- if (logical_operation_enabled)
- blending_enabled = false;
- else
- blending_enabled = data != 0;
- }
- if (maddress == 0x030c) {
- depth_test_enabled = data != 0;
- }
- if (maddress == 0x0354) {
- depth_function = (NV2A_COMPARISON_OP)data;
- }
- if (maddress == 0x0358) {
- //color_mask = data;
- if (data & 0x000000ff)
- data |= 0x000000ff;
- if (data & 0x0000ff00)
- data |= 0x0000ff00;
- if (data & 0x00ff0000)
- data |= 0x00ff0000;
- if (data & 0xff000000)
- data |= 0xff000000;
- color_mask = data;
- }
- if (maddress == 0x035c) {
- uint32_t g = channel[chanel][subchannel].object.method[0x0214 / 4];
- depth_write_enabled = data != 0;
- if ((g == 0) || (g > 0x7ffffffc))
- depth_write_enabled = false;
- }
- if (maddress == 0x032c) {
- stencil_test_enabled = data != 0;
- }
- if (maddress == 0x0364) {
- stencil_func = (NV2A_COMPARISON_OP)data;
- }
- if (maddress == 0x0368) {
- if (data > 255)
- data = 255;
- stencil_ref = data;
- }
- if (maddress == 0x036c) {
- stencil_mask = data;
- }
- if (maddress == 0x0370) {
- stencil_op_fail = (NV2A_STENCIL_OP)data;
- }
- if (maddress == 0x0374) {
- stencil_op_zfail = (NV2A_STENCIL_OP)data;
- }
- if (maddress == 0x0378) {
- stencil_op_zpass = (NV2A_STENCIL_OP)data;
- }
- if (maddress == 0x0344) {
- blend_function_source = (NV2A_BLEND_FACTOR)data;
- }
- if (maddress == 0x0348) {
- blend_function_destination = (NV2A_BLEND_FACTOR)data;
- }
- if (maddress == 0x034c) {
- blend_color = data;
- }
- if (maddress == 0x0350) {
- blend_equation = (NV2A_BLEND_EQUATION)data;
- }
- if (maddress == 0x0d40) {
- if (data != 0)
- blending_enabled = false;
- else
- blending_enabled = channel[chanel][subchannel].object.method[0x0304 / 4] != 0;
- logical_operation_enabled = data != 0;
- }
- if (maddress == 0x0d44) {
- logical_operation = (NV2A_LOGIC_OP)data;
- }
- // Texture Units
- if ((maddress >= 0x1b00) && (maddress < 0x1c00)) {
- int unit;//,off;
-
- unit = (maddress >> 6) & 3;
- //off=maddress & 0xc0;
- maddress = maddress & ~0xc0;
- if (maddress == 0x1b00) {
- uint32_t offset;//,base;
- //uint32_t dmahand,dmaoff,dmasiz;
-
- offset = data;
- texture[unit].buffer = direct_access_ptr(offset);
- /*if (dma0 != 0) {
- dmahand=channel[channel][subchannel].object.method[0x184/4];
- geforce_read_dma_object(dmahand,dmaoff,dmasiz);
- } else if (dma1 != 0) {
- dmahand=channel[channel][subchannel].object.method[0x188/4];
- geforce_read_dma_object(dmahand,dmaoff,dmasiz);
- }*/
- }
- if (maddress == 0x1b04) {
- int basesizeu, basesizev, basesizew, format;
- bool rectangle;
-
- texture[unit].dma0 = (data >> 0) & 1;
- texture[unit].dma1 = (data >> 1) & 1;
- texture[unit].cubic = (data >> 2) & 1;
- texture[unit].noborder = (data >> 3) & 1;
- texture[unit].dims = (data >> 4) & 15;
- texture[unit].mipmap = (data >> 19) & 1;
- format = (data >> 8) & 255;
- basesizeu = (data >> 20) & 15;
- basesizev = (data >> 24) & 15;
- basesizew = (data >> 28) & 15;
- texture[unit].sizes = 1 << basesizeu;
- texture[unit].sizet = 1 << basesizev;
- texture[unit].sizer = 1 << basesizew;
- texture[unit].dilate = dilatechose[(basesizeu << 4) + basesizev];
- texture[unit].format = (NV2A_TEX_FORMAT)format;
- switch (texture[unit].format)
- {
- case NV2A_TEX_FORMAT::A1R5G5B5_RECT:
- case NV2A_TEX_FORMAT::R5G6B5_RECT:
- case NV2A_TEX_FORMAT::A8R8G8B8_RECT:
- case NV2A_TEX_FORMAT::DSDT8_RECT:
- case NV2A_TEX_FORMAT::A4R4G4B4_RECT:
- case NV2A_TEX_FORMAT::R8G8B8_RECT:
- case NV2A_TEX_FORMAT::A8L8_RECT:
- case NV2A_TEX_FORMAT::Z24_RECT:
- case NV2A_TEX_FORMAT::Z16_RECT:
- case NV2A_TEX_FORMAT::HILO16_RECT:
- case NV2A_TEX_FORMAT::SIGNED_HILO8_RECT:
- rectangle = true;
- break;
- default:
- rectangle = false;
- }
- texture[unit].rectangle = rectangle;
- if (debug_grab_texttype == format) {
- FILE *f;
- int written;
-
- debug_grab_texttype = -1;
- f = fopen(debug_grab_textfile, "wb");
- if (f) {
- written = (int)fwrite(texture[unit].buffer, texture[unit].sizes * texture[unit].sizet * 4, 1, f);
- fclose(f);
- machine().logerror("Written %d bytes of texture to specified file\n", written);
- }
- else
- machine().logerror("Unable to save texture to specified file\n");
- }
- }
- if (maddress == 0x1b08) {
- texture[unit].addrmodes = (data >> 0) & 15;
- texture[unit].addrmodet = (data >> 8) & 15;
- texture[unit].addrmoder = (data >> 16) & 15;
- }
- if (maddress == 0x1b0c) {
- texture[unit].colorkey = (data >> 0) & 3;
- texture[unit].imagefield = (data >> 3) & 1;
- texture[unit].aniso = (data >> 4) & 3;
- texture[unit].mipmapmaxlod = (data >> 6) & 0xfff;
- texture[unit].mipmapminlod = (data >> 18) & 0xfff;
- // enable texture ?
- texture[unit].enabled = (data >> 30) & 3;
- }
- if (maddress == 0x1b10) {
- texture[unit].rectangle_pitch = data >> 16;
- }
- if (maddress == 0x1b1c) {
- texture[unit].rectheight = data & 0xffff;
- texture[unit].rectwidth = data >> 16;
- }
- countlen--;
- }
- if (maddress == 0x1e70) {
- texture[0].mode = data & 31;
- texture[1].mode = (data >> 5) & 31;
- texture[2].mode = (data >> 10) & 31;
- texture[3].mode = (data >> 15) & 31;
- }
- // projection matrix
- if ((maddress >= 0x0440) && (maddress < 0x0480)) {
- maddress = (maddress - 0x0440) / 4;
- *(uint32_t *)(&matrix.projection[maddress >> 2][maddress & 3]) = data;
- countlen--;
- }
- // modelview matrix
- if ((maddress >= 0x0480) && (maddress < 0x04c0)) {
- maddress = (maddress - 0x0480) / 4;
- /* the modelview matrix is obtained by direct3d by multiplying the world matrix and the view matrix
- modelview = world * view
- given a point in 3d space with coordinates x y and z, to find te transformed coordinates
- first create a row vector with components (x,y,z,1) then multiply the vector by the matrix
- transformed = rowvector * matrix
- in direct3d the matrix is stored as the sequence (first digit row, second digit column)
- 11 12 13 14
- 21 22 23 24
- 31 32 33 34
- 41 42 43 44
- but it is sent transposed as the sequence
- 11 21 31 41 12 22 32 42 13 23 33 43 14 24 34 44
- so in matrix.modelview[x][y] x is the column and y is the row of the direct3d matrix
- */
- *(uint32_t *)(&matrix.modelview[maddress >> 2][maddress & 3]) = data;
- countlen--;
- }
- // inverse modelview matrix
- if ((maddress >= 0x0580) && (maddress < 0x05c0)) {
- maddress = (maddress - 0x0580) / 4;
- *(uint32_t *)(&matrix.modelview_inverse[maddress >> 2][maddress & 3]) = data;
- countlen--;
- }
- // composite matrix
- if ((maddress >= 0x0680) && (maddress < 0x06c0)) {
- maddress = (maddress - 0x0680) / 4;
- /* the composite matrix is computed by direct3d by multiplying the
- world, view, projection and viewport matrices
- composite = world * view * projection * viewport
- the viewport matrix applies the viewport scale and offset
- */
- *(uint32_t *)(&matrix.composite[maddress >> 2][maddress & 3]) = data;
- countlen--;
- }
- // viewport translate
- if ((maddress >= 0x0a20) && (maddress < 0x0a30)) {
- maddress = (maddress - 0x0a20) / 4;
- *(uint32_t *)(&matrix.translate[maddress]) = data;
- // set corresponding vertex shader constant too
- vertexprogram.exec.c_constant[59].iv(maddress, data); // constant -37
-#ifdef LOG_NV2A
- if (maddress == 3)
- machine().logerror("viewport translate = {%f %f %f %f}\n", matrix.translate[0], matrix.translate[1], matrix.translate[2], matrix.translate[3]);
-#endif
- countlen--;
- }
- // viewport scale
- if ((maddress >= 0x0af0) && (maddress < 0x0b00)) {
- maddress = (maddress - 0x0af0) / 4;
- *(uint32_t *)(&matrix.scale[maddress]) = data;
- // set corresponding vertex shader constant too
- vertexprogram.exec.c_constant[58].iv(maddress, data); // constant -38
-#ifdef LOG_NV2A
- if (maddress == 3)
- machine().logerror("viewport scale = {%f %f %f %f}\n", matrix.scale[0], matrix.scale[1], matrix.scale[2], matrix.scale[3]);
-#endif
- countlen--;
- }
- // Vertex program (shader)
- if (maddress == 0x1e94) {
- /*if (data == 2)
- machine().logerror("Enabled vertex program\n");
- else if (data == 4)
- machine().logerror("Enabled fixed function pipeline\n");
- else if (data == 6)
- machine().logerror("Enabled both fixed function pipeline and vertex program ?\n");
- else
- machine().logerror("Unknown value %d to method 0x1e94\n",data);*/
- vertex_pipeline = data & 6;
- countlen--;
- }
- if (maddress == 0x1e9c) {
- //machine().logerror("VP_UPLOAD_FROM_ID %d\n",data);
- vertexprogram.upload_instruction_index = data;
- vertexprogram.upload_instruction_component = 0;
- countlen--;
- }
- if (maddress == 0x1ea0) {
- //machine().logerror("VP_START_FROM_ID %d\n",data);
- vertexprogram.instructions = vertexprogram.upload_instruction_index;
- vertexprogram.start_instruction = data;
- countlen--;
- }
- if (maddress == 0x1ea4) {
- //machine().logerror("VP_UPLOAD_CONST_ID %d\n",data);
- vertexprogram.upload_parameter_index = data;
- vertexprogram.upload_parameter_component = 0;
- countlen--;
- }
- if ((maddress >= 0x0b00) && (maddress < 0x0b80)) {
- //machine().logerror("VP_UPLOAD_INST\n");
- if (vertexprogram.upload_instruction_index < 256) {
- vertexprogram.exec.op[vertexprogram.upload_instruction_index].i[vertexprogram.upload_instruction_component] = data;
- vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified |= (1 << vertexprogram.upload_instruction_component);
- }
- else
- machine().logerror("Need to increase size of vertexprogram.instruction to %d\n\r", vertexprogram.upload_instruction_index);
- if (vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified == 15) {
- vertexprogram.exec.op[vertexprogram.upload_instruction_index].modified = 0;
- vertexprogram.exec.decode_instruction(vertexprogram.upload_instruction_index);
- }
- vertexprogram.upload_instruction_component++;
- if (vertexprogram.upload_instruction_component >= 4) {
- vertexprogram.upload_instruction_component = 0;
- vertexprogram.upload_instruction_index++;
- }
- }
- if ((maddress >= 0x0b80) && (maddress < 0x0c00)) {
- //machine().logerror("VP_UPLOAD_CONST\n");
- if (vertexprogram.upload_parameter_index < 192) {
- vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].iv(vertexprogram.upload_parameter_component, data);
- }
- else
- machine().logerror("Need to increase size of vertexprogram.parameter to %d\n\r", vertexprogram.upload_parameter_index);
- vertexprogram.upload_parameter_component++;
- if (vertexprogram.upload_parameter_component >= 4) {
-#ifdef LOG_NV2A
- if ((vertexprogram.upload_parameter_index == 58) || (vertexprogram.upload_parameter_index == 59))
- machine().logerror("vp constant %d (%s) = {%f %f %f %f}\n", vertexprogram.upload_parameter_index,
- vertexprogram.upload_parameter_index == 58 ? "viewport scale" : "viewport translate",
- vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[0],
- vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[1],
- vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[2],
- vertexprogram.exec.c_constant[vertexprogram.upload_parameter_index].fv[3]);
-#endif
- vertexprogram.upload_parameter_component = 0;
- vertexprogram.upload_parameter_index++;
- }
- }
- if ((maddress >= 0x1e80) && (maddress < 0x1e90)) {
- machine().logerror("Setting v0 vertex program input component %d to %f\n", (maddress - 0x1e80) / 4, *((float *)&data));
- }
- if (maddress == 0x1e90) {
- machine().logerror("Received explicit method to run vertex program\n");
- }
- if (maddress == 0x02a8) {
- fog_color = data;
- }
- // Register combiners
- if (maddress == 0x0288) {
- combiner.setup.final.mapin_rgb.D_input = (Combiner::InputRegister)(data & 15);
- combiner.setup.final.mapin_rgb.D_component = (data >> 4) & 1;
- combiner.setup.final.mapin_rgb.D_mapping = (Combiner::MapFunction)((data >> 5) & 7);
- combiner.setup.final.mapin_rgb.C_input = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.final.mapin_rgb.C_component = (data >> 12) & 1;
- combiner.setup.final.mapin_rgb.C_mapping = (Combiner::MapFunction)((data >> 13) & 7);
- combiner.setup.final.mapin_rgb.B_input = (Combiner::InputRegister)((data >> 16) & 15);
- combiner.setup.final.mapin_rgb.B_component = (data >> 20) & 1;
- combiner.setup.final.mapin_rgb.B_mapping = (Combiner::MapFunction)((data >> 21) & 7);
- combiner.setup.final.mapin_rgb.A_input = (Combiner::InputRegister)((data >> 24) & 15);
- combiner.setup.final.mapin_rgb.A_component = (data >> 28) & 1;
- combiner.setup.final.mapin_rgb.A_mapping = (Combiner::MapFunction)((data >> 29) & 7);
- countlen--;
- }
- if (maddress == 0x028c) {
- combiner.setup.final.color_sum_clamp = (data >> 7) & 1;
- combiner.setup.final.mapin_alpha.G_input = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.final.mapin_alpha.G_component = (data >> 12) & 1;
- combiner.setup.final.mapin_alpha.G_mapping = (Combiner::MapFunction)((data >> 13) & 7);
- combiner.setup.final.mapin_rgb.F_input = (Combiner::InputRegister)((data >> 16) & 15);
- combiner.setup.final.mapin_rgb.F_component = (data >> 20) & 1;
- combiner.setup.final.mapin_rgb.F_mapping = (Combiner::MapFunction)((data >> 21) & 7);
- combiner.setup.final.mapin_rgb.E_input = (Combiner::InputRegister)((data >> 24) & 15);
- combiner.setup.final.mapin_rgb.E_component = (data >> 28) & 1;
- combiner.setup.final.mapin_rgb.E_mapping = (Combiner::MapFunction)((data >> 29) & 7);
- countlen--;
- }
- if ((maddress >= 0x0260) && (maddress < 0x0280)) {
- int n;
-
- n = (maddress - 0x0260) >> 2;
- combiner.setup.stage[n].mapin_alpha.D_input = (Combiner::InputRegister)(data & 15);
- combiner.setup.stage[n].mapin_alpha.D_component = (data >> 4) & 1;
- combiner.setup.stage[n].mapin_alpha.D_mapping = (Combiner::MapFunction)((data >> 5) & 7);
- combiner.setup.stage[n].mapin_alpha.C_input = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.stage[n].mapin_alpha.C_component = (data >> 12) & 1;
- combiner.setup.stage[n].mapin_alpha.C_mapping = (Combiner::MapFunction)((data >> 13) & 7);
- combiner.setup.stage[n].mapin_alpha.B_input = (Combiner::InputRegister)((data >> 16) & 15);
- combiner.setup.stage[n].mapin_alpha.B_component = (data >> 20) & 1;
- combiner.setup.stage[n].mapin_alpha.B_mapping = (Combiner::MapFunction)((data >> 21) & 7);
- combiner.setup.stage[n].mapin_alpha.A_input = (Combiner::InputRegister)((data >> 24) & 15);
- combiner.setup.stage[n].mapin_alpha.A_component = (data >> 28) & 1;
- combiner.setup.stage[n].mapin_alpha.A_mapping = (Combiner::MapFunction)((data >> 29) & 7);
- countlen--;
- }
- if ((maddress >= 0x0ac0) && (maddress < 0x0ae0)) {
- int n;
-
- n = (maddress - 0x0ac0) >> 2;
- combiner.setup.stage[n].mapin_rgb.D_input = (Combiner::InputRegister)(data & 15);
- combiner.setup.stage[n].mapin_rgb.D_component = (data >> 4) & 1;
- combiner.setup.stage[n].mapin_rgb.D_mapping = (Combiner::MapFunction)((data >> 5) & 7);
- combiner.setup.stage[n].mapin_rgb.C_input = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.stage[n].mapin_rgb.C_component = (data >> 12) & 1;
- combiner.setup.stage[n].mapin_rgb.C_mapping = (Combiner::MapFunction)((data >> 13) & 7);
- combiner.setup.stage[n].mapin_rgb.B_input = (Combiner::InputRegister)((data >> 16) & 15);
- combiner.setup.stage[n].mapin_rgb.B_component = (data >> 20) & 1;
- combiner.setup.stage[n].mapin_rgb.B_mapping = (Combiner::MapFunction)((data >> 21) & 7);
- combiner.setup.stage[n].mapin_rgb.A_input = (Combiner::InputRegister)((data >> 24) & 15);
- combiner.setup.stage[n].mapin_rgb.A_component = (data >> 28) & 1;
- combiner.setup.stage[n].mapin_rgb.A_mapping = (Combiner::MapFunction)((data >> 29) & 7);
- countlen--;
- }
- if ((maddress >= 0x0a60) && (maddress < 0x0a80)) {
- int n;
-
- n = (maddress - 0x0a60) >> 2;
- combiner_argb8_float(data, combiner.setup.stage[n].constantcolor0);
- countlen--;
- }
- if ((maddress >= 0x0a80) && (maddress < 0x0aa0)) {
- int n;
-
- n = (maddress - 0x0a80) >> 2;
- combiner_argb8_float(data, combiner.setup.stage[n].constantcolor1);
- countlen--;
- }
- if ((maddress >= 0x0aa0) && (maddress < 0x0ac0)) {
- int n;
-
- n = (maddress - 0x0aa0) >> 2;
- combiner.setup.stage[n].mapout_alpha.CD_output = (Combiner::InputRegister)(data & 15);
- combiner.setup.stage[n].mapout_alpha.AB_output = (Combiner::InputRegister)((data >> 4) & 15);
- combiner.setup.stage[n].mapout_alpha.SUM_output = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.stage[n].mapout_alpha.CD_dotproduct = (data >> 12) & 1;
- combiner.setup.stage[n].mapout_alpha.AB_dotproduct = (data >> 13) & 1;
- combiner.setup.stage[n].mapout_alpha.muxsum = (data >> 14) & 1;
- combiner.setup.stage[n].mapout_alpha.bias = (data >> 15) & 1;
- combiner.setup.stage[n].mapout_alpha.scale = (data >> 16) & 3;
- //combiner.=(data >> 27) & 7;
- countlen--;
- }
- if (maddress == 0x1e20) {
- combiner_argb8_float(data, combiner.setup.final.constantcolor0);
- countlen--;
- }
- if (maddress == 0x1e24) {
- combiner_argb8_float(data, combiner.setup.final.constantcolor1);
- countlen--;
- }
- if ((maddress >= 0x1e40) && (maddress < 0x1e60)) {
- int n;
-
- n = (maddress - 0x1e40) >> 2;
- combiner.setup.stage[n].mapout_rgb.CD_output = (Combiner::InputRegister)(data & 15);
- combiner.setup.stage[n].mapout_rgb.AB_output = (Combiner::InputRegister)((data >> 4) & 15);
- combiner.setup.stage[n].mapout_rgb.SUM_output = (Combiner::InputRegister)((data >> 8) & 15);
- combiner.setup.stage[n].mapout_rgb.CD_dotproduct = (data >> 12) & 1;
- combiner.setup.stage[n].mapout_rgb.AB_dotproduct = (data >> 13) & 1;
- combiner.setup.stage[n].mapout_rgb.muxsum = (data >> 14) & 1;
- combiner.setup.stage[n].mapout_rgb.bias = (data >> 15) & 1;
- combiner.setup.stage[n].mapout_rgb.scale = (data >> 16) & 3;
- //combiner.=(data >> 27) & 7;
- countlen--;
- }
- if (maddress == 0x1e60) {
- combiner.setup.stages = data & 15;
- countlen--;
- }
- return 0;
-}
-
-int nv2a_renderer::execute_method_m2mf(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t method, uint32_t address, uint32_t data, int &countlen)
-{
- if (method == 0x0180) {
-#ifdef LOG_NV2A
- machine().logerror("m2mf method 0180 notify\n");
-#endif
- geforce_read_dma_object(data, dma_offset[10], dma_size[10]);
- }
- return 0;
-}
-
-int nv2a_renderer::execute_method_surf2d(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t method, uint32_t address, uint32_t data, int &countlen)
-{
- if (method == 0x0184) {
-#ifdef LOG_NV2A
- machine().logerror("surf2d method 0184 source\n");
-#endif
- geforce_read_dma_object(data, dma_offset[11], dma_size[11]);
- }
- if (method == 0x0188) {
-#ifdef LOG_NV2A
- machine().logerror("surf2d method 0188 destination\n");
-#endif
- geforce_read_dma_object(data, dma_offset[12], dma_size[12]);
- }
- if (method == 0x0300) {
- bitblit.format = data; // 0xa is a8r8g8b8
- }
- if (method == 0x0304) {
- bitblit.pitch_source = data & 0xffff;
- bitblit.pitch_destination = data >> 16;
- }
- if (method == 0x0308) {
- bitblit.source_address = dma_offset[11] + data;
- }
- if (method == 0x030c) {
- bitblit.destination_address = dma_offset[12] + data;
- }
- return 0;
-}
-
-int nv2a_renderer::execute_method_blit(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t method, uint32_t address, uint32_t data, int &countlen)
-{
- if (method == 0x019c) {
-#ifdef LOG_NV2A
- machine().logerror("blit method 019c surface objecct handle %d\n", data); // set to 0x11
-#endif
- }
- if (method == 0x02fc) {
-#ifdef LOG_NV2A
- machine().logerror("blit method 02fc operation %d\n", data); // 3 is copy from source to destination
-#endif
- bitblit.op = data;
- }
- if (method == 0x0300) {
- bitblit.sourcex = data & 0xffff;
- bitblit.sourcey = data >> 16;
- }
- if (method == 0x0304) {
- bitblit.destinationx = data & 0xffff;
- bitblit.destinationy = data >> 16;
- }
- if (method == 0x0308) {
- bitblit.width = data & 0xffff;
- bitblit.heigth = data >> 16;
- surface_2d_blit();
- }
- return 0;
-}
-
-void nv2a_renderer::surface_2d_blit()
-{
- int x, y;
- uint32_t *src, *dest;
- uint32_t *srcrow, *destrow;
-
- if (bitblit.format != 0xa) {
- machine().logerror("Unsupported format %d in surface_2d_blit\n", bitblit.format);
- return;
- }
- srcrow = (uint32_t *)direct_access_ptr(bitblit.source_address + bitblit.pitch_source * bitblit.sourcey + bitblit.sourcex * 4);
- destrow = (uint32_t *)direct_access_ptr(bitblit.destination_address + bitblit.pitch_destination * bitblit.destinationy + bitblit.destinationx * 4);
- for (y = 0; y < bitblit.heigth; y++) {
- src = srcrow;
- dest = destrow;
- for (x = 0; x < bitblit.width; x++) {
- *dest = *src;
- dest++;
- src++;
- }
- srcrow += bitblit.pitch_source >> 2;
- destrow += bitblit.pitch_destination >> 2;
- }
-}
-
-bool nv2a_renderer::toggle_register_combiners_usage()
-{
- combiner.used = 1 - combiner.used;
- return combiner.used != 0;
-}
-
-bool nv2a_renderer::toggle_wait_vblank_support()
-{
- enable_waitvblank = !enable_waitvblank;
- return enable_waitvblank;
-}
-
-bool nv2a_renderer::toggle_clipping_w_support()
-{
- enable_clipping_w = !enable_clipping_w;
- return enable_clipping_w;
-}
-
-void nv2a_renderer::debug_grab_texture(int type, const char *filename)
-{
- debug_grab_texttype = type;
- if (debug_grab_textfile == nullptr)
- debug_grab_textfile = (char *)malloc(128);
- strncpy(debug_grab_textfile, filename, 127);
-}
-
-void nv2a_renderer::debug_grab_vertex_program_slot(int slot, uint32_t *instruction)
-{
- if (slot >= 1024 / 4)
- return;
- instruction[0] = vertexprogram.exec.op[slot].i[0];
- instruction[1] = vertexprogram.exec.op[slot].i[1];
- instruction[2] = vertexprogram.exec.op[slot].i[2];
- instruction[3] = vertexprogram.exec.op[slot].i[3];
-}
-
-void nv2a_renderer::combiner_argb8_float(uint32_t color, float reg[4])
-{
- reg[2] = (float)(color & 0xff) / 255.0f;
- reg[1] = (float)((color >> 8) & 0xff) / 255.0f;
- reg[0] = (float)((color >> 16) & 0xff) / 255.0f;
- reg[3] = (float)((color >> 24) & 0xff) / 255.0f;
-}
-
-uint32_t nv2a_renderer::combiner_float_argb8(float reg[4])
-{
- uint32_t r, g, b, a;
-
- a = reg[3] * 255.0f;
- b = reg[2] * 255.0f;
- g = reg[1] * 255.0f;
- r = reg[0] * 255.0f;
- return (a << 24) | (r << 16) | (g << 8) | b;
-}
-
-float nv2a_renderer::combiner_map_input_select(int id, Combiner::InputRegister code, int index)
-{
- switch ((int)code) {
- case 0:
- default:
- return combiner.work[id].registers.zero[index];
- case 1:
- return combiner.work[id].registers.color0[index];
- case 2:
- return combiner.work[id].registers.color1[index];
- case 3:
- return combiner.work[id].registers.fogcolor[index];
- case 4:
- return combiner.work[id].registers.primarycolor[index];
- case 5:
- return combiner.work[id].registers.secondarycolor[index];
- case 8:
- return combiner.work[id].registers.texture0color[index];
- case 9:
- return combiner.work[id].registers.texture1color[index];
- case 10:
- return combiner.work[id].registers.texture2color[index];
- case 11:
- return combiner.work[id].registers.texture3color[index];
- case 12:
- return combiner.work[id].registers.spare0[index];
- case 13:
- return combiner.work[id].registers.spare1[index];
- case 14:
- return combiner.work[id].variables.sumclamp[index];
- case 15:
- return combiner.work[id].variables.EF[index];
- }
-
- // never executed
- //return 0;
-}
-
-float *nv2a_renderer::combiner_map_input_select_array(int id, Combiner::InputRegister code)
-{
- switch ((int)code) {
- case 0:
- default:
- return combiner.work[id].registers.zero;
- case 1:
- return combiner.work[id].registers.color0;
- case 2:
- return combiner.work[id].registers.color1;
- case 3:
- return combiner.work[id].registers.fogcolor;
- case 4:
- return combiner.work[id].registers.primarycolor;
- case 5:
- return combiner.work[id].registers.secondarycolor;
- case 8:
- return combiner.work[id].registers.texture0color;
- case 9:
- return combiner.work[id].registers.texture1color;
- case 10:
- return combiner.work[id].registers.texture2color;
- case 11:
- return combiner.work[id].registers.texture3color;
- case 12:
- return combiner.work[id].registers.spare0;
- case 13:
- return combiner.work[id].registers.spare1;
- case 14:
- return combiner.work[id].variables.sumclamp;
- case 15:
- return combiner.work[id].variables.EF;
- }
-
- // never executed
- //return 0;
-}
-
-float *nv2a_renderer::combiner_map_output_select_array(int id, Combiner::InputRegister code)
-{
- switch ((int)code) {
- case 0:
- return nullptr;
- case 1:
- return nullptr;
- case 2:
- return nullptr;
- case 3:
- return nullptr;
- case 4:
- return combiner.work[id].registers.primarycolor;
- case 5:
- return combiner.work[id].registers.secondarycolor;
- case 8:
- return combiner.work[id].registers.texture0color;
- case 9:
- return combiner.work[id].registers.texture1color;
- case 10:
- return combiner.work[id].registers.texture2color;
- case 11:
- return combiner.work[id].registers.texture3color;
- case 12:
- return combiner.work[id].registers.spare0;
- case 13:
- return combiner.work[id].registers.spare1;
- case 14:
- return nullptr;
- case 15:
- default:
- return nullptr;
- }
-}
-
-float nv2a_renderer::combiner_map_input_function(Combiner::MapFunction code, float value)
-{
- switch ((int)code) {
- case 0: // unsigned identity
- return std::max(0.0f, value);
- case 1: // unsigned invert
- return 1.0f - std::clamp(value, 0.0f, 1.0f);
- case 2: // expand normal
- return 2.0f * std::max(0.0f, value) - 1.0f;
- case 3: // expand negate
- return -2.0f * std::max(0.0f, value) + 1.0f;
- case 4: // half bias normal
- return std::max(0.0f, value) - 0.5f;
- case 5: // half bias negate
- return -std::max(0.0f, value) + 0.5f;
- case 6: // signed identyty
- return value;
- case 7: // signed negate
- default:
- return -value;
- }
-
- // never executed
- //return 0;
-}
-
-void nv2a_renderer::combiner_map_input_function_array(Combiner::MapFunction code, float *data)
-{
- switch ((int)code) {
- case 0:
- data[0] = std::max(0.0f, data[0]);
- data[1] = std::max(0.0f, data[1]);
- data[2] = std::max(0.0f, data[2]);
- break;
- case 1:
- data[0] = 1.0f - std::clamp(data[0], 0.0f, 1.0f);
- data[1] = 1.0f - std::clamp(data[1], 0.0f, 1.0f);
- data[2] = 1.0f - std::clamp(data[2], 0.0f, 1.0f);
- break;
- case 2:
- data[0] = 2.0f * std::max(0.0f, data[0]) - 1.0f;
- data[1] = 2.0f * std::max(0.0f, data[1]) - 1.0f;
- data[2] = 2.0f * std::max(0.0f, data[2]) - 1.0f;
- break;
- case 3:
- data[0] = -2.0f * std::max(0.0f, data[0]) + 1.0f;
- data[1] = -2.0f * std::max(0.0f, data[1]) + 1.0f;
- data[2] = -2.0f * std::max(0.0f, data[2]) + 1.0f;
- break;
- case 4:
- data[0] = std::max(0.0f, data[0]) - 0.5f;
- data[1] = std::max(0.0f, data[1]) - 0.5f;
- data[2] = std::max(0.0f, data[2]) - 0.5f;
- break;
- case 5:
- data[0] = -std::max(0.0f, data[0]) + 0.5f;
- data[1] = -std::max(0.0f, data[1]) + 0.5f;
- data[2] = -std::max(0.0f, data[2]) + 0.5f;
- break;
- case 6:
- return;
- case 7:
- default:
- data[0] = -data[0];
- data[1] = -data[1];
- data[2] = -data[2];
- break;
- }
-}
-
-void nv2a_renderer::combiner_initialize_registers(int id, float rgba[6][4])
-{
- for (int n = 0; n < 4; n++) {
- combiner.work[id].registers.primarycolor[n] = rgba[0][n];
- combiner.work[id].registers.secondarycolor[n] = rgba[1][n];
- combiner.work[id].registers.texture0color[n] = rgba[2][n];
- combiner.work[id].registers.texture1color[n] = rgba[3][n];
- combiner.work[id].registers.texture2color[n] = rgba[4][n];
- combiner.work[id].registers.texture3color[n] = rgba[5][n];
- combiner.work[id].registers.fogcolor[n] = rgba[6][n];
- }
- combiner.work[id].registers.spare0[3] = combiner.work[id].registers.texture0color[3]; // alpha of spare 0 must be the alpha of the pixel from texture 0
- combiner.work[id].registers.zero[0] = combiner.work[id].registers.zero[1] = combiner.work[id].registers.zero[2] = combiner.work[id].registers.zero[3] = 0;
-}
-
-void nv2a_renderer::combiner_initialize_stage(int id, int stage_number)
-{
- int n = stage_number;
-
- // put register_constantcolor0 in register_color0
- combiner.work[id].registers.color0[0] = combiner.setup.stage[n].constantcolor0[0];
- combiner.work[id].registers.color0[1] = combiner.setup.stage[n].constantcolor0[1];
- combiner.work[id].registers.color0[2] = combiner.setup.stage[n].constantcolor0[2];
- combiner.work[id].registers.color0[3] = combiner.setup.stage[n].constantcolor0[3];
- // put register_constantcolor1 in register_color1
- combiner.work[id].registers.color1[0] = combiner.setup.stage[n].constantcolor1[0];
- combiner.work[id].registers.color1[1] = combiner.setup.stage[n].constantcolor1[1];
- combiner.work[id].registers.color1[2] = combiner.setup.stage[n].constantcolor1[2];
- combiner.work[id].registers.color1[3] = combiner.setup.stage[n].constantcolor1[3];
-}
-
-void nv2a_renderer::combiner_initialize_final(int id)
-{
- // put register_constantcolor0 in register_color0
- combiner.work[id].registers.color0[0] = combiner.setup.final.constantcolor0[0];
- combiner.work[id].registers.color0[1] = combiner.setup.final.constantcolor0[1];
- combiner.work[id].registers.color0[2] = combiner.setup.final.constantcolor0[2];
- combiner.work[id].registers.color0[3] = combiner.setup.final.constantcolor0[3];
- // put register_constantcolor1 in register_color1
- combiner.work[id].registers.color1[0] = combiner.setup.final.constantcolor1[0];
- combiner.work[id].registers.color1[1] = combiner.setup.final.constantcolor1[1];
- combiner.work[id].registers.color1[2] = combiner.setup.final.constantcolor1[2];
- combiner.work[id].registers.color1[3] = combiner.setup.final.constantcolor1[3];
-}
-
-void nv2a_renderer::combiner_map_stage_input(int id, int stage_number)
-{
- int n = stage_number;
- int c, d, i;
- float v, *pv;
-
- // rgb portion
- // A
- // get pointer to rgb components of selected input register
- pv = combiner_map_input_select_array(id, combiner.setup.stage[n].mapin_rgb.A_input);
- c = combiner.setup.stage[n].mapin_rgb.A_component * 3;
- i = combiner.setup.stage[n].mapin_rgb.A_component ^ 1;
- // copy components to A
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.A[d] = pv[c];
- c += i;
- }
- // apply mapping function
- combiner_map_input_function_array(combiner.setup.stage[n].mapin_rgb.A_mapping, combiner.work[id].variables.A);
- // B
- pv = combiner_map_input_select_array(id, combiner.setup.stage[n].mapin_rgb.B_input);
- c = combiner.setup.stage[n].mapin_rgb.B_component * 3;
- i = combiner.setup.stage[n].mapin_rgb.B_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.B[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.stage[n].mapin_rgb.B_mapping, combiner.work[id].variables.B);
- // C
- pv = combiner_map_input_select_array(id, combiner.setup.stage[n].mapin_rgb.C_input);
- c = combiner.setup.stage[n].mapin_rgb.C_component * 3;
- i = combiner.setup.stage[n].mapin_rgb.C_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.C[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.stage[n].mapin_rgb.C_mapping, combiner.work[id].variables.C);
- // D
- pv = combiner_map_input_select_array(id, combiner.setup.stage[n].mapin_rgb.D_input);
- c = combiner.setup.stage[n].mapin_rgb.D_component * 3;
- i = combiner.setup.stage[n].mapin_rgb.D_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.D[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.stage[n].mapin_rgb.D_mapping, combiner.work[id].variables.D);
-
- // alpha portion
- // A
- // get component (blue or alpha) from selected input
- v = combiner_map_input_select(id, combiner.setup.stage[n].mapin_alpha.A_input, 2 + combiner.setup.stage[n].mapin_alpha.A_component);
- // copy component to A
- combiner.work[id].variables.A[3] = combiner_map_input_function(combiner.setup.stage[n].mapin_alpha.A_mapping, v);
- // B
- v = combiner_map_input_select(id, combiner.setup.stage[n].mapin_alpha.B_input, 2 + combiner.setup.stage[n].mapin_alpha.B_component);
- combiner.work[id].variables.B[3] = combiner_map_input_function(combiner.setup.stage[n].mapin_alpha.B_mapping, v);
- // C
- v = combiner_map_input_select(id, combiner.setup.stage[n].mapin_alpha.C_input, 2 + combiner.setup.stage[n].mapin_alpha.C_component);
- combiner.work[id].variables.C[3] = combiner_map_input_function(combiner.setup.stage[n].mapin_alpha.C_mapping, v);
- // D
- v = combiner_map_input_select(id, combiner.setup.stage[n].mapin_alpha.D_input, 2 + combiner.setup.stage[n].mapin_alpha.D_component);
- combiner.work[id].variables.D[3] = combiner_map_input_function(combiner.setup.stage[n].mapin_alpha.D_mapping, v);
-}
-
-void nv2a_renderer::combiner_map_stage_output(int id, int stage_number)
-{
- int n = stage_number;
- float *f;
-
- // rgb
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_rgb.AB_output);
- if (f) {
- f[0] = combiner.work[id].functions.RGBop1[0];
- f[1] = combiner.work[id].functions.RGBop1[1];
- f[2] = combiner.work[id].functions.RGBop1[2];
- }
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_rgb.CD_output);
- if (f) {
- f[0] = combiner.work[id].functions.RGBop2[0];
- f[1] = combiner.work[id].functions.RGBop2[1];
- f[2] = combiner.work[id].functions.RGBop2[2];
- }
- if ((combiner.setup.stage[n].mapout_rgb.AB_dotproduct | combiner.setup.stage[n].mapout_rgb.CD_dotproduct) == 0) {
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_rgb.SUM_output);
- if (f) {
- f[0] = combiner.work[id].functions.RGBop3[0];
- f[1] = combiner.work[id].functions.RGBop3[1];
- f[2] = combiner.work[id].functions.RGBop3[2];
- }
- }
- // alpha
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_alpha.AB_output);
- if (f)
- f[3] = combiner.work[id].functions.Aop1;
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_alpha.CD_output);
- if (f)
- f[3] = combiner.work[id].functions.Aop2;
- f = combiner_map_output_select_array(id, combiner.setup.stage[n].mapout_alpha.SUM_output);
- if (f)
- f[3] = combiner.work[id].functions.Aop3;
-}
-
-void nv2a_renderer::combiner_map_final_input(int id)
-{
- int c, d, i;
- float *pv;
-
- // E
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.E_input);
- c = combiner.setup.final.mapin_rgb.E_component * 3;
- i = combiner.setup.final.mapin_rgb.E_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.E[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.E_mapping, combiner.work[id].variables.E);
- // F
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.F_input);
- c = combiner.setup.final.mapin_rgb.F_component * 3;
- i = combiner.setup.final.mapin_rgb.F_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.F[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.F_mapping, combiner.work[id].variables.F);
- // EF
- combiner.work[id].variables.EF[0] = combiner.work[id].variables.E[0] * combiner.work[id].variables.F[0];
- combiner.work[id].variables.EF[1] = combiner.work[id].variables.E[1] * combiner.work[id].variables.F[1];
- combiner.work[id].variables.EF[2] = combiner.work[id].variables.E[2] * combiner.work[id].variables.F[2];
- // sumclamp
- combiner.work[id].variables.sumclamp[0] = std::max(0.0f, combiner.work[id].registers.spare0[0]) + std::max(0.0f, combiner.work[id].registers.secondarycolor[0]);
- combiner.work[id].variables.sumclamp[1] = std::max(0.0f, combiner.work[id].registers.spare0[1]) + std::max(0.0f, combiner.work[id].registers.secondarycolor[1]);
- combiner.work[id].variables.sumclamp[2] = std::max(0.0f, combiner.work[id].registers.spare0[2]) + std::max(0.0f, combiner.work[id].registers.secondarycolor[2]);
- if (combiner.setup.final.color_sum_clamp != 0) {
- combiner.work[id].variables.sumclamp[0] = std::min(combiner.work[id].variables.sumclamp[0], 1.0f);
- combiner.work[id].variables.sumclamp[1] = std::min(combiner.work[id].variables.sumclamp[1], 1.0f);
- combiner.work[id].variables.sumclamp[2] = std::min(combiner.work[id].variables.sumclamp[2], 1.0f);
- }
- // A
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.A_input);
- c = combiner.setup.final.mapin_rgb.A_component * 3;
- i = combiner.setup.final.mapin_rgb.A_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.A[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.A_mapping, combiner.work[id].variables.A);
- // B
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.B_input);
- c = combiner.setup.final.mapin_rgb.B_component * 3;
- i = combiner.setup.final.mapin_rgb.B_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.B[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.B_mapping, combiner.work[id].variables.B);
- // C
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.C_input);
- c = combiner.setup.final.mapin_rgb.C_component * 3;
- i = combiner.setup.final.mapin_rgb.C_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.C[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.C_mapping, combiner.work[id].variables.C);
- // D
- pv = combiner_map_input_select_array(id, combiner.setup.final.mapin_rgb.D_input);
- c = combiner.setup.final.mapin_rgb.D_component * 3;
- i = combiner.setup.final.mapin_rgb.D_component ^ 1;
- for (d = 0; d < 3; d++) {
- combiner.work[id].variables.D[d] = pv[c];
- c += i;
- }
- combiner_map_input_function_array(combiner.setup.final.mapin_rgb.D_mapping, combiner.work[id].variables.D);
- // G
- combiner.work[id].variables.G = combiner_map_input_select(id, combiner.setup.final.mapin_alpha.G_input, 2 + combiner.setup.final.mapin_alpha.G_component);
-}
-
-void nv2a_renderer::combiner_final_output(int id)
-{
- // rgb
- combiner.work[id].output[0] = combiner.work[id].variables.A[0] * combiner.work[id].variables.B[0] + (1.0f - combiner.work[id].variables.A[0])*combiner.work[id].variables.C[0] + combiner.work[id].variables.D[0];
- combiner.work[id].output[1] = combiner.work[id].variables.A[1] * combiner.work[id].variables.B[1] + (1.0f - combiner.work[id].variables.A[1])*combiner.work[id].variables.C[1] + combiner.work[id].variables.D[1];
- combiner.work[id].output[2] = combiner.work[id].variables.A[2] * combiner.work[id].variables.B[2] + (1.0f - combiner.work[id].variables.A[2])*combiner.work[id].variables.C[2] + combiner.work[id].variables.D[2];
- combiner.work[id].output[0] = std::min(combiner.work[id].output[0], 2.0f);
- combiner.work[id].output[1] = std::min(combiner.work[id].output[1], 2.0f);
- combiner.work[id].output[2] = std::min(combiner.work[id].output[2], 2.0f);
- // a
- combiner.work[id].output[3] = combiner_map_input_function(combiner.setup.final.mapin_alpha.G_mapping, combiner.work[id].variables.G);
-}
-
-void nv2a_renderer::combiner_function_AB(int id, float result[4])
-{
- result[0] = combiner.work[id].variables.A[0] * combiner.work[id].variables.B[0];
- result[1] = combiner.work[id].variables.A[1] * combiner.work[id].variables.B[1];
- result[2] = combiner.work[id].variables.A[2] * combiner.work[id].variables.B[2];
-}
-
-void nv2a_renderer::combiner_function_AdotB(int id, float result[4])
-{
- result[0] = combiner.work[id].variables.A[0] * combiner.work[id].variables.B[0] + combiner.work[id].variables.A[1] * combiner.work[id].variables.B[1] + combiner.work[id].variables.A[2] * combiner.work[id].variables.B[2];
- result[1] = result[0];
- result[2] = result[0];
-}
-
-void nv2a_renderer::combiner_function_CD(int id, float result[4])
-{
- result[0] = combiner.work[id].variables.C[0] * combiner.work[id].variables.D[0];
- result[1] = combiner.work[id].variables.C[1] * combiner.work[id].variables.D[1];
- result[2] = combiner.work[id].variables.C[2] * combiner.work[id].variables.D[2];
-}
-
-void nv2a_renderer::combiner_function_CdotD(int id, float result[4])
-{
- result[0] = combiner.work[id].variables.C[0] * combiner.work[id].variables.D[0] + combiner.work[id].variables.C[1] * combiner.work[id].variables.D[1] + combiner.work[id].variables.C[2] * combiner.work[id].variables.D[2];
- result[1] = result[0];
- result[2] = result[0];
-}
-
-void nv2a_renderer::combiner_function_ABmuxCD(int id, float result[4])
-{
- if (combiner.work[id].registers.spare0[3] >= 0.5f)
- combiner_function_AB(id, result);
- else
- combiner_function_CD(id, result);
-}
-
-void nv2a_renderer::combiner_function_ABsumCD(int id, float result[4])
-{
- result[0] = combiner.work[id].variables.A[0] * combiner.work[id].variables.B[0] + combiner.work[id].variables.C[0] * combiner.work[id].variables.D[0];
- result[1] = combiner.work[id].variables.A[1] * combiner.work[id].variables.B[1] + combiner.work[id].variables.C[1] * combiner.work[id].variables.D[1];
- result[2] = combiner.work[id].variables.A[2] * combiner.work[id].variables.B[2] + combiner.work[id].variables.C[2] * combiner.work[id].variables.D[2];
-}
-
-void nv2a_renderer::combiner_compute_rgb_outputs(int id, int stage_number)
-{
- int n = stage_number;
- int m;
- float bias, scale;
-
- // select bias and scale
- if (combiner.setup.stage[n].mapout_rgb.bias)
- bias = -0.5;
- else
- bias = 0;
- switch (combiner.setup.stage[n].mapout_rgb.scale) {
- case 0:
- default:
- scale = 1.0;
- break;
- case 1:
- scale = 2.0;
- break;
- case 2:
- scale = 4.0;
- break;
- case 3:
- scale = 0.5;
- break;
- }
- // first
- if (combiner.setup.stage[n].mapout_rgb.AB_dotproduct) {
- m = 1;
- combiner_function_AdotB(id, combiner.work[id].functions.RGBop1);
- }
- else {
- m = 0;
- combiner_function_AB(id, combiner.work[id].functions.RGBop1);
- }
- combiner.work[id].functions.RGBop1[0] = std::clamp((combiner.work[id].functions.RGBop1[0] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop1[1] = std::clamp((combiner.work[id].functions.RGBop1[1] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop1[2] = std::clamp((combiner.work[id].functions.RGBop1[2] + bias) * scale, -1.0f, 1.0f);
- // second
- if (combiner.setup.stage[n].mapout_rgb.CD_dotproduct) {
- m = m | 1;
- combiner_function_CdotD(id, combiner.work[id].functions.RGBop2);
- }
- else
- combiner_function_CD(id, combiner.work[id].functions.RGBop2);
- combiner.work[id].functions.RGBop2[0] = std::clamp((combiner.work[id].functions.RGBop2[0] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop2[1] = std::clamp((combiner.work[id].functions.RGBop2[1] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop2[2] = std::clamp((combiner.work[id].functions.RGBop2[2] + bias) * scale, -1.0f, 1.0f);
- // third
- if (m == 0) {
- if (combiner.setup.stage[n].mapout_rgb.muxsum)
- combiner_function_ABmuxCD(id, combiner.work[id].functions.RGBop3);
- else
- combiner_function_ABsumCD(id, combiner.work[id].functions.RGBop3);
- combiner.work[id].functions.RGBop3[0] = std::clamp((combiner.work[id].functions.RGBop3[0] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop3[1] = std::clamp((combiner.work[id].functions.RGBop3[1] + bias) * scale, -1.0f, 1.0f);
- combiner.work[id].functions.RGBop3[2] = std::clamp((combiner.work[id].functions.RGBop3[2] + bias) * scale, -1.0f, 1.0f);
- }
-}
-
-void nv2a_renderer::combiner_compute_alpha_outputs(int id, int stage_number)
-{
- int n = stage_number;
- float bias, scale;
-
- // select bias and scale
- if (combiner.setup.stage[n].mapout_alpha.bias)
- bias = -0.5;
- else
- bias = 0;
- switch (combiner.setup.stage[n].mapout_alpha.scale) {
- case 0:
- default:
- scale = 1.0;
- break;
- case 1:
- scale = 2.0;
- break;
- case 2:
- scale = 4.0;
- break;
- case 3:
- scale = 0.5;
- break;
- }
- // first
- combiner.work[id].functions.Aop1 = combiner.work[id].variables.A[3] * combiner.work[id].variables.B[3];
- combiner.work[id].functions.Aop1 = std::clamp((combiner.work[id].functions.Aop1 + bias) * scale, -1.0f, 1.0f);
- // second
- combiner.work[id].functions.Aop2 = combiner.work[id].variables.C[3] * combiner.work[id].variables.D[3];
- combiner.work[id].functions.Aop2 = std::clamp((combiner.work[id].functions.Aop2 + bias) * scale, -1.0f, 1.0f);
- // third
- if (combiner.setup.stage[n].mapout_alpha.muxsum) {
- if (combiner.work[id].registers.spare0[3] >= 0.5f)
- combiner.work[id].functions.Aop3 = combiner.work[id].variables.A[3] * combiner.work[id].variables.B[3];
- else
- combiner.work[id].functions.Aop3 = combiner.work[id].variables.C[3] * combiner.work[id].variables.D[3];
- }
- else
- combiner.work[id].functions.Aop3 = combiner.work[id].variables.A[3] * combiner.work[id].variables.B[3] + combiner.work[id].variables.C[3] * combiner.work[id].variables.D[3];
- combiner.work[id].functions.Aop3 = std::clamp((combiner.work[id].functions.Aop3 + bias) * scale, -1.0f, 1.0f);
-}
-
-WRITE_LINE_MEMBER(nv2a_renderer::vblank_callback)
-{
-/*#ifdef LOG_NV2A
- printf("vblank_callback\n\r");
-#endif*/
- if ((state != 0) && (puller_waiting == 1)) {
- puller_waiting = 0;
- puller_timer_work(nullptr, 0);
- }
- if (state != 0) {
- pcrtc[0x100 / 4] |= 1;
- pcrtc[0x808 / 4] |= 0x10000;
- }
- else {
- pcrtc[0x100 / 4] &= ~1;
- pcrtc[0x808 / 4] &= ~0x10000;
- }
- if (update_interrupts() == true)
- irq_callback(1); // IRQ 3
- else
- irq_callback(0); // IRQ 3
-}
-
-bool nv2a_renderer::update_interrupts()
-{
- if (pcrtc[0x100 / 4] & pcrtc[0x140 / 4])
- pmc[0x100 / 4] |= 0x1000000;
- else
- pmc[0x100 / 4] &= ~0x1000000;
- if (pgraph[0x100 / 4] & pgraph[0x140 / 4])
- pmc[0x100 / 4] |= 0x1000;
- else
- pmc[0x100 / 4] &= ~0x1000;
- if (((pmc[0x100 / 4] & 0x7fffffff) && (pmc[0x140 / 4] & 1)) || ((pmc[0x100 / 4] & 0x80000000) && (pmc[0x140 / 4] & 2))) {
- // send interrupt
- return true;
- }
- else
- return false;
-}
-
-uint32_t nv2a_renderer::screen_update_callback(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
-{
- if (displayedtarget != nullptr) {
- bitmap_rgb32 bm(displayedtarget, 640, 480, 640);
- uint32_t *dst = (uint32_t *)bitmap.raw_pixptr(0, 0);
-
- //printf("updatescreen %08X\n\r",pcrtc[0x800/4]);
- memcpy(dst, displayedtarget, bitmap.rowbytes()*bitmap.height());
- }
- return 0;
-}
-
-void nv2a_renderer::geforce_assign_object(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t address)
-{
- uint32_t handle, offset, objclass, data;
-
- handle = space.read_dword(address);
- offset = geforce_object_offset(handle);
-#ifdef LOG_NV2A
- machine().logerror(" assign to subchannel %d object at %d in ramin", subchannel, offset);
-#endif
- channel[chanel][subchannel].object.offset = offset;
- data = ramin[offset / 4];
- objclass = data & 0xff;
-#ifdef LOG_NV2A
- machine().logerror(" class %03X\n", objclass);
-#endif
- channel[chanel][subchannel].object.objclass = objclass;
-}
-
-TIMER_CALLBACK_MEMBER(nv2a_renderer::puller_timer_work)
-{
- int chanel;
- int method, count;
- uint32_t *dmaput, *dmaget;
- uint32_t cmd;
- COMMAND cmdtype;
- int countlen;
- int ret;
- address_space *space = puller_space;
- uint32_t subch;
-
- for (chanel = 0; chanel < 32; chanel++) {
- dmaput = &channel[chanel][0].regs[0x40 / 4];
- dmaget = &channel[chanel][0].regs[0x44 / 4];
- while (*dmaget != *dmaput) {
- cmd = space->read_dword(*dmaget);
- *dmaget += 4;
- cmdtype = geforce_commandkind(cmd);
- switch (cmdtype)
- {
- case COMMAND::JUMP:
- #ifdef LOG_NV2A
- machine().logerror("jump dmaget %08X", *dmaget);
- #endif
- *dmaget = cmd & 0xfffffffc;
- #ifdef LOG_NV2A
- machine().logerror(" -> %08X\n\r", *dmaget);
- #endif
- break;
- case COMMAND::INCREASING:
- method = cmd & (2047 << 2); // if method >= 0x100 send it to assigned object
- subch = (cmd >> 13) & 7;
- count = (cmd >> 18) & 2047;
- if ((method == 0) && (count == 1)) { // OBJECT method, bind an engine object to a subchannel
- geforce_assign_object(*space, chanel, subch, *dmaget);
- *dmaget += 4;
- }
- else {
- #ifdef LOG_NV2A
- machine().logerror(" subch. %d method %04x count %d\n", subch, method, count);
- #endif
- ret = 0;
- while (count > 0) {
- countlen = 1;
- ret = execute_method(*space, chanel, subch, method, *dmaget, countlen);
- count--;
- method += 4;
- *dmaget += 4;
- if (ret != 0)
- break;
- }
- if (ret != 0) {
- puller_timer->enable(false);
- puller_waiting = ret;
- return;
- }
- }
- break;
- case COMMAND::NON_INCREASING:
- method = cmd & (2047 << 2);
- subch = (cmd >> 13) & 7;
- count = (cmd >> 18) & 2047;
- if ((method == 0) && (count == 1)) {
- geforce_assign_object(*space, chanel, subch, *dmaget);
- *dmaget += 4;
- }
- else {
- #ifdef LOG_NV2A
- machine().logerror(" subch. %d method %04x count %d\n", subch, method, count);
- #endif
- while (count > 0) {
- countlen = count;
- ret = execute_method(*space, chanel, subch, method, *dmaget, countlen);
- *dmaget += 4 * (count - countlen);
- count = countlen;
- }
- }
- break;
- case COMMAND::LONG_NON_INCREASING:
- method = cmd & (2047 << 2);
- subch = (cmd >> 13) & 7;
- count = space->read_dword(*dmaget);
- *dmaget += 4;
- if ((method == 0) && (count == 1)) {
- geforce_assign_object(*space, chanel, subch, *dmaget);
- *dmaget += 4;
- }
- else {
- #ifdef LOG_NV2A
- machine().logerror(" subch. %d method %04x count %d\n", subch, method, count);
- #endif
- while (count > 0) {
- countlen = count;
- ret = execute_method(*space, chanel, subch, method, *dmaget, countlen);
- *dmaget += 4 * (count - countlen);
- count = countlen;
- }
- }
- break;
- default:
- machine().logerror(" unimplemented command %08X\n", cmd);
- }
- }
- }
-}
-
-uint32_t nv2a_renderer::geforce_r(offs_t offset, uint32_t mem_mask)
-{
- static int x, ret;
-
- ret = 0;
- if (offset == 0x1804f6) {
- x = x ^ 0x08080808;
- ret = x;
- }
- if ((offset >= 0x00100000 / 4) && (offset < 0x00101000 / 4)) {
- //machine().logerror("NV_2A: read PFB[%06X] mask %08X value %08X\n",offset*4-0x00100000,mem_mask,ret);
- if (offset == 0x100200 / 4)
- return 3;
- }
- else if ((offset >= 0x00101000 / 4) && (offset < 0x00102000 / 4)) {
- //machine().logerror("NV_2A: read STRAPS[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,ret);
- }
- else if ((offset >= 0x00002000 / 4) && (offset < 0x00004000 / 4)) {
- ret = pfifo[offset - 0x00002000 / 4];
- // PFIFO.CACHE1.STATUS or PFIFO.RUNOUT_STATUS
- if ((offset == 0x3214 / 4) || (offset == 0x2400 / 4))
- ret = 0x10;
- //machine().logerror("NV_2A: read PFIFO[%06X] value %08X\n",offset*4-0x00002000,ret);
- }
- else if ((offset >= 0x00700000 / 4) && (offset < 0x00800000 / 4)) {
- ret = ramin[offset - 0x00700000 / 4];
- //machine().logerror("NV_2A: read PRAMIN[%06X] value %08X\n",offset*4-0x00700000,ret);
- }
- else if ((offset >= 0x00400000 / 4) && (offset < 0x00402000 / 4)) {
- ret = pgraph[offset - 0x00400000 / 4];
- //machine().logerror("NV_2A: read PGRAPH[%06X] value %08X\n",offset*4-0x00400000,ret);
- }
- else if ((offset >= 0x00600000 / 4) && (offset < 0x00601000 / 4)) {
- ret = pcrtc[offset - 0x00600000 / 4];
- //machine().logerror("NV_2A: read PCRTC[%06X] value %08X\n",offset*4-0x00600000,ret);
- }
- else if ((offset >= 0x00000000 / 4) && (offset < 0x00001000 / 4)) {
- ret = pmc[offset - 0x00000000 / 4];
- //machine().logerror("NV_2A: read PMC[%06X] value %08X\n",offset*4-0x00000000,ret);
- }
- else if ((offset >= 0x00800000 / 4) && (offset < 0x00900000 / 4)) {
- // 32 channels size 0x10000 each, 8 subchannels per channel size 0x2000 each
- int chanel, subchannel, suboffset;
-
- suboffset = offset - 0x00800000 / 4;
- chanel = (suboffset >> (16 - 2)) & 31;
- subchannel = (suboffset >> (13 - 2)) & 7;
- suboffset = suboffset & 0x7ff;
- if (suboffset < 0x80 / 4)
- ret = channel[chanel][subchannel].regs[suboffset];
- //machine().logerror("NV_2A: read channel[%02X,%d,%04X]=%08X\n",chanel,subchannel,suboffset*4,ret);
- return ret;
- }
- //machine().logerror("NV_2A: read at %08X mask %08X value %08X\n",0xfd000000+offset*4,mem_mask,ret);
- return ret;
-}
-
-void nv2a_renderer::geforce_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask)
-{
- uint32_t old;
- bool update_int;
-
- update_int = false;
- if ((offset >= 0x00101000 / 4) && (offset < 0x00102000 / 4)) {
- //machine().logerror("NV_2A: write STRAPS[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,data);
- }
- else if ((offset >= 0x00002000 / 4) && (offset < 0x00004000 / 4)) {
- int e = offset - 0x00002000 / 4;
- if (e >= (sizeof(pfifo) / sizeof(uint32_t)))
- return;
- COMBINE_DATA(pfifo + e);
- //machine().logerror("NV_2A: read PFIFO[%06X]=%08X\n",offset*4-0x00002000,data & mem_mask); // 2210 pfifo ramht & 1f0 << 12
- }
- else if ((offset >= 0x00700000 / 4) && (offset < 0x00800000 / 4)) {
- int e = offset - 0x00700000 / 4;
- if (e >= (sizeof(ramin) / sizeof(uint32_t)))
- return;
- COMBINE_DATA(ramin + e);
- //machine().logerror("NV_2A: write PRAMIN[%06X]=%08X\n",offset*4-0x00700000,data & mem_mask);
- }
- else if ((offset >= 0x00400000 / 4) && (offset < 0x00402000 / 4)) {
- int e = offset - 0x00400000 / 4;
- if (e >= (sizeof(pgraph) / sizeof(uint32_t)))
- return;
- old = pgraph[e];
- COMBINE_DATA(pgraph + e);
- if (e == 0x100 / 4) {
- pgraph[e] = old & ~data;
- if (data & 1)
- pgraph[0x108 / 4] = 0;
- update_int = true;
- }
- if (e == 0x140 / 4)
- update_int = true;
- if (e == 0x720 / 4) {
- if ((data & 1) && (puller_waiting == 2)) {
- puller_waiting = 0;
- puller_timer->enable();
- puller_timer->adjust(attotime::zero);
- }
- }
- if ((e >= 0x900 / 4) && (e < 0xa00 / 4))
- pgraph[e] = 0;
- //machine().logerror("NV_2A: write PGRAPH[%06X]=%08X\n",offset*4-0x00400000,data & mem_mask);
- }
- else if ((offset >= 0x00600000 / 4) && (offset < 0x00601000 / 4)) {
- int e = offset - 0x00600000 / 4;
- if (e >= (sizeof(pcrtc) / sizeof(uint32_t)))
- return;
- old = pcrtc[e];
- COMBINE_DATA(pcrtc + e);
- if (e == 0x100 / 4) {
- pcrtc[e] = old & ~data;
- update_int = true;
- }
- if (e == 0x140 / 4)
- update_int = true;
- if (e == 0x800 / 4) {
- displayedtarget = (uint32_t *)direct_access_ptr(pcrtc[e]);
-#ifdef LOG_NV2A
- printf("crtc buffer %08X\n\r", data);
-#endif
- }
- //machine().logerror("NV_2A: write PCRTC[%06X]=%08X\n",offset*4-0x00600000,data & mem_mask);
- }
- else if ((offset >= 0x00000000 / 4) && (offset < 0x00001000 / 4)) {
- int e = offset - 0x00000000 / 4;
- if (e >= (sizeof(pmc) / sizeof(uint32_t)))
- return;
- COMBINE_DATA(pmc + e);
- if (e == 0x200 / 4) // PMC.ENABLE register
- if (data & 0x1100) // either PFIFO or PGRAPH enabled
- for (int ch = 0; ch < 32; ch++) // zero dma_get in all the channels
- channel[ch][0].regs[0x44 / 4] = 0;
- //machine().logerror("NV_2A: write PMC[%06X]=%08X\n",offset*4-0x00000000,data & mem_mask);
- }
- else if ((offset >= 0x00800000 / 4) && (offset < 0x00900000 / 4)) {
- // 32 channels size 0x10000 each, 8 subchannels per channel size 0x2000 each
- int chanel, subchannel, suboffset;
- //int method, count, handle, objclass;
-
- suboffset = offset - 0x00800000 / 4;
- chanel = (suboffset >> (16 - 2)) & 31;
- subchannel = (suboffset >> (13 - 2)) & 7;
- suboffset = suboffset & 0x7ff;
- //machine().logerror("NV_2A: write channel[%02X,%d,%04X]=%08X\n",chanel,subchannel,suboffset*4,data & mem_mask);
- COMBINE_DATA(&channel[chanel][subchannel].regs[suboffset]);
- if (suboffset >= 0x80 / 4)
- return;
- if ((suboffset == 0x40 / 4) || (suboffset == 0x44 / 4)) { // DMA_PUT or DMA_GET
- uint32_t *dmaput, *dmaget;
-
- dmaput = &channel[chanel][0].regs[0x40 / 4];
- dmaget = &channel[chanel][0].regs[0x44 / 4];
- //printf("dmaget %08X dmaput %08X\n\r",*dmaget,*dmaput);
- if (*dmaget != *dmaput) {
- if (puller_waiting == 0) {
- puller_space = &space;
- puller_timer->enable();
- puller_timer->adjust(attotime::zero);
- }
- }
- }
- }
- //else
- // machine().logerror("NV_2A: write at %08X mask %08X value %08X\n",0xfd000000+offset*4,mem_mask,data);
- if (update_int == true) {
- if (update_interrupts() == true)
- irq_callback(1); // IRQ 3
- else
- irq_callback(0); // IRQ 3
- }
-}
-
-void nv2a_renderer::savestate_items()
-{
-}
-
-void nv2a_renderer::set_ram_base(void *base)
-{
- basemempointer = (uint8_t*)base;
- topmempointer = basemempointer + 512 * 1024 * 1024 - 1;
-}
-
-void nv2a_renderer::start(address_space *cpu_space)
-{
- puller_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nv2a_renderer::puller_timer_work), this), (void *)"NV2A Puller Timer");
- puller_timer->enable(false);
-}