diff options
author | yz70s <yz70s@users.noreply.github.com> | 2015-08-28 09:59:54 +0200 |
---|---|---|
committer | yz70s <yz70s@users.noreply.github.com> | 2015-08-28 10:08:55 +0200 |
commit | ece079aa7438e3342272ff52eebbc8a233f00786 (patch) | |
tree | e4ea4cedf25cdb9901f15d019357c4629d7221dd | |
parent | 017ebde24e06e7799fc0e8453321a725ee71f780 (diff) |
chihiro.c: under the hood 3d accelerator changes [Samuele Zannoli]
-correct some errors
-add more primitives to some graphic methods
-add color mask support
-method 0x100 (NOP) generates correct interrupt
-some method parameters are readable from mmio registers
-rw-r--r-- | src/mame/includes/chihiro.h | 9 | ||||
-rw-r--r-- | src/mame/video/chihiro.c | 252 |
2 files changed, 221 insertions, 40 deletions
diff --git a/src/mame/includes/chihiro.h b/src/mame/includes/chihiro.h index 55f6e20ab8c..85f47d52e88 100644 --- a/src/mame/includes/chihiro.h +++ b/src/mame/includes/chihiro.h @@ -185,6 +185,7 @@ public: 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()); @@ -194,6 +195,7 @@ public: enabled_vertex_attributes = 0; indexesleft_count = 0; vertex_pipeline = 4; + color_mask = 0xffffffff; alpha_test_enabled = false; alpha_reference = 0; alpha_func = nv2a_renderer::ALWAYS; @@ -238,8 +240,10 @@ public: } DECLARE_READ32_MEMBER(geforce_r); DECLARE_WRITE32_MEMBER(geforce_w); - bool vblank_callback(screen_device &screen, bool state); + void vblank_callback(screen_device &screen, bool state); UINT32 screen_update_callback(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + bool update_interrupts(); + void set_interrupt_device(pic8259_device *device); void render_texture_simple(INT32 scanline, const extent_t &extent, const nvidia_object_data &extradata, int threadid); void render_color(INT32 scanline, const extent_t &extent, const nvidia_object_data &extradata, int threadid); @@ -303,10 +307,12 @@ public: UINT32 pfifo[0x2000 / 4]; UINT32 pcrtc[0x1000 / 4]; UINT32 pmc[0x1000 / 4]; + UINT32 pgraph[0x2000 / 4]; UINT32 ramin[0x100000 / 4]; UINT32 dma_offset[2]; UINT32 dma_size[2]; UINT8 *basemempointer; + pic8259_device *interruptdevice; rectangle limits_rendertarget; UINT32 pitch_rendertarget; UINT32 pitch_depthbuffer; @@ -441,6 +447,7 @@ public: int used; osd_lock *lock; } combiner; + UINT32 color_mask; bool alpha_test_enabled; int alpha_func; int alpha_reference; diff --git a/src/mame/video/chihiro.c b/src/mame/video/chihiro.c index 734c18853ec..70a529ed784 100644 --- a/src/mame/video/chihiro.c +++ b/src/mame/video/chihiro.c @@ -3,6 +3,7 @@ #include "emu.h" #include "video/poly.h" #include "bitmap.h" +#include "machine/pic8259.h" #include "includes/chihiro.h" //#define LOG_NV2A @@ -945,14 +946,20 @@ int nv2a_renderer::geforce_commandkind(UINT32 word) UINT32 nv2a_renderer::geforce_object_offset(UINT32 handle) { UINT32 h = ((((handle >> 11) ^ handle) >> 11) ^ handle) & 0x7ff; - UINT32 o = (pfifo[0x210 / 4] & 0x1f) << 8; // or 12 ? + UINT32 o = (pfifo[0x210 / 4] & 0x1ff) << 8; // 0x1ff is not certain UINT32 e = o + h * 8; // at 0xfd000000+0x00700000 UINT32 w; - if (ramin[e / 4] != handle) - e = 0; + if (ramin[e / 4] != handle) { + // this should never happen + for (UINT32 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; + return (w & 0xffff) * 0x10; // 0xffff is not certain } void nv2a_renderer::geforce_read_dma_object(UINT32 handle, UINT32 &offset, UINT32 &size) @@ -1246,7 +1253,9 @@ void nv2a_renderer::write_pixel(int x, int y, UINT32 color, UINT32 depth) addr = rendertarget + (dilated0[dilate_rendertarget][x] + dilated1[dilate_rendertarget][y]); else // type_rendertarget == LINEAR*/ addr = rendertarget + (pitch_rendertarget / 4)*y + x; - fbcolor = *addr; + fbcolor = 0; + if (color_mask != 0) + fbcolor = *addr; daddr=depthbuffer + (pitch_depthbuffer / 4)*y + x; deptsten = *daddr; c[3] = color >> 24; @@ -1772,8 +1781,12 @@ void nv2a_renderer::write_pixel(int x, int y, UINT32 color, UINT32 depth) break; } } - fbcolor = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0]; - *addr = fbcolor; + if (color_mask != 0) { + UINT32 fbcolor_tmp; + + fbcolor_tmp = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0]; + *addr = (fbcolor & ~color_mask) | (fbcolor_tmp & color_mask); + } if (depth_write_enabled) dep = depth; deptsten = (dep << 8) | sten; @@ -2233,6 +2246,9 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN maddress = method * 4; data = space.read_dword(address); channel[chanel][subchannel].object.method[method] = data; +#ifdef LOG_NV2A + printf("A:%08X MTHD:%08X D:%08X\n\r",address,maddress,data); +#endif if (maddress == 0x17fc) { indexesleft_count = 0; indexesleft_first = 0; @@ -2270,6 +2286,21 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN } wait(); } + else if (type == nv2a_renderer::TRIANGLE_FAN) { + vertex_nv vert[3]; + vertex_t xy[3]; + + read_vertices_0x1810(space, vert, offset, 2); + convert_vertices_poly(vert, xy, 2); + count = count - 2; + offset = offset + 2; + for (n = 0; n <= count; n++) { + read_vertices_0x1810(space, vert + (((n + 1) & 1) + 1), offset + n, 1); + convert_vertices_poly(vert + (((n + 1) & 1) + 1), xy + (((n + 1) & 1) + 1), 1); + render_triangle(limits_rendertarget, renderspans, 4 + 4 * 2, xy[0], xy[(~(n + 1) & 1) + 1], xy[((n + 1) & 1) + 1]); + } + wait(); + } else if (type == nv2a_renderer::TRIANGLE_STRIP) { vertex_nv vert[4]; vertex_t xy[4]; @@ -2311,9 +2342,6 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN // 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 type = channel[chanel][subchannel].object.method[0x17fc / 4]; -#ifdef LOG_NV2A - printf("vertex %d %d %d\n\r", type, offset, count); -#endif if (type == nv2a_renderer::QUADS) { while (1) { vertex_nv vert[4]; @@ -2332,6 +2360,34 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN render_polygon<4>(limits_rendertarget, renderspans, 4 + 4 * 2, xy); // 4 rgba, 4 texture units 2 uv } } + else if (type == nv2a_renderer::TRIANGLE_FAN) { + if ((countlen * mult + indexesleft_count) >= 3) { + vertex_nv vert[3]; + vertex_t xy[3]; + int c, count; + + if (mult == 1) + c = read_vertices_0x1808(space, vert, address, 2); + else + c = read_vertices_0x1800(space, vert, address, 2); + convert_vertices_poly(vert, xy, 2); + address = address + c * 4; + countlen = countlen - c; + count = countlen * mult + indexesleft_count; + for (n = 1; n <= count; n++) { + if (mult == 1) + c = read_vertices_0x1808(space, vert + ((n & 1) + 1), address, 1); + else + c = read_vertices_0x1800(space, vert + ((n & 1) + 1), address, 1); + + convert_vertices_poly(vert + ((n & 1) + 1), xy + ((n & 1) + 1), 1); + address = address + c * 4; + countlen = countlen - c; + render_triangle(limits_rendertarget, renderspans, 4 + 4 * 2, xy[0], xy[(~n & 1) + 1], xy[(n & 1) + 1]); + } + wait(); + } + } else if (type == nv2a_renderer::TRIANGLES) { while (1) { vertex_nv vert[3]; @@ -2446,6 +2502,24 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN } wait(); } + else if (type == nv2a_renderer::TRIANGLES) { + while (countlen > 0) { + vertex_nv vert[3]; + vertex_t xy[3]; + int c; + + c = read_vertices_0x1818(space, vert, address, 3); + convert_vertices_poly(vert, xy, 3); + countlen = countlen - c; + if (countlen < 0) { + logerror("Method 0x1818 missing %d words to draw a complete primitive\n", -countlen); + countlen = 0; + break; + } + address = address + c * 3; + render_triangle(limits_rendertarget, renderspans, 4 + 4 * 2, xy[0], xy[1], xy[2]); // 4 rgba, 4 texture units 2 uv + } + } else if (type == nv2a_renderer::TRIANGLE_STRIP) { vertex_nv vert[4]; vertex_t xy[4]; @@ -2613,7 +2687,9 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN // clear colors UINT32 color = channel[chanel][subchannel].object.method[0x1d90 / 4]; bm.fill(color); - //printf("clearscreen\n\r"); +#ifdef LOG_NV2A + printf("clearscreen\n\r"); +#endif } if ((data & 0x03) == 3) { bitmap_rgb32 bm(depthbuffer, (limits_rendertarget.right() + 1) * m, (limits_rendertarget.bottom() + 1) * m, pitch_rendertarget / 4); // why *2 ? @@ -2649,19 +2725,28 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN dilate_rendertarget = dilatechose[(log2width_rendertarget << 4) + log2height_rendertarget]; } if (maddress == 0x020c) { - // line size ? pitch_rendertarget=data & 0xffff; pitch_depthbuffer=(data >> 16) & 0xffff; - //printf("Pitch color %04X zbuffer %04X\n\r",pitch_rendertarget,pitch_depthbuffer); +#ifdef LOG_NV2A + printf("Pitch color %04X zbuffer %04X\n\r",pitch_rendertarget,pitch_depthbuffer); +#endif countlen--; } if (maddress == 0x0100) { - // just temporarily - if ((data & 0x1f) == 1) { - data = data >> 5; - data = data & 0x0ffffff0; - displayedtarget = (UINT32 *)direct_access_ptr(data); + countlen--; + if (data != 0) { + pgraph[0x704 / 4] = 0x100; + pgraph[0x708 / 4] = data; + pgraph[0x100 / 4] |= 1; + pgraph[0x108 / 4] |= 1; + if (update_interrupts() == true) + interruptdevice->ir3_w(1); // IRQ 3 + else + interruptdevice->ir3_w(0); // IRQ 3 + return 2; } + else + return 0; } if (maddress == 0x0130) { countlen--; @@ -2670,16 +2755,32 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN 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 ? rendertarget = (UINT32 *)direct_access_ptr(data); - //printf("Render target at %08X\n\r",data); +#ifdef LOG_NV2A + printf("Render target at %08X\n\r", data); +#endif countlen--; } if (maddress == 0x0214) { // zbuffer offset ? depthbuffer = (UINT32 *)direct_access_ptr(data); - //printf("Depth buffer at %08X\n\r",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) @@ -2709,6 +2810,18 @@ int nv2a_renderer::geforce_exec_method(address_space & space, UINT32 chanel, UIN if (maddress == 0x0354) { depth_function = 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 g = channel[chanel][subchannel].object.method[0x0214 / 4]; depth_write_enabled = data != 0; @@ -3648,22 +3761,40 @@ void nv2a_renderer::combiner_compute_a_outputs(int stage_number) combiner.function_Aop3 = MAX(MIN((combiner.function_Aop3 + biasa) * scalea, 1.0f), -1.0f); } -bool nv2a_renderer::vblank_callback(screen_device &screen, bool state) +void nv2a_renderer::vblank_callback(screen_device &screen, bool state) { - //printf("vblank_callback\n\r"); - if (state == true) +#ifdef LOG_NV2A + printf("vblank_callback\n\r"); +#endif + if ((state == true) && (puller_waiting == 1)) { + puller_waiting = 0; + puller_timer_work(NULL, 0); + } + if (state == true) { pcrtc[0x100 / 4] |= 1; - else + pcrtc[0x808 / 4] |= 0x10000; + } + else { pcrtc[0x100 / 4] &= ~1; + pcrtc[0x808 / 4] &= ~0x10000; + } + if (update_interrupts() == true) + interruptdevice->ir3_w(1); // IRQ 3 + else + interruptdevice->ir3_w(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 ((state == true) && (puller_waiting == 1)) { - puller_waiting = 0; - puller_timer_work(NULL, 0); - } - if ((pmc[0x100 / 4] != 0) && (pmc[0x140 / 4] != 0)) { + 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; } @@ -3692,6 +3823,9 @@ TIMER_CALLBACK_MEMBER(nv2a_renderer::puller_timer_work) int countlen; int ret; address_space *space = puller_space; +#ifdef LOG_NV2A + UINT32 subch; +#endif chanel = puller_channel; subchannel = puller_subchannel; @@ -3748,7 +3882,7 @@ TIMER_CALLBACK_MEMBER(nv2a_renderer::puller_timer_work) } if (ret != 0) { puller_timer->enable(false); - puller_waiting = 1; + puller_waiting = ret; return; } } @@ -3847,6 +3981,7 @@ READ32_MEMBER(nv2a_renderer::geforce_r) //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]; //logerror("NV_2A: read PGRAPH[%06X] value %08X\n",offset*4-0x00400000,ret); } else if ((offset >= 0x00600000 / 4) && (offset < 0x00601000 / 4)) { @@ -3870,16 +4005,16 @@ READ32_MEMBER(nv2a_renderer::geforce_r) //logerror("NV_2A: read channel[%02X,%d,%04X]=%08X\n",chanel,subchannel,suboffset*4,ret); return ret; } - else - { - /* nothing */ - } //logerror("NV_2A: read at %08X mask %08X value %08X\n",0xfd000000+offset*4,mem_mask,ret); return ret; } WRITE32_MEMBER(nv2a_renderer::geforce_w) { + UINT32 old; + bool update_int; + + update_int = false; if ((offset >= 0x00101000 / 4) && (offset < 0x00102000 / 4)) { //logerror("NV_2A: write STRAPS[%06X] mask %08X value %08X\n",offset*4-0x00101000,mem_mask,data); } @@ -3898,16 +4033,47 @@ WRITE32_MEMBER(nv2a_renderer::geforce_w) //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))) + 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; //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))) 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 *)direct_access_ptr(data); - //printf("crtc buffer %08X\n\r", data); + displayedtarget = (UINT32 *)direct_access_ptr(pcrtc[e]); +#ifdef LOG_NV2A + printf("crtc buffer %08X\n\r", data); +#endif } //logerror("NV_2A: write PCRTC[%06X]=%08X\n",offset*4-0x00600000,data & mem_mask); } @@ -3922,9 +4088,6 @@ WRITE32_MEMBER(nv2a_renderer::geforce_w) // 32 channels size 0x10000 each, 8 subchannels per channel size 0x2000 each int chanel, subchannel, suboffset; //int method, count, handle, objclass; -#ifdef LOG_NV2A - int subch; -#endif suboffset = offset - 0x00800000 / 4; chanel = (suboffset >> (16 - 2)) & 31; @@ -3959,6 +4122,12 @@ WRITE32_MEMBER(nv2a_renderer::geforce_w) } //else // 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) + interruptdevice->ir3_w(1); // IRQ 3 + else + interruptdevice->ir3_w(0); // IRQ 3 + } } void nv2a_renderer::savestate_items() @@ -3971,3 +4140,8 @@ 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); } + +void nv2a_renderer::set_interrupt_device(pic8259_device *device) +{ + interruptdevice = device; +} |