// license:BSD-3-Clause // copyright-holders:Samuele Zannoli /* * geforce 3d (NV2A) vertex program disassembler */ #ifndef MAME_INCLUDES_XBOX_NV2A_H #define MAME_INCLUDES_XBOX_NV2A_H #pragma once #include "machine/pic8259.h" #include "video/poly.h" #include class vertex_program_disassembler { static const char *srctypes[]; static const char *scaops[]; static const int scapar2[]; static const char *vecops[]; static const int vecpar2[]; static const char *vecouts[]; static const char compchar[]; int o[6]; int state; struct sourcefields { int Sign; int SwizzleX; int SwizzleY; int SwizzleZ; int SwizzleW; int TempIndex; int ParameterType; }; struct fields { int ScaOperation; int VecOperation; int SourceConstantIndex; int InputIndex; sourcefields src[3]; int VecTempWriteMask; int VecTempIndex; int ScaTempWriteMask; int OutputWriteMask; int OutputSelect; int OutputIndex; int MultiplexerControl; int Usea0x; int EndOfProgram; }; fields f; void decodefields(unsigned int *dwords, int offset, fields &decoded); int disassemble_mask(int mask, char *s); int disassemble_swizzle(sourcefields f, char *s); int disassemble_source(sourcefields f, fields fi, char *s); int disassemble_output(fields f, char *s); int output_types(fields f, int *o); public: vertex_program_disassembler() { state = 0; } int disassemble(unsigned int *instruction, char *line); }; /* * geforce 3d (NV2A) vertex structure */ struct vertex_nv { union { float fv[4]; uint32_t iv[4]; } attribute[16]; }; /* * geforce 3d (NV2A) vertex program simulator */ class vertex_program_simulator { public: enum VectorialOperation { VecNOP=0, VecMOV, VecMUL, VecADD, VecMAD, VecDP3, VecDPH, VecDP4, VecDST, VecMIN, VecMAX, VecSLT, VecSGE, VecARL }; enum ScalarOperation { ScaNOP=0, ScaIMV, ScaRCP, ScaRCC, ScaRSQ, ScaEXP, ScaLOG, ScaLIT }; vertex_program_simulator(); // input vertex vertex_nv *input; // input parameters struct constant { float fv[4]; void iv(int idx, uint32_t value) { union { uint32_t i; float f; } cnv; cnv.i = value; fv[idx] = cnv.f; } } c_constant[192]; union temp { float fv[4]; } r_temp[32]; // output vertex vertex_nv *output; // instructions struct instruction { unsigned int i[4]; int modified; struct decoded { int SwizzleA[4], SignA, ParameterTypeA, TempIndexA; int SwizzleB[4], SignB, ParameterTypeB, TempIndexB; int SwizzleC[4], SignC, ParameterTypeC, TempIndexC; VectorialOperation VecOperation; ScalarOperation ScaOperation; int OutputWriteMask, MultiplexerControl; int VecTempWriteMask, ScaTempWriteMask; int VecTempIndex, OutputIndex; int InputIndex; int SourceConstantIndex; int OutputSelect; int Usea0x; int EndOfProgram; } d; } op[256]; public: void set_data(vertex_nv *in, vertex_nv *out); void reset(); int step(); void decode_instruction(int address); void execute(); void jump(int address); void process(int address, vertex_nv *in, vertex_nv *out, int count); int status(); private: void initialize_outputs(); void initialize_temps(); void initialize_constants(); void generate_input(float t[4], int sign, int type, int temp, int swizzle[4]); void compute_vectorial_operation(float t[4], int instruction, float par[3 * 4]); void compute_scalar_operation(float t[4], int instruction, float par[3 * 4]); int ip; int a0x; }; class nv2a_renderer; // forward declaration struct nvidia_object_data { nv2a_renderer *data; }; /* * geforce 3d (NV2A) accelerator */ /* very simplified view there is a set of context objects context objects are stored in RAMIN each context object is identified by an handle stored in RAMHT each context object can be assigned to a channel to assign you give to the channel an handle for the object offset in ramht=(((((handle >> 11) xor handle) >> 11) xor handle) & 0x7ff)*8 offset in ramht contains the handle itself offset in ramht+4 contains in the lower 16 bits the offset in RAMIN divided by 16 objects have methods used to do drawing most methods set parameters, others actually draw */ class nv2a_renderer : public poly_manager { public: enum class VERTEX_PARAMETER { PARAM_COLOR_B = 0, PARAM_COLOR_G = 1, PARAM_COLOR_R = 2, PARAM_COLOR_A = 3, PARAM_TEXTURE0_U = 4, PARAM_TEXTURE0_V = 5, PARAM_TEXTURE1_U = 6, PARAM_TEXTURE1_V = 7, PARAM_TEXTURE2_U = 8, PARAM_TEXTURE2_V = 9, PARAM_TEXTURE3_U = 10, PARAM_TEXTURE3_V = 11, PARAM_Z = 12 }; enum class NV2A_BEGIN_END { STOP = 0, POINTS = 1, LINES = 2, LINE_LOOP = 3, LINE_STRIP = 4, TRIANGLES = 5, TRIANGLE_STRIP = 6, TRIANGLE_FAN = 7, QUADS = 8, QUAD_STRIP = 9, POLYGON = 10 }; enum class NV2A_VERTEX_ATTR { POS = 0, // position WEIGHT = 1, // blend weight NORMAL = 2, COLOR0 = 3, // diffuse COLOR1 = 4, // specular FOG = 5, BACKCOLOR0 = 7, // back diffuse BACKCOLOR1 = 8, // back specular TEX0 = 9, // texture coordinate TEX1 = 10, TEX2 = 11, TEX3 = 12 }; enum class NV2A_VTXBUF_TYPE { UBYTE_D3D = 0, // what is the difference with opengl UBYTE ? FLOAT = 2, UBYTE_OGL = 4, USHORT = 5, FLOAT_PACKED = 6 // used for vertex color }; enum class NV2A_TEX_FORMAT { L8 = 0x0, I8 = 0x1, A1R5G5B5 = 0x2, A4R4G4B4 = 0x4, R5G6B5 = 0x5, A8R8G8B8 = 0x6, X8R8G8B8 = 0x7, INDEX8 = 0xb, DXT1 = 0xc, DXT3 = 0xe, DXT5 = 0xf, A1R5G5B5_RECT = 0x10, R5G6B5_RECT = 0x11, A8R8G8B8_RECT = 0x12, L8_RECT = 0x13, DSDT8_RECT = 0x17, A8L8 = 0x1a, I8_RECT = 0x1b, A4R4G4B4_RECT = 0x1d, R8G8B8_RECT = 0x1e, A8L8_RECT = 0x20, Z24 = 0x2a, Z24_RECT = 0x2b, Z16 = 0x2c, Z16_RECT = 0x2d, DSDT8 = 0x28, HILO16 = 0x33, HILO16_RECT = 0x36, HILO8 = 0x44, SIGNED_HILO8 = 0x45, HILO8_RECT = 0x46, SIGNED_HILO8_RECT = 0x47 }; enum class NV2A_LOGIC_OP { CLEAR = 0x1500, AND = 0x1501, AND_REVERSE = 0x1502, COPY = 0x1503, AND_INVERTED = 0x1504, NOOP = 0x1505, XOR = 0x1506, OR = 0x1507, NOR = 0x1508, EQUIV = 0x1509, INVERT = 0x150a, OR_REVERSE = 0x150b, COPY_INVERTED = 0x150c, OR_INVERTED = 0x150d, NAND = 0x150e, SET = 0x150f }; enum class NV2A_BLEND_EQUATION { FUNC_ADD = 0x8006, MIN = 0x8007, MAX = 0x8008, FUNC_SUBTRACT = 0x800a, FUNC_REVERSE_SUBTRACT = 0x80b }; enum class NV2A_BLEND_FACTOR { ZERO = 0x0000, ONE = 0x0001, SRC_COLOR = 0x0300, ONE_MINUS_SRC_COLOR = 0x0301, SRC_ALPHA = 0x0302, ONE_MINUS_SRC_ALPHA = 0x0303, DST_ALPHA = 0x0304, ONE_MINUS_DST_ALPHA = 0x0305, DST_COLOR = 0x0306, ONE_MINUS_DST_COLOR = 0x0307, SRC_ALPHA_SATURATE = 0x0308, CONSTANT_COLOR = 0x8001, ONE_MINUS_CONSTANT_COLOR = 0x8002, CONSTANT_ALPHA = 0x8003, ONE_MINUS_CONSTANT_ALPHA = 0x8004 }; enum class NV2A_COMPARISON_OP { NEVER = 0x0200, LESS = 0x0201, EQUAL = 0x0202, LEQUAL = 0x0203, GREATER = 0x0204, NOTEQUAL = 0x0205, GEQUAL = 0x0206, ALWAYS = 0x0207 }; enum class NV2A_STENCIL_OP { ZEROOP = 0x0000, INVERTOP = 0x150a, KEEP = 0x1e00, REPLACE = 0x1e01, INCR = 0x1e02, DECR = 0x1e03, INCR_WRAP = 0x8507, DECR_WRAP = 0x8508 }; enum class NV2A_RT_TYPE { LINEAR = 1, SWIZZLED = 2 }; enum class NV2A_RT_DEPTH_FORMAT { Z16 = 0x0001, Z24S8 = 0x0002 }; enum class NV2A_COLOR_FORMAT { X1R5G5B5_Z1R5G5B5 = 1, X1R5G5B5_X1R5G5B5 = 2, R5G6B5 = 3, X8R8G8B8_Z8R8G8B8 = 4, X8R8G8B8_X8R8G8B8 = 5, X1A7R8G8B8_Z1A7R8G8B8 = 6, X1A7R8G8B8_X1A7R8G8B8 = 7, A8R8G8B8 = 8, B8 = 9, G8B8 = 10 }; enum class NV2A_GL_FRONT_FACE { CW = 0x0900, CCW = 0x0901 }; enum class NV2A_GL_CULL_FACE { FRONT = 0x0404, BACK = 0x0405, FRONT_AND_BACK = 0x0408 }; struct nv2avertex_t : public vertex_t { double w; }; nv2a_renderer(running_machine &machine) : poly_manager(machine) { memset(channel, 0, sizeof(channel)); memset(pfifo, 0, sizeof(pfifo)); memset(pcrtc, 0, sizeof(pcrtc)); memset(pmc, 0, sizeof(pmc)); memset(pgraph, 0, sizeof(pgraph)); memset(ramin, 0, sizeof(ramin)); computedilated(); objectdata = &(object_data_alloc()); objectdata->data = this; combiner.used = 0; enabled_vertex_attributes = 0; primitives_total_count = 0; indexesleft_count = 0; triangles_bfculled = 0; vertex_pipeline = 4; color_mask = 0xffffffff; backface_culling_enabled = false; backface_culling_winding = NV2A_GL_FRONT_FACE::CCW; backface_culling_culled = NV2A_GL_CULL_FACE::BACK; alpha_test_enabled = false; alpha_reference = 0; alpha_func = NV2A_COMPARISON_OP::ALWAYS; depth_test_enabled = false; depth_function = NV2A_COMPARISON_OP::LESS; depth_write_enabled = false; stencil_test_enabled = false; stencil_func = NV2A_COMPARISON_OP::ALWAYS; stencil_ref = 0; stencil_mask = -1; stencil_op_fail = NV2A_STENCIL_OP::KEEP; stencil_op_zfail = NV2A_STENCIL_OP::KEEP; stencil_op_zpass = NV2A_STENCIL_OP::KEEP; blending_enabled = false; blend_equation = NV2A_BLEND_EQUATION::FUNC_ADD; blend_color = 0; blend_function_destination = NV2A_BLEND_FACTOR::ZERO; blend_function_source = NV2A_BLEND_FACTOR::ONE; logical_operation_enabled = false; logical_operation = NV2A_LOGIC_OP::COPY; for (int n = 0; n < 8; n++) clippingwindows[n].set(0, 0, 640, 480); limits_rendertarget.set(0, 0, 640, 480); pitch_rendertarget = 0; pitch_depthbuffer = 0; size_rendertarget = 0; size_depthbuffer = 0; log2height_rendertarget = 0; log2width_rendertarget = 0; dilate_rendertarget = 0; antialiasing_rendertarget = 0; type_rendertarget = NV2A_RT_TYPE::LINEAR; depthformat_rendertarget = NV2A_RT_DEPTH_FORMAT::Z24S8; colorformat_rendertarget = NV2A_COLOR_FORMAT::A8R8G8B8; bytespixel_rendertarget = 4; clear_rendertarget.set(0, 0, 639, 479); primitive_type = NV2A_BEGIN_END::STOP; antialias_control = 0; supersample_factor_x = 1.0; supersample_factor_y = 1.0; rendertarget = nullptr; depthbuffer = nullptr; displayedtarget = nullptr; puller_waiting = 0; debug_grab_texttype = -1; debug_grab_textfile = nullptr; enable_waitvblank = true; enable_clipping_w = false; memset(vertex_attribute_words, 0, sizeof(vertex_attribute_words)); memset(vertex_attribute_offset, 0, sizeof(vertex_attribute_offset)); memset(&persistvertexattr, 0, sizeof(persistvertexattr)); for (int n = 0; n < 16; n++) persistvertexattr.attribute[n].fv[3] = 1; } DECLARE_READ32_MEMBER(geforce_r); DECLARE_WRITE32_MEMBER(geforce_w); DECLARE_WRITE_LINE_MEMBER(vblank_callback); uint32_t screen_update_callback(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); bool update_interrupts(); void set_irq_callbaclk(std::function callback) { irq_callback = callback; } void render_texture_simple(int32_t scanline, const extent_t &extent, const nvidia_object_data &extradata, int threadid); void render_color(int32_t scanline, const extent_t &extent, const nvidia_object_data &extradata, int threadid); void render_register_combiners(int32_t scanline, const extent_t &extent, const nvidia_object_data &objectdata, int threadid); int geforce_commandkind(uint32_t word); uint32_t geforce_object_offset(uint32_t handle); void geforce_read_dma_object(uint32_t handle, uint32_t &offset, uint32_t &size); void geforce_assign_object(address_space &space, uint32_t chanel, uint32_t subchannel, uint32_t address); int geforce_exec_method(address_space &space, uint32_t channel, uint32_t subchannel, uint32_t method, uint32_t address, int &countlen); uint32_t texture_get_texel(int number, int x, int y); uint8_t *read_pixel(int x, int y, int32_t c[4]); void write_pixel(int x, int y, uint32_t color, int depth); void combiner_initialize_registers(uint32_t argb8[6]); void combiner_initialize_stage(int stage_number); void combiner_initialize_final(); void combiner_map_input(int stage_number); // map combiner registers to variables A..D void combiner_map_output(int stage_number); // map combiner calculation results to combiner registers void combiner_map_final_input(); // map final combiner registers to variables A..F void combiner_final_output(); // generate final combiner output float combiner_map_input_select(int code, int index); // get component index in register code float *combiner_map_input_select3(int code); // get pointer to register code float *combiner_map_output_select3(int code); // get pointer to register code for output float combiner_map_input_function(int code, float value); // apply input mapping function code to value void combiner_map_input_function3(int code, float *data); // apply input mapping function code to data void combiner_function_AB(float result[4]); void combiner_function_AdotB(float result[4]); void combiner_function_CD(float result[4]); void combiner_function_CdotD(float result[4]); void combiner_function_ABmuxCD(float result[4]); void combiner_function_ABsumCD(float result[4]); void combiner_compute_rgb_outputs(int index); void combiner_compute_a_outputs(int index); void combiner_argb8_float(uint32_t color, float reg[4]); uint32_t combiner_float_argb8(float reg[4]); uint32_t dilate0(uint32_t value, int bits); uint32_t dilate1(uint32_t value, int bits); void computedilated(void); bool toggle_register_combiners_usage(); bool toggle_wait_vblank_support(); bool toggle_clipping_w_support(); void debug_grab_texture(int type, const char *filename); void debug_grab_vertex_program_slot(int slot, uint32_t *instruction); void start(address_space *cpu_space); void savestate_items(); void compute_supersample_factors(float &horizontal, float &vertical); void compute_limits_rendertarget(uint32_t chanel, uint32_t subchannel); void compute_size_rendertarget(uint32_t chanel, uint32_t subchannel); void extract_packed_float(uint32_t data, float &first, float &second, float &third); void read_vertex(address_space & space, offs_t address, vertex_nv &vertex, int attrib); int read_vertices_0x180x(address_space & space, vertex_nv *destination, uint32_t address, int limit); int read_vertices_0x1810(address_space & space, vertex_nv *destination, int offset, int limit); int read_vertices_0x1818(address_space & space, vertex_nv *destination, uint32_t address, int limit); void convert_vertices_poly(vertex_nv *source, nv2avertex_t *destination, int count); void assemble_primitive(vertex_nv *source, int count, render_delegate &renderspans); int clip_triangle_w(nv2avertex_t *vi[3], nv2avertex_t *vo); uint32_t render_triangle_clipping(const rectangle &cliprect, render_delegate callback, int paramcount, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3); uint32_t render_triangle_culling(const rectangle &cliprect, render_delegate callback, int paramcount, nv2avertex_t &_v1, nv2avertex_t &_v2, nv2avertex_t &_v3); void clear_render_target(int what, uint32_t value); void clear_depth_buffer(int what, uint32_t value); inline uint8_t *direct_access_ptr(offs_t address); TIMER_CALLBACK_MEMBER(puller_timer_work); struct { uint32_t regs[0x80 / 4]; struct { uint32_t objhandle; uint32_t objclass; uint32_t method[0x2000 / 4]; // int execute_method(address_space & space, uint32_t method, uint32_t address, int &countlen); // for the future } object; } channel[32][8]; uint32_t pfifo[0x2000 / 4]; uint32_t pcrtc[0x1000 / 4]; uint32_t pmc[0x1000 / 4]; uint32_t pgraph[0x2000 / 4]; uint32_t ramin[0x100000 / 4]; uint32_t dma_offset[2]; uint32_t dma_size[2]; uint8_t *basemempointer; uint8_t *topmempointer; std::function irq_callback; rectangle clippingwindows[8]; rectangle limits_rendertarget; uint32_t pitch_rendertarget; uint32_t pitch_depthbuffer; uint32_t size_rendertarget; uint32_t size_depthbuffer; int log2height_rendertarget; int log2width_rendertarget; int dilate_rendertarget; int antialiasing_rendertarget; NV2A_RT_TYPE type_rendertarget; NV2A_RT_DEPTH_FORMAT depthformat_rendertarget; NV2A_COLOR_FORMAT colorformat_rendertarget; int bytespixel_rendertarget; rectangle clear_rendertarget; uint32_t antialias_control; float supersample_factor_x; float supersample_factor_y; uint32_t *rendertarget; uint32_t *depthbuffer; uint32_t *displayedtarget; uint32_t vertexbuffer_address[16]; int vertexbuffer_stride[16]; NV2A_VTXBUF_TYPE vertexbuffer_kind[16]; int vertexbuffer_size[16]; struct { int enabled; int sizeu; int sizev; int sizew; int dilate; NV2A_TEX_FORMAT format; bool rectangle; int rectangle_pitch; void *buffer; int dma0; int dma1; int cubic; int noborder; int dims; int mipmap; int colorkey; int imagefield; int aniso; int mipmapmaxlod; int mipmapminlod; int rectheight; int rectwidth; } texture[4]; uint32_t triangles_bfculled; NV2A_BEGIN_END primitive_type; uint32_t primitives_count; uint32_t primitives_total_count; int indexesleft_count; int indexesleft_first; uint32_t vertex_indexes[1024]; // vertex indices sent by the software to the 3d accelerator int vertex_count; unsigned int vertex_first; int vertex_accumulated; vertex_nv vertex_software[1024+2]; // vertex attributes sent by the software to the 3d accelerator nv2avertex_t vertex_xy[1024+2]; // vertex attributes computed by the 3d accelerator vertex_nv persistvertexattr; // persistent vertex attributes render_delegate render_spans_callback; struct { float variable_A[4]; // 0=R 1=G 2=B 3=A float variable_B[4]; float variable_C[4]; float variable_D[4]; float variable_E[4]; float variable_F[4]; float variable_G; float variable_EF[4]; float variable_sumclamp[4]; float function_RGBop1[4]; // 0=R 1=G 2=B float function_RGBop2[4]; float function_RGBop3[4]; float function_Aop1; float function_Aop2; float function_Aop3; float register_primarycolor[4]; // rw float register_secondarycolor[4]; float register_texture0color[4]; float register_texture1color[4]; float register_texture2color[4]; float register_texture3color[4]; float register_color0[4]; float register_color1[4]; float register_spare0[4]; float register_spare1[4]; float register_fogcolor[4]; // ro float register_zero[4]; float output[4]; struct { float register_constantcolor0[4]; float register_constantcolor1[4]; int mapin_aA_input; int mapin_aA_component; int mapin_aA_mapping; int mapin_aB_input; int mapin_aB_component; int mapin_aB_mapping; int mapin_aC_input; int mapin_aC_component; int mapin_aC_mapping; int mapin_aD_input; int mapin_aD_component; int mapin_aD_mapping; int mapin_rgbA_input; int mapin_rgbA_component; int mapin_rgbA_mapping; int mapin_rgbB_input; int mapin_rgbB_component; int mapin_rgbB_mapping; int mapin_rgbC_input; int mapin_rgbC_component; int mapin_rgbC_mapping; int mapin_rgbD_input; int mapin_rgbD_component; int mapin_rgbD_mapping; int mapout_aCD_output; int mapout_aAB_output; int mapout_aSUM_output; int mapout_aCD_dotproduct; int mapout_aAB_dotproduct; int mapout_a_muxsum; int mapout_a_bias; int mapout_a_scale; int mapout_rgbCD_output; int mapout_rgbAB_output; int mapout_rgbSUM_output; int mapout_rgbCD_dotproduct; int mapout_rgbAB_dotproduct; int mapout_rgb_muxsum; int mapout_rgb_bias; int mapout_rgb_scale; } stage[8]; struct { float register_constantcolor0[4]; float register_constantcolor1[4]; int color_sum_clamp; int mapin_rgbA_input; int mapin_rgbA_component; int mapin_rgbA_mapping; int mapin_rgbB_input; int mapin_rgbB_component; int mapin_rgbB_mapping; int mapin_rgbC_input; int mapin_rgbC_component; int mapin_rgbC_mapping; int mapin_rgbD_input; int mapin_rgbD_component; int mapin_rgbD_mapping; int mapin_rgbE_input; int mapin_rgbE_component; int mapin_rgbE_mapping; int mapin_rgbF_input; int mapin_rgbF_component; int mapin_rgbF_mapping; int mapin_aG_input; int mapin_aG_component; int mapin_aG_mapping; } final; int stages; int used; std::mutex lock; } combiner; uint32_t color_mask; bool backface_culling_enabled; NV2A_GL_FRONT_FACE backface_culling_winding; NV2A_GL_CULL_FACE backface_culling_culled; bool alpha_test_enabled; NV2A_COMPARISON_OP alpha_func; int alpha_reference; bool depth_test_enabled; NV2A_COMPARISON_OP depth_function; bool depth_write_enabled; bool stencil_test_enabled; NV2A_COMPARISON_OP stencil_func; int stencil_ref; int stencil_mask; NV2A_STENCIL_OP stencil_op_fail; NV2A_STENCIL_OP stencil_op_zfail; NV2A_STENCIL_OP stencil_op_zpass; bool blending_enabled; NV2A_BLEND_EQUATION blend_equation; NV2A_BLEND_FACTOR blend_function_source; NV2A_BLEND_FACTOR blend_function_destination; uint32_t blend_color; bool logical_operation_enabled; NV2A_LOGIC_OP logical_operation; struct { float modelview[4][4]; float modelview_inverse[4][4]; float composite[4][4]; float projection[4][4]; float translate[4]; float scale[4]; } matrix; struct { vertex_program_simulator exec; int instructions; int upload_instruction_index; int upload_instruction_component; int start_instruction; int upload_parameter_index; int upload_parameter_component; } vertexprogram; int vertex_pipeline; int enabled_vertex_attributes; int vertex_attribute_words[16]; int vertex_attribute_offset[16]; emu_timer *puller_timer; int puller_waiting; address_space *puller_space; uint32_t dilated0[16][2048]; uint32_t dilated1[16][2048]; int dilatechose[256]; nvidia_object_data *objectdata; int debug_grab_texttype; char *debug_grab_textfile; bool enable_waitvblank; bool enable_clipping_w; }; #endif // MAME_INCLUDES_XBOX_NV2A_H