diff --git a/scripts/src/video.lua b/scripts/src/video.lua index dbd271989ca..b61b5ffb0f7 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -805,18 +805,6 @@ if (VIDEOS["PCF2100"]~=null) then } end --------------------------------------------------- --- ---@src/devices/video/polylgcy.h,VIDEOS["POLY"] = true --------------------------------------------------- - -if (VIDEOS["POLY"]~=null) then - files { - MAME_DIR .. "src/devices/video/polylgcy.cpp", - MAME_DIR .. "src/devices/video/polylgcy.h", - } -end - -------------------------------------------------- -- --@src/devices/video/psx.h,VIDEOS["PSX"] = true @@ -1156,8 +1144,13 @@ if (VIDEOS["VOODOO"]~=null) then files { MAME_DIR .. "src/devices/video/voodoo.cpp", MAME_DIR .. "src/devices/video/voodoo.h", - MAME_DIR .. "src/devices/video/vooddefs.ipp", - MAME_DIR .. "src/devices/video/voodoo_rast.ipp", + MAME_DIR .. "src/devices/video/voodoo_2.cpp", + MAME_DIR .. "src/devices/video/voodoo_2.h", + MAME_DIR .. "src/devices/video/voodoo_banshee.cpp", + MAME_DIR .. "src/devices/video/voodoo_banshee.h", + MAME_DIR .. "src/devices/video/voodoo_regs.h", + MAME_DIR .. "src/devices/video/voodoo_render.cpp", + MAME_DIR .. "src/devices/video/voodoo_render.h", } end diff --git a/src/devices/machine/gt64xxx.cpp b/src/devices/machine/gt64xxx.cpp index 54ea16d5e3d..15e20e56ebf 100644 --- a/src/devices/machine/gt64xxx.cpp +++ b/src/devices/machine/gt64xxx.cpp @@ -873,7 +873,13 @@ TIMER_CALLBACK_MEMBER(gt64xxx_device::timer_callback) /* if we're a timer, adjust the timer to fire again */ if (m_reg[GREG_TIMER_CONTROL] & (2 << (2 * which))) - timer->timer->adjust(TIMER_PERIOD * timer->count, which); + { + // unsure what a 0-length timer should do, but it produces an infinite loop so guard against it + u32 effcount = timer->count; + if (effcount == 0) + effcount = (which != 0) ? 0xffffff : 0xffffffff; + timer->timer->adjust(TIMER_PERIOD * effcount, which); + } else timer->active = timer->count = 0; diff --git a/src/devices/machine/k033906.cpp b/src/devices/machine/k033906.cpp index d3debafd75d..5ffad3b74eb 100644 --- a/src/devices/machine/k033906.cpp +++ b/src/devices/machine/k033906.cpp @@ -98,7 +98,7 @@ void k033906_device::reg_w(int reg, uint32_t data) case 0x10: // initEnable { - m_voodoo->voodoo_set_init_enable(data); + m_voodoo->set_init_enable(data); break; } diff --git a/src/devices/machine/k033906.h b/src/devices/machine/k033906.h index 3184b210a90..21187ad0541 100644 --- a/src/devices/machine/k033906.h +++ b/src/devices/machine/k033906.h @@ -45,7 +45,7 @@ private: int m_reg_set; // 1 = access reg / 0 = access ram - required_device m_voodoo; + required_device m_voodoo; std::unique_ptr m_reg; std::unique_ptr m_ram; diff --git a/src/devices/machine/pci.h b/src/devices/machine/pci.h index 37ad677a476..0a0a570b451 100644 --- a/src/devices/machine/pci.h +++ b/src/devices/machine/pci.h @@ -121,6 +121,10 @@ protected: address_map_constructor delegate(map, name, static_cast(this)); add_map(size, flags, delegate); } + template void add_map(uint64_t size, int flags, T &device, void (T::*map)(address_map &map), const char *name) { + address_map_constructor delegate(map, name, &device); + add_map(size, flags, delegate, &device); + } void add_rom(const uint8_t *data, uint32_t size); void add_rom_from_region(); diff --git a/src/devices/video/poly.h b/src/devices/video/poly.h index 25b50675506..d61e1bd6137 100644 --- a/src/devices/video/poly.h +++ b/src/devices/video/poly.h @@ -37,34 +37,213 @@ #pragma once -#include "screen.h" - #include #include +#define KEEP_POLY_STATISTICS 0 +#define TRACK_POLY_WAITS 0 + + + //************************************************************************** -// DEBUGGING +// CONSTANTS //************************************************************************** -// keep statistics -#define KEEP_POLY_STATISTICS 0 - +static constexpr u8 POLY_FLAG_INCLUDE_BOTTOM_EDGE = 0x01; +static constexpr u8 POLY_FLAG_INCLUDE_RIGHT_EDGE = 0x02; +static constexpr u8 POLY_FLAG_NO_WORK_QUEUE = 0x04; +static constexpr u8 POLY_FLAG_NO_CLIPPING = 0x08; //************************************************************************** // TYPE DEFINITIONS //************************************************************************** +// class for managing an array of items +template +class poly_array +{ +public: + // this is really architecture-specific, but 64 is a reasonable + // value for most modern x64/ARM architectures + static constexpr size_t CACHE_LINE_SHIFT = 6; + static constexpr size_t CACHE_LINE_SIZE = 1 << CACHE_LINE_SHIFT; + static constexpr uintptr_t CACHE_LINE_MASK = ~uintptr_t(0) << CACHE_LINE_SHIFT; + + // size of an item, rounded up to the cache line size + static constexpr size_t ITEM_SIZE = ((sizeof(ArrayType) + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; + + // items are allocated in a 64k chunks + static constexpr size_t CHUNK_GRANULARITY = 65536; + + // number of items in a chunk + static constexpr u32 ITEMS_PER_CHUNK = CHUNK_GRANULARITY / ITEM_SIZE; + + // construction + poly_array() : + m_base(nullptr), + m_next(0), + m_max(0), + m_allocated(0) + { + for (int index = 0; index < TrackingCount; index++) + m_last[index] = nullptr; + + // allocate one chunk to start with + realloc(ITEMS_PER_CHUNK); + } + + // destruction + ~poly_array() { m_base = nullptr; } + + // getters + u32 count() const { return m_next; } + u32 max() const { return m_max; } + size_t itemsize() const { return ITEM_SIZE; } + u32 allocated() const { return m_allocated; } + + // return an item by index + ArrayType &byindex(u32 index) + { + if (index < m_allocated) + return *item_ptr(index); + assert(m_chain); + return m_chain->byindex(index - m_allocated); + } + + // return a contiguous chunk of items + ArrayType *contiguous(u32 index, u32 count, u32 &chunk) + { + if (index < m_allocated) + { + chunk = std::min(count, m_allocated - index); + return item_ptr(index); + } + assert(m_chain); + return m_chain->contiguous(index - m_allocated, count, chunk); + } + + // compute the index + int indexof(ArrayType &item) const + { + u32 result = (reinterpret_cast(&item) - m_base) / ITEM_SIZE; + if (result < m_allocated) + return result; + assert(m_chain); + return m_allocated + m_chain->indexof(item); + } + + // operations + void reset() + { + m_next = 0; + + // if we didn't have a chain, just repopulate + if (!m_chain) + repopulate(); + else + { + // otherwise, reallocate and get rid of the chain + realloc(m_max); + m_chain.reset(); + } + } + + // allocate a return a new item + ArrayType &next(int index = 0) + { + assert(index < TrackingCount); + + // track the maximum + if (m_next > m_max) + m_max = m_next; + + // fast case: fits within our array + ArrayType *item; + if (m_next < m_allocated) + item = new(item_ptr(m_next)) ArrayType; + + // otherwise, allocate from the chain + else + { + if (!m_chain) + m_chain = std::make_unique>(); + item = &m_chain->next(); + } + + // set the last item + m_next++; + if (TrackingCount > 0) + m_last[index] = item; + return *item; + } + + // return the last + ArrayType &last(int index = 0) const + { + assert(index < TrackingCount); + assert(m_last[index] != nullptr); + return *m_last[index]; + } + +private: + // internal helper to make size pointers + ArrayType *item_ptr(u32 index) + { + return reinterpret_cast(m_base + index * ITEM_SIZE); + } + + // reallocate to the given size + void realloc(u32 count) + { + // round the count up to a chunk size + count = ((count + ITEMS_PER_CHUNK - 1) / ITEMS_PER_CHUNK) * ITEMS_PER_CHUNK; + + // allocate a fresh new array + std::unique_ptr new_alloc = std::make_unique(ITEM_SIZE * count + CACHE_LINE_SIZE); + std::fill_n(&new_alloc[0], ITEM_SIZE * count + CACHE_LINE_SIZE, 0); + + // align the base to a cache line + m_base = reinterpret_cast((uintptr_t(new_alloc.get()) + CACHE_LINE_SIZE - 1) & CACHE_LINE_MASK); + + // repopulate last items into the base of the new array + repopulate(); + + // replace the old allocation with the new one + m_alloc = std::move(new_alloc); + m_allocated = count; + } + + // repopulate items + void repopulate() + { + for (int index = 0; index < TrackingCount; index++) + if (m_last[index] != nullptr) + { + if (m_last[index] == item_ptr(m_next)) + m_next++; + else + next(index) = *m_last[index]; + } + } + + // internal state + u8 *m_base; + u32 m_next; + u32 m_max; + u32 m_allocated; + std::unique_ptr m_alloc; + std::unique_ptr> m_chain; + std::array m_last; +}; + + // poly_manager is a template class -template +template class poly_manager { public: - static constexpr uint8_t FLAG_INCLUDE_BOTTOM_EDGE = 0x01; - static constexpr uint8_t FLAG_INCLUDE_RIGHT_EDGE = 0x02; - static constexpr uint8_t FLAG_NO_WORK_QUEUE = 0x04; - // each vertex has an X/Y coordinate and a set of parameters struct vertex_t { @@ -72,177 +251,112 @@ public: vertex_t(BaseType _x, BaseType _y) { x = _x; y = _y; } BaseType x, y; // X, Y coordinates - BaseType p[MaxParams]; // interpolated parameters + std::array p; // interpolated parameters }; // a single extent describes a span and a list of parameter extents struct extent_t { - int16_t startx, stopx; // starting (inclusive)/ending (exclusive) endpoints - struct + struct param_t { BaseType start; // parameter value at start BaseType dpdx; // dp/dx relative to start - } param[MaxParams]; + }; + int16_t startx, stopx; // starting (inclusive)/ending (exclusive) endpoints + std::array param; // array of parameter start/delays void *userdata; // custom per-span data }; // delegate type for scanline callbacks - typedef delegate render_delegate; + typedef delegate render_delegate; // construction/destruction - poly_manager(running_machine &machine, uint8_t flags = 0); - poly_manager(screen_device &screen, uint8_t flags = 0); + poly_manager(running_machine &machine); virtual ~poly_manager(); // getters - running_machine &machine() const { return m_machine; } - screen_device &screen() const { assert(m_screen != nullptr); return *m_screen; } uint32_t triangles_drawn() const { return m_triangles; } // synchronization void wait(const char *debug_reason = "general"); // object data allocators - ObjectData &object_data_alloc(); - ObjectData &object_data_last() const { return m_object.last(); } + ObjectType &object_data_alloc(); + ObjectType &object_data_last() const { return m_object.last(); } // tiles - uint32_t render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2); + template + uint32_t render_tile(rectangle const &cliprect, render_delegate callback, vertex_t const &v1, vertex_t const &v2); // triangles - uint32_t render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2, const vertex_t &v3); - uint32_t render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); - uint32_t render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); + template + uint32_t render_triangle(rectangle const &cliprect, render_delegate callback, vertex_t const &v1, vertex_t const &v2, vertex_t const &v3); + template + uint32_t render_triangle_fan(rectangle const &cliprect, render_delegate callback, int numverts, vertex_t const *v); + template + uint32_t render_triangle_strip(rectangle const &cliprect, render_delegate callback, int numverts, vertex_t const *v); uint32_t render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents); // polygons - template - uint32_t render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v); + template + uint32_t render_polygon(const rectangle &cliprect, render_delegate callback, const vertex_t *v); // public helpers - int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, BaseType clipval); + template + int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, BaseType clipval); + +protected: + // optional overrides + virtual void reset_after_wait() { } private: - poly_manager(running_machine &machine, screen_device *screen, uint8_t flags); - - // turn this on to log the reasons for any long waits - static constexpr bool POLY_LOG_WAITS = false; - // number of profiling ticks before we consider a wait "long" static constexpr osd_ticks_t POLY_LOG_WAIT_THRESHOLD = 1000; static constexpr int SCANLINES_PER_BUCKET = 32; - static constexpr int CACHE_LINE_SIZE = 64; // this is a general guess static constexpr int TOTAL_BUCKETS = (512 / SCANLINES_PER_BUCKET); - static constexpr int UNITS_PER_POLY = (100 / SCANLINES_PER_BUCKET); // polygon_info describes a single polygon, which includes the poly_params struct polygon_info { poly_manager * m_owner; // pointer back to the poly manager - ObjectData * m_object; // object data pointer + ObjectType * m_object; // object data pointer render_delegate m_callback; // callback to handle a scanline's worth of work }; // internal unit of work struct work_unit { + work_unit &operator=(work_unit const &rhs) + { + // this is just to satisfy the compiler; we don't actually copy + fatalerror("Attempt to copy work_unit"); + } + std::atomic count_next; // number of scanlines and index of next item to process - polygon_info * polygon; // pointer to polygon - int16_t scanline; // starting scanline - uint16_t previtem; // index of previous item in the same bucket - #ifndef PTR64 - uint32_t dummy; // pad to 16 bytes - #endif - extent_t extent[SCANLINES_PER_BUCKET]; // array of scanline extents - }; - - //------------------------------------------------- - // global helpers for float base types - //------------------------------------------------- - - static float poly_floor(float x) { return floorf(x); } - static float poly_abs(float x) { return fabsf(x); } - static float poly_recip(float x) { return 1.0f / x; } - - - //------------------------------------------------- - // global helpers for double base types - //------------------------------------------------- - - static double poly_floor(double x) { return floor(x); } - static double poly_abs(double x) { return fabs(x); } - static double poly_recip(double x) { return 1.0 / x; } - - - // class for managing an array of items - template - class poly_array - { - // size of an item, rounded up to the cache line size - static const int k_itemsize = ((sizeof(_Type) + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; - - public: - // construction - poly_array(running_machine &machine, poly_manager &manager) - : m_manager(manager), - m_base(make_unique_clear(k_itemsize * _Count)), - m_next(0), - m_max(0), - m_waits(0) { } - - // destruction - ~poly_array() { m_base = nullptr; } - - // operators - _Type &operator[](int index) const { assert(index >= 0 && index < _Count); return *reinterpret_cast<_Type *>(m_base.get() + index * k_itemsize); } - - // getters - int count() const { return m_next; } - int max() const { return m_max; } - int waits() const { return m_waits; } - int itemsize() const { return k_itemsize; } - int allocated() const { return _Count; } - int indexof(_Type &item) const { int result = (reinterpret_cast(&item) - m_base.get()) / k_itemsize; assert(result >= 0 && result < _Count); return result; } - - // operations - void reset() { m_next = 0; } - _Type &next() { if (m_next > m_max) m_max = m_next; assert(m_next < _Count); return *new(m_base.get() + m_next++ * k_itemsize) _Type; } - _Type &last() const { return (*this)[m_next - 1]; } - void wait_for_space(int count = 1) { while ((m_next + count) >= _Count) { m_waits++; m_manager.wait(""); } } - - private: - // internal state - poly_manager & m_manager; - std::unique_ptr m_base; - int m_next; - int m_max; - int m_waits; + polygon_info * polygon; // pointer to polygon + int32_t scanline; // starting scanline + uint32_t previtem; // index of previous item in the same bucket + extent_t extent[SCANLINES_PER_BUCKET]; // array of scanline extents }; // internal array types - typedef poly_array polygon_array; - typedef poly_array objectdata_array; - typedef poly_array unit_array; + using polygon_array = poly_array; + using objectdata_array = poly_array; + using unit_array = poly_array; // round in a cross-platform consistent manner inline int32_t round_coordinate(BaseType value) { - int32_t result = poly_floor(value); - - if ((value > 0) && (result < 0)) - return INT_MAX-1; + int32_t result = int32_t(std::floor(value)); + if (value > 0 && result < 0) + return INT_MAX - 1; return result + (value - BaseType(result) > BaseType(0.5)); } // internal helpers polygon_info &polygon_alloc(int minx, int maxx, int miny, int maxy, render_delegate callback) { - // wait for space in the polygon and unit arrays - m_polygon.wait_for_space(); - m_unit.wait_for_space((maxy - miny) / SCANLINES_PER_BUCKET + 2); - // return and initialize the next one polygon_info &polygon = m_polygon.next(); polygon.m_owner = this; @@ -251,33 +365,75 @@ private: return polygon; } + // enqueue work items in contiguous chunks + void queue_items(u32 start) + { + // do nothing if no queue; items will be processed on the next wait + if (m_queue == nullptr) + return; + + // enqueue the items in contiguous chunks + while (start < m_unit.count()) + { + u32 chunk; + work_unit *base = m_unit.contiguous(start, m_unit.count() - start, chunk); + osd_work_item_queue_multiple(m_queue, work_item_callback, chunk, base, m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + start += chunk; + } + } + static void *work_item_callback(void *param, int threadid); void presave() { wait("pre-save"); } // queue management - running_machine & m_machine; - screen_device * m_screen; - osd_work_queue * m_queue; // work queue + osd_work_queue *m_queue; // work queue // arrays - polygon_array m_polygon; // array of polygons - objectdata_array m_object; // array of object data - unit_array m_unit; // array of work units - - // misc data - uint8_t const m_flags; // flags + polygon_array m_polygon; // array of polygons + objectdata_array m_object; // array of object data + unit_array m_unit; // array of work units // buckets - uint16_t m_unit_bucket[TOTAL_BUCKETS]; // buckets for tracking unit usage + uint32_t m_unit_bucket[TOTAL_BUCKETS]; // buckets for tracking unit usage // statistics - uint32_t m_tiles; // number of tiles queued - uint32_t m_triangles; // number of triangles queued - uint32_t m_quads; // number of quads queued - uint64_t m_pixels; // number of pixels rendered + uint32_t m_tiles; // number of tiles queued + uint32_t m_triangles; // number of triangles queued + uint32_t m_quads; // number of quads queued + uint64_t m_pixels; // number of pixels rendered #if KEEP_POLY_STATISTICS - uint32_t m_conflicts[WORK_MAX_THREADS]; // number of conflicts found, per thread - uint32_t m_resolved[WORK_MAX_THREADS]; // number of conflicts resolved, per thread + uint32_t m_conflicts[WORK_MAX_THREADS] = { 0 }; // number of conflicts found, per thread + uint32_t m_resolved[WORK_MAX_THREADS] = { 0 }; // number of conflicts resolved, per thread +#endif +#if TRACK_POLY_WAITS + static std::string friendly_number(u64 number); + struct wait_tracker + { + void update(int items, osd_ticks_t time) + { + total_waits++; + if (items > 0) + { + total_actual_waits++; + total_cycles += time; + if (time < 100) + bucket_waits[0]++; + else if (time < 1000) + bucket_waits[1]++; + else if (time < 10000) + bucket_waits[2]++; + else + bucket_waits[3]++; + } + } + + u32 total_waits = 0; + u32 total_actual_waits = 0; + u32 bucket_waits[4] = { 0 }; + u64 total_cycles = 0; + }; + using waitmap_t = std::unordered_map; + waitmap_t m_waitmap; #endif }; @@ -286,44 +442,19 @@ private: // poly_manager - constructor //------------------------------------------------- -template -poly_manager::poly_manager(running_machine &machine, uint8_t flags) - : poly_manager(machine, nullptr, flags) +template +poly_manager::poly_manager(running_machine &machine) : + m_queue(nullptr), + m_tiles(0), + m_triangles(0), + m_quads(0), + m_pixels(0) { -} - - -template -poly_manager::poly_manager(screen_device &screen, uint8_t flags) - : poly_manager(screen.machine(), &screen, flags) -{ -} - - -template -poly_manager::poly_manager(running_machine &machine, screen_device *screen, uint8_t flags) - : m_machine(machine) - , m_screen(screen) - , m_queue(nullptr) - , m_polygon(machine, *this) - , m_object(machine, *this) - , m_unit(machine, *this) - , m_flags(flags) - , m_tiles(0) - , m_triangles(0) - , m_quads(0) - , m_pixels(0) -{ -#if KEEP_POLY_STATISTICS - memset(m_conflicts, 0, sizeof(m_conflicts)); - memset(m_resolved, 0, sizeof(m_resolved)); -#endif - // create the work queue - if (!(flags & FLAG_NO_WORK_QUEUE)) + if (!(Flags & POLY_FLAG_NO_WORK_QUEUE)) m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); - memset(m_unit_bucket, 0xff, sizeof(m_unit_bucket)); + std::fill_n(&m_unit_bucket[0], std::size(m_unit_bucket), 0xffffffff); // request a pre-save callback for synchronization machine.save().register_presave(save_prepost_delegate(FUNC(poly_manager::presave), this)); @@ -334,8 +465,31 @@ poly_manager::poly_manager(running_ma // ~poly_manager - destructor //------------------------------------------------- -template -poly_manager::~poly_manager() +#if TRACK_POLY_WAITS +template +inline std::string poly_manager::friendly_number(u64 number) +{ + static char const s_suffixes[] = " kmbtqisp"; + double value = double(number); + int suffixnum = 0; + + if (number < 1000000) + return string_format("%6d ", int(number)); + while (value >= 1000) + { + value /= 1000.0; + suffixnum++; + } + if (value >= 100) + return string_format("%6.1f%c", value, s_suffixes[suffixnum]); + if (value >= 10) + return string_format("%6.2f%c", value, s_suffixes[suffixnum]); + return string_format("%6.3f%c", value, s_suffixes[suffixnum]); +} +#endif + +template +poly_manager::~poly_manager() { #if KEEP_POLY_STATISTICS { @@ -348,17 +502,48 @@ poly_manager::~poly_manager() } // output global stats - printf("Total triangles = %d\n", m_triangles); - printf("Total quads = %d\n", m_quads); + osd_printf_info("Total triangles = %d\n", m_triangles); + osd_printf_info("Total quads = %d\n", m_quads); if (m_pixels > 1000000000) - printf("Total pixels = %d%09d\n", (uint32_t)(m_pixels / 1000000000), (uint32_t)(m_pixels % 1000000000)); + osd_printf_info("Total pixels = %d%09d\n", uint32_t(m_pixels / 1000000000), uint32_t(m_pixels % 1000000000)); else - printf("Total pixels = %d\n", (uint32_t)m_pixels); + osd_printf_info("Total pixels = %d\n", uint32_t(m_pixels)); - printf("Conflicts: %d resolved, %d total\n", resolved, conflicts); - printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), m_unit.waits(), m_unit.itemsize(), m_unit.allocated() * m_unit.itemsize()); - printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_polygon.max(), m_polygon.allocated(), m_polygon.waits(), m_polygon.itemsize(), m_polygon.allocated() * m_polygon.itemsize()); - printf("Object data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), m_object.waits(), m_object.itemsize(), m_object.allocated() * m_object.itemsize()); + osd_printf_info("Conflicts: %d resolved, %d total\n", resolved, conflicts); + osd_printf_info("Units: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), int(m_unit.itemsize()), int(m_unit.allocated() * m_unit.itemsize())); + osd_printf_info("Polygons: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_polygon.max(), m_polygon.allocated(), int(m_polygon.itemsize()), int(m_polygon.allocated() * m_polygon.itemsize())); + osd_printf_info("Object data: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), int(m_object.itemsize()), int(m_object.allocated() * m_object.itemsize())); +} +#endif +#if TRACK_POLY_WAITS +{ + osd_printf_info("Wait summary:\n"); + osd_printf_info("Cause Cycles Waits Actuals Average <100 100-1k 1k-10k 10k+\n"); + osd_printf_info("------------------ ------- ------- ------- ------- ------- ------- ------- -------\n"); + while (1) + { + typename waitmap_t::value_type *biggest = nullptr; + for (auto &item : m_waitmap) + if (item.second.total_cycles > 0) + if (biggest == nullptr || item.second.total_cycles > biggest->second.total_cycles) + biggest = &item; + + if (biggest == nullptr) + break; + + osd_printf_info("%-20s%-7s %-7s %-7s %-7s %-7s %-7s %-7s %-7s\n", + biggest->first.c_str(), + friendly_number(biggest->second.total_cycles).c_str(), + friendly_number(biggest->second.total_waits).c_str(), + friendly_number(biggest->second.total_actual_waits).c_str(), + (biggest->second.total_actual_waits == 0) ? "n/a" : friendly_number(biggest->second.total_cycles / biggest->second.total_actual_waits).c_str(), + friendly_number(biggest->second.bucket_waits[0]).c_str(), + friendly_number(biggest->second.bucket_waits[1]).c_str(), + friendly_number(biggest->second.bucket_waits[2]).c_str(), + friendly_number(biggest->second.bucket_waits[3]).c_str()); + + biggest->second.total_cycles = 0; + } } #endif @@ -372,20 +557,20 @@ poly_manager::~poly_manager() // work_item_callback - process a work item //------------------------------------------------- -template -void *poly_manager::work_item_callback(void *param, int threadid) +template +void *poly_manager::work_item_callback(void *param, int threadid) { while (1) { work_unit &unit = *(work_unit *)param; polygon_info &polygon = *unit.polygon; - int count = unit.count_next & 0xffff; + int count = unit.count_next & 0xff; uint32_t orig_count_next; // if our previous item isn't done yet, enqueue this item to the end and proceed - if (unit.previtem != 0xffff) + if (unit.previtem != 0xffffffff) { - work_unit &prevunit = polygon.m_owner->m_unit[unit.previtem]; + work_unit &prevunit = polygon.m_owner->m_unit.byindex(unit.previtem); if (prevunit.count_next != 0) { uint32_t unitnum = polygon.m_owner->m_unit.indexof(unit); @@ -395,7 +580,7 @@ void *poly_manager::work_item_callbac do { orig_count_next = prevunit.count_next; - new_count_next = orig_count_next | (unitnum << 16); + new_count_next = orig_count_next | (unitnum << 8); } while (!prevunit.count_next.compare_exchange_weak(orig_count_next, new_count_next, std::memory_order_release, std::memory_order_relaxed)); #if KEEP_POLY_STATISTICS @@ -421,10 +606,10 @@ void *poly_manager::work_item_callbac } while (!unit.count_next.compare_exchange_weak(orig_count_next, 0, std::memory_order_release, std::memory_order_relaxed)); // if we have no more work to do, do nothing - orig_count_next >>= 16; + orig_count_next >>= 8; if (orig_count_next == 0) break; - param = &polygon.m_owner->m_unit[orig_count_next]; + param = &polygon.m_owner->m_unit.byindex(orig_count_next); } return nullptr; } @@ -434,14 +619,13 @@ void *poly_manager::work_item_callbac // wait - stall until all work is complete //------------------------------------------------- -template -void poly_manager::wait(const char *debug_reason) +template +void poly_manager::wait(const char *debug_reason) { - osd_ticks_t time; - - // remember the start time if we're logging - if (POLY_LOG_WAITS) - time = get_profile_ticks(); +#if TRACK_POLY_WAITS + int items = osd_work_queue_items(m_queue); + osd_ticks_t time = get_profile_ticks(); +#endif // wait for all pending work items to complete if (m_queue != nullptr) @@ -450,42 +634,32 @@ void poly_manager::wait(const char *d // if we don't have a queue, just run the whole list now else for (int unitnum = 0; unitnum < m_unit.count(); unitnum++) - work_item_callback(&m_unit[unitnum], 0); + work_item_callback(&m_unit.byindex(unitnum), 0); - // log any long waits - if (POLY_LOG_WAITS) - { - time = get_profile_ticks() - time; - if (time > POLY_LOG_WAIT_THRESHOLD) - machine().logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason); - } +#if TRACK_POLY_WAITS + m_waitmap[debug_reason].update(items, get_profile_ticks() - time); +#endif - // reset the state + // reset all the poly arrays m_polygon.reset(); m_unit.reset(); - memset(m_unit_bucket, 0xff, sizeof(m_unit_bucket)); + m_object.reset(); - // we need to preserve the last object data that was supplied - if (m_object.count() > 0) - { - ObjectData temp = object_data_last(); - m_object.reset(); - m_object.next() = temp; - } - else - m_object.reset(); + // clear the buckets + std::fill_n(&m_unit_bucket[0], std::size(m_unit_bucket), 0xffffffff); + + // allow derived classes to do additional cleanup + reset_after_wait(); } //------------------------------------------------- -// object_data_alloc - allocate a new ObjectData +// object_data_alloc - allocate a new ObjectType //------------------------------------------------- -template -ObjectData &poly_manager::object_data_alloc() +template +ObjectType &poly_manager::object_data_alloc() { - // wait for a work item if we have to, then return the next item - m_object.wait_for_space(); return m_object.next(); } @@ -494,19 +668,16 @@ ObjectData &poly_manager::object_data // render_tile - render a tile //------------------------------------------------- -template -uint32_t poly_manager::render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2) +template +template +uint32_t poly_manager::render_tile(rectangle const &cliprect, render_delegate callback, vertex_t const &_v1, vertex_t const &_v2) { const vertex_t *v1 = &_v1; const vertex_t *v2 = &_v2; // first sort by Y if (v2->y < v1->y) - { - const vertex_t *tv = v1; - v1 = v2; - v2 = tv; - } + std::swap(v1, v2); // compute some integral X/Y vertex values int32_t v1y = round_coordinate(v1->y); @@ -514,11 +685,14 @@ uint32_t poly_manager::render_tile(co // clip coordinates int32_t v1yclip = v1y; - int32_t v2yclip = v2y + ((m_flags & FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - v1yclip = std::max(v1yclip, cliprect.top()); - v2yclip = std::min(v2yclip, cliprect.bottom() + 1); - if (v2yclip - v1yclip <= 0) - return 0; + int32_t v2yclip = v2y + ((Flags & POLY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + v1yclip = std::max(v1yclip, cliprect.top()); + v2yclip = std::min(v2yclip, cliprect.bottom() + 1); + if (v2yclip - v1yclip <= 0) + return 0; + } // determine total X extents BaseType minx = v1->x; @@ -530,16 +704,16 @@ uint32_t poly_manager::render_tile(co polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v2yclip, callback); // compute parameter deltas - BaseType param_dpdx[MaxParams]; - BaseType param_dpdy[MaxParams]; - if (paramcount > 0) + std::array param_dpdx; + std::array param_dpdy; + if (ParamCount > 0) { - BaseType oox = poly_recip(v2->x - v1->x); - BaseType ooy = poly_recip(v2->y - v1->y); - for (int paramnum = 0; paramnum < paramcount; paramnum++) + BaseType oox = BaseType(1.0) / (v2->x - v1->x); + BaseType ooy = BaseType(1.0) / (v2->y - v1->y); + for (int paramnum = 0; paramnum < ParamCount; paramnum++) { - param_dpdx[paramnum] = oox * (v2->p[paramnum] - v1->p[paramnum]); - param_dpdy[paramnum] = ooy * (v2->p[paramnum] - v1->p[paramnum]); + param_dpdx[paramnum] = oox * (v2->p[paramnum] - v1->p[paramnum]); + param_dpdy[paramnum] = ooy * (v2->p[paramnum] - v1->p[paramnum]); } } @@ -549,23 +723,20 @@ uint32_t poly_manager::render_tile(co // force start < stop if (istartx > istopx) - { - int32_t temp = istartx; - istartx = istopx; - istopx = temp; - } + std::swap(istartx, istopx); // include the right edge if requested - if (m_flags & FLAG_INCLUDE_RIGHT_EDGE) + if (Flags & POLY_FLAG_INCLUDE_RIGHT_EDGE) istopx++; // apply left/right clipping - if (istartx < cliprect.left()) - istartx = cliprect.left(); - if (istopx > cliprect.right()) - istopx = cliprect.right() + 1; - if (istartx >= istopx) - return 0; + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + istartx = std::max(istartx, cliprect.left()); + istopx = std::min(istopx, cliprect.right() + 1); + if (istartx >= istopx) + return 0; + } // compute the X extents for each scanline int32_t pixels = 0; @@ -573,12 +744,12 @@ uint32_t poly_manager::render_tile(co int32_t scaninc = 1; for (int32_t curscan = v1yclip; curscan < v2yclip; curscan += scaninc) { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + uint32_t bucketnum = (uint32_t(curscan) / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; uint32_t unit_index = m_unit.count(); work_unit &unit = m_unit.next(); // determine how much to advance to hit the next bucket - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; + scaninc = SCANLINES_PER_BUCKET - uint32_t(curscan) % SCANLINES_PER_BUCKET; // fill in the work unit basics unit.polygon = &polygon; @@ -590,29 +761,28 @@ uint32_t poly_manager::render_tile(co // iterate over extents for (int extnum = 0; extnum < unit.count_next; extnum++) { - // compute the ending X based on which part of the triangle we're in - BaseType fully = BaseType(curscan + extnum) + BaseType(0.5); - // set the extent and update the total pixel count extent_t &extent = unit.extent[extnum]; extent.startx = istartx; extent.stopx = istopx; - extent.userdata = nullptr; pixels += istopx - istartx; // fill in the parameters for the extent - BaseType fullstartx = BaseType(istartx) + BaseType(0.5); - for (int paramnum = 0; paramnum < paramcount; paramnum++) + if (ParamCount > 0) { - extent.param[paramnum].start = v1->p[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; - extent.param[paramnum].dpdx = param_dpdx[paramnum]; + BaseType fullstartx = BaseType(istartx) + BaseType(0.5); + BaseType fully = BaseType(curscan + extnum) + BaseType(0.5); + for (int paramnum = 0; paramnum < ParamCount; paramnum++) + { + extent.param[paramnum].start = v1->p[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; + extent.param[paramnum].dpdx = param_dpdx[paramnum]; + } } } } // enqueue the work items - if (m_queue != nullptr) - osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + queue_items(startunit); // return the total number of pixels in the triangle m_tiles++; @@ -626,8 +796,9 @@ uint32_t poly_manager::render_tile(co // given 3 vertexes //------------------------------------------------- -template -uint32_t poly_manager::render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2, const vertex_t &_v3) +template +template +uint32_t poly_manager::render_triangle(const rectangle &cliprect, render_delegate callback, const vertex_t &_v1, const vertex_t &_v2, const vertex_t &_v3) { const vertex_t *v1 = &_v1; const vertex_t *v2 = &_v2; @@ -635,22 +806,12 @@ uint32_t poly_manager::render_triangl // first sort by Y if (v2->y < v1->y) - { - const vertex_t *tv = v1; - v1 = v2; - v2 = tv; - } + std::swap(v1, v2); if (v3->y < v2->y) { - const vertex_t *tv = v2; - v2 = v3; - v3 = tv; + std::swap(v2, v3); if (v2->y < v1->y) - { - const vertex_t *tv2 = v1; - v1 = v2; - v2 = tv2; - } + std::swap(v1, v2); } // compute some integral X/Y vertex values @@ -659,19 +820,18 @@ uint32_t poly_manager::render_triangl // clip coordinates int32_t v1yclip = v1y; - int32_t v3yclip = v3y + ((m_flags & FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - v1yclip = std::max(v1yclip, cliprect.top()); - v3yclip = std::min(v3yclip, cliprect.bottom() + 1); - if (v3yclip - v1yclip <= 0) - return 0; + int32_t v3yclip = v3y + ((Flags & POLY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + v1yclip = std::max(v1yclip, cliprect.top()); + v3yclip = std::min(v3yclip, cliprect.bottom() + 1); + if (v3yclip - v1yclip <= 0) + return 0; + } // determine total X extents - BaseType minx = v1->x; - BaseType maxx = v1->x; - if (v2->x < minx) minx = v2->x; - else if (v2->x > maxx) maxx = v2->x; - if (v3->x < minx) minx = v3->x; - else if (v3->x > maxx) maxx = v3->x; + BaseType minx = std::min(std::min(v1->x, v2->x), v3->x); + BaseType maxx = std::max(std::max(v1->x, v2->x), v3->x); // allocate and populate a new polygon polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v3yclip, callback); @@ -682,10 +842,10 @@ uint32_t poly_manager::render_triangl BaseType dxdy_v2v3 = (v3->y == v2->y) ? BaseType(0.0) : (v3->x - v2->x) / (v3->y - v2->y); // compute parameter starting points and deltas - BaseType param_start[MaxParams]; - BaseType param_dpdx[MaxParams]; - BaseType param_dpdy[MaxParams]; - if (paramcount > 0) + std::array param_start; + std::array param_dpdx; + std::array param_dpdy; + if (ParamCount > 0) { BaseType a00 = v2->y - v3->y; BaseType a01 = v3->x - v2->x; @@ -698,9 +858,9 @@ uint32_t poly_manager::render_triangl BaseType a22 = v1->x*v2->y - v2->x*v1->y; BaseType det = a02 + a12 + a22; - if (poly_abs(det) < BaseType(0.00001)) + if (std::abs(det) < BaseType(0.00001)) { - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) { param_dpdx[paramnum] = BaseType(0.0); param_dpdy[paramnum] = BaseType(0.0); @@ -709,8 +869,8 @@ uint32_t poly_manager::render_triangl } else { - BaseType idet = poly_recip(det); - for (int paramnum = 0; paramnum < paramcount; paramnum++) + BaseType idet = BaseType(1.0) / det; + for (int paramnum = 0; paramnum < ParamCount; paramnum++) { param_dpdx[paramnum] = idet * (v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); param_dpdy[paramnum] = idet * (v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); @@ -718,12 +878,6 @@ uint32_t poly_manager::render_triangl } } } - else // GCC 4.7.0 incorrectly claims these are uninitialized; humor it by initializing in the (hopefully rare) zero parameter case - { - param_start[0] = BaseType(0.0); - param_dpdx[0] = BaseType(0.0); - param_dpdy[0] = BaseType(0.0); - } // compute the X extents for each scanline int32_t pixels = 0; @@ -731,12 +885,12 @@ uint32_t poly_manager::render_triangl int32_t scaninc = 1; for (int32_t curscan = v1yclip; curscan < v3yclip; curscan += scaninc) { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + uint32_t bucketnum = (uint32_t(curscan) / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; uint32_t unit_index = m_unit.count(); work_unit &unit = m_unit.next(); // determine how much to advance to hit the next bucket - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; + scaninc = SCANLINES_PER_BUCKET - uint32_t(curscan) % SCANLINES_PER_BUCKET; // fill in the work unit basics unit.polygon = &polygon; @@ -763,21 +917,18 @@ uint32_t poly_manager::render_triangl // force start < stop if (istartx > istopx) - { - int32_t temp = istartx; - istartx = istopx; - istopx = temp; - } + std::swap(istartx, istopx); // include the right edge if requested - if (m_flags & FLAG_INCLUDE_RIGHT_EDGE) + if (Flags & POLY_FLAG_INCLUDE_RIGHT_EDGE) istopx++; // apply left/right clipping - if (istartx < cliprect.left()) - istartx = cliprect.left(); - if (istopx > cliprect.right()) - istopx = cliprect.right() + 1; + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + istartx = std::max(istartx, cliprect.left()); + istopx = std::min(istopx, cliprect.right() + 1); + } // set the extent and update the total pixel count if (istartx >= istopx) @@ -785,12 +936,11 @@ uint32_t poly_manager::render_triangl extent_t &extent = unit.extent[extnum]; extent.startx = istartx; extent.stopx = istopx; - extent.userdata = nullptr; pixels += istopx - istartx; // fill in the parameters for the extent BaseType fullstartx = BaseType(istartx) + BaseType(0.5); - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) { extent.param[paramnum].start = param_start[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; extent.param[paramnum].dpdx = param_dpdx[paramnum]; @@ -799,8 +949,7 @@ uint32_t poly_manager::render_triangl } // enqueue the work items - if (m_queue != nullptr) - osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + queue_items(startunit); // return the total number of pixels in the triangle m_triangles++; @@ -814,13 +963,14 @@ uint32_t poly_manager::render_triangl // triangles in a fan //------------------------------------------------- -template -uint32_t poly_manager::render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +template +template +uint32_t poly_manager::render_triangle_fan(const rectangle &cliprect, render_delegate callback, int numverts, const vertex_t *v) { // iterate over vertices uint32_t pixels = 0; for (int vertnum = 2; vertnum < numverts; vertnum++) - pixels += render_triangle(cliprect, callback, paramcount, v[0], v[vertnum - 1], v[vertnum]); + pixels += render_triangle(cliprect, callback, v[0], v[vertnum - 1], v[vertnum]); return pixels; } @@ -830,13 +980,14 @@ uint32_t poly_manager::render_triangl // triangles in a strip //------------------------------------------------- -template -uint32_t poly_manager::render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +template +template +uint32_t poly_manager::render_triangle_strip(const rectangle &cliprect, render_delegate callback, int numverts, const vertex_t *v) { // iterate over vertices uint32_t pixels = 0; for (int vertnum = 2; vertnum < numverts; vertnum++) - pixels += render_triangle(cliprect, callback, paramcount, v[vertnum - 2], v[vertnum - 1], v[vertnum]); + pixels += render_triangle(cliprect, callback, v[vertnum - 2], v[vertnum - 1], v[vertnum]); return pixels; } @@ -846,14 +997,19 @@ uint32_t poly_manager::render_triangl // render of an object, given specific extents //------------------------------------------------- -template -uint32_t poly_manager::render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents) +template +uint32_t poly_manager::render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents) { // clip coordinates - int32_t v1yclip = std::max(startscanline, cliprect.top()); - int32_t v3yclip = std::min(startscanline + numscanlines, cliprect.bottom() + 1); - if (v3yclip - v1yclip <= 0) - return 0; + int32_t v1yclip = startscanline; + int32_t v3yclip = startscanline + numscanlines; + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + v1yclip = std::max(v1yclip, cliprect.top()); + v3yclip = std::min(v3yclip, cliprect.bottom() + 1); + if (v3yclip - v1yclip <= 0) + return 0; + } // allocate and populate a new polygon polygon_info &polygon = polygon_alloc(0, 0, v1yclip, v3yclip, callback); @@ -864,12 +1020,12 @@ uint32_t poly_manager::render_triangl int32_t scaninc = 1; for (int32_t curscan = v1yclip; curscan < v3yclip; curscan += scaninc) { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + uint32_t bucketnum = (uint32_t(curscan) / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; uint32_t unit_index = m_unit.count(); work_unit &unit = m_unit.next(); // determine how much to advance to hit the next bucket - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; + scaninc = SCANLINES_PER_BUCKET - uint32_t(curscan) % SCANLINES_PER_BUCKET; // fill in the work unit basics unit.polygon = &polygon; @@ -885,14 +1041,13 @@ uint32_t poly_manager::render_triangl int32_t istartx = srcextent.startx, istopx = srcextent.stopx; // apply left/right clipping - if (istartx < cliprect.left()) - istartx = cliprect.left(); - if (istartx > cliprect.right()) - istartx = cliprect.right() + 1; - if (istopx < cliprect.left()) - istopx = cliprect.left(); - if (istopx > cliprect.right()) - istopx = cliprect.right() + 1; + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + istartx = std::max(istartx, cliprect.left()); + istartx = std::min(istartx, cliprect.right() + 1); + istopx = std::max(istopx, cliprect.left()); + istopx = std::min(istopx, cliprect.right() + 1); + } // set the extent and update the total pixel count extent_t &extent = unit.extent[extnum]; @@ -905,18 +1060,17 @@ uint32_t poly_manager::render_triangl extent.param[paramnum].start = srcextent.param[paramnum].start; extent.param[paramnum].dpdx = srcextent.param[paramnum].dpdx; } - extent.userdata = srcextent.userdata; + if (istartx < istopx) pixels += istopx - istartx; - else if(istopx < istartx) + else if (istopx < istartx) pixels += istartx - istopx; } } // enqueue the work items - if (m_queue != nullptr) - osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + queue_items(startunit); // return the total number of pixels in the object m_triangles++; @@ -930,25 +1084,23 @@ uint32_t poly_manager::render_triangl // to 32 vertices //------------------------------------------------- -template -template -uint32_t poly_manager::render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v) +template +template +uint32_t poly_manager::render_polygon(const rectangle &cliprect, render_delegate callback, const vertex_t *v) { // determine min/max Y vertices BaseType minx = v[0].x; BaseType maxx = v[0].x; int minv = 0; int maxv = 0; - for (int vertnum = 1; vertnum < _NumVerts; vertnum++) + for (int vertnum = 1; vertnum < NumVerts; vertnum++) { if (v[vertnum].y < v[minv].y) minv = vertnum; else if (v[vertnum].y > v[maxv].y) maxv = vertnum; - if (v[vertnum].x < minx) - minx = v[vertnum].x; - else if (v[vertnum].x > maxx) - maxx = v[vertnum].x; + minx = std::min(minx, v[vertnum].x); + maxx = std::max(maxx, v[vertnum].x); } // determine start/end scanlines @@ -957,11 +1109,14 @@ uint32_t poly_manager::render_polygon // clip coordinates int32_t minyclip = miny; - int32_t maxyclip = maxy + ((m_flags & FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - minyclip = std::max(minyclip, cliprect.top()); - maxyclip = std::min(maxyclip, cliprect.bottom() + 1); - if (maxyclip - minyclip <= 0) - return 0; + int32_t maxyclip = maxy + ((Flags & POLY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + if (!(Flags & POLY_FLAG_NO_CLIPPING)) + { + minyclip = std::max(minyclip, cliprect.top()); + maxyclip = std::min(maxyclip, cliprect.bottom() + 1); + if (maxyclip - minyclip <= 0) + return 0; + } // allocate a new polygon polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), minyclip, maxyclip, callback); @@ -969,50 +1124,50 @@ uint32_t poly_manager::render_polygon // walk forward to build up the forward edge list struct poly_edge { - poly_edge * next; // next edge in sequence - int index; // index of this edge - const vertex_t * v1; // pointer to first vertex - const vertex_t * v2; // pointer to second vertex - BaseType dxdy; // dx/dy along the edge - BaseType dpdy[MaxParams]; // per-parameter dp/dy values + poly_edge *next; // next edge in sequence + int index; // index of this edge + const vertex_t *v1; // pointer to first vertex + const vertex_t *v2; // pointer to second vertex + BaseType dxdy; // dx/dy along the edge + std::array dpdy; // per-parameter dp/dy values }; - poly_edge fedgelist[_NumVerts - 1]; + poly_edge fedgelist[NumVerts - 1]; poly_edge *edgeptr = &fedgelist[0]; - for (int curv = minv; curv != maxv; curv = (curv == _NumVerts - 1) ? 0 : (curv + 1)) + for (int curv = minv; curv != maxv; curv = (curv == NumVerts - 1) ? 0 : (curv + 1)) { // set the two vertices edgeptr->v1 = &v[curv]; - edgeptr->v2 = &v[(curv == _NumVerts - 1) ? 0 : (curv + 1)]; + edgeptr->v2 = &v[(curv == NumVerts - 1) ? 0 : (curv + 1)]; // if horizontal, skip altogether if (edgeptr->v1->y == edgeptr->v2->y) continue; // need dx/dy always, and parameter deltas as necessary - BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + BaseType ooy = BaseType(1.0) / (edgeptr->v2->y - edgeptr->v1->y); edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; ++edgeptr; } // walk backward to build up the backward edge list - poly_edge bedgelist[_NumVerts - 1]; + poly_edge bedgelist[NumVerts - 1]; edgeptr = &bedgelist[0]; - for (int curv = minv; curv != maxv; curv = (curv == 0) ? (_NumVerts - 1) : (curv - 1)) + for (int curv = minv; curv != maxv; curv = (curv == 0) ? (NumVerts - 1) : (curv - 1)) { // set the two vertices edgeptr->v1 = &v[curv]; - edgeptr->v2 = &v[(curv == 0) ? (_NumVerts - 1) : (curv - 1)]; + edgeptr->v2 = &v[(curv == 0) ? (NumVerts - 1) : (curv - 1)]; // if horizontal, skip altogether if (edgeptr->v1->y == edgeptr->v2->y) continue; // need dx/dy always, and parameter deltas as necessary - BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + BaseType ooy = BaseType(1.0) / (edgeptr->v2->y - edgeptr->v1->y); edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; ++edgeptr; } @@ -1039,12 +1194,12 @@ uint32_t poly_manager::render_polygon int32_t scaninc = 1; for (int32_t curscan = minyclip; curscan < maxyclip; curscan += scaninc) { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + uint32_t bucketnum = (uint32_t(curscan) / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; uint32_t unit_index = m_unit.count(); work_unit &unit = m_unit.next(); // determine how much to advance to hit the next bucket - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; + scaninc = SCANLINES_PER_BUCKET - uint32_t(curscan) % SCANLINES_PER_BUCKET; // fill in the work unit basics unit.polygon = &polygon; @@ -1071,14 +1226,14 @@ uint32_t poly_manager::render_polygon // compute parameter starting points and deltas extent_t &extent = unit.extent[extnum]; - if (paramcount > 0) + if (ParamCount > 0) { BaseType ldy = fully - ledge->v1->y; BaseType rdy = fully - redge->v1->y; - BaseType oox = poly_recip(stopx - startx); + BaseType oox = BaseType(1.0) / (stopx - startx); // iterate over parameters - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) { BaseType lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; BaseType rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; @@ -1090,32 +1245,33 @@ uint32_t poly_manager::render_polygon } // include the right edge if requested - if (m_flags & FLAG_INCLUDE_RIGHT_EDGE) + if (Flags & POLY_FLAG_INCLUDE_RIGHT_EDGE) istopx++; // apply left/right clipping - if (istartx < cliprect.left()) + if (!(Flags & POLY_FLAG_NO_CLIPPING)) { - for (int paramnum = 0; paramnum < paramcount; paramnum++) - extent.param[paramnum].start += (cliprect.left() - istartx) * extent.param[paramnum].dpdx; - istartx = cliprect.left(); + if (istartx < cliprect.left()) + { + for (int paramnum = 0; paramnum < ParamCount; paramnum++) + extent.param[paramnum].start += (cliprect.left() - istartx) * extent.param[paramnum].dpdx; + istartx = cliprect.left(); + } + if (istopx > cliprect.right()) + istopx = cliprect.right() + 1; } - if (istopx > cliprect.right()) - istopx = cliprect.right() + 1; // set the extent and update the total pixel count if (istartx >= istopx) istartx = istopx = 0; extent.startx = istartx; extent.stopx = istopx; - extent.userdata = nullptr; pixels += istopx - istartx; } } // enqueue the work items - if (m_queue != nullptr) - osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + queue_items(startunit); // return the total number of pixels in the triangle m_quads++; @@ -1129,8 +1285,9 @@ uint32_t poly_manager::render_polygon // a z coordinate //------------------------------------------------- -template -int poly_manager::zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, BaseType clipval) +template +template +int poly_manager::zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, BaseType clipval) { bool prevclipped = (v[numverts - 1].p[0] < clipval); vertex_t *nextout = outv; @@ -1148,7 +1305,7 @@ int poly_manager::zclip_if_less(int n BaseType frac = (clipval - v1.p[0]) / (v2.p[0] - v1.p[0]); nextout->x = v1.x + frac * (v2.x - v1.x); nextout->y = v1.y + frac * (v2.y - v1.y); - for (int paramnum = 0; paramnum < paramcount; paramnum++) + for (int paramnum = 0; paramnum < ParamCount; paramnum++) nextout->p[paramnum] = v1.p[paramnum] + frac * (v2.p[paramnum] - v1.p[paramnum]); ++nextout; } @@ -1167,13 +1324,13 @@ int poly_manager::zclip_if_less(int n template struct frustum_clip_vertex { - BaseType x, y, z, w; // A 3d coordinate already transformed by a projection matrix - BaseType p[MaxParams]; // Additional parameters to clip + BaseType x, y, z, w; // A 3d coordinate already transformed by a projection matrix + std::array p; // Additional parameters to clip }; template -int frustum_clip_w(const frustum_clip_vertex* v, int num_vertices, frustum_clip_vertex* out) +int frustum_clip_w(frustum_clip_vertex const *v, int num_vertices, frustum_clip_vertex *out) { if (num_vertices <= 0) return 0; @@ -1225,7 +1382,7 @@ int frustum_clip_w(const frustum_clip_vertex* v, int num_ve template -int frustum_clip(const frustum_clip_vertex* v, int num_vertices, frustum_clip_vertex* out, int axis, int sign) +int frustum_clip(frustum_clip_vertex const *v, int num_vertices, frustum_clip_vertex *out, int axis, int sign) { if (num_vertices <= 0) return 0; @@ -1293,7 +1450,7 @@ int frustum_clip(const frustum_clip_vertex* v, int num_vert template -int frustum_clip_all(frustum_clip_vertex* clip_vert, int num_vertices, frustum_clip_vertex* out) +int frustum_clip_all(frustum_clip_vertex *clip_vert, int num_vertices, frustum_clip_vertex *out) { num_vertices = frustum_clip_w(clip_vert, num_vertices, clip_vert); num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 0, 0); // W <= -X diff --git a/src/devices/video/polylgcy.cpp b/src/devices/video/polylgcy.cpp deleted file mode 100644 index 9bfc35f9733..00000000000 --- a/src/devices/video/polylgcy.cpp +++ /dev/null @@ -1,1376 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ville Linde, Aaron Giles -/*************************************************************************** - - polylgcy.c - - Legacy helper routines for polygon rendering. - -***************************************************************************/ - -#include "emu.h" -#include "polylgcy.h" - -#include - - -namespace { - -/*************************************************************************** - DEBUGGING -***************************************************************************/ - -/* keep statistics */ -#define KEEP_STATISTICS 0 - -/* turn this on to log the reasons for any long waits */ -#define LOG_WAITS 0 - -/* number of profiling ticks before we consider a wait "long" */ -#define LOG_WAIT_THRESHOLD 1000 - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define SCANLINES_PER_BUCKET 8 -#define CACHE_LINE_SIZE 64 /* this is a general guess */ -#define TOTAL_BUCKETS (512 / SCANLINES_PER_BUCKET) -#define UNITS_PER_POLY (100 / SCANLINES_PER_BUCKET) - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* forward definitions */ -struct polygon_info; - - -/* tri_extent describes start/end points for a scanline */ -struct tri_extent -{ - int16_t startx; /* starting X coordinate (inclusive) */ - int16_t stopx; /* ending X coordinate (exclusive) */ -}; - - -/* single set of polygon per-parameter data */ -struct poly_param -{ - float start; /* parameter value at starting X,Y */ - float dpdx; /* dp/dx relative to starting X */ - float dpdy; /* dp/dy relative to starting Y */ -}; - - -/* poly edge is used internally for quad rendering */ -struct poly_edge -{ - poly_edge * next; /* next edge in sequence */ - int index; /* index of this edge */ - const poly_vertex * v1; /* pointer to first vertex */ - const poly_vertex * v2; /* pointer to second vertex */ - float dxdy; /* dx/dy along the edge */ - float dpdy[POLYLGCY_MAX_VERTEX_PARAMS];/* per-parameter dp/dy values */ -}; - - -/* poly section is used internally for quad rendering */ -struct poly_section -{ - const poly_edge * ledge; /* pointer to left edge */ - const poly_edge * redge; /* pointer to right edge */ - float ybottom; /* bottom of this section */ -}; - - -/* work_unit_shared is a common set of data shared between tris and quads */ -struct work_unit_shared -{ - polygon_info * polygon; /* pointer to polygon */ - std::atomic count_next; /* number of scanlines and index of next item to process */ - int16_t scanline; /* starting scanline and count */ - uint16_t previtem; /* index of previous item in the same bucket */ -#ifndef PTR64 - uint32_t dummy; /* pad to 16 bytes */ -#endif -}; - - -/* tri_work_unit is a triangle-specific work-unit */ -struct tri_work_unit -{ - work_unit_shared shared; /* shared data */ - tri_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */ -}; - - -/* quad_work_unit is a quad-specific work-unit */ -struct quad_work_unit -{ - work_unit_shared shared; /* shared data */ - poly_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */ -}; - - -/* work_unit is a union of the two types */ -union work_unit -{ - work_unit_shared shared; /* shared data */ - tri_work_unit tri; /* triangle work unit */ - quad_work_unit quad; /* quad work unit */ -}; - - -/* polygon_info describes a single polygon, which includes the poly_params */ -struct polygon_info -{ - legacy_poly_manager * poly; /* pointer back to the poly manager */ - void * dest; /* pointer to the destination we are rendering to */ - void * extra; /* extra data pointer */ - uint8_t numparams; /* number of parameters for this polygon */ - uint8_t numverts; /* number of vertices in this polygon */ - poly_draw_scanline_func callback; /* callback to handle a scanline's worth of work */ - int32_t xorigin; /* X origin for all parameters */ - int32_t yorigin; /* Y origin for all parameters */ - poly_param param[POLYLGCY_MAX_VERTEX_PARAMS];/* array of parameter data */ -}; - -} // anonymous namespace - - -/* full poly manager description */ -struct legacy_poly_manager -{ - /* queue management */ - osd_work_queue * queue; /* work queue */ - - /* triangle work units */ - std::vector unit; /* array of work unit pointers */ - uint32_t unit_next; /* index of next unit to allocate */ - uint32_t unit_count; /* number of work units available */ - size_t unit_size; /* size of each work unit, in bytes */ - - /* quad work units */ - uint32_t quadunit_next; /* index of next unit to allocate */ - uint32_t quadunit_count; /* number of work units available */ - size_t quadunit_size; /* size of each work unit, in bytes */ - - /* poly data */ - std::vector polygon; /* array of polygon pointers */ - uint32_t polygon_next; /* index of next polygon to allocate */ - uint32_t polygon_count; /* number of polygon items available */ - size_t polygon_size; /* size of each polygon, in bytes */ - - /* extra data */ - std::vector extra; /* array of extra data pointers */ - uint32_t extra_next; /* index of next extra data to allocate */ - uint32_t extra_count; /* number of extra data items available */ - size_t extra_size; /* size of each extra data, in bytes */ - - /* misc data */ - uint8_t flags; /* flags */ - - /* buckets */ - uint16_t unit_bucket[TOTAL_BUCKETS]; /* buckets for tracking unit usage */ - - /* statistics */ - uint32_t triangles; /* number of triangles queued */ - uint32_t quads; /* number of quads queued */ - uint64_t pixels; /* number of pixels rendered */ -#if KEEP_STATISTICS - uint32_t unit_waits; /* number of times we waited for a unit */ - uint32_t unit_max; /* maximum units used */ - uint32_t polygon_waits; /* number of times we waited for a polygon */ - uint32_t polygon_max; /* maximum polygons used */ - uint32_t extra_waits; /* number of times we waited for an extra data */ - uint32_t extra_max; /* maximum extra data used */ - uint32_t conflicts[WORK_MAX_THREADS]; /* number of conflicts found, per thread */ - uint32_t resolved[WORK_MAX_THREADS]; /* number of conflicts resolved, per thread */ -#endif - - std::vector m_work_unit_alloc; - std::vector m_polygon_alloc; - std::vector m_extra_alloc; -}; - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void *poly_item_callback(void *param, int threadid); -static void poly_state_presave(legacy_poly_manager &poly); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - round_coordinate - round a coordinate to - an integer, following rules that 0.5 rounds - down --------------------------------------------------*/ - -static inline int32_t round_coordinate(float value) -{ - int32_t result = floor(value); - return result + (value - (float)result > 0.5f); -} - - -/*------------------------------------------------- - convert_tri_extent_to_poly_extent - convert - a simple tri_extent to a full poly_extent --------------------------------------------------*/ - -static inline void convert_tri_extent_to_poly_extent(poly_extent *dstextent, const tri_extent *srcextent, const polygon_info *polygon, int32_t y) -{ - /* copy start/stop always */ - dstextent->startx = srcextent->startx; - dstextent->stopx = srcextent->stopx; - - /* if we have parameters, process them as well */ - for (int paramnum = 0; paramnum < polygon->numparams; paramnum++) - { - dstextent->param[paramnum].start = polygon->param[paramnum].start + srcextent->startx * polygon->param[paramnum].dpdx + y * polygon->param[paramnum].dpdy; - dstextent->param[paramnum].dpdx = polygon->param[paramnum].dpdx; - } -} - - -/*------------------------------------------------- - interpolate_vertex - interpolate values in - a vertex based on p[0] crossing the clipval --------------------------------------------------*/ - -static inline void interpolate_vertex(poly_vertex *outv, const poly_vertex *v1, const poly_vertex *v2, int paramcount, float clipval) -{ - float frac = (clipval - v1->p[0]) / (v2->p[0] - v1->p[0]); - int paramnum; - - /* create a new one at the intersection point */ - outv->x = v1->x + frac * (v2->x - v1->x); - outv->y = v1->y + frac * (v2->y - v1->y); - for (paramnum = 0; paramnum < paramcount; paramnum++) - outv->p[paramnum] = v1->p[paramnum] + frac * (v2->p[paramnum] - v1->p[paramnum]); -} - - -/*------------------------------------------------- - copy_vertex - copy vertex data from one to - another --------------------------------------------------*/ - -static inline void copy_vertex(poly_vertex *outv, const poly_vertex *v, int paramcount) -{ - int paramnum; - - outv->x = v->x; - outv->y = v->y; - for (paramnum = 0; paramnum < paramcount; paramnum++) - outv->p[paramnum] = v->p[paramnum]; -} - - -/*------------------------------------------------- - allocate_polygon - allocate a new polygon - object, blocking if we run out --------------------------------------------------*/ - -static inline polygon_info *allocate_polygon(legacy_poly_manager *poly, int miny, int maxy) -{ - /* wait for a work item if we have to */ - if (poly->polygon_next + 1 > poly->polygon_count) - { - poly_wait(poly, "Out of polygons"); -#if KEEP_STATISTICS - poly->polygon_waits++; -#endif - } - else if (poly->unit_next + (maxy - miny) / SCANLINES_PER_BUCKET + 2 > poly->unit_count) - { - poly_wait(poly, "Out of work units"); -#if KEEP_STATISTICS - poly->unit_waits++; -#endif - } -#if KEEP_STATISTICS - poly->polygon_max = std::max(poly->polygon_max, poly->polygon_next + 1); -#endif - return poly->polygon[poly->polygon_next++]; -} - - - -/*************************************************************************** - INITIALIZATION/TEARDOWN -***************************************************************************/ - -legacy_poly_manager_owner::legacy_poly_manager_owner() : m_poly(nullptr) -{ -} - - -legacy_poly_manager_owner::~legacy_poly_manager_owner() -{ - delete m_poly; -} - -/*------------------------------------------------- - allocate_array - allocate an array of pointers --------------------------------------------------*/ - -template -static void allocate_array(running_machine &machine, std::vector &buffer, std::vector &ptrarray, size_t *itemsize, uint32_t itemcount) -{ - int itemnum; - - /* fail if 0 */ - if (itemcount == 0) - return; - - /* round to a cache line boundary */ - *itemsize = ((*itemsize + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; - - /* allocate the array */ - ptrarray.resize(itemcount); - - /* allocate the actual items */ - buffer.resize(*itemsize * itemcount); - - /* initialize the pointer array */ - for (itemnum = 0; itemnum < itemcount; itemnum++) - ptrarray[itemnum] = reinterpret_cast(&buffer[*itemsize * itemnum]); -} - - - -/*------------------------------------------------- - poly_alloc - initialize a new polygon - manager --------------------------------------------------*/ - -void poly_alloc(legacy_poly_manager_owner &owner, running_machine &machine, int max_polys, size_t extra_data_size, uint8_t flags) -{ - /* allocate the manager itself */ - legacy_poly_manager *poly = new legacy_poly_manager; - owner.m_poly = poly; - poly->flags = flags; - - /* allocate polygons */ - poly->polygon_size = sizeof(polygon_info); - poly->polygon_count = std::max(max_polys, 1); - poly->polygon_next = 0; - allocate_array(machine, poly->m_polygon_alloc, poly->polygon, &poly->polygon_size, poly->polygon_count); - - /* allocate extra data */ - poly->extra_size = extra_data_size; - poly->extra_count = poly->polygon_count; - poly->extra_next = 1; - allocate_array(machine, poly->m_extra_alloc, poly->extra, &poly->extra_size, poly->extra_count); - - /* allocate triangle work units */ - poly->unit_size = (flags & POLYLGCY_FLAG_ALLOW_QUADS) ? sizeof(quad_work_unit) : sizeof(tri_work_unit); - poly->unit_count = std::min(poly->polygon_count * UNITS_PER_POLY, 65535U); - poly->unit_next = 0; - allocate_array(machine, poly->m_work_unit_alloc, poly->unit, &poly->unit_size, poly->unit_count); - - /* create the work queue */ - if (!(flags & POLYLGCY_FLAG_NO_WORK_QUEUE)) - poly->queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); - - /* request a pre-save callback for synchronization */ - machine.save().register_presave(save_prepost_delegate(FUNC(poly_state_presave), poly)); -} - - -/*------------------------------------------------- - poly_free - free a polygon manager --------------------------------------------------*/ - -void poly_free(legacy_poly_manager *poly) -{ -#if KEEP_STATISTICS -{ - int conflicts = 0, resolved = 0; - for (int i = 0; i < std::size(poly->conflicts); i++) - { - conflicts += poly->conflicts[i]; - resolved += poly->resolved[i]; - } - printf("Total triangles = %d\n", poly->triangles); - printf("Total quads = %d\n", poly->quads); - if (poly->pixels > 1000000000) - printf("Total pixels = %d%09d\n", (uint32_t)(poly->pixels / 1000000000), (uint32_t)(poly->pixels % 1000000000)); - else - printf("Total pixels = %d\n", (uint32_t)poly->pixels); - printf("Conflicts: %d resolved, %d total\n", resolved, conflicts); - printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->unit_max, poly->unit_count, poly->unit_waits, (u32) poly->unit_size, poly->unit_count * (u32) poly->unit_size); - printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->polygon_max, poly->polygon_count, poly->polygon_waits, (u32) poly->polygon_size, poly->polygon_count * (u32) poly->polygon_size); - printf("Extra data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->extra_max, poly->extra_count, poly->extra_waits, (u32) poly->extra_size, poly->extra_count * (u32) poly->extra_size); -} -#endif - - /* free the work queue */ - if (poly->queue != nullptr) - osd_work_queue_free(poly->queue); -} - - - -/*************************************************************************** - COMMON FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - poly_wait - wait for all pending rendering - to complete --------------------------------------------------*/ - -void poly_wait(legacy_poly_manager *poly, const char *debug_reason) -{ - osd_ticks_t time; - - /* remember the start time if we're logging */ - if (LOG_WAITS) - time = get_profile_ticks(); - - /* wait for all pending work items to complete */ - if (poly->queue != nullptr) - osd_work_queue_wait(poly->queue, osd_ticks_per_second() * 100); - - /* if we don't have a queue, just run the whole list now */ - else - { - int unitnum; - for (unitnum = 0; unitnum < poly->unit_next; unitnum++) - poly_item_callback(poly->unit[unitnum], 0); - } - - /* log any long waits */ - if (LOG_WAITS) - { - time = get_profile_ticks() - time; - if (time > LOG_WAIT_THRESHOLD) - osd_printf_verbose("Poly:Waited %d cycles for %s\n", (int)time, debug_reason); - } - - /* reset the state */ - poly->polygon_next = poly->unit_next = 0; - memset(poly->unit_bucket, 0xff, sizeof(poly->unit_bucket)); - - /* we need to preserve the last extra data that was supplied */ - if (poly->extra_next > 1) - memcpy(poly->extra[0], poly->extra[poly->extra_next - 1], poly->extra_size); - poly->extra_next = 1; -} - - -/*------------------------------------------------- - poly_get_extra_data - get a pointer to the - extra data for the next polygon --------------------------------------------------*/ - -void *poly_get_extra_data(legacy_poly_manager *poly) -{ - /* wait for a work item if we have to */ - if (poly->extra_next + 1 > poly->extra_count) - { - poly_wait(poly, "Out of extra data"); -#if KEEP_STATISTICS - poly->extra_waits++; -#endif - } - - /* return a pointer to the extra data for the next item */ -#if KEEP_STATISTICS - poly->extra_max = std::max(poly->extra_max, poly->extra_next + 1); -#endif - return poly->extra[poly->extra_next++]; -} - - - -/*************************************************************************** - CORE TRIANGLE RENDERING -***************************************************************************/ - -/*------------------------------------------------- - poly_render_triangle - render a single - triangle given 3 vertexes --------------------------------------------------*/ - -uint32_t poly_render_triangle(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3) -{ - float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3; - const poly_vertex *tv; - int32_t curscan, scaninc; - polygon_info *polygon; - int32_t v1yclip, v3yclip; - int32_t v1y, v3y, v1x; - int32_t pixels = 0; - uint32_t startunit; - - /* first sort by Y */ - if (v2->y < v1->y) - { - tv = v1; - v1 = v2; - v2 = tv; - } - if (v3->y < v2->y) - { - tv = v2; - v2 = v3; - v3 = tv; - if (v2->y < v1->y) - { - tv = v1; - v1 = v2; - v2 = tv; - } - } - - /* compute some integral X/Y vertex values */ - v1x = round_coordinate(v1->x); - v1y = round_coordinate(v1->y); - v3y = round_coordinate(v3->y); - - /* clip coordinates */ - v1yclip = v1y; - v3yclip = v3y + ((poly->flags & POLYLGCY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - v1yclip = std::max(v1yclip, cliprect.min_y); - v3yclip = std::min(v3yclip, cliprect.max_y + 1); - if (v3yclip - v1yclip <= 0) - return 0; - - /* allocate a new polygon */ - polygon = allocate_polygon(poly, v1yclip, v3yclip); - - /* fill in the polygon information */ - polygon->poly = poly; - polygon->dest = dest; - polygon->callback = callback; - polygon->extra = poly->extra[poly->extra_next - 1]; - polygon->numparams = paramcount; - polygon->numverts = 3; - - /* set the start X/Y coordinates */ - polygon->xorigin = v1x; - polygon->yorigin = v1y; - - /* compute the slopes for each portion of the triangle */ - dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y); - dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y); - dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y); - - /* compute the X extents for each scanline */ - startunit = poly->unit_next; - for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) - { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; - uint32_t unit_index = poly->unit_next++; - tri_work_unit *unit = &poly->unit[unit_index]->tri; - int extnum; - - /* determine how much to advance to hit the next bucket */ - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; - - /* fill in the work unit basics */ - unit->shared.polygon = polygon; - unit->shared.count_next = std::min(v3yclip - curscan, scaninc); - unit->shared.scanline = curscan; - unit->shared.previtem = poly->unit_bucket[bucketnum]; - poly->unit_bucket[bucketnum] = unit_index; - - /* iterate over extents */ - for (extnum = 0; extnum < unit->shared.count_next; extnum++) - { - float fully = (float)(curscan + extnum) + 0.5f; - float startx = v1->x + (fully - v1->y) * dxdy_v1v3; - float stopx; - int32_t istartx, istopx; - - /* compute the ending X based on which part of the triangle we're in */ - if (fully < v2->y) - stopx = v1->x + (fully - v1->y) * dxdy_v1v2; - else - stopx = v2->x + (fully - v2->y) * dxdy_v2v3; - - /* clamp to full pixels */ - istartx = round_coordinate(startx); - istopx = round_coordinate(stopx); - - /* force start < stop */ - if (istartx > istopx) - { - int32_t temp = istartx; - istartx = istopx; - istopx = temp; - } - - /* include the right edge if requested */ - if (poly->flags & POLYLGCY_FLAG_INCLUDE_RIGHT_EDGE) - istopx++; - - /* apply left/right clipping */ - if (istartx < cliprect.min_x) - istartx = cliprect.min_x; - if (istopx > cliprect.max_x) - istopx = cliprect.max_x + 1; - - /* set the extent and update the total pixel count */ - if (istartx >= istopx) - istartx = istopx = 0; - unit->extent[extnum].startx = istartx; - unit->extent[extnum].stopx = istopx; - pixels += istopx - istartx; - } - } -#if KEEP_STATISTICS - poly->unit_max = std::max(poly->unit_max, poly->unit_next); -#endif - - /* compute parameter starting points and deltas */ - if (paramcount > 0) - { - float a00 = v2->y - v3->y; - float a01 = v3->x - v2->x; - float a02 = v2->x*v3->y - v3->x*v2->y; - float a10 = v3->y - v1->y; - float a11 = v1->x - v3->x; - float a12 = v3->x*v1->y - v1->x*v3->y; - float a20 = v1->y - v2->y; - float a21 = v2->x - v1->x; - float a22 = v1->x*v2->y - v2->x*v1->y; - float det = a02 + a12 + a22; - - if(fabsf(det) < 0.001f) { - for (int paramnum = 0; paramnum < paramcount; paramnum++) - { - poly_param *params = &polygon->param[paramnum]; - params->dpdx = 0; - params->dpdy = 0; - params->start = v1->p[paramnum]; - } - } - else - { - float idet = 1/det; - for (int paramnum = 0; paramnum < paramcount; paramnum++) - { - poly_param *params = &polygon->param[paramnum]; - params->dpdx = idet*(v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); - params->dpdy = idet*(v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); - params->start = idet*(v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22); - } - } - } - - /* enqueue the work items */ - if (poly->queue != nullptr) - osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); - - /* return the total number of pixels in the triangle */ - poly->triangles++; - poly->pixels += pixels; - return pixels; -} - - -/*------------------------------------------------- - poly_render_triangle_fan - render a set of - triangles in a fan --------------------------------------------------*/ - -uint32_t poly_render_triangle_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) -{ - uint32_t pixels = 0; - int vertnum; - - /* iterate over vertices */ - for (vertnum = 2; vertnum < numverts; vertnum++) - pixels += poly_render_triangle(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum]); - return pixels; -} - - -/*------------------------------------------------- - poly_render_triangle_custom - perform a custom - render of an object, given specific extents --------------------------------------------------*/ - -uint32_t poly_render_triangle_custom(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int startscanline, int numscanlines, const poly_extent *extents) -{ - int32_t curscan, scaninc; - polygon_info *polygon; - int32_t v1yclip, v3yclip; - int32_t pixels = 0; - uint32_t startunit; - - /* clip coordinates */ - v1yclip = std::max(startscanline, cliprect.min_y); - v3yclip = std::min(startscanline + numscanlines, cliprect.max_y + 1); - if (v3yclip - v1yclip <= 0) - return 0; - - /* allocate a new polygon */ - polygon = allocate_polygon(poly, v1yclip, v3yclip); - - /* fill in the polygon information */ - polygon->poly = poly; - polygon->dest = dest; - polygon->callback = callback; - polygon->extra = poly->extra[poly->extra_next - 1]; - polygon->numparams = 0; - polygon->numverts = 3; - - /* compute the X extents for each scanline */ - startunit = poly->unit_next; - for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) - { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; - uint32_t unit_index = poly->unit_next++; - tri_work_unit *unit = &poly->unit[unit_index]->tri; - int extnum; - - /* determine how much to advance to hit the next bucket */ - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; - - /* fill in the work unit basics */ - unit->shared.polygon = polygon; - unit->shared.count_next = std::min(v3yclip - curscan, scaninc); - unit->shared.scanline = curscan; - unit->shared.previtem = poly->unit_bucket[bucketnum]; - poly->unit_bucket[bucketnum] = unit_index; - - /* iterate over extents */ - for (extnum = 0; extnum < unit->shared.count_next; extnum++) - { - const poly_extent *extent = &extents[(curscan + extnum) - startscanline]; - int32_t istartx = extent->startx, istopx = extent->stopx; - - /* force start < stop */ - if (istartx > istopx) - { - int32_t temp = istartx; - istartx = istopx; - istopx = temp; - } - - /* apply left/right clipping */ - if (istartx < cliprect.min_x) - istartx = cliprect.min_x; - if (istopx > cliprect.max_x) - istopx = cliprect.max_x + 1; - - /* set the extent and update the total pixel count */ - unit->extent[extnum].startx = istartx; - unit->extent[extnum].stopx = istopx; - if (istartx < istopx) - pixels += istopx - istartx; - } - } -#if KEEP_STATISTICS - poly->unit_max = std::max(poly->unit_max, poly->unit_next); -#endif - - /* enqueue the work items */ - if (poly->queue != nullptr) - osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); - - /* return the total number of pixels in the object */ - poly->triangles++; - poly->pixels += pixels; - return pixels; -} - - - -/*************************************************************************** - CORE QUAD RENDERING -***************************************************************************/ - -/*------------------------------------------------- - poly_render_quad - render a single quad - given 4 vertexes --------------------------------------------------*/ - -uint32_t poly_render_quad(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4) -{ - poly_edge fedgelist[3], bedgelist[3]; - const poly_edge *ledge, *redge; - const poly_vertex *v[4]; - poly_edge *edgeptr; - int minv, maxv, curv; - int32_t minyclip, maxyclip; - int32_t miny, maxy; - int32_t curscan, scaninc; - polygon_info *polygon; - int32_t pixels = 0; - uint32_t startunit; - - assert(poly->flags & POLYLGCY_FLAG_ALLOW_QUADS); - - /* arrays make things easier */ - v[0] = v1; - v[1] = v2; - v[2] = v3; - v[3] = v4; - - /* determine min/max Y vertices */ - if (v[1]->y < v[0]->y) - minv = 1, maxv = 0; - else - minv = 0, maxv = 1; - if (v[2]->y < v[minv]->y) - minv = 2; - else if (v[2]->y > v[maxv]->y) - maxv = 2; - if (v[3]->y < v[minv]->y) - minv = 3; - else if (v[3]->y > v[maxv]->y) - maxv = 3; - - /* determine start/end scanlines */ - miny = round_coordinate(v[minv]->y); - maxy = round_coordinate(v[maxv]->y); - - /* clip coordinates */ - minyclip = miny; - maxyclip = maxy + ((poly->flags & POLYLGCY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - minyclip = std::max(minyclip, cliprect.min_y); - maxyclip = std::min(maxyclip, cliprect.max_y + 1); - if (maxyclip - minyclip <= 0) - return 0; - - /* allocate a new polygon */ - polygon = allocate_polygon(poly, minyclip, maxyclip); - - /* fill in the polygon information */ - polygon->poly = poly; - polygon->dest = dest; - polygon->callback = callback; - polygon->extra = poly->extra[poly->extra_next - 1]; - polygon->numparams = paramcount; - polygon->numverts = 4; - - /* walk forward to build up the forward edge list */ - edgeptr = &fedgelist[0]; - for (curv = minv; curv != maxv; curv = (curv + 1) & 3) - { - int paramnum; - float ooy; - - /* set the two vertices */ - edgeptr->v1 = v[curv]; - edgeptr->v2 = v[(curv + 1) & 3]; - - /* if horizontal, skip altogether */ - if (edgeptr->v1->y == edgeptr->v2->y) - continue; - - /* need dx/dy always, and parameter deltas as necessary */ - ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); - edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (paramnum = 0; paramnum < paramcount; paramnum++) - edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; - edgeptr++; - } - - /* walk backward to build up the backward edge list */ - edgeptr = &bedgelist[0]; - for (curv = minv; curv != maxv; curv = (curv - 1) & 3) - { - int paramnum; - float ooy; - - /* set the two vertices */ - edgeptr->v1 = v[curv]; - edgeptr->v2 = v[(curv - 1) & 3]; - - /* if horizontal, skip altogether */ - if (edgeptr->v1->y == edgeptr->v2->y) - continue; - - /* need dx/dy always, and parameter deltas as necessary */ - ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); - edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (paramnum = 0; paramnum < paramcount; paramnum++) - edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; - edgeptr++; - } - - /* determine which list is left/right: */ - /* if the first vertex is shared, compare the slopes */ - /* if the first vertex is not shared, compare the X coordinates */ - if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || - (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) - { - ledge = fedgelist; - redge = bedgelist; - } - else - { - ledge = bedgelist; - redge = fedgelist; - } - - /* compute the X extents for each scanline */ - startunit = poly->unit_next; - for (curscan = minyclip; curscan < maxyclip; curscan += scaninc) - { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; - uint32_t unit_index = poly->unit_next++; - quad_work_unit *unit = &poly->unit[unit_index]->quad; - int extnum; - - /* determine how much to advance to hit the next bucket */ - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; - - /* fill in the work unit basics */ - unit->shared.polygon = polygon; - unit->shared.count_next = std::min(maxyclip - curscan, scaninc); - unit->shared.scanline = curscan; - unit->shared.previtem = poly->unit_bucket[bucketnum]; - poly->unit_bucket[bucketnum] = unit_index; - - /* iterate over extents */ - for (extnum = 0; extnum < unit->shared.count_next; extnum++) - { - float fully = (float)(curscan + extnum) + 0.5f; - float startx, stopx; - int32_t istartx, istopx; - int paramnum; - - /* compute the ending X based on which part of the triangle we're in */ - while (fully > ledge->v2->y && fully < v[maxv]->y) - ledge++; - while (fully > redge->v2->y && fully < v[maxv]->y) - redge++; - startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; - stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; - - /* clamp to full pixels */ - istartx = round_coordinate(startx); - istopx = round_coordinate(stopx); - - /* compute parameter starting points and deltas */ - if (paramcount > 0) - { - float ldy = fully - ledge->v1->y; - float rdy = fully - redge->v1->y; - float oox = 1.0f / (stopx - startx); - - /* iterate over parameters */ - for (paramnum = 0; paramnum < paramcount; paramnum++) - { - float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; - float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; - float dpdx = (rparam - lparam) * oox; - - unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx; - unit->extent[extnum].param[paramnum].dpdx = dpdx; - } - } - - /* include the right edge if requested */ - if (poly->flags & POLYLGCY_FLAG_INCLUDE_RIGHT_EDGE) - istopx++; - - /* apply left/right clipping */ - if (istartx < cliprect.min_x) - { - for (paramnum = 0; paramnum < paramcount; paramnum++) - unit->extent[extnum].param[paramnum].start += (cliprect.min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx; - istartx = cliprect.min_x; - } - if (istopx > cliprect.max_x) - istopx = cliprect.max_x + 1; - - /* set the extent and update the total pixel count */ - if (istartx >= istopx) - istartx = istopx = 0; - unit->extent[extnum].startx = istartx; - unit->extent[extnum].stopx = istopx; - pixels += istopx - istartx; - } - } -#if KEEP_STATISTICS - poly->unit_max = std::max(poly->unit_max, poly->unit_next); -#endif - - /* enqueue the work items */ - if (poly->queue != nullptr) - osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); - - /* return the total number of pixels in the triangle */ - poly->quads++; - poly->pixels += pixels; - return pixels; -} - - -/*------------------------------------------------- - poly_render_quad_fan - render a set of - quads in a fan --------------------------------------------------*/ - -uint32_t poly_render_quad_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) -{ - uint32_t pixels = 0; - int vertnum; - - /* iterate over vertices */ - for (vertnum = 2; vertnum < numverts; vertnum += 2) - pixels += poly_render_quad(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum], &v[std::min(vertnum + 1, numverts - 1)]); - return pixels; -} - - - -/*************************************************************************** - CORE POLYGON RENDERING -***************************************************************************/ - -/*------------------------------------------------- - poly_render_polygon - render a single polygon up - to 32 vertices --------------------------------------------------*/ - -uint32_t poly_render_polygon(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) -{ - poly_edge fedgelist[POLYLGCY_MAX_POLYGON_VERTS - 1], bedgelist[POLYLGCY_MAX_POLYGON_VERTS - 1]; - const poly_edge *ledge, *redge; - poly_edge *edgeptr; - int minv, maxv, curv; - int32_t minyclip, maxyclip; - int32_t miny, maxy; - int32_t curscan, scaninc; - polygon_info *polygon; - int32_t pixels = 0; - uint32_t startunit; - int vertnum; - - assert(poly->flags & POLYLGCY_FLAG_ALLOW_QUADS); - - /* determine min/max Y vertices */ - minv = maxv = 0; - for (vertnum = 1; vertnum < numverts; vertnum++) - { - if (v[vertnum].y < v[minv].y) - minv = vertnum; - else if (v[vertnum].y > v[maxv].y) - maxv = vertnum; - } - - /* determine start/end scanlines */ - miny = round_coordinate(v[minv].y); - maxy = round_coordinate(v[maxv].y); - - /* clip coordinates */ - minyclip = miny; - maxyclip = maxy + ((poly->flags & POLYLGCY_FLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); - minyclip = std::max(minyclip, cliprect.min_y); - maxyclip = std::min(maxyclip, cliprect.max_y + 1); - if (maxyclip - minyclip <= 0) - return 0; - - /* allocate a new polygon */ - polygon = allocate_polygon(poly, minyclip, maxyclip); - - /* fill in the polygon information */ - polygon->poly = poly; - polygon->dest = dest; - polygon->callback = callback; - polygon->extra = poly->extra[poly->extra_next - 1]; - polygon->numparams = paramcount; - polygon->numverts = numverts; - - /* walk forward to build up the forward edge list */ - edgeptr = &fedgelist[0]; - for (curv = minv; curv != maxv; curv = (curv == numverts - 1) ? 0 : (curv + 1)) - { - int paramnum; - float ooy; - - /* set the two vertices */ - edgeptr->v1 = &v[curv]; - edgeptr->v2 = &v[(curv == numverts - 1) ? 0 : (curv + 1)]; - - /* if horizontal, skip altogether */ - if (edgeptr->v1->y == edgeptr->v2->y) - continue; - - /* need dx/dy always, and parameter deltas as necessary */ - ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); - edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (paramnum = 0; paramnum < paramcount; paramnum++) - edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; - edgeptr++; - } - - /* walk backward to build up the backward edge list */ - edgeptr = &bedgelist[0]; - for (curv = minv; curv != maxv; curv = (curv == 0) ? (numverts - 1) : (curv - 1)) - { - int paramnum; - float ooy; - - /* set the two vertices */ - edgeptr->v1 = &v[curv]; - edgeptr->v2 = &v[(curv == 0) ? (numverts - 1) : (curv - 1)]; - - /* if horizontal, skip altogether */ - if (edgeptr->v1->y == edgeptr->v2->y) - continue; - - /* need dx/dy always, and parameter deltas as necessary */ - ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); - edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; - for (paramnum = 0; paramnum < paramcount; paramnum++) - edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; - edgeptr++; - } - - /* determine which list is left/right: */ - /* if the first vertex is shared, compare the slopes */ - /* if the first vertex is not shared, compare the X coordinates */ - if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || - (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) - { - ledge = fedgelist; - redge = bedgelist; - } - else - { - ledge = bedgelist; - redge = fedgelist; - } - - /* compute the X extents for each scanline */ - startunit = poly->unit_next; - for (curscan = minyclip; curscan < maxyclip; curscan += scaninc) - { - uint32_t bucketnum = ((uint32_t)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; - uint32_t unit_index = poly->unit_next++; - quad_work_unit *unit = &poly->unit[unit_index]->quad; - int extnum; - - /* determine how much to advance to hit the next bucket */ - scaninc = SCANLINES_PER_BUCKET - (uint32_t)curscan % SCANLINES_PER_BUCKET; - - /* fill in the work unit basics */ - unit->shared.polygon = polygon; - unit->shared.count_next = std::min(maxyclip - curscan, scaninc); - unit->shared.scanline = curscan; - unit->shared.previtem = poly->unit_bucket[bucketnum]; - poly->unit_bucket[bucketnum] = unit_index; - - /* iterate over extents */ - for (extnum = 0; extnum < unit->shared.count_next; extnum++) - { - float fully = (float)(curscan + extnum) + 0.5f; - float startx, stopx; - int32_t istartx, istopx; - int paramnum; - - /* compute the ending X based on which part of the triangle we're in */ - while (fully > ledge->v2->y && fully < v[maxv].y) - ledge++; - while (fully > redge->v2->y && fully < v[maxv].y) - redge++; - startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; - stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; - - /* clamp to full pixels */ - istartx = round_coordinate(startx); - istopx = round_coordinate(stopx); - - /* compute parameter starting points and deltas */ - if (paramcount > 0) - { - float ldy = fully - ledge->v1->y; - float rdy = fully - redge->v1->y; - float oox = 1.0f / (stopx - startx); - - /* iterate over parameters */ - for (paramnum = 0; paramnum < paramcount; paramnum++) - { - float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; - float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; - float dpdx = (rparam - lparam) * oox; - - unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx; - unit->extent[extnum].param[paramnum].dpdx = dpdx; - } - } - - /* include the right edge if requested */ - if (poly->flags & POLYLGCY_FLAG_INCLUDE_RIGHT_EDGE) - istopx++; - - /* apply left/right clipping */ - if (istartx < cliprect.min_x) - { - for (paramnum = 0; paramnum < paramcount; paramnum++) - unit->extent[extnum].param[paramnum].start += (cliprect.min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx; - istartx = cliprect.min_x; - } - if (istopx > cliprect.max_x) - istopx = cliprect.max_x + 1; - - /* set the extent and update the total pixel count */ - if (istartx >= istopx) - istartx = istopx = 0; - unit->extent[extnum].startx = istartx; - unit->extent[extnum].stopx = istopx; - pixels += istopx - istartx; - } - } -#if KEEP_STATISTICS - poly->unit_max = std::max(poly->unit_max, poly->unit_next); -#endif - - /* enqueue the work items */ - if (poly->queue != nullptr) - osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); - - /* return the total number of pixels in the triangle */ - poly->quads++; - poly->pixels += pixels; - return pixels; -} - - - -/*************************************************************************** - CLIPPING -***************************************************************************/ - -/*------------------------------------------------- - poly_zclip_if_less - z clip a polygon against - the given value, returning a set of clipped - vertices --------------------------------------------------*/ - -int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval) -{ - int prevclipped = (v[numverts - 1].p[0] < clipval); - poly_vertex *nextout = outv; - int vertnum; - - /* iterate over vertices */ - for (vertnum = 0; vertnum < numverts; vertnum++) - { - int thisclipped = (v[vertnum].p[0] < clipval); - - /* if we switched from clipped to non-clipped, interpolate a vertex */ - if (thisclipped != prevclipped) - interpolate_vertex(nextout++, &v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)], &v[vertnum], paramcount, clipval); - - /* if this vertex is not clipped, copy it in */ - if (!thisclipped) - copy_vertex(nextout++, &v[vertnum], paramcount); - - /* remember the last state */ - prevclipped = thisclipped; - } - return nextout - outv; -} - - - -/*************************************************************************** - INTERNAL FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - poly_item_callback - callback for each poly - item --------------------------------------------------*/ - -static void *poly_item_callback(void *param, int threadid) -{ - while (1) - { - work_unit *unit = (work_unit *)param; - polygon_info *polygon = unit->shared.polygon; - int count = unit->shared.count_next & 0xffff; - uint32_t orig_count_next; - int curscan; - - /* if our previous item isn't done yet, enqueue this item to the end and proceed */ - if (unit->shared.previtem != 0xffff) - { - work_unit *prevunit = polygon->poly->unit[unit->shared.previtem]; - if (prevunit->shared.count_next != 0) - { - uint32_t unitnum = ((uint8_t *)unit - (uint8_t *)polygon->poly->unit[0]) / polygon->poly->unit_size; - uint32_t new_count_next; - - /* attempt to atomically swap in this new value */ - do - { - orig_count_next = prevunit->shared.count_next; - new_count_next = orig_count_next | (unitnum << 16); - } while (!prevunit->shared.count_next.compare_exchange_weak(orig_count_next, new_count_next, std::memory_order_release, std::memory_order_relaxed)); - -#if KEEP_STATISTICS - /* track resolved conflicts */ - polygon->poly->conflicts[threadid]++; - if (orig_count_next != 0) - polygon->poly->resolved[threadid]++; -#endif - /* if we succeeded, skip out early so we can do other work */ - if (orig_count_next != 0) - break; - } - } - - /* iterate over extents */ - for (curscan = 0; curscan < count; curscan++) - { - if (polygon->numverts == 3) - { - poly_extent tmpextent; - convert_tri_extent_to_poly_extent(&tmpextent, &unit->tri.extent[curscan], polygon, unit->shared.scanline + curscan); - (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &tmpextent, polygon->extra, threadid); - } - else - (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &unit->quad.extent[curscan], polygon->extra, threadid); - } - - /* set our count to 0 and re-fetch the original count value */ - do - { - orig_count_next = unit->shared.count_next; - } while (!unit->shared.count_next.compare_exchange_weak(orig_count_next, 0, std::memory_order_release, std::memory_order_relaxed)); - - /* if we have no more work to do, do nothing */ - orig_count_next >>= 16; - if (orig_count_next == 0) - break; - param = polygon->poly->unit[orig_count_next]; - } - return nullptr; -} - - -/*------------------------------------------------- - poly_state_presave - pre-save callback to - ensure everything is synced before saving --------------------------------------------------*/ - -static void poly_state_presave(legacy_poly_manager &poly) -{ - poly_wait(&poly, "pre-save"); -} diff --git a/src/devices/video/polylgcy.h b/src/devices/video/polylgcy.h deleted file mode 100644 index a768b3e3b3c..00000000000 --- a/src/devices/video/polylgcy.h +++ /dev/null @@ -1,165 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ville Linde, Aaron Giles -/*************************************************************************** - - polylgcy.h - - Legacy polygon helper routines. - -**************************************************************************** - - Pixel model: - - (0.0,0.0) (1.0,0.0) (2.0,0.0) (3.0,0.0) - +---------------+---------------+---------------+ - | | | | - | | | | - | (0.5,0.5) | (1.5,0.5) | (2.5,0.5) | - | * | * | * | - | | | | - | | | | - (0.0,1.0) (1.0,1.0) (2.0,1.0) (3.0,1.0) - +---------------+---------------+---------------+ - | | | | - | | | | - | (0.5,1.5) | (1.5,1.5) | (2.5,1.5) | - | * | * | * | - | | | | - | | | | - | | | | - +---------------+---------------+---------------+ - (0.0,2.0) (1.0,2.0) (2.0,2.0) (3.0,2.0) - -***************************************************************************/ - -#ifndef MAME_VIDEO_POLYLGCY_H -#define MAME_VIDEO_POLYLGCY_H - -#pragma once - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -static constexpr unsigned POLYLGCY_MAX_VERTEX_PARAMS = 6; -static constexpr unsigned POLYLGCY_MAX_POLYGON_VERTS = 32; - -static constexpr uint8_t POLYLGCY_FLAG_INCLUDE_BOTTOM_EDGE = 0x01; -static constexpr uint8_t POLYLGCY_FLAG_INCLUDE_RIGHT_EDGE = 0x02; -static constexpr uint8_t POLYLGCY_FLAG_NO_WORK_QUEUE = 0x04; -static constexpr uint8_t POLYLGCY_FLAG_ALLOW_QUADS = 0x08; - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* opaque reference to the poly manager */ -struct legacy_poly_manager; -class legacy_poly_manager_owner -{ -public: - legacy_poly_manager_owner(); - ~legacy_poly_manager_owner(); - - operator legacy_poly_manager *() { return m_poly; } - - legacy_poly_manager *m_poly; -}; - - -/* input vertex data */ -struct poly_vertex -{ - float x; /* X coordinate */ - float y; /* Y coordinate */ - float p[POLYLGCY_MAX_VERTEX_PARAMS]; /* interpolated parameter values */ -}; - - -/* poly_param_extent describes information for a single parameter in an extent */ -struct poly_param_extent -{ - float start; /* parameter value at starting X,Y */ - float dpdx; /* dp/dx relative to starting X */ -}; - - -/* poly_extent describes start/end points for a scanline, along with per-scanline parameters */ -struct poly_extent -{ - int16_t startx; /* starting X coordinate (inclusive) */ - int16_t stopx; /* ending X coordinate (exclusive) */ - poly_param_extent param[POLYLGCY_MAX_VERTEX_PARAMS]; /* starting and dx values for each parameter */ -}; - - -/* callback routine to process a batch of scanlines in a triangle */ -typedef void (*poly_draw_scanline_func)(void *dest, int32_t scanline, const poly_extent *extent, const void *extradata, int threadid); - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - - -/* ----- initialization/teardown ----- */ - -/* allocate a new poly manager that can render triangles */ -void poly_alloc(legacy_poly_manager_owner &owner, running_machine &machine, int max_polys, size_t extra_data_size, uint8_t flags); - -/* free a poly manager */ -void poly_free(legacy_poly_manager *poly); - - - -/* ----- common functions ----- */ - -/* wait until all polygons in the queue have been rendered */ -void poly_wait(legacy_poly_manager *poly, const char *debug_reason); - -/* get a pointer to the extra data for the next polygon */ -void *poly_get_extra_data(legacy_poly_manager *poly); - - - -/* ----- core triangle rendering ----- */ - -/* render a single triangle given 3 vertexes */ -uint32_t poly_render_triangle(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3); - -/* render a set of triangles in a fan */ -uint32_t poly_render_triangle_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); - -/* perform a custom render of an object, given specific extents */ -uint32_t poly_render_triangle_custom(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int startscanline, int numscanlines, const poly_extent *extents); - - - -/* ----- core quad rendering ----- */ - -/* render a single quad given 4 vertexes */ -uint32_t poly_render_quad(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4); - -/* render a set of quads in a fan */ -uint32_t poly_render_quad_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); - - - -/* ----- core polygon rendering ----- */ - -/* render a single polygon up to 32 vertices */ -uint32_t poly_render_polygon(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); - - - -/* ----- clipping ----- */ - -/* zclip (assumes p[0] == z) a polygon */ -int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval); - - -#endif // MAME_VIDEO_POLYLGCY_H diff --git a/src/devices/video/vooddefs.ipp b/src/devices/video/vooddefs.ipp deleted file mode 100644 index d9726edf960..00000000000 --- a/src/devices/video/vooddefs.ipp +++ /dev/null @@ -1,3181 +0,0 @@ - // license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - vooddefs.h - - 3dfx Voodoo Graphics SST-1/2 emulator. - -***************************************************************************/ - -#ifndef MAME_VIDEO_VOODDEFS_IPP -#define MAME_VIDEO_VOODDEFS_IPP - -#pragma once - -#include "voodoo.h" - - - -/************************************* - * - * Core types - * - *************************************/ - -typedef voodoo_reg rgb_union; - - - - - -/************************************* - * - * Inline FIFO management - * - *************************************/ - -inline void voodoo_device::fifo_state::add(uint32_t data) -{ - /* compute the value of 'in' after we add this item */ - int32_t next_in = in + 1; - if (next_in >= size) - next_in = 0; - - /* as long as it's not equal to the output pointer, we can do it */ - if (next_in != out) - { - base[in] = data; - in = next_in; - } -} - - -inline uint32_t voodoo_device::fifo_state::remove() -{ - uint32_t data = 0xffffffff; - - /* as long as we have data, we can do it */ - if (out != in) - { - int32_t next_out; - - /* fetch the data */ - data = base[out]; - - /* advance the output pointer */ - next_out = out + 1; - if (next_out >= size) - next_out = 0; - out = next_out; - } - return data; -} - - -inline int32_t voodoo_device::fifo_state::items() const -{ - int32_t items = in - out; - if (items < 0) - items += size; - return items; -} - - - -/************************************* - * - * Computes a fast 16.16 reciprocal - * of a 16.32 value; used for - * computing 1/w in the rasterizer. - * - * Since it is trivial to also - * compute log2(1/w) = -log2(w) at - * the same time, we do that as well - * to 16.8 precision for LOD - * calculations. - * - * On a Pentium M, this routine is - * 20% faster than a 64-bit integer - * divide and also produces the log - * for free. - * - *************************************/ - -static inline int32_t fast_reciplog(int64_t value, int32_t *log2) -{ - extern uint32_t voodoo_reciplog[]; - uint32_t temp, recip, rlog; - uint32_t interp; - uint32_t *table; - int neg = false; - int lz, exp = 0; - - /* always work with unsigned numbers */ - if (value < 0) - { - value = -value; - neg = true; - } - - /* if we've spilled out of 32 bits, push it down under 32 */ - if (value & 0xffff00000000U) - { - temp = (uint32_t)(value >> 16); - exp -= 16; - } - else - temp = (uint32_t)value; - - /* if the resulting value is 0, the reciprocal is infinite */ - if (UNEXPECTED(temp == 0)) - { - *log2 = 1000 << LOG_OUTPUT_PREC; - return neg ? 0x80000000 : 0x7fffffff; - } - - /* determine how many leading zeros in the value and shift it up high */ - lz = count_leading_zeros_32(temp); - temp <<= lz; - exp += lz; - - /* compute a pointer to the table entries we want */ - /* math is a bit funny here because we shift one less than we need to in order */ - /* to account for the fact that there are two uint32_t's per table entry */ - table = &voodoo_reciplog[(temp >> (31 - RECIPLOG_LOOKUP_BITS - 1)) & ((2 << RECIPLOG_LOOKUP_BITS) - 2)]; - - /* compute the interpolation value */ - interp = (temp >> (31 - RECIPLOG_LOOKUP_BITS - 8)) & 0xff; - - /* do a linear interpolatation between the two nearest table values */ - /* for both the log and the reciprocal */ - rlog = (table[1] * (0x100 - interp) + table[3] * interp) >> 8; - recip = (table[0] * (0x100 - interp) + table[2] * interp) >> 8; - - /* the log result is the fractional part of the log; round it to the output precision */ - rlog = (rlog + (1 << (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC - 1))) >> (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC); - - /* the exponent is the non-fractional part of the log; normally, we would subtract it from rlog */ - /* but since we want the log(1/value) = -log(value), we subtract rlog from the exponent */ - *log2 = ((exp - (31 - RECIPLOG_INPUT_PREC)) << LOG_OUTPUT_PREC) - rlog; - - /* adjust the exponent to account for all the reciprocal-related parameters to arrive at a final shift amount */ - exp += (RECIP_OUTPUT_PREC - RECIPLOG_LOOKUP_PREC) - (31 - RECIPLOG_INPUT_PREC); - - /* shift by the exponent */ - if (exp < 0) - recip >>= -exp; - else - recip <<= exp; - - /* on the way out, apply the original sign to the reciprocal */ - return neg ? -recip : recip; -} - - - -/************************************* - * - * Float-to-int conversions - * - *************************************/ - -static inline int32_t float_to_int32(uint32_t data, int fixedbits) -{ - int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; - int32_t result = (data & 0x7fffff) | 0x800000; - if (exponent < 0) - { - if (exponent > -32) - result >>= -exponent; - else - result = 0; - } - else - { - if (exponent < 32) - result <<= exponent; - else - result = 0x7fffffff; - } - if (data & 0x80000000) - result = -result; - return result; -} - - -static inline int64_t float_to_int64(uint32_t data, int fixedbits) -{ - int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; - int64_t result = (data & 0x7fffff) | 0x800000; - if (exponent < 0) - { - if (exponent > -64) - result >>= -exponent; - else - result = 0; - } - else - { - if (exponent < 64) - result <<= exponent; - else - result = 0x7fffffffffffffffU; - } - if (data & 0x80000000) - result = -result; - return result; -} - - - -/************************************* - * - * Rasterizer inlines - * - *************************************/ - -static inline uint32_t normalize_color_path(uint32_t eff_color_path) -{ - /* ignore the subpixel adjust and texture enable flags */ - eff_color_path &= ~((1 << 26) | (1 << 27)); - - return eff_color_path; -} - - -static inline uint32_t normalize_alpha_mode(uint32_t eff_alpha_mode) -{ - /* always ignore alpha ref value */ - eff_alpha_mode &= ~(0xff << 24); - - /* if not doing alpha testing, ignore the alpha function and ref value */ - if (!ALPHAMODE_ALPHATEST(eff_alpha_mode)) - eff_alpha_mode &= ~(7 << 1); - - /* if not doing alpha blending, ignore the source and dest blending factors */ - if (!ALPHAMODE_ALPHABLEND(eff_alpha_mode)) - eff_alpha_mode &= ~((15 << 8) | (15 << 12) | (15 << 16) | (15 << 20)); - - return eff_alpha_mode; -} - - -static inline uint32_t normalize_fog_mode(uint32_t eff_fog_mode) -{ - /* if not doing fogging, ignore all the other fog bits */ - if (!FOGMODE_ENABLE_FOG(eff_fog_mode)) - eff_fog_mode = 0; - - return eff_fog_mode; -} - - -static inline uint32_t normalize_fbz_mode(uint32_t eff_fbz_mode) -{ - /* ignore the draw buffer */ - eff_fbz_mode &= ~(3 << 14); - - return eff_fbz_mode; -} - - -static inline uint32_t normalize_tex_mode(uint32_t eff_tex_mode) -{ - /* ignore the NCC table and seq_8_downld flags */ - eff_tex_mode &= ~((1 << 5) | (1 << 31)); - - /* classify texture formats into 3 format categories */ - if (TEXMODE_FORMAT(eff_tex_mode) < 8) - eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (0 << 8); - else if (TEXMODE_FORMAT(eff_tex_mode) >= 10 && TEXMODE_FORMAT(eff_tex_mode) <= 12) - eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (10 << 8); - else - eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (8 << 8); - - return eff_tex_mode; -} - - -inline uint32_t voodoo_device::raster_info::compute_hash() const -{ - uint32_t result; - - /* make a hash */ - result = eff_color_path; - result = (result << 1) | (result >> 31); - result ^= eff_fbz_mode; - result = (result << 1) | (result >> 31); - result ^= eff_alpha_mode; - result = (result << 1) | (result >> 31); - result ^= eff_fog_mode; - result = (result << 1) | (result >> 31); - result ^= eff_tex_mode_0; - result = (result << 1) | (result >> 31); - result ^= eff_tex_mode_1; - - return result % RASTER_HASH_SIZE; -} - - - -/************************************* - * - * Dithering macros - * - *************************************/ - -/* note that these equations and the dither matrixes have - been confirmed to be exact matches to the real hardware */ -#define DITHER_RB(val,dith) ((((val) << 1) - ((val) >> 4) + ((val) >> 7) + (dith)) >> 1) -#define DITHER_G(val,dith) ((((val) << 2) - ((val) >> 4) + ((val) >> 6) + (dith)) >> 2) - -#define DECLARE_DITHER_POINTERS \ - const uint8_t *dither_lookup = nullptr; \ - const uint8_t *dither4 = nullptr; \ - const uint8_t *dither = nullptr -#define DECLARE_DITHER_POINTERS_NO_DITHER_VAR \ - const uint8_t *dither_lookup = nullptr; -#define COMPUTE_DITHER_POINTERS(FBZMODE, YY, FOGMODE) \ -do \ -{ \ - if (FBZMODE_ENABLE_DITHERING(FBZMODE) || FOGMODE_FOG_DITHER(FOGMODE)) \ - dither4 = &dither_matrix_4x4[((YY) & 3) * 4]; \ - /* compute the dithering pointers */ \ - if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ - { \ - if (FBZMODE_DITHER_TYPE(FBZMODE) == 0) \ - { \ - dither = &dither_subtract_4x4[((YY) & 3) * 4]; \ - dither_lookup = &dither4_lookup[(YY & 3) << 11]; \ - } \ - else \ - { \ - dither = &dither_subtract_2x2[((YY) & 3) * 4]; \ - dither_lookup = &dither2_lookup[(YY & 3) << 11]; \ - } \ - } \ -} \ -while (0) - -#define COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(FBZMODE, YY) \ -do \ -{ \ - /* compute the dithering pointers */ \ - if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ - { \ - if (FBZMODE_DITHER_TYPE(FBZMODE) == 0) \ - { \ - dither_lookup = &dither4_lookup[(YY & 3) << 11]; \ - } \ - else \ - { \ - dither_lookup = &dither2_lookup[(YY & 3) << 11]; \ - } \ - } \ -} \ -while (0) - -#define APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, RR, GG, BB) \ -do \ -{ \ - /* apply dithering */ \ - if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ - { \ - /* look up the dither value from the appropriate matrix */ \ - const uint8_t *dith = &DITHER_LOOKUP[((XX) & 3) << 1]; \ - \ - /* apply dithering to R,G,B */ \ - (RR) = dith[((RR) << 3) + 0]; \ - (GG) = dith[((GG) << 3) + 1]; \ - (BB) = dith[((BB) << 3) + 0]; \ - } \ - else \ - { \ - (RR) >>= 3; \ - (GG) >>= 2; \ - (BB) >>= 3; \ - } \ -} \ -while (0) - - - -/************************************* - * - * Clamping macros - * - *************************************/ - -#define CLAMPED_ARGB(ITERR, ITERG, ITERB, ITERA, FBZCP, RESULT) \ -do \ -{ \ - r = (int32_t)(ITERR) >> 12; \ - g = (int32_t)(ITERG) >> 12; \ - b = (int32_t)(ITERB) >> 12; \ - a = (int32_t)(ITERA) >> 12; \ - \ - if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ - { \ - r &= 0xfff; \ - RESULT.rgb.r = r; \ - if (r == 0xfff) \ - RESULT.rgb.r = 0; \ - else if (r == 0x100) \ - RESULT.rgb.r = 0xff; \ - \ - g &= 0xfff; \ - RESULT.rgb.g = g; \ - if (g == 0xfff) \ - RESULT.rgb.g = 0; \ - else if (g == 0x100) \ - RESULT.rgb.g = 0xff; \ - \ - b &= 0xfff; \ - RESULT.rgb.b = b; \ - if (b == 0xfff) \ - RESULT.rgb.b = 0; \ - else if (b == 0x100) \ - RESULT.rgb.b = 0xff; \ - \ - a &= 0xfff; \ - RESULT.rgb.a = a; \ - if (a == 0xfff) \ - RESULT.rgb.a = 0; \ - else if (a == 0x100) \ - RESULT.rgb.a = 0xff; \ - } \ - else \ - { \ - RESULT.rgb.r = (r < 0) ? 0 : (r > 0xff) ? 0xff : r; \ - RESULT.rgb.g = (g < 0) ? 0 : (g > 0xff) ? 0xff : g; \ - RESULT.rgb.b = (b < 0) ? 0 : (b > 0xff) ? 0xff : b; \ - RESULT.rgb.a = (a < 0) ? 0 : (a > 0xff) ? 0xff : a; \ - } \ -} \ -while (0) - -static inline rgbaint_t ATTR_FORCE_INLINE clampARGB(const rgbaint_t &iterargb, uint32_t FBZCP) -{ - rgbaint_t result(iterargb); - //rgbaint_t colorint((int32_t) (itera>>12), (int32_t) (iterr>>12), (int32_t) (iterg>>12), (int32_t) (iterb>>12)); - result.shr_imm(12); - - if (!FBZCP_RGBZW_CLAMP(FBZCP)) - { - //r &= 0xfff; - result.and_imm(0xfff); - //if (r == 0xfff) - rgbaint_t temp(result); - temp.cmpeq_imm(0xfff); - // result.rgb.r = 0; - result.andnot_reg(temp); - //else if (r == 0x100) - // result.rgb.r = 0xff; - temp.set(result); - temp.cmpeq_imm(0x100); - result.or_reg(temp); - // else wrap - result.and_imm(0xff); - } - else - { - //return colorint.to_rgba_clamp(); - result.clamp_to_uint8(); - } - return result; -} - -#define CLAMPED_Z(ITERZ, FBZCP, RESULT) \ -do \ -{ \ - (RESULT) = (int32_t)(ITERZ) >> 12; \ - if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ - { \ - (RESULT) &= 0xfffff; \ - if ((RESULT) == 0xfffff) \ - (RESULT) = 0; \ - else if ((RESULT) == 0x10000) \ - (RESULT) = 0xffff; \ - else \ - (RESULT) &= 0xffff; \ - } \ - else \ - { \ - CLAMP((RESULT), 0, 0xffff); \ - } \ -} \ -while (0) - - -#define CLAMPED_W(ITERW, FBZCP, RESULT) \ -do \ -{ \ - (RESULT) = (int16_t)((ITERW) >> 32); \ - if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ - { \ - (RESULT) &= 0xffff; \ - if ((RESULT) == 0xffff) \ - (RESULT) = 0; \ - else if ((RESULT) == 0x100) \ - (RESULT) = 0xff; \ - (RESULT) &= 0xff; \ - } \ - else \ - { \ - CLAMP((RESULT), 0, 0xff); \ - } \ -} \ -while (0) - - - -/************************************* - * - * Chroma keying macro - * - *************************************/ - -#define APPLY_CHROMAKEY(VV, STATS, FBZMODE, COLOR) \ -do \ -{ \ - if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE)) \ - { \ - /* non-range version */ \ - if (!CHROMARANGE_ENABLE((VV)->reg[chromaRange].u)) \ - { \ - if (((COLOR.u ^ (VV)->reg[chromaKey].u) & 0xffffff) == 0) \ - { \ - (STATS)->chroma_fail++; \ - goto skipdrawdepth; \ - } \ - } \ - \ - /* tricky range version */ \ - else \ - { \ - int32_t low, high, test; \ - int results = 0; \ - \ - /* check blue */ \ - low = (VV)->reg[chromaKey].rgb.b; \ - high = (VV)->reg[chromaRange].rgb.b; \ - test = COLOR.rgb.b; \ - results = (test >= low && test <= high); \ - results ^= CHROMARANGE_BLUE_EXCLUSIVE((VV)->reg[chromaRange].u); \ - results <<= 1; \ - \ - /* check green */ \ - low = (VV)->reg[chromaKey].rgb.g; \ - high = (VV)->reg[chromaRange].rgb.g; \ - test = COLOR.rgb.g; \ - results |= (test >= low && test <= high); \ - results ^= CHROMARANGE_GREEN_EXCLUSIVE((VV)->reg[chromaRange].u); \ - results <<= 1; \ - \ - /* check red */ \ - low = (VV)->reg[chromaKey].rgb.r; \ - high = (VV)->reg[chromaRange].rgb.r; \ - test = COLOR.rgb.r; \ - results |= (test >= low && test <= high); \ - results ^= CHROMARANGE_RED_EXCLUSIVE((VV)->reg[chromaRange].u); \ - \ - /* final result */ \ - if (CHROMARANGE_UNION_MODE((VV)->reg[chromaRange].u)) \ - { \ - if (results != 0) \ - { \ - (STATS)->chroma_fail++; \ - goto skipdrawdepth; \ - } \ - } \ - else \ - { \ - if (results == 7) \ - { \ - (STATS)->chroma_fail++; \ - goto skipdrawdepth; \ - } \ - } \ - } \ - } \ -} \ -while (0) - -inline bool ATTR_FORCE_INLINE voodoo_device::chromaKeyTest(voodoo_device *vd, stats_block *stats, uint32_t fbzModeReg, rgbaint_t rgbaIntColor) -{ - { - rgb_union color; - color.u = rgbaIntColor.to_rgba(); - /* non-range version */ - if (!CHROMARANGE_ENABLE(vd->reg[chromaRange].u)) - { - if (((color.u ^ vd->reg[chromaKey].u) & 0xffffff) == 0) - { - stats->chroma_fail++; - return false; - } - } - - /* tricky range version */ - else - { - int32_t low, high, test; - int results; - - /* check blue */ - low = vd->reg[chromaKey].rgb.b; - high = vd->reg[chromaRange].rgb.b; - test = color.rgb.b; - results = (test >= low && test <= high); - results ^= CHROMARANGE_BLUE_EXCLUSIVE(vd->reg[chromaRange].u); - results <<= 1; - - /* check green */ - low = vd->reg[chromaKey].rgb.g; - high = vd->reg[chromaRange].rgb.g; - test = color.rgb.g; - results |= (test >= low && test <= high); - results ^= CHROMARANGE_GREEN_EXCLUSIVE(vd->reg[chromaRange].u); - results <<= 1; - - /* check red */ - low = vd->reg[chromaKey].rgb.r; - high = vd->reg[chromaRange].rgb.r; - test = color.rgb.r; - results |= (test >= low && test <= high); - results ^= CHROMARANGE_RED_EXCLUSIVE(vd->reg[chromaRange].u); - - /* final result */ - if (CHROMARANGE_UNION_MODE(vd->reg[chromaRange].u)) - { - if (results != 0) - { - stats->chroma_fail++; - return false; - } - } - else - { - if (results == 7) - { - stats->chroma_fail++; - return false; - } - } - } - } - return true; -} - - - -/************************************* - * - * Alpha masking macro - * - *************************************/ - -#define APPLY_ALPHAMASK(VV, STATS, FBZMODE, AA) \ -do \ -{ \ - if (FBZMODE_ENABLE_ALPHA_MASK(FBZMODE)) \ - { \ - if (((AA) & 1) == 0) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - } \ -} \ -while (0) - -inline bool voodoo_device::alphaMaskTest(stats_block *stats, uint32_t fbzModeReg, uint8_t alpha) -{ - { - if ((alpha & 1) == 0) - { - stats->afunc_fail++; - return false; - } - } - return true; -} - -/************************************* - * - * Alpha testing macro - * - *************************************/ - -#define APPLY_ALPHATEST(VV, STATS, ALPHAMODE, AA) \ -do \ -{ \ - if (ALPHAMODE_ALPHATEST(ALPHAMODE)) \ - { \ - uint8_t alpharef = (VV)->reg[alphaMode].rgb.a; \ - switch (ALPHAMODE_ALPHAFUNCTION(ALPHAMODE)) \ - { \ - case 0: /* alphaOP = never */ \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - \ - case 1: /* alphaOP = less than */ \ - if ((AA) >= alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 2: /* alphaOP = equal */ \ - if ((AA) != alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 3: /* alphaOP = less than or equal */ \ - if ((AA) > alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 4: /* alphaOP = greater than */ \ - if ((AA) <= alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 5: /* alphaOP = not equal */ \ - if ((AA) == alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 6: /* alphaOP = greater than or equal */ \ - if ((AA) < alpharef) \ - { \ - (STATS)->afunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 7: /* alphaOP = always */ \ - break; \ - } \ - } \ -} \ -while (0) - -inline bool ATTR_FORCE_INLINE voodoo_device::alphaTest(uint8_t alpharef, stats_block *stats, uint32_t alphaModeReg, uint8_t alpha) -{ - { - switch (ALPHAMODE_ALPHAFUNCTION(alphaModeReg)) - { - case 0: /* alphaOP = never */ - stats->afunc_fail++; - return false; - - case 1: /* alphaOP = less than */ - if (alpha >= alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 2: /* alphaOP = equal */ - if (alpha != alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 3: /* alphaOP = less than or equal */ - if (alpha > alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 4: /* alphaOP = greater than */ - if (alpha <= alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 5: /* alphaOP = not equal */ - if (alpha == alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 6: /* alphaOP = greater than or equal */ - if (alpha < alpharef) - { - stats->afunc_fail++; - return false; - } - break; - - case 7: /* alphaOP = always */ - break; - } - } - return true; -} - - -/************************************* - * - * Alpha blending macro - * - *************************************/ - -#define APPLY_ALPHA_BLEND(FBZMODE, ALPHAMODE, XX, DITHER, RR, GG, BB, AA) \ -do \ -{ \ - if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) \ - { \ - int dpix = dest[XX]; \ - int dr, dg, db; \ - EXTRACT_565_TO_888(dpix, dr, dg, db); \ - int da = FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) ? depth[XX] : 0xff; \ - int sr = (RR); \ - int sg = (GG); \ - int sb = (BB); \ - int sa = (AA); \ - int ta; \ - \ - /* apply dither subtraction */ \ - if (FBZMODE_ALPHA_DITHER_SUBTRACT(FBZMODE)) \ - { \ - /* look up the dither value from the appropriate matrix */ \ - int dith = DITHER[(XX) & 3]; \ - \ - /* subtract the dither value */ \ - dr = ((dr << 1) + 15 - dith) >> 1; \ - dg = ((dg << 2) + 15 - dith) >> 2; \ - db = ((db << 1) + 15 - dith) >> 1; \ - } \ - \ - /* compute source portion */ \ - switch (ALPHAMODE_SRCRGBBLEND(ALPHAMODE)) \ - { \ - default: /* reserved */ \ - case 0: /* AZERO */ \ - (RR) = (GG) = (BB) = 0; \ - break; \ - \ - case 1: /* ASRC_ALPHA */ \ - (RR) = (sr * (sa + 1)) >> 8; \ - (GG) = (sg * (sa + 1)) >> 8; \ - (BB) = (sb * (sa + 1)) >> 8; \ - break; \ - \ - case 2: /* A_COLOR */ \ - (RR) = (sr * (dr + 1)) >> 8; \ - (GG) = (sg * (dg + 1)) >> 8; \ - (BB) = (sb * (db + 1)) >> 8; \ - break; \ - \ - case 3: /* ADST_ALPHA */ \ - (RR) = (sr * (da + 1)) >> 8; \ - (GG) = (sg * (da + 1)) >> 8; \ - (BB) = (sb * (da + 1)) >> 8; \ - break; \ - \ - case 4: /* AONE */ \ - break; \ - \ - case 5: /* AOMSRC_ALPHA */ \ - (RR) = (sr * (0x100 - sa)) >> 8; \ - (GG) = (sg * (0x100 - sa)) >> 8; \ - (BB) = (sb * (0x100 - sa)) >> 8; \ - break; \ - \ - case 6: /* AOM_COLOR */ \ - (RR) = (sr * (0x100 - dr)) >> 8; \ - (GG) = (sg * (0x100 - dg)) >> 8; \ - (BB) = (sb * (0x100 - db)) >> 8; \ - break; \ - \ - case 7: /* AOMDST_ALPHA */ \ - (RR) = (sr * (0x100 - da)) >> 8; \ - (GG) = (sg * (0x100 - da)) >> 8; \ - (BB) = (sb * (0x100 - da)) >> 8; \ - break; \ - \ - case 15: /* ASATURATE */ \ - ta = (sa < (0x100 - da)) ? sa : (0x100 - da); \ - (RR) = (sr * (ta + 1)) >> 8; \ - (GG) = (sg * (ta + 1)) >> 8; \ - (BB) = (sb * (ta + 1)) >> 8; \ - break; \ - } \ - \ - /* add in dest portion */ \ - switch (ALPHAMODE_DSTRGBBLEND(ALPHAMODE)) \ - { \ - default: /* reserved */ \ - case 0: /* AZERO */ \ - break; \ - \ - case 1: /* ASRC_ALPHA */ \ - (RR) += (dr * (sa + 1)) >> 8; \ - (GG) += (dg * (sa + 1)) >> 8; \ - (BB) += (db * (sa + 1)) >> 8; \ - break; \ - \ - case 2: /* A_COLOR */ \ - (RR) += (dr * (sr + 1)) >> 8; \ - (GG) += (dg * (sg + 1)) >> 8; \ - (BB) += (db * (sb + 1)) >> 8; \ - break; \ - \ - case 3: /* ADST_ALPHA */ \ - (RR) += (dr * (da + 1)) >> 8; \ - (GG) += (dg * (da + 1)) >> 8; \ - (BB) += (db * (da + 1)) >> 8; \ - break; \ - \ - case 4: /* AONE */ \ - (RR) += dr; \ - (GG) += dg; \ - (BB) += db; \ - break; \ - \ - case 5: /* AOMSRC_ALPHA */ \ - (RR) += (dr * (0x100 - sa)) >> 8; \ - (GG) += (dg * (0x100 - sa)) >> 8; \ - (BB) += (db * (0x100 - sa)) >> 8; \ - break; \ - \ - case 6: /* AOM_COLOR */ \ - (RR) += (dr * (0x100 - sr)) >> 8; \ - (GG) += (dg * (0x100 - sg)) >> 8; \ - (BB) += (db * (0x100 - sb)) >> 8; \ - break; \ - \ - case 7: /* AOMDST_ALPHA */ \ - (RR) += (dr * (0x100 - da)) >> 8; \ - (GG) += (dg * (0x100 - da)) >> 8; \ - (BB) += (db * (0x100 - da)) >> 8; \ - break; \ - \ - case 15: /* A_COLORBEFOREFOG */ \ - (RR) += (dr * (prefogr + 1)) >> 8; \ - (GG) += (dg * (prefogg + 1)) >> 8; \ - (BB) += (db * (prefogb + 1)) >> 8; \ - break; \ - } \ - \ - /* blend the source alpha */ \ - (AA) = 0; \ - if (ALPHAMODE_SRCALPHABLEND(ALPHAMODE) == 4) \ - (AA) = sa; \ - \ - /* blend the dest alpha */ \ - if (ALPHAMODE_DSTALPHABLEND(ALPHAMODE) == 4) \ - (AA) += da; \ - \ - /* clamp */ \ - CLAMP((RR), 0x00, 0xff); \ - CLAMP((GG), 0x00, 0xff); \ - CLAMP((BB), 0x00, 0xff); \ - CLAMP((AA), 0x00, 0xff); \ - } \ -} \ -while (0) - -static inline void ATTR_FORCE_INLINE alphaBlend(uint32_t FBZMODE, uint32_t ALPHAMODE, int32_t x, const uint8_t *dither, int dpix, uint16_t *depth, rgbaint_t &preFog, rgbaint_t &srcColor, rgb_t *convTable) -{ - { - //int dpix = dest[XX]; - int dr, dg, db; - //EXTRACT_565_TO_888(dpix, dr, dg, db); - rgb_t drgb = convTable[dpix]; - drgb.expand_rgb(dr, dg, db); - int da = FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) ? depth[x] : 0xff; - //int sr = (RR); - //int sg = (GG); - //int sb = (BB); - //int sa = (AA); - int sa = srcColor.get_a(); - int ta; - int srcAlphaScale, destAlphaScale; - rgbaint_t srcScale, destScale; - - /* apply dither subtraction */ - if (FBZMODE_ALPHA_DITHER_SUBTRACT(FBZMODE)) - { - /* look up the dither value from the appropriate matrix */ - int dith = dither[x & 3]; - - /* subtract the dither value */ - dr += dith; - db += dith; - dg += dith >> 1; - } - - /* blend the source alpha */ - if (ALPHAMODE_SRCALPHABLEND(ALPHAMODE) == 4) - srcAlphaScale = 256; - //(AA) = sa; - else - srcAlphaScale = 0; - - /* compute source portion */ - switch (ALPHAMODE_SRCRGBBLEND(ALPHAMODE)) - { - default: /* reserved */ - case 0: /* AZERO */ - srcScale.zero(); - //(RR) = (GG) = (BB) = 0; - break; - - case 1: /* ASRC_ALPHA */ - ta = sa + 1; - srcScale.set_all(ta); - //(RR) = (sr * (sa + 1)) >> 8; - //(GG) = (sg * (sa + 1)) >> 8; - //(BB) = (sb * (sa + 1)) >> 8; - break; - - case 2: /* A_COLOR */ - srcScale.set(dr, dr, dg, db); - srcScale.add_imm(1); - //(RR) = (sr * (dr + 1)) >> 8; - //(GG) = (sg * (dg + 1)) >> 8; - //(BB) = (sb * (db + 1)) >> 8; - break; - - case 3: /* ADST_ALPHA */ - ta = da + 1; - srcScale.set_all(ta); - //(RR) = (sr * (da + 1)) >> 8; - //(GG) = (sg * (da + 1)) >> 8; - //(BB) = (sb * (da + 1)) >> 8; - break; - - case 4: /* AONE */ - srcScale.set_all(256); - break; - - case 5: /* AOMSRC_ALPHA */ - ta = (0x100 - sa); - srcScale.set_all(ta); - //(RR) = (sr * (0x100 - sa)) >> 8; - //(GG) = (sg * (0x100 - sa)) >> 8; - //(BB) = (sb * (0x100 - sa)) >> 8; - break; - - case 6: /* AOM_COLOR */ - srcScale.set((0x100 - dr), (0x100 - dr), (0x100 - dg), (0x100 - db)); - //(RR) = (sr * (0x100 - dr)) >> 8; - //(GG) = (sg * (0x100 - dg)) >> 8; - //(BB) = (sb * (0x100 - db)) >> 8; - break; - - case 7: /* AOMDST_ALPHA */ - ta = (0x100 - da); - srcScale.set_all(ta); - //(RR) = (sr * (0x100 - da)) >> 8; - //(GG) = (sg * (0x100 - da)) >> 8; - //(BB) = (sb * (0x100 - da)) >> 8; - break; - - case 15: /* ASATURATE */ - ta = (sa < (0x100 - da)) ? sa : (0x100 - da); - ta++; - srcScale.set_all(ta); - //(RR) = (sr * (ta + 1)) >> 8; - //(GG) = (sg * (ta + 1)) >> 8; - //(BB) = (sb * (ta + 1)) >> 8; - break; - } - // Set srcScale alpha - srcScale.set_a16(srcAlphaScale); - - /* blend the dest alpha */ - if (ALPHAMODE_DSTALPHABLEND(ALPHAMODE) == 4) - destAlphaScale = 256; - //(AA) += da; - else - destAlphaScale = 0; - - /* add in dest portion */ - switch (ALPHAMODE_DSTRGBBLEND(ALPHAMODE)) - { - default: /* reserved */ - case 0: /* AZERO */ - destScale.zero(); - break; - - case 1: /* ASRC_ALPHA */ - ta = sa + 1; - destScale.set_all(ta); - //(RR) += (dr * (sa + 1)) >> 8; - //(GG) += (dg * (sa + 1)) >> 8; - //(BB) += (db * (sa + 1)) >> 8; - break; - - case 2: /* A_COLOR */ - destScale.set(srcColor); - destScale.add_imm(1); - //(RR) += (dr * (sr + 1)) >> 8; - //(GG) += (dg * (sg + 1)) >> 8; - //(BB) += (db * (sb + 1)) >> 8; - break; - - case 3: /* ADST_ALPHA */ - ta = da + 1; - destScale.set_all(ta); - //(RR) += (dr * (da + 1)) >> 8; - //(GG) += (dg * (da + 1)) >> 8; - //(BB) += (db * (da + 1)) >> 8; - break; - - case 4: /* AONE */ - destScale.set_all(256); - //(RR) += dr; - //(GG) += dg; - //(BB) += db; - break; - - case 5: /* AOMSRC_ALPHA */ - ta = (0x100 - sa); - destScale.set_all(ta); - //(RR) += (dr * (0x100 - sa)) >> 8; - //(GG) += (dg * (0x100 - sa)) >> 8; - //(BB) += (db * (0x100 - sa)) >> 8; - break; - - case 6: /* AOM_COLOR */ - destScale.set_all(0x100); - destScale.sub(srcColor); - //destScale.set(destAlphaScale, (0x100 - color.rgb.r), (0x100 - color.rgb.g), (0x100 - color.rgb.b)); - //(RR) += (dr * (0x100 - sr)) >> 8; - //(GG) += (dg * (0x100 - sg)) >> 8; - //(BB) += (db * (0x100 - sb)) >> 8; - break; - - case 7: /* AOMDST_ALPHA */ - ta = (0x100 - da); - destScale.set_all(ta); - //(RR) += (dr * (0x100 - da)) >> 8; - //(GG) += (dg * (0x100 - da)) >> 8; - //(BB) += (db * (0x100 - da)) >> 8; - break; - - case 15: /* A_COLORBEFOREFOG */ - destScale.set(preFog); - destScale.add_imm(1); - //(RR) += (dr * (prefogr + 1)) >> 8; - //(GG) += (dg * (prefogg + 1)) >> 8; - //(BB) += (db * (prefogb + 1)) >> 8; - break; - } - - // Set destScale alpha - destScale.set_a16(destAlphaScale); - - // Main blend - rgbaint_t destColor(da, dr, dg, db); - - srcColor.scale2_add_and_clamp(srcScale, destColor, destScale); - /* clamp */ - //CLAMP((RR), 0x00, 0xff); - //CLAMP((GG), 0x00, 0xff); - //CLAMP((BB), 0x00, 0xff); - //CLAMP((AA), 0x00, 0xff); - } -} - - -/************************************* - * - * Fogging macro - * - *************************************/ - -#define APPLY_FOGGING(VV, FOGMODE, FBZCP, XX, DITHER4, RR, GG, BB, ITERZ, ITERW, ITERAXXX) \ -do \ -{ \ - if (FOGMODE_ENABLE_FOG(FOGMODE)) \ - { \ - rgb_union fogcolor = (VV)->reg[fogColor]; \ - int32_t fr, fg, fb; \ - \ - /* constant fog bypasses everything else */ \ - if (FOGMODE_FOG_CONSTANT(FOGMODE)) \ - { \ - fr = fogcolor.rgb.r; \ - fg = fogcolor.rgb.g; \ - fb = fogcolor.rgb.b; \ - } \ - \ - /* non-constant fog comes from several sources */ \ - else \ - { \ - int32_t fogblend = 0; \ - \ - /* if fog_add is zero, we start with the fog color */ \ - if (FOGMODE_FOG_ADD(FOGMODE) == 0) \ - { \ - fr = fogcolor.rgb.r; \ - fg = fogcolor.rgb.g; \ - fb = fogcolor.rgb.b; \ - } \ - else \ - fr = fg = fb = 0; \ - \ - /* if fog_mult is zero, we subtract the incoming color */ \ - if (FOGMODE_FOG_MULT(FOGMODE) == 0) \ - { \ - fr -= (RR); \ - fg -= (GG); \ - fb -= (BB); \ - } \ - \ - /* fog blending mode */ \ - switch (FOGMODE_FOG_ZALPHA(FOGMODE)) \ - { \ - case 0: /* fog table */ \ - { \ - int32_t delta = (VV)->fbi.fogdelta[fogdepth >> 10]; \ - int32_t deltaval; \ - \ - /* perform the multiply against lower 8 bits of wfloat */ \ - deltaval = (delta & (VV)->fbi.fogdelta_mask) * \ - ((fogdepth >> 2) & 0xff); \ - \ - /* fog zones allow for negating this value */ \ - if (FOGMODE_FOG_ZONES(FOGMODE) && (delta & 2)) \ - deltaval = -deltaval; \ - deltaval >>= 6; \ - \ - /* apply dither */ \ - if (FOGMODE_FOG_DITHER(FOGMODE)) \ - deltaval += DITHER4[(XX) & 3]; \ - deltaval >>= 4; \ - \ - /* add to the blending factor */ \ - fogblend = (VV)->fbi.fogblend[fogdepth >> 10] + deltaval; \ - break; \ - } \ - \ - case 1: /* iterated A */ \ - fogblend = ITERAXXX.rgb.a; \ - break; \ - \ - case 2: /* iterated Z */ \ - CLAMPED_Z((ITERZ), FBZCP, fogblend); \ - fogblend >>= 8; \ - break; \ - \ - case 3: /* iterated W - Voodoo 2 only */ \ - CLAMPED_W((ITERW), FBZCP, fogblend); \ - break; \ - } \ - \ - /* perform the blend */ \ - fogblend++; \ - fr = (fr * fogblend) >> 8; \ - fg = (fg * fogblend) >> 8; \ - fb = (fb * fogblend) >> 8; \ - } \ - \ - /* if fog_mult is 0, we add this to the original color */ \ - if (FOGMODE_FOG_MULT(FOGMODE) == 0) \ - { \ - (RR) += fr; \ - (GG) += fg; \ - (BB) += fb; \ - } \ - \ - /* otherwise this just becomes the new color */ \ - else \ - { \ - (RR) = fr; \ - (GG) = fg; \ - (BB) = fb; \ - } \ - \ - /* clamp */ \ - CLAMP((RR), 0x00, 0xff); \ - CLAMP((GG), 0x00, 0xff); \ - CLAMP((BB), 0x00, 0xff); \ - } \ -} \ -while (0) - -static inline void ATTR_FORCE_INLINE applyFogging(voodoo_device *vd, uint32_t fbzModeReg, uint32_t fogModeReg, uint32_t fbzCpReg, int32_t x, const uint8_t *dither4, int32_t wFloat, - rgbaint_t &color, int32_t iterz, int64_t iterw, const rgbaint_t &iterargb) -{ - { - /* constant fog bypasses everything else */ - rgbaint_t fogColorLocal(vd->reg[fogColor].u); - - if (FOGMODE_FOG_CONSTANT(fogModeReg)) - { - /* if fog_mult is 0, we add this to the original color */ - if (FOGMODE_FOG_MULT(fogModeReg) == 0) - { - fogColorLocal.add(color); - fogColorLocal.clamp_to_uint8(); - //color += fog; - } - - /* otherwise this just becomes the new color */ - else - { - //color = fogColorLocal; - //color = fog; - } - } - /* non-constant fog comes from several sources */ - else - { - int32_t fogblend = 0; - - /* if fog_add is zero, we start with the fog color */ - if (FOGMODE_FOG_ADD(fogModeReg)) - fogColorLocal.zero(); - //fr = fg = fb = 0; - - /* if fog_mult is zero, we subtract the incoming color */ - if (!FOGMODE_FOG_MULT(fogModeReg)) - { - // Need to check this, manual states 9 bits - fogColorLocal.sub(color); - //fog.rgb -= color.rgb; - //fr -= (RR); - //fg -= (GG); - //fb -= (BB); - } - - /* fog blending mode */ - switch (FOGMODE_FOG_ZALPHA(fogModeReg)) - { - case 0: /* fog table */ - { - int32_t fogDepth = wFloat; - /* add the bias for fog selection*/ - if (FBZMODE_ENABLE_DEPTH_BIAS(fbzModeReg)) - { - fogDepth += (int16_t)vd->reg[zaColor].u; - CLAMP(fogDepth, 0, 0xffff); - } - int32_t delta = vd->fbi.fogdelta[fogDepth >> 10]; - int32_t deltaval; - - /* perform the multiply against lower 8 bits of wfloat */ - deltaval = (delta & vd->fbi.fogdelta_mask) * - ((fogDepth >> 2) & 0xff); - - /* fog zones allow for negating this value */ - if (FOGMODE_FOG_ZONES(fogModeReg) && (delta & 2)) - deltaval = -deltaval; - deltaval >>= 6; - - /* apply dither */ - if (FOGMODE_FOG_DITHER(fogModeReg)) - deltaval += dither4[x&3]; - deltaval >>= 4; - - /* add to the blending factor */ - fogblend = vd->fbi.fogblend[fogDepth >> 10] + deltaval; - break; - } - - case 1: /* iterated A */ - fogblend = iterargb.get_a(); - break; - - case 2: /* iterated Z */ - CLAMPED_Z(iterz, fbzCpReg, fogblend); - fogblend >>= 8; - break; - - case 3: /* iterated W - Voodoo 2 only */ - CLAMPED_W(iterw, fbzCpReg, fogblend); - break; - } - - /* perform the blend */ - fogblend++; - - //fr = (fr * fogblend) >> 8; - //fg = (fg * fogblend) >> 8; - //fb = (fb * fogblend) >> 8; - /* if fog_mult is 0, we add this to the original color */ - fogColorLocal.scale_imm_and_clamp((int16_t)fogblend); - if (FOGMODE_FOG_MULT(fogModeReg) == 0) - { - fogColorLocal.add(color); - fogColorLocal.clamp_to_uint8(); - //color += fog; - //(RR) += fr; - //(GG) += fg; - //(BB) += fb; - } - - /* otherwise this just becomes the new color */ - else - { - //color = fog; - //(RR) = fr; - //(GG) = fg; - //(BB) = fb; - } - } - - - /* clamp */ - //CLAMP((RR), 0x00, 0xff); - //CLAMP((GG), 0x00, 0xff); - //CLAMP((BB), 0x00, 0xff); - fogColorLocal.merge_alpha16(color); - color.set(fogColorLocal); - } -} - - -/************************************* - * - * Texture pipeline macro - * - *************************************/ - -#define TEXTURE_PIPELINE(TT, XX, DITHER4, TEXMODE, COTHER, LOOKUP, LODBASE, ITERS, ITERT, ITERW, RESULT) \ -do \ -{ \ - int32_t blendr, blendg, blendb, blenda; \ - int32_t tr, tg, tb, ta; \ - int32_t s, t, lod, ilod; \ - int32_t smax, tmax; \ - uint32_t texbase; \ - rgb_union c_local; \ - \ - /* determine the S/T/LOD values for this texture */ \ - if (TEXMODE_ENABLE_PERSPECTIVE(TEXMODE)) \ - { \ - if (USE_FAST_RECIP) { \ - const int32_t oow = fast_reciplog((ITERW), &lod); \ - s = ((int64_t)oow * (ITERS)) >> 29; \ - t = ((int64_t)oow * (ITERT)) >> 29; \ - } else { \ - multi_reciplog(ITERS, ITERT, ITERW, lod, s, t); \ - } \ - lod += (LODBASE); \ - } \ - else \ - { \ - s = (ITERS) >> 14; \ - t = (ITERT) >> 14; \ - lod = (LODBASE); \ - } \ - \ - /* clamp W */ \ - if (TEXMODE_CLAMP_NEG_W(TEXMODE) && (ITERW) < 0) \ - s = t = 0; \ - \ - /* clamp the LOD */ \ - lod += (TT)->lodbias; \ - if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE)) \ - lod += DITHER4[(XX) & 3] << 4; \ - if (lod < (TT)->lodmin) \ - lod = (TT)->lodmin; \ - if (lod > (TT)->lodmax) \ - lod = (TT)->lodmax; \ - \ - /* now the LOD is in range; if we don't own this LOD, take the next one */ \ - ilod = lod >> 8; \ - if (!(((TT)->lodmask >> ilod) & 1)) \ - ilod++; \ - \ - /* fetch the texture base */ \ - texbase = (TT)->lodoffset[ilod]; \ - \ - /* compute the maximum s and t values at this LOD */ \ - smax = (TT)->wmask >> ilod; \ - tmax = (TT)->hmask >> ilod; \ - \ - /* determine whether we are point-sampled or bilinear */ \ - if ((lod == (TT)->lodmin && !TEXMODE_MAGNIFICATION_FILTER(TEXMODE)) || \ - (lod != (TT)->lodmin && !TEXMODE_MINIFICATION_FILTER(TEXMODE))) \ - { \ - /* point sampled */ \ - \ - uint32_t texel0; \ - \ - /* adjust S/T for the LOD and strip off the fractions */ \ - s >>= ilod + 18; \ - t >>= ilod + 18; \ - \ - /* clamp/wrap S/T if necessary */ \ - if (TEXMODE_CLAMP_S(TEXMODE)) \ - CLAMP(s, 0, smax); \ - if (TEXMODE_CLAMP_T(TEXMODE)) \ - CLAMP(t, 0, tmax); \ - s &= smax; \ - t &= tmax; \ - t *= smax + 1; \ - \ - /* fetch texel data */ \ - if (TEXMODE_FORMAT(TEXMODE) < 8) \ - { \ - texel0 = *(uint8_t *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \ - c_local.u = (LOOKUP)[texel0]; \ - } \ - else \ - { \ - texel0 = *(uint16_t *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \ - if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \ - c_local.u = (LOOKUP)[texel0]; \ - else \ - c_local.u = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \ - ((texel0 & 0xff00) << 16); \ - } \ - } \ - else \ - { \ - /* bilinear filtered */ \ - \ - uint32_t texel0, texel1, texel2, texel3; \ - uint32_t sfrac, tfrac; \ - int32_t s1, t1; \ - \ - /* adjust S/T for the LOD and strip off all but the low 8 bits of */ \ - /* the fraction */ \ - s >>= ilod + 10; \ - t >>= ilod + 10; \ - \ - /* also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel */ \ - s -= 0x80; \ - t -= 0x80; \ - \ - /* extract the fractions */ \ - sfrac = s & (TT)->bilinear_mask; \ - tfrac = t & (TT)->bilinear_mask; \ - \ - /* now toss the rest */ \ - s >>= 8; \ - t >>= 8; \ - s1 = s + 1; \ - t1 = t + 1; \ - \ - /* clamp/wrap S/T if necessary */ \ - if (TEXMODE_CLAMP_S(TEXMODE)) \ - { \ - CLAMP(s, 0, smax); \ - CLAMP(s1, 0, smax); \ - } \ - if (TEXMODE_CLAMP_T(TEXMODE)) \ - { \ - CLAMP(t, 0, tmax); \ - CLAMP(t1, 0, tmax); \ - } \ - s &= smax; \ - s1 &= smax; \ - t &= tmax; \ - t1 &= tmax; \ - t *= smax + 1; \ - t1 *= smax + 1; \ - \ - /* fetch texel data */ \ - if (TEXMODE_FORMAT(TEXMODE) < 8) \ - { \ - texel0 = *(uint8_t *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \ - texel1 = *(uint8_t *)&(TT)->ram[(texbase + t + s1) & (TT)->mask]; \ - texel2 = *(uint8_t *)&(TT)->ram[(texbase + t1 + s) & (TT)->mask]; \ - texel3 = *(uint8_t *)&(TT)->ram[(texbase + t1 + s1) & (TT)->mask]; \ - texel0 = (LOOKUP)[texel0]; \ - texel1 = (LOOKUP)[texel1]; \ - texel2 = (LOOKUP)[texel2]; \ - texel3 = (LOOKUP)[texel3]; \ - } \ - else \ - { \ - texel0 = *(uint16_t *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \ - texel1 = *(uint16_t *)&(TT)->ram[(texbase + 2*(t + s1)) & (TT)->mask];\ - texel2 = *(uint16_t *)&(TT)->ram[(texbase + 2*(t1 + s)) & (TT)->mask];\ - texel3 = *(uint16_t *)&(TT)->ram[(texbase + 2*(t1 + s1)) & (TT)->mask];\ - if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \ - { \ - texel0 = (LOOKUP)[texel0]; \ - texel1 = (LOOKUP)[texel1]; \ - texel2 = (LOOKUP)[texel2]; \ - texel3 = (LOOKUP)[texel3]; \ - } \ - else \ - { \ - texel0 = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \ - ((texel0 & 0xff00) << 16); \ - texel1 = ((LOOKUP)[texel1 & 0xff] & 0xffffff) | \ - ((texel1 & 0xff00) << 16); \ - texel2 = ((LOOKUP)[texel2 & 0xff] & 0xffffff) | \ - ((texel2 & 0xff00) << 16); \ - texel3 = ((LOOKUP)[texel3 & 0xff] & 0xffffff) | \ - ((texel3 & 0xff00) << 16); \ - } \ - } \ - \ - /* weigh in each texel */ \ - c_local.u = rgbaint_t::bilinear_filter(texel0, texel1, texel2, texel3, sfrac, tfrac); \ - } \ - \ - /* select zero/other for RGB */ \ - if (!TEXMODE_TC_ZERO_OTHER(TEXMODE)) \ - { \ - tr = COTHER.rgb.r; \ - tg = COTHER.rgb.g; \ - tb = COTHER.rgb.b; \ - } \ - else \ - tr = tg = tb = 0; \ - \ - /* select zero/other for alpha */ \ - if (!TEXMODE_TCA_ZERO_OTHER(TEXMODE)) \ - ta = COTHER.rgb.a; \ - else \ - ta = 0; \ - \ - /* potentially subtract c_local */ \ - if (TEXMODE_TC_SUB_CLOCAL(TEXMODE)) \ - { \ - tr -= c_local.rgb.r; \ - tg -= c_local.rgb.g; \ - tb -= c_local.rgb.b; \ - } \ - if (TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) \ - ta -= c_local.rgb.a; \ - \ - /* blend RGB */ \ - switch (TEXMODE_TC_MSELECT(TEXMODE)) \ - { \ - default: /* reserved */ \ - case 0: /* zero */ \ - blendr = blendg = blendb = 0; \ - break; \ - \ - case 1: /* c_local */ \ - blendr = c_local.rgb.r; \ - blendg = c_local.rgb.g; \ - blendb = c_local.rgb.b; \ - break; \ - \ - case 2: /* a_other */ \ - blendr = blendg = blendb = COTHER.rgb.a; \ - break; \ - \ - case 3: /* a_local */ \ - blendr = blendg = blendb = c_local.rgb.a; \ - break; \ - \ - case 4: /* LOD (detail factor) */ \ - if ((TT)->detailbias <= lod) \ - blendr = blendg = blendb = 0; \ - else \ - { \ - blendr = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\ - if (blendr > (TT)->detailmax) \ - blendr = (TT)->detailmax; \ - blendg = blendb = blendr; \ - } \ - break; \ - \ - case 5: /* LOD fraction */ \ - blendr = blendg = blendb = lod & 0xff; \ - break; \ - } \ - \ - /* blend alpha */ \ - switch (TEXMODE_TCA_MSELECT(TEXMODE)) \ - { \ - default: /* reserved */ \ - case 0: /* zero */ \ - blenda = 0; \ - break; \ - \ - case 1: /* c_local */ \ - blenda = c_local.rgb.a; \ - break; \ - \ - case 2: /* a_other */ \ - blenda = COTHER.rgb.a; \ - break; \ - \ - case 3: /* a_local */ \ - blenda = c_local.rgb.a; \ - break; \ - \ - case 4: /* LOD (detail factor) */ \ - if ((TT)->detailbias <= lod) \ - blenda = 0; \ - else \ - { \ - blenda = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\ - if (blenda > (TT)->detailmax) \ - blenda = (TT)->detailmax; \ - } \ - break; \ - \ - case 5: /* LOD fraction */ \ - blenda = lod & 0xff; \ - break; \ - } \ - \ - /* reverse the RGB blend */ \ - if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE)) \ - { \ - blendr ^= 0xff; \ - blendg ^= 0xff; \ - blendb ^= 0xff; \ - } \ - \ - /* reverse the alpha blend */ \ - if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE)) \ - blenda ^= 0xff; \ - \ - /* do the blend */ \ - tr = (tr * (blendr + 1)) >> 8; \ - tg = (tg * (blendg + 1)) >> 8; \ - tb = (tb * (blendb + 1)) >> 8; \ - ta = (ta * (blenda + 1)) >> 8; \ - \ - /* add clocal or alocal to RGB */ \ - switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE)) \ - { \ - case 3: /* reserved */ \ - case 0: /* nothing */ \ - break; \ - \ - case 1: /* add c_local */ \ - tr += c_local.rgb.r; \ - tg += c_local.rgb.g; \ - tb += c_local.rgb.b; \ - break; \ - \ - case 2: /* add_alocal */ \ - tr += c_local.rgb.a; \ - tg += c_local.rgb.a; \ - tb += c_local.rgb.a; \ - break; \ - } \ - \ - /* add clocal or alocal to alpha */ \ - if (TEXMODE_TCA_ADD_ACLOCAL(TEXMODE)) \ - ta += c_local.rgb.a; \ - \ - /* clamp */ \ - RESULT.rgb.r = (tr < 0) ? 0 : (tr > 0xff) ? 0xff : tr; \ - RESULT.rgb.g = (tg < 0) ? 0 : (tg > 0xff) ? 0xff : tg; \ - RESULT.rgb.b = (tb < 0) ? 0 : (tb > 0xff) ? 0xff : tb; \ - RESULT.rgb.a = (ta < 0) ? 0 : (ta > 0xff) ? 0xff : ta; \ - \ - /* invert */ \ - if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE)) \ - RESULT.u ^= 0x00ffffff; \ - if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE)) \ - RESULT.rgb.a ^= 0xff; \ -} \ -while (0) - - - -/************************************* - * - * Pixel pipeline macros - * - *************************************/ - -#define PIXEL_PIPELINE_BEGIN(vd, STATS, XX, YY, FBZCOLORPATH, FBZMODE, ITERZ, ITERW) \ -do \ -{ \ - int32_t depthval, wfloat, biasdepth; \ - int32_t r, g, b; \ - \ - (STATS)->pixels_in++; \ - \ - /* apply clipping */ \ - /* note that for perf reasons, we assume the caller has done clipping */ \ - \ - /* handle stippling */ \ - if (FBZMODE_ENABLE_STIPPLE(FBZMODE)) \ - { \ - /* rotate mode */ \ - if (FBZMODE_STIPPLE_PATTERN(FBZMODE) == 0) \ - { \ - vd->reg[stipple].u = (vd->reg[stipple].u << 1) | (vd->reg[stipple].u >> 31);\ - if ((vd->reg[stipple].u & 0x80000000) == 0) \ - { \ - vd->stats.total_stippled++; \ - goto skipdrawdepth; \ - } \ - } \ - \ - /* pattern mode */ \ - else \ - { \ - int stipple_index = (((YY) & 3) << 3) | (~(XX) & 7); \ - if (((vd->reg[stipple].u >> stipple_index) & 1) == 0) \ - { \ - vd->stats.total_stippled++; \ - goto skipdrawdepth; \ - } \ - } \ - } \ - \ - /* compute "floating point" W value (used for depth and fog) */ \ - if ((ITERW) & 0xffff00000000U) \ - wfloat = 0x0000; \ - else \ - { \ - uint32_t temp = (uint32_t)(ITERW); \ - if (!(temp & 0xffff0000)) \ - wfloat = 0xffff; \ - else \ - { \ - int exp = count_leading_zeros_32(temp); \ - wfloat = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \ - } \ - } \ - \ - /* compute depth value (W or Z) for this pixel */ \ - if (FBZMODE_WBUFFER_SELECT(FBZMODE)) \ - { \ - if (!FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE)) \ - depthval = wfloat; \ - else \ - { \ - if ((ITERZ) & 0xf0000000) \ - depthval = 0x0000; \ - else \ - { \ - uint32_t temp = (ITERZ << 4); \ - if (!(temp & 0xffff0000)) \ - depthval = 0xffff; \ - else \ - { \ - int exp = count_leading_zeros_32(temp); \ - depthval = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \ - } \ - } \ - } \ - } \ - else \ - { \ - CLAMPED_Z(ITERZ, FBZCOLORPATH, depthval); \ - } \ - /* add the bias */ \ - biasdepth = depthval; \ - if (FBZMODE_ENABLE_DEPTH_BIAS(FBZMODE)) \ - { \ - biasdepth += (int16_t)vd->reg[zaColor].u; \ - CLAMP(biasdepth, 0, 0xffff); \ - } - - -#define DEPTH_TEST(vd, STATS, XX, FBZMODE) \ -do \ -{ \ - /* handle depth buffer testing */ \ - if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) \ - { \ - int32_t depthsource; \ - \ - /* the source depth is either the iterated W/Z+bias or a */ \ - /* constant value */ \ - if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) == 0) \ - depthsource = biasdepth; \ - else \ - depthsource = (uint16_t)vd->reg[zaColor].u; \ - \ - /* test against the depth buffer */ \ - switch (FBZMODE_DEPTH_FUNCTION(FBZMODE)) \ - { \ - case 0: /* depthOP = never */ \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - \ - case 1: /* depthOP = less than */ \ - if (depthsource >= depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 2: /* depthOP = equal */ \ - if (depthsource != depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 3: /* depthOP = less than or equal */ \ - if (depthsource > depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 4: /* depthOP = greater than */ \ - if (depthsource <= depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 5: /* depthOP = not equal */ \ - if (depthsource == depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 6: /* depthOP = greater than or equal */ \ - if (depthsource < depth[XX]) \ - { \ - (STATS)->zfunc_fail++; \ - goto skipdrawdepth; \ - } \ - break; \ - \ - case 7: /* depthOP = always */ \ - break; \ - } \ - } \ -} \ -while (0) - -inline bool ATTR_FORCE_INLINE voodoo_device::depthTest(uint16_t zaColorReg, stats_block *stats, int32_t destDepth, uint32_t fbzModeReg, int32_t biasdepth) -{ - /* handle depth buffer testing */ - { - int32_t depthsource; - - /* the source depth is either the iterated W/Z+bias or a */ - /* constant value */ - if (FBZMODE_DEPTH_SOURCE_COMPARE(fbzModeReg) == 0) - depthsource = biasdepth; - else - depthsource = zaColorReg; - - /* test against the depth buffer */ - switch (FBZMODE_DEPTH_FUNCTION(fbzModeReg)) - { - case 0: /* depthOP = never */ - stats->zfunc_fail++; - return false; - - case 1: /* depthOP = less than */ - if (depthsource >= destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 2: /* depthOP = equal */ - if (depthsource != destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 3: /* depthOP = less than or equal */ - if (depthsource > destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 4: /* depthOP = greater than */ - if (depthsource <= destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 5: /* depthOP = not equal */ - if (depthsource == destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 6: /* depthOP = greater than or equal */ - if (depthsource < destDepth) - { - stats->zfunc_fail++; - return false; - } - break; - - case 7: /* depthOP = always */ - break; - } - } - return true; -} - -#define PIXEL_PIPELINE_END(STATS, DITHER_LOOKUP, XX, dest, depth, FBZMODE) \ - \ - r = color.get_r(); g = color.get_g(); b = color.get_b(); \ - /* modify the pixel for debugging purposes */ \ - MODIFY_PIXEL(VV); \ - \ - /* write to framebuffer */ \ - if (FBZMODE_RGB_BUFFER_MASK(FBZMODE)) \ - { \ - /* apply dithering */ \ - APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b); \ - dest[XX] = (r << 11) | (g << 5) | b; \ - } \ - \ - /* write to aux buffer */ \ - /*if (depth && FBZMODE_AUX_BUFFER_MASK(FBZMODE))*/ \ - if (FBZMODE_AUX_BUFFER_MASK(FBZMODE)) \ - { \ - if (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0) \ - depth[XX] = biasdepth; \ - else \ - depth[XX] = color.get_a(); \ - } \ - \ - /* track pixel writes to the frame buffer regardless of mask */ \ - (STATS)->pixels_out++; \ - \ -skipdrawdepth: \ - ; \ -} \ -while (0) - - - -/************************************* - * - * Colorpath pipeline macro - * - *************************************/ - -/* - - c_other_is_used: - - if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE) || - FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0) - - c_local_is_used: - - if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH) || - FBZCP_CC_MSELECT(FBZCOLORPATH) == 1 || - FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH) == 1) - - NEEDS_ITER_RGB: - - if ((c_other_is_used && FBZCP_CC_RGBSELECT(FBZCOLORPATH) == 0) || - (c_local_is_used && (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) != 0 || FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0)) - - NEEDS_ITER_A: - - if ((a_other_is_used && FBZCP_CC_ASELECT(FBZCOLORPATH) == 0) || - (a_local_is_used && FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 0)) - - NEEDS_ITER_Z: - - if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0 || - FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) != 0 || - FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 2) - - -*/ - -/* - Expects the following declarations to be outside of this scope: - - int32_t r, g, b, a; -*/ -#define COLORPATH_PIPELINE(VV, STATS, FBZCOLORPATH, FBZMODE, ALPHAMODE, TEXELARGB, ITERZ, ITERW, ITERARGB) \ -do \ -{ \ - int32_t blendr, blendg, blendb, blenda; \ - rgb_union c_other; \ - rgb_union c_local; \ - \ - /* compute c_other */ \ - switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH)) \ - { \ - case 0: /* iterated RGB */ \ - c_other.u = ITERARGB.u; \ - break; \ - \ - case 1: /* texture RGB */ \ - c_other.u = TEXELARGB.u; \ - break; \ - \ - case 2: /* color1 RGB */ \ - c_other.u = (VV)->reg[color1].u; \ - break; \ - \ - default: /* reserved - voodoo3 framebufferRGB */ \ - c_other.u = 0; \ - break; \ - } \ - \ - /* handle chroma key */ \ - APPLY_CHROMAKEY(VV, STATS, FBZMODE, c_other); \ - \ - /* compute a_other */ \ - switch (FBZCP_CC_ASELECT(FBZCOLORPATH)) \ - { \ - case 0: /* iterated alpha */ \ - c_other.rgb.a = ITERARGB.rgb.a; \ - break; \ - \ - case 1: /* texture alpha */ \ - c_other.rgb.a = TEXELARGB.rgb.a; \ - break; \ - \ - case 2: /* color1 alpha */ \ - c_other.rgb.a = (VV)->reg[color1].rgb.a; \ - break; \ - \ - default: /* reserved */ \ - c_other.rgb.a = 0; \ - break; \ - } \ - \ - /* handle alpha mask */ \ - APPLY_ALPHAMASK(VV, STATS, FBZMODE, c_other.rgb.a); \ - \ - /* compute c_local */ \ - if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0) \ - { \ - if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0) /* iterated RGB */ \ - c_local.u = ITERARGB.u; \ - else /* color0 RGB */ \ - c_local.u = (VV)->reg[color0].u; \ - } \ - else \ - { \ - if (!(TEXELARGB.rgb.a & 0x80)) /* iterated RGB */ \ - c_local.u = ITERARGB.u; \ - else /* color0 RGB */ \ - c_local.u = (VV)->reg[color0].u; \ - } \ - \ - /* compute a_local */ \ - switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH)) \ - { \ - default: \ - case 0: /* iterated alpha */ \ - c_local.rgb.a = ITERARGB.rgb.a; \ - break; \ - \ - case 1: /* color0 alpha */ \ - c_local.rgb.a = (VV)->reg[color0].rgb.a; \ - break; \ - \ - case 2: /* clamped iterated Z[27:20] */ \ - { \ - int temp; \ - CLAMPED_Z(ITERZ, FBZCOLORPATH, temp); \ - c_local.rgb.a = (uint8_t)temp; \ - break; \ - } \ - \ - case 3: /* clamped iterated W[39:32] */ \ - { \ - int temp; \ - CLAMPED_W(ITERW, FBZCOLORPATH, temp); /* Voodoo 2 only */ \ - c_local.rgb.a = (uint8_t)temp; \ - break; \ - } \ - } \ - \ - /* select zero or a_other */ \ - if (!FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH)) \ - a = c_other.rgb.a; \ - else \ - a = 0; \ - \ - /* subtract a_local */ \ - if (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH)) \ - a -= c_local.rgb.a; \ - \ - /* blend alpha */ \ - switch (FBZCP_CCA_MSELECT(FBZCOLORPATH)) \ - { \ - default: /* reserved */ \ - case 0: /* 0 */ \ - blenda = 0; \ - break; \ - \ - case 1: /* a_local */ \ - blenda = c_local.rgb.a; \ - break; \ - \ - case 2: /* a_other */ \ - blenda = c_other.rgb.a; \ - break; \ - \ - case 3: /* a_local */ \ - blenda = c_local.rgb.a; \ - break; \ - \ - case 4: /* texture alpha */ \ - blenda = TEXELARGB.rgb.a; \ - break; \ - } \ - \ - /* reverse the alpha blend */ \ - if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH)) \ - blenda ^= 0xff; \ - \ - /* do the blend */ \ - a = (a * (blenda + 1)) >> 8; \ - \ - /* add clocal or alocal to alpha */ \ - if (FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH)) \ - a += c_local.rgb.a; \ - \ - /* clamp */ \ - CLAMP(a, 0x00, 0xff); \ - \ - /* invert */ \ - if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH)) \ - a ^= 0xff; \ - \ - /* handle alpha test */ \ - APPLY_ALPHATEST(VV, STATS, ALPHAMODE, a); \ - \ - \ - /* select zero or c_other */ \ - if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0) \ - { \ - r = c_other.rgb.r; \ - g = c_other.rgb.g; \ - b = c_other.rgb.b; \ - } \ - else \ - r = g = b = 0; \ - \ - /* subtract c_local */ \ - if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH)) \ - { \ - r -= c_local.rgb.r; \ - g -= c_local.rgb.g; \ - b -= c_local.rgb.b; \ - } \ - \ - /* blend RGB */ \ - switch (FBZCP_CC_MSELECT(FBZCOLORPATH)) \ - { \ - default: /* reserved */ \ - case 0: /* 0 */ \ - blendr = blendg = blendb = 0; \ - break; \ - \ - case 1: /* c_local */ \ - blendr = c_local.rgb.r; \ - blendg = c_local.rgb.g; \ - blendb = c_local.rgb.b; \ - break; \ - \ - case 2: /* a_other */ \ - blendr = blendg = blendb = c_other.rgb.a; \ - break; \ - \ - case 3: /* a_local */ \ - blendr = blendg = blendb = c_local.rgb.a; \ - break; \ - \ - case 4: /* texture alpha */ \ - blendr = blendg = blendb = TEXELARGB.rgb.a; \ - break; \ - \ - case 5: /* texture RGB (Voodoo 2 only) */ \ - blendr = TEXELARGB.rgb.r; \ - blendg = TEXELARGB.rgb.g; \ - blendb = TEXELARGB.rgb.b; \ - break; \ - } \ - \ - /* reverse the RGB blend */ \ - if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH)) \ - { \ - blendr ^= 0xff; \ - blendg ^= 0xff; \ - blendb ^= 0xff; \ - } \ - \ - /* do the blend */ \ - r = (r * (blendr + 1)) >> 8; \ - g = (g * (blendg + 1)) >> 8; \ - b = (b * (blendb + 1)) >> 8; \ - \ - /* add clocal or alocal to RGB */ \ - switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH)) \ - { \ - case 3: /* reserved */ \ - case 0: /* nothing */ \ - break; \ - \ - case 1: /* add c_local */ \ - r += c_local.rgb.r; \ - g += c_local.rgb.g; \ - b += c_local.rgb.b; \ - break; \ - \ - case 2: /* add_alocal */ \ - r += c_local.rgb.a; \ - g += c_local.rgb.a; \ - b += c_local.rgb.a; \ - break; \ - } \ - \ - /* clamp */ \ - CLAMP(r, 0x00, 0xff); \ - CLAMP(g, 0x00, 0xff); \ - CLAMP(b, 0x00, 0xff); \ - \ - /* invert */ \ - if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH)) \ - { \ - r ^= 0xff; \ - g ^= 0xff; \ - b ^= 0xff; \ - } \ -} \ -while (0) - -inline bool ATTR_FORCE_INLINE voodoo_device::combineColor(voodoo_device *vd, stats_block *STATS, uint32_t FBZCOLORPATH, uint32_t FBZMODE, - rgbaint_t TEXELARGB, int32_t ITERZ, int64_t ITERW, rgbaint_t &srcColor) -{ - rgbaint_t c_other; - rgbaint_t c_local; - rgbaint_t blend_color, blend_factor; - rgbaint_t add_val; - - /* compute c_other */ - switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH)) - { - case 0: /* iterated RGB */ - c_other.set(srcColor); - break; - - case 1: /* texture RGB */ - c_other.set(TEXELARGB); - break; - - case 2: /* color1 RGB */ - c_other.set(vd->reg[color1].u); - break; - - default: /* reserved - voodoo3 LFB RGB */ - c_other.zero(); - break; - } - - /* handle chroma key */ - if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE)) - if (!chromaKeyTest(vd, STATS, FBZMODE, c_other)) - return false; - //APPLY_CHROMAKEY(vd->m_vds, STATS, FBZMODE, c_other); - - /* compute a_other */ - switch (FBZCP_CC_ASELECT(FBZCOLORPATH)) - { - case 0: /* iterated alpha */ - c_other.merge_alpha16(srcColor); - break; - - case 1: /* texture alpha */ - c_other.merge_alpha16(TEXELARGB); - break; - - case 2: /* color1 alpha */ - c_other.set_a16(vd->reg[color1].rgb.a); - break; - - default: /* reserved - voodoo3 LFB Alpha*/ - c_other.zero_alpha(); - break; - } - - /* handle alpha mask */ - if (FBZMODE_ENABLE_ALPHA_MASK(FBZMODE)) - if (!alphaMaskTest(STATS, FBZMODE, c_other.get_a())) - return false; - //APPLY_ALPHAMASK(vd->m_vds, STATS, FBZMODE, c_other.rgb.a); - - - /* compute c_local */ - if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0) - { - if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0) /* iterated RGB */ - c_local.set(srcColor); - else /* color0 RGB */ - c_local.set(vd->reg[color0].u); - } - else - { - if (!(TEXELARGB.get_a() & 0x80)) /* iterated RGB */ - c_local.set(srcColor); - else /* color0 RGB */ - c_local.set(vd->reg[color0].u); - } - - /* compute a_local */ - switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH)) - { - default: - case 0: /* iterated alpha */ - c_local.merge_alpha16(srcColor); - break; - - case 1: /* color0 alpha */ - c_local.set_a16(vd->reg[color0].rgb.a); - break; - - case 2: /* clamped iterated Z[27:20] */ - { - int temp; - CLAMPED_Z(ITERZ, FBZCOLORPATH, temp); - c_local.set_a16((uint8_t) temp); - break; - } - - case 3: /* clamped iterated W[39:32] */ - { - int temp; - CLAMPED_W(ITERW, FBZCOLORPATH, temp); /* Voodoo 2 only */ - c_local.set_a16((uint8_t) temp); - break; - } - } - - /* select zero or c_other */ - if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH)) - //r = g = b = 0; - blend_color.zero(); - else - blend_color.set(c_other); - - /* select zero or a_other */ - if (FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH)) - blend_color.zero_alpha(); - else - blend_color.merge_alpha16(c_other); - - /* subtract a/c_local */ - if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH) || (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH))) - { - rgbaint_t sub_val; - - if (!FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH)) - sub_val.zero(); - else - sub_val.set(c_local); - - if (!FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH)) - sub_val.zero_alpha(); - else - sub_val.merge_alpha16(c_local); - - blend_color.sub(sub_val); - } - - /* blend RGB */ - switch (FBZCP_CC_MSELECT(FBZCOLORPATH)) - { - default: /* reserved */ - case 0: /* 0 */ - blend_factor.zero(); - break; - - case 1: /* c_local */ - blend_factor.set(c_local); - break; - - case 2: /* a_other */ - blend_factor.set(c_other.select_alpha32()); - break; - - case 3: /* a_local */ - blend_factor.set(c_local.select_alpha32()); - break; - - case 4: /* texture alpha */ - blend_factor.set(TEXELARGB.select_alpha32()); - break; - - case 5: /* texture RGB (Voodoo 2 only) */ - blend_factor.set(TEXELARGB); - break; - } - - /* blend alpha */ - switch (FBZCP_CCA_MSELECT(FBZCOLORPATH)) - { - default: /* reserved */ - case 0: /* 0 */ - blend_factor.zero_alpha(); - break; - - case 1: /* a_local */ - case 3: /* a_local */ - blend_factor.merge_alpha16(c_local); - break; - - case 2: /* a_other */ - blend_factor.merge_alpha16(c_other); - break; - - case 4: /* texture alpha */ - blend_factor.merge_alpha16(TEXELARGB); - break; - } - - /* reverse the RGB blend */ - if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH)) - blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); - - /* reverse the alpha blend */ - if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH)) - blend_factor.xor_imm_rgba(0xff, 0, 0, 0); - - /* do the blend */ - //color.rgb.a = (color.rgb.a * (blenda + 1)) >> 8; - //color.rgb.r = (color.rgb.r * (blendr + 1)) >> 8; - //color.rgb.g = (color.rgb.g * (blendg + 1)) >> 8; - //color.rgb.b = (color.rgb.b * (blendb + 1)) >> 8; - - /* add clocal or alocal to RGB */ - switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH)) - { - case 3: /* reserved */ - case 0: /* nothing */ - add_val.zero(); - break; - - case 1: /* add c_local */ - add_val.set(c_local); - break; - - case 2: /* add_alocal */ - add_val.set(c_local.select_alpha32()); - break; - } - - /* add clocal or alocal to alpha */ - if (!FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH)) - add_val.zero_alpha(); - else - //color.rgb.a += c_local.rgb.a; - add_val.merge_alpha16(c_local); - - /* clamp */ - //CLAMP(color.rgb.a, 0x00, 0xff); - //CLAMP(color.rgb.r, 0x00, 0xff); - //CLAMP(color.rgb.g, 0x00, 0xff); - //CLAMP(color.rgb.b, 0x00, 0xff); - blend_factor.add_imm(1); - blend_color.scale_add_and_clamp(blend_factor, add_val); - - /* invert */ - if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH)) - blend_color.xor_imm_rgba(0xff, 0, 0, 0); - /* invert */ - if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH)) - blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); - - srcColor.set(blend_color); - - return true; -} - - - -/************************************* - * - * Rasterizer generator macro - * - *************************************/ - -#define RASTERIZER(name, TMUS, FBZCOLORPATH, FBZMODE, ALPHAMODE, FOGMODE, TEXMODE0, TEXMODE1) \ - \ -void voodoo_device::raster_##name(void *destbase, int32_t y, const poly_extent *extent, const void *extradata, int threadid) \ -{ \ - const poly_extra_data *extra = (const poly_extra_data *)extradata; \ - voodoo_device *vd = extra->device; \ - stats_block *stats = &vd->thread_stats[threadid]; \ - DECLARE_DITHER_POINTERS; \ - int32_t startx = extent->startx; \ - int32_t stopx = extent->stopx; \ - rgbaint_t iterargb, iterargbDelta; \ - int32_t iterz; \ - int64_t iterw; \ - tmu_state::stw_t iterstw0, iterstw1; \ - tmu_state::stw_t deltastw0, deltastw1; \ - uint16_t *depth; \ - uint16_t *dest; \ - int32_t dx, dy; \ - int32_t scry; \ - int32_t x; \ - \ - /* determine the screen Y */ \ - scry = y; \ - if (FBZMODE_Y_ORIGIN(FBZMODE)) \ - scry = (vd->fbi.yorigin - y); \ - \ - /* compute dithering */ \ - COMPUTE_DITHER_POINTERS(FBZMODE, y, FOGMODE); \ - \ - /* apply clipping */ \ - if (FBZMODE_ENABLE_CLIPPING(FBZMODE)) \ - { \ - int32_t tempclip; \ - \ - /* Y clipping buys us the whole scanline */ \ - if (scry < ((vd->reg[clipLowYHighY].u >> 16) & 0x3ff) || \ - scry >= (vd->reg[clipLowYHighY].u & 0x3ff)) \ - { \ - stats->pixels_in += stopx - startx; \ - stats->clip_fail += stopx - startx; \ - return; \ - } \ - \ - /* X clipping */ \ - tempclip = vd->reg[clipLeftRight].u & 0x3ff; \ - /* Check for start outsize of clipping boundary */ \ - if (startx >= tempclip) \ - { \ - stats->pixels_in += stopx - startx; \ - vd->stats.total_clipped += stopx - startx; \ - return; \ - } \ - if (stopx > tempclip) \ - { \ - stats->pixels_in += stopx - tempclip; \ - vd->stats.total_clipped += stopx - tempclip; \ - stopx = tempclip; \ - } \ - tempclip = (vd->reg[clipLeftRight].u >> 16) & 0x3ff; \ - if (startx < tempclip) \ - { \ - stats->pixels_in += tempclip - startx; \ - vd->stats.total_clipped += tempclip - startx; \ - startx = tempclip; \ - } \ - } \ - \ - /* get pointers to the target buffer and depth buffer */ \ - dest = (uint16_t *)destbase + scry * vd->fbi.rowpixels; \ - depth = (vd->fbi.auxoffs != ~0) ? ((uint16_t *)(vd->fbi.ram + vd->fbi.auxoffs) + scry * vd->fbi.rowpixels) : nullptr; \ - \ - /* compute the starting parameters */ \ - dx = startx - (extra->ax >> 4); \ - dy = y - (extra->ay >> 4); \ - int32_t iterr = extra->startr + dy * extra->drdy + dx * extra->drdx; \ - int32_t iterg = extra->startg + dy * extra->dgdy + dx * extra->dgdx; \ - int32_t iterb = extra->startb + dy * extra->dbdy + dx * extra->dbdx; \ - int32_t itera = extra->starta + dy * extra->dady + dx * extra->dadx; \ - iterargb.set(itera, iterr, iterg, iterb); \ - iterargbDelta.set(extra->dadx, extra->drdx, extra->dgdx, extra->dbdx); \ - iterz = extra->startz + dy * extra->dzdy + dx * extra->dzdx; \ - iterw = extra->startw + dy * extra->dwdy + dx * extra->dwdx; \ - if (TMUS >= 1) \ - { \ - iterstw0.set( \ - extra->starts0 + dy * extra->ds0dy + dx * extra->ds0dx, \ - extra->startt0 + dy * extra->dt0dy + dx * extra->dt0dx, \ - extra->startw0 + dy * extra->dw0dy + dx * extra->dw0dx); \ - deltastw0.set(extra->ds0dx, extra->dt0dx, extra->dw0dx); \ - } \ - if (TMUS >= 2) \ - { \ - iterstw1.set( \ - extra->starts1 + dy * extra->ds1dy + dx * extra->ds1dx, \ - extra->startt1 + dy * extra->dt1dy + dx * extra->dt1dx, \ - extra->startw1 + dy * extra->dw1dy + dx * extra->dw1dx); \ - deltastw1.set(extra->ds1dx, extra->dt1dx, extra->dw1dx); \ - } \ - extra->info->hits++; \ - /* loop in X */ \ - for (x = startx; x < stopx; x++) \ - { \ - rgbaint_t texel(0); \ - rgbaint_t color, preFog; \ - \ - /* pixel pipeline part 1 handles depth setup and stippling */ \ - PIXEL_PIPELINE_BEGIN(vd, stats, x, y, FBZCOLORPATH, FBZMODE, iterz, iterw); \ - /* depth testing */ \ - if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) \ - if (!depthTest((uint16_t) vd->reg[zaColor].u, stats, depth[x], FBZMODE, biasdepth)) \ - goto skipdrawdepth; \ - \ - /* run the texture pipeline on TMU1 to produce a value in texel */ \ - /* note that they set LOD min to 8 to "disable" a TMU */ \ - if (TMUS >= 2 && vd->tmu[1].lodmin < (8 << 8)) { \ - int32_t tmp; \ - const rgbaint_t texelZero(0); \ - texel = vd->tmu[1].genTexture(x, dither4, TEXMODE1, vd->tmu[1].lookup, extra->lodbase1, \ - iterstw1, tmp); \ - texel = vd->tmu[1].combineTexture(TEXMODE1, texel, texelZero, tmp); \ - } \ - /* run the texture pipeline on TMU0 to produce a final */ \ - /* result in texel */ \ - /* note that they set LOD min to 8 to "disable" a TMU */ \ - if (TMUS >= 1 && vd->tmu[0].lodmin < (8 << 8)) \ - { \ - if (!vd->send_config) \ - { \ - int32_t lod0; \ - rgbaint_t texelT0; \ - texelT0 = vd->tmu[0].genTexture(x, dither4, TEXMODE0, vd->tmu[0].lookup, extra->lodbase0, \ - iterstw0, lod0); \ - texel = vd->tmu[0].combineTexture(TEXMODE0, texelT0, texel, lod0); \ - } \ - else \ - { \ - texel.set(vd->tmu_config); \ - } \ - } \ - \ - /* colorpath pipeline selects source colors and does blending */ \ - color = clampARGB(iterargb, FBZCOLORPATH); \ - if (!combineColor(vd, stats, FBZCOLORPATH, FBZMODE, texel, iterz, iterw, color)) \ - goto skipdrawdepth; \ - /* handle alpha test */ \ - if (ALPHAMODE_ALPHATEST(ALPHAMODE)) \ - if (!alphaTest(vd->reg[alphaMode].rgb.a, stats, ALPHAMODE, color.get_a())) \ - goto skipdrawdepth; \ - \ - /* perform fogging */ \ - preFog.set(color); \ - if (FOGMODE_ENABLE_FOG(FOGMODE)) \ - applyFogging(vd, FBZMODE, FOGMODE, FBZCOLORPATH, x, dither4, wfloat, color, iterz, iterw, iterargb); \ - \ - /* perform alpha blending */ \ - if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) \ - alphaBlend(FBZMODE, ALPHAMODE, x, dither, dest[x], depth, preFog, color, vd->fbi.rgb565); \ - \ - /* pixel pipeline part 2 handles final output */ \ - PIXEL_PIPELINE_END(stats, dither_lookup, x, dest, depth, FBZMODE); \ - \ - /* update the iterated parameters */ \ - iterargb += iterargbDelta; \ - iterz += extra->dzdx; \ - iterw += extra->dwdx; \ - if (TMUS >= 1) \ - { \ - iterstw0.add(deltastw0); \ - } \ - if (TMUS >= 2) \ - { \ - iterstw1.add(deltastw1); \ - } \ - } \ -} - - -// ****************************************************************************************************************************** -// Computes a log2 of a 16.32 value to 2 fractional bits of precision. -// The return value is coded as a 24.8 value. -// The maximum error using a 4 bit lookup from the mantissa is 0.0875, which is less than 1/2 lsb (0.125) for 2 bits of fraction. -// An offset of +(56 << 8) is added for alignment in multi_reciplog -// ****************************************************************************************************************************** -inline int32_t ATTR_FORCE_INLINE voodoo_device::tmu_state::new_log2(double &value, const int &offset) -{ - static const int32_t new_log2_table[16] = {0, 22, 44, 63, 82, 100, 118, 134, 150, 165, 179, 193, 207, 220, 232, 244}; - uint64_t ival = *((uint64_t *)&value); - // Return 0 if negative - if (ival & ((uint64_t)1 << 63)) - return 0; - // We zero the result if negative so don't worry about the sign bit - int32_t exp = (ival>>52); - exp -= 1023+32-offset; - exp <<= 8; - uint32_t addr = (uint64_t)(ival>>48) & 0xf; - exp += new_log2_table[addr]; - return exp; -} - -inline rgbaint_t ATTR_FORCE_INLINE voodoo_device::tmu_state::genTexture(int32_t x, const uint8_t *dither4, const uint32_t TEXMODE, rgb_t *LOOKUP, int32_t LODBASE, const stw_t &iterstw, int32_t &lod) -{ - rgbaint_t result; - int32_t s, t, ilod; - - /* determine the S/T/LOD values for this texture */ - lod = (LODBASE); - if (TEXMODE_ENABLE_PERSPECTIVE(TEXMODE)) - { - int32_t wLog; - iterstw.calc_stow(s, t, wLog); - lod += wLog; - } - else - { -#if ((!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64)) - // Extra shift by 8 due to how sse class is stored - iterstw.get_st_shiftr(s, t, (14 + 10 + 8)); -#else - iterstw.get_st_shiftr(s, t, (14 + 10)); -#endif - } - - /* clamp W */ - if (TEXMODE_CLAMP_NEG_W(TEXMODE) && iterstw.is_w_neg()) - { - s = t = 0; - } - - /* clamp the LOD */ - lod += lodbias; - if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE)) - lod += dither4[x&3] << 4; - CLAMP(lod, lodmin, lodmax); - - /* now the LOD is in range; if we don't own this LOD, take the next one */ - ilod = lod >> 8; - if (!((lodmask >> ilod) & 1)) - ilod++; - - /* fetch the texture base */ - uint32_t texbase = lodoffset[ilod]; - - /* compute the maximum s and t values at this LOD */ - int32_t smax = wmask >> ilod; - int32_t tmax = hmask >> ilod; - - /* determine whether we are point-sampled or bilinear */ - if ((lod == lodmin && !TEXMODE_MAGNIFICATION_FILTER(TEXMODE)) || - (lod != lodmin && !TEXMODE_MINIFICATION_FILTER(TEXMODE))) - { - /* point sampled */ - - uint32_t texel0; - - /* adjust S/T for the LOD and strip off the fractions */ - s >>= ilod + (18-10); - t >>= ilod + (18-10); - - /* clamp/wrap S/T if necessary */ - if (TEXMODE_CLAMP_S(TEXMODE)) - CLAMP(s, 0, smax); - if (TEXMODE_CLAMP_T(TEXMODE)) - CLAMP(t, 0, tmax); - s &= smax; - t &= tmax; - t *= smax + 1; - - /* fetch texel data */ - if (TEXMODE_FORMAT(TEXMODE) < 8) - { - texel0 = *(uint8_t *)&ram[(texbase + t + s) & mask]; - result.set((LOOKUP)[texel0]); - } - else - { - texel0 = *(uint16_t *)&ram[(texbase + 2*(t + s)) & mask]; - if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) - result.set((LOOKUP)[texel0]); - else - result.set(((LOOKUP)[texel0 & 0xff] & 0xffffff) | ((texel0 & 0xff00) << 16)); - } - } - else - { - /* bilinear filtered */ - - uint32_t texel0, texel1, texel2, texel3; - uint32_t sfrac, tfrac; - int32_t s1, t1; - - /* adjust S/T for the LOD and strip off all but the low 8 bits of */ - /* the fraction */ - s >>= ilod; // + (10-10); - t >>= ilod; // + (10-10); - - /* also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel */ - s -= 0x80; - t -= 0x80; - - /* extract the fractions */ - sfrac = s & bilinear_mask; - tfrac = t & bilinear_mask; - - /* now toss the rest */ - s >>= 8; - t >>= 8; - s1 = s + 1; - t1 = t + 1; - - /* clamp/wrap S/T if necessary */ - if (TEXMODE_CLAMP_S(TEXMODE)) - { - if (s < 0) { - s = 0; - s1 = 0; - } else if (s >= smax) { - s = smax; - s1 = smax; - } - //CLAMP(s, 0, smax); - //CLAMP(s1, 0, smax); - } else { - s &= smax; - s1 &= smax; - } - - if (TEXMODE_CLAMP_T(TEXMODE)) - { - if (t < 0) { - t = 0; - t1 = 0; - } else if (t >= tmax) { - t = tmax; - t1 = tmax; - } - //CLAMP(t, 0, tmax); - //CLAMP(t1, 0, tmax); - } else { - t &= tmax; - t1 &= tmax; - } - t *= smax + 1; - t1 *= smax + 1; - - /* fetch texel data */ - if (TEXMODE_FORMAT(TEXMODE) < 8) - { - texel0 = *(uint8_t *)&ram[(texbase + t + s) & mask]; - texel1 = *(uint8_t *)&ram[(texbase + t + s1) & mask]; - texel2 = *(uint8_t *)&ram[(texbase + t1 + s) & mask]; - texel3 = *(uint8_t *)&ram[(texbase + t1 + s1) & mask]; - texel0 = (LOOKUP)[texel0]; - texel1 = (LOOKUP)[texel1]; - texel2 = (LOOKUP)[texel2]; - texel3 = (LOOKUP)[texel3]; - } - else - { - texel0 = *(uint16_t *)&ram[(texbase + 2*(t + s)) & mask]; - texel1 = *(uint16_t *)&ram[(texbase + 2*(t + s1)) & mask]; - texel2 = *(uint16_t *)&ram[(texbase + 2*(t1 + s)) & mask]; - texel3 = *(uint16_t *)&ram[(texbase + 2*(t1 + s1)) & mask]; - if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) - { - texel0 = (LOOKUP)[texel0]; - texel1 = (LOOKUP)[texel1]; - texel2 = (LOOKUP)[texel2]; - texel3 = (LOOKUP)[texel3]; - } - else - { - texel0 = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | ((texel0 & 0xff00) << 16); - texel1 = ((LOOKUP)[texel1 & 0xff] & 0xffffff) | ((texel1 & 0xff00) << 16); - texel2 = ((LOOKUP)[texel2 & 0xff] & 0xffffff) | ((texel2 & 0xff00) << 16); - texel3 = ((LOOKUP)[texel3 & 0xff] & 0xffffff) | ((texel3 & 0xff00) << 16); - } - } - - /* weigh in each texel */ - - result.bilinear_filter_rgbaint(texel0, texel1, texel2, texel3, sfrac, tfrac); - } - return result; -} - -inline rgbaint_t ATTR_FORCE_INLINE voodoo_device::tmu_state::combineTexture(const uint32_t TEXMODE, const rgbaint_t& c_local, const rgbaint_t& c_other, int32_t lod) -{ - rgbaint_t blend_color, blend_factor; - rgbaint_t add_val; - - /* select zero/other for RGB */ - if (TEXMODE_TC_ZERO_OTHER(TEXMODE)) - blend_color.zero(); - else - blend_color.set(c_other); - - /* select zero/other for alpha */ - if (TEXMODE_TCA_ZERO_OTHER(TEXMODE)) - blend_color.zero_alpha(); - else - blend_color.merge_alpha16(c_other); - - if (TEXMODE_TC_SUB_CLOCAL(TEXMODE) || TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) - { - rgbaint_t sub_val; - - /* potentially subtract c_local */ - if (!TEXMODE_TC_SUB_CLOCAL(TEXMODE)) - sub_val.zero(); - else - sub_val.set(c_local); - - if (!TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) - sub_val.zero_alpha(); - else - sub_val.merge_alpha16(c_local); - - blend_color.sub(sub_val); - } - - /* blend RGB */ - switch (TEXMODE_TC_MSELECT(TEXMODE)) - { - default: /* reserved */ - case 0: /* zero */ - blend_factor.zero(); - break; - - case 1: /* c_local */ - blend_factor.set(c_local); - break; - - case 2: /* a_other */ - blend_factor.set(c_other.select_alpha32()); - break; - - case 3: /* a_local */ - blend_factor.set(c_local.select_alpha32()); - break; - - case 4: /* LOD (detail factor) */ - if (detailbias <= lod) - blend_factor.zero(); - else - { - uint8_t tmp; - tmp = (((detailbias - lod) << detailscale) >> 8); - if (tmp > detailmax) - tmp = detailmax; - blend_factor.set_all(tmp); - } - break; - - case 5: /* LOD fraction */ - blend_factor.set_all(lod & 0xff); - break; - } - - /* blend alpha */ - switch (TEXMODE_TCA_MSELECT(TEXMODE)) - { - default: /* reserved */ - case 0: /* zero */ - blend_factor.zero_alpha(); - break; - - case 1: /* c_local */ - blend_factor.merge_alpha16(c_local); - break; - - case 2: /* a_other */ - blend_factor.merge_alpha16(c_other); - break; - - case 3: /* a_local */ - blend_factor.merge_alpha16(c_local); - break; - - case 4: /* LOD (detail factor) */ - if (detailbias <= lod) - blend_factor.zero_alpha(); - else - { - uint8_t tmp; - tmp = (((detailbias - lod) << detailscale) >> 8); - if (tmp > detailmax) - tmp = detailmax; - blend_factor.set_a16(tmp); - } - break; - - case 5: /* LOD fraction */ - blend_factor.set_a16(lod & 0xff); - break; - } - - /* reverse the RGB blend */ - if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE)) - blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); - - /* reverse the alpha blend */ - if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE)) - blend_factor.xor_imm_rgba(0xff, 0, 0, 0); - - /* do the blend */ - //tr = (tr * (blendr + 1)) >> 8; - //tg = (tg * (blendg + 1)) >> 8; - //tb = (tb * (blendb + 1)) >> 8; - //ta = (ta * (blenda + 1)) >> 8; - - /* add clocal or alocal to RGB */ - switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE)) - { - case 3: /* reserved */ - case 0: /* nothing */ - add_val.zero(); - break; - - case 1: /* add c_local */ - add_val.set(c_local); - break; - - case 2: /* add_alocal */ - add_val.set(c_local.select_alpha32()); - break; - } - - /* add clocal or alocal to alpha */ - if (!TEXMODE_TCA_ADD_ACLOCAL(TEXMODE)) - add_val.zero_alpha(); - else - add_val.merge_alpha16(c_local); - - /* clamp */ - //result.rgb.r = (tr < 0) ? 0 : (tr > 0xff) ? 0xff : tr; - //result.rgb.g = (tg < 0) ? 0 : (tg > 0xff) ? 0xff : tg; - //result.rgb.b = (tb < 0) ? 0 : (tb > 0xff) ? 0xff : tb; - //result.rgb.a = (ta < 0) ? 0 : (ta > 0xff) ? 0xff : ta; - blend_factor.add_imm(1); - blend_color.scale_add_and_clamp(blend_factor, add_val); - - /* invert */ - if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE)) - blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); - if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE)) - blend_color.xor_imm_rgba(0xff, 0, 0, 0); - return blend_color; -} - -#endif // MAME_VIDEO_VOODDEFS_IPP diff --git a/src/devices/video/voodoo.cpp b/src/devices/video/voodoo.cpp index ea5a22f7aec..df52d84e7a2 100644 --- a/src/devices/video/voodoo.cpp +++ b/src/devices/video/voodoo.cpp @@ -8,16 +8,6 @@ **************************************************************************** -//fix me -- blitz2k dies when starting a game with heavy fog (in DRC) - -**************************************************************************** - - 3dfx Voodoo Graphics SST-1/2 emulator - - emulator by Aaron Giles - - -------------------------- - Specs: Voodoo 1 (SST1): @@ -29,32 +19,6 @@ 64 entry PCI FIFO memory FIFO up to 65536 entries - Voodoo 2: - 2,4MB frame buffer RAM - 2,4,8,16MB texture RAM - 90MHz clock frquency - clears @ 2 pixels/clock (RGB and depth simultaneously) - renders @ 1 pixel/clock - ultrafast clears @ 16 pixels/clock - 128 entry PCI FIFO - memory FIFO up to 65536 entries - - Voodoo Banshee (h3): - Integrated VGA support - 2,4,8MB frame buffer RAM - 90MHz clock frquency - clears @ 2 pixels/clock (RGB and depth simultaneously) - renders @ 1 pixel/clock - ultrafast clears @ 32 pixels/clock - - Voodoo 3 ("Avenger"/h4): - Integrated VGA support - 4,8,16MB frame buffer RAM - 143MHz clock frquency - clears @ 2 pixels/clock (RGB and depth simultaneously) - renders @ 1 pixel/clock - ultrafast clears @ 32 pixels/clock - -------------------------- still to be implemented: @@ -141,5589 +105,812 @@ bits(7:4) and bit(24)), X, and Y: **************************************************************************/ +/* + +TODO: + - look at speed on Konami games (nbapbp, racingj, etc) + - look at timing issues on IT games + - bad textures in some Voodoo 3 games (mocapb for example) + - update callers to use maps + +*/ #include "emu.h" #include "voodoo.h" -#include "vooddefs.ipp" -#include "screen.h" +using namespace voodoo; -/************************************* - * - * Debugging - * - *************************************/ +//************************************************************************** +// GLOBAL HELPERS +//************************************************************************** -#define DEBUG_DEPTH (0) -#define DEBUG_BACKBUF (0) -#define DEBUG_STATS (0) +//------------------------------------------------- +// float_to_int32 - convert a floating-point +// value in raw IEEE format into an integer with +// the given number of fractional bits +//------------------------------------------------- -#define LOG_VBLANK_SWAP (0) -#define LOG_FIFO (0) -#define LOG_FIFO_VERBOSE (0) -#define LOG_REGISTERS (0) -#define LOG_WAITS (0) -#define LOG_LFB (0) -#define LOG_TEXTURE_RAM (0) -#define LOG_RASTERIZERS (0) -#define LOG_CMDFIFO (0) -#define LOG_CMDFIFO_VERBOSE (0) -#define LOG_BANSHEE_2D (0) - -#define MODIFY_PIXEL(VV) - -// Need to turn off cycle eating when debugging MIPS drc -// otherwise timer interrupts won't match nodrc debug mode. -#define EAT_CYCLES (1) - - -namespace { - -/************************************* - * - * Alias map of the first 64 - * registers when remapped - * - *************************************/ - -const uint8_t register_alias_map[0x40] = +inline s32 float_to_int32(u32 data, int fixedbits) { - vdstatus, 0x004/4, vertexAx, vertexAy, - vertexBx, vertexBy, vertexCx, vertexCy, - startR, dRdX, dRdY, startG, - dGdX, dGdY, startB, dBdX, - dBdY, startZ, dZdX, dZdY, - startA, dAdX, dAdY, startS, - dSdX, dSdY, startT, dTdX, - dTdY, startW, dWdX, dWdY, + // compute the effective exponent + int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; - triangleCMD,0x084/4, fvertexAx, fvertexAy, - fvertexBx, fvertexBy, fvertexCx, fvertexCy, - fstartR, fdRdX, fdRdY, fstartG, - fdGdX, fdGdY, fstartB, fdBdX, - fdBdY, fstartZ, fdZdX, fdZdY, - fstartA, fdAdX, fdAdY, fstartS, - fdSdX, fdSdY, fstartT, fdTdX, - fdTdY, fstartW, fdWdX, fdWdY -}; + // extract the mantissa and return the implied leading 1 bit + s32 result = (data & 0x7fffff) | 0x800000; - -/************************************* - * - * Table of per-register access rights - * - *************************************/ - -const uint8_t voodoo_register_access[0x100] = -{ - /* 0x000 */ - REG_RP, 0, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x040 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x080 */ - REG_WPF, 0, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x0c0 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x100 */ - REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWF, REG_RWF, REG_RWF, REG_RWF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, 0, 0, - - /* 0x140 */ - REG_RWF, REG_RWF, REG_RWF, REG_R, - REG_R, REG_R, REG_R, REG_R, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x180 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x1c0 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x200 */ - REG_RW, REG_R, REG_RW, REG_RW, - REG_RW, REG_RW, REG_RW, REG_RW, - REG_W, REG_W, REG_W, REG_W, - REG_W, 0, 0, 0, - - /* 0x240 */ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x280 */ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x2c0 */ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x300 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x340 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x380 */ - REG_WF -}; - -const uint8_t voodoo2_register_access[0x100] = -{ - /* 0x000 */ - REG_RP, REG_RWPT, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x040 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x080 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x0c0 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x100 */ - REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWF, REG_RWF, REG_RWF, REG_RWF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x140 */ - REG_RWF, REG_RWF, REG_RWF, REG_R, - REG_R, REG_R, REG_R, REG_R, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x180 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x1c0 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_RWT, REG_RWT, REG_RWT, REG_RWT, - REG_RWT, REG_RWT, REG_RWT, REG_RW, - - /* 0x200 */ - REG_RWT, REG_R, REG_RWT, REG_RWT, - REG_RWT, REG_RWT, REG_RWT, REG_RWT, - REG_WT, REG_WT, REG_WF, REG_WT, - REG_WT, REG_WT, REG_WT, REG_WT, - - /* 0x240 */ - REG_R, REG_RWT, REG_RWT, REG_RWT, - 0, 0, REG_R, REG_R, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x280 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, 0, 0, - 0, 0, 0, 0, - - /* 0x2c0 */ - REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWPF, REG_RWPF, REG_RWPF, REG_WPF, - - /* 0x300 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x340 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x380 */ - REG_WF -}; - -const uint8_t banshee_register_access[0x100] = -{ - /* 0x000 */ - REG_RP, REG_RWPT, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x040 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x080 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x0c0 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x100 */ - REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, - REG_RWF, REG_RWF, REG_RWF, REG_RWF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x140 */ - REG_RWF, REG_RWF, REG_RWF, REG_R, - REG_R, REG_R, REG_R, REG_R, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x180 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x1c0 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - 0, 0, 0, REG_RWF, - REG_RWF, REG_RWF, REG_RWF, 0, - - /* 0x200 */ - REG_RWF, REG_RWF, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x240 */ - 0, 0, 0, REG_WT, - REG_RWF, REG_RWF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_R, REG_R, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - - /* 0x280 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, 0, 0, - 0, 0, 0, 0, - - /* 0x2c0 */ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - - /* 0x300 */ - REG_WPF, REG_WPF, REG_WPF, REG_WPF, - REG_WPF, REG_WPF, REG_WPF, 0, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x340 */ - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - REG_WF, REG_WF, REG_WF, REG_WF, - - /* 0x380 */ - REG_WF -}; - - -/************************************* - * - * Register string table for debug - * - *************************************/ - -const char *const voodoo_reg_name[] = -{ - /* 0x000 */ - "status", "{intrCtrl}", "vertexAx", "vertexAy", - "vertexBx", "vertexBy", "vertexCx", "vertexCy", - "startR", "startG", "startB", "startZ", - "startA", "startS", "startT", "startW", - /* 0x040 */ - "dRdX", "dGdX", "dBdX", "dZdX", - "dAdX", "dSdX", "dTdX", "dWdX", - "dRdY", "dGdY", "dBdY", "dZdY", - "dAdY", "dSdY", "dTdY", "dWdY", - /* 0x080 */ - "triangleCMD", "reserved084", "fvertexAx", "fvertexAy", - "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy", - "fstartR", "fstartG", "fstartB", "fstartZ", - "fstartA", "fstartS", "fstartT", "fstartW", - /* 0x0c0 */ - "fdRdX", "fdGdX", "fdBdX", "fdZdX", - "fdAdX", "fdSdX", "fdTdX", "fdWdX", - "fdRdY", "fdGdY", "fdBdY", "fdZdY", - "fdAdY", "fdSdY", "fdTdY", "fdWdY", - /* 0x100 */ - "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode", - "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY", - "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor", - "zaColor", "chromaKey", "{chromaRange}","{userIntrCMD}", - /* 0x140 */ - "stipple", "color0", "color1", "fbiPixelsIn", - "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut", - "fogTable160", "fogTable164", "fogTable168", "fogTable16c", - "fogTable170", "fogTable174", "fogTable178", "fogTable17c", - /* 0x180 */ - "fogTable180", "fogTable184", "fogTable188", "fogTable18c", - "fogTable190", "fogTable194", "fogTable198", "fogTable19c", - "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac", - "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc", - /* 0x1c0 */ - "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc", - "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc", - "{cmdFifoBaseAddr}","{cmdFifoBump}","{cmdFifoRdPtr}","{cmdFifoAMin}", - "{cmdFifoAMax}","{cmdFifoDepth}","{cmdFifoHoles}","reserved1fc", - /* 0x200 */ - "fbiInit4", "vRetrace", "backPorch", "videoDimensions", - "fbiInit0", "fbiInit1", "fbiInit2", "fbiInit3", - "hSync", "vSync", "clutData", "dacData", - "maxRgbDelta", "{hBorder}", "{vBorder}", "{borderColor}", - /* 0x240 */ - "{hvRetrace}", "{fbiInit5}", "{fbiInit6}", "{fbiInit7}", - "reserved250", "reserved254", "{fbiSwapHistory}","{fbiTrianglesOut}", - "{sSetupMode}", "{sVx}", "{sVy}", "{sARGB}", - "{sRed}", "{sGreen}", "{sBlue}", "{sAlpha}", - /* 0x280 */ - "{sVz}", "{sWb}", "{sWtmu0}", "{sS/Wtmu0}", - "{sT/Wtmu0}", "{sWtmu1}", "{sS/Wtmu1}", "{sT/Wtmu1}", - "{sDrawTriCMD}","{sBeginTriCMD}","reserved2a8", "reserved2ac", - "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc", - /* 0x2c0 */ - "{bltSrcBaseAddr}","{bltDstBaseAddr}","{bltXYStrides}","{bltSrcChromaRange}", - "{bltDstChromaRange}","{bltClipX}","{bltClipY}","reserved2dc", - "{bltSrcXY}", "{bltDstXY}", "{bltSize}", "{bltRop}", - "{bltColor}", "reserved2f4", "{bltCommand}", "{bltData}", - /* 0x300 */ - "textureMode", "tLOD", "tDetail", "texBaseAddr", - "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","trexInit0", - "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2", - "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6", - /* 0x340 */ - "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A", - "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2", - "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6", - "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A", - /* 0x380 */ - "nccTable1.B" -}; - -const char *const banshee_reg_name[] = -{ - /* 0x000 */ - "status", "intrCtrl", "vertexAx", "vertexAy", - "vertexBx", "vertexBy", "vertexCx", "vertexCy", - "startR", "startG", "startB", "startZ", - "startA", "startS", "startT", "startW", - /* 0x040 */ - "dRdX", "dGdX", "dBdX", "dZdX", - "dAdX", "dSdX", "dTdX", "dWdX", - "dRdY", "dGdY", "dBdY", "dZdY", - "dAdY", "dSdY", "dTdY", "dWdY", - /* 0x080 */ - "triangleCMD", "reserved084", "fvertexAx", "fvertexAy", - "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy", - "fstartR", "fstartG", "fstartB", "fstartZ", - "fstartA", "fstartS", "fstartT", "fstartW", - /* 0x0c0 */ - "fdRdX", "fdGdX", "fdBdX", "fdZdX", - "fdAdX", "fdSdX", "fdTdX", "fdWdX", - "fdRdY", "fdGdY", "fdBdY", "fdZdY", - "fdAdY", "fdSdY", "fdTdY", "fdWdY", - /* 0x100 */ - "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode", - "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY", - "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor", - "zaColor", "chromaKey", "chromaRange", "userIntrCMD", - /* 0x140 */ - "stipple", "color0", "color1", "fbiPixelsIn", - "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut", - "fogTable160", "fogTable164", "fogTable168", "fogTable16c", - "fogTable170", "fogTable174", "fogTable178", "fogTable17c", - /* 0x180 */ - "fogTable180", "fogTable184", "fogTable188", "fogTable18c", - "fogTable190", "fogTable194", "fogTable198", "fogTable19c", - "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac", - "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc", - /* 0x1c0 */ - "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc", - "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc", - "reserved1e0", "reserved1e4", "reserved1e8", "colBufferAddr", - "colBufferStride","auxBufferAddr","auxBufferStride","reserved1fc", - /* 0x200 */ - "clipLeftRight1","clipTopBottom1","reserved208","reserved20c", - "reserved210", "reserved214", "reserved218", "reserved21c", - "reserved220", "reserved224", "reserved228", "reserved22c", - "reserved230", "reserved234", "reserved238", "reserved23c", - /* 0x240 */ - "reserved240", "reserved244", "reserved248", "swapPending", - "leftOverlayBuf","rightOverlayBuf","fbiSwapHistory","fbiTrianglesOut", - "sSetupMode", "sVx", "sVy", "sARGB", - "sRed", "sGreen", "sBlue", "sAlpha", - /* 0x280 */ - "sVz", "sWb", "sWtmu0", "sS/Wtmu0", - "sT/Wtmu0", "sWtmu1", "sS/Wtmu1", "sT/Wtmu1", - "sDrawTriCMD", "sBeginTriCMD", "reserved2a8", "reserved2ac", - "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc", - /* 0x2c0 */ - "reserved2c0", "reserved2c4", "reserved2c8", "reserved2cc", - "reserved2d0", "reserved2d4", "reserved2d8", "reserved2dc", - "reserved2e0", "reserved2e4", "reserved2e8", "reserved2ec", - "reserved2f0", "reserved2f4", "reserved2f8", "reserved2fc", - /* 0x300 */ - "textureMode", "tLOD", "tDetail", "texBaseAddr", - "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","reserved31c", - "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2", - "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6", - /* 0x340 */ - "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A", - "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2", - "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6", - "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A", - /* 0x380 */ - "nccTable1.B" -}; - - -/************************************* - * - * Register string table for debug - * - *************************************/ - -const char *const banshee_io_reg_name[] = -{ - /* 0x000 */ - "status", "pciInit0", "sipMonitor", "lfbMemoryConfig", - "miscInit0", "miscInit1", "dramInit0", "dramInit1", - "agpInit", "tmuGbeInit", "vgaInit0", "vgaInit1", - "dramCommand", "dramData", "reserved38", "reserved3c", - - /* 0x040 */ - "pllCtrl0", "pllCtrl1", "pllCtrl2", "dacMode", - "dacAddr", "dacData", "rgbMaxDelta", "vidProcCfg", - "hwCurPatAddr", "hwCurLoc", "hwCurC0", "hwCurC1", - "vidInFormat", "vidInStatus", "vidSerialParallelPort","vidInXDecimDeltas", - - /* 0x080 */ - "vidInDecimInitErrs","vidInYDecimDeltas","vidPixelBufThold","vidChromaMin", - "vidChromaMax", "vidCurrentLine","vidScreenSize","vidOverlayStartCoords", - "vidOverlayEndScreenCoord","vidOverlayDudx","vidOverlayDudxOffsetSrcWidth","vidOverlayDvdy", - "vga[b0]", "vga[b4]", "vga[b8]", "vga[bc]", - - /* 0x0c0 */ - "vga[c0]", "vga[c4]", "vga[c8]", "vga[cc]", - "vga[d0]", "vga[d4]", "vga[d8]", "vga[dc]", - "vidOverlayDvdyOffset","vidDesktopStartAddr","vidDesktopOverlayStride","vidInAddr0", - "vidInAddr1", "vidInAddr2", "vidInStride", "vidCurrOverlayStartAddr" -}; - - -/************************************* - * - * Register string table for debug - * - *************************************/ - -const char *const banshee_agp_reg_name[] = -{ - /* 0x000 */ - "agpReqSize", "agpHostAddressLow","agpHostAddressHigh","agpGraphicsAddress", - "agpGraphicsStride","agpMoveCMD","reserved18", "reserved1c", - "cmdBaseAddr0", "cmdBaseSize0", "cmdBump0", "cmdRdPtrL0", - "cmdRdPtrH0", "cmdAMin0", "reserved38", "cmdAMax0", - - /* 0x040 */ - "reserved40", "cmdFifoDepth0","cmdHoleCnt0", "reserved4c", - "cmdBaseAddr1", "cmdBaseSize1", "cmdBump1", "cmdRdPtrL1", - "cmdRdPtrH1", "cmdAMin1", "reserved68", "cmdAMax1", - "reserved70", "cmdFifoDepth1","cmdHoleCnt1", "reserved7c", - - /* 0x080 */ - "cmdFifoThresh","cmdHoleInt", "reserved88", "reserved8c", - "reserved90", "reserved94", "reserved98", "reserved9c", - "reserveda0", "reserveda4", "reserveda8", "reservedac", - "reservedb0", "reservedb4", "reservedb8", "reservedbc", - - /* 0x0c0 */ - "reservedc0", "reservedc4", "reservedc8", "reservedcc", - "reservedd0", "reservedd4", "reservedd8", "reserveddc", - "reservede0", "reservede4", "reservede8", "reservedec", - "reservedf0", "reservedf4", "reservedf8", "reservedfc", - - /* 0x100 */ - "yuvBaseAddress","yuvStride", "reserved108", "reserved10c", - "reserved110", "reserved114", "reserved118", "reserved11c", - "crc1", "reserved124", "reserved128", "reserved12c", - "crc2", "reserved134", "reserved138", "reserved13c" -}; - -} // anonymous namespace - - -struct voodoo_device::poly_extra_data -{ - voodoo_device * device; - raster_info * info; // pointer to rasterizer information - - int16_t ax, ay; // vertex A x,y (12.4) - int32_t startr, startg, startb, starta; // starting R,G,B,A (12.12) - int32_t startz; // starting Z (20.12) - int64_t startw; // starting W (16.32) - int32_t drdx, dgdx, dbdx, dadx; // delta R,G,B,A per X - int32_t dzdx; // delta Z per X - int64_t dwdx; // delta W per X - int32_t drdy, dgdy, dbdy, dady; // delta R,G,B,A per Y - int32_t dzdy; // delta Z per Y - int64_t dwdy; // delta W per Y - - int64_t starts0, startt0; // starting S,T (14.18) - int64_t startw0; // starting W (2.30) - int64_t ds0dx, dt0dx; // delta S,T per X - int64_t dw0dx; // delta W per X - int64_t ds0dy, dt0dy; // delta S,T per Y - int64_t dw0dy; // delta W per Y - int32_t lodbase0; // used during rasterization - - int64_t starts1, startt1; // starting S,T (14.18) - int64_t startw1; // starting W (2.30) - int64_t ds1dx, dt1dx; // delta S,T per X - int64_t dw1dx; // delta W per X - int64_t ds1dy, dt1dy; // delta S,T per Y - int64_t dw1dy; // delta W per Y - int32_t lodbase1; // used during rasterization - - uint16_t dither[16]; // dither matrix, for fastfill -}; - - - -/************************************* - * - * Statics - * - *************************************/ - -static const rectangle global_cliprect(-4096, 4095, -4096, 4095); - -/* fast dither lookup */ -static uint8_t dither4_lookup[256*16*2]; -static uint8_t dither2_lookup[256*16*2]; - -/* fast reciprocal+log2 lookup */ -uint32_t voodoo_reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2]; - - - - - -/************************************* - * - * Specific rasterizers - * - *************************************/ - -#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \ - RASTERIZER(fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, (((tex0) == 0xffffffff) ? 0 : ((tex1) == 0xffffffff) ? 1 : 2), fbzcp, fbz, alpha, fog, tex0, tex1) - -#include "voodoo_rast.ipp" - -#undef RASTERIZER_ENTRY - - - -/************************************* - * - * Rasterizer table - * - *************************************/ - -#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \ - { nullptr, voodoo_device::raster_##fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, false, 0, 0, 0, fbzcp, alpha, fog, fbz, tex0, tex1 }, - -const voodoo_device::raster_info voodoo_device::predef_raster_table[] = -{ -#include "voodoo_rast.ipp" - { nullptr } -}; - -#undef RASTERIZER_ENTRY - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -/************************************* - * - * Video update - * - *************************************/ - -int voodoo_device::voodoo_update(bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - int changed = fbi.video_changed; - int drawbuf = fbi.frontbuf; - int x, y; - - /* reset the video changed flag */ - fbi.video_changed = false; - - /* if we are blank, just fill with black */ - if (vd_type <= TYPE_VOODOO_2 && FBIINIT1_SOFTWARE_BLANK(reg[fbiInit1].u)) + // shift by the exponent, handling minimum/maximum + if (exponent < 0) { - bitmap.fill(0, cliprect); - return changed; - } - - /* if the CLUT is dirty, recompute the pens array */ - if (fbi.clut_dirty) - { - uint8_t rtable[32], gtable[64], btable[32]; - - /* Voodoo/Voodoo-2 have an internal 33-entry CLUT */ - if (vd_type <= TYPE_VOODOO_2) - { - /* kludge: some of the Midway games write 0 to the last entry when they obviously mean FF */ - if ((fbi.clut[32] & 0xffffff) == 0 && (fbi.clut[31] & 0xffffff) != 0) - fbi.clut[32] = 0x20ffffff; - - /* compute the R/G/B pens first */ - for (x = 0; x < 32; x++) - { - /* treat X as a 5-bit value, scale up to 8 bits, and linear interpolate for red/blue */ - y = (x << 3) | (x >> 2); - rtable[x] = (fbi.clut[y >> 3].r() * (8 - (y & 7)) + fbi.clut[(y >> 3) + 1].r() * (y & 7)) >> 3; - btable[x] = (fbi.clut[y >> 3].b() * (8 - (y & 7)) + fbi.clut[(y >> 3) + 1].b() * (y & 7)) >> 3; - - /* treat X as a 6-bit value with LSB=0, scale up to 8 bits, and linear interpolate */ - y = (x * 2) + 0; - y = (y << 2) | (y >> 4); - gtable[x*2+0] = (fbi.clut[y >> 3].g() * (8 - (y & 7)) + fbi.clut[(y >> 3) + 1].g() * (y & 7)) >> 3; - - /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */ - y = (x * 2) + 1; - y = (y << 2) | (y >> 4); - gtable[x*2+1] = (fbi.clut[y >> 3].g() * (8 - (y & 7)) + fbi.clut[(y >> 3) + 1].g() * (y & 7)) >> 3; - } - } - - /* Banshee and later have a 512-entry CLUT that can be bypassed */ + if (exponent > -32) + result >>= -exponent; else - { - int which = (banshee.io[io_vidProcCfg] >> 13) & 1; - int bypass = (banshee.io[io_vidProcCfg] >> 11) & 1; - - /* compute R/G/B pens first */ - for (x = 0; x < 32; x++) - { - /* treat X as a 5-bit value, scale up to 8 bits */ - y = (x << 3) | (x >> 2); - rtable[x] = bypass ? y : fbi.clut[which * 256 + y].r(); - btable[x] = bypass ? y : fbi.clut[which * 256 + y].b(); - - /* treat X as a 6-bit value with LSB=0, scale up to 8 bits */ - y = (x * 2) + 0; - y = (y << 2) | (y >> 4); - gtable[x*2+0] = bypass ? y : fbi.clut[which * 256 + y].g(); - - /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */ - y = (x * 2) + 1; - y = (y << 2) | (y >> 4); - gtable[x*2+1] = bypass ? y : fbi.clut[which * 256 + y].g(); - } - } - - /* now compute the actual pens array */ - for (x = 0; x < 65536; x++) - { - int r = rtable[(x >> 11) & 0x1f]; - int g = gtable[(x >> 5) & 0x3f]; - int b = btable[x & 0x1f]; - fbi.pen[x] = rgb_t(r, g, b); - } - - /* no longer dirty */ - fbi.clut_dirty = false; - changed = true; + result = 0; } - - /* debugging! */ - if (DEBUG_BACKBUF && machine().input().code_pressed(KEYCODE_L)) - drawbuf = fbi.backbuf; - - /* copy from the current front buffer */ - for (y = cliprect.min_y; y <= cliprect.max_y; y++) - if (y >= fbi.yoffs) - { - uint16_t const *const src = (uint16_t *)(fbi.ram + fbi.rgboffs[drawbuf]) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs; - uint32_t *const dst = &bitmap.pix(y); - for (x = cliprect.min_x; x <= cliprect.max_x; x++) - dst[x] = fbi.pen[src[x]]; - } - - /* update stats display */ - if (DEBUG_STATS) + else { - int statskey = (machine().input().code_pressed(KEYCODE_BACKSLASH)); - if (statskey && statskey != stats.lastkey) - stats.display = !stats.display; - stats.lastkey = statskey; - - /* display stats */ - if (stats.display) - popmessage(stats.buffer, 0, 0); + if (exponent < 32) + result <<= exponent; + else + result = 0x7fffffff; } - /* update render override */ - if (DEBUG_DEPTH) + // negate based on the sign + return (data & 0x80000000) ? -result : result; +} + + +//------------------------------------------------- +// float_to_int64 - convert a floating-point +// value in raw IEEE format into an integer with +// the given number of fractional bits +//------------------------------------------------- + +inline s64 float_to_int64(u32 data, int fixedbits) +{ + // compute the effective exponent + int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; + + // extract the mantissa and return the implied leading 1 bit + s64 result = (data & 0x7fffff) | 0x800000; + + // shift by the exponent, handling minimum/maximum + if (exponent < 0) { - stats.render_override = machine().input().code_pressed(KEYCODE_ENTER); - if (stats.render_override) - { - for (y = cliprect.min_y; y <= cliprect.max_y; y++) - { - uint16_t const *const src = (uint16_t*)(fbi.ram + fbi.auxoffs) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs; - uint32_t *const dst = &bitmap.pix(y); - for (x = cliprect.min_x; x <= cliprect.max_x; x++) - dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff); - } - } + if (exponent > -64) + result >>= -exponent; + else + result = 0; } - return changed; + else + { + if (exponent < 64) + result <<= exponent; + else + result = 0x7fffffffffffffffull; + } + + // negate based on the sign + return (data & 0x80000000) ? -result : result; +} + + +//************************************************************************** +// VOODOO REGISTERS +//************************************************************************** + +//------------------------------------------------- +// register_save - save live state +//------------------------------------------------- + +void voodoo_regs::register_save(save_proxy &save) +{ + save.save_item(NAME(m_regs)); + save.save_item(NAME(m_starts)); + save.save_item(NAME(m_startt)); + save.save_item(NAME(m_startw)); + save.save_item(NAME(m_dsdx)); + save.save_item(NAME(m_dtdx)); + save.save_item(NAME(m_dwdx)); + save.save_item(NAME(m_dsdy)); + save.save_item(NAME(m_dtdy)); + save.save_item(NAME(m_dwdy)); +} + + +//------------------------------------------------- +// s_alias_map - remap of first 64 registers +//------------------------------------------------- + +u8 const voodoo_regs::s_alias_map[0x40] = +{ + voodoo_regs::reg_vdstatus, 0x004/4, voodoo_regs::reg_vertexAx, voodoo_regs::reg_vertexAy, + voodoo_regs::reg_vertexBx, voodoo_regs::reg_vertexBy, voodoo_regs::reg_vertexCx, voodoo_regs::reg_vertexCy, + voodoo_regs::reg_startR, voodoo_regs::reg_dRdX, voodoo_regs::reg_dRdY, voodoo_regs::reg_startG, + voodoo_regs::reg_dGdX, voodoo_regs::reg_dGdY, voodoo_regs::reg_startB, voodoo_regs::reg_dBdX, + voodoo_regs::reg_dBdY, voodoo_regs::reg_startZ, voodoo_regs::reg_dZdX, voodoo_regs::reg_dZdY, + voodoo_regs::reg_startA, voodoo_regs::reg_dAdX, voodoo_regs::reg_dAdY, voodoo_regs::reg_startS, + voodoo_regs::reg_dSdX, voodoo_regs::reg_dSdY, voodoo_regs::reg_startT, voodoo_regs::reg_dTdX, + voodoo_regs::reg_dTdY, voodoo_regs::reg_startW, voodoo_regs::reg_dWdX, voodoo_regs::reg_dWdY, + + voodoo_regs::reg_triangleCMD,0x084/4, voodoo_regs::reg_fvertexAx, voodoo_regs::reg_fvertexAy, + voodoo_regs::reg_fvertexBx, voodoo_regs::reg_fvertexBy, voodoo_regs::reg_fvertexCx, voodoo_regs::reg_fvertexCy, + voodoo_regs::reg_fstartR, voodoo_regs::reg_fdRdX, voodoo_regs::reg_fdRdY, voodoo_regs::reg_fstartG, + voodoo_regs::reg_fdGdX, voodoo_regs::reg_fdGdY, voodoo_regs::reg_fstartB, voodoo_regs::reg_fdBdX, + voodoo_regs::reg_fdBdY, voodoo_regs::reg_fstartZ, voodoo_regs::reg_fdZdX, voodoo_regs::reg_fdZdY, + voodoo_regs::reg_fstartA, voodoo_regs::reg_fdAdX, voodoo_regs::reg_fdAdY, voodoo_regs::reg_fstartS, + voodoo_regs::reg_fdSdX, voodoo_regs::reg_fdSdY, voodoo_regs::reg_fstartT, voodoo_regs::reg_fdTdX, + voodoo_regs::reg_fdTdY, voodoo_regs::reg_fstartW, voodoo_regs::reg_fdWdX, voodoo_regs::reg_fdWdY +}; + + +//************************************************************************** +// SHARED TABLES +//************************************************************************** + +//------------------------------------------------- +// shared_tables - constructor +//------------------------------------------------- + +shared_tables::shared_tables() +{ + // configure the array of texel formats + texel[0] = rgb332; + texel[1] = nullptr; + texel[2] = alpha8; + texel[3] = int8; + texel[4] = ai44; + texel[5] = nullptr; + texel[6] = nullptr; + texel[7] = nullptr; + texel[8] = rgb332; + texel[9] = nullptr; + texel[10] = rgb565; + texel[11] = argb1555; + texel[12] = argb4444; + texel[13] = int8; + texel[14] = nullptr; + texel[15] = nullptr; + + // build static 8-bit texel tables + for (int val = 0; val < 256; val++) + { + // 8-bit RGB (3-3-2) + rgb332[val] = rgbexpand<3,3,2>(val, 5, 2, 0).set_a(0xff); + + // 8-bit alpha + alpha8[val] = rgb_t(val, val, val, val); + + // 8-bit intensity + int8[val] = rgb_t(0xff, val, val, val); + + // 8-bit alpha, intensity + ai44[val] = argbexpand<4,4,4,4>(val, 4, 0, 0, 0); + } + + // build static 16-bit texel tables + for (int val = 0; val < 65536; val++) + { + // table 10 = 16-bit RGB (5-6-5) + rgb565[val] = rgbexpand<5,6,5>(val, 11, 5, 0).set_a(0xff); + + // table 11 = 16 ARGB (1-5-5-5) + argb1555[val] = argbexpand<1,5,5,5>(val, 15, 10, 5, 0); + + // table 12 = 16-bit ARGB (4-4-4-4) + argb4444[val] = argbexpand<4,4,4,4>(val, 12, 8, 4, 0); + } +} + + +//************************************************************************** +// TMU STATE +//************************************************************************** + +//------------------------------------------------- +// tmu_state - constructor +//------------------------------------------------- + +tmu_state::tmu_state() : + m_index(0), + m_ram(nullptr), + m_mask(0), + m_basemask(0xfffff), + m_baseshift(3) +{ +} + + +//------------------------------------------------- +// init - configure local state +//------------------------------------------------- + +void tmu_state::init(int index, shared_tables const &share, u8 *ram, u32 size) +{ + // configure texture RAM + m_index = index; + m_ram = ram; + m_mask = size - 1; + m_regdirty = true; + m_palette_dirty[0] = m_palette_dirty[1] = m_palette_dirty[2] = m_palette_dirty[3] = true; + m_texel_lookup = &share.texel[0]; +} + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void tmu_state::register_save(save_proxy &save) +{ + // register state + save.save_class(NAME(m_reg)); + save.save_item(NAME(m_palette)); +} + + +//------------------------------------------------- +// post_load - mark everything dirty following a +// state load +//------------------------------------------------- + +void tmu_state::post_load() +{ + m_regdirty = true; + m_palette_dirty[0] = m_palette_dirty[1] = m_palette_dirty[2] = m_palette_dirty[3] = true; +} + + +//------------------------------------------------- +// ncc_w - handle a write to the NCC/palette +// registers +//------------------------------------------------- + +void tmu_state::ncc_w(offs_t regnum, u32 data) +{ + u32 regindex = regnum - voodoo_regs::reg_nccTable; + + // I/Q entries in NCC 0 reference the palette if the high bit is set + if (BIT(data, 31) && regindex >= 4 && regindex < 12) + { + // extract the palette index + int const index = (BIT(data, 24, 7) << 1) | BIT(regindex, 0); + + // compute RGB and ARGB values + rgb_t rgb = 0xff000000 | data; + rgb_t argb = argbexpand<6,6,6,6>(data, 18, 12, 6, 0); + + // set and mark dirty + if (m_palette[0][index] != rgb) + { + m_palette[0][index] = rgb; + m_palette_dirty[0] = true; + } + if (m_palette[1][index] != argb) + { + m_palette[1][index] = argb; + m_palette_dirty[1] = true; + } + return; + } + + // if no delta, don't mark dirty + if (m_reg.read(regnum) == data) + return; + + // write the updated data and mark dirty + m_reg.write(regnum, data); + m_palette_dirty[2 + regindex / 12] = true; +} + + +//------------------------------------------------- +// prepare_texture - handle updating the texture +// state if the texture configuration is dirty +//------------------------------------------------- + +inline rasterizer_texture &tmu_state::prepare_texture(voodoo_renderer &renderer) +{ + // if the texture parameters are dirty, update them + if (m_regdirty) + { + // determine the lookup + auto const texmode = m_reg.texture_mode(); + u32 const texformat = texmode.format(); + rgb_t const *lookup = m_texel_lookup[texformat]; + + // if null lookup, then we need something dynamic + if (lookup == nullptr) + { + // could be either straight palette or NCC table + int palindex; + if ((texformat & 7) == 1) + { + // NCC case: palindex = 2 or 3 based on table select + palindex = 2 + texmode.ncc_table_select(); + if (m_palette_dirty[palindex]) + { + u32 const *regs = m_reg.subset(voodoo_regs::reg_nccTable + 12 * (palindex & 1)); + renderer.alloc_palette(m_index * 4 + palindex).compute_ncc(regs); + } + } + else + { + // palette case: palindex = 0 or 1 based on RGB vs RGBA + palindex = (texformat == 6) ? 1 : 0; + if (m_palette_dirty[palindex]) + renderer.alloc_palette(m_index * 4 + palindex).copy(&m_palette[palindex & 1][0]); + } + + // clear the dirty flag and fetch the texels + m_palette_dirty[palindex] = false; + lookup = renderer.last_palette(m_index * 4 + palindex).texels(); + } + + // recompute the rasterization parameters + renderer.alloc_texture(m_index).recompute(m_reg, m_ram, m_mask, lookup, m_basemask, m_baseshift); + m_regdirty = false; + } + return renderer.last_texture(m_index); } -/************************************* - * - * Chip reset - * - *************************************/ +//************************************************************************** +// MEMORY FIFO +//************************************************************************** +//------------------------------------------------- +// memory_fifo - constructor +//------------------------------------------------- -int voodoo_device::voodoo_get_type() +memory_fifo::memory_fifo() : + m_base(nullptr), + m_size(0), + m_in(0), + m_out(0) { - return vd_type; } -int voodoo_device::voodoo_is_stalled() +//------------------------------------------------- +// configure - set the base/size and reset +//------------------------------------------------- + +void memory_fifo::configure(u32 *base, u32 size) { - return pci.stall_state != NOT_STALLED; + m_base = base; + m_size = size; + reset(); } -void voodoo_device::voodoo_set_init_enable(uint32_t newval) +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void memory_fifo::register_save(save_proxy &save) { - pci.init_enable = newval; + save.save_item(NAME(m_size)); + save.save_item(NAME(m_in)); + save.save_item(NAME(m_out)); +} + + +//------------------------------------------------- +// add - append an item to the fifo +//------------------------------------------------- + +inline void memory_fifo::add(u32 data) +{ + // compute the value of 'in' after we add this item + s32 next_in = m_in + 1; + if (next_in >= m_size) + next_in = 0; + + // as long as it's not equal to the output pointer, we can do it + if (next_in != m_out) + { + m_base[m_in] = data; + m_in = next_in; + } +} + + +//------------------------------------------------- +// remove - remove the next item from the fifo +//------------------------------------------------- + +inline u32 memory_fifo::remove() +{ + // return invalid data if empty + if (m_out == m_in) + return 0xffffffff; + + // determine next output + s32 next_out = m_out + 1; + if (next_out >= m_size) + next_out = 0; + + // fetch current and advance + u32 data = m_base[m_out]; + m_out = next_out; + return data; +} + + +//************************************************************************** +// DEBUG STATS +//************************************************************************** + +//------------------------------------------------- +// debug_stats - constructor +//------------------------------------------------- + +debug_stats::debug_stats() : + m_lastkey(false), + m_display(false) +{ + reset(); +} + + +//------------------------------------------------- +// add_emulation_stats - add in statistics from +// the emulation stats +//------------------------------------------------- + +void debug_stats::add_emulation_stats(thread_stats_block const &block) +{ + m_pixels_in += block.pixels_in; + m_pixels_out += block.pixels_out; + m_chroma_fail += block.chroma_fail; + m_zfunc_fail += block.zfunc_fail; + m_afunc_fail += block.afunc_fail; + m_clipped += block.clip_fail; + m_stippled += block.stipple_count; +} + + +//------------------------------------------------- +// reset - reset per-swap statistics +//------------------------------------------------- + +void debug_stats::reset() +{ + m_stalls = 0; + m_triangles = 0; + m_pixels_in = 0; + m_pixels_out = 0; + m_chroma_fail = 0; + m_zfunc_fail = 0; + m_afunc_fail = 0; + m_clipped = 0; + m_stippled = 0; + m_reg_writes = 0; + m_reg_reads = 0; + m_lfb_writes = 0; + m_lfb_reads = 0; + m_tex_writes = 0; + std::fill_n(&m_texture_mode[0], std::size(m_texture_mode), 0); +} + + +//------------------------------------------------- +// update_string - compute the string to display +// all the statistics +//------------------------------------------------- + +void debug_stats::update_string(rectangle const &visarea, u32 swap_history) +{ + // create a string of texture modes used + char texmodes[17] = { 0 }; + char *texptr = &texmodes[0]; + for (int mode = 0; mode < 16; mode++) + if (m_texture_mode[mode]) + *texptr++ = "0123456789ABCDEF"[mode]; + *texptr = 0; + + // build the string + m_string = string_format("Swap:%6d\n" + "Hist:%08X\n" + "Stal:%6d\n" + "Rend:%6d%%\n" + "Poly:%6d\n" + "PxIn:%6d\n" + "POut:%6d\n" + "Clip:%6d\n" + "Stip:%6d\n" + "Chro:%6d\n" + "ZFun:%6d\n" + "AFun:%6d\n" + "RegW:%6d\n" + "RegR:%6d\n" + "LFBW:%6d\n" + "LFBR:%6d\n" + "TexW:%6d\n" + "TexM:%s", + m_swaps, swap_history, m_stalls, m_pixels_out * 100 / (visarea.width() * visarea.height()), + m_triangles, m_pixels_in, m_pixels_out, m_clipped, m_stippled, + m_chroma_fail, m_zfunc_fail, m_afunc_fail, + m_reg_writes, m_reg_reads, m_lfb_writes, m_lfb_reads, m_tex_writes, texmodes); +} + + +//------------------------------------------------- +// update_display_state - based on the current key +// state, update and return whether stats should +// be shown +//------------------------------------------------- + +bool debug_stats::update_display_state(bool key_pressed) +{ + if (key_pressed && key_pressed != m_lastkey) + m_display = !m_display; + m_lastkey = key_pressed; + return m_display; +} + + +//************************************************************************** +// GENERIC VOODOO DEVICE +//************************************************************************** + +//------------------------------------------------- +// generic_voodoo_device - constructor +//------------------------------------------------- + +generic_voodoo_device::generic_voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo_model model) : + device_t(mconfig, type, tag, owner, clock), + device_video_interface(mconfig, *this), + m_model(model), + m_fbmem_in_mb(0), + m_tmumem0_in_mb(0), + m_tmumem1_in_mb(0), + m_status_cycles(0), + m_cpu(*this, finder_base::DUMMY_TAG), + m_vblank_cb(*this), + m_stall_cb(*this), + m_pciint_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device startup +//------------------------------------------------- + +void generic_voodoo_device::device_start() +{ + // resolve callbacks + m_vblank_cb.resolve(); + m_stall_cb.resolve(); + m_pciint_cb.resolve(); +} + + +//************************************************************************** +// VOODOO 1 DEVICE +//************************************************************************** + +//------------------------------------------------- +// voodoo_1_device - constructor +//------------------------------------------------- + +DEFINE_DEVICE_TYPE(VOODOO_1, voodoo_1_device, "voodoo_1", "3dfx Voodoo Graphics") + +voodoo_1_device::voodoo_1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo_model model) : + generic_voodoo_device(mconfig, type, tag, owner, clock, model), + m_chipmask(1), + m_init_enable(0), + m_stall_state(NOT_STALLED), + m_stall_trigger(0), + m_operation_end(attotime::zero), + m_flush_flag(false), + m_fbram(nullptr), + m_fbmask(0), + m_rgboffs{ u32(~0), u32(~0), u32(~0) }, + m_auxoffs(~0), + m_frontbuf(0), + m_backbuf(1), + m_video_changed(true), + m_lfb_stride(0), + m_width(512), + m_height(384), + m_xoffs(0), + m_yoffs(0), + m_vsyncstart(0), + m_vsyncstop(0), + m_swaps_pending(0), + m_vblank(0), + m_vblank_count(0), + m_vblank_swap_pending(0), + m_vblank_swap(0), + m_vblank_dont_swap(0), + m_vsync_start_timer(nullptr), + m_vsync_stop_timer(nullptr), + m_stall_resume_timer(nullptr), + m_last_status_pc(0), + m_last_status_value(0), + m_clut_dirty(true), + m_clut(33), + m_pen(65536) +{ + for (int index = 0; index < std::size(m_regtable); index++) + m_regtable[index].unpack(s_register_table[index], *this); +} + + +//------------------------------------------------- +// ~voodoo_1_device - destructor +//------------------------------------------------- + +voodoo_1_device::~voodoo_1_device() +{ +} + + +//------------------------------------------------- +// core_map - device map for core memory access +//------------------------------------------------- + +void voodoo_1_device::core_map(address_map &map) +{ + // Voodoo-1 memory map: + // + // 00ab----`--ccccrr`rrrrrr-- Register access + // a = alternate register map if fbi_init3().tri_register_remap() + // b = byte swizzle data if fbi_init0().swizzle_reg_writes() + // c = chip mask select + // r = register index ($00-$FF) + // 01-yyyyy`yyyyyxxx`xxxxxxx- Linear frame buffer access (16-bit) + // 01yyyyyy`yyyyxxxx`xxxxxx-- Linear frame buffer access (32-bit) + // 1-ccllll`tttttttt`sssssss- Texture memory access, where: + // c = chip mask select + // l = LOD + // t = Y index + // s = X index + // + map(0x000000, 0x3fffff).rw(FUNC(voodoo_1_device::map_register_r), FUNC(voodoo_1_device::map_register_w)); + map(0x400000, 0x7fffff).rw(FUNC(voodoo_1_device::map_lfb_r), FUNC(voodoo_1_device::map_lfb_w)); + map(0x800000, 0xffffff).w(FUNC(voodoo_1_device::map_texture_w)); +} + + +//------------------------------------------------- +// read - generic read handler until everyone is +// using the memory map +//------------------------------------------------- + +u32 voodoo_1_device::read(offs_t offset, u32 mem_mask) +{ + switch (offset >> (22-2)) + { + case 0x000000 >> 22: + return map_register_r(offset); + + case 0x400000 >> 22: + return map_lfb_r(offset - 0x400000/4); + + default: + return 0xffffffff; + } +} + + +//------------------------------------------------- +// write - generic write handler until everyone is +// using the memory map +//------------------------------------------------- + +void voodoo_1_device::write(offs_t offset, u32 data, u32 mem_mask) +{ + switch (offset >> (22-2)) + { + case 0x000000 >> 22: + map_register_w(offset, data, mem_mask); + break; + + case 0x400000 >> 22: + map_lfb_w(offset - 0x400000/4, data, mem_mask); + break; + + case 0x800000 >> 22: + case 0xc00000 >> 22: + map_texture_w(offset - 0x800000/4, data, mem_mask); + break; + } +} + + +//------------------------------------------------- +// set_init_enable - set the externally-controlled +// init_en register +//------------------------------------------------- + +void voodoo_1_device::set_init_enable(u32 newval) +{ + m_init_enable = reg_init_en(newval); if (LOG_REGISTERS) logerror("VOODOO.REG:initEnable write = %08X\n", newval); } +//------------------------------------------------- +// update - update the screen bitmap +//------------------------------------------------- -/************************************* - * - * Common initialization - * - *************************************/ - -void voodoo_device::init_fbi(voodoo_device* vd,fbi_state *f, void *memory, int fbmem) +int voodoo_1_device::update(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - /* allocate frame buffer RAM and set pointers */ - f->ram = (uint8_t *)memory; - f->mask = fbmem - 1; - f->rgboffs[0] = f->rgboffs[1] = f->rgboffs[2] = 0; - f->auxoffs = ~0; - - /* default to 0x0 */ - f->frontbuf = 0; - f->backbuf = 1; - f->width = 512; - f->height = 384; - - /* init the pens */ - f->clut_dirty = true; - if (vd->vd_type <= TYPE_VOODOO_2) + // if we are blank, just fill with black + if (m_reg.fbi_init1().software_blank()) { - for (int pen = 0; pen < 32; pen++) - vd->fbi.clut[pen] = rgb_t(pen, pal5bit(pen), pal5bit(pen), pal5bit(pen)); - vd->fbi.clut[32] = rgb_t(32,0xff,0xff,0xff); - } - else - { - for (int pen = 0; pen < 512; pen++) - vd->fbi.clut[pen] = rgb_t(pen,pen,pen); + bitmap.fill(0, cliprect); + int changed = m_video_changed; + m_video_changed = false; + return changed; } - // build static 16-bit rgb565 to rgb888 conversion table - for (int val = 0; val < 65536; val++) + // if the CLUT is dirty, recompute the pens array + if (m_clut_dirty) { - int r, g, b; + rgb_t const *clutbase = &m_clut[0]; - /* table 10 = 16-bit RGB (5-6-5) */ - EXTRACT_565_TO_888(val, r, g, b); - vd->fbi.rgb565[val] = rgb_t(0xff, r, g, b); - } + // kludge: some of the Midway games write 0 to the last entry when they obviously mean FF + if ((m_clut[32] & 0xffffff) == 0 && (m_clut[31] & 0xffffff) != 0) + m_clut[32] = 0x20ffffff; - /* allocate a VBLANK timer */ - f->vsync_stop_timer = vd->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_device::vblank_off_callback), vd), vd); - f->vsync_start_timer = vd->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_device::vblank_callback),vd), vd); - f->vblank = false; - - /* initialize the memory FIFO */ - f->fifo.base = nullptr; - f->fifo.size = f->fifo.in = f->fifo.out = 0; - - /* set the fog delta mask */ - f->fogdelta_mask = (vd->vd_type < TYPE_VOODOO_2) ? 0xff : 0xfc; -} - - -void voodoo_device::tmu_shared_state::init() -{ - /* build static 8-bit texel tables */ - for (int val = 0; val < 256; val++) - { - int r, g, b, a; - - /* 8-bit RGB (3-3-2) */ - EXTRACT_332_TO_888(val, r, g, b); - rgb332[val] = rgb_t(0xff, r, g, b); - - /* 8-bit alpha */ - alpha8[val] = rgb_t(val, val, val, val); - - /* 8-bit intensity */ - int8[val] = rgb_t(0xff, val, val, val); - - /* 8-bit alpha, intensity */ - a = ((val >> 0) & 0xf0) | ((val >> 4) & 0x0f); - r = ((val << 4) & 0xf0) | ((val << 0) & 0x0f); - ai44[val] = rgb_t(a, r, r, r); - } - - /* build static 16-bit texel tables */ - for (int val = 0; val < 65536; val++) - { - int r, g, b, a; - - /* table 10 = 16-bit RGB (5-6-5) */ - // Use frame buffer table - - /* table 11 = 16 ARGB (1-5-5-5) */ - EXTRACT_1555_TO_8888(val, a, r, g, b); - argb1555[val] = rgb_t(a, r, g, b); - - /* table 12 = 16-bit ARGB (4-4-4-4) */ - EXTRACT_4444_TO_8888(val, a, r, g, b); - argb4444[val] = rgb_t(a, r, g, b); - } - - rgb565 = nullptr; -} - - -void voodoo_device::tmu_state::init(uint8_t vdt, tmu_shared_state &share, voodoo_reg *r, void *memory, int tmem) -{ - /* allocate texture RAM */ - ram = reinterpret_cast(memory); - mask = tmem - 1; - reg = r; - regdirty = false; - bilinear_mask = (vdt >= TYPE_VOODOO_2) ? 0xff : 0xf0; - - /* mark the NCC tables dirty and configure their registers */ - ncc[0].dirty = ncc[1].dirty = true; - ncc[0].reg = ®[nccTable+0]; - ncc[1].reg = ®[nccTable+12]; - - /* create pointers to all the tables */ - texel[0] = share.rgb332; - texel[1] = ncc[0].texel; - texel[2] = share.alpha8; - texel[3] = share.int8; - texel[4] = share.ai44; - texel[5] = palette; - texel[6] = (vdt >= TYPE_VOODOO_2) ? palettea : nullptr; - texel[7] = nullptr; - texel[8] = share.rgb332; - texel[9] = ncc[0].texel; - texel[10] = share.rgb565; - texel[11] = share.argb1555; - texel[12] = share.argb4444; - texel[13] = share.int8; - texel[14] = palette; - texel[15] = nullptr; - lookup = texel[0]; - - /* attach the palette to NCC table 0 */ - ncc[0].palette = palette; - if (vdt >= TYPE_VOODOO_2) - ncc[0].palettea = palettea; - - /* set up texture address calculations */ - if (vdt <= TYPE_VOODOO_2) - { - texaddr_mask = 0x0fffff; - texaddr_shift = 3; - } - else - { - texaddr_mask = 0xfffff0; - texaddr_shift = 0; - } -} - - -void voodoo_device::voodoo_postload() -{ - fbi.clut_dirty = true; - for (tmu_state &tm : tmu) - { - tm.regdirty = true; - for (tmu_state::ncc_table &ncc : tm.ncc) - ncc.dirty = true; - } - - /* recompute video memory to get the FBI FIFO base recomputed */ - if (vd_type <= TYPE_VOODOO_2) - recompute_video_memory(); -} - - -void voodoo_device::init_save_state(voodoo_device *vd) -{ - vd->machine().save().register_postload(save_prepost_delegate(FUNC(voodoo_device::voodoo_postload), vd)); - - /* register states: core */ - vd->save_item(NAME(vd->extra_cycles)); - vd->save_pointer(NAME(&vd->reg[0].u), std::size(vd->reg)); - vd->save_item(NAME(vd->alt_regmap)); - - /* register states: pci */ - vd->save_item(NAME(vd->pci.fifo.in)); - vd->save_item(NAME(vd->pci.fifo.out)); - vd->save_item(NAME(vd->pci.init_enable)); - vd->save_item(NAME(vd->pci.stall_state)); - vd->save_item(NAME(vd->pci.op_pending)); - vd->save_item(NAME(vd->pci.op_end_time)); - vd->save_item(NAME(vd->pci.fifo_mem)); - - /* register states: dac */ - vd->save_item(NAME(vd->dac.reg)); - vd->save_item(NAME(vd->dac.read_result)); - - /* register states: fbi */ - vd->save_pointer(NAME(vd->fbi.ram), vd->fbi.mask + 1); - vd->save_item(NAME(vd->fbi.rgboffs)); - vd->save_item(NAME(vd->fbi.auxoffs)); - vd->save_item(NAME(vd->fbi.frontbuf)); - vd->save_item(NAME(vd->fbi.backbuf)); - vd->save_item(NAME(vd->fbi.swaps_pending)); - vd->save_item(NAME(vd->fbi.video_changed)); - vd->save_item(NAME(vd->fbi.yorigin)); - vd->save_item(NAME(vd->fbi.lfb_base)); - vd->save_item(NAME(vd->fbi.lfb_stride)); - vd->save_item(NAME(vd->fbi.width)); - vd->save_item(NAME(vd->fbi.height)); - vd->save_item(NAME(vd->fbi.xoffs)); - vd->save_item(NAME(vd->fbi.yoffs)); - vd->save_item(NAME(vd->fbi.vsyncstart)); - vd->save_item(NAME(vd->fbi.vsyncstop)); - vd->save_item(NAME(vd->fbi.rowpixels)); - vd->save_item(NAME(vd->fbi.vblank)); - vd->save_item(NAME(vd->fbi.vblank_count)); - vd->save_item(NAME(vd->fbi.vblank_swap_pending)); - vd->save_item(NAME(vd->fbi.vblank_swap)); - vd->save_item(NAME(vd->fbi.vblank_dont_swap)); - vd->save_item(NAME(vd->fbi.cheating_allowed)); - vd->save_item(NAME(vd->fbi.sign)); - vd->save_item(NAME(vd->fbi.ax)); - vd->save_item(NAME(vd->fbi.ay)); - vd->save_item(NAME(vd->fbi.bx)); - vd->save_item(NAME(vd->fbi.by)); - vd->save_item(NAME(vd->fbi.cx)); - vd->save_item(NAME(vd->fbi.cy)); - vd->save_item(NAME(vd->fbi.startr)); - vd->save_item(NAME(vd->fbi.startg)); - vd->save_item(NAME(vd->fbi.startb)); - vd->save_item(NAME(vd->fbi.starta)); - vd->save_item(NAME(vd->fbi.startz)); - vd->save_item(NAME(vd->fbi.startw)); - vd->save_item(NAME(vd->fbi.drdx)); - vd->save_item(NAME(vd->fbi.dgdx)); - vd->save_item(NAME(vd->fbi.dbdx)); - vd->save_item(NAME(vd->fbi.dadx)); - vd->save_item(NAME(vd->fbi.dzdx)); - vd->save_item(NAME(vd->fbi.dwdx)); - vd->save_item(NAME(vd->fbi.drdy)); - vd->save_item(NAME(vd->fbi.dgdy)); - vd->save_item(NAME(vd->fbi.dbdy)); - vd->save_item(NAME(vd->fbi.dady)); - vd->save_item(NAME(vd->fbi.dzdy)); - vd->save_item(NAME(vd->fbi.dwdy)); - vd->save_item(NAME(vd->fbi.lfb_stats.pixels_in)); - vd->save_item(NAME(vd->fbi.lfb_stats.pixels_out)); - vd->save_item(NAME(vd->fbi.lfb_stats.chroma_fail)); - vd->save_item(NAME(vd->fbi.lfb_stats.zfunc_fail)); - vd->save_item(NAME(vd->fbi.lfb_stats.afunc_fail)); - vd->save_item(NAME(vd->fbi.lfb_stats.clip_fail)); - vd->save_item(NAME(vd->fbi.lfb_stats.stipple_count)); - vd->save_item(NAME(vd->fbi.sverts)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, x)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, y)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, a)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, r)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, g)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, b)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, z)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, wb)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, w0)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, s0)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, t0)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, w1)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, s1)); - vd->save_item(STRUCT_MEMBER(vd->fbi.svert, t1)); - vd->save_item(NAME(vd->fbi.fifo.size)); - vd->save_item(NAME(vd->fbi.fifo.in)); - vd->save_item(NAME(vd->fbi.fifo.out)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, enable)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, count_holes)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, base)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, end)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, rdptr)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, amin)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, amax)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, depth)); - vd->save_item(STRUCT_MEMBER(vd->fbi.cmdfifo, holes)); - vd->save_item(NAME(vd->fbi.fogblend)); - vd->save_item(NAME(vd->fbi.fogdelta)); - vd->save_item(NAME(vd->fbi.clut)); - - /* register states: tmu */ - for (int index = 0; index < std::size(vd->tmu); index++) - { - tmu_state *tmu = &vd->tmu[index]; - if (tmu->ram == nullptr) - continue; - if (tmu->ram != vd->fbi.ram) - vd->save_pointer(NAME(tmu->ram), tmu->mask + 1, index); - vd->save_item(NAME(tmu->starts), index); - vd->save_item(NAME(tmu->startt), index); - vd->save_item(NAME(tmu->startw), index); - vd->save_item(NAME(tmu->dsdx), index); - vd->save_item(NAME(tmu->dtdx), index); - vd->save_item(NAME(tmu->dwdx), index); - vd->save_item(NAME(tmu->dsdy), index); - vd->save_item(NAME(tmu->dtdy), index); - vd->save_item(NAME(tmu->dwdy), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, ir), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, ig), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, ib), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, qr), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, qg), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, qb), index); - vd->save_item(STRUCT_MEMBER(tmu->ncc, y), index); - } - - /* register states: banshee */ - if (vd->vd_type >= TYPE_VOODOO_BANSHEE) - { - vd->save_item(NAME(vd->banshee.io)); - vd->save_item(NAME(vd->banshee.agp)); - vd->save_item(NAME(vd->banshee.vga)); - vd->save_item(NAME(vd->banshee.crtc)); - vd->save_item(NAME(vd->banshee.seq)); - vd->save_item(NAME(vd->banshee.gc)); - vd->save_item(NAME(vd->banshee.att)); - vd->save_item(NAME(vd->banshee.attff)); - } -} - - - -/************************************* - * - * Statistics management - * - *************************************/ - -void voodoo_device::accumulate_statistics(const stats_block &block) -{ - /* apply internal voodoo statistics */ - reg[fbiPixelsIn].u += block.pixels_in; - reg[fbiPixelsOut].u += block.pixels_out; - reg[fbiChromaFail].u += block.chroma_fail; - reg[fbiZfuncFail].u += block.zfunc_fail; - reg[fbiAfuncFail].u += block.afunc_fail; - - /* apply emulation statistics */ - stats.total_pixels_in += block.pixels_in; - stats.total_pixels_out += block.pixels_out; - stats.total_chroma_fail += block.chroma_fail; - stats.total_zfunc_fail += block.zfunc_fail; - stats.total_afunc_fail += block.afunc_fail; - stats.total_clipped += block.clip_fail; - stats.total_stippled += block.stipple_count; -} - - -void voodoo_device::update_statistics(bool accumulate) -{ - /* accumulate/reset statistics from all units */ - for (int threadnum = 0; threadnum < WORK_MAX_THREADS; threadnum++) - { - if (accumulate) - accumulate_statistics(thread_stats[threadnum]); - memset(&thread_stats[threadnum], 0, sizeof(thread_stats[threadnum])); - } - - /* accumulate/reset statistics from the LFB */ - if (accumulate) - accumulate_statistics(fbi.lfb_stats); - memset(&fbi.lfb_stats, 0, sizeof(fbi.lfb_stats)); -} - - - -/************************************* - * - * VBLANK management - * - *************************************/ - -void voodoo_device::swap_buffers(voodoo_device *vd) -{ - int count; - - if (LOG_VBLANK_SWAP) vd->logerror("--- swap_buffers @ %d\n", vd->m_screen->vpos()); - - /* force a partial update */ - vd->m_screen->update_partial(vd->m_screen->vpos()); - vd->fbi.video_changed = true; - - /* keep a history of swap intervals */ - count = vd->fbi.vblank_count; - if (count > 15) - count = 15; - vd->reg[fbiSwapHistory].u = (vd->reg[fbiSwapHistory].u << 4) | count; - - /* rotate the buffers */ - if (vd->vd_type <= TYPE_VOODOO_2) - { - if (vd->vd_type < TYPE_VOODOO_2 || !vd->fbi.vblank_dont_swap) + // compute the R/B pens first + u8 rtable[32], gtable[64], btable[32]; + for (u32 rawcolor = 0; rawcolor < 32; rawcolor++) { - if (vd->fbi.rgboffs[2] == ~0) - { - vd->fbi.frontbuf = 1 - vd->fbi.frontbuf; - vd->fbi.backbuf = 1 - vd->fbi.frontbuf; - } - else - { - vd->fbi.frontbuf = (vd->fbi.frontbuf + 1) % 3; - vd->fbi.backbuf = (vd->fbi.frontbuf + 1) % 3; - } + // treat rawcolor as a 5-bit value, scale up to 8 bits, and linear interpolate for red/blue + u32 color = pal5bit(rawcolor); + rtable[rawcolor] = (clutbase[color >> 3].r() * (8 - (color & 7)) + clutbase[(color >> 3) + 1].r() * (color & 7)) >> 3; + btable[rawcolor] = (clutbase[color >> 3].b() * (8 - (color & 7)) + clutbase[(color >> 3) + 1].b() * (color & 7)) >> 3; } - } - else - vd->fbi.rgboffs[0] = vd->reg[leftOverlayBuf].u & vd->fbi.mask & ~0x0f; - /* decrement the pending count and reset our state */ - if (vd->fbi.swaps_pending) - vd->fbi.swaps_pending--; - vd->fbi.vblank_count = 0; - vd->fbi.vblank_swap_pending = false; - - /* reset the last_op_time to now and start processing the next command */ - if (vd->pci.op_pending) - { - if (LOG_VBLANK_SWAP) vd->logerror("---- swap_buffers flush begin\n"); - vd->pci.op_end_time = vd->machine().time(); - flush_fifos(vd, vd->pci.op_end_time); - if (LOG_VBLANK_SWAP) vd->logerror("---- swap_buffers flush end\n"); - } - - /* we may be able to unstall now */ - if (vd->pci.stall_state != NOT_STALLED) - vd->check_stalled_cpu(vd->machine().time()); - - /* periodically log rasterizer info */ - vd->stats.swaps++; - if (LOG_RASTERIZERS && vd->stats.swaps % 1000 == 0) - dump_rasterizer_stats(vd); - - /* update the statistics (debug) */ - if (vd->stats.display) - { - const rectangle &visible_area = vd->m_screen->visible_area(); - int screen_area = visible_area.width() * visible_area.height(); - char *statsptr = vd->stats.buffer; - int pixelcount; - int i; - - vd->update_statistics(true); - pixelcount = vd->stats.total_pixels_out; - - statsptr += sprintf(statsptr, "Swap:%6d\n", vd->stats.swaps); - statsptr += sprintf(statsptr, "Hist:%08X\n", vd->reg[fbiSwapHistory].u); - statsptr += sprintf(statsptr, "Stal:%6d\n", vd->stats.stalls); - statsptr += sprintf(statsptr, "Rend:%6d%%\n", pixelcount * 100 / screen_area); - statsptr += sprintf(statsptr, "Poly:%6d\n", vd->stats.total_triangles); - statsptr += sprintf(statsptr, "PxIn:%6d\n", vd->stats.total_pixels_in); - statsptr += sprintf(statsptr, "POut:%6d\n", vd->stats.total_pixels_out); - statsptr += sprintf(statsptr, "Clip:%6d\n", vd->stats.total_clipped); - statsptr += sprintf(statsptr, "Stip:%6d\n", vd->stats.total_stippled); - statsptr += sprintf(statsptr, "Chro:%6d\n", vd->stats.total_chroma_fail); - statsptr += sprintf(statsptr, "ZFun:%6d\n", vd->stats.total_zfunc_fail); - statsptr += sprintf(statsptr, "AFun:%6d\n", vd->stats.total_afunc_fail); - statsptr += sprintf(statsptr, "RegW:%6d\n", vd->stats.reg_writes); - statsptr += sprintf(statsptr, "RegR:%6d\n", vd->stats.reg_reads); - statsptr += sprintf(statsptr, "LFBW:%6d\n", vd->stats.lfb_writes); - statsptr += sprintf(statsptr, "LFBR:%6d\n", vd->stats.lfb_reads); - statsptr += sprintf(statsptr, "TexW:%6d\n", vd->stats.tex_writes); - statsptr += sprintf(statsptr, "TexM:"); - for (i = 0; i < 16; i++) - if (vd->stats.texture_mode[i]) - *statsptr++ = "0123456789ABCDEF"[i]; - *statsptr = 0; - } - - /* update statistics */ - vd->stats.stalls = 0; - vd->stats.total_triangles = 0; - vd->stats.total_pixels_in = 0; - vd->stats.total_pixels_out = 0; - vd->stats.total_chroma_fail = 0; - vd->stats.total_zfunc_fail = 0; - vd->stats.total_afunc_fail = 0; - vd->stats.total_clipped = 0; - vd->stats.total_stippled = 0; - vd->stats.reg_writes = 0; - vd->stats.reg_reads = 0; - vd->stats.lfb_writes = 0; - vd->stats.lfb_reads = 0; - vd->stats.tex_writes = 0; - memset(vd->stats.texture_mode, 0, sizeof(vd->stats.texture_mode)); -} - - -void voodoo_device::adjust_vblank_timer() -{ - attotime vblank_period = m_screen->time_until_pos(fbi.vsyncstart); - if (LOG_VBLANK_SWAP) logerror("adjust_vblank_timer: period: %s\n", vblank_period.as_string()); - /* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */ - if (vblank_period == attotime::zero) - vblank_period = m_screen->frame_period(); - fbi.vsync_start_timer->adjust(vblank_period); -} - - -TIMER_CALLBACK_MEMBER( voodoo_device::vblank_off_callback ) -{ - if (LOG_VBLANK_SWAP) logerror("--- vblank end\n"); - - /* set internal state and call the client */ - fbi.vblank = false; - - // PCI Vblank IRQ enable is VOODOO2 and up - if (vd_type >= TYPE_VOODOO_2) - { - if (reg[intrCtrl].u & 0x8) // call IRQ handler if VSYNC interrupt (falling) is enabled + // then the G pens + for (u32 rawcolor = 0; rawcolor < 64; rawcolor++) { - reg[intrCtrl].u |= 0x200; // VSYNC int (falling) active - reg[intrCtrl].u &= ~0x80000000; - if (!m_pciint.isnull()) - m_pciint(true); - - } - } - // External vblank handler - if (!m_vblank.isnull()) - m_vblank(false); - - /* go to the end of the next frame */ - adjust_vblank_timer(); -} - - -TIMER_CALLBACK_MEMBER( voodoo_device::vblank_callback ) -{ - if (LOG_VBLANK_SWAP) logerror("--- vblank start\n"); - - /* flush the pipes */ - if (pci.op_pending) - { - if (LOG_VBLANK_SWAP) logerror("---- vblank flush begin\n"); - flush_fifos(this, machine().time()); - if (LOG_VBLANK_SWAP) logerror("---- vblank flush end\n"); - } - - /* increment the count */ - fbi.vblank_count++; - if (fbi.vblank_count > 250) - fbi.vblank_count = 250; - if (LOG_VBLANK_SWAP) logerror("---- vblank count = %u swap = %u pending = %u", fbi.vblank_count, fbi.vblank_swap, fbi.vblank_swap_pending); - if (fbi.vblank_swap_pending) - if (LOG_VBLANK_SWAP) logerror(" (target=%d)", fbi.vblank_swap); - if (LOG_VBLANK_SWAP) logerror("\n"); - - /* if we're past the swap count, do the swap */ - if (fbi.vblank_swap_pending && fbi.vblank_count >= fbi.vblank_swap) - swap_buffers(this); - - /* set a timer for the next off state */ - fbi.vsync_stop_timer->adjust(m_screen->time_until_pos(fbi.vsyncstop)); - - - - /* set internal state and call the client */ - fbi.vblank = true; - - // PCI Vblank IRQ enable is VOODOO2 and up - if (vd_type >= TYPE_VOODOO_2) - { - if (reg[intrCtrl].u & 0x4) // call IRQ handler if VSYNC interrupt (rising) is enabled - { - reg[intrCtrl].u |= 0x100; // VSYNC int (rising) active - reg[intrCtrl].u &= ~0x80000000; - if (!m_pciint.isnull()) - m_pciint(true); - } - } - // External vblank handler - if (!m_vblank.isnull()) - m_vblank(true); -} - - - -/************************************* - * - * Chip reset - * - *************************************/ - -void voodoo_device::reset_counters() -{ - update_statistics(false); - reg[fbiPixelsIn].u = 0; - reg[fbiChromaFail].u = 0; - reg[fbiZfuncFail].u = 0; - reg[fbiAfuncFail].u = 0; - reg[fbiPixelsOut].u = 0; -} - - -void voodoo_device::soft_reset() -{ - reset_counters(); - reg[fbiTrianglesOut].u = 0; - fbi.fifo.reset(); - pci.fifo.reset(); -} - - - -/************************************* - * - * Recompute video memory layout - * - *************************************/ - -void voodoo_device::recompute_video_memory() -{ - uint32_t const buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(reg[fbiInit2].u); - uint32_t const fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(reg[fbiInit4].u); - uint32_t fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(reg[fbiInit4].u); - uint32_t memory_config; - - /* memory config is determined differently between V1 and V2 */ - memory_config = FBIINIT2_ENABLE_TRIPLE_BUF(reg[fbiInit2].u); - if (vd_type == TYPE_VOODOO_2 && memory_config == 0) - memory_config = FBIINIT5_BUFFER_ALLOCATION(reg[fbiInit5].u); - - /* tiles are 64x16/32; x_tiles specifies how many half-tiles */ - fbi.tile_width = (vd_type == TYPE_VOODOO_1) ? 64 : 32; - fbi.tile_height = (vd_type == TYPE_VOODOO_1) ? 16 : 32; - fbi.x_tiles = FBIINIT1_X_VIDEO_TILES(reg[fbiInit1].u); - if (vd_type == TYPE_VOODOO_2) - { - fbi.x_tiles = (fbi.x_tiles << 1) | - (FBIINIT1_X_VIDEO_TILES_BIT5(reg[fbiInit1].u) << 5) | - (FBIINIT6_X_VIDEO_TILES_BIT0(reg[fbiInit6].u)); - } - fbi.rowpixels = fbi.tile_width * fbi.x_tiles; - -// logerror("VOODOO.VIDMEM: buffer_pages=%X fifo=%X-%X tiles=%X rowpix=%d\n", buffer_pages, fifo_start_page, fifo_last_page, fbi.x_tiles, fbi.rowpixels); - - /* first RGB buffer always starts at 0 */ - fbi.rgboffs[0] = 0; - - /* second RGB buffer starts immediately afterwards */ - fbi.rgboffs[1] = buffer_pages * 0x1000; - - /* remaining buffers are based on the config */ - switch (memory_config) - { - case 3: /* reserved */ - logerror("VOODOO.ERROR:Unexpected memory configuration in recompute_video_memory!\n"); - [[fallthrough]]; - case 0: /* 2 color buffers, 1 aux buffer */ - fbi.rgboffs[2] = ~0; - fbi.auxoffs = 2 * buffer_pages * 0x1000; - break; - - case 1: /* 3 color buffers, 0 aux buffers */ - fbi.rgboffs[2] = 2 * buffer_pages * 0x1000; - fbi.auxoffs = ~0; - break; - - case 2: /* 3 color buffers, 1 aux buffers */ - fbi.rgboffs[2] = 2 * buffer_pages * 0x1000; - fbi.auxoffs = 3 * buffer_pages * 0x1000; - break; - } - - /* clamp the RGB buffers to video memory */ - for (int buf = 0; buf < 3; buf++) - if (fbi.rgboffs[buf] != ~0 && fbi.rgboffs[buf] > fbi.mask) - fbi.rgboffs[buf] = fbi.mask; - - /* clamp the aux buffer to video memory */ - if (fbi.auxoffs != ~0 && fbi.auxoffs > fbi.mask) - fbi.auxoffs = fbi.mask; - -/* osd_printf_debug("rgb[0] = %08X rgb[1] = %08X rgb[2] = %08X aux = %08X\n", - fbi.rgboffs[0], fbi.rgboffs[1], fbi.rgboffs[2], fbi.auxoffs);*/ - - /* compute the memory FIFO location and size */ - if (fifo_last_page > fbi.mask / 0x1000) - fifo_last_page = fbi.mask / 0x1000; - - /* is it valid and enabled? */ - if (fifo_start_page <= fifo_last_page && FBIINIT0_ENABLE_MEMORY_FIFO(reg[fbiInit0].u)) - { - fbi.fifo.base = (uint32_t *)(fbi.ram + fifo_start_page * 0x1000); - fbi.fifo.size = (fifo_last_page + 1 - fifo_start_page) * 0x1000 / 4; - if (fbi.fifo.size > 65536*2) - fbi.fifo.size = 65536*2; - } - - /* if not, disable the FIFO */ - else - { - fbi.fifo.base = nullptr; - fbi.fifo.size = 0; - } - - /* reset the FIFO */ - fbi.fifo.reset(); - - /* reset our front/back buffers if they are out of range */ - if (fbi.rgboffs[2] == ~0) - { - if (fbi.frontbuf == 2) - fbi.frontbuf = 0; - if (fbi.backbuf == 2) - fbi.backbuf = 0; - } -} - - - -/************************************* - * - * NCC table management - * - *************************************/ - -void voodoo_device::tmu_state::ncc_table::write(offs_t regnum, uint32_t data) -{ - /* I/Q entries reference the plaette if the high bit is set */ - if (regnum >= 4 && (data & 0x80000000) && palette) - { - int const index = ((data >> 23) & 0xfe) | (regnum & 1); - - /* set the ARGB for this palette index */ - palette[index] = 0xff000000 | data; - - /* if we have an ARGB palette as well, compute its value */ - if (palettea) - { - int a = ((data >> 16) & 0xfc) | ((data >> 22) & 0x03); - int r = ((data >> 10) & 0xfc) | ((data >> 16) & 0x03); - int g = ((data >> 4) & 0xfc) | ((data >> 10) & 0x03); - int b = ((data << 2) & 0xfc) | ((data >> 4) & 0x03); - palettea[index] = rgb_t(a, r, g, b); + // treat rawcolor as a 6-bit value, scale up to 8 bits, and linear interpolate + u32 color = pal6bit(rawcolor); + gtable[rawcolor] = (clutbase[color >> 3].g() * (8 - (color & 7)) + clutbase[(color >> 3) + 1].g() * (color & 7)) >> 3; } - /* this doesn't dirty the table or go to the registers, so bail */ - return; + // now assemble the values into their final form + for (u32 pen = 0; pen < 65536; pen++) + m_pen[pen] = rgb_t(rtable[BIT(pen, 11, 5)], gtable[BIT(pen, 5, 6)], btable[BIT(pen, 0, 5)]); + + // no longer dirty + m_clut_dirty = false; + m_video_changed = true; } - - /* if the register matches, don't update */ - if (data == reg[regnum].u) - return; - reg[regnum].u = data; - - /* first four entries are packed Y values */ - if (regnum < 4) - { - regnum *= 4; - y[regnum+0] = (data >> 0) & 0xff; - y[regnum+1] = (data >> 8) & 0xff; - y[regnum+2] = (data >> 16) & 0xff; - y[regnum+3] = (data >> 24) & 0xff; - } - - /* the second four entries are the I RGB values */ - else if (regnum < 8) - { - regnum &= 3; - ir[regnum] = (int32_t)(data << 5) >> 23; - ig[regnum] = (int32_t)(data << 14) >> 23; - ib[regnum] = (int32_t)(data << 23) >> 23; - } - - /* the final four entries are the Q RGB values */ - else - { - regnum &= 3; - qr[regnum] = (int32_t)(data << 5) >> 23; - qg[regnum] = (int32_t)(data << 14) >> 23; - qb[regnum] = (int32_t)(data << 23) >> 23; - } - - /* mark the table dirty */ - dirty = true; + return update_common(bitmap, cliprect, &m_pen[0]); } -void voodoo_device::tmu_state::ncc_table::update() +//------------------------------------------------- +// device_start - device startup +//------------------------------------------------- + +void voodoo_1_device::device_start() { - /* generte all 256 possibilities */ - for (int i = 0; i < 256; i++) - { - int vi = (i >> 2) & 0x03; - int vq = (i >> 0) & 0x03; + // resolve configuration-related items + generic_voodoo_device::device_start(); - /* start with the intensity */ - int r, g, b; - r = g = b = y[(i >> 4) & 0x0f]; + // validate configuration + if (m_fbmem_in_mb == 0) + fatalerror("%s: Invalid Voodoo memory configuration", tag()); + if (!BIT(m_chipmask, 1) && m_tmumem0_in_mb == 0) + fatalerror("%s: Invalid Voodoo memory configuration", tag()); - /* add the coloring */ - r += ir[vi] + qr[vq]; - g += ig[vi] + qg[vq]; - b += ib[vi] + qb[vq]; + // create shared tables + m_shared = std::make_unique(); + voodoo::dither_helper::init_static(); - /* clamp */ - CLAMP(r, 0, 255); - CLAMP(g, 0, 255); - CLAMP(b, 0, 255); - - /* fill in the table */ - texel[i] = rgb_t(0xff, r, g, b); - } - - /* no longer dirty */ - dirty = false; -} - - - -/************************************* - * - * Faux DAC implementation - * - *************************************/ - -void voodoo_device::dac_state::data_w(uint8_t regnum, uint8_t data) -{ - reg[regnum] = data; -} - - -void voodoo_device::dac_state::data_r(uint8_t regnum) -{ - uint8_t result = 0xff; - - /* switch off the DAC register requested */ - switch (regnum) - { - case 5: - /* this is just to make startup happy */ - switch (reg[7]) - { - case 0x01: result = 0x55; break; - case 0x07: result = 0x71; break; - case 0x0b: result = 0x79; break; - } - break; - - default: - result = reg[regnum]; - break; - } - - /* remember the read result; it is fetched elsewhere */ - read_result = result; -} - - - -/************************************* - * - * Texuture parameter computation - * - *************************************/ - -void voodoo_device::tmu_state::recompute_texture_params() -{ - int bppscale; - uint32_t base; - int lod; - - /* extract LOD parameters */ - lodmin = TEXLOD_LODMIN(reg[tLOD].u) << 6; - lodmax = TEXLOD_LODMAX(reg[tLOD].u) << 6; - lodbias = (int8_t)(TEXLOD_LODBIAS(reg[tLOD].u) << 2) << 4; - - /* determine which LODs are present */ - lodmask = 0x1ff; - if (TEXLOD_LOD_TSPLIT(reg[tLOD].u)) - { - if (!TEXLOD_LOD_ODD(reg[tLOD].u)) - lodmask = 0x155; - else - lodmask = 0x0aa; - } - - /* determine base texture width/height */ - wmask = hmask = 0xff; - if (TEXLOD_LOD_S_IS_WIDER(reg[tLOD].u)) - hmask >>= TEXLOD_LOD_ASPECT(reg[tLOD].u); - else - wmask >>= TEXLOD_LOD_ASPECT(reg[tLOD].u); - - /* determine the bpp of the texture */ - bppscale = TEXMODE_FORMAT(reg[textureMode].u) >> 3; - - /* start with the base of LOD 0 */ - if (texaddr_shift == 0 && (reg[texBaseAddr].u & 1)) - osd_printf_debug("Tiled texture\n"); - base = (reg[texBaseAddr].u & texaddr_mask) << texaddr_shift; - lodoffset[0] = base & mask; - - /* LODs 1-3 are different depending on whether we are in multitex mode */ - /* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */ - /* they want multitex mode when they really don't -- disable for now */ - // Enable for Voodoo 3 or Viper breaks - VL. - // Add check for upper nibble not equal to zero to fix funkball -- TG - if (TEXLOD_TMULTIBASEADDR(reg[tLOD].u) && (reg[tLOD].u >> 28) == 0) - { - base = (reg[texBaseAddr_1].u & texaddr_mask) << texaddr_shift; - lodoffset[1] = base & mask; - base = (reg[texBaseAddr_2].u & texaddr_mask) << texaddr_shift; - lodoffset[2] = base & mask; - base = (reg[texBaseAddr_3_8].u & texaddr_mask) << texaddr_shift; - lodoffset[3] = base & mask; - } - else - { - if (lodmask & (1 << 0)) - base += (((wmask >> 0) + 1) * ((hmask >> 0) + 1)) << bppscale; - lodoffset[1] = base & mask; - if (lodmask & (1 << 1)) - base += (((wmask >> 1) + 1) * ((hmask >> 1) + 1)) << bppscale; - lodoffset[2] = base & mask; - if (lodmask & (1 << 2)) - base += (((wmask >> 2) + 1) * ((hmask >> 2) + 1)) << bppscale; - lodoffset[3] = base & mask; - } - - /* remaining LODs make sense */ - for (lod = 4; lod <= 8; lod++) - { - if (lodmask & (1 << (lod - 1))) - { - uint32_t size = ((wmask >> (lod - 1)) + 1) * ((hmask >> (lod - 1)) + 1); - if (size < 4) size = 4; - base += size << bppscale; - } - lodoffset[lod] = base & mask; - } - - /* set the NCC lookup appropriately */ - texel[1] = texel[9] = ncc[TEXMODE_NCC_TABLE_SELECT(reg[textureMode].u)].texel; - - /* pick the lookup table */ - lookup = texel[TEXMODE_FORMAT(reg[textureMode].u)]; - - /* compute the detail parameters */ - detailmax = TEXDETAIL_DETAIL_MAX(reg[tDetail].u); - detailbias = (int8_t)(TEXDETAIL_DETAIL_BIAS(reg[tDetail].u) << 2) << 6; - detailscale = TEXDETAIL_DETAIL_SCALE(reg[tDetail].u); - - /* ensure that the NCC tables are up to date */ - if ((TEXMODE_FORMAT(reg[textureMode].u) & 7) == 1) - { - ncc_table &n = ncc[TEXMODE_NCC_TABLE_SELECT(reg[textureMode].u)]; - texel[1] = texel[9] = n.texel; - if (n.dirty) - n.update(); - } - - /* no longer dirty */ - regdirty = false; - - /* check for separate RGBA filtering */ - if (TEXDETAIL_SEPARATE_RGBA_FILTER(reg[tDetail].u)) - fatalerror("Separate RGBA filters!\n"); -} - - -inline int32_t voodoo_device::tmu_state::prepare() -{ - int64_t texdx, texdy; - int32_t lodbase; - - /* if the texture parameters are dirty, update them */ - if (regdirty) - recompute_texture_params(); - - /* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */ - texdx = int64_t(dsdx >> 14) * int64_t(dsdx >> 14) + int64_t(dtdx >> 14) * int64_t(dtdx >> 14); - texdy = int64_t(dsdy >> 14) * int64_t(dsdy >> 14) + int64_t(dtdy >> 14) * int64_t(dtdy >> 14); - - /* pick whichever is larger and shift off some high bits -> 28.20 */ - if (texdx < texdy) - texdx = texdy; - texdx >>= 16; - - /* use our fast reciprocal/log on this value; it expects input as a */ - /* 16.32 number, and returns the log of the reciprocal, so we have to */ - /* adjust the result: negative to get the log of the original value */ - /* plus 12 to account for the extra exponent, and divided by 2 to */ - /* get the log of the square root of texdx */ -#if USE_FAST_RECIP == 1 - (void)fast_reciplog(texdx, &lodbase); - return (-lodbase + (12 << 8)) / 2; -#else - double tmpTex = texdx; - lodbase = new_log2(tmpTex, 0); - return (lodbase + (12 << 8)) / 2; -#endif -} - - - -/************************************* - * - * Command FIFO depth computation - * - *************************************/ - -int voodoo_device::cmdfifo_compute_expected_depth(cmdfifo_info &f) -{ - uint32_t *fifobase = (uint32_t *)fbi.ram; - uint32_t readptr = f.rdptr; - uint32_t command = fifobase[readptr / 4]; - int i, count = 0; - - /* low 3 bits specify the packet type */ - switch (command & 7) - { - /* - Packet type 0: 1 or 2 words - - Word Bits - 0 31:29 = reserved - 0 28:6 = Address [24:2] - 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) - 0 2:0 = Packet type (0) - 1 31:11 = reserved (JMP AGP only) - 1 10:0 = Address [35:25] - */ - case 0: - if (((command >> 3) & 7) == 4) - return 2; - return 1; - - /* - Packet type 1: 1 + N words - - Word Bits - 0 31:16 = Number of words - 0 15 = Increment? - 0 14:3 = Register base - 0 2:0 = Packet type (1) - 1 31:0 = Data word - */ - case 1: - return 1 + (command >> 16); - - /* - Packet type 2: 1 + N words - - Word Bits - 0 31:3 = 2D Register mask - 0 2:0 = Packet type (2) - 1 31:0 = Data word - */ - case 2: - for (i = 3; i <= 31; i++) - if (command & (1 << i)) count++; - return 1 + count; - - /* - Packet type 3: 1 + N words - - Word Bits - 0 31:29 = Number of dummy entries following the data - 0 28 = Packed color data? - 0 25 = Disable ping pong sign correction (0=normal, 1=disable) - 0 24 = Culling sign (0=positive, 1=negative) - 0 23 = Enable culling (0=disable, 1=enable) - 0 22 = Strip mode (0=strip, 1=fan) - 0 17 = Setup S1 and T1 - 0 16 = Setup W1 - 0 15 = Setup S0 and T0 - 0 14 = Setup W0 - 0 13 = Setup Wb - 0 12 = Setup Z - 0 11 = Setup Alpha - 0 10 = Setup RGB - 0 9:6 = Number of vertices - 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) - 0 2:0 = Packet type (3) - 1 31:0 = Data word - */ - case 3: - count = 2; /* X/Y */ - if (command & (1 << 28)) - { - if (command & (3 << 10)) count++; /* ARGB */ - } - else - { - if (command & (1 << 10)) count += 3; /* RGB */ - if (command & (1 << 11)) count++; /* A */ - } - if (command & (1 << 12)) count++; /* Z */ - if (command & (1 << 13)) count++; /* Wb */ - if (command & (1 << 14)) count++; /* W0 */ - if (command & (1 << 15)) count += 2; /* S0/T0 */ - if (command & (1 << 16)) count++; /* W1 */ - if (command & (1 << 17)) count += 2; /* S1/T1 */ - count *= (command >> 6) & 15; /* numverts */ - return 1 + count + (command >> 29); - - /* - Packet type 4: 1 + N words - - Word Bits - 0 31:29 = Number of dummy entries following the data - 0 28:15 = General register mask - 0 14:3 = Register base - 0 2:0 = Packet type (4) - 1 31:0 = Data word - */ - case 4: - for (i = 15; i <= 28; i++) - if (command & (1 << i)) count++; - return 1 + count + (command >> 29); - - /* - Packet type 5: 2 + N words - - Word Bits - 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) - 0 29:26 = Byte disable W2 - 0 25:22 = Byte disable WN - 0 21:3 = Num words - 0 2:0 = Packet type (5) - 1 31:30 = Reserved - 1 29:0 = Base address [24:0] - 2 31:0 = Data word - */ - case 5: - return 2 + ((command >> 3) & 0x7ffff); - - default: - osd_printf_debug("UNKNOWN PACKET TYPE %d\n", command & 7); - return 1; - } -} - - - -/************************************* - * - * Command FIFO execution - * - *************************************/ - -uint32_t voodoo_device::cmdfifo_execute(voodoo_device *vd, cmdfifo_info *f) -{ - uint32_t *fifobase = (uint32_t *)vd->fbi.ram; - uint32_t readptr = f->rdptr; - uint32_t *src = &fifobase[readptr / 4]; - uint32_t command = *src++; - int count, inc, code, i; - fbi_state::setup_vertex svert = {0}; - offs_t target; - int cycles = 0; - - switch (command & 7) - { - /* - Packet type 0: 1 or 2 words - - Word Bits - 0 31:29 = reserved - 0 28:6 = Address [24:2] - 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) - 0 2:0 = Packet type (0) - 1 31:11 = reserved (JMP AGP only) - 1 10:0 = Address [35:25] - */ - case 0: - - /* extract parameters */ - target = (command >> 4) & 0x1fffffc; - - /* switch off of the specific command */ - switch ((command >> 3) & 7) - { - case 0: /* NOP */ - if (LOG_CMDFIFO) vd->logerror(" NOP\n"); - break; - - case 1: /* JSR */ - if (LOG_CMDFIFO) vd->logerror(" JSR $%06X\n", target); - osd_printf_debug("JSR in CMDFIFO!\n"); - src = &fifobase[target / 4]; - break; - - case 2: /* RET */ - if (LOG_CMDFIFO) vd->logerror(" RET $%06X\n", target); - fatalerror("RET in CMDFIFO!\n"); - - case 3: /* JMP LOCAL FRAME BUFFER */ - if (LOG_CMDFIFO) vd->logerror(" JMP LOCAL FRAMEBUF $%06X\n", target); - src = &fifobase[target / 4]; - break; - - case 4: /* JMP AGP */ - if (LOG_CMDFIFO) vd->logerror(" JMP AGP $%06X\n", target); - fatalerror("JMP AGP in CMDFIFO!\n"); - src = &fifobase[target / 4]; - break; - - default: - osd_printf_debug("INVALID JUMP COMMAND!\n"); - fatalerror(" INVALID JUMP COMMAND\n"); - } - break; - - /* - Packet type 1: 1 + N words - - Word Bits - 0 31:16 = Number of words - 0 15 = Increment? - 0 14:3 = Register base - 0 2:0 = Packet type (1) - 1 31:0 = Data word - */ - case 1: - - /* extract parameters */ - count = command >> 16; - inc = (command >> 15) & 1; - target = (command >> 3) & 0xfff; - - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target); - - if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (target & 0x800)) - { - // Banshee/Voodoo3 2D register writes - - /* loop over all registers and write them one at a time */ - for (i = 0; i < count; i++, target += inc) - { - cycles += banshee_2d_w(vd, target & 0xff, *src); - //logerror(" 2d reg: %03x = %08X\n", target & 0x7ff, *src); - src++; - } - } - else - { - /* loop over all registers and write them one at a time */ - for (i = 0; i < count; i++, target += inc) - cycles += register_w(vd, target, *src++); - } - break; - - /* - Packet type 2: 1 + N words - - Word Bits - 0 31:3 = 2D Register mask - 0 2:0 = Packet type (2) - 1 31:0 = Data word - */ - case 2: - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 2: mask=%X\n", (command >> 3) & 0x1ffffff); - - /* loop over all registers and write them one at a time */ - for (i = 3; i <= 31; i++) - if (command & (1 << i)) - cycles += register_w(vd, banshee2D_clip0Min + (i - 3), *src++); - break; - - /* - Packet type 3: 1 + N words - - Word Bits - 0 31:29 = Number of dummy entries following the data - 0 28 = Packed color data? - 0 25 = Disable ping pong sign correction (0=normal, 1=disable) - 0 24 = Culling sign (0=positive, 1=negative) - 0 23 = Enable culling (0=disable, 1=enable) - 0 22 = Strip mode (0=strip, 1=fan) - 0 17 = Setup S1 and T1 - 0 16 = Setup W1 - 0 15 = Setup S0 and T0 - 0 14 = Setup W0 - 0 13 = Setup Wb - 0 12 = Setup Z - 0 11 = Setup Alpha - 0 10 = Setup RGB - 0 9:6 = Number of vertices - 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) - 0 2:0 = Packet type (3) - 1 31:0 = Data word - */ - case 3: - - /* extract parameters */ - count = (command >> 6) & 15; - code = (command >> 3) & 7; - - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 3: count=%d code=%d mask=%03X smode=%02X pc=%d\n", count, code, (command >> 10) & 0xfff, (command >> 22) & 0x3f, (command >> 28) & 1); - - /* copy relevant bits into the setup mode register */ - vd->reg[sSetupMode].u = ((command >> 10) & 0xff) | ((command >> 6) & 0xf0000); - - /* loop over triangles */ - for (i = 0; i < count; i++) - { - /* always extract X/Y */ - svert.x = *(float *)src++; - svert.y = *(float *)src++; - - /* load ARGB values if packed */ - if (command & (1 << 28)) - { - if (command & (3 << 10)) - { - rgb_t argb = *src++; - if (command & (1 << 10)) - { - svert.r = argb.r(); - svert.g = argb.g(); - svert.b = argb.b(); - } - if (command & (1 << 11)) - svert.a = argb.a(); - } - } - - /* load ARGB values if not packed */ - else - { - if (command & (1 << 10)) - { - svert.r = *(float *)src++; - svert.g = *(float *)src++; - svert.b = *(float *)src++; - } - if (command & (1 << 11)) - svert.a = *(float *)src++; - } - - /* load Z and Wb values */ - if (command & (1 << 12)) - svert.z = *(float *)src++; - if (command & (1 << 13)) - svert.wb = svert.w0 = svert.w1 = *(float *)src++; - - /* load W0, S0, T0 values */ - if (command & (1 << 14)) - svert.w0 = svert.w1 = *(float *)src++; - if (command & (1 << 15)) - { - svert.s0 = svert.s1 = *(float *)src++; - svert.t0 = svert.t1 = *(float *)src++; - } - - /* load W1, S1, T1 values */ - if (command & (1 << 16)) - svert.w1 = *(float *)src++; - if (command & (1 << 17)) - { - svert.s1 = *(float *)src++; - svert.t1 = *(float *)src++; - } - - /* if we're starting a new strip, or if this is the first of a set of verts */ - /* for a series of individual triangles, initialize all the verts */ - if ((code == 1 && i == 0) || (code == 0 && i % 3 == 0)) - { - vd->fbi.sverts = 1; - vd->fbi.svert[0] = vd->fbi.svert[1] = vd->fbi.svert[2] = svert; - } - - /* otherwise, add this to the list */ - else - { - /* for strip mode, shuffle vertex 1 down to 0 */ - if (!(command & (1 << 22))) - vd->fbi.svert[0] = vd->fbi.svert[1]; - - /* copy 2 down to 1 and add our new one regardless */ - vd->fbi.svert[1] = vd->fbi.svert[2]; - vd->fbi.svert[2] = svert; - - /* if we have enough, draw */ - if (++vd->fbi.sverts >= 3) - cycles += setup_and_draw_triangle(vd); - } - } - - /* account for the extra dummy words */ - src += command >> 29; - break; - - /* - Packet type 4: 1 + N words - - Word Bits - 0 31:29 = Number of dummy entries following the data - 0 28:15 = General register mask - 0 14:3 = Register base - 0 2:0 = Packet type (4) - 1 31:0 = Data word - */ - case 4: - - /* extract parameters */ - target = (command >> 3) & 0xfff; - - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", (command >> 15) & 0x3fff, target, command >> 29); - - if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (target & 0x800)) - { - // Banshee/Voodoo3 2D register writes - - /* loop over all registers and write them one at a time */ - target &= 0xff; - for (i = 15; i <= 28; i++) - { - if (command & (1 << i)) - { - cycles += banshee_2d_w(vd, target + (i - 15), *src); - //logerror(" 2d reg: %03x = %08X\n", target & 0x7ff, *src); - src++; - } - } - } - else - { - /* loop over all registers and write them one at a time */ - for (i = 15; i <= 28; i++) - if (command & (1 << i)) - cycles += register_w(vd, target + (i - 15), *src++); - } - - /* account for the extra dummy words */ - src += command >> 29; - break; - - /* - Packet type 5: 2 + N words - - Word Bits - 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) - 0 29:26 = Byte disable W2 - 0 25:22 = Byte disable WN - 0 21:3 = Num words - 0 2:0 = Packet type (5) - 1 31:30 = Reserved - 1 29:0 = Base address [24:0] - 2 31:0 = Data word - */ - case 5: - - /* extract parameters */ - count = (command >> 3) & 0x7ffff; - target = *src++ / 4; - - /* handle LFB writes */ - switch (command >> 30) - { - case 0: // Linear FB - { - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 5: FB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); - - uint32_t addr = target * 4; - for (i=0; i < count; i++) - { - uint32_t data = *src++; - - vd->fbi.ram[BYTE_XOR_LE(addr + 0)] = (uint8_t)(data); - vd->fbi.ram[BYTE_XOR_LE(addr + 1)] = (uint8_t)(data >> 8); - vd->fbi.ram[BYTE_XOR_LE(addr + 2)] = (uint8_t)(data >> 16); - vd->fbi.ram[BYTE_XOR_LE(addr + 3)] = (uint8_t)(data >> 24); - - addr += 4; - } - break; - } - case 2: // 3D LFB - { - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 5: 3D LFB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); - - /* loop over words */ - for (i = 0; i < count; i++) - cycles += lfb_w(vd, target++, *src++, 0xffffffff); - - break; - } - - case 1: // Planar YUV - { - // TODO - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 5: Planar YUV count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); - - /* just update the pointers for now */ - for (i = 0; i < count; i++) - { - target++; - src++; - } - - break; - } - - case 3: // Texture Port - { - if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 5: textureRAM count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); - - /* loop over words */ - for (i = 0; i < count; i++) - cycles += texture_w(vd, target++, *src++); - - break; - } - } - - break; - - default: - fprintf(stderr, "PACKET TYPE %d\n", command & 7); - break; - } - - /* by default just update the read pointer past all the data we consumed */ - f->rdptr = 4 * (src - fifobase); - return cycles; -} - - - -/************************************* - * - * Handle execution if we're ready - * - *************************************/ - -int32_t voodoo_device::cmdfifo_execute_if_ready(cmdfifo_info &f) -{ - /* all CMDFIFO commands need at least one word */ - if (f.depth == 0) - return -1; - - /* see if we have enough for the current command */ - int const needed_depth = cmdfifo_compute_expected_depth(f); - if (f.depth < needed_depth) - return -1; - - /* execute */ - int const cycles = cmdfifo_execute(this, &f); - f.depth -= needed_depth; - return cycles; -} - - - -/************************************* - * - * Handle writes to the CMD FIFO - * - *************************************/ - -void voodoo_device::cmdfifo_w(voodoo_device *vd, cmdfifo_info *f, offs_t offset, uint32_t data) -{ - uint32_t addr = f->base + offset * 4; - uint32_t *fifobase = (uint32_t *)vd->fbi.ram; - - if (LOG_CMDFIFO_VERBOSE) vd->logerror("CMDFIFO_w(%04X) = %08X\n", offset, data); - - /* write the data */ - if (addr < f->end) - fifobase[addr / 4] = data; - - /* count holes? */ - if (f->count_holes) - { - /* in-order, no holes */ - if (f->holes == 0 && addr == f->amin + 4) - { - f->amin = f->amax = addr; - f->depth++; - } - - /* out-of-order, below the minimum */ - else if (addr < f->amin) - { - if (f->holes != 0) - vd->logerror("Unexpected CMDFIFO: AMin=%08X AMax=%08X Holes=%d WroteTo:%08X\n", - f->amin, f->amax, f->holes, addr); - //f->amin = f->amax = addr; - f->holes += (addr - f->base) / 4; - f->amin = f->base; - f->amax = addr; - - f->depth++; - } - - /* out-of-order, but within the min-max range */ - else if (addr < f->amax) - { - f->holes--; - if (f->holes == 0) - { - f->depth += (f->amax - f->amin) / 4; - f->amin = f->amax; - } - } - - /* out-of-order, bumping max */ - else - { - f->holes += (addr - f->amax) / 4 - 1; - f->amax = addr; - } - } - - /* execute if we can */ - if (!vd->pci.op_pending) - { - int32_t cycles = vd->cmdfifo_execute_if_ready(*f); - if (cycles > 0) - { - vd->pci.op_pending = true; - vd->pci.op_end_time = vd->machine().time() + attotime(0, (attoseconds_t)cycles * vd->attoseconds_per_cycle); - - if (LOG_FIFO_VERBOSE) - { - vd->logerror("VOODOO.FIFO:direct write start at %d.%018d end at %d.%018d\n", - vd->machine().time().seconds(), vd->machine().time().attoseconds(), - vd->pci.op_end_time.seconds(), vd->pci.op_end_time.attoseconds()); - } - } - } -} - - - -/************************************* - * - * Stall the active cpu until we are - * ready - * - *************************************/ - -TIMER_CALLBACK_MEMBER( voodoo_device::stall_cpu_callback ) -{ - check_stalled_cpu(machine().time()); -} - - -void voodoo_device::check_stalled_cpu(attotime current_time) -{ - int resume = false; - - /* flush anything we can */ - if (pci.op_pending) - flush_fifos(this, current_time); - - /* if we're just stalled until the LWM is passed, see if we're ok now */ - if (pci.stall_state == STALLED_UNTIL_FIFO_LWM) - { - /* if there's room in the memory FIFO now, we can proceed */ - if (FBIINIT0_ENABLE_MEMORY_FIFO(reg[fbiInit0].u)) - { - if (fbi.fifo.items() < 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(reg[fbiInit0].u)) - resume = true; - } - else if (pci.fifo.space() > 2 * FBIINIT0_PCI_FIFO_LWM(reg[fbiInit0].u)) - resume = true; - } - - /* if we're stalled until the FIFOs are empty, check now */ - else if (pci.stall_state == STALLED_UNTIL_FIFO_EMPTY) - { - if (FBIINIT0_ENABLE_MEMORY_FIFO(reg[fbiInit0].u)) - { - if (fbi.fifo.empty() && pci.fifo.empty()) - resume = true; - } - else if (pci.fifo.empty()) - resume = true; - } - - /* resume if necessary */ - if (resume || !pci.op_pending) - { - if (LOG_FIFO) logerror("VOODOO.FIFO:Stall condition cleared; resuming\n"); - pci.stall_state = NOT_STALLED; - - /* either call the callback, or trigger the trigger */ - if (!m_stall.isnull()) - m_stall(false); - else - machine().scheduler().trigger(trigger); - } - - /* if not, set a timer for the next one */ - else - { - pci.continue_timer->adjust(pci.op_end_time - current_time); - } -} - - -void voodoo_device::stall_cpu(int state, attotime current_time) -{ - /* sanity check */ - if (!pci.op_pending) fatalerror("FIFOs not empty, no op pending!\n"); - - /* set the state and update statistics */ - pci.stall_state = state; - stats.stalls++; - - /* either call the callback, or spin the CPU */ - if (!m_stall.isnull()) - m_stall(true); - else - m_cpu->spin_until_trigger(trigger); - - /* set a timer to clear the stall */ - pci.continue_timer->adjust(pci.op_end_time - current_time); -} - - - -/************************************* - * - * Voodoo register writes - * - *************************************/ - -int32_t voodoo_device::register_w(voodoo_device *vd, offs_t offset, uint32_t data) -{ - uint32_t origdata = data; - int32_t cycles = 0; - int64_t data64; - uint8_t regnum; - uint8_t chips; - - /* statistics */ - vd->stats.reg_writes++; - - /* determine which chips we are addressing */ - chips = (offset >> 8) & 0xf; - if (chips == 0) - chips = 0xf; - chips &= vd->chipmask; - - /* the first 64 registers can be aliased differently */ - if ((offset & 0x800c0) == 0x80000 && vd->alt_regmap) - regnum = register_alias_map[offset & 0x3f]; - else - regnum = offset & 0xff; - - /* first make sure this register is readable */ - if (!(vd->regaccess[regnum] & REGISTER_WRITE)) - { - vd->logerror("VOODOO.ERROR:Invalid attempt to write %s\n", vd->regnames[regnum]); - return 0; - } - - /* switch off the register */ - switch (regnum) - { - case intrCtrl: - vd->reg[regnum].u = data; - // Setting bit 31 clears the PCI interrupts - if (data & 0x80000000) { - // Clear pci interrupt - if (!vd->m_pciint.isnull()) - vd->m_pciint(false); - } - break; - /* Vertex data is 12.4 formatted fixed point */ - case fvertexAx: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexAx: - if (chips & 1) vd->fbi.ax = (int16_t)data; - break; - - case fvertexAy: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexAy: - if (chips & 1) vd->fbi.ay = (int16_t)data; - break; - - case fvertexBx: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexBx: - if (chips & 1) vd->fbi.bx = (int16_t)data; - break; - - case fvertexBy: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexBy: - if (chips & 1) vd->fbi.by = (int16_t)data; - break; - - case fvertexCx: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexCx: - if (chips & 1) vd->fbi.cx = (int16_t)data; - break; - - case fvertexCy: - data = float_to_int32(data, 4); - [[fallthrough]]; - case vertexCy: - if (chips & 1) vd->fbi.cy = (int16_t)data; - break; - - /* RGB data is 12.12 formatted fixed point */ - case fstartR: - data = float_to_int32(data, 12); - [[fallthrough]]; - case startR: - if (chips & 1) vd->fbi.startr = (int32_t)(data << 8) >> 8; - break; - - case fstartG: - data = float_to_int32(data, 12); - [[fallthrough]]; - case startG: - if (chips & 1) vd->fbi.startg = (int32_t)(data << 8) >> 8; - break; - - case fstartB: - data = float_to_int32(data, 12); - [[fallthrough]]; - case startB: - if (chips & 1) vd->fbi.startb = (int32_t)(data << 8) >> 8; - break; - - case fstartA: - data = float_to_int32(data, 12); - [[fallthrough]]; - case startA: - if (chips & 1) vd->fbi.starta = (int32_t)(data << 8) >> 8; - break; - - case fdRdX: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dRdX: - if (chips & 1) vd->fbi.drdx = (int32_t)(data << 8) >> 8; - break; - - case fdGdX: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dGdX: - if (chips & 1) vd->fbi.dgdx = (int32_t)(data << 8) >> 8; - break; - - case fdBdX: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dBdX: - if (chips & 1) vd->fbi.dbdx = (int32_t)(data << 8) >> 8; - break; - - case fdAdX: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dAdX: - if (chips & 1) vd->fbi.dadx = (int32_t)(data << 8) >> 8; - break; - - case fdRdY: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dRdY: - if (chips & 1) vd->fbi.drdy = (int32_t)(data << 8) >> 8; - break; - - case fdGdY: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dGdY: - if (chips & 1) vd->fbi.dgdy = (int32_t)(data << 8) >> 8; - break; - - case fdBdY: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dBdY: - if (chips & 1) vd->fbi.dbdy = (int32_t)(data << 8) >> 8; - break; - - case fdAdY: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dAdY: - if (chips & 1) vd->fbi.dady = (int32_t)(data << 8) >> 8; - break; - - /* Z data is 20.12 formatted fixed point */ - case fstartZ: - data = float_to_int32(data, 12); - [[fallthrough]]; - case startZ: - if (chips & 1) vd->fbi.startz = (int32_t)data; - break; - - case fdZdX: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dZdX: - if (chips & 1) vd->fbi.dzdx = (int32_t)data; - break; - - case fdZdY: - data = float_to_int32(data, 12); - [[fallthrough]]; - case dZdY: - if (chips & 1) vd->fbi.dzdy = (int32_t)data; - break; - - /* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */ - case fstartS: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].starts = data64; - if (chips & 4) vd->tmu[1].starts = data64; - break; - case startS: - if (chips & 2) vd->tmu[0].starts = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].starts = (int64_t)(int32_t)data << 14; - break; - - case fstartT: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].startt = data64; - if (chips & 4) vd->tmu[1].startt = data64; - break; - case startT: - if (chips & 2) vd->tmu[0].startt = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].startt = (int64_t)(int32_t)data << 14; - break; - - case fdSdX: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].dsdx = data64; - if (chips & 4) vd->tmu[1].dsdx = data64; - break; - case dSdX: - if (chips & 2) vd->tmu[0].dsdx = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].dsdx = (int64_t)(int32_t)data << 14; - break; - - case fdTdX: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].dtdx = data64; - if (chips & 4) vd->tmu[1].dtdx = data64; - break; - case dTdX: - if (chips & 2) vd->tmu[0].dtdx = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].dtdx = (int64_t)(int32_t)data << 14; - break; - - case fdSdY: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].dsdy = data64; - if (chips & 4) vd->tmu[1].dsdy = data64; - break; - case dSdY: - if (chips & 2) vd->tmu[0].dsdy = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].dsdy = (int64_t)(int32_t)data << 14; - break; - - case fdTdY: - data64 = float_to_int64(data, 32); - if (chips & 2) vd->tmu[0].dtdy = data64; - if (chips & 4) vd->tmu[1].dtdy = data64; - break; - case dTdY: - if (chips & 2) vd->tmu[0].dtdy = (int64_t)(int32_t)data << 14; - if (chips & 4) vd->tmu[1].dtdy = (int64_t)(int32_t)data << 14; - break; - - /* W data is 2.30 formatted fixed point, converted to 16.32 internally */ - case fstartW: - data64 = float_to_int64(data, 32); - if (chips & 1) vd->fbi.startw = data64; - if (chips & 2) vd->tmu[0].startw = data64; - if (chips & 4) vd->tmu[1].startw = data64; - break; - case startW: - if (chips & 1) vd->fbi.startw = (int64_t)(int32_t)data << 2; - if (chips & 2) vd->tmu[0].startw = (int64_t)(int32_t)data << 2; - if (chips & 4) vd->tmu[1].startw = (int64_t)(int32_t)data << 2; - break; - - case fdWdX: - data64 = float_to_int64(data, 32); - if (chips & 1) vd->fbi.dwdx = data64; - if (chips & 2) vd->tmu[0].dwdx = data64; - if (chips & 4) vd->tmu[1].dwdx = data64; - break; - case dWdX: - if (chips & 1) vd->fbi.dwdx = (int64_t)(int32_t)data << 2; - if (chips & 2) vd->tmu[0].dwdx = (int64_t)(int32_t)data << 2; - if (chips & 4) vd->tmu[1].dwdx = (int64_t)(int32_t)data << 2; - break; - - case fdWdY: - data64 = float_to_int64(data, 32); - if (chips & 1) vd->fbi.dwdy = data64; - if (chips & 2) vd->tmu[0].dwdy = data64; - if (chips & 4) vd->tmu[1].dwdy = data64; - break; - case dWdY: - if (chips & 1) vd->fbi.dwdy = (int64_t)(int32_t)data << 2; - if (chips & 2) vd->tmu[0].dwdy = (int64_t)(int32_t)data << 2; - if (chips & 4) vd->tmu[1].dwdy = (int64_t)(int32_t)data << 2; - break; - - /* setup bits */ - case sARGB: - if (chips & 1) - { - rgb_t rgbdata(data); - vd->reg[sAlpha].f = rgbdata.a(); - vd->reg[sRed].f = rgbdata.r(); - vd->reg[sGreen].f = rgbdata.g(); - vd->reg[sBlue].f = rgbdata.b(); - } - break; - - /* mask off invalid bits for different cards */ - case fbzColorPath: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type < TYPE_VOODOO_2) - data &= 0x0fffffff; - if (chips & 1) vd->reg[fbzColorPath].u = data; - break; - - case fbzMode: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type < TYPE_VOODOO_2) - data &= 0x001fffff; - if (chips & 1) vd->reg[fbzMode].u = data; - break; - - case fogMode: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type < TYPE_VOODOO_2) - data &= 0x0000003f; - if (chips & 1) vd->reg[fogMode].u = data; - break; - - /* triangle drawing */ - case triangleCMD: - vd->fbi.cheating_allowed = (vd->fbi.ax != 0 || vd->fbi.ay != 0 || vd->fbi.bx > 50 || vd->fbi.by != 0 || vd->fbi.cx != 0 || vd->fbi.cy > 50); - vd->fbi.sign = data; - cycles = triangle(vd); - break; - - case ftriangleCMD: - vd->fbi.cheating_allowed = true; - vd->fbi.sign = data; - cycles = triangle(vd); - break; - - case sBeginTriCMD: - cycles = begin_triangle(vd); - break; - - case sDrawTriCMD: - cycles = draw_triangle(vd); - break; - - /* other commands */ - case nopCMD: - poly_wait(vd->poly, vd->regnames[regnum]); - if (data & 1) - vd->reset_counters(); - if (data & 2) - vd->reg[fbiTrianglesOut].u = 0; - break; - - case fastfillCMD: - cycles = fastfill(vd); - break; - - case swapbufferCMD: - poly_wait(vd->poly, vd->regnames[regnum]); - cycles = swapbuffer(vd, data); - break; - - case userIntrCMD: - poly_wait(vd->poly, vd->regnames[regnum]); - // Bit 5 of intrCtrl enables user interrupts - if (vd->reg[intrCtrl].u & 0x20) { - // Bits 19:12 are set to cmd 9:2, bit 11 is user interrupt flag - vd->reg[intrCtrl].u |= ((data << 10) & 0x000ff000) | 0x800; - vd->reg[intrCtrl].u &= ~0x80000000; - - // Signal pci interrupt handler - if (!vd->m_pciint.isnull()) - vd->m_pciint(true); - } - break; - - /* gamma table access -- Voodoo/Voodoo2 only */ - case clutData: - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1)) - { - poly_wait(vd->poly, vd->regnames[regnum]); - if (!FBIINIT1_VIDEO_TIMING_RESET(vd->reg[fbiInit1].u)) - { - int index = data >> 24; - if (index <= 32) - { - vd->fbi.clut[index] = data; - vd->fbi.clut_dirty = true; - } - } - else - vd->logerror("clutData ignored because video timing reset = 1\n"); - } - break; - - /* external DAC access -- Voodoo/Voodoo2 only */ - case dacData: - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1)) - { - poly_wait(vd->poly, vd->regnames[regnum]); - if (!(data & 0x800)) - vd->dac.data_w((data >> 8) & 7, data & 0xff); - else - vd->dac.data_r((data >> 8) & 7); - } - break; - - /* vertical sync rate -- Voodoo/Voodoo2 only */ - case hSync: - case vSync: - case backPorch: - case videoDimensions: - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1)) - { - poly_wait(vd->poly, vd->regnames[regnum]); - vd->reg[regnum].u = data; - if (vd->reg[hSync].u != 0 && vd->reg[vSync].u != 0 && vd->reg[videoDimensions].u != 0) - { - int hvis, vvis, htotal, vtotal, hbp, vbp; - attoseconds_t refresh = vd->m_screen->frame_period().attoseconds(); - attoseconds_t stdperiod, medperiod, vgaperiod; - attoseconds_t stddiff, meddiff, vgadiff; - rectangle visarea; - - if (vd->vd_type == TYPE_VOODOO_2) - { - htotal = ((vd->reg[hSync].u >> 16) & 0x7ff) + 1 + (vd->reg[hSync].u & 0x1ff) + 1; - vtotal = ((vd->reg[vSync].u >> 16) & 0x1fff) + (vd->reg[vSync].u & 0x1fff); - hvis = vd->reg[videoDimensions].u & 0x7ff; - vvis = (vd->reg[videoDimensions].u >> 16) & 0x7ff; - hbp = (vd->reg[backPorch].u & 0x1ff) + 2; - vbp = (vd->reg[backPorch].u >> 16) & 0x1ff; - } - else - { - htotal = ((vd->reg[hSync].u >> 16) & 0x3ff) + 1 + (vd->reg[hSync].u & 0xff) + 1; - vtotal = ((vd->reg[vSync].u >> 16) & 0xfff) + (vd->reg[vSync].u & 0xfff); - hvis = vd->reg[videoDimensions].u & 0x3ff; - vvis = (vd->reg[videoDimensions].u >> 16) & 0x3ff; - hbp = (vd->reg[backPorch].u & 0xff) + 2; - vbp = (vd->reg[backPorch].u >> 16) & 0xff; - } - - /* create a new visarea */ - visarea.set(hbp, hbp + std::max(hvis - 1, 0), vbp, vbp + std::max(vvis - 1, 0)); - - /* keep within bounds */ - visarea.max_x = (std::min)(visarea.max_x, htotal - 1); - visarea.max_y = (std::min)(visarea.max_y, vtotal - 1); - - /* compute the new period for standard res, medium res, and VGA res */ - stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal; - medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal; - vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal; - - /* compute a diff against the current refresh period */ - stddiff = stdperiod - refresh; - if (stddiff < 0) stddiff = -stddiff; - meddiff = medperiod - refresh; - if (meddiff < 0) meddiff = -meddiff; - vgadiff = vgaperiod - refresh; - if (vgadiff < 0) vgadiff = -vgadiff; - - osd_printf_debug("hSync=%08X vSync=%08X backPorch=%08X videoDimensions=%08X\n", - vd->reg[hSync].u, vd->reg[vSync].u, vd->reg[backPorch].u, vd->reg[videoDimensions].u); - osd_printf_debug("Horiz: %d-%d (%d total) Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal); - - /* configure the screen based on which one matches the closest */ - if (stddiff < meddiff && stddiff < vgadiff) - { - vd->m_screen->configure(htotal, vtotal, visarea, stdperiod); - osd_printf_debug("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod)); - } - else if (meddiff < vgadiff) - { - vd->m_screen->configure(htotal, vtotal, visarea, medperiod); - osd_printf_debug("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod)); - } - else - { - vd->m_screen->configure(htotal, vtotal, visarea, vgaperiod); - osd_printf_debug("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod)); - } - - /* configure the new framebuffer info */ - vd->fbi.width = hvis; - vd->fbi.height = vvis; - vd->fbi.xoffs = hbp; - vd->fbi.yoffs = vbp; - vd->fbi.vsyncstart = (vd->reg[vSync].u >> 16) & 0xfff; - vd->fbi.vsyncstop = (vd->reg[vSync].u >> 0) & 0xfff; - osd_printf_debug("yoffs: %d vsyncstart: %d vsyncstop: %d\n", vbp, vd->fbi.vsyncstart, vd->fbi.vsyncstop); - /* recompute the time of VBLANK */ - vd->adjust_vblank_timer(); - - /* if changing dimensions, update video memory layout */ - if (regnum == videoDimensions) - vd->recompute_video_memory(); - } - } - break; - - /* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */ - case fbiInit0: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(vd->pci.init_enable)) - { - vd->reg[fbiInit0].u = data; - if (FBIINIT0_GRAPHICS_RESET(data)) - vd->soft_reset(); - if (FBIINIT0_FIFO_RESET(data)) - vd->pci.fifo.reset(); - vd->recompute_video_memory(); - } - break; - - /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */ - case fbiInit5: - case fbiInit6: - if (vd->vd_type < TYPE_VOODOO_2) - break; - [[fallthrough]]; - - /* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */ - /* most of these affect memory layout, so always recompute that when done */ - case fbiInit1: - case fbiInit2: - case fbiInit4: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(vd->pci.init_enable)) - { - vd->reg[regnum].u = data; - vd->recompute_video_memory(); - vd->fbi.video_changed = true; - } - break; - - case fbiInit3: - poly_wait(vd->poly, vd->regnames[regnum]); - if (vd->vd_type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(vd->pci.init_enable)) - { - vd->reg[regnum].u = data; - vd->alt_regmap = FBIINIT3_TRI_REGISTER_REMAP(data); - vd->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(vd->reg[fbiInit3].u); - vd->recompute_video_memory(); - } - break; - - case fbiInit7: -/* case swapPending: -- Banshee */ - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(vd->pci.init_enable)) - { - poly_wait(vd->poly, vd->regnames[regnum]); - vd->reg[regnum].u = data; - vd->fbi.cmdfifo[0].enable = FBIINIT7_CMDFIFO_ENABLE(data); - vd->fbi.cmdfifo[0].count_holes = !FBIINIT7_DISABLE_CMDFIFO_HOLES(data); - } - else if (vd->vd_type >= TYPE_VOODOO_BANSHEE) - vd->fbi.swaps_pending++; - break; - - /* cmdFifo -- Voodoo2 only */ - case cmdFifoBaseAddr: - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - { - poly_wait(vd->poly, vd->regnames[regnum]); - vd->reg[regnum].u = data; - vd->fbi.cmdfifo[0].base = (data & 0x3ff) << 12; - vd->fbi.cmdfifo[0].end = (((data >> 16) & 0x3ff) + 1) << 12; - } - break; - - case cmdFifoBump: - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - fatalerror("cmdFifoBump\n"); - break; - - case cmdFifoRdPtr: - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - vd->fbi.cmdfifo[0].rdptr = data; - break; - - case cmdFifoAMin: -/* case colBufferAddr: -- Banshee */ - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - vd->fbi.cmdfifo[0].amin = data; - else if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (chips & 1)) - vd->fbi.rgboffs[1] = data & vd->fbi.mask & ~0x0f; - break; - - case cmdFifoAMax: -/* case colBufferStride: -- Banshee */ - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - vd->fbi.cmdfifo[0].amax = data; - else if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (chips & 1)) - { - if (data & 0x8000) - vd->fbi.rowpixels = (data & 0x7f) << 6; - else - vd->fbi.rowpixels = (data & 0x3fff) >> 1; - } - break; - - case cmdFifoDepth: -/* case auxBufferAddr: -- Banshee */ - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - vd->fbi.cmdfifo[0].depth = data; - else if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (chips & 1)) - vd->fbi.auxoffs = data & vd->fbi.mask & ~0x0f; - break; - - case cmdFifoHoles: -/* case auxBufferStride: -- Banshee */ - if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1)) - vd->fbi.cmdfifo[0].holes = data; - else if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (chips & 1)) - { - int rowpixels; - - if (data & 0x8000) - rowpixels = (data & 0x7f) << 6; - else - rowpixels = (data & 0x3fff) >> 1; - if (vd->fbi.rowpixels != rowpixels) - fatalerror("aux buffer stride differs from color buffer stride\n"); - } - break; - - /* nccTable entries are processed and expanded immediately */ - case nccTable+0: - case nccTable+1: - case nccTable+2: - case nccTable+3: - case nccTable+4: - case nccTable+5: - case nccTable+6: - case nccTable+7: - case nccTable+8: - case nccTable+9: - case nccTable+10: - case nccTable+11: - poly_wait(vd->poly, vd->regnames[regnum]); - if (chips & 2) vd->tmu[0].ncc[0].write(regnum - nccTable, data); - if (chips & 4) vd->tmu[1].ncc[0].write(regnum - nccTable, data); - break; - - case nccTable+12: - case nccTable+13: - case nccTable+14: - case nccTable+15: - case nccTable+16: - case nccTable+17: - case nccTable+18: - case nccTable+19: - case nccTable+20: - case nccTable+21: - case nccTable+22: - case nccTable+23: - poly_wait(vd->poly, vd->regnames[regnum]); - if (chips & 2) vd->tmu[0].ncc[1].write(regnum - (nccTable+12), data); - if (chips & 4) vd->tmu[1].ncc[1].write(regnum - (nccTable+12), data); - break; - - /* fogTable entries are processed and expanded immediately */ - case fogTable+0: - case fogTable+1: - case fogTable+2: - case fogTable+3: - case fogTable+4: - case fogTable+5: - case fogTable+6: - case fogTable+7: - case fogTable+8: - case fogTable+9: - case fogTable+10: - case fogTable+11: - case fogTable+12: - case fogTable+13: - case fogTable+14: - case fogTable+15: - case fogTable+16: - case fogTable+17: - case fogTable+18: - case fogTable+19: - case fogTable+20: - case fogTable+21: - case fogTable+22: - case fogTable+23: - case fogTable+24: - case fogTable+25: - case fogTable+26: - case fogTable+27: - case fogTable+28: - case fogTable+29: - case fogTable+30: - case fogTable+31: - poly_wait(vd->poly, vd->regnames[regnum]); - if (chips & 1) - { - int base = 2 * (regnum - fogTable); - vd->fbi.fogdelta[base + 0] = (data >> 0) & 0xff; - vd->fbi.fogblend[base + 0] = (data >> 8) & 0xff; - vd->fbi.fogdelta[base + 1] = (data >> 16) & 0xff; - vd->fbi.fogblend[base + 1] = (data >> 24) & 0xff; - } - break; - - /* texture modifications cause us to recompute everything */ - case textureMode: - case tLOD: - case tDetail: - case texBaseAddr: - case texBaseAddr_1: - case texBaseAddr_2: - case texBaseAddr_3_8: - if (chips & 2) - { - if (vd->tmu[0].reg[regnum].u != data) { - poly_wait(vd->poly, vd->regnames[regnum]); - vd->tmu[0].regdirty = true; - vd->tmu[0].reg[regnum].u = data; - } - } - if (chips & 4) - { - if (vd->tmu[1].reg[regnum].u != data) { - poly_wait(vd->poly, vd->regnames[regnum]); - vd->tmu[1].regdirty = true; - vd->tmu[1].reg[regnum].u = data; - } - } - break; - - case trexInit1: - vd->logerror("VOODOO.REG:%s(%d) write = %08X\n", (regnum < 0x384 / 4) ? vd->regnames[regnum] : "oob", chips, data); - /* send tmu config data to the frame buffer */ - vd->send_config = (TREXINIT_SEND_TMU_CONFIG(data) > 0); - goto default_case; - - /* these registers are referenced in the renderer; we must wait for pending work before changing */ - case chromaRange: - case chromaKey: - case alphaMode: - case fogColor: - case stipple: - case zaColor: - case color1: - case color0: - case clipLowYHighY: - case clipLeftRight: - poly_wait(vd->poly, vd->regnames[regnum]); - [[fallthrough]]; - /* by default, just feed the data to the chips */ - default: -default_case: - if (chips & 1) vd->reg[0x000 + regnum].u = data; - if (chips & 2) vd->reg[0x100 + regnum].u = data; - if (chips & 4) vd->reg[0x200 + regnum].u = data; - if (chips & 8) vd->reg[0x300 + regnum].u = data; - break; - } - - if (LOG_REGISTERS) - { - if (regnum < fvertexAx || regnum > fdWdY) - vd->logerror("VOODOO.REG:%s(%d) write = %08X\n", (regnum < 0x384/4) ? vd->regnames[regnum] : "oob", chips, origdata); - else - vd->logerror("VOODOO.REG:%s(%d) write = %f\n", (regnum < 0x384/4) ? vd->regnames[regnum] : "oob", chips, (double) u2f(origdata)); - } - - return cycles; -} - - - -/************************************* - * - * Voodoo LFB writes - * - *************************************/ -int32_t voodoo_device::lfb_direct_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - /* statistics */ - stats.lfb_writes++; - - /* byte swizzling */ - if (LFBMODE_BYTE_SWIZZLE_WRITES(reg[lfbMode].u)) - { - data = swapendian_int32(data); - mem_mask = swapendian_int32(mem_mask); - } - - /* word swapping */ - if (LFBMODE_WORD_SWAP_WRITES(reg[lfbMode].u)) - { - data = (data << 16) | (data >> 16); - mem_mask = (mem_mask << 16) | (mem_mask >> 16); - } - - // TODO: This direct write is not verified. - // For direct lfb access just write the data - /* compute X,Y */ - offset <<= 1; - int const x = offset & ((1 << fbi.lfb_stride) - 1); - int const y = (offset >> fbi.lfb_stride); - uint16_t *const dest = (uint16_t *)(fbi.ram + fbi.lfb_base*4); - uint32_t const destmax = (fbi.mask + 1 - fbi.lfb_base*4) / 2; - uint32_t const bufoffs = y * fbi.rowpixels + x; - if (bufoffs >= destmax) { - logerror("lfb_direct_w: Buffer offset out of bounds x=%i y=%i offset=%08X bufoffs=%08X data=%08X\n", x, y, offset, bufoffs, data); - return 0; - } - if (ACCESSING_BITS_0_15) - dest[bufoffs + 0] = data&0xffff; - if (ACCESSING_BITS_16_31) - dest[bufoffs + 1] = data>>16; - // Need to notify that frame buffer has changed - fbi.video_changed = true; - if (LOG_LFB) logerror("VOODOO.LFB:write direct (%d,%d) = %08X & %08X\n", x, y, data, mem_mask); - return 0; -} - -int32_t voodoo_device::lfb_w(voodoo_device* vd, offs_t offset, uint32_t data, uint32_t mem_mask) -{ - uint16_t *dest, *depth; - uint32_t destmax, depthmax; - int sa[2], sz[2]; - uint8_t sr[2], sg[2], sb[2]; - int x, y, scry, mask; - int pix, destbuf; - rgb_t sourceColor; - - /* statistics */ - vd->stats.lfb_writes++; - - /* byte swizzling */ - if (LFBMODE_BYTE_SWIZZLE_WRITES(vd->reg[lfbMode].u)) - { - data = swapendian_int32(data); - mem_mask = swapendian_int32(mem_mask); - } - - /* word swapping */ - if (LFBMODE_WORD_SWAP_WRITES(vd->reg[lfbMode].u)) - { - data = (data << 16) | (data >> 16); - mem_mask = (mem_mask << 16) | (mem_mask >> 16); - } - - /* extract default depth and alpha values */ - sz[0] = sz[1] = vd->reg[zaColor].u & 0xffff; - sa[0] = sa[1] = vd->reg[zaColor].u >> 24; - - /* first extract A,R,G,B from the data */ - switch (LFBMODE_WRITE_FORMAT(vd->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(vd->reg[lfbMode].u)) - { - case 16*0 + 0: /* ARGB, 16-bit RGB 5-6-5 */ - case 16*2 + 0: /* RGBA, 16-bit RGB 5-6-5 */ - //EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]); - //EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]); - sourceColor = vd->fbi.rgb565[data & 0xffff]; - sourceColor.expand_rgb(sr[0], sg[0], sb[0]); - sourceColor = vd->fbi.rgb565[data >> 16]; - sourceColor.expand_rgb(sr[1], sg[1], sb[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - case 16*1 + 0: /* ABGR, 16-bit RGB 5-6-5 */ - case 16*3 + 0: /* BGRA, 16-bit RGB 5-6-5 */ - //EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]); - //EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]); - sourceColor = vd->fbi.rgb565[data & 0xffff]; - sourceColor.expand_rgb(sb[0], sg[0], sr[0]); - sourceColor = vd->fbi.rgb565[data >> 16]; - sourceColor.expand_rgb(sb[1], sg[1], sr[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - - case 16*0 + 1: /* ARGB, 16-bit RGB x-5-5-5 */ - EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]); - EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - case 16*1 + 1: /* ABGR, 16-bit RGB x-5-5-5 */ - EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]); - EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - case 16*2 + 1: /* RGBA, 16-bit RGB x-5-5-5 */ - EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]); - EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - case 16*3 + 1: /* BGRA, 16-bit RGB x-5-5-5 */ - EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]); - EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]); - mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); - offset <<= 1; - break; - - case 16*0 + 2: /* ARGB, 16-bit ARGB 1-5-5-5 */ - EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); - EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); - offset <<= 1; - break; - case 16*1 + 2: /* ABGR, 16-bit ARGB 1-5-5-5 */ - EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); - EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); - offset <<= 1; - break; - case 16*2 + 2: /* RGBA, 16-bit ARGB 1-5-5-5 */ - EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); - EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); - offset <<= 1; - break; - case 16*3 + 2: /* BGRA, 16-bit ARGB 1-5-5-5 */ - EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); - EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); - offset <<= 1; - break; - - case 16*0 + 4: /* ARGB, 32-bit RGB x-8-8-8 */ - EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT; - break; - case 16*1 + 4: /* ABGR, 32-bit RGB x-8-8-8 */ - EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT; - break; - case 16*2 + 4: /* RGBA, 32-bit RGB x-8-8-8 */ - EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT; - break; - case 16*3 + 4: /* BGRA, 32-bit RGB x-8-8-8 */ - EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT; - break; - - case 16*0 + 5: /* ARGB, 32-bit ARGB 8-8-8-8 */ - EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; - break; - case 16*1 + 5: /* ABGR, 32-bit ARGB 8-8-8-8 */ - EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; - break; - case 16*2 + 5: /* RGBA, 32-bit ARGB 8-8-8-8 */ - EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; - break; - case 16*3 + 5: /* BGRA, 32-bit ARGB 8-8-8-8 */ - EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; - break; - - case 16*0 + 12: /* ARGB, 32-bit depth+RGB 5-6-5 */ - case 16*2 + 12: /* RGBA, 32-bit depth+RGB 5-6-5 */ - sz[0] = data >> 16; - //EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]); - sourceColor = vd->fbi.rgb565[data & 0xffff]; - sourceColor.expand_rgb(sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*1 + 12: /* ABGR, 32-bit depth+RGB 5-6-5 */ - case 16*3 + 12: /* BGRA, 32-bit depth+RGB 5-6-5 */ - sz[0] = data >> 16; - //EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]); - sourceColor = vd->fbi.rgb565[data & 0xffff]; - sourceColor.expand_rgb(sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - - case 16*0 + 13: /* ARGB, 32-bit depth+RGB x-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*1 + 13: /* ABGR, 32-bit depth+RGB x-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*2 + 13: /* RGBA, 32-bit depth+RGB x-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*3 + 13: /* BGRA, 32-bit depth+RGB x-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - - case 16*0 + 14: /* ARGB, 32-bit depth+ARGB 1-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*1 + 14: /* ABGR, 32-bit depth+ARGB 1-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*2 + 14: /* RGBA, 32-bit depth+ARGB 1-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - case 16*3 + 14: /* BGRA, 32-bit depth+ARGB 1-5-5-5 */ - sz[0] = data >> 16; - EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); - mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; - break; - - case 16*0 + 15: /* ARGB, 16-bit depth */ - case 16*1 + 15: /* ARGB, 16-bit depth */ - case 16*2 + 15: /* ARGB, 16-bit depth */ - case 16*3 + 15: /* ARGB, 16-bit depth */ - sz[0] = data & 0xffff; - sz[1] = data >> 16; - mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4); - offset <<= 1; - break; - - default: /* reserved */ - vd->logerror("lfb_w: Unknown format\n"); - return 0; - } - - /* compute X,Y */ - x = offset & ((1 << vd->fbi.lfb_stride) - 1); - y = (offset >> vd->fbi.lfb_stride) & 0x3ff; - - /* adjust the mask based on which half of the data is written */ - if (!ACCESSING_BITS_0_15) - mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW); - if (!ACCESSING_BITS_16_31) - mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW); - - /* select the target buffer */ - destbuf = (vd->vd_type >= TYPE_VOODOO_BANSHEE) ? 1 : LFBMODE_WRITE_BUFFER_SELECT(vd->reg[lfbMode].u); - switch (destbuf) - { - case 0: /* front buffer */ - dest = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.frontbuf]); - destmax = (vd->fbi.mask + 1 - vd->fbi.rgboffs[vd->fbi.frontbuf]) / 2; - vd->fbi.video_changed = true; - break; - - case 1: /* back buffer */ - dest = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.backbuf]); - destmax = (vd->fbi.mask + 1 - vd->fbi.rgboffs[vd->fbi.backbuf]) / 2; - break; - - default: /* reserved */ - return 0; - } - depth = (uint16_t *)(vd->fbi.ram + vd->fbi.auxoffs); - depthmax = (vd->fbi.mask + 1 - vd->fbi.auxoffs) / 2; - - /* simple case: no pipeline */ - if (!LFBMODE_ENABLE_PIXEL_PIPELINE(vd->reg[lfbMode].u)) - { - DECLARE_DITHER_POINTERS_NO_DITHER_VAR; - uint32_t bufoffs; - - if (LOG_LFB) vd->logerror("VOODOO.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", LFBMODE_WRITE_FORMAT(vd->reg[lfbMode].u), x, y, data, mem_mask); - - /* determine the screen Y */ - scry = y; - if (LFBMODE_Y_ORIGIN(vd->reg[lfbMode].u)) - scry = (vd->fbi.yorigin - y); - - /* advance pointers to the proper row */ - bufoffs = scry * vd->fbi.rowpixels + x; - - /* compute dithering */ - COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(vd->reg[fbzMode].u, y); - - /* wait for any outstanding work to finish */ - poly_wait(vd->poly, "LFB Write"); - - /* loop over up to two pixels */ - for (pix = 0; mask; pix++) - { - /* make sure we care about this pixel */ - if (mask & 0x0f) - { - /* write to the RGB buffer */ - if ((mask & LFB_RGB_PRESENT) && bufoffs < destmax) - { - /* apply dithering and write to the screen */ - APPLY_DITHER(vd->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]); - dest[bufoffs] = (sr[pix] << 11) | (sg[pix] << 5) | sb[pix]; - } - - /* make sure we have an aux buffer to write to */ - if (depth && bufoffs < depthmax) - { - /* write to the alpha buffer */ - if ((mask & LFB_ALPHA_PRESENT) && FBZMODE_ENABLE_ALPHA_PLANES(vd->reg[fbzMode].u)) - depth[bufoffs] = sa[pix]; - - /* write to the depth buffer */ - if ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(vd->reg[fbzMode].u)) - depth[bufoffs] = sz[pix]; - } - - /* track pixel writes to the frame buffer regardless of mask */ - vd->reg[fbiPixelsOut].u++; - } - - /* advance our pointers */ - bufoffs++; - x++; - mask >>= 4; - } - } - - /* tricky case: run the full pixel pipeline on the pixel */ - else - { - DECLARE_DITHER_POINTERS; - - if (LOG_LFB) vd->logerror("VOODOO.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", LFBMODE_WRITE_FORMAT(vd->reg[lfbMode].u), x, y, data, mem_mask); - - /* determine the screen Y */ - scry = y; - if (FBZMODE_Y_ORIGIN(vd->reg[fbzMode].u)) - scry = (vd->fbi.yorigin - y); - - /* advance pointers to the proper row */ - dest += scry * vd->fbi.rowpixels; - if (depth) - depth += scry * vd->fbi.rowpixels; - - /* compute dithering */ - COMPUTE_DITHER_POINTERS(vd->reg[fbzMode].u, y, vd->reg[fogMode].u); - - /* loop over up to two pixels */ - for (pix = 0; mask; pix++) - { - /* make sure we care about this pixel */ - if (mask & 0x0f) - { - stats_block *stats = &vd->fbi.lfb_stats; - int64_t iterw; - if (LFBMODE_WRITE_W_SELECT(vd->reg[lfbMode].u)) { - iterw = (uint32_t) vd->reg[zaColor].u << 16; - } else { - // The most significant fractional bits of 16.32 W are set to z - iterw = (uint32_t) sz[pix] << 16; - } - int32_t iterz = sz[pix] << 12; - - /* apply clipping */ - if (FBZMODE_ENABLE_CLIPPING(vd->reg[fbzMode].u)) - { - if (x < ((vd->reg[clipLeftRight].u >> 16) & 0x3ff) || - x >= (vd->reg[clipLeftRight].u & 0x3ff) || - scry < ((vd->reg[clipLowYHighY].u >> 16) & 0x3ff) || - scry >= (vd->reg[clipLowYHighY].u & 0x3ff)) - { - stats->pixels_in++; - stats->clip_fail++; - goto nextpixel; - } - } - - rgbaint_t color, preFog; - rgbaint_t iterargb(0); - - - /* pixel pipeline part 1 handles depth testing and stippling */ - //PIXEL_PIPELINE_BEGIN(v, stats, x, y, vd->reg[fbzColorPath].u, vd->reg[fbzMode].u, iterz, iterw); -// Start PIXEL_PIPE_BEGIN copy - //#define PIXEL_PIPELINE_BEGIN(VV, STATS, XX, YY, FBZCOLORPATH, FBZMODE, ITERZ, ITERW) - int32_t biasdepth; - int32_t r, g, b; - - (stats)->pixels_in++; - - /* apply clipping */ - /* note that for perf reasons, we assume the caller has done clipping */ - - /* handle stippling */ - if (FBZMODE_ENABLE_STIPPLE(vd->reg[fbzMode].u)) - { - /* rotate mode */ - if (FBZMODE_STIPPLE_PATTERN(vd->reg[fbzMode].u) == 0) - { - vd->reg[stipple].u = (vd->reg[stipple].u << 1) | (vd->reg[stipple].u >> 31); - if ((vd->reg[stipple].u & 0x80000000) == 0) - { - vd->stats.total_stippled++; - goto skipdrawdepth; - } - } - - /* pattern mode */ - else - { - int stipple_index = ((y & 3) << 3) | (~x & 7); - if (((vd->reg[stipple].u >> stipple_index) & 1) == 0) - { - vd->stats.total_stippled++; - goto nextpixel; - } - } - } -// End PIXEL_PIPELINE_BEGIN COPY - - // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used - biasdepth = (uint32_t) sz[pix]; - - - /* Perform depth testing */ - if (FBZMODE_ENABLE_DEPTHBUF(vd->reg[fbzMode].u)) - if (!depthTest((uint16_t) vd->reg[zaColor].u, stats, depth[x], vd->reg[fbzMode].u, biasdepth)) - goto nextpixel; - - /* use the RGBA we stashed above */ - color.set(sa[pix], sr[pix], sg[pix], sb[pix]); - - /* handle chroma key */ - if (FBZMODE_ENABLE_CHROMAKEY(vd->reg[fbzMode].u)) - if (!chromaKeyTest(vd, stats, vd->reg[fbzMode].u, color)) - goto nextpixel; - /* handle alpha mask */ - if (FBZMODE_ENABLE_ALPHA_MASK(vd->reg[fbzMode].u)) - if (!alphaMaskTest(stats, vd->reg[fbzMode].u, color.get_a())) - goto nextpixel; - /* handle alpha test */ - if (ALPHAMODE_ALPHATEST(vd->reg[alphaMode].u)) - if (!alphaTest(vd->reg[alphaMode].rgb.a, stats, vd->reg[alphaMode].u, color.get_a())) - goto nextpixel; - - /* perform fogging */ - preFog.set(color); - if (FOGMODE_ENABLE_FOG(vd->reg[fogMode].u)) - applyFogging(vd, vd->reg[fbzMode].u, vd->reg[fogMode].u, vd->reg[fbzColorPath].u, x, dither4, biasdepth, color, iterz, iterw, iterargb); - - /* wait for any outstanding work to finish */ - poly_wait(vd->poly, "LFB Write"); - - /* perform alpha blending */ - if (ALPHAMODE_ALPHABLEND(vd->reg[alphaMode].u)) - alphaBlend(vd->reg[fbzMode].u, vd->reg[alphaMode].u, x, dither, dest[x], depth, preFog, color, vd->fbi.rgb565); - - /* pixel pipeline part 2 handles final output */ - PIXEL_PIPELINE_END(stats, dither_lookup, x, dest, depth, vd->reg[fbzMode].u) { }; -nextpixel: - /* advance our pointers */ - x++; - mask >>= 4; - } - } - - return 0; -} - - - -/************************************* - * - * Voodoo texture RAM writes - * - *************************************/ - -int32_t voodoo_device::texture_w(voodoo_device *vd, offs_t offset, uint32_t data) -{ - int tmunum = (offset >> 19) & 0x03; - tmu_state *t; - - /* statistics */ - vd->stats.tex_writes++; - - /* point to the right TMU */ - if (!(vd->chipmask & (2 << tmunum))) - return 0; - t = &vd->tmu[tmunum]; - - if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u)) - fatalerror("Texture direct write!\n"); - - /* wait for any outstanding work to finish */ - poly_wait(vd->poly, "Texture write"); - - /* update texture info if dirty */ - if (t->regdirty) - t->recompute_texture_params(); - - /* swizzle the data */ - if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u)) - data = swapendian_int32(data); - if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u)) - data = (data >> 16) | (data << 16); - - /* 8-bit texture case */ - if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8) - { - int lod, tt, ts; - uint32_t tbaseaddr; - uint8_t *dest; - - /* extract info */ - if (vd->vd_type <= TYPE_VOODOO_2) - { - lod = (offset >> 15) & 0x0f; - tt = (offset >> 7) & 0xff; - - /* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */ - if (TEXMODE_SEQ_8_DOWNLD(vd->tmu[0].reg/*t->reg*/[textureMode].u)) { - ts = (offset << 2) & 0xfc; - } - else { - ts = (offset << 1) & 0xfc; - } - /* validate parameters */ - if (lod > 8) - return 0; - - /* compute the base address */ - tbaseaddr = t->lodoffset[lod]; - tbaseaddr += tt * ((t->wmask >> lod) + 1) + ts; - - if (LOG_TEXTURE_RAM) vd->logerror("Texture 8-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data); - } - else - { - tbaseaddr = t->lodoffset[0] + offset*4; - - if (LOG_TEXTURE_RAM) vd->logerror("Texture 8-bit w: offset=%X data=%08X\n", offset*4, data); - } - - /* write the four bytes in little-endian order */ - dest = t->ram; - tbaseaddr &= t->mask; - dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff; - dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff; - dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff; - dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff; - } - - /* 16-bit texture case */ - else - { - int lod, tt, ts; - uint32_t tbaseaddr; - uint16_t *dest; - - /* extract info */ - if (vd->vd_type <= TYPE_VOODOO_2) - { - lod = (offset >> 15) & 0x0f; - tt = (offset >> 7) & 0xff; - ts = (offset << 1) & 0xfe; - - /* validate parameters */ - if (lod > 8) - return 0; - - /* compute the base address */ - tbaseaddr = t->lodoffset[lod]; - tbaseaddr += 2 * (tt * ((t->wmask >> lod) + 1) + ts); - - if (LOG_TEXTURE_RAM) vd->logerror("Texture 16-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data); - } - else - { - tbaseaddr = t->lodoffset[0] + offset*4; - - if (LOG_TEXTURE_RAM) vd->logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data); - } - - /* write the two words in little-endian order */ - dest = (uint16_t *)t->ram; - tbaseaddr &= t->mask; - tbaseaddr >>= 1; - dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff; - dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff; - } - - return 0; -} - - - -/************************************* - * - * Flush data from the FIFOs - * - *************************************/ - -void voodoo_device::flush_fifos(voodoo_device *vd, attotime current_time) -{ - static uint8_t in_flush; - - /* check for recursive calls */ - if (in_flush) - return; - in_flush = true; - - if (!vd->pci.op_pending) fatalerror("flush_fifos called with no pending operation\n"); - - if (LOG_FIFO_VERBOSE) - { - vd->logerror("VOODOO.FIFO:flush_fifos start -- pending=%d.%018d cur=%d.%018d\n", - vd->pci.op_end_time.seconds(), vd->pci.op_end_time.attoseconds(), - current_time.seconds(), current_time.attoseconds()); - } - - /* loop while we still have cycles to burn */ - while (vd->pci.op_end_time <= current_time) - { - int32_t extra_cycles = 0; - int32_t cycles; - - /* loop over 0-cycle stuff; this constitutes the bulk of our writes */ - do - { - fifo_state *fifo; - uint32_t address; - uint32_t data; - - /* we might be in CMDFIFO mode */ - if (vd->fbi.cmdfifo[0].enable) - { - /* if we don't have anything to execute, we're done for now */ - cycles = vd->cmdfifo_execute_if_ready(vd->fbi.cmdfifo[0]); - if (cycles == -1) - { - vd->pci.op_pending = false; - in_flush = false; - if (LOG_FIFO_VERBOSE) vd->logerror("VOODOO.FIFO:flush_fifos end -- CMDFIFO empty\n"); - return; - } - } - else if (vd->fbi.cmdfifo[1].enable) - { - /* if we don't have anything to execute, we're done for now */ - cycles = vd->cmdfifo_execute_if_ready(vd->fbi.cmdfifo[1]); - if (cycles == -1) - { - vd->pci.op_pending = false; - in_flush = false; - if (LOG_FIFO_VERBOSE) vd->logerror("VOODOO.FIFO:flush_fifos end -- CMDFIFO empty\n"); - return; - } - } - - /* else we are in standard PCI/memory FIFO mode */ - else - { - /* choose which FIFO to read from */ - if (!vd->fbi.fifo.empty()) - fifo = &vd->fbi.fifo; - else if (!vd->pci.fifo.empty()) - fifo = &vd->pci.fifo; - else - { - vd->pci.op_pending = false; - in_flush = false; - if (LOG_FIFO_VERBOSE) vd->logerror("VOODOO.FIFO:flush_fifos end -- FIFOs empty\n"); - return; - } - - /* extract address and data */ - address = fifo->remove(); - data = fifo->remove(); - - /* target the appropriate location */ - if ((address & (0xc00000/4)) == 0) - cycles = register_w(vd, address, data); - else if (address & (0x800000/4)) - cycles = texture_w(vd, address, data); - else - { - uint32_t mem_mask = 0xffffffff; - - /* compute mem_mask */ - if (address & 0x80000000) - mem_mask &= 0x0000ffff; - if (address & 0x40000000) - mem_mask &= 0xffff0000; - address &= 0xffffff; - - cycles = lfb_w(vd, address, data, mem_mask); - } - } - - /* accumulate smaller operations */ - if (cycles < ACCUMULATE_THRESHOLD) - { - extra_cycles += cycles; - cycles = 0; - } - } - while (cycles == 0); - - /* account for extra cycles */ - cycles += extra_cycles; - - /* account for those cycles */ - vd->pci.op_end_time += attotime(0, (attoseconds_t)cycles * vd->attoseconds_per_cycle); - - if (LOG_FIFO_VERBOSE) - { - vd->logerror("VOODOO.FIFO:update -- pending=%d.%018d cur=%d.%018d\n", - vd->pci.op_end_time.seconds(), vd->pci.op_end_time.attoseconds(), - current_time.seconds(), current_time.attoseconds()); - } - } - - if (LOG_FIFO_VERBOSE) - { - vd->logerror("VOODOO.FIFO:flush_fifos end -- pending command complete at %d.%018d\n", - vd->pci.op_end_time.seconds(), vd->pci.op_end_time.attoseconds()); - } - - in_flush = false; -} - - - -/************************************* - * - * Handle a write to the Voodoo - * memory space - * - *************************************/ - -void voodoo_device::voodoo_w(offs_t offset, u32 data, u32 mem_mask) -{ - int stall = false; - - g_profiler.start(PROFILER_USER1); - - /* should not be getting accesses while stalled */ - if (pci.stall_state != NOT_STALLED) - logerror("voodoo_w while stalled!\n"); - - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - /* special handling for registers */ - if ((offset & 0xc00000/4) == 0) - { - uint8_t access; - - /* some special stuff for Voodoo 2 */ - if (vd_type >= TYPE_VOODOO_2) - { - /* we might be in CMDFIFO mode */ - if (FBIINIT7_CMDFIFO_ENABLE(reg[fbiInit7].u)) - { - /* if bit 21 is set, we're writing to the FIFO */ - if (offset & 0x200000/4) - { - /* check for byte swizzling (bit 18) */ - if (offset & 0x40000/4) - data = swapendian_int32(data); - cmdfifo_w(this, &fbi.cmdfifo[0], offset & 0xffff, data); - g_profiler.stop(); - return; - } - - /* we're a register access; but only certain ones are allowed */ - access = regaccess[offset & 0xff]; - if (!(access & REGISTER_WRITETHRU)) - { - /* track swap buffers regardless */ - if ((offset & 0xff) == swapbufferCMD) - fbi.swaps_pending++; - - logerror("Ignoring write to %s in CMDFIFO mode\n", regnames[offset & 0xff]); - g_profiler.stop(); - return; - } - } - - /* if not, we might be byte swizzled (bit 20) */ - else if (offset & 0x100000/4) - data = swapendian_int32(data); - } - - /* check the access behavior; note that the table works even if the */ - /* alternate mapping is used */ - access = regaccess[offset & 0xff]; - - /* ignore if writes aren't allowed */ - if (!(access & REGISTER_WRITE)) - { - g_profiler.stop(); - return; - } - - // if this is non-FIFO command, execute immediately - if (!(access & REGISTER_FIFO)) { - register_w(this, offset, data); - g_profiler.stop(); - return; - } - - /* track swap buffers */ - if ((offset & 0xff) == swapbufferCMD) - fbi.swaps_pending++; - } - - /* if we don't have anything pending, or if FIFOs are disabled, just execute */ - if (!pci.op_pending || !INITEN_ENABLE_PCI_FIFO(pci.init_enable)) - { - int cycles; - - /* target the appropriate location */ - if ((offset & (0xc00000/4)) == 0) - cycles = register_w(this, offset, data); - else if (offset & (0x800000/4)) - cycles = texture_w(this, offset, data); - else - cycles = lfb_w(this, offset, data, mem_mask); - - /* if we ended up with cycles, mark the operation pending */ - if (cycles) - { - pci.op_pending = true; - pci.op_end_time = machine().time() + attotime(0, (attoseconds_t)cycles * attoseconds_per_cycle); - - if (LOG_FIFO_VERBOSE) - { - logerror("VOODOO.FIFO:direct write start at %d.%018d end at %d.%018d\n", - machine().time().seconds(), machine().time().attoseconds(), - pci.op_end_time.seconds(), pci.op_end_time.attoseconds()); - } - } - g_profiler.stop(); - return; - } - - /* modify the offset based on the mem_mask */ - if (mem_mask != 0xffffffff) - { - if (!ACCESSING_BITS_16_31) - offset |= 0x80000000; - if (!ACCESSING_BITS_0_15) - offset |= 0x40000000; - } - - /* if there's room in the PCI FIFO, add there */ - if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w adding to PCI FIFO @ %08X=%08X\n", this, offset, data); - if (!pci.fifo.full()) - { - pci.fifo.add(offset); - pci.fifo.add(data); - } - else - fatalerror("PCI FIFO full\n"); - - /* handle flushing to the memory FIFO */ - if (FBIINIT0_ENABLE_MEMORY_FIFO(reg[fbiInit0].u) && - pci.fifo.space() <= 2 * FBIINIT4_MEMORY_FIFO_LWM(reg[fbiInit4].u)) - { - uint8_t valid[4]; - - /* determine which types of data can go to the memory FIFO */ - valid[0] = true; - valid[1] = FBIINIT0_LFB_TO_MEMORY_FIFO(reg[fbiInit0].u); - valid[2] = valid[3] = FBIINIT0_TEXMEM_TO_MEMORY_FIFO(reg[fbiInit0].u); - - /* flush everything we can */ - if (LOG_FIFO_VERBOSE) logerror("VOODOO.FIFO:voodoo_w moving PCI FIFO to memory FIFO\n"); - while (!pci.fifo.empty() && valid[(pci.fifo.peek() >> 22) & 3]) - { - fbi.fifo.add(pci.fifo.remove()); - fbi.fifo.add(pci.fifo.remove()); - } - - /* if we're above the HWM as a result, stall */ - if (FBIINIT0_STALL_PCIE_FOR_HWM(reg[fbiInit0].u) && - fbi.fifo.items() >= 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(reg[fbiInit0].u)) - { - if (LOG_FIFO) logerror("VOODOO.FIFO:voodoo_w hit memory FIFO HWM -- stalling\n"); - stall_cpu(STALLED_UNTIL_FIFO_LWM, machine().time()); - } - } - - /* if we're at the LWM for the PCI FIFO, stall */ - if (FBIINIT0_STALL_PCIE_FOR_HWM(reg[fbiInit0].u) && - pci.fifo.space() <= 2 * FBIINIT0_PCI_FIFO_LWM(reg[fbiInit0].u)) - { - if (LOG_FIFO) logerror("VOODOO.FIFO:voodoo_w hit PCI FIFO free LWM -- stalling\n"); - stall_cpu(STALLED_UNTIL_FIFO_LWM, machine().time()); - } - - /* if we weren't ready, and this is a non-FIFO access, stall until the FIFOs are clear */ - if (stall) - { - if (LOG_FIFO_VERBOSE) logerror("VOODOO.FIFO:voodoo_w wrote non-FIFO register -- stalling until clear\n"); - stall_cpu(STALLED_UNTIL_FIFO_EMPTY, machine().time()); - } - - g_profiler.stop(); -} - - - -/************************************* - * - * Handle a register read - * - *************************************/ - -uint32_t voodoo_device::register_r(voodoo_device *vd, offs_t offset) -{ - int regnum = offset & 0xff; - uint32_t result; - - /* statistics */ - vd->stats.reg_reads++; - - /* first make sure this register is readable */ - if (!(vd->regaccess[regnum] & REGISTER_READ)) - { - vd->logerror("VOODOO.ERROR:Invalid attempt to read %s\n", regnum < 225 ? vd->regnames[regnum] : "unknown register"); - return 0xffffffff; - } - - /* default result is the FBI register value */ - result = vd->reg[regnum].u; - - /* some registers are dynamic; compute them */ - switch (regnum) - { - case vdstatus: - - /* start with a blank slate */ - result = 0; - - /* bits 5:0 are the PCI FIFO free space */ - if (vd->pci.fifo.empty()) - result |= 0x3f << 0; - else - { - int temp = vd->pci.fifo.space()/2; - if (temp > 0x3f) - temp = 0x3f; - result |= temp << 0; - } - - /* bit 6 is the vertical retrace */ - result |= vd->fbi.vblank << 6; - - /* bit 7 is FBI graphics engine busy */ - if (vd->pci.op_pending) - result |= 1 << 7; - - /* bit 8 is TREX busy */ - if (vd->pci.op_pending) - result |= 1 << 8; - - /* bit 9 is overall busy */ - if (vd->pci.op_pending) - result |= 1 << 9; - - /* Banshee is different starting here */ - if (vd->vd_type < TYPE_VOODOO_BANSHEE) - { - /* bits 11:10 specifies which buffer is visible */ - result |= vd->fbi.frontbuf << 10; - - /* bits 27:12 indicate memory FIFO freespace */ - if (!FBIINIT0_ENABLE_MEMORY_FIFO(vd->reg[fbiInit0].u) || vd->fbi.fifo.empty()) - result |= 0xffff << 12; - else - { - int temp = vd->fbi.fifo.space()/2; - if (temp > 0xffff) - temp = 0xffff; - result |= temp << 12; - } - } - else - { - /* bit 10 is 2D busy */ - - /* bit 11 is cmd FIFO 0 busy */ - if (vd->fbi.cmdfifo[0].enable && vd->fbi.cmdfifo[0].depth > 0) - result |= 1 << 11; - - /* bit 12 is cmd FIFO 1 busy */ - if (vd->fbi.cmdfifo[1].enable && vd->fbi.cmdfifo[1].depth > 0) - result |= 1 << 12; - } - - /* bits 30:28 are the number of pending swaps */ - if (vd->fbi.swaps_pending > 7) - result |= 7 << 28; - else - result |= vd->fbi.swaps_pending << 28; - - /* bit 31 is not used */ - - /* eat some cycles since people like polling here */ - if (EAT_CYCLES) vd->m_cpu->eat_cycles(1000); - break; - - /* bit 2 of the initEnable register maps this to dacRead */ - case fbiInit2: - if (INITEN_REMAP_INIT_TO_DAC(vd->pci.init_enable)) - result = vd->dac.read_result; - break; - - /* return the current visible scanline */ - case vRetrace: - /* eat some cycles since people like polling here */ - if (EAT_CYCLES) vd->m_cpu->eat_cycles(10); - // Return 0 if vblank is active - if (vd->fbi.vblank) { - result = 0; - } - else { - // Want screen position from vblank off - result = vd->m_screen->vpos(); - } - break; - - /* return visible horizontal and vertical positions. Read by the Vegas startup sequence */ - case hvRetrace: - /* eat some cycles since people like polling here */ - if (EAT_CYCLES) vd->m_cpu->eat_cycles(10); - //result = 0x200 << 16; /* should be between 0x7b and 0x267 */ - //result |= 0x80; /* should be between 0x17 and 0x103 */ - // Return 0 if vblank is active - if (vd->fbi.vblank) { - result = 0; - } - else { - // Want screen position from vblank off - result = vd->m_screen->vpos(); - } - // Hpos - result |= vd->m_screen->hpos() << 16; - break; - - /* cmdFifo -- Voodoo2 only */ - case cmdFifoRdPtr: - result = vd->fbi.cmdfifo[0].rdptr; - - /* eat some cycles since people like polling here */ - if (EAT_CYCLES) vd->m_cpu->eat_cycles(1000); - break; - - case cmdFifoAMin: - result = vd->fbi.cmdfifo[0].amin; - break; - - case cmdFifoAMax: - result = vd->fbi.cmdfifo[0].amax; - break; - - case cmdFifoDepth: - result = vd->fbi.cmdfifo[0].depth; - break; - - case cmdFifoHoles: - result = vd->fbi.cmdfifo[0].holes; - break; - - /* all counters are 24-bit only */ - case fbiPixelsIn: - case fbiChromaFail: - case fbiZfuncFail: - case fbiAfuncFail: - case fbiPixelsOut: - vd->update_statistics(true); - [[fallthrough]]; - case fbiTrianglesOut: - result = vd->reg[regnum].u & 0xffffff; - break; - } - - if (LOG_REGISTERS) - { - int logit = true; - - /* don't log multiple identical status reads from the same address */ - if (regnum == vdstatus) - { - offs_t pc = vd->m_cpu->pc(); - if (pc == vd->last_status_pc && result == vd->last_status_value) - logit = false; - vd->last_status_pc = pc; - vd->last_status_value = result; - } - if (regnum == cmdFifoRdPtr) - logit = false; - - if (logit) - vd->logerror("VOODOO.REG:%s read = %08X\n", vd->regnames[regnum], result); - } - - return result; -} - - - -/************************************* - * - * Handle an LFB read - * - *************************************/ - -static uint32_t lfb_r(voodoo_device *vd, offs_t offset, bool lfb_3d) -{ - uint16_t *buffer; - uint32_t bufmax; - uint32_t bufoffs; - uint32_t data; - int x, y, scry, destbuf; - - /* statistics */ - vd->stats.lfb_reads++; - - /* compute X,Y */ - offset <<= 1; - x = offset & ((1 << vd->fbi.lfb_stride) - 1); - y = (offset >> vd->fbi.lfb_stride); - - /* select the target buffer */ - if (lfb_3d) { - y &= 0x3ff; - destbuf = (vd->vd_type >= TYPE_VOODOO_BANSHEE) ? 1 : LFBMODE_READ_BUFFER_SELECT(vd->reg[lfbMode].u); - switch (destbuf) - { - case 0: /* front buffer */ - buffer = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.frontbuf]); - bufmax = (vd->fbi.mask + 1 - vd->fbi.rgboffs[vd->fbi.frontbuf]) / 2; - break; - - case 1: /* back buffer */ - buffer = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.backbuf]); - bufmax = (vd->fbi.mask + 1 - vd->fbi.rgboffs[vd->fbi.backbuf]) / 2; - break; - - case 2: /* aux buffer */ - if (vd->fbi.auxoffs == ~0) - return 0xffffffff; - buffer = (uint16_t *)(vd->fbi.ram + vd->fbi.auxoffs); - bufmax = (vd->fbi.mask + 1 - vd->fbi.auxoffs) / 2; - break; - - default: /* reserved */ - return 0xffffffff; - } - - /* determine the screen Y */ - scry = y; - if (LFBMODE_Y_ORIGIN(vd->reg[lfbMode].u)) - scry = (vd->fbi.yorigin - y); - } else { - // Direct lfb access - buffer = (uint16_t *)(vd->fbi.ram + vd->fbi.lfb_base*4); - bufmax = (vd->fbi.mask + 1 - vd->fbi.lfb_base*4) / 2; - scry = y; - } - - /* advance pointers to the proper row */ - bufoffs = scry * vd->fbi.rowpixels + x; - if (bufoffs >= bufmax) { - vd->logerror("LFB_R: Buffer offset out of bounds x=%i y=%i lfb_3d=%i offset=%08X bufoffs=%08X\n", x, y, lfb_3d, offset, (uint32_t) bufoffs); - return 0xffffffff; - } - - /* wait for any outstanding work to finish */ - poly_wait(vd->poly, "LFB read"); - - /* compute the data */ - data = buffer[bufoffs + 0] | (buffer[bufoffs + 1] << 16); - - /* word swapping */ - if (LFBMODE_WORD_SWAP_READS(vd->reg[lfbMode].u)) - data = (data << 16) | (data >> 16); - - /* byte swizzling */ - if (LFBMODE_BYTE_SWIZZLE_READS(vd->reg[lfbMode].u)) - data = swapendian_int32(data); - - if (LOG_LFB) vd->logerror("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data); - return data; -} - - - -/************************************* - * - * Handle a read from the Voodoo - * memory space - * - *************************************/ - -u32 voodoo_device::voodoo_r(offs_t offset) -{ - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - /* target the appropriate location */ - if (!(offset & (0xc00000/4))) - return register_r(this, offset); - else if (!(offset & (0x800000/4))) - return lfb_r(this, offset, true); - - return 0xffffffff; -} - - - -/************************************* - * - * Handle a read from the Banshee - * I/O space - * - *************************************/ - -u32 voodoo_banshee_device::banshee_agp_r(offs_t offset) -{ - uint32_t result; - - offset &= 0x1ff/4; - - /* switch off the offset */ - switch (offset) - { - case cmdRdPtrL0: - result = fbi.cmdfifo[0].rdptr; - break; - - case cmdAMin0: - result = fbi.cmdfifo[0].amin; - break; - - case cmdAMax0: - result = fbi.cmdfifo[0].amax; - break; - - case cmdFifoDepth0: - result = fbi.cmdfifo[0].depth; - break; - - case cmdHoleCnt0: - result = fbi.cmdfifo[0].holes; - break; - - case cmdRdPtrL1: - result = fbi.cmdfifo[1].rdptr; - break; - - case cmdAMin1: - result = fbi.cmdfifo[1].amin; - break; - - case cmdAMax1: - result = fbi.cmdfifo[1].amax; - break; - - case cmdFifoDepth1: - result = fbi.cmdfifo[1].depth; - break; - - case cmdHoleCnt1: - result = fbi.cmdfifo[1].holes; - break; - - default: - result = banshee.agp[offset]; - break; - } - - if (LOG_REGISTERS) - logerror("%s:banshee_r(AGP:%s)\n", machine().describe_context(), banshee_agp_reg_name[offset]); - return result; -} - - -u32 voodoo_banshee_device::banshee_r(offs_t offset, u32 mem_mask) -{ - uint32_t result = 0xffffffff; - - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - if (offset < 0x80000/4) - result = banshee_io_r(offset, mem_mask); - else if (offset < 0x100000/4) - result = banshee_agp_r(offset); - else if (offset < 0x200000/4) - logerror("%s:banshee_r(2D:%X)\n", machine().describe_context(), (offset*4) & 0xfffff); - else if (offset < 0x600000/4) - result = register_r(this, offset & 0x1fffff/4); - else if (offset < 0x800000/4) - logerror("%s:banshee_r(TEX0:%X)\n", machine().describe_context(), (offset*4) & 0x1fffff); - else if (offset < 0xa00000/4) - logerror("%s:banshee_r(TEX1:%X)\n", machine().describe_context(), (offset*4) & 0x1fffff); - else if (offset < 0xc00000/4) - logerror("%s:banshee_r(FLASH Bios ROM:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); - else if (offset < 0x1000000/4) - logerror("%s:banshee_r(YUV:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); - else if (offset < 0x2000000/4) - { - result = lfb_r(this, offset & 0xffffff/4, true); - } else { - logerror("%s:banshee_r(%X) Access out of bounds\n", machine().describe_context(), offset*4); - } - return result; -} - - -u32 voodoo_banshee_device::banshee_fb_r(offs_t offset) -{ - uint32_t result = 0xffffffff; - - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - if (offset < fbi.lfb_base) - { -#if LOG_LFB - logerror("%s:banshee_fb_r(%X)\n", machine().describe_context(), offset*4); -#endif - if (offset*4 <= fbi.mask) - result = ((uint32_t *)fbi.ram)[offset]; - else - logerror("%s:banshee_fb_r(%X) Access out of bounds\n", machine().describe_context(), offset*4); - } - else { - if (LOG_LFB) - logerror("%s:banshee_fb_r(%X) to lfb_r: %08X lfb_base=%08X\n", machine().describe_context(), offset*4, offset - fbi.lfb_base, fbi.lfb_base); - result = lfb_r(this, offset - fbi.lfb_base, false); - } - return result; -} - - -u8 voodoo_banshee_device::banshee_vga_r(offs_t offset) -{ - uint8_t result = 0xff; - - offset &= 0x1f; - - /* switch off the offset */ - switch (offset + 0x3c0) - { - /* attribute access */ - case 0x3c0: - if (banshee.vga[0x3c1 & 0x1f] < std::size(banshee.att)) - result = banshee.att[banshee.vga[0x3c1 & 0x1f]]; - if (LOG_REGISTERS) - logerror("%s:banshee_att_r(%X)\n", machine().describe_context(), banshee.vga[0x3c1 & 0x1f]); - break; - - /* Input status 0 */ - case 0x3c2: - /* - bit 7 = Interrupt Status. When its value is ?1?, denotes that an interrupt is pending. - bit 6:5 = Feature Connector. These 2 bits are readable bits from the feature connector. - bit 4 = Sense. This bit reflects the state of the DAC monitor sense logic. - bit 3:0 = Reserved. Read back as 0. - */ - result = 0x00; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset); - break; - - /* Sequencer access */ - case 0x3c5: - if (banshee.vga[0x3c4 & 0x1f] < std::size(banshee.seq)) - result = banshee.seq[banshee.vga[0x3c4 & 0x1f]]; - if (LOG_REGISTERS) - logerror("%s:banshee_seq_r(%X)\n", machine().describe_context(), banshee.vga[0x3c4 & 0x1f]); - break; - - /* Feature control */ - case 0x3ca: - result = banshee.vga[0x3da & 0x1f]; - banshee.attff = 0; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset); - break; - - /* Miscellaneous output */ - case 0x3cc: - result = banshee.vga[0x3c2 & 0x1f]; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset); - break; - - /* Graphics controller access */ - case 0x3cf: - if (banshee.vga[0x3ce & 0x1f] < std::size(banshee.gc)) - result = banshee.gc[banshee.vga[0x3ce & 0x1f]]; - if (LOG_REGISTERS) - logerror("%s:banshee_gc_r(%X)\n", machine().describe_context(), banshee.vga[0x3ce & 0x1f]); - break; - - /* CRTC access */ - case 0x3d5: - if (banshee.vga[0x3d4 & 0x1f] < std::size(banshee.crtc)) - result = banshee.crtc[banshee.vga[0x3d4 & 0x1f]]; - if (LOG_REGISTERS) - logerror("%s:banshee_crtc_r(%X)\n", machine().describe_context(), banshee.vga[0x3d4 & 0x1f]); - break; - - /* Input status 1 */ - case 0x3da: - /* - bit 7:6 = Reserved. These bits read back 0. - bit 5:4 = Display Status. These 2 bits reflect 2 of the 8 pixel data outputs from the Attribute - controller, as determined by the Attribute controller index 0x12 bits 4 and 5. - bit 3 = Vertical sync Status. A ?1? indicates vertical retrace is in progress. - bit 2:1 = Reserved. These bits read back 0x2. - bit 0 = Display Disable. When this bit is 1, either horizontal or vertical display end has occurred, - otherwise video data is being displayed. - */ - result = 0x04; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset); - break; - - default: - result = banshee.vga[offset]; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset); - break; - } - return result; -} - - -u32 voodoo_banshee_device::banshee_io_r(offs_t offset, u32 mem_mask) -{ - uint32_t result; - - offset &= 0xff/4; - - /* switch off the offset */ - switch (offset) - { - case io_status: - result = register_r(this, 0); - break; - - case io_dacData: - result = fbi.clut[banshee.io[io_dacAddr] & 0x1ff] = banshee.io[offset]; - if (LOG_REGISTERS) - logerror("%s:banshee_dac_r(%X)\n", machine().describe_context(), banshee.io[io_dacAddr] & 0x1ff); - break; - - case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc: - case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc: - case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc: - result = 0; - if (ACCESSING_BITS_0_7) - result |= banshee_vga_r(offset*4+0) << 0; - if (ACCESSING_BITS_8_15) - result |= banshee_vga_r(offset*4+1) << 8; - if (ACCESSING_BITS_16_23) - result |= banshee_vga_r(offset*4+2) << 16; - if (ACCESSING_BITS_24_31) - result |= banshee_vga_r(offset*4+3) << 24; - break; - - default: - result = banshee.io[offset]; - if (LOG_REGISTERS) - logerror("%s:banshee_io_r(%s)\n", machine().describe_context(), banshee_io_reg_name[offset]); - break; - } - - return result; -} - - -u32 voodoo_banshee_device::banshee_rom_r(offs_t offset) -{ - logerror("%s:banshee_rom_r(%X)\n", machine().describe_context(), offset*4); - return 0xffffffff; -} - -static void blit_2d(voodoo_device *vd, uint32_t data) -{ - switch (vd->banshee.blt_cmd) - { - case 0: // NOP - wait for idle - { - break; - } - - case 1: // Screen-to-screen blit - { - // TODO -#if LOG_BANSHEE_2D - vd->logerror(" blit_2d:screen_to_screen: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - break; - } - - case 2: // Screen-to-screen stretch blit - { - fatalerror(" blit_2d:screen_to_screen_stretch: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); - } - - case 3: // Host-to-screen blit - { - uint32_t addr = vd->banshee.blt_dst_base; - - addr += (vd->banshee.blt_dst_y * vd->banshee.blt_dst_stride) + (vd->banshee.blt_dst_x * vd->banshee.blt_dst_bpp); - -#if LOG_BANSHEE_2D - vd->logerror(" blit_2d:host_to_screen: %08x -> %08x, %d, %d\n", data, addr, vd->banshee.blt_dst_x, vd->banshee.blt_dst_y); -#endif - - switch (vd->banshee.blt_dst_bpp) - { - case 1: - vd->fbi.ram[addr+0] = data & 0xff; - vd->fbi.ram[addr+1] = (data >> 8) & 0xff; - vd->fbi.ram[addr+2] = (data >> 16) & 0xff; - vd->fbi.ram[addr+3] = (data >> 24) & 0xff; - vd->banshee.blt_dst_x += 4; - break; - case 2: - vd->fbi.ram[addr+1] = data & 0xff; - vd->fbi.ram[addr+0] = (data >> 8) & 0xff; - vd->fbi.ram[addr+3] = (data >> 16) & 0xff; - vd->fbi.ram[addr+2] = (data >> 24) & 0xff; - vd->banshee.blt_dst_x += 2; - break; - case 3: - vd->banshee.blt_dst_x += 1; - break; - case 4: - vd->fbi.ram[addr+3] = data & 0xff; - vd->fbi.ram[addr+2] = (data >> 8) & 0xff; - vd->fbi.ram[addr+1] = (data >> 16) & 0xff; - vd->fbi.ram[addr+0] = (data >> 24) & 0xff; - vd->banshee.blt_dst_x += 1; - break; - } - - if (vd->banshee.blt_dst_x >= vd->banshee.blt_dst_width) - { - vd->banshee.blt_dst_x = 0; - vd->banshee.blt_dst_y++; - } - break; - } - - case 5: // Rectangle fill - { - fatalerror("blit_2d:rectangle_fill: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); - } - - case 6: // Line - { - fatalerror("blit_2d:line: end X %d, end Y %d\n", data & 0xfff, (data >> 16) & 0xfff); - } - - case 7: // Polyline - { - fatalerror("blit_2d:polyline: end X %d, end Y %d\n", data & 0xfff, (data >> 16) & 0xfff); - } - - case 8: // Polygon fill - { - fatalerror("blit_2d:polygon_fill\n"); - } - - default: - { - fatalerror("blit_2d: unknown command %d\n", vd->banshee.blt_cmd); - } - } -} - -int32_t voodoo_device::banshee_2d_w(voodoo_device *vd, offs_t offset, uint32_t data) -{ - switch (offset) - { - case banshee2D_command: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:command: cmd %d, ROP0 %02X\n", data & 0xf, data >> 24); -#endif - - vd->banshee.blt_src_x = vd->banshee.blt_regs[banshee2D_srcXY] & 0xfff; - vd->banshee.blt_src_y = (vd->banshee.blt_regs[banshee2D_srcXY] >> 16) & 0xfff; - vd->banshee.blt_src_base = vd->banshee.blt_regs[banshee2D_srcBaseAddr] & 0xffffff; - vd->banshee.blt_src_stride = vd->banshee.blt_regs[banshee2D_srcFormat] & 0x3fff; - vd->banshee.blt_src_width = vd->banshee.blt_regs[banshee2D_srcSize] & 0xfff; - vd->banshee.blt_src_height = (vd->banshee.blt_regs[banshee2D_srcSize] >> 16) & 0xfff; - - switch ((vd->banshee.blt_regs[banshee2D_srcFormat] >> 16) & 0xf) - { - case 1: vd->banshee.blt_src_bpp = 1; break; - case 3: vd->banshee.blt_src_bpp = 2; break; - case 4: vd->banshee.blt_src_bpp = 3; break; - case 5: vd->banshee.blt_src_bpp = 4; break; - case 8: vd->banshee.blt_src_bpp = 2; break; - case 9: vd->banshee.blt_src_bpp = 2; break; - default: vd->banshee.blt_src_bpp = 1; break; - } - - vd->banshee.blt_dst_x = vd->banshee.blt_regs[banshee2D_dstXY] & 0xfff; - vd->banshee.blt_dst_y = (vd->banshee.blt_regs[banshee2D_dstXY] >> 16) & 0xfff; - vd->banshee.blt_dst_base = vd->banshee.blt_regs[banshee2D_dstBaseAddr] & 0xffffff; - vd->banshee.blt_dst_stride = vd->banshee.blt_regs[banshee2D_dstFormat] & 0x3fff; - vd->banshee.blt_dst_width = vd->banshee.blt_regs[banshee2D_dstSize] & 0xfff; - vd->banshee.blt_dst_height = (vd->banshee.blt_regs[banshee2D_dstSize] >> 16) & 0xfff; - - switch ((vd->banshee.blt_regs[banshee2D_dstFormat] >> 16) & 0x7) - { - case 1: vd->banshee.blt_dst_bpp = 1; break; - case 3: vd->banshee.blt_dst_bpp = 2; break; - case 4: vd->banshee.blt_dst_bpp = 3; break; - case 5: vd->banshee.blt_dst_bpp = 4; break; - default: vd->banshee.blt_dst_bpp = 1; break; - } - - vd->banshee.blt_cmd = data & 0xf; - break; - - case banshee2D_colorBack: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:colorBack: %08X\n", data); -#endif - vd->banshee.blt_regs[banshee2D_colorBack] = data; - break; - - case banshee2D_colorFore: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:colorFore: %08X\n", data); -#endif - vd->banshee.blt_regs[banshee2D_colorFore] = data; - break; - - case banshee2D_srcBaseAddr: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:srcBaseAddr: %08X, %s\n", data & 0xffffff, data & 0x80000000 ? "tiled" : "non-tiled"); -#endif - vd->banshee.blt_regs[banshee2D_srcBaseAddr] = data; - break; - - case banshee2D_dstBaseAddr: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:dstBaseAddr: %08X, %s\n", data & 0xffffff, data & 0x80000000 ? "tiled" : "non-tiled"); -#endif - vd->banshee.blt_regs[banshee2D_dstBaseAddr] = data; - break; - - case banshee2D_srcSize: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:srcSize: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_srcSize] = data; - break; - - case banshee2D_dstSize: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:dstSize: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_dstSize] = data; - break; - - case banshee2D_srcXY: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:srcXY: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_srcXY] = data; - break; - - case banshee2D_dstXY: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:dstXY: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_dstXY] = data; - break; - - case banshee2D_srcFormat: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:srcFormat: str %d, fmt %d, packing %d\n", data & 0x3fff, (data >> 16) & 0xf, (data >> 22) & 0x3); -#endif - vd->banshee.blt_regs[banshee2D_srcFormat] = data; - break; - - case banshee2D_dstFormat: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:dstFormat: str %d, fmt %d\n", data & 0x3fff, (data >> 16) & 0xf); -#endif - vd->banshee.blt_regs[banshee2D_dstFormat] = data; - break; - - case banshee2D_clip0Min: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:clip0Min: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_clip0Min] = data; - break; - - case banshee2D_clip0Max: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:clip0Max: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_clip0Max] = data; - break; - - case banshee2D_clip1Min: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:clip1Min: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_clip1Min] = data; - break; - - case banshee2D_clip1Max: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:clip1Max: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); -#endif - vd->banshee.blt_regs[banshee2D_clip1Max] = data; - break; - - case banshee2D_rop: -#if LOG_BANSHEE_2D - vd->logerror(" 2D:rop: %d, %d, %d\n", data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff); -#endif - vd->banshee.blt_regs[banshee2D_rop] = data; - break; - - default: - if (offset >= 0x20 && offset < 0x40) - { - blit_2d(vd, data); - } - else if (offset >= 0x40 && offset < 0x80) - { - // TODO: colorPattern - } - break; - } - - - return 1; -} - - - - -void voodoo_banshee_device::banshee_agp_w(offs_t offset, u32 data, u32 mem_mask) -{ - offset &= 0x1ff/4; - - /* switch off the offset */ - switch (offset) - { - case cmdBaseAddr0: - COMBINE_DATA(&banshee.agp[offset]); - fbi.cmdfifo[0].base = (data & 0xffffff) << 12; - fbi.cmdfifo[0].end = fbi.cmdfifo[0].base + (((banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12); - break; - - case cmdBaseSize0: - COMBINE_DATA(&banshee.agp[offset]); - fbi.cmdfifo[0].end = fbi.cmdfifo[0].base + (((banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12); - fbi.cmdfifo[0].enable = (data >> 8) & 1; - fbi.cmdfifo[0].count_holes = (~data >> 10) & 1; - break; - - case cmdBump0: - fatalerror("cmdBump0\n"); - - case cmdRdPtrL0: - fbi.cmdfifo[0].rdptr = data; - break; - - case cmdAMin0: - fbi.cmdfifo[0].amin = data; - break; - - case cmdAMax0: - fbi.cmdfifo[0].amax = data; - break; - - case cmdFifoDepth0: - fbi.cmdfifo[0].depth = data; - break; - - case cmdHoleCnt0: - fbi.cmdfifo[0].holes = data; - break; - - case cmdBaseAddr1: - COMBINE_DATA(&banshee.agp[offset]); - fbi.cmdfifo[1].base = (data & 0xffffff) << 12; - fbi.cmdfifo[1].end = fbi.cmdfifo[1].base + (((banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12); - break; - - case cmdBaseSize1: - COMBINE_DATA(&banshee.agp[offset]); - fbi.cmdfifo[1].end = fbi.cmdfifo[1].base + (((banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12); - fbi.cmdfifo[1].enable = (data >> 8) & 1; - fbi.cmdfifo[1].count_holes = (~data >> 10) & 1; - break; - - case cmdBump1: - fatalerror("cmdBump1\n"); - - case cmdRdPtrL1: - fbi.cmdfifo[1].rdptr = data; - break; - - case cmdAMin1: - fbi.cmdfifo[1].amin = data; - break; - - case cmdAMax1: - fbi.cmdfifo[1].amax = data; - break; - - case cmdFifoDepth1: - fbi.cmdfifo[1].depth = data; - break; - - case cmdHoleCnt1: - fbi.cmdfifo[1].holes = data; - break; - - default: - COMBINE_DATA(&banshee.agp[offset]); - break; - } - - if (LOG_REGISTERS) - logerror("%s:banshee_w(AGP:%s) = %08X & %08X\n", machine().describe_context(), banshee_agp_reg_name[offset], data, mem_mask); -} - - -void voodoo_banshee_device::banshee_w(offs_t offset, u32 data, u32 mem_mask) -{ - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - if (offset < 0x80000/4) - banshee_io_w(offset, data, mem_mask); - else if (offset < 0x100000/4) - banshee_agp_w(offset, data, mem_mask); - else if (offset < 0x200000/4) - logerror("%s:banshee_w(2D:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0xfffff, data, mem_mask); - else if (offset < 0x600000/4) - register_w(this, offset & 0x1fffff/4, data); - else if (offset < 0x800000/4) - logerror("%s:banshee_w(TEX0:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x1fffff, data, mem_mask); - else if (offset < 0xa00000/4) - logerror("%s:banshee_w(TEX1:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x1fffff, data, mem_mask); - else if (offset < 0xc00000/4) - logerror("%s:banshee_r(FLASH Bios ROM:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); - else if (offset < 0x1000000/4) - logerror("%s:banshee_w(YUV:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x3fffff, data, mem_mask); - else if (offset < 0x2000000/4) - { - lfb_w(this, offset & 0xffffff/4, data, mem_mask); - } else { - logerror("%s:banshee_w Address out of range %08X = %08X & %08X\n", machine().describe_context(), (offset*4), data, mem_mask); - } -} - - -void voodoo_banshee_device::banshee_fb_w(offs_t offset, u32 data, u32 mem_mask) -{ - uint32_t addr = offset*4; - - /* if we have something pending, flush the FIFOs up to the current time */ - if (pci.op_pending) - flush_fifos(this, machine().time()); - - if (offset < fbi.lfb_base) - { - if (fbi.cmdfifo[0].enable && addr >= fbi.cmdfifo[0].base && addr < fbi.cmdfifo[0].end) - cmdfifo_w(this, &fbi.cmdfifo[0], (addr - fbi.cmdfifo[0].base) / 4, data); - else if (fbi.cmdfifo[1].enable && addr >= fbi.cmdfifo[1].base && addr < fbi.cmdfifo[1].end) - cmdfifo_w(this, &fbi.cmdfifo[1], (addr - fbi.cmdfifo[1].base) / 4, data); - else - { - if (offset*4 <= fbi.mask) - COMBINE_DATA(&((uint32_t *)fbi.ram)[offset]); - else - logerror("%s:banshee_fb_w Out of bounds (%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); -#if LOG_LFB - logerror("%s:banshee_fb_w(%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); -#endif - } - } - else - lfb_direct_w(offset - fbi.lfb_base, data, mem_mask); -} - - -void voodoo_banshee_device::banshee_vga_w(offs_t offset, u8 data) -{ - offset &= 0x1f; - - /* switch off the offset */ - switch (offset + 0x3c0) - { - /* attribute access */ - case 0x3c0: - case 0x3c1: - if (banshee.attff == 0) - { - banshee.vga[0x3c1 & 0x1f] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_w(%X) = %02X\n", machine().describe_context(), 0x3c0+offset, data); - } - else - { - if (banshee.vga[0x3c1 & 0x1f] < std::size(banshee.att)) - banshee.att[banshee.vga[0x3c1 & 0x1f]] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_att_w(%X) = %02X\n", machine().describe_context(), banshee.vga[0x3c1 & 0x1f], data); - } - banshee.attff ^= 1; - break; - - /* Sequencer access */ - case 0x3c5: - if (banshee.vga[0x3c4 & 0x1f] < std::size(banshee.seq)) - banshee.seq[banshee.vga[0x3c4 & 0x1f]] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_seq_w(%X) = %02X\n", machine().describe_context(), banshee.vga[0x3c4 & 0x1f], data); - break; - - /* Graphics controller access */ - case 0x3cf: - if (banshee.vga[0x3ce & 0x1f] < std::size(banshee.gc)) - banshee.gc[banshee.vga[0x3ce & 0x1f]] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_gc_w(%X) = %02X\n", machine().describe_context(), banshee.vga[0x3ce & 0x1f], data); - break; - - /* CRTC access */ - case 0x3d5: - if (banshee.vga[0x3d4 & 0x1f] < std::size(banshee.crtc)) - banshee.crtc[banshee.vga[0x3d4 & 0x1f]] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_crtc_w(%X) = %02X\n", machine().describe_context(), banshee.vga[0x3d4 & 0x1f], data); - break; - - default: - banshee.vga[offset] = data; - if (LOG_REGISTERS) - logerror("%s:banshee_vga_w(%X) = %02X\n", machine().describe_context(), 0x3c0+offset, data); - break; - } -} - - -void voodoo_banshee_device::banshee_io_w(offs_t offset, u32 data, u32 mem_mask) -{ - uint32_t old; - - offset &= 0xff/4; - old = banshee.io[offset]; - - /* switch off the offset */ - switch (offset) - { - case io_vidProcCfg: - COMBINE_DATA(&banshee.io[offset]); - if ((banshee.io[offset] ^ old) & 0x2800) - fbi.clut_dirty = true; - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - - case io_dacData: - COMBINE_DATA(&banshee.io[offset]); - if (banshee.io[offset] != fbi.clut[banshee.io[io_dacAddr] & 0x1ff]) - { - fbi.clut[banshee.io[io_dacAddr] & 0x1ff] = banshee.io[offset]; - fbi.clut_dirty = true; - } - if (LOG_REGISTERS) - logerror("%s:banshee_dac_w(%X) = %08X & %08X\n", machine().describe_context(), banshee.io[io_dacAddr] & 0x1ff, data, mem_mask); - break; - - case io_miscInit0: - COMBINE_DATA(&banshee.io[offset]); - fbi.yorigin = (data >> 18) & 0xfff; - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - - case io_vidScreenSize: - if (data & 0xfff) - fbi.width = data & 0xfff; - if (data & 0xfff000) - fbi.height = (data >> 12) & 0xfff; - [[fallthrough]]; - case io_vidOverlayDudx: - case io_vidOverlayDvdy: - { - COMBINE_DATA(&banshee.io[offset]); - - // Get horizontal total and vertical total from CRTC registers - int htotal = (banshee.crtc[0] + 5) * 8; - int vtotal = banshee.crtc[6]; - vtotal |= ((banshee.crtc[7] >> 0) & 0x1) << 8; - vtotal |= ((banshee.crtc[7] >> 5) & 0x1) << 9; - vtotal += 2; - - int vstart = banshee.crtc[0x10]; - vstart |= ((banshee.crtc[7] >> 2) & 0x1) << 8; - vstart |= ((banshee.crtc[7] >> 7) & 0x1) << 9; - - int vstop = banshee.crtc[0x11] & 0xf; - // Compare to see if vstop is before or after low 4 bits of vstart - if (vstop < (vstart & 0xf)) - vstop |= (vstart + 0x10) & ~0xf; - else - vstop |= vstart & ~0xf; - - // Get pll k, m and n from pllCtrl0 - const uint32_t k = (banshee.io[io_pllCtrl0] >> 0) & 0x3; - const uint32_t m = (banshee.io[io_pllCtrl0] >> 2) & 0x3f; - const uint32_t n = (banshee.io[io_pllCtrl0] >> 8) & 0xff; - const double video_clock = (XTAL(14'318'181) * (n + 2) / ((m + 2) << k)).dvalue(); - const double frame_period = vtotal * htotal / video_clock; - //osd_printf_info("k: %d m: %d n: %d clock: %f period: %f rate: %.2f\n", k, m, n, video_clock, frame_period, 1.0 / frame_period); - - int width = fbi.width; - int height = fbi.height; - //vd->fbi.xoffs = hbp; - //vd->fbi.yoffs = vbp; - - if (banshee.io[io_vidOverlayDudx] != 0) - width = (fbi.width * banshee.io[io_vidOverlayDudx]) / 1048576; - if (banshee.io[io_vidOverlayDvdy] != 0) - height = (fbi.height * banshee.io[io_vidOverlayDvdy]) / 1048576; - if (LOG_REGISTERS) - logerror("configure screen: htotal: %d vtotal: %d vstart: %d vstop: %d width: %d height: %d refresh: %f\n", - htotal, vtotal, vstart, vstop, width, height, 1.0 / frame_period); - if (htotal > 0 && vtotal > 0) { - rectangle visarea(0, width - 1, 0, height - 1); - m_screen->configure(htotal, vtotal, visarea, DOUBLE_TO_ATTOSECONDS(frame_period)); - - // Set the vsync start and stop - fbi.vsyncstart = vstart; - fbi.vsyncstop = vstop; - adjust_vblank_timer(); - } - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - } - - case io_lfbMemoryConfig: - fbi.lfb_base = (data & 0x1fff) << (12-2); - fbi.lfb_stride = ((data >> 13) & 7) + 9; - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - - case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc: - case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc: - case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc: - if (ACCESSING_BITS_0_7) - banshee_vga_w(offset*4+0, data >> 0); - if (ACCESSING_BITS_8_15) - banshee_vga_w(offset*4+1, data >> 8); - if (ACCESSING_BITS_16_23) - banshee_vga_w(offset*4+2, data >> 16); - if (ACCESSING_BITS_24_31) - banshee_vga_w(offset*4+3, data >> 24); - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - - default: - COMBINE_DATA(&banshee.io[offset]); - if (LOG_REGISTERS) - logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); - break; - } -} - - - -/*************************************************************************** - DEVICE INTERFACE -***************************************************************************/ - -/*------------------------------------------------- - device start callback --------------------------------------------------*/ - -void voodoo_device::device_resolve_objects() -{ - if (!m_screen) - m_screen = m_screen_finder; - else if (m_screen_finder) - throw emu_fatalerror("%s: screen set by both configuration and direct reference (%s and %s)\n", tag(), m_screen_finder->tag(), m_screen->tag()); - else if (m_screen_finder.finder_tag() != finder_base::DUMMY_TAG) - throw emu_fatalerror("%s: configured screen %s not found\n", tag(), m_screen_finder.finder_tag()); - - if (!m_cpu) - m_cpu = m_cpu_finder; - else if (m_cpu_finder) - throw emu_fatalerror("%s: CPU set by both configuration and direct reference (%s and %s)\n", tag(), m_cpu_finder->tag(), m_cpu->tag()); - else if (m_cpu_finder.finder_tag() != finder_base::DUMMY_TAG) - throw emu_fatalerror("%s: configured CPU %s not found\n", tag(), m_cpu_finder.finder_tag()); -} - -void voodoo_device::device_start() -{ - if (!m_screen || !m_cpu) - throw device_missing_dependencies(); - - /* validate configuration */ - assert(m_fbmem > 0); - - /* copy config data */ - freq = clock(); - m_vblank.resolve(); - m_stall.resolve(); - m_pciint.resolve(); - - /* create a multiprocessor work queue */ - poly_alloc(poly, machine(), 64, sizeof(poly_extra_data), 0); - thread_stats = std::make_unique(WORK_MAX_THREADS); - - /* create a table of precomputed 1/n and log2(n) values */ - /* n ranges from 1.0000 to 2.0000 */ - for (int val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++) - { - uint32_t value = (1 << RECIPLOG_LOOKUP_BITS) + val; - voodoo_reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value; - voodoo_reciplog[val*2 + 1] = (uint32_t)(LOGB2((double)value / (double)(1 << RECIPLOG_LOOKUP_BITS)) * (double)(1 << RECIPLOG_LOOKUP_PREC)); - } - - /* create dithering tables */ - for (int val = 0; val < 256*16*2; val++) - { - int g = (val >> 0) & 1; - int x = (val >> 1) & 3; - int color = (val >> 3) & 0xff; - int y = (val >> 11) & 3; - - if (!g) - { - dither4_lookup[val] = DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3; - dither2_lookup[val] = DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3; - } - else - { - dither4_lookup[val] = DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2; - dither2_lookup[val] = DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2; - } - } - - tmu_config = 0x11; // revision 1 - - /* configure type-specific values */ - switch (vd_type) - { - case TYPE_VOODOO_1: - regaccess = voodoo_register_access; - regnames = voodoo_reg_name; - alt_regmap = 0; - fbi.lfb_stride = 10; - break; - - case TYPE_VOODOO_2: - regaccess = voodoo2_register_access; - regnames = voodoo_reg_name; - alt_regmap = 0; - fbi.lfb_stride = 10; - tmu_config |= 0x800; - break; - - case TYPE_VOODOO_BANSHEE: - regaccess = banshee_register_access; - regnames = banshee_reg_name; - alt_regmap = 1; - fbi.lfb_stride = 11; - break; - - case TYPE_VOODOO_3: - regaccess = banshee_register_access; - regnames = banshee_reg_name; - alt_regmap = 1; - fbi.lfb_stride = 11; - break; - - default: - fatalerror("Unsupported voodoo card in voodoo_start!\n"); - } - - /* set the type, and initialize the chip mask */ - index = 0; + // determine our index within the system, then set our trigger + u32 index = 0; for (device_t &scan : device_enumerator(machine().root_device())) if (scan.type() == this->type()) { @@ -5731,899 +918,2486 @@ void voodoo_device::device_start() break; index++; } + m_stall_trigger = 51324 + index; - if (m_tmumem1 != 0) - tmu_config |= 0xc0; // two TMUs + // allocate timers for VBLANK + m_vsync_stop_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_1_device::vblank_stop), this), this); + m_vsync_start_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_1_device::vblank_start),this), this); - chipmask = 0x01; - attoseconds_per_cycle = ATTOSECONDS_PER_SECOND / freq; - trigger = 51324 + index; - - /* build the rasterizer table */ - std::fill(std::begin(raster_hash), std::end(raster_hash), nullptr); - for (const raster_info *info = predef_raster_table; info->callback; info++) - add_rasterizer(this, info); - - /* set up the PCI FIFO */ - pci.fifo.base = pci.fifo_mem; - pci.fifo.size = 64*2; - pci.fifo.in = pci.fifo.out = 0; - pci.stall_state = NOT_STALLED; - pci.continue_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_device::stall_cpu_callback), this), nullptr); - - /* allocate memory */ - void *fbmem, *tmumem[2]; - uint32_t tmumem0 = m_tmumem0; - uint32_t tmumem1 = m_tmumem1; - if (vd_type <= TYPE_VOODOO_2) + // add TMUs to the chipmask if memory is specified (later chips leave + // the tmumem values at 0 and set the chipmask directly to indicate + // that RAM is shared) + if (m_tmumem0_in_mb != 0) { - /* separate FB/TMU memory */ - fbmem = (m_fbmem_alloc = std::make_unique(m_fbmem << 20)).get(); - tmumem[0] = (m_tmumem_alloc[0] = std::make_unique(m_tmumem0 << 20)).get(); - tmumem[1] = (m_tmumem1 != 0) ? (m_tmumem_alloc[1] = std::make_unique(m_tmumem1 << 20)).get() : nullptr; + m_chipmask |= 2; + if (m_tmumem1_in_mb != 0) + m_chipmask |= 4; + } + + // allocate memory + u32 total_allocation = m_fbmem_in_mb + m_tmumem0_in_mb + m_tmumem1_in_mb; + m_memory = std::make_unique(total_allocation * 1024 * 1024 + 4096); + + // configure frame buffer memory, aligning the base to a 4k boundary + m_fbram = (u8 *)(((uintptr_t(m_memory.get()) + 4095) >> 12) << 12); + m_fbmask = m_fbmem_in_mb * 1024 * 1024 - 1; + + // configure texture memory + u8 *tmumem[2] = { nullptr, nullptr }; + u8 tmusize[2] = { m_tmumem0_in_mb, m_tmumem1_in_mb }; + if (tmusize[0] != 0) + { + // separate framebuffer and texture RAM (Voodoo 1/2) + tmumem[0] = m_fbram + m_fbmem_in_mb * 1024 * 1024; + tmumem[1] = tmumem[0] + tmusize[0] * 1024 * 1024; } else { - /* shared memory */ - tmumem[0] = tmumem[1] = fbmem = (m_fbmem_alloc = std::make_unique(m_fbmem << 20)).get(); - tmumem0 = m_fbmem; - if (vd_type == TYPE_VOODOO_3) - tmumem1 = m_fbmem; + // shared framebuffer and texture RAM (Voodoo Banshee/3) + tmumem[0] = tmumem[1] = m_fbram; + tmusize[0] = tmusize[1] = m_fbmem_in_mb; } - /* set up frame buffer */ - init_fbi(this, &fbi, fbmem, m_fbmem << 20); + // initialize the frame buffer + m_rgboffs[0] = m_rgboffs[1] = m_rgboffs[2] = 0; + m_auxoffs = ~0; - /* build shared TMU tables */ - tmushare.init(); - // Point the rgb565 table to the frame buffer table - tmushare.rgb565 = fbi.rgb565; + m_frontbuf = 0; + m_backbuf = 1; + m_swaps_pending = 0; + m_video_changed = true; - /* set up the TMUs */ - tmu[0].init(vd_type, tmushare, ®[0x100], tmumem[0], tmumem0 << 20); - chipmask |= 0x02; - if (tmumem1 != 0) + m_lfb_stride = 10; + + m_width = 512; + m_height = 384; + m_xoffs = 0; + m_yoffs = 0; + m_vsyncstart = 0; + m_vsyncstop = 0; + + m_vblank = 0; + m_vblank_count = 0; + m_vblank_swap_pending = 0; + m_vblank_swap = 0; + m_vblank_dont_swap = 0; + + m_lfb_stats.reset(); + + // initialize the memory FIFO + m_fbmem_fifo.configure(nullptr, 0); + + // initialize the CLUT + for (int pen = 0; pen < 32; pen++) + m_clut[pen] = rgb_t(pen, pal5bit(pen), pal5bit(pen), pal5bit(pen)); + m_clut[32] = rgb_t(32,0xff,0xff,0xff); + m_clut_dirty = true; + + // initialize the TMUs + u16 tmu_config = 0x11; + m_tmu[0].init(0, *m_shared.get(), tmumem[0], tmusize[0] * 1024 * 1024); + if (BIT(m_chipmask, 2)) { - tmu[1].init(vd_type, tmushare, ®[0x200], tmumem[1], tmumem1 << 20); - chipmask |= 0x04; - tmu_config |= 0x40; + m_tmu[1].init(1, *m_shared.get(), tmumem[1], tmusize[1] * 1024 * 1024); + tmu_config |= 0xc0; } - /* initialize some registers */ - for (voodoo_reg &r : reg) - r.u = 0; - pci.init_enable = 0; - reg[fbiInit0].u = (1 << 4) | (0x10 << 6); - reg[fbiInit1].u = (1 << 1) | (1 << 8) | (1 << 12) | (2 << 20); - reg[fbiInit2].u = (1 << 6) | (0x100 << 23); - reg[fbiInit3].u = (2 << 13) | (0xf << 17); - reg[fbiInit4].u = (1 << 0); + // create the renderer + m_renderer = std::make_unique(machine(), tmu_config, m_shared->rgb565, m_reg, &m_tmu[0].regs(), BIT(m_chipmask, 2) ? &m_tmu[1].regs() : nullptr); - /* initialize banshee registers */ - memset(banshee.io, 0, sizeof(banshee.io)); - banshee.io[io_pciInit0] = 0x01800040; - banshee.io[io_sipMonitor] = 0x40000000; - banshee.io[io_lfbMemoryConfig] = 0x000a2200; - banshee.io[io_dramInit0] = 0x00579d29; - if (m_fbmem == 16) - banshee.io[io_dramInit0] |= 0x0c000000; // Midway Vegas (denver) expects 2 banks of 16MBit SGRAMs - else - banshee.io[io_dramInit0] |= 0x08000000; // Konami Viper expects 16MBit SGRAMs - banshee.io[io_dramInit1] = 0x00f02200; - banshee.io[io_tmuGbeInit] = 0x00000bfb; + // set up the PCI FIFO + m_pci_fifo.configure(m_pci_fifo_mem, 64*2); + m_stall_state = NOT_STALLED; + m_stall_resume_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(voodoo_1_device::stall_resume_callback), this)); - /* do a soft reset to reset everything else */ + // initialize registers + m_init_enable = 0; + m_reg.write(voodoo_regs::reg_fbiInit0, (1 << 4) | (0x10 << 6)); + m_reg.write(voodoo_regs::reg_fbiInit1, (1 << 1) | (1 << 8) | (1 << 12) | (2 << 20)); + m_reg.write(voodoo_regs::reg_fbiInit2, (1 << 6) | (0x100 << 23)); + m_reg.write(voodoo_regs::reg_fbiInit3, (2 << 13) | (0xf << 17)); + m_reg.write(voodoo_regs::reg_fbiInit4, (1 << 0)); + + // do a soft reset to reset everything else soft_reset(); - /* register for save states */ - init_save_state(this); + // register for save states + save_proxy save(*this); + register_save(save, total_allocation); } - -/*************************************************************************** - COMMAND HANDLERS -***************************************************************************/ - -/*------------------------------------------------- - fastfill - execute the 'fastfill' - command --------------------------------------------------*/ - -int32_t voodoo_device::fastfill(voodoo_device *vd) -{ - int sx = (vd->reg[clipLeftRight].u >> 16) & 0x3ff; - int ex = (vd->reg[clipLeftRight].u >> 0) & 0x3ff; - int sy = (vd->reg[clipLowYHighY].u >> 16) & 0x3ff; - int ey = (vd->reg[clipLowYHighY].u >> 0) & 0x3ff; - poly_extent extents[64]; - uint16_t dithermatrix[16]; - uint16_t *drawbuf = nullptr; - uint32_t pixels = 0; - - /* if we're not clearing either, take no time */ - if (!FBZMODE_RGB_BUFFER_MASK(vd->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(vd->reg[fbzMode].u)) - return 0; - - /* are we clearing the RGB buffer? */ - if (FBZMODE_RGB_BUFFER_MASK(vd->reg[fbzMode].u)) - { - /* determine the draw buffer */ - int destbuf = (vd->vd_type >= TYPE_VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(vd->reg[fbzMode].u); - switch (destbuf) - { - case 0: /* front buffer */ - drawbuf = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.frontbuf]); - break; - - case 1: /* back buffer */ - drawbuf = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.backbuf]); - break; - - default: /* reserved */ - break; - } - - /* determine the dither pattern */ - for (int y = 0; y < 4; y++) - { - DECLARE_DITHER_POINTERS_NO_DITHER_VAR; - COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(vd->reg[fbzMode].u, y); - for (int x = 0; x < 4; x++) - { - int r = vd->reg[color1].rgb.r; - int g = vd->reg[color1].rgb.g; - int b = vd->reg[color1].rgb.b; - - APPLY_DITHER(vd->reg[fbzMode].u, x, dither_lookup, r, g, b); - dithermatrix[y*4 + x] = (r << 11) | (g << 5) | b; - } - } - } - - /* fill in a block of extents */ - extents[0].startx = sx; - extents[0].stopx = ex; - std::fill(std::begin(extents) + 1, std::end(extents), extents[0]); - - /* iterate over blocks of extents */ - for (int y = sy; y < ey; y += std::size(extents)) - { - poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(vd->poly); - int count = (std::min)(ey - y, int(std::size(extents))); - - extra->device = vd; - memcpy(extra->dither, dithermatrix, sizeof(extra->dither)); - - pixels += poly_render_triangle_custom(vd->poly, drawbuf, global_cliprect, raster_fastfill, y, count, extents); - } - - /* 2 pixels per clock */ - return pixels / 2; -} - - -/*------------------------------------------------- - swapbuffer - execute the 'swapbuffer' - command --------------------------------------------------*/ - -int32_t voodoo_device::swapbuffer(voodoo_device* vd, uint32_t data) -{ - /* set the don't swap value for Voodoo 2 */ - vd->fbi.vblank_swap_pending = true; - vd->fbi.vblank_swap = (data >> 1) & 0xff; - vd->fbi.vblank_dont_swap = (data >> 9) & 1; - - /* if we're not syncing to the retrace, process the command immediately */ - if (!(data & 1)) - { - swap_buffers(vd); - return 0; - } - - /* determine how many cycles to wait; we deliberately overshoot here because */ - /* the final count gets updated on the VBLANK */ - return (vd->fbi.vblank_swap + 1) * vd->freq / 10; -} - - -/*------------------------------------------------- - triangle - execute the 'triangle' - command --------------------------------------------------*/ - -int32_t voodoo_device::triangle(voodoo_device *vd) -{ - int texcount; - uint16_t *drawbuf; - int destbuf; - int pixels; - - g_profiler.start(PROFILER_USER2); - - /* determine the number of TMUs involved */ - texcount = 0; - if (!FBIINIT3_DISABLE_TMUS(vd->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(vd->reg[fbzColorPath].u)) - { - texcount = 1; - if (vd->chipmask & 0x04) - texcount = 2; - } - - /* perform subpixel adjustments */ - if (FBZCP_CCA_SUBPIXEL_ADJUST(vd->reg[fbzColorPath].u)) - { - int32_t dx = 8 - (vd->fbi.ax & 15); - int32_t dy = 8 - (vd->fbi.ay & 15); - - /* adjust iterated R,G,B,A and W/Z */ - vd->fbi.startr += (dy * vd->fbi.drdy + dx * vd->fbi.drdx) >> 4; - vd->fbi.startg += (dy * vd->fbi.dgdy + dx * vd->fbi.dgdx) >> 4; - vd->fbi.startb += (dy * vd->fbi.dbdy + dx * vd->fbi.dbdx) >> 4; - vd->fbi.starta += (dy * vd->fbi.dady + dx * vd->fbi.dadx) >> 4; - vd->fbi.startw += (dy * vd->fbi.dwdy + dx * vd->fbi.dwdx) >> 4; - vd->fbi.startz += mul_32x32_shift(dy, vd->fbi.dzdy, 4) + mul_32x32_shift(dx, vd->fbi.dzdx, 4); - - /* adjust iterated W/S/T for TMU 0 */ - if (texcount >= 1) - { - vd->tmu[0].startw += (dy * vd->tmu[0].dwdy + dx * vd->tmu[0].dwdx) >> 4; - vd->tmu[0].starts += (dy * vd->tmu[0].dsdy + dx * vd->tmu[0].dsdx) >> 4; - vd->tmu[0].startt += (dy * vd->tmu[0].dtdy + dx * vd->tmu[0].dtdx) >> 4; - - /* adjust iterated W/S/T for TMU 1 */ - if (texcount >= 2) - { - vd->tmu[1].startw += (dy * vd->tmu[1].dwdy + dx * vd->tmu[1].dwdx) >> 4; - vd->tmu[1].starts += (dy * vd->tmu[1].dsdy + dx * vd->tmu[1].dsdx) >> 4; - vd->tmu[1].startt += (dy * vd->tmu[1].dtdy + dx * vd->tmu[1].dtdx) >> 4; - } - } - } - - /* wait for any outstanding work to finish */ -// poly_wait(vd->poly, "triangle"); - - /* determine the draw buffer */ - destbuf = (vd->vd_type >= TYPE_VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(vd->reg[fbzMode].u); - switch (destbuf) - { - case 0: /* front buffer */ - drawbuf = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.frontbuf]); - vd->fbi.video_changed = true; - break; - - case 1: /* back buffer */ - drawbuf = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.backbuf]); - break; - - default: /* reserved */ - return TRIANGLE_SETUP_CLOCKS; - } - - /* find a rasterizer that matches our current state */ - pixels = triangle_create_work_item(vd, drawbuf, texcount); - - /* update stats */ - vd->reg[fbiTrianglesOut].u++; - - /* update stats */ - vd->stats.total_triangles++; - - g_profiler.stop(); - - /* 1 pixel per clock, plus some setup time */ - if (LOG_REGISTERS) vd->logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels); - return TRIANGLE_SETUP_CLOCKS + pixels; -} - - -/*------------------------------------------------- - begin_triangle - execute the 'beginTri' - command --------------------------------------------------*/ - -int32_t voodoo_device::begin_triangle(voodoo_device *vd) -{ - fbi_state::setup_vertex *sv = &vd->fbi.svert[2]; - - /* extract all the data from registers */ - sv->x = vd->reg[sVx].f; - sv->y = vd->reg[sVy].f; - sv->wb = vd->reg[sWb].f; - sv->w0 = vd->reg[sWtmu0].f; - sv->s0 = vd->reg[sS_W0].f; - sv->t0 = vd->reg[sT_W0].f; - sv->w1 = vd->reg[sWtmu1].f; - sv->s1 = vd->reg[sS_Wtmu1].f; - sv->t1 = vd->reg[sT_Wtmu1].f; - sv->a = vd->reg[sAlpha].f; - sv->r = vd->reg[sRed].f; - sv->g = vd->reg[sGreen].f; - sv->b = vd->reg[sBlue].f; - - /* spread it across all three verts and reset the count */ - vd->fbi.svert[0] = vd->fbi.svert[1] = vd->fbi.svert[2]; - vd->fbi.sverts = 1; - - return 0; -} - - -/*------------------------------------------------- - draw_triangle - execute the 'DrawTri' - command --------------------------------------------------*/ - -int32_t voodoo_device::draw_triangle(voodoo_device *vd) -{ - fbi_state::setup_vertex *sv = &vd->fbi.svert[2]; - int cycles = 0; - - /* for strip mode, shuffle vertex 1 down to 0 */ - if (!(vd->reg[sSetupMode].u & (1 << 16))) - vd->fbi.svert[0] = vd->fbi.svert[1]; - - /* copy 2 down to 1 regardless */ - vd->fbi.svert[1] = vd->fbi.svert[2]; - - /* extract all the data from registers */ - sv->x = vd->reg[sVx].f; - sv->y = vd->reg[sVy].f; - sv->wb = vd->reg[sWb].f; - sv->w0 = vd->reg[sWtmu0].f; - sv->s0 = vd->reg[sS_W0].f; - sv->t0 = vd->reg[sT_W0].f; - sv->w1 = vd->reg[sWtmu1].f; - sv->s1 = vd->reg[sS_Wtmu1].f; - sv->t1 = vd->reg[sT_Wtmu1].f; - sv->a = vd->reg[sAlpha].f; - sv->r = vd->reg[sRed].f; - sv->g = vd->reg[sGreen].f; - sv->b = vd->reg[sBlue].f; - - /* if we have enough verts, go ahead and draw */ - if (++vd->fbi.sverts >= 3) - cycles = setup_and_draw_triangle(vd); - - return cycles; -} - - - -/*************************************************************************** - TRIANGLE HELPERS -***************************************************************************/ - -/*------------------------------------------------- - setup_and_draw_triangle - process the setup - parameters and render the triangle --------------------------------------------------*/ - -int32_t voodoo_device::setup_and_draw_triangle(voodoo_device *vd) -{ - float dx1, dy1, dx2, dy2; - float divisor, tdiv; - - /* compute the divisor */ - // Just need sign for now - divisor = ((vd->fbi.svert[0].x - vd->fbi.svert[1].x) * (vd->fbi.svert[0].y - vd->fbi.svert[2].y) - - (vd->fbi.svert[0].x - vd->fbi.svert[2].x) * (vd->fbi.svert[0].y - vd->fbi.svert[1].y)); - - /* backface culling */ - if (vd->reg[sSetupMode].u & 0x20000) - { - int culling_sign = (vd->reg[sSetupMode].u >> 18) & 1; - int divisor_sign = (divisor < 0); - - /* if doing strips and ping pong is enabled, apply the ping pong */ - if ((vd->reg[sSetupMode].u & 0x90000) == 0x00000) - culling_sign ^= (vd->fbi.sverts - 3) & 1; - - /* if our sign matches the culling sign, we're done for */ - if (divisor_sign == culling_sign) - return TRIANGLE_SETUP_CLOCKS; - } - - // Finish the divisor - divisor = 1.0f / divisor; - - /* grab the X/Ys at least */ - vd->fbi.ax = (int16_t)(vd->fbi.svert[0].x * 16.0f); - vd->fbi.ay = (int16_t)(vd->fbi.svert[0].y * 16.0f); - vd->fbi.bx = (int16_t)(vd->fbi.svert[1].x * 16.0f); - vd->fbi.by = (int16_t)(vd->fbi.svert[1].y * 16.0f); - vd->fbi.cx = (int16_t)(vd->fbi.svert[2].x * 16.0f); - vd->fbi.cy = (int16_t)(vd->fbi.svert[2].y * 16.0f); - - /* compute the dx/dy values */ - dx1 = vd->fbi.svert[0].y - vd->fbi.svert[2].y; - dx2 = vd->fbi.svert[0].y - vd->fbi.svert[1].y; - dy1 = vd->fbi.svert[0].x - vd->fbi.svert[1].x; - dy2 = vd->fbi.svert[0].x - vd->fbi.svert[2].x; - - /* set up R,G,B */ - tdiv = divisor * 4096.0f; - if (vd->reg[sSetupMode].u & (1 << 0)) - { - vd->fbi.startr = (int32_t)(vd->fbi.svert[0].r * 4096.0f); - vd->fbi.drdx = (int32_t)(((vd->fbi.svert[0].r - vd->fbi.svert[1].r) * dx1 - (vd->fbi.svert[0].r - vd->fbi.svert[2].r) * dx2) * tdiv); - vd->fbi.drdy = (int32_t)(((vd->fbi.svert[0].r - vd->fbi.svert[2].r) * dy1 - (vd->fbi.svert[0].r - vd->fbi.svert[1].r) * dy2) * tdiv); - vd->fbi.startg = (int32_t)(vd->fbi.svert[0].g * 4096.0f); - vd->fbi.dgdx = (int32_t)(((vd->fbi.svert[0].g - vd->fbi.svert[1].g) * dx1 - (vd->fbi.svert[0].g - vd->fbi.svert[2].g) * dx2) * tdiv); - vd->fbi.dgdy = (int32_t)(((vd->fbi.svert[0].g - vd->fbi.svert[2].g) * dy1 - (vd->fbi.svert[0].g - vd->fbi.svert[1].g) * dy2) * tdiv); - vd->fbi.startb = (int32_t)(vd->fbi.svert[0].b * 4096.0f); - vd->fbi.dbdx = (int32_t)(((vd->fbi.svert[0].b - vd->fbi.svert[1].b) * dx1 - (vd->fbi.svert[0].b - vd->fbi.svert[2].b) * dx2) * tdiv); - vd->fbi.dbdy = (int32_t)(((vd->fbi.svert[0].b - vd->fbi.svert[2].b) * dy1 - (vd->fbi.svert[0].b - vd->fbi.svert[1].b) * dy2) * tdiv); - } - - /* set up alpha */ - if (vd->reg[sSetupMode].u & (1 << 1)) - { - vd->fbi.starta = (int32_t)(vd->fbi.svert[0].a * 4096.0f); - vd->fbi.dadx = (int32_t)(((vd->fbi.svert[0].a - vd->fbi.svert[1].a) * dx1 - (vd->fbi.svert[0].a - vd->fbi.svert[2].a) * dx2) * tdiv); - vd->fbi.dady = (int32_t)(((vd->fbi.svert[0].a - vd->fbi.svert[2].a) * dy1 - (vd->fbi.svert[0].a - vd->fbi.svert[1].a) * dy2) * tdiv); - } - - /* set up Z */ - if (vd->reg[sSetupMode].u & (1 << 2)) - { - vd->fbi.startz = (int32_t)(vd->fbi.svert[0].z * 4096.0f); - vd->fbi.dzdx = (int32_t)(((vd->fbi.svert[0].z - vd->fbi.svert[1].z) * dx1 - (vd->fbi.svert[0].z - vd->fbi.svert[2].z) * dx2) * tdiv); - vd->fbi.dzdy = (int32_t)(((vd->fbi.svert[0].z - vd->fbi.svert[2].z) * dy1 - (vd->fbi.svert[0].z - vd->fbi.svert[1].z) * dy2) * tdiv); - } - - /* set up Wb */ - tdiv = divisor * 65536.0f * 65536.0f; - if (vd->reg[sSetupMode].u & (1 << 3)) - { - vd->fbi.startw = vd->tmu[0].startw = vd->tmu[1].startw = (int64_t)(vd->fbi.svert[0].wb * 65536.0f * 65536.0f); - vd->fbi.dwdx = vd->tmu[0].dwdx = vd->tmu[1].dwdx = ((vd->fbi.svert[0].wb - vd->fbi.svert[1].wb) * dx1 - (vd->fbi.svert[0].wb - vd->fbi.svert[2].wb) * dx2) * tdiv; - vd->fbi.dwdy = vd->tmu[0].dwdy = vd->tmu[1].dwdy = ((vd->fbi.svert[0].wb - vd->fbi.svert[2].wb) * dy1 - (vd->fbi.svert[0].wb - vd->fbi.svert[1].wb) * dy2) * tdiv; - } - - /* set up W0 */ - if (vd->reg[sSetupMode].u & (1 << 4)) - { - vd->tmu[0].startw = vd->tmu[1].startw = (int64_t)(vd->fbi.svert[0].w0 * 65536.0f * 65536.0f); - vd->tmu[0].dwdx = vd->tmu[1].dwdx = ((vd->fbi.svert[0].w0 - vd->fbi.svert[1].w0) * dx1 - (vd->fbi.svert[0].w0 - vd->fbi.svert[2].w0) * dx2) * tdiv; - vd->tmu[0].dwdy = vd->tmu[1].dwdy = ((vd->fbi.svert[0].w0 - vd->fbi.svert[2].w0) * dy1 - (vd->fbi.svert[0].w0 - vd->fbi.svert[1].w0) * dy2) * tdiv; - } - - /* set up S0,T0 */ - if (vd->reg[sSetupMode].u & (1 << 5)) - { - vd->tmu[0].starts = vd->tmu[1].starts = (int64_t)(vd->fbi.svert[0].s0 * 65536.0f * 65536.0f); - vd->tmu[0].dsdx = vd->tmu[1].dsdx = ((vd->fbi.svert[0].s0 - vd->fbi.svert[1].s0) * dx1 - (vd->fbi.svert[0].s0 - vd->fbi.svert[2].s0) * dx2) * tdiv; - vd->tmu[0].dsdy = vd->tmu[1].dsdy = ((vd->fbi.svert[0].s0 - vd->fbi.svert[2].s0) * dy1 - (vd->fbi.svert[0].s0 - vd->fbi.svert[1].s0) * dy2) * tdiv; - vd->tmu[0].startt = vd->tmu[1].startt = (int64_t)(vd->fbi.svert[0].t0 * 65536.0f * 65536.0f); - vd->tmu[0].dtdx = vd->tmu[1].dtdx = ((vd->fbi.svert[0].t0 - vd->fbi.svert[1].t0) * dx1 - (vd->fbi.svert[0].t0 - vd->fbi.svert[2].t0) * dx2) * tdiv; - vd->tmu[0].dtdy = vd->tmu[1].dtdy = ((vd->fbi.svert[0].t0 - vd->fbi.svert[2].t0) * dy1 - (vd->fbi.svert[0].t0 - vd->fbi.svert[1].t0) * dy2) * tdiv; - } - - /* set up W1 */ - if (vd->reg[sSetupMode].u & (1 << 6)) - { - vd->tmu[1].startw = (int64_t)(vd->fbi.svert[0].w1 * 65536.0f * 65536.0f); - vd->tmu[1].dwdx = ((vd->fbi.svert[0].w1 - vd->fbi.svert[1].w1) * dx1 - (vd->fbi.svert[0].w1 - vd->fbi.svert[2].w1) * dx2) * tdiv; - vd->tmu[1].dwdy = ((vd->fbi.svert[0].w1 - vd->fbi.svert[2].w1) * dy1 - (vd->fbi.svert[0].w1 - vd->fbi.svert[1].w1) * dy2) * tdiv; - } - - /* set up S1,T1 */ - if (vd->reg[sSetupMode].u & (1 << 7)) - { - vd->tmu[1].starts = (int64_t)(vd->fbi.svert[0].s1 * 65536.0f * 65536.0f); - vd->tmu[1].dsdx = ((vd->fbi.svert[0].s1 - vd->fbi.svert[1].s1) * dx1 - (vd->fbi.svert[0].s1 - vd->fbi.svert[2].s1) * dx2) * tdiv; - vd->tmu[1].dsdy = ((vd->fbi.svert[0].s1 - vd->fbi.svert[2].s1) * dy1 - (vd->fbi.svert[0].s1 - vd->fbi.svert[1].s1) * dy2) * tdiv; - vd->tmu[1].startt = (int64_t)(vd->fbi.svert[0].t1 * 65536.0f * 65536.0f); - vd->tmu[1].dtdx = ((vd->fbi.svert[0].t1 - vd->fbi.svert[1].t1) * dx1 - (vd->fbi.svert[0].t1 - vd->fbi.svert[2].t1) * dx2) * tdiv; - vd->tmu[1].dtdy = ((vd->fbi.svert[0].t1 - vd->fbi.svert[2].t1) * dy1 - (vd->fbi.svert[0].t1 - vd->fbi.svert[1].t1) * dy2) * tdiv; - } - - /* draw the triangle */ - vd->fbi.cheating_allowed = 1; - return triangle(vd); -} - - -/*------------------------------------------------- - triangle_create_work_item - finish triangle - setup and create the work item --------------------------------------------------*/ - -int32_t voodoo_device::triangle_create_work_item(voodoo_device* vd, uint16_t *drawbuf, int texcount) -{ - poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(vd->poly); - - raster_info *info = find_rasterizer(vd, texcount); - poly_vertex vert[3]; - - /* fill in the vertex data */ - vert[0].x = (float)vd->fbi.ax * (1.0f / 16.0f); - vert[0].y = (float)vd->fbi.ay * (1.0f / 16.0f); - vert[1].x = (float)vd->fbi.bx * (1.0f / 16.0f); - vert[1].y = (float)vd->fbi.by * (1.0f / 16.0f); - vert[2].x = (float)vd->fbi.cx * (1.0f / 16.0f); - vert[2].y = (float)vd->fbi.cy * (1.0f / 16.0f); - - /* fill in the extra data */ - extra->device = vd; - extra->info = info; - - /* fill in triangle parameters */ - extra->ax = vd->fbi.ax; - extra->ay = vd->fbi.ay; - extra->startr = vd->fbi.startr; - extra->startg = vd->fbi.startg; - extra->startb = vd->fbi.startb; - extra->starta = vd->fbi.starta; - extra->startz = vd->fbi.startz; - extra->startw = vd->fbi.startw; - extra->drdx = vd->fbi.drdx; - extra->dgdx = vd->fbi.dgdx; - extra->dbdx = vd->fbi.dbdx; - extra->dadx = vd->fbi.dadx; - extra->dzdx = vd->fbi.dzdx; - extra->dwdx = vd->fbi.dwdx; - extra->drdy = vd->fbi.drdy; - extra->dgdy = vd->fbi.dgdy; - extra->dbdy = vd->fbi.dbdy; - extra->dady = vd->fbi.dady; - extra->dzdy = vd->fbi.dzdy; - extra->dwdy = vd->fbi.dwdy; - - /* fill in texture 0 parameters */ - if (texcount > 0) - { - extra->starts0 = vd->tmu[0].starts; - extra->startt0 = vd->tmu[0].startt; - extra->startw0 = vd->tmu[0].startw; - extra->ds0dx = vd->tmu[0].dsdx; - extra->dt0dx = vd->tmu[0].dtdx; - extra->dw0dx = vd->tmu[0].dwdx; - extra->ds0dy = vd->tmu[0].dsdy; - extra->dt0dy = vd->tmu[0].dtdy; - extra->dw0dy = vd->tmu[0].dwdy; - extra->lodbase0 = vd->tmu[0].prepare(); - vd->stats.texture_mode[TEXMODE_FORMAT(vd->tmu[0].reg[textureMode].u)]++; - - /* fill in texture 1 parameters */ - if (texcount > 1) - { - extra->starts1 = vd->tmu[1].starts; - extra->startt1 = vd->tmu[1].startt; - extra->startw1 = vd->tmu[1].startw; - extra->ds1dx = vd->tmu[1].dsdx; - extra->dt1dx = vd->tmu[1].dtdx; - extra->dw1dx = vd->tmu[1].dwdx; - extra->ds1dy = vd->tmu[1].dsdy; - extra->dt1dy = vd->tmu[1].dtdy; - extra->dw1dy = vd->tmu[1].dwdy; - extra->lodbase1 = vd->tmu[1].prepare(); - vd->stats.texture_mode[TEXMODE_FORMAT(vd->tmu[1].reg[textureMode].u)]++; - } - } - - /* farm the rasterization out to other threads */ - info->polys++; - return poly_render_triangle(vd->poly, drawbuf, global_cliprect, info->callback, 0, &vert[0], &vert[1], &vert[2]); -} - - - -/*************************************************************************** - RASTERIZER MANAGEMENT -***************************************************************************/ - -/*------------------------------------------------- - add_rasterizer - add a rasterizer to our - hash table --------------------------------------------------*/ - -voodoo_device::raster_info *voodoo_device::add_rasterizer(voodoo_device *vd, const raster_info *cinfo) -{ - raster_info *info = &vd->rasterizer[vd->next_rasterizer++]; - int hash = cinfo->compute_hash(); - - if (vd->next_rasterizer > MAX_RASTERIZERS) - throw emu_fatalerror("voodoo_device::add_rasterizer: Out of space for new rasterizers!"); - - /* make a copy of the info */ - *info = *cinfo; - - /* fill in the data */ - info->hits = 0; - info->polys = 0; - info->hash = hash; - - /* hook us into the hash table */ - info->next = vd->raster_hash[hash]; - vd->raster_hash[hash] = info; - - if (LOG_RASTERIZERS) - printf("Adding rasterizer @ %p : cp=%08X am=%08X %08X fbzM=%08X tm0=%08X tm1=%08X (hash=%d)\n", - (void *)info->callback, - info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode, - info->eff_tex_mode_0, info->eff_tex_mode_1, hash); - - return info; -} - - -/*------------------------------------------------- - find_rasterizer - find a rasterizer that - matches our current parameters and return - it, creating a new one if necessary --------------------------------------------------*/ - -voodoo_device::raster_info *voodoo_device::find_rasterizer(voodoo_device *vd, int texcount) -{ - raster_info *info, *prev = nullptr; - raster_info curinfo; - int hash; - - /* build an info struct with all the parameters */ - curinfo.eff_color_path = normalize_color_path(vd->reg[fbzColorPath].u); - curinfo.eff_alpha_mode = normalize_alpha_mode(vd->reg[alphaMode].u); - curinfo.eff_fog_mode = normalize_fog_mode(vd->reg[fogMode].u); - curinfo.eff_fbz_mode = normalize_fbz_mode(vd->reg[fbzMode].u); - curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(vd->tmu[0].reg[textureMode].u) : 0xffffffff; - curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(vd->tmu[1].reg[textureMode].u) : 0xffffffff; - - /* compute the hash */ - hash = curinfo.compute_hash(); - - /* find the appropriate hash entry */ - for (info = vd->raster_hash[hash]; info; prev = info, info = info->next) - if (info->eff_color_path == curinfo.eff_color_path && - info->eff_alpha_mode == curinfo.eff_alpha_mode && - info->eff_fog_mode == curinfo.eff_fog_mode && - info->eff_fbz_mode == curinfo.eff_fbz_mode && - info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 && - info->eff_tex_mode_1 == curinfo.eff_tex_mode_1) - { - /* got it, move us to the head of the list */ - if (prev) - { - prev->next = info->next; - info->next = vd->raster_hash[hash]; - vd->raster_hash[hash] = info; - } - - /* return the result */ - return info; - } - - /* generate a new one using the generic entry */ - curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu; - curinfo.is_generic = true; - curinfo.display = 0; - curinfo.polys = 0; - curinfo.hits = 0; - curinfo.next = nullptr; - curinfo.hash = hash; - - return add_rasterizer(vd, &curinfo); -} - - -/*------------------------------------------------- - dump_rasterizer_stats - dump statistics on - the current rasterizer usage patterns --------------------------------------------------*/ - -void voodoo_device::dump_rasterizer_stats(voodoo_device *vd) -{ - static uint8_t display_index; - raster_info *cur, *best; - int hash; - - printf("----\n"); - display_index++; - - /* loop until we've displayed everything */ - while (1) - { - best = nullptr; - - /* find the highest entry */ - for (hash = 0; hash < RASTER_HASH_SIZE; hash++) - for (cur = vd->raster_hash[hash]; cur; cur = cur->next) - if (cur->display != display_index && (best == nullptr || cur->hits > best->hits)) - best = cur; - - /* if we're done, we're done */ - if (best == nullptr || best->hits == 0) - break; - - /* print it */ - printf("RASTERIZER_ENTRY( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) /* %c %2d %8d %10d */\n", - best->eff_color_path, - best->eff_alpha_mode, - best->eff_fog_mode, - best->eff_fbz_mode, - best->eff_tex_mode_0, - best->eff_tex_mode_1, - best->is_generic ? '*' : ' ', - best->hash, - best->polys, - best->hits); - - /* reset */ - best->display = display_index; - } -} - -voodoo_device::voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt) - : device_t(mconfig, type, tag, owner, clock) - , m_fbmem(0) - , m_tmumem0(0) - , m_tmumem1(0) - , m_vblank(*this) - , m_stall(*this) - , m_pciint(*this) - , m_screen_finder(*this, finder_base::DUMMY_TAG) - , m_cpu_finder(*this, finder_base::DUMMY_TAG) - , index(0) - , m_screen(nullptr) - , m_cpu(nullptr) - , vd_type(vdt) - , chipmask(0) - , freq(0) - , attoseconds_per_cycle(0) - , extra_cycles(0) - , trigger(0) - , regaccess(nullptr) - , regnames(nullptr) - , alt_regmap(0) - , thread_stats(nullptr) - , last_status_pc(0) - , last_status_value(0) - , next_rasterizer(0) - , send_config(false) - , tmu_config(0) -{ -} - -voodoo_device::~voodoo_device() -{ -} - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void voodoo_device::device_reset() -{ - soft_reset(); -} - //------------------------------------------------- // device_stop - device-specific stop //------------------------------------------------- -void voodoo_device::device_stop() +void voodoo_1_device::device_stop() { - /* release the work queue, ensuring all work is finished */ - if (poly != nullptr) - poly_free(poly); + m_renderer->wait("Destruction"); } -DEFINE_DEVICE_TYPE(VOODOO_1, voodoo_1_device, "voodoo_1", "3dfx Voodoo Graphics") +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- -voodoo_1_device::voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_device(mconfig, VOODOO_1, tag, owner, clock, TYPE_VOODOO_1) +void voodoo_1_device::device_reset() { + soft_reset(); } -DEFINE_DEVICE_TYPE(VOODOO_2, voodoo_2_device, "voodoo_2", "3dfx Voodoo 2") +//------------------------------------------------- +// device_post_load - update after loading save +// state +//------------------------------------------------- -voodoo_2_device::voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_device(mconfig, VOODOO_2, tag, owner, clock, TYPE_VOODOO_2) +void voodoo_1_device::device_post_load() { + // dirty everything so it gets recomputed + m_clut_dirty = true; + for (tmu_state &tm : m_tmu) + tm.post_load(); + + // recompute FBI memory FIFO to get the base pointer set + if (m_fbmem_fifo.configured()) + recompute_fbmem_fifo(); } -DEFINE_DEVICE_TYPE(VOODOO_BANSHEE, voodoo_banshee_device, "voodoo_banshee", "3dfx Voodoo Banshee") +//------------------------------------------------- +// soft_reset - handle reset when initiated by +// a register write +//------------------------------------------------- -voodoo_banshee_device::voodoo_banshee_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_banshee_device(mconfig, VOODOO_BANSHEE, tag, owner, clock, TYPE_VOODOO_BANSHEE) -{ -} - -voodoo_banshee_device::voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt) - : voodoo_device(mconfig, type, tag, owner, clock, vdt) +void voodoo_1_device::soft_reset() { + reset_counters(); + m_reg.write(voodoo_regs::reg_fbiTrianglesOut, 0); + m_pci_fifo.reset(); + m_fbmem_fifo.reset(); } -DEFINE_DEVICE_TYPE(VOODOO_3, voodoo_3_device, "voodoo_3", "3dfx Voodoo 3") +//------------------------------------------------- +// register_save - register items for save states +//------------------------------------------------- -voodoo_3_device::voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_banshee_device(mconfig, VOODOO_3, tag, owner, clock, TYPE_VOODOO_3) +ALLOW_SAVE_TYPE(reg_init_en); +ALLOW_SAVE_TYPE(voodoo_regs::register_data); +ALLOW_SAVE_TYPE(voodoo_1_device::stall_state); + +void voodoo_1_device::register_save(save_proxy &save, u32 total_allocation) { + // PCI state/FIFOs + save.save_item(NAME(m_init_enable)); + save.save_item(NAME(m_stall_state)); + save.save_item(NAME(m_operation_end)); + save.save_class(NAME(m_pci_fifo)); + save.save_class(NAME(m_fbmem_fifo)); + + // allocated memory + save.save_pointer(NAME(m_fbram), 1024 * 1024 * total_allocation); + save.save_class(NAME(*m_renderer.get())); + + // video buffer configuration + save.save_item(NAME(m_rgboffs)); + save.save_item(NAME(m_auxoffs)); + save.save_item(NAME(m_frontbuf)); + save.save_item(NAME(m_backbuf)); + + // linear frame buffer access configuration + save.save_item(NAME(m_lfb_stride)); + + // video configuration + save.save_item(NAME(m_width)); + save.save_item(NAME(m_height)); + save.save_item(NAME(m_xoffs)); + save.save_item(NAME(m_yoffs)); + save.save_item(NAME(m_vsyncstart)); + save.save_item(NAME(m_vsyncstop)); + + // VBLANK/swapping state + save.save_item(NAME(m_swaps_pending)); + save.save_item(NAME(m_vblank)); + save.save_item(NAME(m_vblank_count)); + save.save_item(NAME(m_vblank_swap_pending)); + save.save_item(NAME(m_vblank_swap)); + save.save_item(NAME(m_vblank_dont_swap)); + + // register state + save.save_class(NAME(m_reg)); + save.save_class(NAME(m_tmu[0])); + save.save_class(NAME(m_tmu[1])); + save.save_item(NAME(m_dac_reg)); + save.save_item(NAME(m_dac_read_result)); + + // memory for PCI FIFO + save.save_item(NAME(m_pci_fifo_mem)); + + // pens and CLUT + save.save_item(NAME(m_clut)); } +//------------------------------------------------- +// draw_buffer_indirect - given a 2-bit index, +// return the front/back buffer for drawing +//------------------------------------------------- -/*************************************************************************** - GENERIC RASTERIZERS -***************************************************************************/ - -/*------------------------------------------------- - raster_fastfill - per-scanline - implementation of the 'fastfill' command --------------------------------------------------*/ - -void voodoo_device::raster_fastfill(void *destbase, int32_t y, const poly_extent *extent, const void *extradata, int threadid) +u16 *voodoo_1_device::draw_buffer_indirect(int index) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - voodoo_device* vd = extra->device; - stats_block *stats = &vd->thread_stats[threadid]; - int32_t startx = extent->startx; - int32_t stopx = extent->stopx; - int scry, x; - - /* determine the screen Y */ - scry = y; - if (FBZMODE_Y_ORIGIN(vd->reg[fbzMode].u)) - scry = (vd->fbi.yorigin - y); - - /* fill this RGB row */ - if (FBZMODE_RGB_BUFFER_MASK(vd->reg[fbzMode].u)) + switch (index) { - const uint16_t *ditherow = &extra->dither[(y & 3) * 4]; - uint64_t expanded = *(uint64_t *)ditherow; - uint16_t *dest = (uint16_t *)destbase + scry * vd->fbi.rowpixels; - - for (x = startx; x < stopx && (x & 3) != 0; x++) - dest[x] = ditherow[x & 3]; - for ( ; x < (stopx & ~3); x += 4) - *(uint64_t *)&dest[x] = expanded; - for ( ; x < stopx; x++) - dest[x] = ditherow[x & 3]; - stats->pixels_out += stopx - startx; - } - - /* fill this dest buffer row */ - if (FBZMODE_AUX_BUFFER_MASK(vd->reg[fbzMode].u) && vd->fbi.auxoffs != ~0) - { - uint16_t depth = vd->reg[zaColor].u; - uint64_t expanded = ((uint64_t)depth << 48) | ((uint64_t)depth << 32) | ((uint64_t)depth << 16) | (uint64_t)depth; - uint16_t *dest = (uint16_t *)(vd->fbi.ram + vd->fbi.auxoffs) + scry * vd->fbi.rowpixels; - - for (x = startx; x < stopx && (x & 3) != 0; x++) - dest[x] = depth; - for ( ; x < (stopx & ~3); x += 4) - *(uint64_t *)&dest[x] = expanded; - for ( ; x < stopx; x++) - dest[x] = depth; + case 0: m_video_changed = true; return front_buffer(); + case 1: return back_buffer(); + default: return nullptr; } } -/*------------------------------------------------- - generic_0tmu - generic rasterizer for 0 TMUs --------------------------------------------------*/ +//------------------------------------------------- +// lfb_buffer_indirect - given a 2-bit index, +// return the front/back/depth buffer for LFB +// access +//------------------------------------------------- -RASTERIZER(generic_0tmu, 0, vd->reg[fbzColorPath].u, vd->reg[fbzMode].u, vd->reg[alphaMode].u, - vd->reg[fogMode].u, 0, 0) +u16 *voodoo_1_device::lfb_buffer_indirect(int index) +{ + switch (index) + { + case 0: m_video_changed = true; return front_buffer(); + case 1: return back_buffer(); + case 2: return aux_buffer(); + default: return nullptr; + } +} -/*------------------------------------------------- - generic_1tmu - generic rasterizer for 1 TMU --------------------------------------------------*/ +//------------------------------------------------- +// prepare_for_read - handle housekeeping before +// processing a direct PCI read +//------------------------------------------------- -RASTERIZER(generic_1tmu, 1, vd->reg[fbzColorPath].u, vd->reg[fbzMode].u, vd->reg[alphaMode].u, - vd->reg[fogMode].u, vd->tmu[0].reg[textureMode].u, 0) +void voodoo_1_device::prepare_for_read() +{ + // if we have something pending, flush the FIFOs up to the current time + if (operation_pending()) + flush_fifos(machine().time()); +} -/*------------------------------------------------- - generic_2tmu - generic rasterizer for 2 TMUs --------------------------------------------------*/ +//------------------------------------------------- +// prepare_for_write - handle housekeeping before +// processing a direct PCI write +//------------------------------------------------- -RASTERIZER(generic_2tmu, 2, vd->reg[fbzColorPath].u, vd->reg[fbzMode].u, vd->reg[alphaMode].u, - vd->reg[fogMode].u, vd->tmu[0].reg[textureMode].u, vd->tmu[1].reg[textureMode].u) +bool voodoo_1_device::prepare_for_write() +{ + // should not be getting accesses while stalled (but we do) + if (m_stall_state != NOT_STALLED) + logerror("voodoo_1_device::write while stalled!\n"); + + // if we have something pending, flush the FIFOs up to the current time + bool pending = operation_pending(); + if (pending) + { + flush_fifos(machine().time()); + pending = operation_pending(); + } + return pending; +} + + +//------------------------------------------------- +// recompute_fbmem_fifo - recompute and configure +// the framebuffer RAM-based FIFO based on the +// fbiInit registers +//------------------------------------------------- + +void voodoo_1_device::recompute_fbmem_fifo() +{ + // compute the memory FIFO location and size + u32 fifo_last_page = m_reg.fbi_init4().memory_fifo_stop_row(); + if (fifo_last_page > m_fbmask / 0x1000) + fifo_last_page = m_fbmask / 0x1000; + + // is it valid and enabled? + u32 const fifo_start_page = m_reg.fbi_init4().memory_fifo_start_row(); + if (fifo_start_page <= fifo_last_page && m_reg.fbi_init0().enable_memory_fifo()) + { + u32 size = std::min((fifo_last_page + 1 - fifo_start_page) * 0x1000 / 4, 65536*2); + m_fbmem_fifo.configure((u32 *)(m_fbram + fifo_start_page * 0x1000), size); + } + + // if not, disable the FIFO + else + m_fbmem_fifo.configure(nullptr, 0); +} + + +//------------------------------------------------- +// add_to_fifo - add a write to the PCI FIFO, +// spilling to the memory FIFO as configured +//------------------------------------------------- + +void voodoo_1_device::add_to_fifo(u32 offset, u32 data, u32 mem_mask) +{ + // add flags to the offset based on the mem_mask + if (!ACCESSING_BITS_16_31) + offset |= memory_fifo::NO_16_31; + if (!ACCESSING_BITS_0_15) + offset |= memory_fifo::NO_0_15; + + // if there's room in the PCI FIFO, add there + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.%d.FIFO:adding to PCI FIFO @ %08X=%08X\n", this, offset, data); + assert(!m_pci_fifo.full()); + + // add as offset/data pair + m_pci_fifo.add(offset); + m_pci_fifo.add(data); + + // handle flushing to the memory FIFO + if (m_reg.fbi_init0().enable_memory_fifo() && m_pci_fifo.space() <= 2 * m_reg.fbi_init4().memory_fifo_lwm()) + { + u8 valid[4]; + + // determine which types of data can go to the memory FIFO + valid[0] = true; + valid[1] = m_reg.fbi_init0().lfb_to_memory_fifo(); + valid[2] = valid[3] = m_reg.fbi_init0().texmem_to_memory_fifo(); + + // flush everything we can + if (LOG_FIFO_VERBOSE) logerror("VOODOO.FIFO:moving PCI FIFO to memory FIFO\n"); + while (!m_pci_fifo.empty() && valid[(m_pci_fifo.peek() >> 22) & 3]) + { + m_fbmem_fifo.add(m_pci_fifo.remove()); + m_fbmem_fifo.add(m_pci_fifo.remove()); + } + + // if we're above the HWM as a result, stall + if (m_reg.fbi_init0().stall_pcie_for_hwm() && m_fbmem_fifo.items() >= 2 * 32 * m_reg.fbi_init0().memory_fifo_hwm()) + { + if (LOG_FIFO) logerror("VOODOO.FIFO:hit memory FIFO HWM -- stalling\n"); + stall_cpu(STALLED_UNTIL_FIFO_LWM); + } + } + + // if we're at the LWM for the PCI FIFO, stall + if (m_reg.fbi_init0().stall_pcie_for_hwm() && m_pci_fifo.space() <= 2 * m_reg.fbi_init0().pci_fifo_lwm()) + { + if (LOG_FIFO) logerror("VOODOO.FIFO:hit PCI FIFO free LWM -- stalling\n"); + stall_cpu(STALLED_UNTIL_FIFO_LWM); + } +} + + +//------------------------------------------------- +// flush_fifos - flush data out of FIFOs up to +// the current time +//------------------------------------------------- + +void voodoo_1_device::flush_fifos(attotime current_time) +{ + // check for recursive calls + if (m_flush_flag) + return; + m_flush_flag = true; + + // should only be called if something is pending + assert(operation_pending()); + + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:flush_fifos start -- pending=%s cur=%s\n", m_operation_end.as_string(18), current_time.as_string(18)); + + // loop while we still have cycles to burn + while (m_operation_end <= current_time) + { + // execute from the FIFOs until we get something that's non-zero + u32 cycles = execute_fifos(); + + // if nothing remains, we're done; clear the flags + if (cycles == 0) + { + clear_pending_operation(); + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:flush_fifos end -- FIFOs empty\n"); + m_flush_flag = false; + return; + } + + // account for those cycles + m_operation_end += clocks_to_attotime(cycles); + + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:update -- pending=%s cur=%s\n", m_operation_end.as_string(18), current_time.as_string(18)); + } + + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:flush_fifos end -- pending command complete at %s\n", m_operation_end.as_string(18)); + + m_flush_flag = false; +} + + +//------------------------------------------------- +// execute_fifos - execute commands from the FIFOs +// until a non-zero cycle count operation is run +//------------------------------------------------- + +u32 voodoo_1_device::execute_fifos() +{ + // loop until FIFOs are empty or until we get a non-zero cycle count + while (1) + { + // prioritize framebuffer FIFO over PCI FIFO + voodoo::memory_fifo &memfifo = !m_fbmem_fifo.empty() ? m_fbmem_fifo : m_pci_fifo; + + // if empty, return 0 + if (memfifo.empty()) + return 0; + + // extract address and data + u32 offset = memfifo.remove(); + u32 data = memfifo.remove(); + + // target the appropriate location + switch (offset & memory_fifo::TYPE_MASK) + { + case memory_fifo::TYPE_REGISTER: + { + // just use the chipmask raw since it was adjusted prior to being added to the FIFO + u32 regnum = BIT(offset, 0, 8); + u32 chipmask = BIT(offset, 8, 4); + + // if we got a non-zero number of cycles back, return + u32 cycles = m_regtable[regnum].write(*this, chipmask, regnum, data); + if (cycles > 0) + return cycles; + break; + } + + case memory_fifo::TYPE_TEXTURE: + internal_texture_w(offset & ~memory_fifo::FLAGS_MASK, data); + break; + + case memory_fifo::TYPE_LFB: + { + u32 mem_mask = 0xffffffff; + if (offset & memory_fifo::NO_16_31) + mem_mask &= 0x0000ffff; + if (offset & memory_fifo::NO_0_15) + mem_mask &= 0xffff0000; + internal_lfb_w(offset & ~memory_fifo::FLAGS_MASK, data, mem_mask); + break; + } + } + } +} + + +//------------------------------------------------- +// map_register_r - handle a mapped read from +// regular register space +//------------------------------------------------- + +u32 voodoo_1_device::map_register_r(offs_t offset) +{ + prepare_for_read(); + + // extract chipmask and register + u32 chipmask = chipmask_from_offset(offset); + u32 regnum = BIT(offset, 0, 8); + return m_regtable[regnum].read(*this, chipmask, regnum); +} + + +//------------------------------------------------- +// map_lfb_r - handle a mapped read from LFB space +//------------------------------------------------- + +u32 voodoo_1_device::map_lfb_r(offs_t offset) +{ + prepare_for_read(); + return internal_lfb_r(offset); +} + + +//------------------------------------------------- +// map_register_w - handle a mapped write to +// regular register space +//------------------------------------------------- + +void voodoo_1_device::map_register_w(offs_t offset, u32 data, u32 mem_mask) +{ + bool pending = prepare_for_write(); + + // extract chipmask and register + u32 chipmask = chipmask_from_offset(offset); + u32 regnum = BIT(offset, 0, 8); + + // handle register swizzling -- manual says bit 21; voodoo2 manual says bit 20 + // guessing it does not overlap with the alternate register mapping bit + if (BIT(offset, 20-2) && m_reg.fbi_init0().swizzle_reg_writes()) + data = swapendian_int32(data); + + // handle aliasing + if (BIT(offset, 21-2) && m_reg.fbi_init3().tri_register_remap()) + regnum = voodoo_regs::alias(regnum); + + // look up the register + auto const ®entry = m_regtable[regnum]; + + // if this is non-FIFO command, execute immediately + if (!regentry.is_fifo()) + return void(regentry.write(*this, chipmask, regnum, data)); + + // track swap buffer commands seen + if (regnum == voodoo_regs::reg_swapbufferCMD) + m_swaps_pending++; + + // if we're busy add to the FIFO + if (pending && m_init_enable.enable_pci_fifo()) + return add_to_fifo(memory_fifo::TYPE_REGISTER | (chipmask << 8) | regnum, data, mem_mask); + + // if we get a non-zero number of cycles back, mark things pending + u32 cycles = regentry.write(*this, chipmask, regnum, data); + if (cycles > 0) + { + m_operation_end = machine().time() + clocks_to_attotime(cycles); + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:direct write start at %s end at %s\n", machine().time().as_string(18), m_operation_end.as_string(18)); + } +} + + +//------------------------------------------------- +// map_lfb_w - handle a mapped write to LFB space +//------------------------------------------------- + +void voodoo_1_device::map_lfb_w(offs_t offset, u32 data, u32 mem_mask) +{ + // if we're busy add to the FIFO, else just execute immediately + if (prepare_for_write() && m_init_enable.enable_pci_fifo()) + add_to_fifo(memory_fifo::TYPE_LFB | offset, data, mem_mask); + else + internal_lfb_w(offset, data, mem_mask); +} + + +//------------------------------------------------- +// map_texture_w - handle a mapped write to +// texture space +//------------------------------------------------- + +void voodoo_1_device::map_texture_w(offs_t offset, u32 data, u32 mem_mask) +{ + // if we're busy add to the FIFO, else just execute immediately + if (prepare_for_write() && m_init_enable.enable_pci_fifo()) + add_to_fifo(memory_fifo::TYPE_TEXTURE | offset, data, mem_mask); + else + internal_texture_w(offset, data); +} + + +//------------------------------------------------- +// internal_lfb_r - handle a read from the linear +// frame buffer +//------------------------------------------------- + +u32 voodoo_1_device::internal_lfb_r(offs_t offset) +{ + // statistics + if (DEBUG_STATS) + m_stats.m_lfb_reads++; + + // linear frame buffer reads are inherently 16-bit; convert offset to an pixel index + offset <<= 1; + + // convert offset into X/Y coordinates + s32 x = offset & ((1 << m_lfb_stride) - 1); + s32 y = offset >> m_lfb_stride; + s32 scry = y; + + // effective Y is determined by the Y origin bit + scry &= 0x3ff; + auto const lfbmode = m_reg.lfb_mode(); + if (lfbmode.y_origin()) + scry = m_renderer->yorigin() - scry; + + // select the target buffer + u16 *buffer = lfb_buffer_indirect(lfbmode.read_buffer_select()); + if (buffer == nullptr) + return 0xffffffff; + + // advance pointers to the proper row + buffer += scry * m_renderer->rowpixels() + x; + if (buffer + 1 >= ram_end()) + { + logerror("internal_lfb_r: Buffer offset out of bounds x=%i y=%i offset=%08X bufoffs=%08X\n", x, y, offset, u32(buffer - lfb_buffer_indirect(lfbmode.read_buffer_select()))); + return 0xffffffff; + } + + // wait for any outstanding work to finish before reading + m_renderer->wait("LFB read"); + + // read and assemble two pixels + u32 data = buffer[0] | (buffer[1] << 16); + + // word swapping + if (lfbmode.word_swap_reads()) + data = (data << 16) | (data >> 16); + + // byte swizzling + if (lfbmode.byte_swizzle_reads()) + data = swapendian_int32(data); + + if (LOG_LFB) + logerror("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data); + return data; +} + + +//------------------------------------------------- +// internal_lfb_w - handle a write to the linear +// frame buffer +//------------------------------------------------- + +void voodoo_1_device::internal_lfb_w(offs_t offset, u32 data, u32 mem_mask) +{ + // statistics + if (DEBUG_STATS) + m_stats.m_lfb_writes++; + + // byte swizzling + auto const lfbmode = m_reg.lfb_mode(); + if (lfbmode.byte_swizzle_writes()) + { + data = swapendian_int32(data); + mem_mask = swapendian_int32(mem_mask); + } + + // word swapping + if (lfbmode.word_swap_writes()) + { + data = (data << 16) | (data >> 16); + mem_mask = (mem_mask << 16) | (mem_mask >> 16); + } + + // convert the incoming data + rgb_t src_color[2]; + u16 src_depth[2]; + u32 mask = expand_lfb_data(lfbmode, data, src_color, src_depth); + + // if there are two pixels, then the offset is *2 + if ((mask & LFB_PIXEL1_MASK) != 0) + offset <<= 1; + + // compute X,Y + s32 x = offset & ((1 << m_lfb_stride) - 1); + s32 y = (offset >> m_lfb_stride) & 0x3ff; + + // adjust the mask based on which half of the data is written + if (!ACCESSING_BITS_0_15) + mask &= ~(LFB_PIXEL0_MASK - LFB_DEPTH_PRESENT_MSW_0); + if (!ACCESSING_BITS_16_31) + mask &= ~(LFB_PIXEL1_MASK + LFB_DEPTH_PRESENT_MSW_0); + + // select the target buffers + u16 *dest = draw_buffer_indirect(lfbmode.write_buffer_select()); + if (dest == nullptr) + return; + u16 *depth = aux_buffer(); + u16 *end = ram_end(); + + // simple case: no pipeline + auto const fbzmode = m_reg.fbz_mode(); + if (!lfbmode.enable_pixel_pipeline()) + { + if (LOG_LFB) + logerror("VOODOO.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", lfbmode.write_format(), x, y, data, mem_mask); + + // determine the screen Y + s32 scry = y; + if (lfbmode.y_origin()) + scry = m_renderer->yorigin() - y; + + // advance pointers to the proper row + dest += scry * m_renderer->rowpixels() + x; + if (depth != nullptr) + depth += scry * m_renderer->rowpixels() + x; + + // wait for any outstanding work to finish + m_renderer->wait("LFB Write"); + + // loop over up to two pixels + voodoo::dither_helper dither(scry, fbzmode); + for (int pix = 0; mask != 0; pix++) + { + // make sure we care about this pixel + if ((mask & LFB_PIXEL0_MASK) != 0) + { + // write to the RGB buffer + rgb_t pixel = src_color[pix]; + if ((mask & LFB_RGB_PRESENT_0) != 0 && dest + pix < end) + dest[pix] = dither.pixel(x, pixel.r(), pixel.g(), pixel.b()); + + // make sure we have an aux buffer to write to + if (depth != nullptr && depth + pix < end) + { + if (fbzmode.enable_alpha_planes()) + { + // write to the alpha buffer + if ((mask & LFB_ALPHA_PRESENT_0) != 0) + depth[pix] = pixel.a(); + } + else + { + // write to the depth buffer + if ((mask & (LFB_DEPTH_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0)) != 0) + depth[pix] = src_depth[pix]; + } + } + + // track pixel writes to the frame buffer regardless of mask + m_reg.add(voodoo_regs::reg_fbiPixelsOut, 1); + } + + // advance our pointers + x++; + mask >>= 4; + } + } + + // tricky case: run the full pixel pipeline on the pixel + else + { + if (LOG_LFB) + logerror("VOODOO.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", lfbmode.write_format(), x, y, data, mem_mask); + + // determine the screen Y + s32 scry = y; + if (fbzmode.y_origin()) + scry = m_renderer->yorigin() - y; + + // advance pointers to the proper row + dest += scry * m_renderer->rowpixels(); + if (depth != nullptr) + depth += scry * m_renderer->rowpixels(); + + // make a dummy poly_extra_data structure with some cached values + poly_data poly; + poly.raster.compute(m_reg, nullptr, nullptr); + poly.destbase = dest; + poly.depthbase = depth; + poly.clipleft = m_reg.clip_left(); + poly.clipright = m_reg.clip_right(); + poly.cliptop = m_reg.clip_top(); + poly.clipbottom = m_reg.clip_bottom(); + poly.color0 = m_reg.color0().argb(); + poly.color1 = m_reg.color1().argb(); + poly.chromakey = m_reg.chroma_key().argb(); + poly.fogcolor = m_reg.fog_color().argb(); + poly.zacolor = m_reg.za_color(); + poly.stipple = m_reg.stipple(); + poly.alpharef = m_reg.alpha_mode().alpharef(); + if (poly.raster.fbzmode().enable_stipple() && !poly.raster.fbzmode().stipple_pattern()) + logerror("Warning: rotated stipple pattern used in LFB write\n"); + + // loop over up to two pixels + thread_stats_block &threadstats = m_lfb_stats; + rgbaint_t iterargb(0); + for (int pix = 0; mask != 0; pix++) + { + // make sure we care about this pixel + if ((mask & LFB_PIXEL0_MASK) != 0) + m_renderer->pixel_pipeline(threadstats, poly, lfbmode, x, y, src_color[pix], src_depth[pix]); + + // advance our pointers + x++; + mask >>= 4; + } + } +} + + +//------------------------------------------------- +// expand_lfb_data - expand a 32-bit raw data +// value into 1 or 2 expanded RGBA and depth +// values +//------------------------------------------------- + +u32 voodoo_1_device::expand_lfb_data(reg_lfb_mode const lfbmode, u32 data, rgb_t src_color[2], u16 src_depth[2]) +{ + // extract default depth value from low bits of zaColor + src_depth[0] = src_depth[1] = m_reg.za_color() & 0xffff; + + // if not otherwise specified, alpha defaults to the upper bits of zaColor + u32 src_alpha = m_reg.za_color() >> 24; + + // extract color information from the data + switch (16 * lfbmode.rgba_lanes() + lfbmode.write_format()) + { + case 16*0 + 0: // ARGB, format 0: 16-bit RGB 5-6-5 + case 16*2 + 0: // RGBA, format 0: 16-bit RGB 5-6-5 + src_color[0] = rgbexpand<5,6,5>(data, 11, 5, 0).set_a(src_alpha); + src_color[1] = rgbexpand<5,6,5>(data, 27, 21, 16).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*1 + 0: // ABGR, format 0: 16-bit RGB 5-6-5 + case 16*3 + 0: // BGRA, format 0: 16-bit RGB 5-6-5 + src_color[0] = rgbexpand<5,6,5>(data, 0, 5, 11).set_a(src_alpha); + src_color[1] = rgbexpand<5,6,5>(data, 16, 21, 27).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*0 + 1: // ARGB, format 1: 16-bit RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 10, 5, 0).set_a(src_alpha); + src_color[1] = rgbexpand<5,5,5>(data, 26, 21, 16).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*1 + 1: // ABGR, format 1: 16-bit RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 0, 5, 10).set_a(src_alpha); + src_color[1] = rgbexpand<5,5,5>(data, 16, 21, 26).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*2 + 1: // RGBA, format 1: 16-bit RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 11, 6, 1).set_a(src_alpha); + src_color[1] = rgbexpand<5,5,5>(data, 27, 22, 17).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*3 + 1: // BGRA, format 1: 16-bit RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 1, 6, 11).set_a(src_alpha); + src_color[1] = rgbexpand<5,5,5>(data, 17, 22, 27).set_a(src_alpha); + return LFB_RGB_PRESENT_0 | LFB_RGB_PRESENT_1; + + case 16*0 + 2: // ARGB, format 2: 16-bit ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 15, 10, 5, 0); + src_color[1] = argbexpand<1,5,5,5>(data, 31, 26, 21, 16); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_RGB_PRESENT_1 | LFB_ALPHA_PRESENT_1; + + case 16*1 + 2: // ABGR, format 2: 16-bit ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 15, 0, 5, 10); + src_color[1] = argbexpand<1,5,5,5>(data, 31, 16, 21, 26); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_RGB_PRESENT_1 | LFB_ALPHA_PRESENT_1; + + case 16*2 + 2: // RGBA, format 2: 16-bit ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 0, 11, 6, 1); + src_color[1] = argbexpand<1,5,5,5>(data, 16, 27, 22, 17); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_RGB_PRESENT_1 | LFB_ALPHA_PRESENT_1; + + case 16*3 + 2: // BGRA, format 2: 16-bit ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 0, 1, 6, 11); + src_color[1] = argbexpand<1,5,5,5>(data, 16, 17, 22, 27); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_RGB_PRESENT_1 | LFB_ALPHA_PRESENT_1; + + case 16*0 + 4: // ARGB, format 4: 32-bit RGB x-8-8-8 + src_color[0] = rgbexpand<8,8,8>(data, 16, 8, 0).set_a(src_alpha); + return LFB_RGB_PRESENT_0; + + case 16*1 + 4: // ABGR, format 4: 32-bit RGB x-8-8-8 + src_color[0] = rgbexpand<8,8,8>(data, 0, 8, 16).set_a(src_alpha); + return LFB_RGB_PRESENT_0; + + case 16*2 + 4: // RGBA, format 4: 32-bit RGB x-8-8-8 + src_color[0] = rgbexpand<8,8,8>(data, 24, 16, 8).set_a(src_alpha); + return LFB_RGB_PRESENT_0; + + case 16*3 + 4: // BGRA, format 4: 32-bit RGB x-8-8-8 + src_color[0] = rgbexpand<8,8,8>(data, 8, 16, 24).set_a(src_alpha); + return LFB_RGB_PRESENT_0; + + case 16*0 + 5: // ARGB, format 5: 32-bit ARGB 8-8-8-8 + src_color[0] = argbexpand<8,8,8,8>(data, 24, 16, 8, 0); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0; + + case 16*1 + 5: // ABGR, format 5: 32-bit ARGB 8-8-8-8 + src_color[0] = argbexpand<8,8,8,8>(data, 24, 0, 8, 16); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0; + + case 16*2 + 5: // RGBA, format 5: 32-bit ARGB 8-8-8-8 + src_color[0] = argbexpand<8,8,8,8>(data, 0, 24, 16, 8); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0; + + case 16*3 + 5: // BGRA, format 5: 32-bit ARGB 8-8-8-8 + src_color[0] = argbexpand<8,8,8,8>(data, 0, 8, 16, 24); + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0; + + case 16*0 + 12: // ARGB, format 12: 32-bit depth+RGB 5-6-5 + case 16*2 + 12: // RGBA, format 12: 32-bit depth+RGB 5-6-5 + src_color[0] = rgbexpand<5,6,5>(data, 11, 5, 0).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*1 + 12: // ABGR, format 12: 32-bit depth+RGB 5-6-5 + case 16*3 + 12: // BGRA, format 12: 32-bit depth+RGB 5-6-5 + src_color[0] = rgbexpand<5,6,5>(data, 0, 5, 11).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*0 + 13: // ARGB, format 13: 32-bit depth+RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 10, 5, 0).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*1 + 13: // ABGR, format 13: 32-bit depth+RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 0, 5, 10).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*2 + 13: // RGBA, format 13: 32-bit depth+RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 11, 6, 1).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*3 + 13: // BGRA, format 13: 32-bit depth+RGB x-5-5-5 + src_color[0] = rgbexpand<5,5,5>(data, 1, 6, 11).set_a(src_alpha); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*0 + 14: // ARGB, format 14: 32-bit depth+ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 15, 10, 5, 0); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*1 + 14: // ABGR, format 14: 32-bit depth+ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 15, 0, 5, 10); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*2 + 14: // RGBA, format 14: 32-bit depth+ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 0, 11, 6, 1); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*3 + 14: // BGRA, format 14: 32-bit depth+ARGB 1-5-5-5 + src_color[0] = argbexpand<1,5,5,5>(data, 0, 1, 6, 11); + src_depth[0] = data >> 16; + return LFB_RGB_PRESENT_0 | LFB_ALPHA_PRESENT_0 | LFB_DEPTH_PRESENT_MSW_0; + + case 16*0 + 15: // ARGB, format 15: 16-bit depth + case 16*1 + 15: // ARGB, format 15: 16-bit depth + case 16*2 + 15: // ARGB, format 15: 16-bit depth + case 16*3 + 15: // ARGB, format 15: 16-bit depth + src_depth[0] = data & 0xffff; + src_depth[1] = data >> 16; + return LFB_DEPTH_PRESENT_0 | LFB_DEPTH_PRESENT_1; + + default: // reserved + logerror("internal_lfb_w: Unknown format\n"); + return 0; + } +} + + +//------------------------------------------------- +// internal_texture_w - handle writes to texture +// RAM +//------------------------------------------------- + +void voodoo_1_device::internal_texture_w(offs_t offset, u32 data) +{ + // statistics + if (DEBUG_STATS) + m_stats.m_tex_writes++; + + // point to the right TMU + int tmunum = BIT(offset, 19, 2); + if (!BIT(m_chipmask, 1 + tmunum)) + return; + + // wait for any outstanding work to finish + m_renderer->wait("Texture write"); + + // the seq_8_downld flag seems to always come from TMU #0 + bool seq_8_downld = m_tmu[0].regs().texture_mode().seq_8_downld(); + + // pull out modes from the TMU and update state + auto ®s = m_tmu[tmunum].regs(); + auto const texlod = regs.texture_lod(); + auto const texmode = regs.texture_mode(); + auto &texture = m_tmu[tmunum].prepare_texture(*m_renderer.get()); + + // texture direct not handled (but never seen so far) + if (texlod.tdirect_write()) + fatalerror("%s: Unsupported texture direct write", tag()); + + // swizzle the data + if (texlod.tdata_swizzle()) + data = swapendian_int32(data); + if (texlod.tdata_swap()) + data = (data >> 16) | (data << 16); + + // determine destination pointer + u32 bytes_per_texel = (texmode.format() < 8) ? 1 : 2; + u32 lod = BIT(offset, 15, 4); + u32 tt = BIT(offset, 7, 8); + u32 ts = (offset << ((seq_8_downld && bytes_per_texel == 1) ? 2 : 1)) & 0xff; + + // validate parameters + if (lod > 8) + return; + u8 *dest = texture.write_ptr(lod, ts, tt, bytes_per_texel); + + // write the four bytes in little-endian order + if (bytes_per_texel == 1) + { + dest[BYTE4_XOR_LE(0)] = (data >> 0) & 0xff; + dest[BYTE4_XOR_LE(1)] = (data >> 8) & 0xff; + dest[BYTE4_XOR_LE(2)] = (data >> 16) & 0xff; + dest[BYTE4_XOR_LE(3)] = (data >> 24) & 0xff; + } + else + { + u16 *dest16 = reinterpret_cast(dest); + dest16[BYTE_XOR_LE(0)] = (data >> 0) & 0xffff; + dest16[BYTE_XOR_LE(1)] = (data >> 16) & 0xffff; + } +} + + +//------------------------------------------------- +// reg_invalid_r - generic invalid register read +//------------------------------------------------- + +u32 voodoo_1_device::reg_invalid_r(u32 chipmask, u32 regnum) +{ + return 0xffffffff; +} + + +//------------------------------------------------- +// reg_passive_r - generic passive register read +//------------------------------------------------- + +u32 voodoo_1_device::reg_passive_r(u32 chipmask, u32 regnum) +{ + return m_reg.read(regnum); +} + + +//------------------------------------------------- +// reg_status_r - status register read +//------------------------------------------------- + +u32 voodoo_1_device::reg_status_r(u32 chipmask, u32 regnum) +{ + u32 result = 0; + + // bits 5:0 are the PCI FIFO free space + result |= std::min(m_pci_fifo.space() / 2, 0x3f) << 0; + + // bit 6 is the vertical retrace + result |= m_vblank << 6; + + // bit 7 is FBI graphics engine busy + // bit 8 is TREX busy + // bit 9 is overall busy + if (operation_pending()) + result |= (1 << 7) | (1 << 8) | (1 << 9); + + // bits 10-11 is displayed buffer + result |= m_frontbuf << 10; + + // bits 12-27 is memory FIFO free space + if (m_reg.fbi_init0().enable_memory_fifo() == 0) + result |= 0xffff << 12; + else + result |= std::min(m_fbmem_fifo.space() / 2, 0xffff) << 12; + + // bits 30:28 are the number of pending swaps + result |= std::min(m_swaps_pending, 7) << 28; + + // eat some cycles since people like polling here + if (m_status_cycles != 0) + m_cpu->eat_cycles(m_status_cycles); + + // bit 31 is PCI interrupt pending (not implemented) + return result; +} + + +//------------------------------------------------- +// reg_fbiinit2_r - fbiInit2 register read +//------------------------------------------------- + +u32 voodoo_1_device::reg_fbiinit2_r(u32 chipmask, u32 regnum) +{ + // bit 2 of the initEnable register maps this to dacRead + return m_init_enable.remap_init_to_dac() ? m_dac_read_result : m_reg.read(regnum); +} + + +//------------------------------------------------- +// reg_vretrace_r - vRetrace register read +//------------------------------------------------- + +u32 voodoo_1_device::reg_vretrace_r(u32 chipmask, u32 regnum) +{ + // return 0 if vblank is active + return m_vblank ? 0 : screen().vpos(); +} + + +//------------------------------------------------- +// reg_stats_r - statistics register reads +//------------------------------------------------- + +u32 voodoo_1_device::reg_stats_r(u32 chipmask, u32 regnum) +{ + update_statistics(true); + return m_reg.read(regnum); +} + + +//------------------------------------------------- +// reg_invalid_w - generic invalid register write +//------------------------------------------------- + +u32 voodoo_1_device::reg_invalid_w(u32 chipmask, u32 regnum, u32 data) +{ + logerror("%s: Unexpected write to register %02X[%X] = %08X\n", machine().describe_context(), regnum, chipmask, data); + return 0; +} + + +//------------------------------------------------- +// reg_status_w - status register write (Voodoo 1) +//------------------------------------------------- + +u32 voodoo_1_device::reg_unimplemented_w(u32 chipmask, u32 regnum, u32 data) +{ + logerror("%s: Unimplemented write to register %02X(%X) = %08X\n", machine().describe_context(), regnum, chipmask, data); + return 0; +} + +//------------------------------------------------- +// reg_passive_w - generic passive register write +//------------------------------------------------- + +u32 voodoo_1_device::reg_passive_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) m_reg.write(regnum, data); + if (BIT(chipmask, 1)) m_tmu[0].regs().write(regnum, data); + if (BIT(chipmask, 2)) m_tmu[1].regs().write(regnum, data); + return 0; +} + + +//------------------------------------------------- +// reg_fpassive_4_w -- passive write with floating +// point to x.4 fixed point conversion +//------------------------------------------------- + +u32 voodoo_1_device::reg_fpassive_4_w(u32 chipmask, u32 regnum, u32 data) +{ + return reg_passive_w(chipmask, regnum - 0x80/4, float_to_int32(data, 4)); +} + + +//------------------------------------------------- +// reg_fpassive_12_w -- passive write with +// floating point to x.12 fixed point conversion +//------------------------------------------------- + +u32 voodoo_1_device::reg_fpassive_12_w(u32 chipmask, u32 regnum, u32 data) +{ + return reg_passive_w(chipmask, regnum - 0x80/4, float_to_int32(data, 12)); +} + + +//------------------------------------------------- +// reg_starts_w -- write to startS (14.18) +// reg_starts_w -- write to startT (14.18) +// reg_dsdx_w -- write to dSdX (14.18) +// reg_dtdx_w -- write to dTdX (14.18) +// reg_dsdy_w -- write to dSdY (14.18) +// reg_dtdy_w -- write to dTdY (14.18) +//------------------------------------------------- + +u32 voodoo_1_device::reg_starts_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_s(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_s(data64); + return 0; +} +u32 voodoo_1_device::reg_startt_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_t(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_t(data64); + return 0; +} +u32 voodoo_1_device::reg_dsdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_ds_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_ds_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_dtdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dt_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dt_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_dsdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_ds_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_ds_dy(data64); + return 0; +} +u32 voodoo_1_device::reg_dtdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 14; + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dt_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dt_dy(data64); + return 0; +} + + +//------------------------------------------------- +// reg_fstarts_w -- write to fstartS +// reg_fstartt_w -- write to fstartT +// reg_fdsdx_w -- write to fdSdX +// reg_fdtdx_w -- write to fdTdX +// reg_fdsdy_w -- write to fdSdY +// reg_fdtdy_w -- write to fdTdY +//------------------------------------------------- + +u32 voodoo_1_device::reg_fstarts_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_s(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_s(data64); + return 0; +} +u32 voodoo_1_device::reg_fstartt_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_t(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_t(data64); + return 0; +} +u32 voodoo_1_device::reg_fdsdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_ds_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_ds_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_fdtdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dt_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dt_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_fdsdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_ds_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_ds_dy(data64); + return 0; +} +u32 voodoo_1_device::reg_fdtdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dt_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dt_dy(data64); + return 0; +} + + +//------------------------------------------------- +// reg_startw_w -- write to startW (2.30 -> 16.32) +// reg_dwdx_w -- write to dWdX (2.30 -> 16.32) +// reg_dwdy_w -- write to dWdY (2.30 -> 16.32) +//------------------------------------------------- + +u32 voodoo_1_device::reg_startw_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 2; + if (BIT(chipmask, 0)) m_reg.write_start_w(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_w(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_w(data64); + return 0; +} +u32 voodoo_1_device::reg_dwdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 2; + if (BIT(chipmask, 0)) m_reg.write_dw_dx(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dw_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dw_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_dwdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = s64(s32(data)) << 2; + if (BIT(chipmask, 0)) m_reg.write_dw_dy(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dw_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dw_dy(data64); + return 0; +} + + +//------------------------------------------------- +// reg_fstartw_w -- write to fstartW +// reg_fdwdx_w -- write to fdWdX +// reg_fdwdy_w -- write to fdWdY +//------------------------------------------------- + +u32 voodoo_1_device::reg_fstartw_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 0)) m_reg.write_start_w(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_start_w(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_start_w(data64); + return 0; +} +u32 voodoo_1_device::reg_fdwdx_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 0)) m_reg.write_dw_dx(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dw_dx(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dw_dx(data64); + return 0; +} +u32 voodoo_1_device::reg_fdwdy_w(u32 chipmask, u32 regnum, u32 data) +{ + s64 data64 = float_to_int64(data, 32); + if (BIT(chipmask, 0)) m_reg.write_dw_dy(data64); + if (BIT(chipmask, 1)) m_tmu[0].regs().write_dw_dy(data64); + if (BIT(chipmask, 2)) m_tmu[1].regs().write_dw_dy(data64); + return 0; +} + + +//------------------------------------------------- +// reg_triangle_w -- write to triangleCMD/ +// ftriangleCMD +//------------------------------------------------- + +u32 voodoo_1_device::reg_triangle_w(u32 chipmask, u32 regnum, u32 data) +{ + return triangle(); +} + + +//------------------------------------------------- +// reg_nop_w -- write to nopCMD +//------------------------------------------------- + +u32 voodoo_1_device::reg_nop_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(data, 0)) + reset_counters(); + if (BIT(data, 1)) + m_reg.write(voodoo_regs::reg_fbiTrianglesOut, 0); + return 0; +} + + +//------------------------------------------------- +// reg_fastfill_w -- write to fastfillCMD +//------------------------------------------------- + +u32 voodoo_1_device::reg_fastfill_w(u32 chipmask, u32 regnum, u32 data) +{ + auto &poly = m_renderer->alloc_poly(); + + // determine the draw buffer (Banshee and later are hard-coded to the back buffer) + poly.destbase = draw_buffer_indirect(m_reg.fbz_mode().draw_buffer()); + if (poly.destbase == nullptr) + return 0; + poly.depthbase = aux_buffer(); + poly.clipleft = m_reg.clip_left(); + poly.clipright = m_reg.clip_right(); + poly.cliptop = m_reg.clip_top(); + poly.clipbottom = m_reg.clip_bottom(); + poly.color1 = m_reg.color1().argb(); + poly.zacolor = m_reg.za_color(); + + // 2 pixels per clock + return m_renderer->enqueue_fastfill(poly) / 2; +} + + +//------------------------------------------------- +// reg_swapbuffer_w -- write to swapbufferCMD +//------------------------------------------------- + +u32 voodoo_1_device::reg_swapbuffer_w(u32 chipmask, u32 regnum, u32 data) +{ + m_renderer->wait("swapbufferCMD"); + + // the don't swap value is Voodoo 2-only, masked off by the register engine + m_vblank_swap_pending = true; + m_vblank_swap = BIT(data, 1, 8); + m_vblank_dont_swap = BIT(data, 9); + + // if we're not syncing to the retrace, process the command immediately + if (!BIT(data, 0)) + { + swap_buffers(); + return 0; + } + + // determine how many cycles to wait; we deliberately overshoot here because + // the final count gets updated on the VBLANK + return (m_vblank_swap + 1) * clock() / 10; +} + + +//------------------------------------------------- +// reg_fogtable_w -- write to fogTable +//------------------------------------------------- + +u32 voodoo_1_device::reg_fogtable_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) m_renderer->write_fog(2 * (regnum - voodoo_regs::reg_fogTable), data); + return 0; +} + + +//------------------------------------------------- +// reg_fbiinit_w -- write to an fbiinit register +//------------------------------------------------- + +u32 voodoo_1_device::reg_fbiinit_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0) && m_init_enable.enable_hw_init()) + { + m_renderer->wait("fbi_init"); + m_reg.write(regnum, data); + + // handle resets written to fbiInit0 + if (regnum == voodoo_regs::reg_fbiInit0 && m_reg.fbi_init0().graphics_reset()) + soft_reset(); + if (regnum == voodoo_regs::reg_fbiInit0 && m_reg.fbi_init0().fifo_reset()) + m_pci_fifo.reset(); + + // compute FIFO layout when fbiInit0 or fbiInit4 change + if (regnum == voodoo_regs::reg_fbiInit0 || regnum == voodoo_regs::reg_fbiInit4) + recompute_fbmem_fifo(); + + // recompute video memory when fbiInit1 or fbiInit2 change + if (regnum == voodoo_regs::reg_fbiInit1 || regnum == voodoo_regs::reg_fbiInit2) + recompute_video_memory(); + + // update Y origina when fbiInit3 changes + if (regnum == voodoo_regs::reg_fbiInit3) + m_renderer->set_yorigin(m_reg.fbi_init3().yorigin_subtract()); + } + return 0; +} + + +//------------------------------------------------- +// reg_video_w -- write to a video configuration +// register; synchronize then recompute everything +//------------------------------------------------- + +u32 voodoo_1_device::reg_video_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("video_configuration"); + m_reg.write(regnum, data); + + auto const hsync = m_reg.hsync(); + auto const vsync = m_reg.vsync(); + auto const back_porch = m_reg.back_porch(); + auto const video_dimensions = m_reg.video_dimensions(); + if (hsync.raw() != 0 && vsync.raw() != 0 && video_dimensions.raw() != 0 && back_porch.raw() != 0) + { + recompute_video_timing( + hsync.hsync_on(), hsync.hsync_off(), + video_dimensions.xwidth(), back_porch.horizontal() + 2, + vsync.vsync_on(), vsync.vsync_off(), + video_dimensions.yheight(), back_porch.vertical()); + } + } + return 0; +} + + +//------------------------------------------------- +// reg_clut_w -- write to clutData; mark dirty if +// changed +//------------------------------------------------- + +u32 voodoo_1_device::reg_clut_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("clut"); + if (m_reg.fbi_init1().video_timing_reset() == 0) + { + int index = BIT(data, 24, 8); + if (index <= 32 && m_clut[index] != data) + { + m_clut[index] = data; + m_clut_dirty = true; + } + } + else + logerror("clutData ignored because video timing reset = 1\n"); + } + return 0; +} + + +//------------------------------------------------- +// reg_dac_w -- write to dacData +//------------------------------------------------- + +u32 voodoo_1_device::reg_dac_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + // upper 2 address bits are only on Voodoo2+ but are masked by the + // register entry for Voodoo 1 so safe to just use them as presented + u32 regnum = BIT(data, 8, 3) + 8 * BIT(data, 12, 2); + if (!BIT(data, 11)) + m_dac_reg[regnum] = BIT(data, 0, 8); + else + { + // this is just to make startup happy + m_dac_read_result = m_dac_reg[regnum]; + switch (m_dac_reg[7]) + { + case 0x01: m_dac_read_result = 0x55; break; + case 0x07: m_dac_read_result = 0x71; break; + case 0x0b: m_dac_read_result = 0x79; break; + } + } + } + return 0; +} + + +//------------------------------------------------- +// reg_texture_w -- passive write to a TMU; mark +// dirty if changed +//------------------------------------------------- + +u32 voodoo_1_device::reg_texture_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 1)) + { + if (data != m_tmu[0].regs().read(regnum)) + { + m_tmu[0].regs().write(regnum, data); + m_tmu[0].mark_dirty(); + } + } + if (BIT(chipmask, 2)) + { + if (data != m_tmu[1].regs().read(regnum)) + { + m_tmu[1].regs().write(regnum, data); + m_tmu[1].mark_dirty(); + } + } + return 0; +} + + +//------------------------------------------------- +// reg_palette_w -- passive write to a palette or +// NCC table; mark dirty if changed +//------------------------------------------------- + +u32 voodoo_1_device::reg_palette_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 1)) m_tmu[0].ncc_w(regnum, data); + if (BIT(chipmask, 2)) m_tmu[1].ncc_w(regnum, data); + return 0; +} + + +//------------------------------------------------- +// adjust_vblank_start_timer -- adjust the VBLANK +// start timer based on latest information +//------------------------------------------------- + +void voodoo_1_device::adjust_vblank_start_timer() +{ + attotime time_until_blank = screen().time_until_pos(m_vsyncstart); + if (LOG_VBLANK_SWAP) + logerror("adjust_vblank_start_timer: period: %s\n", time_until_blank.as_string()); + + // if zero, adjust to next frame, otherwise we may get stuck in an infinite loop + if (time_until_blank == attotime::zero) + time_until_blank = screen().frame_period(); + m_vsync_start_timer->adjust(time_until_blank); +} + + +//------------------------------------------------- +// vblank_start -- timer callback for the start +// of VBLANK +//------------------------------------------------- + +void voodoo_1_device::vblank_start(void *ptr, s32 param) +{ + if (LOG_VBLANK_SWAP) + logerror("--- vblank start\n"); + + // flush the pipes + if (operation_pending()) + { + if (LOG_VBLANK_SWAP) + logerror("---- vblank flush begin\n"); + flush_fifos(machine().time()); + if (LOG_VBLANK_SWAP) + logerror("---- vblank flush end\n"); + } + + // increment the count + m_vblank_count = std::min(m_vblank_count + 1, 250); + + // logging + if (LOG_VBLANK_SWAP) + logerror("---- vblank count = %u swap = %u pending = %u", m_vblank_count, m_vblank_swap, m_vblank_swap_pending); + if (LOG_VBLANK_SWAP && m_vblank_swap_pending) + logerror(" (target=%d)", m_vblank_swap); + if (LOG_VBLANK_SWAP) + logerror("\n"); + + // if we're past the swap count, do the swap + if (m_vblank_swap_pending && m_vblank_count >= m_vblank_swap) + swap_buffers(); + + // set a timer for the next off state + m_vsync_stop_timer->adjust(screen().time_until_pos(m_vsyncstop)); + + // set internal state and call the client + m_vblank = true; + + // notify external VBLANK handler on all models + if (!m_vblank_cb.isnull()) + m_vblank_cb(true); +} + + +//------------------------------------------------- +// vblank_stop -- timer callback for the end of +// VBLANK +//------------------------------------------------- + +void voodoo_1_device::vblank_stop(void *ptr, s32 param) +{ + if (LOG_VBLANK_SWAP) + logerror("--- vblank end\n"); + + // set internal state and call the client + m_vblank = false; + + // notify external VBLANK handler on all models + if (!m_vblank_cb.isnull()) + m_vblank_cb(false); + + // go to the end of the next frame + adjust_vblank_start_timer(); +} + + +//------------------------------------------------- +// swap_buffers -- perform a buffer swap; in most +// cases this comes at VBLANK time +//------------------------------------------------- + +void voodoo_1_device::swap_buffers() +{ + if (LOG_VBLANK_SWAP) + logerror("--- swap_buffers @ %d\n", screen().vpos()); + + // force a partial update + screen().update_partial(screen().vpos()); + m_video_changed = true; + + // keep a history of swap intervals + m_reg.update_swap_history(std::min(m_vblank_count, 15)); + + // rotate the buffers; implementation differs between models + rotate_buffers(); + + // decrement the pending count and reset our state + if (m_swaps_pending != 0) + m_swaps_pending--; + m_vblank_count = 0; + m_vblank_swap_pending = false; + + // reset the last_op_time to now and start processing the next command + if (operation_pending()) + { + if (LOG_VBLANK_SWAP) + logerror("---- swap_buffers flush begin\n"); + flush_fifos(m_operation_end = machine().time()); + if (LOG_VBLANK_SWAP) + logerror("---- swap_buffers flush end\n"); + } + + // we may be able to unstall now + if (m_stall_state != NOT_STALLED) + check_stalled_cpu(machine().time()); + + // periodically log rasterizer info + m_stats.m_swaps++; + if (m_stats.m_swaps % 1000 == 0) + m_renderer->dump_rasterizer_stats(); + + // update the statistics (debug) + if (DEBUG_STATS) + { + if (m_stats.displayed()) + { + update_statistics(true); + m_stats.update_string(screen().visible_area(), m_reg.swap_history()); + } + m_stats.reset(); + } +} + + +//------------------------------------------------- +// rotate_buffers -- rotate the buffers according +// to the current buffer config; this is split +// out so later devices can override +//------------------------------------------------- + +void voodoo_1_device::rotate_buffers() +{ + if (!m_vblank_dont_swap) + { + u32 buffers = (m_rgboffs[2] == ~0) ? 2 : 3; + m_frontbuf = (m_frontbuf + 1) % buffers; + m_backbuf = (m_frontbuf + 1) % buffers; + } +} + + +//------------------------------------------------- +// update_common -- shared update function +//------------------------------------------------- + +int voodoo_1_device::update_common(bitmap_rgb32 &bitmap, const rectangle &cliprect, rgb_t const *pens) +{ + // reset the video changed flag + bool changed = m_video_changed; + m_video_changed = false; + + // select the buffer to draw + int drawbuf = m_frontbuf; + if (DEBUG_BACKBUF && machine().input().code_pressed(KEYCODE_L)) + drawbuf = m_backbuf; + + // copy from the current front buffer + if (LOG_VBLANK_SWAP) logerror("--- update_common @ %d from %08X\n", screen().vpos(), m_rgboffs[m_frontbuf]); + u32 rowpixels = m_renderer->rowpixels(); + u16 *buffer_base = draw_buffer(drawbuf); + for (s32 y = cliprect.min_y; y <= cliprect.max_y; y++) + { + if (y < m_yoffs) + continue; + u16 const *const src = buffer_base + (y - m_yoffs) * rowpixels - m_xoffs; + u32 *dst = &bitmap.pix(y); + for (s32 x = cliprect.min_x; x <= cliprect.max_x; x++) + dst[x] = pens[src[x]]; + } + + // update stats display + if (DEBUG_STATS && m_stats.update_display_state(machine().input().code_pressed(KEYCODE_BACKSLASH))) + popmessage(m_stats.string(), 0, 0); + + // overwrite with the depth buffer if debugging and the ENTER key is pressed + if (DEBUG_DEPTH && machine().input().code_pressed(KEYCODE_ENTER)) + for (s32 y = cliprect.min_y; y <= cliprect.max_y; y++) + { + u16 const *const src = aux_buffer() + (y - m_yoffs) * rowpixels - m_xoffs; + u32 *const dst = &bitmap.pix(y); + for (s32 x = cliprect.min_x; x <= cliprect.max_x; x++) + dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff); + } + + return changed; +} + + +//------------------------------------------------- +// recompute_video_timing -- given hsync and +// vsync parameter, find the best match for known +// monitor types and select the best fit +//------------------------------------------------- + +void voodoo_1_device::recompute_video_timing(u32 hsyncon, u32 hsyncoff, u32 hvis, u32 hbp, u32 vsyncon, u32 vsyncoff, u32 vvis, u32 vbp) +{ + u32 htotal = hsyncoff + 1 + hsyncon + 1; + u32 vtotal = vsyncoff + vsyncon; + + // create a new visarea from the backporch and visible values + rectangle visarea(hbp, hbp + std::max(s32(hvis) - 1, 0), vbp, vbp + std::max(s32(vvis) - 1, 0)); + + // keep within bounds + visarea.max_x = std::min(visarea.max_x, htotal - 1); + visarea.max_y = std::min(visarea.max_y, vtotal - 1); + + // compute the new period for standard res, medium res, and VGA res + attoseconds_t stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal; + attoseconds_t medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal; + attoseconds_t vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal; + + // compute a diff against the current refresh period + attoseconds_t refresh = screen().frame_period().attoseconds(); + attoseconds_t stddiff = std::abs(stdperiod - refresh); + attoseconds_t meddiff = std::abs(medperiod - refresh); + attoseconds_t vgadiff = std::abs(vgaperiod - refresh); + + logerror("hSync=%d-%d, bp=%d, vis=%d vSync=%d-%d, bp=%d, vis=%d\n", hsyncon, hsyncoff, hbp, hvis, vsyncon, vsyncoff, vbp, vvis); + logerror("Horiz: %d-%d (%d total) Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal); + + // configure the screen based on which one matches the closest + if (stddiff < meddiff && stddiff < vgadiff) + { + screen().configure(htotal, vtotal, visarea, stdperiod); + logerror("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod)); + } + else if (meddiff < vgadiff) + { + screen().configure(htotal, vtotal, visarea, medperiod); + logerror("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod)); + } + else + { + screen().configure(htotal, vtotal, visarea, vgaperiod); + logerror("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod)); + } + + // configure the new framebuffer info + m_width = hvis; + m_height = vvis; + m_xoffs = hbp; + m_yoffs = vbp; + m_vsyncstart = vsyncoff; + m_vsyncstop = vsyncon; + logerror("yoffs: %d vsyncstart: %d vsyncstop: %d\n", vbp, m_vsyncstart, m_vsyncstop); + + adjust_vblank_start_timer(); +} + + +//------------------------------------------------- +// recompute_video_memory -- compute the layout +// of video memory +//------------------------------------------------- + +void voodoo_1_device::recompute_video_memory() +{ + // configuration is either double-buffered (0) or triple-buffered (1) + u32 config = m_reg.fbi_init2().enable_triple_buf(); + + // 4-bit tile count; tiles are 64x16 + u32 xtiles = m_reg.fbi_init1().x_video_tiles(); + recompute_video_memory_common(config, xtiles * 64); +} + + +//------------------------------------------------- +// recompute_video_memory_common -- core logic +// for video memory layout based on 2-bit config +// and the computed rowpixels +//------------------------------------------------- + +void voodoo_1_device::recompute_video_memory_common(u32 config, u32 rowpixels) +{ + // remember the front buffer configuration to check for changes + u16 *starting_front = front_buffer(); + u32 starting_rowpix = m_renderer->rowpixels(); + + // first RGB buffer always starts at 0 + m_rgboffs[0] = 0; + + // second RGB buffer starts immediately afterwards + u32 const buffer_pages = m_reg.fbi_init2().video_buffer_offset(); + m_rgboffs[1] = buffer_pages * 0x1000; + + // remaining buffers are based on the config + switch (config) + { + case 3: // reserved +// logerror("VOODOO.ERROR:Unexpected memory configuration in recompute_video_memory!\n"); + [[fallthrough]]; + case 0: // 2 color buffers, 1 aux buffer + m_rgboffs[2] = ~0; + m_auxoffs = 2 * buffer_pages * 0x1000; + break; + + case 1: // 3 color buffers, 0 aux buffers + m_rgboffs[2] = 2 * buffer_pages * 0x1000; + m_auxoffs = ~0; + break; + + case 2: // 3 color buffers, 1 aux buffers + m_rgboffs[2] = 2 * buffer_pages * 0x1000; + m_auxoffs = 3 * buffer_pages * 0x1000; + break; + } + + // clamp the RGB buffers to video memory + for (int buf = 0; buf < 3; buf++) + if (m_rgboffs[buf] != ~0 && m_rgboffs[buf] > m_fbmask) + m_rgboffs[buf] = m_fbmask; + + // clamp the aux buffer to video memory + if (m_auxoffs != ~0 && m_auxoffs > m_fbmask) + m_auxoffs = m_fbmask; + + // reset our front/back buffers if they are out of range + if (m_rgboffs[2] == ~0) + { + if (m_frontbuf == 2) + m_frontbuf = 0; + if (m_backbuf == 2) + m_backbuf = 0; + } + + // mark video changed if the front buffer configuration is different + if (front_buffer() != starting_front || rowpixels != starting_rowpix) + m_video_changed = true; + m_renderer->set_rowpixels(rowpixels); +} + + +//------------------------------------------------- +// triangle - execute the 'triangle' command +//------------------------------------------------- + +s32 voodoo_1_device::triangle() +{ + g_profiler.start(PROFILER_USER2); + + // allocate polygon information now + auto &poly = m_renderer->alloc_poly(); + + // determine the draw buffer + poly.destbase = draw_buffer_indirect(m_reg.fbz_mode().draw_buffer()); + if (poly.destbase == nullptr) + return TRIANGLE_SETUP_CLOCKS; + poly.depthbase = aux_buffer(); + poly.clipleft = m_reg.clip_left(); + poly.clipright = m_reg.clip_right(); + poly.cliptop = m_reg.clip_top(); + poly.clipbottom = m_reg.clip_bottom(); + + // fill in triangle parameters + poly.ax = m_reg.ax(); + poly.ay = m_reg.ay(); + poly.startr = m_reg.start_r(); + poly.startg = m_reg.start_g(); + poly.startb = m_reg.start_b(); + poly.starta = m_reg.start_a(); + poly.startz = m_reg.start_z(); + poly.startw = m_reg.start_w(); + poly.drdx = m_reg.dr_dx(); + poly.dgdx = m_reg.dg_dx(); + poly.dbdx = m_reg.db_dx(); + poly.dadx = m_reg.da_dx(); + poly.dzdx = m_reg.dz_dx(); + poly.dwdx = m_reg.dw_dx(); + poly.drdy = m_reg.dr_dy(); + poly.dgdy = m_reg.dg_dy(); + poly.dbdy = m_reg.db_dy(); + poly.dady = m_reg.da_dy(); + poly.dzdy = m_reg.dz_dy(); + poly.dwdy = m_reg.dw_dy(); + + // perform subpixel adjustments -- note that the documentation indicates this + // is done in the internal registers, so do it there + if (m_reg.fbz_colorpath().cca_subpixel_adjust()) + { + s32 dx = 8 - (poly.ax & 15); + s32 dy = 8 - (poly.ay & 15); + + // adjust iterated R,G,B,A and W/Z + m_reg.write(voodoo_regs::reg_startR, poly.startr += (dy * poly.drdy + dx * poly.drdx) >> 4); + m_reg.write(voodoo_regs::reg_startG, poly.startg += (dy * poly.dgdy + dx * poly.dgdx) >> 4); + m_reg.write(voodoo_regs::reg_startB, poly.startb += (dy * poly.dbdy + dx * poly.dbdx) >> 4); + m_reg.write(voodoo_regs::reg_startA, poly.starta += (dy * poly.dady + dx * poly.dadx) >> 4); + m_reg.write(voodoo_regs::reg_startZ, poly.startz += (dy * poly.dzdy + dx * poly.dzdx) >> 4); + m_reg.write_start_w(poly.startw += (dy * poly.dwdy + dx * poly.dwdx) >> 4); + + // adjust iterated W/S/T for TMU 0 + auto &tmu0regs = m_tmu[0].regs(); + tmu0regs.write_start_w(tmu0regs.start_w() + ((dy * tmu0regs.dw_dy() + dx * tmu0regs.dw_dx()) >> 4)); + tmu0regs.write_start_s(tmu0regs.start_s() + ((dy * tmu0regs.ds_dy() + dx * tmu0regs.ds_dx()) >> 4)); + tmu0regs.write_start_t(tmu0regs.start_t() + ((dy * tmu0regs.dt_dy() + dx * tmu0regs.dt_dx()) >> 4)); + + // adjust iterated W/S/T for TMU 1 + if (BIT(m_chipmask, 2)) + { + auto &tmu1regs = m_tmu[1].regs(); + tmu1regs.write_start_w(tmu1regs.start_w() + ((dy * tmu1regs.dw_dy() + dx * tmu1regs.dw_dx()) >> 4)); + tmu1regs.write_start_s(tmu1regs.start_s() + ((dy * tmu1regs.ds_dy() + dx * tmu1regs.ds_dx()) >> 4)); + tmu1regs.write_start_t(tmu1regs.start_t() + ((dy * tmu1regs.dt_dy() + dx * tmu1regs.dt_dx()) >> 4)); + } + } + + // fill in texture 0 parameters + poly.tex0 = nullptr; + if (poly.raster.texmode0().raw() != 0xffffffff) + { + auto &tmu0regs = m_tmu[0].regs(); + poly.starts0 = tmu0regs.start_s(); + poly.startt0 = tmu0regs.start_t(); + poly.startw0 = tmu0regs.start_w(); + poly.ds0dx = tmu0regs.ds_dx(); + poly.dt0dx = tmu0regs.dt_dx(); + poly.dw0dx = tmu0regs.dw_dx(); + poly.ds0dy = tmu0regs.ds_dy(); + poly.dt0dy = tmu0regs.dt_dy(); + poly.dw0dy = tmu0regs.dw_dy(); + poly.tex0 = &m_tmu[0].prepare_texture(*m_renderer.get()); + if (DEBUG_STATS) + m_stats.m_texture_mode[tmu0regs.texture_mode().format()]++; + } + + // fill in texture 1 parameters + poly.tex1 = nullptr; + if (poly.raster.texmode1().raw() != 0xffffffff) + { + auto &tmu1regs = m_tmu[1].regs(); + poly.starts1 = tmu1regs.start_s(); + poly.startt1 = tmu1regs.start_t(); + poly.startw1 = tmu1regs.start_w(); + poly.ds1dx = tmu1regs.ds_dx(); + poly.dt1dx = tmu1regs.dt_dx(); + poly.dw1dx = tmu1regs.dw_dx(); + poly.ds1dy = tmu1regs.ds_dy(); + poly.dt1dy = tmu1regs.dt_dy(); + poly.dw1dy = tmu1regs.dw_dy(); + poly.tex1 = &m_tmu[1].prepare_texture(*m_renderer.get()); + if (DEBUG_STATS) + m_stats.m_texture_mode[tmu1regs.texture_mode().format()]++; + } + + // fill in color parameters + poly.color0 = m_reg.color0().argb(); + poly.color1 = m_reg.color1().argb(); + poly.chromakey = m_reg.chroma_key().argb(); + poly.fogcolor = m_reg.fog_color().argb(); + poly.zacolor = m_reg.za_color(); + poly.stipple = m_reg.stipple(); + poly.alpharef = m_reg.alpha_mode().alpharef(); + + // fill in the vertex data + voodoo_renderer::vertex_t vert[3]; + vert[0].x = float(m_reg.ax()) * (1.0f / 16.0f); + vert[0].y = float(m_reg.ay()) * (1.0f / 16.0f); + vert[1].x = float(m_reg.bx()) * (1.0f / 16.0f); + vert[1].y = float(m_reg.by()) * (1.0f / 16.0f); + vert[2].x = float(m_reg.cx()) * (1.0f / 16.0f); + vert[2].y = float(m_reg.cy()) * (1.0f / 16.0f); + + // enqueue a triangle + s32 pixels = m_renderer->enqueue_triangle(poly, vert); + + // update stats + m_reg.add(voodoo_regs::reg_fbiTrianglesOut, 1); + if (DEBUG_STATS) + m_stats.m_triangles++; + + g_profiler.stop(); + + if (LOG_REGISTERS) + logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels); + + // 1 pixel per clock, plus some setup time + return TRIANGLE_SETUP_CLOCKS + pixels; +} + + +//------------------------------------------------- +// accumulate_statistics - add the statistics +// from the given thread block to the shared +// statistics +//------------------------------------------------- + +void voodoo_1_device::accumulate_statistics(thread_stats_block const &block) +{ + // update live voodoo statistics + m_reg.add(voodoo_regs::reg_fbiPixelsIn, block.pixels_in); + m_reg.add(voodoo_regs::reg_fbiPixelsOut, block.pixels_out); + m_reg.add(voodoo_regs::reg_fbiChromaFail, block.chroma_fail); + m_reg.add(voodoo_regs::reg_fbiZfuncFail, block.zfunc_fail); + m_reg.add(voodoo_regs::reg_fbiAfuncFail, block.afunc_fail); + + // update emulation statistics + if (DEBUG_STATS) + m_stats.add_emulation_stats(block); +} + + +//------------------------------------------------- +// update_statistics - gather statistics from +// all threads and then reset the thread-local +// information +//------------------------------------------------- + +void voodoo_1_device::update_statistics(bool accumulate) +{ + // accumulate/reset statistics from all units + for (auto &stats : m_renderer->thread_stats()) + { + if (accumulate) + accumulate_statistics(stats); + stats.reset(); + } + + // accumulate/reset statistics from the LFB + if (accumulate) + accumulate_statistics(m_lfb_stats); + m_lfb_stats.reset(); +} + + +//------------------------------------------------- +// reset_counters - reset the exposed statistics +// counters to 0 +//------------------------------------------------- + +void voodoo_1_device::reset_counters() +{ + update_statistics(false); + m_reg.write(voodoo_regs::reg_fbiPixelsIn, 0); + m_reg.write(voodoo_regs::reg_fbiChromaFail, 0); + m_reg.write(voodoo_regs::reg_fbiZfuncFail, 0); + m_reg.write(voodoo_regs::reg_fbiAfuncFail, 0); + m_reg.write(voodoo_regs::reg_fbiPixelsOut, 0); +} + + +//------------------------------------------------- +// check_stalled_cpu - determine if it's time to +// un-stall a CPU given pending operations +//------------------------------------------------- + +void voodoo_1_device::check_stalled_cpu(attotime current_time) +{ + bool resume = false; + + // flush anything we can + if (operation_pending()) + flush_fifos(current_time); + + // if we're just stalled until the LWM is passed, see if we're ok now + if (m_stall_state == STALLED_UNTIL_FIFO_LWM) + { + // if there's room in the memory FIFO now, we can proceed + if (m_reg.fbi_init0().enable_memory_fifo()) + { + if (m_fbmem_fifo.items() < 2 * 32 * m_reg.fbi_init0().memory_fifo_hwm()) + resume = true; + } + else if (m_pci_fifo.space() > 2 * m_reg.fbi_init0().pci_fifo_lwm()) + resume = true; + } + + // if we're stalled until the FIFOs are empty, check now + else if (m_stall_state == STALLED_UNTIL_FIFO_EMPTY) + { + if (m_reg.fbi_init0().enable_memory_fifo()) + { + if (m_fbmem_fifo.empty() && m_pci_fifo.empty()) + resume = true; + } + else if (m_pci_fifo.empty()) + resume = true; + } + + // resume if necessary + if (resume || !operation_pending()) + { + if (LOG_FIFO) + logerror("VOODOO.FIFO:Stall condition cleared; resuming\n"); + m_stall_state = NOT_STALLED; + + // either call the callback, or trigger the trigger + if (!m_stall_cb.isnull()) + m_stall_cb(false); + else + machine().scheduler().trigger(m_stall_trigger); + } + + // if not, set a timer for the next one + else + m_stall_resume_timer->adjust(m_operation_end - current_time); +} + + +//------------------------------------------------- +// stall_cpu - stall our associated CPU until +// operations are complete +//------------------------------------------------- + +void voodoo_1_device::stall_cpu(stall_state state) +{ + // sanity check + assert(operation_pending()); + + // set the state and update statistics + m_stall_state = state; + if (DEBUG_STATS) + m_stats.m_stalls++; + + // either call the callback, or spin the CPU + if (!m_stall_cb.isnull()) + m_stall_cb(true); + else + m_cpu->spin_until_trigger(m_stall_trigger); + + // set a timer to clear the stall + m_stall_resume_timer->adjust(m_operation_end - machine().time()); +} + + +//------------------------------------------------- +// stall_resume_callback - timer callback to +// check the stall state for our CPU +//------------------------------------------------- + +void voodoo_1_device::stall_resume_callback(void *ptr, s32 param) +{ + check_stalled_cpu(machine().time()); +} + + +//************************************************************************** +// VOODOO 1 REGISTER MAP +//************************************************************************** + +#define REGISTER_ENTRY(name, reader, writer, bits, chips, sync, fifo) \ + { static_register_table_entry::make_mask(bits), register_table_entry::CHIPMASK_##chips | register_table_entry::SYNC_##sync | register_table_entry::FIFO_##fifo, #name, &voodoo_1_device::reg_##writer##_w, &voodoo_1_device::reg_##reader##_r }, + +#define RESERVED_ENTRY REGISTER_ENTRY(reserved, invalid, invalid, 32, FBI, NOSYNC, FIFO) + +#define RESERVED_ENTRY_x8 RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY + +static_register_table_entry const voodoo_1_device::s_register_table[256] = +{ + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(status, status, unimplemented,32,FBI, NOSYNC, FIFO) // 000 + RESERVED_ENTRY // 004 + REGISTER_ENTRY(vertexAx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 008 + REGISTER_ENTRY(vertexAy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 00c + REGISTER_ENTRY(vertexBx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 010 + REGISTER_ENTRY(vertexBy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 014 + REGISTER_ENTRY(vertexCx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 018 + REGISTER_ENTRY(vertexCy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 01c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(startR, invalid, passive, 24, FBI, NOSYNC, FIFO) // 020 + REGISTER_ENTRY(startG, invalid, passive, 24, FBI, NOSYNC, FIFO) // 024 + REGISTER_ENTRY(startB, invalid, passive, 24, FBI, NOSYNC, FIFO) // 028 + REGISTER_ENTRY(startZ, invalid, passive, 32, FBI, NOSYNC, FIFO) // 02c + REGISTER_ENTRY(startA, invalid, passive, 24, FBI, NOSYNC, FIFO) // 030 + REGISTER_ENTRY(startS, invalid, starts, 32, TREX, NOSYNC, FIFO) // 034 + REGISTER_ENTRY(startT, invalid, startt, 32, TREX, NOSYNC, FIFO) // 038 + REGISTER_ENTRY(startW, invalid, startw, 32, FBI_TREX, NOSYNC, FIFO) // 03c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 040 + REGISTER_ENTRY(dGdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 044 + REGISTER_ENTRY(dBdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 048 + REGISTER_ENTRY(dZdX, invalid, passive, 32, FBI, NOSYNC, FIFO) // 04c + REGISTER_ENTRY(dAdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 050 + REGISTER_ENTRY(dSdX, invalid, dsdx, 32, TREX, NOSYNC, FIFO) // 054 + REGISTER_ENTRY(dTdX, invalid, dtdx, 32, TREX, NOSYNC, FIFO) // 058 + REGISTER_ENTRY(dWdX, invalid, dwdx, 32, FBI_TREX, NOSYNC, FIFO) // 05c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 060 + REGISTER_ENTRY(dGdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 064 + REGISTER_ENTRY(dBdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 068 + REGISTER_ENTRY(dZdY, invalid, passive, 32, FBI, NOSYNC, FIFO) // 06c + REGISTER_ENTRY(dAdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 070 + REGISTER_ENTRY(dSdY, invalid, dsdy, 32, TREX, NOSYNC, FIFO) // 074 + REGISTER_ENTRY(dTdY, invalid, dtdy, 32, TREX, NOSYNC, FIFO) // 078 + REGISTER_ENTRY(dWdY, invalid, dwdy, 32, FBI_TREX, NOSYNC, FIFO) // 07c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(triangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 080 + RESERVED_ENTRY // 084 + REGISTER_ENTRY(fvertexAx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 088 + REGISTER_ENTRY(fvertexAy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 08c + REGISTER_ENTRY(fvertexBx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 090 + REGISTER_ENTRY(fvertexBy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 094 + REGISTER_ENTRY(fvertexCx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 098 + REGISTER_ENTRY(fvertexCy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 09c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fstartR, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a0 + REGISTER_ENTRY(fstartG, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a4 + REGISTER_ENTRY(fstartB, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a8 + REGISTER_ENTRY(fstartZ, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ac + REGISTER_ENTRY(fstartA, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0b0 + REGISTER_ENTRY(fstartS, invalid, fstarts, 32, TREX, NOSYNC, FIFO) // 0b4 + REGISTER_ENTRY(fstartT, invalid, fstartt, 32, TREX, NOSYNC, FIFO) // 0b8 + REGISTER_ENTRY(fstartW, invalid, fstartw, 32, FBI_TREX, NOSYNC, FIFO) // 0bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c0 + REGISTER_ENTRY(fdGdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c4 + REGISTER_ENTRY(fdBdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c8 + REGISTER_ENTRY(fdZdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0cc + REGISTER_ENTRY(fdAdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0d0 + REGISTER_ENTRY(fdSdX, invalid, fdsdx, 32, TREX, NOSYNC, FIFO) // 0d4 + REGISTER_ENTRY(fdTdX, invalid, fdtdx, 32, TREX, NOSYNC, FIFO) // 0d8 + REGISTER_ENTRY(fdWdX, invalid, fdwdx, 32, FBI_TREX, NOSYNC, FIFO) // 0dc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e0 + REGISTER_ENTRY(fdGdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e4 + REGISTER_ENTRY(fdBdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e8 + REGISTER_ENTRY(fdZdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ec + REGISTER_ENTRY(fdAdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0f0 + REGISTER_ENTRY(fdSdY, invalid, fdsdy, 32, TREX, NOSYNC, FIFO) // 0f4 + REGISTER_ENTRY(fdTdY, invalid, fdtdy, 32, TREX, NOSYNC, FIFO) // 0f8 + REGISTER_ENTRY(fdWdY, invalid, fdwdy, 32, FBI_TREX, NOSYNC, FIFO) // 0fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(ftriangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 100 + REGISTER_ENTRY(fbzColorPath, passive, passive, 28, FBI_TREX, NOSYNC, FIFO) // 104 + REGISTER_ENTRY(fogMode, passive, passive, 6, FBI_TREX, NOSYNC, FIFO) // 108 + REGISTER_ENTRY(alphaMode, passive, passive, 32, FBI_TREX, NOSYNC, FIFO) // 10c + REGISTER_ENTRY(fbzMode, passive, passive, 21, FBI_TREX, SYNC, FIFO) // 110 + REGISTER_ENTRY(lfbMode, passive, passive, 17, FBI_TREX, SYNC, FIFO) // 114 + REGISTER_ENTRY(clipLeftRight, passive, passive, 26, FBI_TREX, SYNC, FIFO) // 118 + REGISTER_ENTRY(clipLowYHighY, passive, passive, 26, FBI_TREX, SYNC, FIFO) // 11c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nopCMD, invalid, nop, 1, FBI_TREX, SYNC, FIFO) // 120 + REGISTER_ENTRY(fastfillCMD, invalid, fastfill, 0, FBI, SYNC, FIFO) // 124 + REGISTER_ENTRY(swapbufferCMD, invalid, swapbuffer, 9, FBI, SYNC, FIFO) // 128 + REGISTER_ENTRY(fogColor, invalid, passive, 24, FBI, SYNC, FIFO) // 12c + REGISTER_ENTRY(zaColor, invalid, passive, 32, FBI, SYNC, FIFO) // 130 + REGISTER_ENTRY(chromaKey, invalid, passive, 24, FBI, SYNC, FIFO) // 134 + RESERVED_ENTRY // 138 + RESERVED_ENTRY // 13c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(stipple, passive, passive, 32, FBI, SYNC, FIFO) // 140 + REGISTER_ENTRY(color0, passive, passive, 32, FBI, SYNC, FIFO) // 144 + REGISTER_ENTRY(color1, passive, passive, 32, FBI, SYNC, FIFO) // 148 + REGISTER_ENTRY(fbiPixelsIn, stats, invalid, 24, FBI, NA, NA) // 14c + REGISTER_ENTRY(fbiChromaFail, stats, invalid, 24, FBI, NA, NA) // 150 + REGISTER_ENTRY(fbiZfuncFail, stats, invalid, 24, FBI, NA, NA) // 154 + REGISTER_ENTRY(fbiAfuncFail, stats, invalid, 24, FBI, NA, NA) // 158 + REGISTER_ENTRY(fbiPixelsOut, stats, invalid, 24, FBI, NA, NA) // 15c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[0], invalid, fogtable, 32, FBI, SYNC, FIFO) // 160 + REGISTER_ENTRY(fogTable[1], invalid, fogtable, 32, FBI, SYNC, FIFO) // 164 + REGISTER_ENTRY(fogTable[2], invalid, fogtable, 32, FBI, SYNC, FIFO) // 168 + REGISTER_ENTRY(fogTable[3], invalid, fogtable, 32, FBI, SYNC, FIFO) // 16c + REGISTER_ENTRY(fogTable[4], invalid, fogtable, 32, FBI, SYNC, FIFO) // 170 + REGISTER_ENTRY(fogTable[5], invalid, fogtable, 32, FBI, SYNC, FIFO) // 174 + REGISTER_ENTRY(fogTable[6], invalid, fogtable, 32, FBI, SYNC, FIFO) // 178 + REGISTER_ENTRY(fogTable[7], invalid, fogtable, 32, FBI, SYNC, FIFO) // 17c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[8], invalid, fogtable, 32, FBI, SYNC, FIFO) // 180 + REGISTER_ENTRY(fogTable[9], invalid, fogtable, 32, FBI, SYNC, FIFO) // 184 + REGISTER_ENTRY(fogTable[10], invalid, fogtable, 32, FBI, SYNC, FIFO) // 188 + REGISTER_ENTRY(fogTable[11], invalid, fogtable, 32, FBI, SYNC, FIFO) // 18c + REGISTER_ENTRY(fogTable[12], invalid, fogtable, 32, FBI, SYNC, FIFO) // 190 + REGISTER_ENTRY(fogTable[13], invalid, fogtable, 32, FBI, SYNC, FIFO) // 194 + REGISTER_ENTRY(fogTable[14], invalid, fogtable, 32, FBI, SYNC, FIFO) // 198 + REGISTER_ENTRY(fogTable[15], invalid, fogtable, 32, FBI, SYNC, FIFO) // 19c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[16], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a0 + REGISTER_ENTRY(fogTable[17], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a4 + REGISTER_ENTRY(fogTable[18], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a8 + REGISTER_ENTRY(fogTable[19], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1ac + REGISTER_ENTRY(fogTable[20], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b0 + REGISTER_ENTRY(fogTable[21], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b4 + REGISTER_ENTRY(fogTable[22], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b8 + REGISTER_ENTRY(fogTable[23], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[24], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c0 + REGISTER_ENTRY(fogTable[25], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c4 + REGISTER_ENTRY(fogTable[26], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c8 + REGISTER_ENTRY(fogTable[27], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1cc + REGISTER_ENTRY(fogTable[28], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d0 + REGISTER_ENTRY(fogTable[29], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d4 + REGISTER_ENTRY(fogTable[30], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d8 + REGISTER_ENTRY(fogTable[31], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1dc + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY_x8 // 1e0-1fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fbiInit4, passive, fbiinit, 28, FBI, NOSYNC, NOFIFO) // 200 + REGISTER_ENTRY(vRetrace, vretrace, invalid, 12, FBI, NA, NA) // 204 + REGISTER_ENTRY(backPorch, passive, video, 24, FBI, NOSYNC, NOFIFO) // 208 + REGISTER_ENTRY(videoDimensions, passive, video, 26, FBI, NOSYNC, NOFIFO) // 20c + REGISTER_ENTRY(fbiInit0, passive, fbiinit, 31, FBI, NOSYNC, NOFIFO) // 210 + REGISTER_ENTRY(fbiInit1, passive, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 214 + REGISTER_ENTRY(fbiInit2, fbiinit2, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 218 + REGISTER_ENTRY(fbiInit3, passive, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 21c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(hSync, invalid, video, 26, FBI, NOSYNC, NOFIFO) // 220 + REGISTER_ENTRY(vSync, invalid, video, 28, FBI, NOSYNC, NOFIFO) // 224 + REGISTER_ENTRY(clutData, invalid, clut, 30, FBI, NOSYNC, NOFIFO) // 228 + REGISTER_ENTRY(dacData, invalid, dac, 12, FBI, NOSYNC, NOFIFO) // 22c + REGISTER_ENTRY(maxRgbDelta, invalid, unimplemented,24,FBI, NOSYNC, NOFIFO) // 230 + RESERVED_ENTRY // 234 + RESERVED_ENTRY // 238 + RESERVED_ENTRY // 23c + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY_x8 // 240-25c + RESERVED_ENTRY_x8 // 260-27c + RESERVED_ENTRY_x8 // 280-29c + RESERVED_ENTRY_x8 // 2a0-2bc + RESERVED_ENTRY_x8 // 2c0-2dc + RESERVED_ENTRY_x8 // 2e0-2fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(textureMode, invalid, texture, 32, TREX, NOSYNC, FIFO) // 300 + REGISTER_ENTRY(tLOD, invalid, texture, 32, TREX, NOSYNC, FIFO) // 304 + REGISTER_ENTRY(tDetail, invalid, texture, 17, TREX, NOSYNC, FIFO) // 308 + REGISTER_ENTRY(texBaseAddr, invalid, texture, 19, TREX, NOSYNC, FIFO) // 30c + REGISTER_ENTRY(texBaseAddr_1, invalid, texture, 19, TREX, NOSYNC, FIFO) // 310 + REGISTER_ENTRY(texBaseAddr_2, invalid, texture, 19, TREX, NOSYNC, FIFO) // 314 + REGISTER_ENTRY(texBaseAddr_3_8, invalid, texture, 19, TREX, NOSYNC, FIFO) // 318 + REGISTER_ENTRY(trexInit0, invalid, passive, 32, TREX, SYNC, FIFO) // 31c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(trexInit1, invalid, passive, 32, TREX, SYNC, FIFO) // 320 + REGISTER_ENTRY(nccTable0[0], invalid, palette, 32, TREX, SYNC, FIFO) // 324 + REGISTER_ENTRY(nccTable0[1], invalid, palette, 32, TREX, SYNC, FIFO) // 328 + REGISTER_ENTRY(nccTable0[2], invalid, palette, 32, TREX, SYNC, FIFO) // 32c + REGISTER_ENTRY(nccTable0[3], invalid, palette, 32, TREX, SYNC, FIFO) // 330 + REGISTER_ENTRY(nccTable0[4], invalid, palette, 32, TREX, SYNC, FIFO) // 334 + REGISTER_ENTRY(nccTable0[5], invalid, palette, 32, TREX, SYNC, FIFO) // 338 + REGISTER_ENTRY(nccTable0[6], invalid, palette, 32, TREX, SYNC, FIFO) // 33c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable0[7], invalid, palette, 32, TREX, SYNC, FIFO) // 340 + REGISTER_ENTRY(nccTable0[8], invalid, palette, 32, TREX, SYNC, FIFO) // 344 + REGISTER_ENTRY(nccTable0[9], invalid, palette, 32, TREX, SYNC, FIFO) // 348 + REGISTER_ENTRY(nccTable0[10], invalid, palette, 32, TREX, SYNC, FIFO) // 34c + REGISTER_ENTRY(nccTable0[11], invalid, palette, 32, TREX, SYNC, FIFO) // 350 + REGISTER_ENTRY(nccTable1[0], invalid, palette, 32, TREX, SYNC, FIFO) // 354 + REGISTER_ENTRY(nccTable1[1], invalid, palette, 32, TREX, SYNC, FIFO) // 358 + REGISTER_ENTRY(nccTable1[2], invalid, palette, 32, TREX, SYNC, FIFO) // 35c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[3], invalid, palette, 32, TREX, SYNC, FIFO) // 360 + REGISTER_ENTRY(nccTable1[4], invalid, palette, 32, TREX, SYNC, FIFO) // 364 + REGISTER_ENTRY(nccTable1[5], invalid, palette, 32, TREX, SYNC, FIFO) // 368 + REGISTER_ENTRY(nccTable1[6], invalid, palette, 32, TREX, SYNC, FIFO) // 36c + REGISTER_ENTRY(nccTable1[7], invalid, palette, 32, TREX, SYNC, FIFO) // 370 + REGISTER_ENTRY(nccTable1[8], invalid, palette, 32, TREX, SYNC, FIFO) // 374 + REGISTER_ENTRY(nccTable1[9], invalid, palette, 32, TREX, SYNC, FIFO) // 378 + REGISTER_ENTRY(nccTable1[10], invalid, palette, 32, TREX, SYNC, FIFO) // 37c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[11], invalid, palette, 32, TREX, SYNC, FIFO) // 380 + RESERVED_ENTRY // 384 + RESERVED_ENTRY // 388 + RESERVED_ENTRY // 38c + RESERVED_ENTRY // 390 + RESERVED_ENTRY // 394 + RESERVED_ENTRY // 398 + RESERVED_ENTRY // 39c + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY_x8 // 3a0-3bc + RESERVED_ENTRY_x8 // 3c0-3dc + RESERVED_ENTRY_x8 // 3e0-3fc +}; diff --git a/src/devices/video/voodoo.h b/src/devices/video/voodoo.h index e33928ce78b..7c56fb985d2 100644 --- a/src/devices/video/voodoo.h +++ b/src/devices/video/voodoo.h @@ -13,1478 +13,757 @@ #pragma once -#include "video/polylgcy.h" -#include "video/rgbutil.h" #include "screen.h" -/************************************* - * - * Misc. constants - * - *************************************/ +// forward declarations +class voodoo_1_device; +namespace voodoo { class save_proxy; } -/* enumeration describing reasons we might be stalled */ -enum + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +namespace voodoo { - NOT_STALLED = 0, - STALLED_UNTIL_FIFO_LWM, - STALLED_UNTIL_FIFO_EMPTY + +// enumeration specifying which model of Voodoo we are emulating +enum class voodoo_model : u8 +{ + VOODOO_1, + VOODOO_2, + VOODOO_BANSHEE, + VOODOO_3 }; +// debug +static constexpr bool DEBUG_DEPTH = false; // ENTER key to view depthbuf +static constexpr bool DEBUG_BACKBUF = false; // L key to view backbuf +static constexpr bool DEBUG_STATS = false; // \ key to view stats + +// logging +static constexpr bool LOG_VBLANK_SWAP = false; +static constexpr bool LOG_FIFO = false; +static constexpr bool LOG_FIFO_VERBOSE = false; +static constexpr bool LOG_REGISTERS = false; +static constexpr bool LOG_WAITS = false; +static constexpr bool LOG_LFB = false; +static constexpr bool LOG_TEXTURE_RAM = false; +static constexpr bool LOG_CMDFIFO = false; +static constexpr bool LOG_CMDFIFO_VERBOSE = false; + +} -// Use old table lookup versus straight double divide -#define USE_FAST_RECIP 0 +//************************************************************************** +// INTERNAL CLASSES +//************************************************************************** -/* maximum number of TMUs */ -#define MAX_TMU 2 - -/* accumulate operations less than this number of clocks */ -#define ACCUMULATE_THRESHOLD 0 - -/* number of clocks to set up a triangle (just a guess) */ -#define TRIANGLE_SETUP_CLOCKS 100 - -/* maximum number of rasterizers */ -#define MAX_RASTERIZERS 1024 - -/* size of the rasterizer hash table */ -#define RASTER_HASH_SIZE 97 - -/* flags for LFB writes */ -#define LFB_RGB_PRESENT 1 -#define LFB_ALPHA_PRESENT 2 -#define LFB_DEPTH_PRESENT 4 -#define LFB_DEPTH_PRESENT_MSW 8 - -/* flags for the register access array */ -#define REGISTER_READ 0x01 /* reads are allowed */ -#define REGISTER_WRITE 0x02 /* writes are allowed */ -#define REGISTER_PIPELINED 0x04 /* writes are pipelined */ -#define REGISTER_FIFO 0x08 /* writes go to FIFO */ -#define REGISTER_WRITETHRU 0x10 /* writes are valid even for CMDFIFO */ - -/* shorter combinations to make the table smaller */ -#define REG_R (REGISTER_READ) -#define REG_W (REGISTER_WRITE) -#define REG_WT (REGISTER_WRITE | REGISTER_WRITETHRU) -#define REG_RW (REGISTER_READ | REGISTER_WRITE) -#define REG_RWT (REGISTER_READ | REGISTER_WRITE | REGISTER_WRITETHRU) -#define REG_RP (REGISTER_READ | REGISTER_PIPELINED) -#define REG_WP (REGISTER_WRITE | REGISTER_PIPELINED) -#define REG_RWP (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED) -#define REG_RWPT (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_WRITETHRU) -#define REG_RF (REGISTER_READ | REGISTER_FIFO) -#define REG_WF (REGISTER_WRITE | REGISTER_FIFO) -#define REG_RWF (REGISTER_READ | REGISTER_WRITE | REGISTER_FIFO) -#define REG_RPF (REGISTER_READ | REGISTER_PIPELINED | REGISTER_FIFO) -#define REG_WPF (REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO) -#define REG_RWPF (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO) - -/* lookup bits is the log2 of the size of the reciprocal/log table */ -#define RECIPLOG_LOOKUP_BITS 9 - -/* input precision is how many fraction bits the input value has; this is a 64-bit number */ -#define RECIPLOG_INPUT_PREC 32 - -/* lookup precision is how many fraction bits each table entry contains */ -#define RECIPLOG_LOOKUP_PREC 22 - -/* output precision is how many fraction bits the result should have */ -#define RECIP_OUTPUT_PREC 15 -#define LOG_OUTPUT_PREC 8 +// include register and render classes +#include "voodoo_regs.h" +#include "voodoo_render.h" - -/************************************* - * - * Register constants - * - *************************************/ - -/* Codes to the right: - R = readable - W = writeable - P = pipelined - F = goes to FIFO -*/ - -/* 0x000 */ -#define vdstatus (0x000/4) /* R P */ -#define intrCtrl (0x004/4) /* RW P -- Voodoo2/Banshee only */ -#define vertexAx (0x008/4) /* W PF */ -#define vertexAy (0x00c/4) /* W PF */ -#define vertexBx (0x010/4) /* W PF */ -#define vertexBy (0x014/4) /* W PF */ -#define vertexCx (0x018/4) /* W PF */ -#define vertexCy (0x01c/4) /* W PF */ -#define startR (0x020/4) /* W PF */ -#define startG (0x024/4) /* W PF */ -#define startB (0x028/4) /* W PF */ -#define startZ (0x02c/4) /* W PF */ -#define startA (0x030/4) /* W PF */ -#define startS (0x034/4) /* W PF */ -#define startT (0x038/4) /* W PF */ -#define startW (0x03c/4) /* W PF */ - -/* 0x040 */ -#define dRdX (0x040/4) /* W PF */ -#define dGdX (0x044/4) /* W PF */ -#define dBdX (0x048/4) /* W PF */ -#define dZdX (0x04c/4) /* W PF */ -#define dAdX (0x050/4) /* W PF */ -#define dSdX (0x054/4) /* W PF */ -#define dTdX (0x058/4) /* W PF */ -#define dWdX (0x05c/4) /* W PF */ -#define dRdY (0x060/4) /* W PF */ -#define dGdY (0x064/4) /* W PF */ -#define dBdY (0x068/4) /* W PF */ -#define dZdY (0x06c/4) /* W PF */ -#define dAdY (0x070/4) /* W PF */ -#define dSdY (0x074/4) /* W PF */ -#define dTdY (0x078/4) /* W PF */ -#define dWdY (0x07c/4) /* W PF */ - -/* 0x080 */ -#define triangleCMD (0x080/4) /* W PF */ -#define fvertexAx (0x088/4) /* W PF */ -#define fvertexAy (0x08c/4) /* W PF */ -#define fvertexBx (0x090/4) /* W PF */ -#define fvertexBy (0x094/4) /* W PF */ -#define fvertexCx (0x098/4) /* W PF */ -#define fvertexCy (0x09c/4) /* W PF */ -#define fstartR (0x0a0/4) /* W PF */ -#define fstartG (0x0a4/4) /* W PF */ -#define fstartB (0x0a8/4) /* W PF */ -#define fstartZ (0x0ac/4) /* W PF */ -#define fstartA (0x0b0/4) /* W PF */ -#define fstartS (0x0b4/4) /* W PF */ -#define fstartT (0x0b8/4) /* W PF */ -#define fstartW (0x0bc/4) /* W PF */ - -/* 0x0c0 */ -#define fdRdX (0x0c0/4) /* W PF */ -#define fdGdX (0x0c4/4) /* W PF */ -#define fdBdX (0x0c8/4) /* W PF */ -#define fdZdX (0x0cc/4) /* W PF */ -#define fdAdX (0x0d0/4) /* W PF */ -#define fdSdX (0x0d4/4) /* W PF */ -#define fdTdX (0x0d8/4) /* W PF */ -#define fdWdX (0x0dc/4) /* W PF */ -#define fdRdY (0x0e0/4) /* W PF */ -#define fdGdY (0x0e4/4) /* W PF */ -#define fdBdY (0x0e8/4) /* W PF */ -#define fdZdY (0x0ec/4) /* W PF */ -#define fdAdY (0x0f0/4) /* W PF */ -#define fdSdY (0x0f4/4) /* W PF */ -#define fdTdY (0x0f8/4) /* W PF */ -#define fdWdY (0x0fc/4) /* W PF */ - -/* 0x100 */ -#define ftriangleCMD (0x100/4) /* W PF */ -#define fbzColorPath (0x104/4) /* RW PF */ -#define fogMode (0x108/4) /* RW PF */ -#define alphaMode (0x10c/4) /* RW PF */ -#define fbzMode (0x110/4) /* RW F */ -#define lfbMode (0x114/4) /* RW F */ -#define clipLeftRight (0x118/4) /* RW F */ -#define clipLowYHighY (0x11c/4) /* RW F */ -#define nopCMD (0x120/4) /* W F */ -#define fastfillCMD (0x124/4) /* W F */ -#define swapbufferCMD (0x128/4) /* W F */ -#define fogColor (0x12c/4) /* W F */ -#define zaColor (0x130/4) /* W F */ -#define chromaKey (0x134/4) /* W F */ -#define chromaRange (0x138/4) /* W F -- Voodoo2/Banshee only */ -#define userIntrCMD (0x13c/4) /* W F -- Voodoo2/Banshee only */ - -/* 0x140 */ -#define stipple (0x140/4) /* RW F */ -#define color0 (0x144/4) /* RW F */ -#define color1 (0x148/4) /* RW F */ -#define fbiPixelsIn (0x14c/4) /* R */ -#define fbiChromaFail (0x150/4) /* R */ -#define fbiZfuncFail (0x154/4) /* R */ -#define fbiAfuncFail (0x158/4) /* R */ -#define fbiPixelsOut (0x15c/4) /* R */ -#define fogTable (0x160/4) /* W F */ - -/* 0x1c0 */ -#define cmdFifoBaseAddr (0x1e0/4) /* RW -- Voodoo2 only */ -#define cmdFifoBump (0x1e4/4) /* RW -- Voodoo2 only */ -#define cmdFifoRdPtr (0x1e8/4) /* RW -- Voodoo2 only */ -#define cmdFifoAMin (0x1ec/4) /* RW -- Voodoo2 only */ -#define colBufferAddr (0x1ec/4) /* RW -- Banshee only */ -#define cmdFifoAMax (0x1f0/4) /* RW -- Voodoo2 only */ -#define colBufferStride (0x1f0/4) /* RW -- Banshee only */ -#define cmdFifoDepth (0x1f4/4) /* RW -- Voodoo2 only */ -#define auxBufferAddr (0x1f4/4) /* RW -- Banshee only */ -#define cmdFifoHoles (0x1f8/4) /* RW -- Voodoo2 only */ -#define auxBufferStride (0x1f8/4) /* RW -- Banshee only */ - -/* 0x200 */ -#define fbiInit4 (0x200/4) /* RW -- Voodoo/Voodoo2 only */ -#define clipLeftRight1 (0x200/4) /* RW -- Banshee only */ -#define vRetrace (0x204/4) /* R -- Voodoo/Voodoo2 only */ -#define clipTopBottom1 (0x204/4) /* RW -- Banshee only */ -#define backPorch (0x208/4) /* RW -- Voodoo/Voodoo2 only */ -#define videoDimensions (0x20c/4) /* RW -- Voodoo/Voodoo2 only */ -#define fbiInit0 (0x210/4) /* RW -- Voodoo/Voodoo2 only */ -#define fbiInit1 (0x214/4) /* RW -- Voodoo/Voodoo2 only */ -#define fbiInit2 (0x218/4) /* RW -- Voodoo/Voodoo2 only */ -#define fbiInit3 (0x21c/4) /* RW -- Voodoo/Voodoo2 only */ -#define hSync (0x220/4) /* W -- Voodoo/Voodoo2 only */ -#define vSync (0x224/4) /* W -- Voodoo/Voodoo2 only */ -#define clutData (0x228/4) /* W F -- Voodoo/Voodoo2 only */ -#define dacData (0x22c/4) /* W -- Voodoo/Voodoo2 only */ -#define maxRgbDelta (0x230/4) /* W -- Voodoo/Voodoo2 only */ -#define hBorder (0x234/4) /* W -- Voodoo2 only */ -#define vBorder (0x238/4) /* W -- Voodoo2 only */ -#define borderColor (0x23c/4) /* W -- Voodoo2 only */ - -/* 0x240 */ -#define hvRetrace (0x240/4) /* R -- Voodoo2 only */ -#define fbiInit5 (0x244/4) /* RW -- Voodoo2 only */ -#define fbiInit6 (0x248/4) /* RW -- Voodoo2 only */ -#define fbiInit7 (0x24c/4) /* RW -- Voodoo2 only */ -#define swapPending (0x24c/4) /* W -- Banshee only */ -#define leftOverlayBuf (0x250/4) /* W -- Banshee only */ -#define rightOverlayBuf (0x254/4) /* W -- Banshee only */ -#define fbiSwapHistory (0x258/4) /* R -- Voodoo2/Banshee only */ -#define fbiTrianglesOut (0x25c/4) /* R -- Voodoo2/Banshee only */ -#define sSetupMode (0x260/4) /* W PF -- Voodoo2/Banshee only */ -#define sVx (0x264/4) /* W PF -- Voodoo2/Banshee only */ -#define sVy (0x268/4) /* W PF -- Voodoo2/Banshee only */ -#define sARGB (0x26c/4) /* W PF -- Voodoo2/Banshee only */ -#define sRed (0x270/4) /* W PF -- Voodoo2/Banshee only */ -#define sGreen (0x274/4) /* W PF -- Voodoo2/Banshee only */ -#define sBlue (0x278/4) /* W PF -- Voodoo2/Banshee only */ -#define sAlpha (0x27c/4) /* W PF -- Voodoo2/Banshee only */ - -/* 0x280 */ -#define sVz (0x280/4) /* W PF -- Voodoo2/Banshee only */ -#define sWb (0x284/4) /* W PF -- Voodoo2/Banshee only */ -#define sWtmu0 (0x288/4) /* W PF -- Voodoo2/Banshee only */ -#define sS_W0 (0x28c/4) /* W PF -- Voodoo2/Banshee only */ -#define sT_W0 (0x290/4) /* W PF -- Voodoo2/Banshee only */ -#define sWtmu1 (0x294/4) /* W PF -- Voodoo2/Banshee only */ -#define sS_Wtmu1 (0x298/4) /* W PF -- Voodoo2/Banshee only */ -#define sT_Wtmu1 (0x29c/4) /* W PF -- Voodoo2/Banshee only */ -#define sDrawTriCMD (0x2a0/4) /* W PF -- Voodoo2/Banshee only */ -#define sBeginTriCMD (0x2a4/4) /* W PF -- Voodoo2/Banshee only */ - -/* 0x2c0 */ -#define bltSrcBaseAddr (0x2c0/4) /* RW PF -- Voodoo2 only */ -#define bltDstBaseAddr (0x2c4/4) /* RW PF -- Voodoo2 only */ -#define bltXYStrides (0x2c8/4) /* RW PF -- Voodoo2 only */ -#define bltSrcChromaRange (0x2cc/4) /* RW PF -- Voodoo2 only */ -#define bltDstChromaRange (0x2d0/4) /* RW PF -- Voodoo2 only */ -#define bltClipX (0x2d4/4) /* RW PF -- Voodoo2 only */ -#define bltClipY (0x2d8/4) /* RW PF -- Voodoo2 only */ -#define bltSrcXY (0x2e0/4) /* RW PF -- Voodoo2 only */ -#define bltDstXY (0x2e4/4) /* RW PF -- Voodoo2 only */ -#define bltSize (0x2e8/4) /* RW PF -- Voodoo2 only */ -#define bltRop (0x2ec/4) /* RW PF -- Voodoo2 only */ -#define bltColor (0x2f0/4) /* RW PF -- Voodoo2 only */ -#define bltCommand (0x2f8/4) /* RW PF -- Voodoo2 only */ -#define bltData (0x2fc/4) /* W PF -- Voodoo2 only */ - -/* 0x300 */ -#define textureMode (0x300/4) /* W PF */ -#define tLOD (0x304/4) /* W PF */ -#define tDetail (0x308/4) /* W PF */ -#define texBaseAddr (0x30c/4) /* W PF */ -#define texBaseAddr_1 (0x310/4) /* W PF */ -#define texBaseAddr_2 (0x314/4) /* W PF */ -#define texBaseAddr_3_8 (0x318/4) /* W PF */ -#define trexInit0 (0x31c/4) /* W F -- Voodoo/Voodoo2 only */ -#define trexInit1 (0x320/4) /* W F */ -#define nccTable (0x324/4) /* W F */ - - - -// 2D registers -#define banshee2D_clip0Min (0x008/4) -#define banshee2D_clip0Max (0x00c/4) -#define banshee2D_dstBaseAddr (0x010/4) -#define banshee2D_dstFormat (0x014/4) -#define banshee2D_srcColorkeyMin (0x018/4) -#define banshee2D_srcColorkeyMax (0x01c/4) -#define banshee2D_dstColorkeyMin (0x020/4) -#define banshee2D_dstColorkeyMax (0x024/4) -#define banshee2D_bresError0 (0x028/4) -#define banshee2D_bresError1 (0x02c/4) -#define banshee2D_rop (0x030/4) -#define banshee2D_srcBaseAddr (0x034/4) -#define banshee2D_commandExtra (0x038/4) -#define banshee2D_lineStipple (0x03c/4) -#define banshee2D_lineStyle (0x040/4) -#define banshee2D_pattern0Alias (0x044/4) -#define banshee2D_pattern1Alias (0x048/4) -#define banshee2D_clip1Min (0x04c/4) -#define banshee2D_clip1Max (0x050/4) -#define banshee2D_srcFormat (0x054/4) -#define banshee2D_srcSize (0x058/4) -#define banshee2D_srcXY (0x05c/4) -#define banshee2D_colorBack (0x060/4) -#define banshee2D_colorFore (0x064/4) -#define banshee2D_dstSize (0x068/4) -#define banshee2D_dstXY (0x06c/4) -#define banshee2D_command (0x070/4) - - -/************************************* - * - * Voodoo Banshee I/O space registers - * - *************************************/ - -/* 0x000 */ -#define io_status (0x000/4) /* */ -#define io_pciInit0 (0x004/4) /* */ -#define io_sipMonitor (0x008/4) /* */ -#define io_lfbMemoryConfig (0x00c/4) /* */ -#define io_miscInit0 (0x010/4) /* */ -#define io_miscInit1 (0x014/4) /* */ -#define io_dramInit0 (0x018/4) /* */ -#define io_dramInit1 (0x01c/4) /* */ -#define io_agpInit (0x020/4) /* */ -#define io_tmuGbeInit (0x024/4) /* */ -#define io_vgaInit0 (0x028/4) /* */ -#define io_vgaInit1 (0x02c/4) /* */ -#define io_dramCommand (0x030/4) /* */ -#define io_dramData (0x034/4) /* */ - -/* 0x040 */ -#define io_pllCtrl0 (0x040/4) /* */ -#define io_pllCtrl1 (0x044/4) /* */ -#define io_pllCtrl2 (0x048/4) /* */ -#define io_dacMode (0x04c/4) /* */ -#define io_dacAddr (0x050/4) /* */ -#define io_dacData (0x054/4) /* */ -#define io_rgbMaxDelta (0x058/4) /* */ -#define io_vidProcCfg (0x05c/4) /* */ -#define io_hwCurPatAddr (0x060/4) /* */ -#define io_hwCurLoc (0x064/4) /* */ -#define io_hwCurC0 (0x068/4) /* */ -#define io_hwCurC1 (0x06c/4) /* */ -#define io_vidInFormat (0x070/4) /* */ -#define io_vidInStatus (0x074/4) /* */ -#define io_vidSerialParallelPort (0x078/4) /* */ -#define io_vidInXDecimDeltas (0x07c/4) /* */ - -/* 0x080 */ -#define io_vidInDecimInitErrs (0x080/4) /* */ -#define io_vidInYDecimDeltas (0x084/4) /* */ -#define io_vidPixelBufThold (0x088/4) /* */ -#define io_vidChromaMin (0x08c/4) /* */ -#define io_vidChromaMax (0x090/4) /* */ -#define io_vidCurrentLine (0x094/4) /* */ -#define io_vidScreenSize (0x098/4) /* */ -#define io_vidOverlayStartCoords (0x09c/4) /* */ -#define io_vidOverlayEndScreenCoord (0x0a0/4) /* */ -#define io_vidOverlayDudx (0x0a4/4) /* */ -#define io_vidOverlayDudxOffsetSrcWidth (0x0a8/4) /* */ -#define io_vidOverlayDvdy (0x0ac/4) /* */ -#define io_vgab0 (0x0b0/4) /* */ -#define io_vgab4 (0x0b4/4) /* */ -#define io_vgab8 (0x0b8/4) /* */ -#define io_vgabc (0x0bc/4) /* */ - -/* 0x0c0 */ -#define io_vgac0 (0x0c0/4) /* */ -#define io_vgac4 (0x0c4/4) /* */ -#define io_vgac8 (0x0c8/4) /* */ -#define io_vgacc (0x0cc/4) /* */ -#define io_vgad0 (0x0d0/4) /* */ -#define io_vgad4 (0x0d4/4) /* */ -#define io_vgad8 (0x0d8/4) /* */ -#define io_vgadc (0x0dc/4) /* */ -#define io_vidOverlayDvdyOffset (0x0e0/4) /* */ -#define io_vidDesktopStartAddr (0x0e4/4) /* */ -#define io_vidDesktopOverlayStride (0x0e8/4) /* */ -#define io_vidInAddr0 (0x0ec/4) /* */ -#define io_vidInAddr1 (0x0f0/4) /* */ -#define io_vidInAddr2 (0x0f4/4) /* */ -#define io_vidInStride (0x0f8/4) /* */ -#define io_vidCurrOverlayStartAddr (0x0fc/4) /* */ - - - -/************************************* - * - * Voodoo Banshee AGP space registers - * - *************************************/ - -/* 0x000 */ -#define agpReqSize (0x000/4) /* */ -#define agpHostAddressLow (0x004/4) /* */ -#define agpHostAddressHigh (0x008/4) /* */ -#define agpGraphicsAddress (0x00c/4) /* */ -#define agpGraphicsStride (0x010/4) /* */ -#define agpMoveCMD (0x014/4) /* */ -#define cmdBaseAddr0 (0x020/4) /* */ -#define cmdBaseSize0 (0x024/4) /* */ -#define cmdBump0 (0x028/4) /* */ -#define cmdRdPtrL0 (0x02c/4) /* */ -#define cmdRdPtrH0 (0x030/4) /* */ -#define cmdAMin0 (0x034/4) /* */ -#define cmdAMax0 (0x03c/4) /* */ - -/* 0x040 */ -#define cmdFifoDepth0 (0x044/4) /* */ -#define cmdHoleCnt0 (0x048/4) /* */ -#define cmdBaseAddr1 (0x050/4) /* */ -#define cmdBaseSize1 (0x054/4) /* */ -#define cmdBump1 (0x058/4) /* */ -#define cmdRdPtrL1 (0x05c/4) /* */ -#define cmdRdPtrH1 (0x060/4) /* */ -#define cmdAMin1 (0x064/4) /* */ -#define cmdAMax1 (0x06c/4) /* */ -#define cmdFifoDepth1 (0x074/4) /* */ -#define cmdHoleCnt1 (0x078/4) /* */ - -/* 0x080 */ -#define cmdFifoThresh (0x080/4) /* */ -#define cmdHoleInt (0x084/4) /* */ - -/* 0x100 */ -#define yuvBaseAddress (0x100/4) /* */ -#define yuvStride (0x104/4) /* */ -#define crc1 (0x120/4) /* */ -#define crc2 (0x130/4) /* */ - - - -/************************************* - * - * Dithering tables - * - *************************************/ - -static const uint8_t dither_matrix_4x4[16] = +namespace voodoo { - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5 -}; -//static const uint8_t dither_matrix_2x2[16] = -//{ -// 2, 10, 2, 10, -// 14, 6, 14, 6, -// 2, 10, 2, 10, -// 14, 6, 14, 6 -//}; -// Using this matrix allows iteagle video memory tests to pass -static const uint8_t dither_matrix_2x2[16] = -{ - 8, 10, 8, 10, - 11, 9, 11, 9, - 8, 10, 8, 10, - 11, 9, 11, 9 -}; +// ======================> save_proxy -// Dither 4x4 subtraction matrix used in alpha blending -static const uint8_t dither_subtract_4x4[16] = -{ - (15 - 0) >> 1, (15 - 8) >> 1, (15 - 2) >> 1, (15 - 10) >> 1, - (15 - 12) >> 1, (15 - 4) >> 1, (15 - 14) >> 1, (15 - 6) >> 1, - (15 - 3) >> 1, (15 - 11) >> 1, (15 - 1) >> 1, (15 - 9) >> 1, - (15 - 15) >> 1, (15 - 7) >> 1, (15 - 13) >> 1, (15 - 5) >> 1 -}; - -// Dither 2x2 subtraction matrix used in alpha blending -static const uint8_t dither_subtract_2x2[16] = -{ - (15 - 8) >> 1, (15 - 10) >> 1, (15 - 8) >> 1, (15 - 10) >> 1, - (15 - 11) >> 1, (15 - 9) >> 1, (15 - 11) >> 1, (15 - 9) >> 1, - (15 - 8) >> 1, (15 - 10) >> 1, (15 - 8) >> 1, (15 - 10) >> 1, - (15 - 11) >> 1, (15 - 9) >> 1, (15 - 11) >> 1, (15 - 9) >> 1 -}; - -/************************************* - * - * Macros for extracting pixels - * - *************************************/ - -#define EXTRACT_565_TO_888(val, a, b, c) \ - (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \ - (b) = (((val) >> 3) & 0xfc) | (((val) >> 9) & 0x03); \ - (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); -#define EXTRACT_x555_TO_888(val, a, b, c) \ - (a) = (((val) >> 7) & 0xf8) | (((val) >> 12) & 0x07); \ - (b) = (((val) >> 2) & 0xf8) | (((val) >> 7) & 0x07); \ - (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); -#define EXTRACT_555x_TO_888(val, a, b, c) \ - (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \ - (b) = (((val) >> 3) & 0xf8) | (((val) >> 8) & 0x07); \ - (c) = (((val) << 2) & 0xf8) | (((val) >> 3) & 0x07); -#define EXTRACT_1555_TO_8888(val, a, b, c, d) \ - (a) = ((int16_t)(val) >> 15) & 0xff; \ - EXTRACT_x555_TO_888(val, b, c, d) -#define EXTRACT_5551_TO_8888(val, a, b, c, d) \ - EXTRACT_555x_TO_888(val, a, b, c) \ - (d) = ((val) & 0x0001) ? 0xff : 0x00; -#define EXTRACT_x888_TO_888(val, a, b, c) \ - (a) = ((val) >> 16) & 0xff; \ - (b) = ((val) >> 8) & 0xff; \ - (c) = ((val) >> 0) & 0xff; -#define EXTRACT_888x_TO_888(val, a, b, c) \ - (a) = ((val) >> 24) & 0xff; \ - (b) = ((val) >> 16) & 0xff; \ - (c) = ((val) >> 8) & 0xff; -#define EXTRACT_8888_TO_8888(val, a, b, c, d) \ - (a) = ((val) >> 24) & 0xff; \ - (b) = ((val) >> 16) & 0xff; \ - (c) = ((val) >> 8) & 0xff; \ - (d) = ((val) >> 0) & 0xff; -#define EXTRACT_4444_TO_8888(val, a, b, c, d) \ - (a) = (((val) >> 8) & 0xf0) | (((val) >> 12) & 0x0f); \ - (b) = (((val) >> 4) & 0xf0) | (((val) >> 8) & 0x0f); \ - (c) = (((val) >> 0) & 0xf0) | (((val) >> 4) & 0x0f); \ - (d) = (((val) << 4) & 0xf0) | (((val) >> 0) & 0x0f); -#define EXTRACT_332_TO_888(val, a, b, c) \ - (a) = (((val) >> 0) & 0xe0) | (((val) >> 3) & 0x1c) | (((val) >> 6) & 0x03); \ - (b) = (((val) << 3) & 0xe0) | (((val) >> 0) & 0x1c) | (((val) >> 3) & 0x03); \ - (c) = (((val) << 6) & 0xc0) | (((val) << 4) & 0x30) | (((val) << 2) & 0x0c) | (((val) << 0) & 0x03); - - -/************************************* - * - * Misc. macros - * - *************************************/ - -/* macro for clamping a value between minimum and maximum values */ -#define CLAMP(val,min,max) do { if ((val) < (min)) { (val) = (min); } else if ((val) > (max)) { (val) = (max); } } while (0) - -/* macro to compute the base 2 log for LOD calculations */ -#define LOGB2(x) (log((double)(x)) / log(2.0)) - - - -/************************************* - * - * Macros for extracting bitfields - * - *************************************/ - -#define INITEN_ENABLE_HW_INIT(val) (((val) >> 0) & 1) -#define INITEN_ENABLE_PCI_FIFO(val) (((val) >> 1) & 1) -#define INITEN_REMAP_INIT_TO_DAC(val) (((val) >> 2) & 1) -#define INITEN_ENABLE_SNOOP0(val) (((val) >> 4) & 1) -#define INITEN_SNOOP0_MEMORY_MATCH(val) (((val) >> 5) & 1) -#define INITEN_SNOOP0_READWRITE_MATCH(val) (((val) >> 6) & 1) -#define INITEN_ENABLE_SNOOP1(val) (((val) >> 7) & 1) -#define INITEN_SNOOP1_MEMORY_MATCH(val) (((val) >> 8) & 1) -#define INITEN_SNOOP1_READWRITE_MATCH(val) (((val) >> 9) & 1) -#define INITEN_SLI_BUS_OWNER(val) (((val) >> 10) & 1) -#define INITEN_SLI_ODD_EVEN(val) (((val) >> 11) & 1) -#define INITEN_SECONDARY_REV_ID(val) (((val) >> 12) & 0xf) /* voodoo 2 only */ -#define INITEN_MFCTR_FAB_ID(val) (((val) >> 16) & 0xf) /* voodoo 2 only */ -#define INITEN_ENABLE_PCI_INTERRUPT(val) (((val) >> 20) & 1) /* voodoo 2 only */ -#define INITEN_PCI_INTERRUPT_TIMEOUT(val) (((val) >> 21) & 1) /* voodoo 2 only */ -#define INITEN_ENABLE_NAND_TREE_TEST(val) (((val) >> 22) & 1) /* voodoo 2 only */ -#define INITEN_ENABLE_SLI_ADDRESS_SNOOP(val) (((val) >> 23) & 1) /* voodoo 2 only */ -#define INITEN_SLI_SNOOP_ADDRESS(val) (((val) >> 24) & 0xff) /* voodoo 2 only */ - -#define FBZCP_CC_RGBSELECT(val) (((val) >> 0) & 3) -#define FBZCP_CC_ASELECT(val) (((val) >> 2) & 3) -#define FBZCP_CC_LOCALSELECT(val) (((val) >> 4) & 1) -#define FBZCP_CCA_LOCALSELECT(val) (((val) >> 5) & 3) -#define FBZCP_CC_LOCALSELECT_OVERRIDE(val) (((val) >> 7) & 1) -#define FBZCP_CC_ZERO_OTHER(val) (((val) >> 8) & 1) -#define FBZCP_CC_SUB_CLOCAL(val) (((val) >> 9) & 1) -#define FBZCP_CC_MSELECT(val) (((val) >> 10) & 7) -#define FBZCP_CC_REVERSE_BLEND(val) (((val) >> 13) & 1) -#define FBZCP_CC_ADD_ACLOCAL(val) (((val) >> 14) & 3) -#define FBZCP_CC_INVERT_OUTPUT(val) (((val) >> 16) & 1) -#define FBZCP_CCA_ZERO_OTHER(val) (((val) >> 17) & 1) -#define FBZCP_CCA_SUB_CLOCAL(val) (((val) >> 18) & 1) -#define FBZCP_CCA_MSELECT(val) (((val) >> 19) & 7) -#define FBZCP_CCA_REVERSE_BLEND(val) (((val) >> 22) & 1) -#define FBZCP_CCA_ADD_ACLOCAL(val) (((val) >> 23) & 3) -#define FBZCP_CCA_INVERT_OUTPUT(val) (((val) >> 25) & 1) -#define FBZCP_CCA_SUBPIXEL_ADJUST(val) (((val) >> 26) & 1) -#define FBZCP_TEXTURE_ENABLE(val) (((val) >> 27) & 1) -#define FBZCP_RGBZW_CLAMP(val) (((val) >> 28) & 1) /* voodoo 2 only */ -#define FBZCP_ANTI_ALIAS(val) (((val) >> 29) & 1) /* voodoo 2 only */ - -#define ALPHAMODE_ALPHATEST(val) (((val) >> 0) & 1) -#define ALPHAMODE_ALPHAFUNCTION(val) (((val) >> 1) & 7) -#define ALPHAMODE_ALPHABLEND(val) (((val) >> 4) & 1) -#define ALPHAMODE_ANTIALIAS(val) (((val) >> 5) & 1) -#define ALPHAMODE_SRCRGBBLEND(val) (((val) >> 8) & 15) -#define ALPHAMODE_DSTRGBBLEND(val) (((val) >> 12) & 15) -#define ALPHAMODE_SRCALPHABLEND(val) (((val) >> 16) & 15) -#define ALPHAMODE_DSTALPHABLEND(val) (((val) >> 20) & 15) -#define ALPHAMODE_ALPHAREF(val) (((val) >> 24) & 0xff) - -#define FOGMODE_ENABLE_FOG(val) (((val) >> 0) & 1) -#define FOGMODE_FOG_ADD(val) (((val) >> 1) & 1) -#define FOGMODE_FOG_MULT(val) (((val) >> 2) & 1) -#define FOGMODE_FOG_ZALPHA(val) (((val) >> 3) & 3) -#define FOGMODE_FOG_CONSTANT(val) (((val) >> 5) & 1) -#define FOGMODE_FOG_DITHER(val) (((val) >> 6) & 1) /* voodoo 2 only */ -#define FOGMODE_FOG_ZONES(val) (((val) >> 7) & 1) /* voodoo 2 only */ - -#define FBZMODE_ENABLE_CLIPPING(val) (((val) >> 0) & 1) -#define FBZMODE_ENABLE_CHROMAKEY(val) (((val) >> 1) & 1) -#define FBZMODE_ENABLE_STIPPLE(val) (((val) >> 2) & 1) -#define FBZMODE_WBUFFER_SELECT(val) (((val) >> 3) & 1) -#define FBZMODE_ENABLE_DEPTHBUF(val) (((val) >> 4) & 1) -#define FBZMODE_DEPTH_FUNCTION(val) (((val) >> 5) & 7) -#define FBZMODE_ENABLE_DITHERING(val) (((val) >> 8) & 1) -#define FBZMODE_RGB_BUFFER_MASK(val) (((val) >> 9) & 1) -#define FBZMODE_AUX_BUFFER_MASK(val) (((val) >> 10) & 1) -#define FBZMODE_DITHER_TYPE(val) (((val) >> 11) & 1) -#define FBZMODE_STIPPLE_PATTERN(val) (((val) >> 12) & 1) -#define FBZMODE_ENABLE_ALPHA_MASK(val) (((val) >> 13) & 1) -#define FBZMODE_DRAW_BUFFER(val) (((val) >> 14) & 3) -#define FBZMODE_ENABLE_DEPTH_BIAS(val) (((val) >> 16) & 1) -#define FBZMODE_Y_ORIGIN(val) (((val) >> 17) & 1) -#define FBZMODE_ENABLE_ALPHA_PLANES(val) (((val) >> 18) & 1) -#define FBZMODE_ALPHA_DITHER_SUBTRACT(val) (((val) >> 19) & 1) -#define FBZMODE_DEPTH_SOURCE_COMPARE(val) (((val) >> 20) & 1) -#define FBZMODE_DEPTH_FLOAT_SELECT(val) (((val) >> 21) & 1) /* voodoo 2 only */ - -#define LFBMODE_WRITE_FORMAT(val) (((val) >> 0) & 0xf) -#define LFBMODE_WRITE_BUFFER_SELECT(val) (((val) >> 4) & 3) -#define LFBMODE_READ_BUFFER_SELECT(val) (((val) >> 6) & 3) -#define LFBMODE_ENABLE_PIXEL_PIPELINE(val) (((val) >> 8) & 1) -#define LFBMODE_RGBA_LANES(val) (((val) >> 9) & 3) -#define LFBMODE_WORD_SWAP_WRITES(val) (((val) >> 11) & 1) -#define LFBMODE_BYTE_SWIZZLE_WRITES(val) (((val) >> 12) & 1) -#define LFBMODE_Y_ORIGIN(val) (((val) >> 13) & 1) -#define LFBMODE_WRITE_W_SELECT(val) (((val) >> 14) & 1) -#define LFBMODE_WORD_SWAP_READS(val) (((val) >> 15) & 1) -#define LFBMODE_BYTE_SWIZZLE_READS(val) (((val) >> 16) & 1) - -#define CHROMARANGE_BLUE_EXCLUSIVE(val) (((val) >> 24) & 1) -#define CHROMARANGE_GREEN_EXCLUSIVE(val) (((val) >> 25) & 1) -#define CHROMARANGE_RED_EXCLUSIVE(val) (((val) >> 26) & 1) -#define CHROMARANGE_UNION_MODE(val) (((val) >> 27) & 1) -#define CHROMARANGE_ENABLE(val) (((val) >> 28) & 1) - -#define FBIINIT0_VGA_PASSTHRU(val) (((val) >> 0) & 1) -#define FBIINIT0_GRAPHICS_RESET(val) (((val) >> 1) & 1) -#define FBIINIT0_FIFO_RESET(val) (((val) >> 2) & 1) -#define FBIINIT0_SWIZZLE_REG_WRITES(val) (((val) >> 3) & 1) -#define FBIINIT0_STALL_PCIE_FOR_HWM(val) (((val) >> 4) & 1) -#define FBIINIT0_PCI_FIFO_LWM(val) (((val) >> 6) & 0x1f) -#define FBIINIT0_LFB_TO_MEMORY_FIFO(val) (((val) >> 11) & 1) -#define FBIINIT0_TEXMEM_TO_MEMORY_FIFO(val) (((val) >> 12) & 1) -#define FBIINIT0_ENABLE_MEMORY_FIFO(val) (((val) >> 13) & 1) -#define FBIINIT0_MEMORY_FIFO_HWM(val) (((val) >> 14) & 0x7ff) -#define FBIINIT0_MEMORY_FIFO_BURST(val) (((val) >> 25) & 0x3f) - -#define FBIINIT1_PCI_DEV_FUNCTION(val) (((val) >> 0) & 1) -#define FBIINIT1_PCI_WRITE_WAIT_STATES(val) (((val) >> 1) & 1) -#define FBIINIT1_MULTI_SST1(val) (((val) >> 2) & 1) /* not on voodoo 2 */ -#define FBIINIT1_ENABLE_LFB(val) (((val) >> 3) & 1) -#define FBIINIT1_X_VIDEO_TILES(val) (((val) >> 4) & 0xf) -#define FBIINIT1_VIDEO_TIMING_RESET(val) (((val) >> 8) & 1) -#define FBIINIT1_SOFTWARE_OVERRIDE(val) (((val) >> 9) & 1) -#define FBIINIT1_SOFTWARE_HSYNC(val) (((val) >> 10) & 1) -#define FBIINIT1_SOFTWARE_VSYNC(val) (((val) >> 11) & 1) -#define FBIINIT1_SOFTWARE_BLANK(val) (((val) >> 12) & 1) -#define FBIINIT1_DRIVE_VIDEO_TIMING(val) (((val) >> 13) & 1) -#define FBIINIT1_DRIVE_VIDEO_BLANK(val) (((val) >> 14) & 1) -#define FBIINIT1_DRIVE_VIDEO_SYNC(val) (((val) >> 15) & 1) -#define FBIINIT1_DRIVE_VIDEO_DCLK(val) (((val) >> 16) & 1) -#define FBIINIT1_VIDEO_TIMING_VCLK(val) (((val) >> 17) & 1) -#define FBIINIT1_VIDEO_CLK_2X_DELAY(val) (((val) >> 18) & 3) -#define FBIINIT1_VIDEO_TIMING_SOURCE(val) (((val) >> 20) & 3) -#define FBIINIT1_ENABLE_24BPP_OUTPUT(val) (((val) >> 22) & 1) -#define FBIINIT1_ENABLE_SLI(val) (((val) >> 23) & 1) -#define FBIINIT1_X_VIDEO_TILES_BIT5(val) (((val) >> 24) & 1) /* voodoo 2 only */ -#define FBIINIT1_ENABLE_EDGE_FILTER(val) (((val) >> 25) & 1) -#define FBIINIT1_INVERT_VID_CLK_2X(val) (((val) >> 26) & 1) -#define FBIINIT1_VID_CLK_2X_SEL_DELAY(val) (((val) >> 27) & 3) -#define FBIINIT1_VID_CLK_DELAY(val) (((val) >> 29) & 3) -#define FBIINIT1_DISABLE_FAST_READAHEAD(val) (((val) >> 31) & 1) - -#define FBIINIT2_DISABLE_DITHER_SUB(val) (((val) >> 0) & 1) -#define FBIINIT2_DRAM_BANKING(val) (((val) >> 1) & 1) -#define FBIINIT2_ENABLE_TRIPLE_BUF(val) (((val) >> 4) & 1) -#define FBIINIT2_ENABLE_FAST_RAS_READ(val) (((val) >> 5) & 1) -#define FBIINIT2_ENABLE_GEN_DRAM_OE(val) (((val) >> 6) & 1) -#define FBIINIT2_ENABLE_FAST_READWRITE(val) (((val) >> 7) & 1) -#define FBIINIT2_ENABLE_PASSTHRU_DITHER(val) (((val) >> 8) & 1) -#define FBIINIT2_SWAP_BUFFER_ALGORITHM(val) (((val) >> 9) & 3) -#define FBIINIT2_VIDEO_BUFFER_OFFSET(val) (((val) >> 11) & 0x1ff) -#define FBIINIT2_ENABLE_DRAM_BANKING(val) (((val) >> 20) & 1) -#define FBIINIT2_ENABLE_DRAM_READ_FIFO(val) (((val) >> 21) & 1) -#define FBIINIT2_ENABLE_DRAM_REFRESH(val) (((val) >> 22) & 1) -#define FBIINIT2_REFRESH_LOAD_VALUE(val) (((val) >> 23) & 0x1ff) - -#define FBIINIT3_TRI_REGISTER_REMAP(val) (((val) >> 0) & 1) -#define FBIINIT3_VIDEO_FIFO_THRESH(val) (((val) >> 1) & 0x1f) -#define FBIINIT3_DISABLE_TMUS(val) (((val) >> 6) & 1) -#define FBIINIT3_FBI_MEMORY_TYPE(val) (((val) >> 8) & 7) -#define FBIINIT3_VGA_PASS_RESET_VAL(val) (((val) >> 11) & 1) -#define FBIINIT3_HARDCODE_PCI_BASE(val) (((val) >> 12) & 1) -#define FBIINIT3_FBI2TREX_DELAY(val) (((val) >> 13) & 0xf) -#define FBIINIT3_TREX2FBI_DELAY(val) (((val) >> 17) & 0x1f) -#define FBIINIT3_YORIGIN_SUBTRACT(val) (((val) >> 22) & 0x3ff) - -#define FBIINIT4_PCI_READ_WAITS(val) (((val) >> 0) & 1) -#define FBIINIT4_ENABLE_LFB_READAHEAD(val) (((val) >> 1) & 1) -#define FBIINIT4_MEMORY_FIFO_LWM(val) (((val) >> 2) & 0x3f) -#define FBIINIT4_MEMORY_FIFO_START_ROW(val) (((val) >> 8) & 0x3ff) -#define FBIINIT4_MEMORY_FIFO_STOP_ROW(val) (((val) >> 18) & 0x3ff) -#define FBIINIT4_VIDEO_CLOCKING_DELAY(val) (((val) >> 29) & 7) /* voodoo 2 only */ - -#define FBIINIT5_DISABLE_PCI_STOP(val) (((val) >> 0) & 1) /* voodoo 2 only */ -#define FBIINIT5_PCI_SLAVE_SPEED(val) (((val) >> 1) & 1) /* voodoo 2 only */ -#define FBIINIT5_DAC_DATA_OUTPUT_WIDTH(val) (((val) >> 2) & 1) /* voodoo 2 only */ -#define FBIINIT5_DAC_DATA_17_OUTPUT(val) (((val) >> 3) & 1) /* voodoo 2 only */ -#define FBIINIT5_DAC_DATA_18_OUTPUT(val) (((val) >> 4) & 1) /* voodoo 2 only */ -#define FBIINIT5_GENERIC_STRAPPING(val) (((val) >> 5) & 0xf) /* voodoo 2 only */ -#define FBIINIT5_BUFFER_ALLOCATION(val) (((val) >> 9) & 3) /* voodoo 2 only */ -#define FBIINIT5_DRIVE_VID_CLK_SLAVE(val) (((val) >> 11) & 1) /* voodoo 2 only */ -#define FBIINIT5_DRIVE_DAC_DATA_16(val) (((val) >> 12) & 1) /* voodoo 2 only */ -#define FBIINIT5_VCLK_INPUT_SELECT(val) (((val) >> 13) & 1) /* voodoo 2 only */ -#define FBIINIT5_MULTI_CVG_DETECT(val) (((val) >> 14) & 1) /* voodoo 2 only */ -#define FBIINIT5_SYNC_RETRACE_READS(val) (((val) >> 15) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_RHBORDER_COLOR(val) (((val) >> 16) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_LHBORDER_COLOR(val) (((val) >> 17) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_BVBORDER_COLOR(val) (((val) >> 18) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_TVBORDER_COLOR(val) (((val) >> 19) & 1) /* voodoo 2 only */ -#define FBIINIT5_DOUBLE_HORIZ(val) (((val) >> 20) & 1) /* voodoo 2 only */ -#define FBIINIT5_DOUBLE_VERT(val) (((val) >> 21) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_16BIT_GAMMA(val) (((val) >> 22) & 1) /* voodoo 2 only */ -#define FBIINIT5_INVERT_DAC_HSYNC(val) (((val) >> 23) & 1) /* voodoo 2 only */ -#define FBIINIT5_INVERT_DAC_VSYNC(val) (((val) >> 24) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_24BIT_DACDATA(val) (((val) >> 25) & 1) /* voodoo 2 only */ -#define FBIINIT5_ENABLE_INTERLACING(val) (((val) >> 26) & 1) /* voodoo 2 only */ -#define FBIINIT5_DAC_DATA_18_CONTROL(val) (((val) >> 27) & 1) /* voodoo 2 only */ -#define FBIINIT5_RASTERIZER_UNIT_MODE(val) (((val) >> 30) & 3) /* voodoo 2 only */ - -#define FBIINIT6_WINDOW_ACTIVE_COUNTER(val) (((val) >> 0) & 7) /* voodoo 2 only */ -#define FBIINIT6_WINDOW_DRAG_COUNTER(val) (((val) >> 3) & 0x1f) /* voodoo 2 only */ -#define FBIINIT6_SLI_SYNC_MASTER(val) (((val) >> 8) & 1) /* voodoo 2 only */ -#define FBIINIT6_DAC_DATA_22_OUTPUT(val) (((val) >> 9) & 3) /* voodoo 2 only */ -#define FBIINIT6_DAC_DATA_23_OUTPUT(val) (((val) >> 11) & 3) /* voodoo 2 only */ -#define FBIINIT6_SLI_SYNCIN_OUTPUT(val) (((val) >> 13) & 3) /* voodoo 2 only */ -#define FBIINIT6_SLI_SYNCOUT_OUTPUT(val) (((val) >> 15) & 3) /* voodoo 2 only */ -#define FBIINIT6_DAC_RD_OUTPUT(val) (((val) >> 17) & 3) /* voodoo 2 only */ -#define FBIINIT6_DAC_WR_OUTPUT(val) (((val) >> 19) & 3) /* voodoo 2 only */ -#define FBIINIT6_PCI_FIFO_LWM_RDY(val) (((val) >> 21) & 0x7f) /* voodoo 2 only */ -#define FBIINIT6_VGA_PASS_N_OUTPUT(val) (((val) >> 28) & 3) /* voodoo 2 only */ -#define FBIINIT6_X_VIDEO_TILES_BIT0(val) (((val) >> 30) & 1) /* voodoo 2 only */ - -#define FBIINIT7_GENERIC_STRAPPING(val) (((val) >> 0) & 0xff) /* voodoo 2 only */ -#define FBIINIT7_CMDFIFO_ENABLE(val) (((val) >> 8) & 1) /* voodoo 2 only */ -#define FBIINIT7_CMDFIFO_MEMORY_STORE(val) (((val) >> 9) & 1) /* voodoo 2 only */ -#define FBIINIT7_DISABLE_CMDFIFO_HOLES(val) (((val) >> 10) & 1) /* voodoo 2 only */ -#define FBIINIT7_CMDFIFO_READ_THRESH(val) (((val) >> 11) & 0x1f) /* voodoo 2 only */ -#define FBIINIT7_SYNC_CMDFIFO_WRITES(val) (((val) >> 16) & 1) /* voodoo 2 only */ -#define FBIINIT7_SYNC_CMDFIFO_READS(val) (((val) >> 17) & 1) /* voodoo 2 only */ -#define FBIINIT7_RESET_PCI_PACKER(val) (((val) >> 18) & 1) /* voodoo 2 only */ -#define FBIINIT7_ENABLE_CHROMA_STUFF(val) (((val) >> 19) & 1) /* voodoo 2 only */ -#define FBIINIT7_CMDFIFO_PCI_TIMEOUT(val) (((val) >> 20) & 0x7f) /* voodoo 2 only */ -#define FBIINIT7_ENABLE_TEXTURE_BURST(val) (((val) >> 27) & 1) /* voodoo 2 only */ - -#define TEXMODE_ENABLE_PERSPECTIVE(val) (((val) >> 0) & 1) -#define TEXMODE_MINIFICATION_FILTER(val) (((val) >> 1) & 1) -#define TEXMODE_MAGNIFICATION_FILTER(val) (((val) >> 2) & 1) -#define TEXMODE_CLAMP_NEG_W(val) (((val) >> 3) & 1) -#define TEXMODE_ENABLE_LOD_DITHER(val) (((val) >> 4) & 1) -#define TEXMODE_NCC_TABLE_SELECT(val) (((val) >> 5) & 1) -#define TEXMODE_CLAMP_S(val) (((val) >> 6) & 1) -#define TEXMODE_CLAMP_T(val) (((val) >> 7) & 1) -#define TEXMODE_FORMAT(val) (((val) >> 8) & 0xf) -#define TEXMODE_TC_ZERO_OTHER(val) (((val) >> 12) & 1) -#define TEXMODE_TC_SUB_CLOCAL(val) (((val) >> 13) & 1) -#define TEXMODE_TC_MSELECT(val) (((val) >> 14) & 7) -#define TEXMODE_TC_REVERSE_BLEND(val) (((val) >> 17) & 1) -#define TEXMODE_TC_ADD_ACLOCAL(val) (((val) >> 18) & 3) -#define TEXMODE_TC_INVERT_OUTPUT(val) (((val) >> 20) & 1) -#define TEXMODE_TCA_ZERO_OTHER(val) (((val) >> 21) & 1) -#define TEXMODE_TCA_SUB_CLOCAL(val) (((val) >> 22) & 1) -#define TEXMODE_TCA_MSELECT(val) (((val) >> 23) & 7) -#define TEXMODE_TCA_REVERSE_BLEND(val) (((val) >> 26) & 1) -#define TEXMODE_TCA_ADD_ACLOCAL(val) (((val) >> 27) & 3) -#define TEXMODE_TCA_INVERT_OUTPUT(val) (((val) >> 29) & 1) -#define TEXMODE_TRILINEAR(val) (((val) >> 30) & 1) -#define TEXMODE_SEQ_8_DOWNLD(val) (((val) >> 31) & 1) - -#define TEXLOD_LODMIN(val) (((val) >> 0) & 0x3f) -#define TEXLOD_LODMAX(val) (((val) >> 6) & 0x3f) -#define TEXLOD_LODBIAS(val) (((val) >> 12) & 0x3f) -#define TEXLOD_LOD_ODD(val) (((val) >> 18) & 1) -#define TEXLOD_LOD_TSPLIT(val) (((val) >> 19) & 1) -#define TEXLOD_LOD_S_IS_WIDER(val) (((val) >> 20) & 1) -#define TEXLOD_LOD_ASPECT(val) (((val) >> 21) & 3) -#define TEXLOD_LOD_ZEROFRAC(val) (((val) >> 23) & 1) -#define TEXLOD_TMULTIBASEADDR(val) (((val) >> 24) & 1) -#define TEXLOD_TDATA_SWIZZLE(val) (((val) >> 25) & 1) -#define TEXLOD_TDATA_SWAP(val) (((val) >> 26) & 1) -#define TEXLOD_TDIRECT_WRITE(val) (((val) >> 27) & 1) /* Voodoo 2 only */ - -#define TEXDETAIL_DETAIL_MAX(val) (((val) >> 0) & 0xff) -#define TEXDETAIL_DETAIL_BIAS(val) (((val) >> 8) & 0x3f) -#define TEXDETAIL_DETAIL_SCALE(val) (((val) >> 14) & 7) -#define TEXDETAIL_RGB_MIN_FILTER(val) (((val) >> 17) & 1) /* Voodoo 2 only */ -#define TEXDETAIL_RGB_MAG_FILTER(val) (((val) >> 18) & 1) /* Voodoo 2 only */ -#define TEXDETAIL_ALPHA_MIN_FILTER(val) (((val) >> 19) & 1) /* Voodoo 2 only */ -#define TEXDETAIL_ALPHA_MAG_FILTER(val) (((val) >> 20) & 1) /* Voodoo 2 only */ -#define TEXDETAIL_SEPARATE_RGBA_FILTER(val) (((val) >> 21) & 1) /* Voodoo 2 only */ - -#define TREXINIT_SEND_TMU_CONFIG(val) (((val) >> 18) & 1) - - - -struct rgba -{ -#ifdef LSB_FIRST - uint8_t b, g, r, a; -#else - uint8_t a, r, g, b; -#endif -}; - - -union voodoo_reg -{ - int32_t i; - uint32_t u; - float f; - rgba rgb; -}; - - - - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ -/* enumeration specifying which model of Voodoo we are emulating */ -enum -{ - TYPE_VOODOO_1, - TYPE_VOODOO_2, - TYPE_VOODOO_BANSHEE, - TYPE_VOODOO_3 -}; - -#define STD_VOODOO_1_CLOCK 50000000 -#define STD_VOODOO_2_CLOCK 90000000 -#define STD_VOODOO_BANSHEE_CLOCK 90000000 -#define STD_VOODOO_3_CLOCK 132000000 - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* ----- device interface ----- */ - -class voodoo_device : public device_t +// save_proxy is a helper class to make hierarchical state saving more manageable; +class save_proxy { public: - ~voodoo_device(); + // constructor + save_proxy(device_t &device) : + m_device(device) + { + } - void set_fbmem(int value) { m_fbmem = value; } - void set_tmumem(int value1, int value2) { m_tmumem0 = value1; m_tmumem1 = value2; } - template void set_screen_tag(T &&tag) { m_screen_finder.set_tag(std::forward(tag)); } - template void set_cpu_tag(T &&tag) { m_cpu_finder.set_tag(std::forward(tag)); } - auto vblank_callback() { return m_vblank.bind(); } - auto stall_callback() { return m_stall.bind(); } - auto pciint_callback() { return m_pciint.bind(); } + // save an item; append the current prefix and pass through + template + void save_item(T &&item, char const *name) + { + std::string fullname = m_prefix; + fullname += name; + m_device.save_item(std::forward(item), fullname.c_str()); + } - void set_screen(screen_device &screen) { assert(!m_screen); m_screen = &screen; } - void set_cpu(cpu_device &cpu) { assert(!m_cpu); m_cpu = &cpu; } + // save a pointer item; append the current prefix and pass through + template + void save_pointer(T &&item, char const *name, u32 count) + { + std::string fullname = m_prefix; + fullname += name; + m_device.save_pointer(std::forward(item), fullname.c_str(), count); + } - u32 voodoo_r(offs_t offset); - void voodoo_w(offs_t offset, u32 data, u32 mem_mask = ~0); + // save a class; update the prefix then call the register_save method on the class + template + void save_class(T &item, char const *name) + { + std::string orig = m_prefix; + m_prefix += name; + m_prefix += "/"; + item.register_save(*this); + m_prefix = orig; + } - uint8_t m_fbmem; - uint8_t m_tmumem0; - uint8_t m_tmumem1; - devcb_write_line m_vblank; - devcb_write_line m_stall; - // This is for internally generated PCI interrupts in Voodoo3 - devcb_write_line m_pciint; +private: + // internal state + device_t &m_device; + std::string m_prefix; +}; - TIMER_CALLBACK_MEMBER( vblank_off_callback ); - TIMER_CALLBACK_MEMBER( stall_cpu_callback ); - TIMER_CALLBACK_MEMBER( vblank_callback ); - void voodoo_postload(); +// ======================> shared_tables - int voodoo_update(bitmap_rgb32 &bitmap, const rectangle &cliprect); - int voodoo_get_type(); - int voodoo_is_stalled(); - void voodoo_set_init_enable(uint32_t newval); +// shared_tables are global tables that are shared between different components +struct shared_tables +{ + // construction + shared_tables(); + + // texel lookups + rgb_t *texel[16]; // 16 texture formats + + // 8-bit lookups + rgb_t rgb332[256]; // RGB 3-3-2 lookup table + rgb_t alpha8[256]; // alpha 8-bit lookup table + rgb_t int8[256]; // intensity 8-bit lookup table + rgb_t ai44[256]; // alpha, intensity 4-4 lookup table + + // 16-bit lookups + rgb_t rgb565[65536]; // RGB 5-6-5 lookup table + rgb_t argb1555[65536]; // ARGB 1-5-5-5 lookup table + rgb_t argb4444[65536]; // ARGB 4-4-4-4 lookup table +}; + + +// ======================> tmu_state + +// tmu_state holds TMU-specific register and palette state +class tmu_state +{ +public: + // construction + tmu_state(); + + // initialization + void init(int index, shared_tables const &share, u8 *ram, u32 size); + + // configuration + void set_baseaddr_mask_shift(u32 mask, u8 shift) { m_basemask = mask; m_baseshift = shift; } + + // state saving + void register_save(save_proxy &save); + void post_load(); + + // simple getters + voodoo_regs ®s() { return m_reg; } + bool dirty() const { return m_regdirty; } + + // simple setters + void mark_dirty() { m_regdirty = true; } + + // write to the NCC/palette registers + void ncc_w(offs_t offset, u32 data); + + // prepare a texture for the renderer + rasterizer_texture &prepare_texture(voodoo_renderer &renderer); + +private: + // internal state + int m_index; // index of ourself + u8 *m_ram; // pointer to our RAM + u32 m_mask; // mask to apply to pointers + u32 m_basemask; // mask to apply to the texBaseAddr + u8 m_baseshift; // shift to apply to the texBaseAddr + + // register state + voodoo_regs m_reg; // TMU registers + bool m_regdirty; // true if the LOD/mode/base registers have changed + + // lookups + rgb_t const * const *m_texel_lookup; // texel lookups for each format + + // palettes + bool m_palette_dirty[4]; // true if palette (0-1) or NCC (2-3) is dirty + rgb_t m_palette[2][256]; // 2 versions of the palette +}; + + +// ======================> memory_fifo + +// memory_fifo is a simple memory access FIFO that is used on the frontend +// PCI bus (64 entries) or within the framebuffer (up to 64k) +class memory_fifo +{ +public: + // FIFO flags, added to offset + static constexpr offs_t FLAGS_MASK = 0xf0000000; + static constexpr offs_t TYPE_MASK = 0xc0000000; + static constexpr offs_t TYPE_REGISTER = 0x00000000; + static constexpr offs_t TYPE_LFB = 0x40000000; + static constexpr offs_t TYPE_TEXTURE = 0x80000000; + static constexpr offs_t NO_16_31 = 0x20000000; + static constexpr offs_t NO_0_15 = 0x10000000; + + // construction + memory_fifo(); + + // configuration + void configure(u32 *base, u32 size); + + // state saving + void register_save(save_proxy &save); + + // basic queries + bool configured() const { return (m_size != 0); } + u32 peek() const { return m_base[m_out]; } + bool empty() const { return (m_in == m_out); } + bool full() const { return ((m_in + 1) == m_out) || (m_in == (m_size - 1) && m_out == 0); } + s32 items() const { s32 result = m_in - m_out; if (result < 0) result += m_size; return result; } + s32 space() const { return m_size - 1 - items(); } + + // reset + void reset() { m_in = m_out = 0; } + + // add/remove items + void add(u32 data); + u32 remove(); + +private: + // internal state + u32 *m_base; // base of the FIFO + s32 m_size; // size of the FIFO + s32 m_in; // input pointer + s32 m_out; // output pointer +}; + + +// ======================> debug_stats + +// debug_stats are enabled via DEBUG_STATS and displayed via the backslash key; +// these are independent of the real on-chip stats kept in thread_stats_block +class debug_stats +{ +public: + // construction + debug_stats(); + + // add in states from the emulation + void add_emulation_stats(thread_stats_block const &block); + + // reset the stats + void reset(); + + // simple getters + bool displayed() const { return m_display; } + char const *string() const { return m_string.c_str(); } + + // compute the string to display + void update_string(rectangle const &visarea, u32 swap_history); + + // based on the current key state, update and return whether stats should be shown + bool update_display_state(bool key_pressed); + + // public access to the statistics that are hand-updated + s32 m_swaps; // total swaps + s32 m_stalls; // total stalls + s32 m_triangles; // total triangles + s32 m_lfb_writes; // LFB writes + s32 m_lfb_reads; // LFB reads + s32 m_reg_writes; // register writes + s32 m_reg_reads; // register reads + s32 m_tex_writes; // texture writes + s32 m_texture_mode[16]; // 16 different texture modes + +private: + // stats that are updated from emulation stats + s32 m_pixels_in; // total pixels in + s32 m_pixels_out; // total pixels out + s32 m_chroma_fail; // total chroma fail + s32 m_zfunc_fail; // total z func fail + s32 m_afunc_fail; // total a func fail + s32 m_clipped; // total clipped + s32 m_stippled; // total stippled + + // internal state + bool m_lastkey; // last key state + bool m_display; // display stats? + std::string m_string; // string +}; + + +// ======================> static_register_table_entry + +// static_register_table_entry represents a read/write handler pair for Voodoo +// registers, along with a valid mask, access flags, and a string name +template +struct static_register_table_entry +{ + static constexpr u32 make_mask(int maskbits) + { + if (maskbits == 0) + return 0; + if (maskbits == 32) + return 0xffffffff; + return (1 << maskbits) - 1; + } + + using read_handler = u32 (BaseType::*)(u32 chipmask, u32 regnum); + using write_handler = u32 (BaseType::*)(u32 chipmask, u32 regnum, u32 data); + + u32 m_mask; // mask to apply to written data + u32 m_chipmask_flags; // valid chips, plus flags + char const *m_name; // string name + write_handler m_write; // write handler + read_handler m_read; // read handler +}; + + +// ======================> register_table_entry + +// register_table_entry is a live version of static_register_table_entry with +// bound delegates in place of the member function pointers +class register_table_entry +{ +public: + // internal delegates + using read_handler = delegate; + using write_handler = delegate; + + // flags for the chipmask + static constexpr u32 CHIPMASK_NA = 0x0000; + static constexpr u32 CHIPMASK_FBI = 0x0001; + static constexpr u32 CHIPMASK_TREX = 0x0006; + static constexpr u32 CHIPMASK_FBI_TREX = 0x0007; + + // flags for the sync state + static constexpr u32 SYNC_NA = 0x0000; + static constexpr u32 SYNC_NOSYNC = 0x0000; + static constexpr u32 SYNC_SYNC = 0x0100; + + // flags for the FIFO state + static constexpr u32 FIFO_NA = 0x0000; + static constexpr u32 FIFO_NOFIFO = 0x0000; + static constexpr u32 FIFO_FIFO = 0x0200; + + // simple getters + char const *name() const { return m_name; } + bool is_sync() const { return ((m_chipmask_flags & SYNC_SYNC) != 0); } + bool is_fifo() const { return ((m_chipmask_flags & FIFO_FIFO) != 0); } + + // read/write helpers + u32 read(voodoo_1_device &device, u32 chipmask, u32 regnum) const; + u32 write(voodoo_1_device &device, u32 chipmask, u32 regnum, u32 data) const; + + // unpack from a static entry + template + void unpack(static_register_table_entry const &source, BaseType &device) + { + m_mask = source.m_mask; + m_chipmask_flags = source.m_chipmask_flags; + m_name = source.m_name; + m_write = write_handler(source.m_write, &device); + m_read = read_handler(source.m_read, &device); + } + +private: + // internal state + u32 m_mask; // mask to apply to written data + u32 m_chipmask_flags; // valid chips, plus flags + char const *m_name; // string name + write_handler m_write; // write handler + read_handler m_read; // read handler +}; + +} + + +//************************************************************************** +// GENERIC VOODOO DEVICE +//************************************************************************** + +// ======================> generic_voodoo_device + +// generic_voodoo_device is a base class that can be used to represent any of the +// specific voodoo devices below +class generic_voodoo_device : public device_t, public device_video_interface +{ +public: + // configuration + void set_fbmem(int value) { m_fbmem_in_mb = value; } + void set_tmumem(int value1, int value2) { m_tmumem0_in_mb = value1; m_tmumem1_in_mb = value2; } + void set_status_cycles(u32 value) { m_status_cycles = value; } + template void set_cpu(T &&tag) { m_cpu.set_tag(std::forward(tag)); } + auto vblank_callback() { return m_vblank_cb.bind(); } + auto stall_callback() { return m_stall_cb.bind(); } + auto pciint_callback() { return m_pciint_cb.bind(); } + + // getters + voodoo::voodoo_model model() const { return m_model; } + + // address map and read/write helpers + virtual void core_map(address_map &map) = 0; + virtual u32 read(offs_t offset, u32 mem_mask = ~0) = 0; + virtual void write(offs_t offset, u32 data, u32 mem_mask = ~0) = 0; + + // external control + virtual void set_init_enable(u32 newval) = 0; + + // video update + virtual int update(bitmap_rgb32 &bitmap, const rectangle &cliprect) = 0; protected: - voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt); + // internal construction + generic_voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model); // device-level overrides - virtual void device_resolve_objects() override; + virtual void device_start() override; + + // configuration + const voodoo::voodoo_model m_model; // which voodoo model + u8 m_fbmem_in_mb; // framebuffer memory, in MB + u8 m_tmumem0_in_mb; // TMU0 memory, in MB + u8 m_tmumem1_in_mb; // TMU1 memory, in MB + u32 m_status_cycles; // number of cycles to eat on status reads (optimization) + required_device m_cpu; // the CPU we interact with + devcb_write_line m_vblank_cb; // VBLANK callback + devcb_write_line m_stall_cb; // stalling callback + devcb_write_line m_pciint_cb; // PCI interrupt callback +}; + + +//************************************************************************** +// VOODOO 1 DEVICE +//************************************************************************** + +DECLARE_DEVICE_TYPE(VOODOO_1, voodoo_1_device) + +// ======================> voodoo_1_device + +// voodoo_1_device represents the original generation of 3dfx Voodoo Graphics devices; +// these devices have independent framebuffer and texture memory, and can be flexibly +// configured with 1 or 2 TMUs +class voodoo_1_device : public generic_voodoo_device +{ + friend class voodoo::register_table_entry; + + // enumeration describing reasons we might be stalled + enum stall_state : u8 + { + NOT_STALLED = 0, + STALLED_UNTIL_FIFO_LWM, + STALLED_UNTIL_FIFO_EMPTY + }; + + // flags for LFB writes + static constexpr u8 LFB_RGB_PRESENT_0 = 0x01; + static constexpr u8 LFB_ALPHA_PRESENT_0 = 0x02; + static constexpr u8 LFB_DEPTH_PRESENT_0 = 0x04; + static constexpr u8 LFB_DEPTH_PRESENT_MSW_0 = 0x08; + static constexpr u8 LFB_PIXEL0_MASK = 0x0f; + + static constexpr u8 LFB_RGB_PRESENT_1 = 0x10; + static constexpr u8 LFB_ALPHA_PRESENT_1 = 0x20; + static constexpr u8 LFB_DEPTH_PRESENT_1 = 0x40; + static constexpr u8 LFB_PIXEL1_MASK = 0x70; + +protected: + // number of clocks to set up a triangle (just a guess) + static constexpr u32 TRIANGLE_SETUP_CLOCKS = 100; + + // internal construction + voodoo_1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model); + +public: + // nominal clock values + static constexpr u32 NOMINAL_CLOCK = 50'000'000; + + // construction + voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + voodoo_1_device(mconfig, VOODOO_1, tag, owner, clock, voodoo::voodoo_model::VOODOO_1) { } + + // destruction + virtual ~voodoo_1_device(); + + // address map and read/write helpers + virtual void core_map(address_map &map) override; + virtual u32 read(offs_t offset, u32 mem_mask = ~0) override; + virtual void write(offs_t offset, u32 data, u32 mem_mask = ~0) override; + + // external control + virtual void set_init_enable(u32 newval) override; + + // video update + virtual int update(bitmap_rgb32 &bitmap, const rectangle &cliprect) override; + +protected: + // device-level overrides virtual void device_start() override; virtual void device_stop() override; virtual void device_reset() override; + virtual void device_post_load() override; - struct tmu_shared_state; + // system management + virtual void soft_reset(); + virtual void register_save(voodoo::save_proxy &save, u32 total_allocation); - struct voodoo_stats - { - voodoo_stats() - { - std::fill(std::begin(texture_mode), std::end(texture_mode), 0); - buffer[0] = 0; - } + // buffer accessors + virtual u16 *draw_buffer_indirect(int index); + virtual u16 *lfb_buffer_indirect(int index); + u16 *draw_buffer(int index) const { return (u16 *)(m_fbram + m_rgboffs[index]); } + u16 *front_buffer() const { return draw_buffer(m_frontbuf); } + u16 *back_buffer() const { return draw_buffer(m_backbuf); } + u16 *aux_buffer() const { return (m_auxoffs != ~0) ? (u16 *)(m_fbram + m_auxoffs) : nullptr; } + u16 *ram_end() const { return (u16 *)(m_fbram + m_fbmask + 1); } - uint8_t lastkey = 0; // last key state - uint8_t display = 0; // display stats? - int32_t swaps = 0; // total swaps - int32_t stalls = 0; // total stalls - int32_t total_triangles = 0; // total triangles - int32_t total_pixels_in = 0; // total pixels in - int32_t total_pixels_out = 0; // total pixels out - int32_t total_chroma_fail = 0; // total chroma fail - int32_t total_zfunc_fail = 0; // total z func fail - int32_t total_afunc_fail = 0; // total a func fail - int32_t total_clipped = 0; // total clipped - int32_t total_stippled = 0; // total stippled - int32_t lfb_writes = 0; // LFB writes - int32_t lfb_reads = 0; // LFB reads - int32_t reg_writes = 0; // register writes - int32_t reg_reads = 0; // register reads - int32_t tex_writes = 0; // texture writes - int32_t texture_mode[16]; // 16 different texture modes - uint8_t render_override = 0; // render override - char buffer[1024]; // string - }; + // read/write and FIFO helpers + void prepare_for_read(); + bool prepare_for_write(); + void recompute_fbmem_fifo(); + void add_to_fifo(u32 offset, u32 data, u32 mem_mask); + void flush_fifos(attotime current_time); + virtual u32 execute_fifos(); + // mapped reads + u32 map_register_r(offs_t offset); + u32 map_lfb_r(offs_t offset); - /* note that this structure is an even 64 bytes long */ - struct stats_block - { - int32_t pixels_in = 0; // pixels in statistic - int32_t pixels_out = 0; // pixels out statistic - int32_t chroma_fail = 0; // chroma test fail statistic - int32_t zfunc_fail = 0; // z function test fail statistic - int32_t afunc_fail = 0; // alpha function test fail statistic - int32_t clip_fail = 0; // clipping fail statistic - int32_t stipple_count = 0; // stipple statistic - int32_t filler[64/4 - 7]; // pad this structure to 64 bytes - }; + // mapped writes + void map_register_w(offs_t offset, u32 data, u32 mem_mask = ~0); + void map_lfb_w(offs_t offset, u32 data, u32 mem_mask = ~0); + void map_texture_w(offs_t offset, u32 data, u32 mem_mask = ~0); + // internal reads and writes + u32 internal_lfb_r(offs_t offset); + void internal_lfb_w(offs_t offset, u32 data, u32 mem_mask); + u32 expand_lfb_data(voodoo::reg_lfb_mode const lfbmode, u32 data, rgb_t src_color[2], u16 src_depth[2]); + virtual void internal_texture_w(offs_t offset, u32 data); - struct fifo_state - { - void reset() { in = out = 0; } - void add(uint32_t data); - uint32_t remove(); - uint32_t peek() { return base[out]; } - bool empty() const { return in == out; } - bool full() const { return ((in + 1) == out) || ((in == (size - 1)) && (out == 0)); } - int32_t items() const; - int32_t space() const { return size - 1 - items(); } + // register read accessors + u32 reg_invalid_r(u32 chipmask, u32 regnum); + u32 reg_passive_r(u32 chipmask, u32 regnum); + u32 reg_status_r(u32 chipmask, u32 regnum); + u32 reg_fbiinit2_r(u32 chipmask, u32 regnum); + u32 reg_vretrace_r(u32 chipmask, u32 regnum); + u32 reg_stats_r(u32 chipmask, u32 regnum); - uint32_t * base = nullptr; // base of the FIFO - int32_t size = 0; // size of the FIFO - int32_t in = 0; // input pointer - int32_t out = 0; // output pointer - }; + // register write accessors + u32 reg_invalid_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_unimplemented_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_passive_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fpassive_4_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fpassive_12_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_starts_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_startt_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dsdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dtdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dsdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dtdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fstarts_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fstartt_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdsdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdtdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdsdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdtdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_startw_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dwdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dwdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fstartw_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdwdx_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fdwdy_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_triangle_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_nop_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fastfill_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_swapbuffer_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fogtable_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fbiinit_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_video_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_clut_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_dac_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_texture_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_palette_w(u32 chipmask, u32 regnum, u32 data); + // VBLANK timing + void adjust_vblank_start_timer(); + virtual void vblank_start(void *ptr, s32 param); + virtual void vblank_stop(void *ptr, s32 param); + void swap_buffers(); + virtual void rotate_buffers(); - struct cmdfifo_info - { - uint8_t enable = 0; // enabled? - uint8_t count_holes = 0; // count holes? - uint32_t base = 0; // base address in framebuffer RAM - uint32_t end = 0; // end address in framebuffer RAM - uint32_t rdptr = 0; // current read pointer - uint32_t amin = 0; // minimum address - uint32_t amax = 0; // maximum address - uint32_t depth = 0; // current depth - uint32_t holes = 0; // number of holes - }; + // video timing and updates + int update_common(bitmap_rgb32 &bitmap, const rectangle &cliprect, rgb_t const *pens); + void recompute_video_timing(u32 hsyncon, u32 hsyncoff, u32 hvis, u32 hbp, u32 vsyncon, u32 vsyncoff, u32 vvis, u32 vbp); + virtual void recompute_video_memory(); + void recompute_video_memory_common(u32 config, u32 rowpixels); + // rendering + voodoo::voodoo_renderer &renderer() { return *m_renderer; } + s32 triangle(); - struct pci_state - { - fifo_state fifo; // PCI FIFO - uint32_t init_enable = 0; // initEnable value - uint8_t stall_state = 0; // state of the system if we're stalled - uint8_t op_pending = 0; // true if an operation is pending - attotime op_end_time = attotime::zero; // time when the pending operation ends - emu_timer * continue_timer = nullptr; // timer to use to continue processing - uint32_t fifo_mem[64*2]; // memory backing the PCI FIFO - }; - - - struct tmu_state - { - class stw_t; - void recompute_texture_params(); - void init(uint8_t vdt, tmu_shared_state &share, voodoo_reg *r, void *memory, int tmem); - int32_t prepare(); - static int32_t new_log2(double &value, const int &offset); - rgbaint_t genTexture(int32_t x, const uint8_t *dither4, const uint32_t TEXMODE, rgb_t *LOOKUP, int32_t LODBASE, const stw_t &iterstw, int32_t &lod); - rgbaint_t combineTexture(const uint32_t TEXMODE, const rgbaint_t& c_local, const rgbaint_t& c_other, int32_t lod); - - struct ncc_table - { - void write(offs_t regnum, uint32_t data); - void update(); - - uint8_t dirty = 0; // is the texel lookup dirty? - voodoo_reg * reg = nullptr; // pointer to our registers - int32_t ir[4], ig[4], ib[4]; // I values for R,G,B - int32_t qr[4], qg[4], qb[4]; // Q values for R,G,B - int32_t y[16]; // Y values - rgb_t * palette = nullptr; // pointer to associated RGB palette - rgb_t * palettea = nullptr; // pointer to associated ARGB palette - rgb_t texel[256]; // texel lookup - }; - - uint8_t * ram = nullptr; // pointer to our RAM - uint32_t mask = 0; // mask to apply to pointers - voodoo_reg * reg = nullptr; // pointer to our register base - uint32_t regdirty = 0; // true if the LOD/mode/base registers have changed - - uint32_t texaddr_mask = 0; // mask for texture address - uint8_t texaddr_shift = 0; // shift for texture address - - int64_t starts = 0, startt = 0; // starting S,T (14.18) - int64_t startw = 0; // starting W (2.30) - int64_t dsdx = 0, dtdx = 0; // delta S,T per X - int64_t dwdx = 0; // delta W per X - int64_t dsdy = 0, dtdy = 0; // delta S,T per Y - int64_t dwdy = 0; // delta W per Y - - int32_t lodmin = 0, lodmax = 0; // min, max LOD values - int32_t lodbias = 0; // LOD bias - uint32_t lodmask = 0; // mask of available LODs - uint32_t lodoffset[9]; // offset of texture base for each LOD - int32_t detailmax = 0; // detail clamp - int32_t detailbias = 0; // detail bias - uint8_t detailscale = 0; // detail scale - - uint32_t wmask = 0; // mask for the current texture width - uint32_t hmask = 0; // mask for the current texture height - - uint32_t bilinear_mask = 0; // mask for bilinear resolution (0xf0 for V1, 0xff for V2) - - ncc_table ncc[2]; // two NCC tables - - rgb_t * lookup = nullptr; // currently selected lookup - rgb_t * texel[16]; // texel lookups for each format - - rgb_t palette[256]; // palette lookup table - rgb_t palettea[256]; // palette+alpha lookup table - }; - - - struct tmu_shared_state - { - void init(); - - rgb_t rgb332[256]; // RGB 3-3-2 lookup table - rgb_t alpha8[256]; // alpha 8-bit lookup table - rgb_t int8[256]; // intensity 8-bit lookup table - rgb_t ai44[256]; // alpha, intensity 4-4 lookup table - - rgb_t* rgb565; // RGB 5-6-5 lookup table - rgb_t argb1555[65536]; // ARGB 1-5-5-5 lookup table - rgb_t argb4444[65536]; // ARGB 4-4-4-4 lookup table - }; - - - struct fbi_state - { - struct setup_vertex - { - float x, y; // X, Y coordinates - float z, wb; // Z and broadcast W values - float r, g, b, a; // A, R, G, B values - float s0, t0, w0; // W, S, T for TMU 0 - float s1, t1, w1; // W, S, T for TMU 1 - }; - - uint8_t * ram = nullptr; // pointer to frame buffer RAM - uint32_t mask = 0; // mask to apply to pointers - uint32_t rgboffs[3] = { 0, 0, 0 }; // word offset to 3 RGB buffers - uint32_t auxoffs = 0; // word offset to 1 aux buffer - - uint8_t frontbuf = 0; // front buffer index - uint8_t backbuf = 0; // back buffer index - uint8_t swaps_pending = 0; // number of pending swaps - uint8_t video_changed = 0; // did the frontbuffer video change? - - uint32_t yorigin = 0; // Y origin subtract value - uint32_t lfb_base = 0; // base of LFB in memory - uint8_t lfb_stride = 0; // stride of LFB accesses in bits - - uint32_t width = 0; // width of current frame buffer - uint32_t height = 0; // height of current frame buffer - uint32_t xoffs = 0; // horizontal offset (back porch) - uint32_t yoffs = 0; // vertical offset (back porch) - uint32_t vsyncstart = 0; // vertical sync start scanline - uint32_t vsyncstop = 0; // vertical sync stop - uint32_t rowpixels = 0; // pixels per row - uint32_t tile_width = 0; // width of video tiles - uint32_t tile_height = 0; // height of video tiles - uint32_t x_tiles = 0; // number of tiles in the X direction - - emu_timer * vsync_stop_timer = nullptr; // VBLANK End timer - emu_timer * vsync_start_timer = nullptr; // VBLANK timer - uint8_t vblank = 0; // VBLANK state - uint8_t vblank_count = 0; // number of VBLANKs since last swap - uint8_t vblank_swap_pending = 0;// a swap is pending, waiting for a vblank - uint8_t vblank_swap = 0; // swap when we hit this count - uint8_t vblank_dont_swap = 0; // don't actually swap when we hit this point - - /* triangle setup info */ - uint8_t cheating_allowed = 0; // allow cheating? - int32_t sign; // triangle sign - int16_t ax, ay; // vertex A x,y (12.4) - int16_t bx, by; // vertex B x,y (12.4) - int16_t cx, cy; // vertex C x,y (12.4) - int32_t startr, startg, startb, starta; // starting R,G,B,A (12.12) - int32_t startz; // starting Z (20.12) - int64_t startw; // starting W (16.32) - int32_t drdx, dgdx, dbdx, dadx; // delta R,G,B,A per X - int32_t dzdx; // delta Z per X - int64_t dwdx; // delta W per X - int32_t drdy, dgdy, dbdy, dady; // delta R,G,B,A per Y - int32_t dzdy; // delta Z per Y - int64_t dwdy; // delta W per Y - - stats_block lfb_stats; // LFB-access statistics - - uint8_t sverts = 0; // number of vertices ready */ - setup_vertex svert[3]; // 3 setup vertices */ - - fifo_state fifo; // framebuffer memory fifo */ - cmdfifo_info cmdfifo[2]; // command FIFOs */ - - uint8_t fogblend[64]; // 64-entry fog table */ - uint8_t fogdelta[64]; // 64-entry fog table */ - uint8_t fogdelta_mask; // mask for for delta (0xff for V1, 0xfc for V2) */ - - rgb_t pen[65536]; // mapping from pixels to pens */ - rgb_t clut[512]; // clut gamma data */ - uint8_t clut_dirty = 1; // do we need to recompute? */ - rgb_t rgb565[65536]; // RGB 5-6-5 lookup table */ - }; - - - struct dac_state - { - void data_w(uint8_t regum, uint8_t data); - void data_r(uint8_t regnum); - - uint8_t reg[8]; // 8 registers - uint8_t read_result; // pending read result - }; - - - struct raster_info - { - uint32_t compute_hash() const; - - raster_info * next = nullptr; // pointer to next entry with the same hash - poly_draw_scanline_func callback = nullptr; // callback pointer - bool is_generic = false; // true if this is one of the generic rasterizers - uint8_t display; // display index - uint32_t hits; // how many hits (pixels) we've used this for - uint32_t polys; // how many polys we've used this for - uint32_t eff_color_path; // effective fbzColorPath value - uint32_t eff_alpha_mode; // effective alphaMode value - uint32_t eff_fog_mode; // effective fogMode value - uint32_t eff_fbz_mode; // effective fbzMode value - uint32_t eff_tex_mode_0; // effective textureMode value for TMU #0 - uint32_t eff_tex_mode_1; // effective textureMode value for TMU #1 - uint32_t hash = 0U; - }; - - - struct poly_extra_data; - - - struct banshee_info - { - uint32_t io[0x40]; // I/O registers - uint32_t agp[0x80]; // AGP registers - uint8_t vga[0x20]; // VGA registers - uint8_t crtc[0x27]; // VGA CRTC registers - uint8_t seq[0x05]; // VGA sequencer registers - uint8_t gc[0x05]; // VGA graphics controller registers - uint8_t att[0x15]; // VGA attribute registers - uint8_t attff; // VGA attribute flip-flop - - uint32_t blt_regs[0x20]; // 2D Blitter registers - uint32_t blt_dst_base = 0; - uint32_t blt_dst_x = 0; - uint32_t blt_dst_y = 0; - uint32_t blt_dst_width = 0; - uint32_t blt_dst_height = 0; - uint32_t blt_dst_stride = 0; - uint32_t blt_dst_bpp = 0; - uint32_t blt_cmd = 0; - uint32_t blt_src_base = 0; - uint32_t blt_src_x = 0; - uint32_t blt_src_y = 0; - uint32_t blt_src_width = 0; - uint32_t blt_src_height = 0; - uint32_t blt_src_stride = 0; - uint32_t blt_src_bpp = 0; - }; - - - static const raster_info predef_raster_table[]; - - // not all of these need to be static, review. - - void check_stalled_cpu(attotime current_time); - static void flush_fifos( voodoo_device* vd, attotime current_time); - static void init_fbi(voodoo_device *vd, fbi_state *f, void *memory, int fbmem); - static int32_t register_w(voodoo_device *vd, offs_t offset, uint32_t data); - static int32_t swapbuffer(voodoo_device *vd, uint32_t data); - static int32_t lfb_w(voodoo_device *vd, offs_t offset, uint32_t data, uint32_t mem_mask); - static int32_t texture_w(voodoo_device *vd, offs_t offset, uint32_t data); - int32_t lfb_direct_w(offs_t offset, uint32_t data, uint32_t mem_mask); - static int32_t banshee_2d_w(voodoo_device *vd, offs_t offset, uint32_t data); - void stall_cpu(int state, attotime current_time); - void soft_reset(); - void recompute_video_memory(); - void adjust_vblank_timer(); - static int32_t fastfill(voodoo_device *vd); - static int32_t triangle(voodoo_device *vd); - static int32_t begin_triangle(voodoo_device *vd); - static int32_t draw_triangle(voodoo_device *vd); - static int32_t setup_and_draw_triangle(voodoo_device *vd); - static int32_t triangle_create_work_item(voodoo_device* vd,uint16_t *drawbuf, int texcount); - static raster_info *add_rasterizer(voodoo_device *vd, const raster_info *cinfo); - static raster_info *find_rasterizer(voodoo_device *vd, int texcount); - static void dump_rasterizer_stats(voodoo_device *vd); - - void accumulate_statistics(const stats_block &block); + // statistics + void accumulate_statistics(const voodoo::thread_stats_block &block); void update_statistics(bool accumulate); void reset_counters(); - static uint32_t register_r(voodoo_device *vd, offs_t offset); + // stall management + bool operation_pending() const { return !m_operation_end.is_zero(); } + void clear_pending_operation() { m_operation_end = attotime::zero; } + void check_stalled_cpu(attotime current_time); + void stall_cpu(stall_state state); + void stall_resume_callback(void *ptr, s32 param); - static void swap_buffers(voodoo_device *vd); - int cmdfifo_compute_expected_depth(cmdfifo_info &f); - static uint32_t cmdfifo_execute(voodoo_device *vd, cmdfifo_info *f); - int32_t cmdfifo_execute_if_ready(cmdfifo_info &f); - static void cmdfifo_w(voodoo_device *vd, cmdfifo_info *f, offs_t offset, uint32_t data); - - static void init_save_state(voodoo_device *vd); - - static void raster_fastfill(void *dest, int32_t scanline, const poly_extent *extent, const void *extradata, int threadid); - static void raster_generic_0tmu(void *dest, int32_t scanline, const poly_extent *extent, const void *extradata, int threadid); - static void raster_generic_1tmu(void *dest, int32_t scanline, const poly_extent *extent, const void *extradata, int threadid); - static void raster_generic_2tmu(void *dest, int32_t scanline, const poly_extent *extent, const void *extradata, int threadid); - -#define RASTERIZER_HEADER(name) \ - static void raster_##name(void *destbase, int32_t y, const poly_extent *extent, const void *extradata, int threadid); -#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \ - RASTERIZER_HEADER(fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1) -#include "voodoo_rast.ipp" - -#undef RASTERIZER_ENTRY - - static bool chromaKeyTest(voodoo_device *vd, stats_block *stats, uint32_t fbzModeReg, rgbaint_t rgaIntColor); - static bool alphaMaskTest(stats_block *stats, uint32_t fbzModeReg, uint8_t alpha); - static bool alphaTest(uint8_t alpharef, stats_block *stats, uint32_t alphaModeReg, uint8_t alpha); - static bool depthTest(uint16_t zaColorReg, stats_block *stats, int32_t destDepth, uint32_t fbzModeReg, int32_t biasdepth); - static bool combineColor(voodoo_device *vd, stats_block *STATS, uint32_t FBZCOLORPATH, uint32_t FBZMODE, rgbaint_t TEXELARGB, int32_t ITERZ, int64_t ITERW, rgbaint_t &srcColor); - -// FIXME: this stuff should not be public -public: - optional_device m_screen_finder; // the screen we are acting on - optional_device m_cpu_finder; // the CPU we interact with - - std::unique_ptr m_fbmem_alloc; - std::unique_ptr m_tmumem_alloc[2]; - - uint8_t index; // index of board - screen_device * m_screen; // the screen we are acting on - cpu_device * m_cpu; // the CPU we interact with - const uint8_t vd_type; // type of system - uint8_t chipmask; // mask for which chips are available - uint32_t freq; // operating frequency - attoseconds_t attoseconds_per_cycle; // attoseconds per cycle - uint32_t extra_cycles; // extra cycles not yet accounted for - int trigger; // trigger used for stalling - - voodoo_reg reg[0x400]; // raw registers - const uint8_t * regaccess; // register access array - const char *const * regnames; // register names array - uint8_t alt_regmap; // enable alternate register map? - - pci_state pci; // PCI state - dac_state dac; // DAC state - - fbi_state fbi; // FBI states - tmu_state tmu[MAX_TMU]; // TMU states - tmu_shared_state tmushare; // TMU shared state - banshee_info banshee; // Banshee state - - legacy_poly_manager_owner poly; // polygon manager - std::unique_ptr thread_stats; // per-thread statistics - - voodoo_stats stats; // internal statistics - - offs_t last_status_pc; // PC of last status description (for logging) - uint32_t last_status_value; // value of last status read (for logging) - - int next_rasterizer; // next rasterizer index - raster_info rasterizer[MAX_RASTERIZERS]; // array of rasterizers - raster_info * raster_hash[RASTER_HASH_SIZE]; // hash table of rasterizers - - bool send_config; - uint32_t tmu_config; -}; - -class voodoo_1_device : public voodoo_device -{ -public: - voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -}; - - -class voodoo_2_device : public voodoo_device -{ -public: - voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -}; - - -class voodoo_banshee_device : public voodoo_device -{ -public: - voodoo_banshee_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - u32 banshee_r(offs_t offset, u32 mem_mask = ~0); - void banshee_w(offs_t offset, u32 data, u32 mem_mask = ~0); - u32 banshee_fb_r(offs_t offset); - void banshee_fb_w(offs_t offset, u32 data, u32 mem_mask = ~0); - u32 banshee_io_r(offs_t offset, u32 mem_mask = ~0); - void banshee_io_w(offs_t offset, u32 data, u32 mem_mask = ~0); - u32 banshee_rom_r(offs_t offset); - u8 banshee_vga_r(offs_t offset); - void banshee_vga_w(offs_t offset, u8 data); - -protected: - voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt); - - // device-level overrides - u32 banshee_agp_r(offs_t offset); - void banshee_agp_w(offs_t offset, u32 data, u32 mem_mask = ~0); -}; - - -class voodoo_3_device : public voodoo_banshee_device -{ -public: - voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -}; - - -DECLARE_DEVICE_TYPE(VOODOO_1, voodoo_1_device) -DECLARE_DEVICE_TYPE(VOODOO_2, voodoo_2_device) -DECLARE_DEVICE_TYPE(VOODOO_BANSHEE, voodoo_banshee_device) -DECLARE_DEVICE_TYPE(VOODOO_3, voodoo_3_device) - -// use SSE on 64-bit implementations, where it can be assumed -#if 1 && ((!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64)) -#include -#ifdef __SSE4_1__ -#include -#endif -class voodoo_device::tmu_state::stw_t -{ -public: - stw_t() { } - stw_t(const stw_t& other) = default; - stw_t &operator=(const stw_t& other) = default; - - void set(s64 s, s64 t, s64 w) { m_st = _mm_set_pd(s << 8, t << 8); m_w = _mm_set1_pd(w); } - int is_w_neg() const { return _mm_comilt_sd(m_w, _mm_set1_pd(0.0)); } - void get_st_shiftr(s32 &s, s32 &t, const s32 &shift) const + // misc helpers + u32 chipmask_from_offset(u32 offset) { - s64 tmpS = _mm_cvtsd_si64(_mm_shuffle_pd(m_st, _mm_setzero_pd(), 1)); - s = tmpS >> shift; - s64 tmpT = _mm_cvtsd_si64(m_st); - t = tmpT >> shift; + u32 chipmask = BIT(offset, 8, 4); + if (chipmask == 0) + chipmask = 0xf; + return chipmask & m_chipmask; } - void add(const stw_t& other) - { - m_st = _mm_add_pd(m_st, other.m_st); - m_w = _mm_add_pd(m_w, other.m_w); - } - void calc_stow(s32 &sow, s32 &tow, int32_t &oowlog) const - { - __m128d tmp = _mm_div_pd(m_st, m_w); - // Allow for 8 bits of decimal in integer - //tmp = _mm_mul_pd(tmp, _mm_set1_pd(256.0)); - __m128i tmp2 = _mm_cvttpd_epi32(tmp); -#ifdef __SSE4_1__ - sow = _mm_extract_epi32(tmp2, 1); - tow = _mm_extract_epi32(tmp2, 0); -#else - sow = _mm_cvtsi128_si32(_mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 0, 1))); - tow = _mm_cvtsi128_si32(tmp2); -#endif - double dW = _mm_cvtsd_f64(m_w); - oowlog = -new_log2(dW, 0); - } -private: - __m128d m_st; - __m128d m_w; -}; -#else -class voodoo_device::tmu_state::stw_t -{ -public: - stw_t() {} - stw_t(const stw_t& other) = default; - stw_t &operator=(const stw_t& other) = default; - void set(s64 s, s64 t, s64 w) { m_s = s; m_t = t; m_w = w; } - int is_w_neg() const { return (m_w < 0) ? 1 : 0; } - void get_st_shiftr(s32 &s, s32 &t, const s32 &shift) const - { - s = m_s >> shift; - t = m_t >> shift; - } - inline void add(const stw_t& other) - { - m_s += other.m_s; - m_t += other.m_t; - m_w += other.m_w; - } - // Computes s/w and t/w and returns log2 of 1/w - // s, t and c are 16.32 values. The results are 24.8. - inline void calc_stow(s32 &sow, s32 &tow, int32_t &oowlog) const - { - double recip = double(1ULL << (47 - 39)) / m_w; - double resAD = m_s * recip; - double resBD = m_t * recip; - oowlog = new_log2(recip, 56); - sow = resAD; - tow = resBD; - } -private: - s64 m_s, m_t, m_w; + // configuration + u8 m_chipmask; // mask for which chips are available + + // PCI state/FIFOs + voodoo::reg_init_en m_init_enable; // initEnable value (set externally) + stall_state m_stall_state; // state of the system if we're stalled + int m_stall_trigger; // trigger used for stalling + attotime m_operation_end; // time when the pending operation ends + voodoo::memory_fifo m_pci_fifo; // PCI FIFO + voodoo::memory_fifo m_fbmem_fifo; // framebuffer memory fifo + bool m_flush_flag; // true if we are currently flushing FIFOs + + // allocated memory + u8 *m_fbram; // pointer to aligned framebuffer + u32 m_fbmask; // mask to apply to pointers + std::unique_ptr m_memory; // allocated framebuffer/texture memory + std::unique_ptr m_shared; // shared tables + std::unique_ptr m_renderer; // rendering helper + + // video buffer configuration + u32 m_rgboffs[3]; // word offset to 3 RGB buffers + u32 m_auxoffs; // word offset to 1 aux buffer + u8 m_frontbuf; // front buffer index + u8 m_backbuf; // back buffer index + bool m_video_changed; // did the frontbuffer video change? + + // linear frame buffer access configuration + u8 m_lfb_stride; // stride of LFB accesses in bits + + // video configuration + u32 m_width; // width of current frame buffer + u32 m_height; // height of current frame buffer + u32 m_xoffs; // horizontal offset (back porch) + u32 m_yoffs; // vertical offset (back porch) + u32 m_vsyncstart; // vertical sync start scanline + u32 m_vsyncstop; // vertical sync stop + + // VBLANK/swapping state + u8 m_swaps_pending; // number of pending swaps + u8 m_vblank; // VBLANK state + u8 m_vblank_count; // number of VBLANKs since last swap + u8 m_vblank_swap_pending; // a swap is pending, waiting for a vblank + u8 m_vblank_swap; // swap when we hit this count + u8 m_vblank_dont_swap; // don't actually swap when we hit this point + + // register state + voodoo::voodoo_regs m_reg; // FBI registers + voodoo::register_table_entry m_regtable[256]; // generated register table + voodoo::tmu_state m_tmu[2]; // TMU states + u8 m_dac_reg[32]; // up to 32 DAC registers + u8 m_dac_read_result; // pending DAC read result + + // timers + emu_timer *m_vsync_start_timer; // VBLANK timer + emu_timer *m_vsync_stop_timer; // VBLANK end timer + emu_timer *m_stall_resume_timer; // timer to resume processing after stall + + // statistics + voodoo::debug_stats m_stats; // internal statistics + voodoo::thread_stats_block m_lfb_stats; // LFB access statistics + + // tracking for logging + offs_t m_last_status_pc; // PC of last status description (for logging) + u32 m_last_status_value; // value of last status read (for logging) + + // memory for PCI FIFO + u32 m_pci_fifo_mem[64*2]; // memory backing the PCI FIFO + + // pens and CLUT + bool m_clut_dirty; // do we need to recompute? + std::vector m_clut; // clut gamma data + std::vector m_pen; // mapping from pixels to pens + + // register table + static voodoo::static_register_table_entry const s_register_table[256]; }; -#endif + + +//************************************************************************** +// INLINE FUNCITIONS +//************************************************************************** + +//------------------------------------------------- +// write - handle a write through a register table +// entry, performing any necessary logging +//------------------------------------------------- + +inline u32 voodoo::register_table_entry::write(voodoo_1_device &device, u32 chipmask, u32 regnum, u32 data) const +{ + // statistics if enabled + if (DEBUG_STATS) + device.m_stats.m_reg_writes++; + + // log if enabled + if (LOG_REGISTERS) + { + if (regnum < voodoo_regs::reg_fvertexAx || regnum > voodoo_regs::reg_fdWdY) + device.logerror("VOODOO.REG:%s(%d) write = %08X\n", m_name, chipmask, data); + else + device.logerror("VOODOO.REG:%s(%d) write = %f\n", m_name, chipmask, double(u2f(data))); + } + return m_write(chipmask & m_chipmask_flags, regnum, data & m_mask); +} + + +//------------------------------------------------- +// read - handle a read through a register table +// entry, performing any necessary logging +//------------------------------------------------- + +inline u32 voodoo::register_table_entry::read(voodoo_1_device &device, u32 chipmask, u32 regnum) const +{ + // statistics if enabled + if (DEBUG_STATS) + device.m_stats.m_reg_reads++; + + // get the result + u32 result = m_read(chipmask & m_chipmask_flags, regnum) & m_mask; + + // log if enabled + if (LOG_REGISTERS) + { + // don't log multiple identical status reads from the same address + bool logit = true; + if (regnum == voodoo_regs::reg_vdstatus) + { + offs_t pc = device.m_cpu->pc(); + if (pc == device.m_last_status_pc && result == device.m_last_status_value) + logit = false; + device.m_last_status_pc = pc; + device.m_last_status_value = result; + } + if (regnum == voodoo_regs::reg_cmdFifoRdPtr) + logit = false; + + if (logit) + device.logerror("VOODOO.REG:%s read = %08X\n", m_name, result); + } + return result; +} #endif // MAME_VIDEO_VOODOO_H diff --git a/src/devices/video/voodoo_2.cpp b/src/devices/video/voodoo_2.cpp new file mode 100644 index 00000000000..5f805d1f604 --- /dev/null +++ b/src/devices/video/voodoo_2.cpp @@ -0,0 +1,1722 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_2.c + + 3dfx Voodoo Graphics SST-1/2 emulator. + +**************************************************************************** + + Specs: + + Voodoo 2: + 2,4MB frame buffer RAM + 2,4,8,16MB texture RAM + 90MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 16 pixels/clock + 128 entry PCI FIFO + memory FIFO up to 65536 entries + +**************************************************************************/ + +#include "emu.h" +#include "voodoo_2.h" + +using namespace voodoo; + + +//************************************************************************** +// COMMAND FIFO +//************************************************************************** + +//------------------------------------------------- +// command_fifo - constructor +//------------------------------------------------- + +command_fifo::command_fifo(voodoo_2_device &device) : + m_device(device), + m_ram(nullptr), + m_mask(0), + m_enable(false), + m_count_holes(false), + m_ram_base(0), + m_ram_end(0), + m_read_index(0), + m_address_min(0), + m_address_max(0), + m_depth(0), + m_holes(0) +{ +} + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void command_fifo::register_save(save_proxy &save) +{ + save.save_item(NAME(m_enable)); + save.save_item(NAME(m_count_holes)); + save.save_item(NAME(m_ram_base)); + save.save_item(NAME(m_ram_end)); + save.save_item(NAME(m_read_index)); + save.save_item(NAME(m_address_min)); + save.save_item(NAME(m_address_max)); + save.save_item(NAME(m_depth)); + save.save_item(NAME(m_holes)); +} + + +//------------------------------------------------- +// execute_if_ready - execute everything we have +// the data for, until we encounter an operation +// that consumes a non-zero number of cycles +//------------------------------------------------- + +u32 command_fifo::execute_if_ready() +{ + while (1) + { + // all CMDFIFO commands need at least one word + if (m_depth == 0) + return 0; + + // see if we have enough for the current command + u32 const needed_depth = words_needed(peek_next()); + if (m_depth < needed_depth) + return 0; + + // read the next command and handle it based on the low 3 bits + u32 command = read_next(); + u32 cycles = (this->*s_packet_handler[BIT(command, 0, 3)])(command); + + // if the number of cycles is non-zero, return + if (cycles > 0) + return cycles; + } +} + + +//------------------------------------------------- +// write - handle a write to the FIFO +//------------------------------------------------- + +void command_fifo::write(offs_t addr, u32 data) +{ + if (LOG_CMDFIFO_VERBOSE) + m_device.logerror("CMDFIFO_w(%04X) = %08X\n", addr, data); + + // write the data if it's within range + if (addr < m_ram_end) + m_ram[(addr / 4) & m_mask] = data; + + // count holes? + if (m_count_holes) + { + // in-order, no holes + if (m_holes == 0 && addr == m_address_min + 4) + { + m_address_min = m_address_max = addr; + m_depth++; + } + + // out-of-order, below the minimum + else if (addr < m_address_min) + { + if (m_holes != 0) + m_device.logerror("Unexpected CMDFIFO: AMin=%08X AMax=%08X Holes=%d WroteTo:%08X\n", m_address_min, m_address_max, m_holes, addr); + m_holes += (addr - m_ram_base) / 4; + m_address_min = m_ram_base; + m_address_max = addr; + m_depth++; + } + + // out-of-order, but within the min-max range + else if (addr < m_address_max) + { + m_holes--; + if (m_holes == 0) + { + m_depth += (m_address_max - m_address_min) / 4; + m_address_min = m_address_max; + } + } + + // out-of-order, bumping max + else + { + m_holes += (addr - m_address_max) / 4 - 1; + m_address_max = addr; + } + } + + // execute if we can + if (!m_device.operation_pending()) + { + s32 cycles = execute_if_ready(); + if (cycles > 0) + { + attotime curtime = m_device.machine().time(); + m_device.m_operation_end = curtime + m_device.clocks_to_attotime(cycles); + + if (LOG_FIFO_VERBOSE) + m_device.logerror("VOODOO.FIFO:direct write start at %s end at %s\n", curtime.as_string(18), m_device.m_operation_end.as_string(18)); + } + } +} + + +//------------------------------------------------- +// words_needed - return the total number of +// words needed for the given command and all its +// parameters +//------------------------------------------------- + +u32 command_fifo::words_needed(u32 command) +{ + // low 3 bits specify the packet type + switch (BIT(command, 0, 3)) + { + case 0: + // Packet type 0: 1 or 2 words + // + // Word Bits + // 0 31:29 = reserved + // 0 28:6 = Address [24:2] + // 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) + // 0 2:0 = Packet type (0) + return (BIT(command, 3, 3) == 4) ? 2 : 1; + + case 1: + // Packet type 1: 1 + N words + // + // Word Bits + // 0 31:16 = Number of words + // 0 15 = Increment? + // 0 14:3 = Register base + // 0 2:0 = Packet type (1) + return 1 + BIT(command, 16, 16); + + case 2: + // Packet type 2: 1 + N words + // + // Word Bits + // 0 31:3 = 2D Register mask + // 0 2:0 = Packet type (2) + return 1 + population_count_32(BIT(command, 3, 29)); + + case 3: + { + // Packet type 3: 1 + N words + // + // Word Bits + // 0 31:29 = Number of dummy entries following the data + // 0 28 = Packed color data? + // 0 25 = Disable ping pong sign correction (0=normal, 1=disable) + // 0 24 = Culling sign (0=positive, 1=negative) + // 0 23 = Enable culling (0=disable, 1=enable) + // 0 22 = Strip mode (0=strip, 1=fan) + // 0 17 = Setup S1 and T1 + // 0 16 = Setup W1 + // 0 15 = Setup S0 and T0 + // 0 14 = Setup W0 + // 0 13 = Setup Wb + // 0 12 = Setup Z + // 0 11 = Setup Alpha + // 0 10 = Setup RGB + // 0 9:6 = Number of vertices + // 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) + // 0 2:0 = Packet type (3) + + // determine words per vertex + u32 count = 2; // X/Y + if (BIT(command, 28)) + count += (BIT(command, 10, 2) != 0) ? 1 : 0; // ARGB in one word + else + count += 3 * BIT(command, 10) + BIT(command, 11); // RGB + A + count += BIT(command, 12); // Z + count += BIT(command, 13); // Wb + count += BIT(command, 14); // W0 + count += 2 * BIT(command, 15); // S0/T0 + count += BIT(command, 16); // W1 + count += 2 * BIT(command, 17); // S1/T1 + + // multiply by the number of verticies + count *= BIT(command, 6, 4); + return 1 + count + BIT(command, 29, 3); + } + + case 4: + // Packet type 4: 1 + N words + // + // Word Bits + // 0 31:29 = Number of dummy entries following the data + // 0 28:15 = General register mask + // 0 14:3 = Register base + // 0 2:0 = Packet type (4) + return 1 + population_count_32(BIT(command, 15, 14)) + BIT(command, 29, 3); + + case 5: + // Packet type 5: 2 + N words + // + // Word Bits + // 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) + // 0 29:26 = Byte disable W2 + // 0 25:22 = Byte disable WN + // 0 21:3 = Num words + // 0 2:0 = Packet type (5) + return 2 + BIT(command, 3, 19); + + default: + m_device.logerror("cmdfifo unknown packet type %d\n", command & 7); + return 1; + } +} + + +//------------------------------------------------- +// packet_type_0 - handle FIFO packet type 0 +//------------------------------------------------- + +u32 command_fifo::packet_type_0(u32 command) +{ + // Packet type 0: 1 or 2 words + // + // Word Bits + // 0 31:29 = reserved + // 0 28:6 = Address [24:2] + // 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) + // 0 2:0 = Packet type (0) + // 1 31:11 = reserved (JMP AGP only) + // 1 10:0 = Address [35:25] + u32 target = BIT(command, 6, 23) << 2; + + // switch off of the specific command; many are unimplemented until we + // see them in real life + switch (BIT(command, 3, 3)) + { + case 0: // NOP + if (LOG_CMDFIFO) + m_device.logerror(" NOP\n"); + break; + + case 1: // JSR + if (LOG_CMDFIFO) + m_device.logerror(" JSR $%06X\n", target); + m_device.logerror("cmdFifo: Unsupported JSR"); + break; + + case 2: // RET + if (LOG_CMDFIFO) + m_device.logerror(" RET $%06X\n", target); + m_device.logerror("cmdFifo: Unsupported RET"); + break; + + case 3: // JMP LOCAL FRAME BUFFER + if (LOG_CMDFIFO) + m_device.logerror(" JMP LOCAL FRAMEBUF $%06X\n", target); + m_read_index = target / 4; + break; + + case 4: // JMP AGP + if (LOG_CMDFIFO) + m_device.logerror(" JMP AGP $%06X\n", target); + m_device.logerror("cmdFifo: Unsupported JMP AGP"); + break; + + default: + m_device.logerror("cmdFifo: Invalid jump command %d", BIT(command, 3, 3)); + break; + } + return 0; +} + + +//------------------------------------------------- +// packet_type_1 - handle FIFO packet type 1 +//------------------------------------------------- + +u32 command_fifo::packet_type_1(u32 command) +{ + // Packet type 1: 1 + N words + // + // Word Bits + // 0 31:16 = Number of words + // 0 15 = Increment? + // 0 14:3 = Register base + // 0 2:0 = Packet type (1) + // 1 31:0 = Data word + u32 count = BIT(command, 16, 16); + u32 inc = BIT(command, 15); + u32 target = BIT(command, 3, 12); + + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target); + + // loop over all registers and write them one at a time + u32 cycles = 0; + for (u32 regbit = 0; regbit < count; regbit++, target += inc) + cycles += m_device.cmdfifo_register_w(target, read_next()); + return cycles; +} + + +//------------------------------------------------- +// packet_type_2 - handle FIFO packet type 2 +//------------------------------------------------- + +u32 command_fifo::packet_type_2(u32 command) +{ + // Packet type 2: 1 + N words + // + // Word Bits + // 0 31:3 = 2D Register mask + // 0 2:0 = Packet type (2) + // 1 31:0 = Data word + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 2: mask=%X\n", BIT(command, 3, 29)); + + // loop over all registers and write them one at a time + u32 cycles = 0; + for (u32 regbit = 3; regbit <= 31; regbit++) + if (BIT(command, regbit)) + cycles += m_device.cmdfifo_2d_w(regbit - 3, read_next()); + return cycles; +} + + +//------------------------------------------------- +// packet_type_3 - handle FIFO packet type 3 +//------------------------------------------------- + +u32 command_fifo::packet_type_3(u32 command) +{ + // Packet type 3: 1 + N words + // + // Word Bits + // 0 31:29 = Number of dummy entries following the data + // 0 28 = Packed color data? + // 0 25 = Disable ping pong sign correction (0=normal, 1=disable) + // 0 24 = Culling sign (0=positive, 1=negative) + // 0 23 = Enable culling (0=disable, 1=enable) + // 0 22 = Strip mode (0=strip, 1=fan) + // 0 17 = Setup S1 and T1 + // 0 16 = Setup W1 + // 0 15 = Setup S0 and T0 + // 0 14 = Setup W0 + // 0 13 = Setup Wb + // 0 12 = Setup Z + // 0 11 = Setup Alpha + // 0 10 = Setup RGB + // 0 9:6 = Number of vertices + // 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) + // 0 2:0 = Packet type (3) + // 1 31:0 = Data word + u32 count = BIT(command, 6, 4); + u32 code = BIT(command, 3, 3); + + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 3: count=%d code=%d mask=%03X smode=%02X pc=%d\n", count, code, BIT(command, 10, 12), BIT(command, 22, 6), BIT(command, 28)); + + // copy relevant bits into the setup mode register + m_device.m_reg.write(voodoo_regs::reg_sSetupMode, BIT(command, 10, 8) | (BIT(command, 22, 4) << 16)); + + // loop over triangles + setup_vertex svert = { 0 }; + u32 cycles = 0; + for (u32 trinum = 0; trinum < count; trinum++) + { + // always extract X/Y + svert.x = read_next_float(); + svert.y = read_next_float(); + + // load ARGB values + if (BIT(command, 28)) + { + // packed form + if (BIT(command, 10, 2) != 0) + { + rgb_t argb = read_next(); + if (BIT(command, 10)) + { + svert.r = argb.r(); + svert.g = argb.g(); + svert.b = argb.b(); + } + if (BIT(command, 11)) + svert.a = argb.a(); + } + } + else + { + // unpacked form + if (BIT(command, 10)) + { + svert.r = read_next_float(); + svert.g = read_next_float(); + svert.b = read_next_float(); + } + if (BIT(command, 11)) + svert.a = read_next_float(); + } + + // load Z and Wb values + if (BIT(command, 12)) + svert.z = read_next_float(); + if (BIT(command, 13)) + svert.wb = svert.w0 = svert.w1 = read_next_float(); + + // load W0, S0, T0 values + if (BIT(command, 14)) + svert.w0 = svert.w1 = read_next_float(); + if (BIT(command, 15)) + { + svert.s0 = svert.s1 = read_next_float(); + svert.t0 = svert.t1 = read_next_float(); + } + + // load W1, S1, T1 values + if (BIT(command, 16)) + svert.w1 = read_next_float(); + if (BIT(command, 17)) + { + svert.s1 = read_next_float(); + svert.t1 = read_next_float(); + } + + // if we're starting a new strip, or if this is the first of a set of verts + // for a series of individual triangles, initialize all the verts + if ((code == 1 && trinum == 0) || (code == 0 && trinum % 3 == 0)) + { + m_device.m_sverts = 1; + m_device.m_svert[0] = m_device.m_svert[1] = m_device.m_svert[2] = svert; + } + + // otherwise, add this to the list + else + { + // for strip mode, shuffle vertex 1 down to 0 + if (!BIT(command, 22)) + m_device.m_svert[0] = m_device.m_svert[1]; + + // copy 2 down to 1 and add our new one regardless + m_device.m_svert[1] = m_device.m_svert[2]; + m_device.m_svert[2] = svert; + + // if we have enough, draw + if (++m_device.m_sverts >= 3) + cycles += m_device.setup_and_draw_triangle(); + } + } + + // account for the extra dummy words + consume(BIT(command, 29, 3)); + return cycles; +} + + +//------------------------------------------------- +// packet_type_4 - handle FIFO packet type 4 +//------------------------------------------------- + +u32 command_fifo::packet_type_4(u32 command) +{ + // Packet type 4: 1 + N words + // + // Word Bits + // 0 31:29 = Number of dummy entries following the data + // 0 28:15 = General register mask + // 0 14:3 = Register base + // 0 2:0 = Packet type (4) + // 1 31:0 = Data word + u32 target = BIT(command, 3, 12); + + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", BIT(command, 15, 14), target, BIT(command, 29, 3)); + + // loop over all registers and write them one at a time + u32 cycles = 0; + for (u32 regbit = 15; regbit <= 28; regbit++, target++) + if (BIT(command, regbit)) + cycles += m_device.cmdfifo_register_w(target, read_next()); + + // account for the extra dummy words + consume(BIT(command, 29, 3)); + return cycles; +} + + +//------------------------------------------------- +// packet_type_5 - handle FIFO packet type 5 +//------------------------------------------------- + +u32 command_fifo::packet_type_5(u32 command) +{ + // Packet type 5: 2 + N words + // + // Word Bits + // 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) + // 0 29:26 = Byte disable W2 + // 0 25:22 = Byte disable WN + // 0 21:3 = Num words + // 0 2:0 = Packet type (5) + // 1 31:30 = Reserved + // 1 29:0 = Base address [24:0] + // 2 31:0 = Data word + u32 count = BIT(command, 3, 19); + u32 target = read_next() / 4; + + // handle LFB writes + switch (BIT(command, 30, 2)) + { + // Linear FB + case 0: + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 5: FB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, BIT(command, 26, 4), BIT(command, 22, 4)); + + for (u32 word = 0; word < count; word++) + m_ram[target++ & m_mask] = little_endianize_int32(read_next()); + break; + + // 3D LFB + case 2: + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 5: 3D LFB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, BIT(command, 26, 4), BIT(command, 22, 4)); + + for (u32 word = 0; word < count; word++) + m_device.internal_lfb_w(target++, read_next(), 0xffffffff); + break; + + // Planar YUV + case 1: + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 5: Planar YUV count=%d dest=%08X bd2=%X bdN=%X\n", count, target, BIT(command, 26, 4), BIT(command, 22, 4)); + + fatalerror("%s: Unsupported planar YUV write via cmdFifo", m_device.tag()); + break; + + // Texture port + case 3: + if (LOG_CMDFIFO) + m_device.logerror(" PACKET TYPE 5: textureRAM count=%d dest=%08X bd2=%X bdN=%X\n", count, target, BIT(command, 26, 4), BIT(command, 22, 4)); + + for (u32 word = 0; word < count; word++) + m_device.internal_texture_w(target++, read_next()); + break; + } + return 0; +} + + +//------------------------------------------------- +// packet_type_unknown - error out on unhandled +// packets +//------------------------------------------------- + +u32 command_fifo::packet_type_unknown(u32 command) +{ + fatalerror("%s: Unsupported cmdFifo packet type %d\n", m_device.tag(), BIT(command, 0, 3)); +} + + +//------------------------------------------------- +// s_packet_handler - static array of pointers to +// handler functions +//------------------------------------------------- + +command_fifo::packet_handler command_fifo::s_packet_handler[8] = +{ + &command_fifo::packet_type_0, + &command_fifo::packet_type_1, + &command_fifo::packet_type_2, + &command_fifo::packet_type_3, + &command_fifo::packet_type_4, + &command_fifo::packet_type_5, + &command_fifo::packet_type_unknown, + &command_fifo::packet_type_unknown +}; + + + +//************************************************************************** +// VOODOO 2 DEVICE +//************************************************************************** + +//------------------------------------------------- +// voodoo_2_device - constructor +//------------------------------------------------- + +DEFINE_DEVICE_TYPE(VOODOO_2, voodoo_2_device, "voodoo_2", "3dfx Voodoo 2") + +voodoo_2_device::voodoo_2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo_model model) : + voodoo_1_device(mconfig, type, tag, owner, clock, model), + m_sverts(0), + m_cmdfifo(*this) +{ + for (int index = 0; index < std::size(m_regtable); index++) + m_regtable[index].unpack(s_register_table[index], *this); +} + + +//------------------------------------------------- +// core_map - device map for core memory access +//------------------------------------------------- + +void voodoo_2_device::core_map(address_map &map) +{ + // Voodoo-2 memory map: + // + // cmdfifo = fbi_init7().cmdfifo_enable() + // + // 00ab----`--ccccrr`rrrrrr-- Register access (if cmdfifo == 0) + // a = alternate register map if fbi_init3().tri_register_remap() + // b = byte swizzle data if fbi_init0().swizzle_reg_writes() + // c = chip mask select + // r = register index ($00-$FF) + // 000-----`------rr`rrrrrr-- Register access (if cmdfifo == 1) + // r = register index ($00-$FF) + // 001--boo`oooooooo`oooooo-- CMDFifo write (if cmdfifo == 1) + // b = byte swizzle data + // o = cmdfifo offset + // 01-yyyyy`yyyyyxxx`xxxxxxx- Linear frame buffer access (16-bit) + // 01yyyyyy`yyyyxxxx`xxxxxx-- Linear frame buffer access (32-bit) + // 1-ccllll`tttttttt`sssssss- Texture memory access, where: + // c = chip mask select + // l = LOD + // t = Y index + // s = X index + // + map(0x000000, 0x3fffff).rw(FUNC(voodoo_2_device::map_register_r), FUNC(voodoo_2_device::map_register_w)); + map(0x400000, 0x7fffff).rw(FUNC(voodoo_2_device::map_lfb_r), FUNC(voodoo_2_device::map_lfb_w)); + map(0x800000, 0xffffff).w(FUNC(voodoo_2_device::map_texture_w)); +} + + +//------------------------------------------------- +// read - generic read handler until everyone is +// using the memory map +//------------------------------------------------- + +u32 voodoo_2_device::read(offs_t offset, u32 mem_mask) +{ + switch (offset >> (22-2)) + { + case 0x000000 >> 22: + return map_register_r(offset); + + case 0x400000 >> 22: + return map_lfb_r(offset - 0x400000/4); + + default: + return 0xffffffff; + } +} + + +//------------------------------------------------- +// write - generic write handler until everyone is +// using the memory map +//------------------------------------------------- + +void voodoo_2_device::write(offs_t offset, u32 data, u32 mem_mask) +{ + switch (offset >> (22-2)) + { + case 0x000000 >> 22: + map_register_w(offset, data, mem_mask); + break; + + case 0x400000 >> 22: + map_lfb_w(offset - 0x400000/4, data, mem_mask); + break; + + case 0x800000 >> 22: + case 0xc00000 >> 22: + map_texture_w(offset - 0x800000/4, data, mem_mask); + break; + } +} + + +//------------------------------------------------- +// device_start - device startup +//------------------------------------------------- + +void voodoo_2_device::device_start() +{ + // start like a Voodoo-1 + voodoo_1_device::device_start(); + + // fogDelta skips the low 2 bits + m_renderer->set_fogdelta_mask(0xfc); + + // bilinear is full resolution + m_renderer->set_bilinear_mask(0xff); + + // TMU configuration has an extra bit + m_renderer->set_tmu_config(m_renderer->tmu_config() | 0x800); + + // initialize Voodoo 2 additions + m_sverts = 0; + m_cmdfifo.init(m_fbram, m_fbmask + 1); +} + + + +//------------------------------------------------- +// map_register_w - handle a mapped write to +// regular register space +//------------------------------------------------- + +void voodoo_2_device::map_register_w(offs_t offset, u32 data, u32 mem_mask) +{ + bool pending = prepare_for_write(); + + // handle cmdfifo writes + if (BIT(offset, 21-2) && m_reg.fbi_init7().cmdfifo_enable()) + { + // check for byte swizzling (bit 18) + if (BIT(offset, 18-2)) + data = swapendian_int32(data); + m_cmdfifo.write_direct(BIT(offset, 0, 16), data); + return; + } + + // extract chipmask and register + u32 chipmask = chipmask_from_offset(offset); + u32 regnum = BIT(offset, 0, 8); + + // handle register swizzling + if (BIT(offset, 20-2) && m_reg.fbi_init0().swizzle_reg_writes()) + data = swapendian_int32(data); + + // handle aliasing + if (BIT(offset, 21-2) && m_reg.fbi_init3().tri_register_remap()) + regnum = voodoo_regs::alias(regnum); + + // look up the register + auto const ®entry = m_regtable[regnum]; + + // if this is non-FIFO command, execute immediately + if (!regentry.is_fifo()) + return void(regentry.write(*this, chipmask, regnum, data)); + + // track swap buffers + if (regnum == voodoo_regs::reg_swapbufferCMD) + m_swaps_pending++; + + // if cmdfifo is enabled, ignore everything else + if (m_reg.fbi_init7().cmdfifo_enable()) + { + logerror("Ignoring write to %s when CMDFIFO is enabled\n", regentry.name()); + return; + } + + // if we're busy add to the fifo + if (pending && m_init_enable.enable_pci_fifo()) + return add_to_fifo(memory_fifo::TYPE_REGISTER | (chipmask << 8) | regnum, data, mem_mask); + + // if we get a non-zero number of cycles back, mark things pending + int cycles = regentry.write(*this, chipmask, regnum, data); + if (cycles > 0) + { + m_operation_end = machine().time() + clocks_to_attotime(cycles); + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:direct write start at %s end at %s\n", machine().time().as_string(18), m_operation_end.as_string(18)); + } +} + + +//------------------------------------------------- +// soft_reset - handle reset when initiated by +// a register write +//------------------------------------------------- + +void voodoo_2_device::soft_reset() +{ + voodoo_1_device::soft_reset(); + m_cmdfifo.set_enable(0); +} + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void voodoo_2_device::register_save(save_proxy &save, u32 total_allocation) +{ + voodoo_1_device::register_save(save, total_allocation); + + // Voodoo 2 stuff + save.save_item(NAME(m_sverts)); + save.save_class(NAME(m_svert[0])); + save.save_class(NAME(m_svert[1])); + save.save_class(NAME(m_svert[2])); + save.save_class(NAME(m_cmdfifo)); +} + + +//------------------------------------------------- +// execute_fifos - execute commands from the FIFOs +// until a non-zero cycle count operation is run +//------------------------------------------------- + +u32 voodoo_2_device::execute_fifos() +{ + // we might be in CMDFIFO mode + if (m_cmdfifo.enabled()) + return m_cmdfifo.execute_if_ready(); + + // otherwise, run the traditional memory FIFOs + return voodoo_1_device::execute_fifos(); +} + + +//------------------------------------------------- +// reg_hvretrace_r - hvRetrace register read +//------------------------------------------------- + +u32 voodoo_2_device::reg_hvretrace_r(u32 chipmask, u32 regnum) +{ + // return 0 for vertical if vblank is active + u32 result = m_vblank ? 0 : screen().vpos(); + return result |= screen().hpos() << 16; +} + + +//------------------------------------------------- +// reg_cmdfifoptr_r - cmdFifoRdPtr register read +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifoptr_r(u32 chipmask, u32 regnum) +{ + return m_cmdfifo.read_pointer(); +} + + +//------------------------------------------------- +// reg_cmdfifodepth_r - cmdFifoDepth register read +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifodepth_r(u32 chipmask, u32 regnum) +{ + return m_cmdfifo.depth(); +} + + +//------------------------------------------------- +// reg_cmdfifoholes_r - cmdFifoHoles register read +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifoholes_r(u32 chipmask, u32 regnum) +{ + return m_cmdfifo.holes(); +} + + +//------------------------------------------------- +// reg_intrctrl_w - intrCtrl register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_intrctrl_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_reg.write(regnum, data); + + // Setting bit 31 clears the PCI interrupts + if (BIT(data, 31) && !m_pciint_cb.isnull()) + m_pciint_cb(false); + } + return 0; +} + + +//------------------------------------------------- +// reg_video2_w -- write to a video configuration +// register; synchronize then recompute everything +//------------------------------------------------- + +u32 voodoo_2_device::reg_video2_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("video_configuration"); + m_reg.write(regnum, data); + + auto const hsync = m_reg.hsync(); + auto const vsync = m_reg.vsync(); + auto const back_porch = m_reg.back_porch(); + auto const video_dimensions = m_reg.video_dimensions(); + if (hsync.raw() != 0 && vsync.raw() != 0 && video_dimensions.raw() != 0 && back_porch.raw() != 0) + { + recompute_video_timing( + hsync.hsync_on(), hsync.hsync_off(), + video_dimensions.xwidth(), back_porch.horizontal() + 2, + vsync.vsync_on(), vsync.vsync_off(), + video_dimensions.yheight(), back_porch.vertical()); + } + } + return 0; +} + + +//------------------------------------------------- +// reg_sargb_w -- sARGB register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_sargb_w(u32 chipmask, u32 regnum, u32 data) +{ + rgb_t rgbdata(data); + + // expand ARGB values into their float registers + m_reg.write_float(voodoo_regs::reg_sAlpha, float(rgbdata.a())); + m_reg.write_float(voodoo_regs::reg_sRed, float(rgbdata.r())); + m_reg.write_float(voodoo_regs::reg_sGreen, float(rgbdata.g())); + m_reg.write_float(voodoo_regs::reg_sBlue, float(rgbdata.b())); + return 0; +} + + +//------------------------------------------------- +// reg_userintr_w -- userIntr register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_userintr_w(u32 chipmask, u32 regnum, u32 data) +{ + m_renderer->wait("userIntrCMD"); + + // Bit 5 of intrCtrl enables user interrupts + if (m_reg.intr_ctrl().user_interrupt_enable()) + { + // Bits 19:12 are set to cmd 9:2, bit 11 is user interrupt flag + m_reg.clear_set(voodoo_regs::reg_intrCtrl, + reg_intr_ctrl::EXTERNAL_PIN_ACTIVE | reg_intr_ctrl::USER_INTERRUPT_TAG_MASK, + ((data << 10) & reg_intr_ctrl::USER_INTERRUPT_TAG_MASK) | reg_intr_ctrl::USER_INTERRUPT_GENERATED); + + // Signal pci interrupt handler + if (!m_pciint_cb.isnull()) + m_pciint_cb(true); + } + return 0; +} + + +//------------------------------------------------- +// reg_cmdfifo_w -- general cmdFifo-related +// register writes +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifo_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("cmdFifo write"); + m_reg.write(regnum, data); + m_cmdfifo.set_base(BIT(m_reg.read(voodoo_regs::reg_cmdFifoBaseAddr), 0, 10) << 12); + m_cmdfifo.set_end((BIT(m_reg.read(voodoo_regs::reg_cmdFifoBaseAddr), 16, 10) + 1) << 12); + m_cmdfifo.set_address_min(m_reg.read(voodoo_regs::reg_cmdFifoAMin)); + m_cmdfifo.set_address_max(m_reg.read(voodoo_regs::reg_cmdFifoAMax)); + } + return 0; +} + + +//------------------------------------------------- +// reg_cmdfifoptr_w -- cmdFifoRdPtr register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifoptr_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("cmdFifoReadPtr"); + m_reg.write(regnum, data); + m_cmdfifo.set_read_pointer(data); + } + return 0; +} + + +//------------------------------------------------- +// reg_cmdfifodepth_w -- cmdFifoDepth register +// write +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifodepth_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("cmdFifoDepth"); + m_reg.write(regnum, data); + m_cmdfifo.set_depth(data); + } + return 0; +} + + +//------------------------------------------------- +// reg_cmdfifoholes_w -- cmdFifoHoles register +// write +//------------------------------------------------- + +u32 voodoo_2_device::reg_cmdfifoholes_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_renderer->wait("cmdFifoHoles"); + m_reg.write(regnum, data); + m_cmdfifo.set_holes(data); + } + return 0; +} + + +//------------------------------------------------- +// reg_fbiinit5_7_w -- fbiInit5/6/7 register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_fbiinit5_7_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0) && m_init_enable.enable_hw_init()) + { + m_renderer->wait("fbiInit5-7"); + m_reg.write(regnum, data); + if (regnum == voodoo_regs::reg_fbiInit5 || regnum == voodoo_regs::reg_fbiInit6) + recompute_video_memory(); + m_cmdfifo.set_enable(m_reg.fbi_init7().cmdfifo_enable()); + m_cmdfifo.set_count_holes(!m_reg.fbi_init7().disable_cmdfifo_holes()); + } + return 0; +} + + +//------------------------------------------------- +// reg_draw_tri_w -- sDrawTri register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_draw_tri_w(u32 chipmask, u32 regnum, u32 data) +{ + return draw_triangle(); +} + + +//------------------------------------------------- +// reg_begin_tri_w -- sBeginTri register write +//------------------------------------------------- + +u32 voodoo_2_device::reg_begin_tri_w(u32 chipmask, u32 regnum, u32 data) +{ + return begin_triangle(); +} + + +//------------------------------------------------- +// cmdfifo_register_w -- handle a register write +// from the cmdfifo +//------------------------------------------------- + +u32 voodoo_2_device::cmdfifo_register_w(u32 offset, u32 data) +{ + u32 chipmask = chipmask_from_offset(offset); + u32 regnum = BIT(offset, 0, 8); + return m_regtable[regnum].write(*this, chipmask, regnum, data); +} + + +//------------------------------------------------- +// cmdfifo_2d_w -- handle a 2D register write +// from the cmdfifo +//------------------------------------------------- + +u32 voodoo_2_device::cmdfifo_2d_w(u32 offset, u32 data) +{ + u32 regnum = voodoo_regs::reg_bltSrcBaseAddr + offset; + return m_regtable[regnum].write(*this, 0x1, regnum, data); +} + + +//------------------------------------------------- +// vblank_start -- timer callback for the start +// of VBLANK +//------------------------------------------------- + +void voodoo_2_device::vblank_start(void *ptr, s32 param) +{ + voodoo_1_device::vblank_start(ptr, param); + + // signal PCI VBLANK rising IRQ on Voodoo-2 and later + if (m_reg.intr_ctrl().vsync_rising_enable()) + { + m_reg.clear_set(voodoo_regs::reg_intrCtrl, reg_intr_ctrl::EXTERNAL_PIN_ACTIVE, reg_intr_ctrl::VSYNC_RISING_GENERATED); + if (!m_pciint_cb.isnull()) + m_pciint_cb(true); + } +} + + +//------------------------------------------------- +// vblank_stop -- timer callback for the end of +// VBLANK +//------------------------------------------------- + +void voodoo_2_device::vblank_stop(void *ptr, s32 param) +{ + voodoo_1_device::vblank_stop(ptr, param); + + // signal PCI VBLANK falling IRQ on Voodoo-2 and later + if (m_reg.intr_ctrl().vsync_falling_enable()) + { + m_reg.clear_set(voodoo_regs::reg_intrCtrl, reg_intr_ctrl::EXTERNAL_PIN_ACTIVE, reg_intr_ctrl::VSYNC_FALLING_GENERATED); + if (!m_pciint_cb.isnull()) + m_pciint_cb(true); + } +} + + +//------------------------------------------------- +// recompute_video_memory -- compute the layout +// of video memory +//------------------------------------------------- + +void voodoo_2_device::recompute_video_memory() +{ + // for backwards compatibility, the triple-buffered bit is still supported + u32 config = m_reg.fbi_init2().enable_triple_buf(); + + // but if left at 0, configuration comes from fbiInit5 instead + if (config == 0) + config = m_reg.fbi_init5().buffer_allocation(); + + // 6-bit tile count is assembled from various bits; tiles are 32x32 + u32 xtiles = m_reg.fbi_init6().x_video_tiles_bit0() | + (m_reg.fbi_init1().x_video_tiles() << 1) | + (m_reg.fbi_init1().x_video_tiles_bit5() << 5); + recompute_video_memory_common(config, xtiles * 32); +} + + +//------------------------------------------------- +// begin_triangle - execute the 'beginTri' +// command +//------------------------------------------------- + +s32 voodoo_2_device::begin_triangle() +{ + // extract setup data + auto &sv = m_svert[2]; + sv.x = m_reg.read_float(voodoo_regs::reg_sVx); + sv.y = m_reg.read_float(voodoo_regs::reg_sVy); + sv.wb = m_reg.read_float(voodoo_regs::reg_sWb); + sv.w0 = m_reg.read_float(voodoo_regs::reg_sWtmu0); + sv.s0 = m_reg.read_float(voodoo_regs::reg_sS_W0); + sv.t0 = m_reg.read_float(voodoo_regs::reg_sT_W0); + sv.w1 = m_reg.read_float(voodoo_regs::reg_sWtmu1); + sv.s1 = m_reg.read_float(voodoo_regs::reg_sS_Wtmu1); + sv.t1 = m_reg.read_float(voodoo_regs::reg_sT_Wtmu1); + sv.a = m_reg.read_float(voodoo_regs::reg_sAlpha); + sv.r = m_reg.read_float(voodoo_regs::reg_sRed); + sv.g = m_reg.read_float(voodoo_regs::reg_sGreen); + sv.b = m_reg.read_float(voodoo_regs::reg_sBlue); + + // spread it across all three verts and reset the count + m_svert[0] = m_svert[1] = sv; + m_sverts = 1; + return 0; +} + + +//------------------------------------------------- +// draw_triangle - execute the 'DrawTri' +// command +//------------------------------------------------- + +s32 voodoo_2_device::draw_triangle() +{ + // for strip mode, shuffle vertex 1 down to 0 + if (!m_reg.setup_mode().fan_mode()) + m_svert[0] = m_svert[1]; + + // copy 2 down to 1 regardless + m_svert[1] = m_svert[2]; + + // extract setup data + auto &sv = m_svert[2]; + sv.x = m_reg.read_float(voodoo_regs::reg_sVx); + sv.y = m_reg.read_float(voodoo_regs::reg_sVy); + sv.wb = m_reg.read_float(voodoo_regs::reg_sWb); + sv.w0 = m_reg.read_float(voodoo_regs::reg_sWtmu0); + sv.s0 = m_reg.read_float(voodoo_regs::reg_sS_W0); + sv.t0 = m_reg.read_float(voodoo_regs::reg_sT_W0); + sv.w1 = m_reg.read_float(voodoo_regs::reg_sWtmu1); + sv.s1 = m_reg.read_float(voodoo_regs::reg_sS_Wtmu1); + sv.t1 = m_reg.read_float(voodoo_regs::reg_sT_Wtmu1); + sv.a = m_reg.read_float(voodoo_regs::reg_sAlpha); + sv.r = m_reg.read_float(voodoo_regs::reg_sRed); + sv.g = m_reg.read_float(voodoo_regs::reg_sGreen); + sv.b = m_reg.read_float(voodoo_regs::reg_sBlue); + + // if we have enough verts, go ahead and draw + int cycles = 0; + if (++m_sverts >= 3) + cycles = setup_and_draw_triangle(); + return cycles; +} + + +//------------------------------------------------- +// setup_and_draw_triangle - process the setup +// parameters and render the triangle +//------------------------------------------------- + +s32 voodoo_2_device::setup_and_draw_triangle() +{ + auto &sv0 = m_svert[0]; + auto &sv1 = m_svert[1]; + auto &sv2 = m_svert[2]; + + // compute the divisor, but we only need to know the sign up front + // for backface culling + float divisor = (sv0.x - sv1.x) * (sv0.y - sv2.y) - (sv0.x - sv2.x) * (sv0.y - sv1.y); + + // backface culling + auto const setup_mode = m_reg.setup_mode(); + if (setup_mode.enable_culling()) + { + int culling_sign = setup_mode.culling_sign(); + int divisor_sign = (divisor < 0); + + // if doing strips and ping pong is enabled, apply the ping pong + if (!setup_mode.fan_mode() && !setup_mode.disable_ping_pong_correction()) + culling_sign ^= (m_sverts - 3) & 1; + + // if our sign matches the culling sign, we're done for + if (divisor_sign == culling_sign) + return TRIANGLE_SETUP_CLOCKS; + } + + // compute the reciprocal now that we know we need it + divisor = 1.0f / divisor; + + // grab the X/Ys at least + m_reg.write(voodoo_regs::reg_vertexAx, s16(sv0.x * 16.0f)); + m_reg.write(voodoo_regs::reg_vertexAy, s16(sv0.y * 16.0f)); + m_reg.write(voodoo_regs::reg_vertexBx, s16(sv1.x * 16.0f)); + m_reg.write(voodoo_regs::reg_vertexBy, s16(sv1.y * 16.0f)); + m_reg.write(voodoo_regs::reg_vertexCx, s16(sv2.x * 16.0f)); + m_reg.write(voodoo_regs::reg_vertexCy, s16(sv2.y * 16.0f)); + + // compute the dx/dy values + float dx1 = sv0.y - sv2.y; + float dx2 = sv0.y - sv1.y; + float dy1 = sv0.x - sv1.x; + float dy2 = sv0.x - sv2.x; + + // set up R,G,B + float const argbzscale = 4096.0f; + float const argbzdiv = argbzscale * divisor; + if (setup_mode.setup_rgb()) + { + m_reg.write(voodoo_regs::reg_startR, s32(sv0.r * argbzscale)); + m_reg.write(voodoo_regs::reg_dRdX, s32(((sv0.r - sv1.r) * dx1 - (sv0.r - sv2.r) * dx2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_dRdY, s32(((sv0.r - sv2.r) * dy1 - (sv0.r - sv1.r) * dy2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_startG, s32(sv0.g * argbzscale)); + m_reg.write(voodoo_regs::reg_dGdX, s32(((sv0.g - sv1.g) * dx1 - (sv0.g - sv2.g) * dx2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_dGdY, s32(((sv0.g - sv2.g) * dy1 - (sv0.g - sv1.g) * dy2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_startB, s32(sv0.b * argbzscale)); + m_reg.write(voodoo_regs::reg_dBdX, s32(((sv0.b - sv1.b) * dx1 - (sv0.b - sv2.b) * dx2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_dBdY, s32(((sv0.b - sv2.b) * dy1 - (sv0.b - sv1.b) * dy2) * argbzdiv)); + } + + // set up alpha + if (setup_mode.setup_alpha()) + { + m_reg.write(voodoo_regs::reg_startA, s32(sv0.a * argbzscale)); + m_reg.write(voodoo_regs::reg_dAdX, s32(((sv0.a - sv1.a) * dx1 - (sv0.a - sv2.a) * dx2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_dAdY, s32(((sv0.a - sv2.a) * dy1 - (sv0.a - sv1.a) * dy2) * argbzdiv)); + } + + // set up Z + if (setup_mode.setup_z()) + { + m_reg.write(voodoo_regs::reg_startZ, s32(sv0.z * argbzscale)); + m_reg.write(voodoo_regs::reg_dZdX, s32(((sv0.z - sv1.z) * dx1 - (sv0.z - sv2.z) * dx2) * argbzdiv)); + m_reg.write(voodoo_regs::reg_dZdY, s32(((sv0.z - sv2.z) * dy1 - (sv0.z - sv1.z) * dy2) * argbzdiv)); + } + + // set up Wb + float const wscale = 65536.0f * 65536.0f; + float const wdiv = wscale * divisor; + auto &tmu0reg = m_tmu[0].regs(); + auto &tmu1reg = m_tmu[1].regs(); + if (setup_mode.setup_wb()) + { + s64 startw = s64(sv0.wb * wscale); + s64 dwdx = s64(((sv0.wb - sv1.wb) * dx1 - (sv0.wb - sv2.wb) * dx2) * wdiv); + s64 dwdy = s64(((sv0.wb - sv2.wb) * dy1 - (sv0.wb - sv1.wb) * dy2) * wdiv); + m_reg.write_start_w(startw); + m_reg.write_dw_dx(dwdx); + m_reg.write_dw_dy(dwdy); + tmu0reg.write_start_w(startw); + tmu0reg.write_dw_dx(dwdx); + tmu0reg.write_dw_dy(dwdy); + tmu1reg.write_start_w(startw); + tmu1reg.write_dw_dx(dwdx); + tmu1reg.write_dw_dy(dwdy); + } + + // set up W0 + if (setup_mode.setup_w0()) + { + s64 startw = s64(sv0.w0 * wscale); + s64 dwdx = s64(((sv0.w0 - sv1.w0) * dx1 - (sv0.w0 - sv2.w0) * dx2) * wdiv); + s64 dwdy = s64(((sv0.w0 - sv2.w0) * dy1 - (sv0.w0 - sv1.w0) * dy2) * wdiv); + tmu0reg.write_start_w(startw); + tmu0reg.write_dw_dx(dwdx); + tmu0reg.write_dw_dy(dwdy); + tmu1reg.write_start_w(startw); + tmu1reg.write_dw_dx(dwdx); + tmu1reg.write_dw_dy(dwdy); + } + + // set up S0,T0 + float const stscale = 65536.0f * 65536.0f; + float const stdiv = stscale * divisor; + if (setup_mode.setup_st0()) + { + s64 starts = s64(sv0.s0 * stscale); + s64 dsdx = s64(((sv0.s0 - sv1.s0) * dx1 - (sv0.s0 - sv2.s0) * dx2) * stdiv); + s64 dsdy = s64(((sv0.s0 - sv2.s0) * dy1 - (sv0.s0 - sv1.s0) * dy2) * stdiv); + s64 startt = s64(sv0.t0 * stscale); + s64 dtdx = s64(((sv0.t0 - sv1.t0) * dx1 - (sv0.t0 - sv2.t0) * dx2) * stdiv); + s64 dtdy = s64(((sv0.t0 - sv2.t0) * dy1 - (sv0.t0 - sv1.t0) * dy2) * stdiv); + tmu0reg.write_start_s(starts); + tmu0reg.write_start_t(startt); + tmu0reg.write_ds_dx(dsdx); + tmu0reg.write_dt_dx(dtdx); + tmu0reg.write_ds_dy(dsdy); + tmu0reg.write_dt_dy(dtdy); + tmu1reg.write_start_s(starts); + tmu1reg.write_start_t(startt); + tmu1reg.write_ds_dx(dsdx); + tmu1reg.write_dt_dx(dtdx); + tmu1reg.write_ds_dy(dsdy); + tmu1reg.write_dt_dy(dtdy); + } + + // set up W1 + if (setup_mode.setup_w1()) + { + s64 startw = s64(sv0.w1 * wscale); + s64 dwdx = s64(((sv0.w1 - sv1.w1) * dx1 - (sv0.w1 - sv2.w1) * dx2) * wdiv); + s64 dwdy = s64(((sv0.w1 - sv2.w1) * dy1 - (sv0.w1 - sv1.w1) * dy2) * wdiv); + tmu1reg.write_start_w(startw); + tmu1reg.write_dw_dx(dwdx); + tmu1reg.write_dw_dy(dwdy); + } + + // set up S1,T1 + if (setup_mode.setup_st1()) + { + s64 starts = s64(sv0.s1 * stscale); + s64 dsdx = s64(((sv0.s1 - sv1.s1) * dx1 - (sv0.s1 - sv2.s1) * dx2) * stdiv); + s64 dsdy = s64(((sv0.s1 - sv2.s1) * dy1 - (sv0.s1 - sv1.s1) * dy2) * stdiv); + s64 startt = s64(sv0.t1 * stscale); + s64 dtdx = s64(((sv0.t1 - sv1.t1) * dx1 - (sv0.t1 - sv2.t1) * dx2) * stdiv); + s64 dtdy = s64(((sv0.t1 - sv2.t1) * dy1 - (sv0.t1 - sv1.t1) * dy2) * stdiv); + tmu1reg.write_start_s(starts); + tmu1reg.write_start_t(startt); + tmu1reg.write_ds_dx(dsdx); + tmu1reg.write_dt_dx(dtdx); + tmu1reg.write_ds_dy(dsdy); + tmu1reg.write_dt_dy(dtdy); + } + + // draw the triangle + return triangle(); +} + + +//************************************************************************** +// VOODOO 2 REGISTER MAP +//************************************************************************** + +#define REGISTER_ENTRY(name, reader, writer, bits, chips, sync, fifo) \ + { static_register_table_entry::make_mask(bits), register_table_entry::CHIPMASK_##chips | register_table_entry::SYNC_##sync | register_table_entry::FIFO_##fifo, #name, &voodoo_2_device::reg_##writer##_w, &voodoo_2_device::reg_##reader##_r }, + +#define RESERVED_ENTRY REGISTER_ENTRY(reserved, invalid, invalid, 32, FBI, NOSYNC, FIFO) + +#define RESERVED_ENTRY_x8 RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY + +static_register_table_entry const voodoo_2_device::s_register_table[256] = +{ + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(status, status, invalid, 32, FBI, NOSYNC, FIFO) // 000 + REGISTER_ENTRY(intrCtrl, passive, intrctrl, 32, FBI, NOSYNC, NOFIFO) // 004 - cmdFIFO mode + REGISTER_ENTRY(vertexAx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 008 + REGISTER_ENTRY(vertexAy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 00c + REGISTER_ENTRY(vertexBx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 010 + REGISTER_ENTRY(vertexBy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 014 + REGISTER_ENTRY(vertexCx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 018 + REGISTER_ENTRY(vertexCy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 01c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(startR, invalid, passive, 24, FBI, NOSYNC, FIFO) // 020 + REGISTER_ENTRY(startG, invalid, passive, 24, FBI, NOSYNC, FIFO) // 024 + REGISTER_ENTRY(startB, invalid, passive, 24, FBI, NOSYNC, FIFO) // 028 + REGISTER_ENTRY(startZ, invalid, passive, 32, FBI, NOSYNC, FIFO) // 02c + REGISTER_ENTRY(startA, invalid, passive, 24, FBI, NOSYNC, FIFO) // 030 + REGISTER_ENTRY(startS, invalid, starts, 32, TREX, NOSYNC, FIFO) // 034 + REGISTER_ENTRY(startT, invalid, startt, 32, TREX, NOSYNC, FIFO) // 038 + REGISTER_ENTRY(startW, invalid, startw, 32, FBI_TREX, NOSYNC, FIFO) // 03c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 040 + REGISTER_ENTRY(dGdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 044 + REGISTER_ENTRY(dBdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 048 + REGISTER_ENTRY(dZdX, invalid, passive, 32, FBI, NOSYNC, FIFO) // 04c + REGISTER_ENTRY(dAdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 050 + REGISTER_ENTRY(dSdX, invalid, dsdx, 32, TREX, NOSYNC, FIFO) // 054 + REGISTER_ENTRY(dTdX, invalid, dtdx, 32, TREX, NOSYNC, FIFO) // 058 + REGISTER_ENTRY(dWdX, invalid, dwdx, 32, FBI_TREX, NOSYNC, FIFO) // 05c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 060 + REGISTER_ENTRY(dGdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 064 + REGISTER_ENTRY(dBdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 068 + REGISTER_ENTRY(dZdY, invalid, passive, 32, FBI, NOSYNC, FIFO) // 06c + REGISTER_ENTRY(dAdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 070 + REGISTER_ENTRY(dSdY, invalid, dsdy, 32, TREX, NOSYNC, FIFO) // 074 + REGISTER_ENTRY(dTdY, invalid, dtdy, 32, TREX, NOSYNC, FIFO) // 078 + REGISTER_ENTRY(dWdY, invalid, dwdy, 32, FBI_TREX, NOSYNC, FIFO) // 07c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(triangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 080 + RESERVED_ENTRY // 084 + REGISTER_ENTRY(fvertexAx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 088 + REGISTER_ENTRY(fvertexAy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 08c + REGISTER_ENTRY(fvertexBx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 090 + REGISTER_ENTRY(fvertexBy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 094 + REGISTER_ENTRY(fvertexCx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 098 + REGISTER_ENTRY(fvertexCy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 09c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fstartR, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a0 + REGISTER_ENTRY(fstartG, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a4 + REGISTER_ENTRY(fstartB, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a8 + REGISTER_ENTRY(fstartZ, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ac + REGISTER_ENTRY(fstartA, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0b0 + REGISTER_ENTRY(fstartS, invalid, fstarts, 32, TREX, NOSYNC, FIFO) // 0b4 + REGISTER_ENTRY(fstartT, invalid, fstartt, 32, TREX, NOSYNC, FIFO) // 0b8 + REGISTER_ENTRY(fstartW, invalid, fstartw, 32, FBI_TREX, NOSYNC, FIFO) // 0bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c0 + REGISTER_ENTRY(fdGdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c4 + REGISTER_ENTRY(fdBdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c8 + REGISTER_ENTRY(fdZdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0cc + REGISTER_ENTRY(fdAdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0d0 + REGISTER_ENTRY(fdSdX, invalid, fdsdx, 32, TREX, NOSYNC, FIFO) // 0d4 + REGISTER_ENTRY(fdTdX, invalid, fdtdx, 32, TREX, NOSYNC, FIFO) // 0d8 + REGISTER_ENTRY(fdWdX, invalid, fdwdx, 32, FBI_TREX, NOSYNC, FIFO) // 0dc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e0 + REGISTER_ENTRY(fdGdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e4 + REGISTER_ENTRY(fdBdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e8 + REGISTER_ENTRY(fdZdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ec + REGISTER_ENTRY(fdAdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0f0 + REGISTER_ENTRY(fdSdY, invalid, fdsdy, 32, TREX, NOSYNC, FIFO) // 0f4 + REGISTER_ENTRY(fdTdY, invalid, fdtdy, 32, TREX, NOSYNC, FIFO) // 0f8 + REGISTER_ENTRY(fdWdY, invalid, fdwdy, 32, FBI_TREX, NOSYNC, FIFO) // 0fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(ftriangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 100 + REGISTER_ENTRY(fbzColorPath, passive, passive, 30, FBI_TREX, NOSYNC, FIFO) // 104 + REGISTER_ENTRY(fogMode, passive, passive, 8, FBI_TREX, NOSYNC, FIFO) // 108 + REGISTER_ENTRY(alphaMode, passive, passive, 32, FBI_TREX, NOSYNC, FIFO) // 10c + REGISTER_ENTRY(fbzMode, passive, passive, 22, FBI_TREX, SYNC, FIFO) // 110 + REGISTER_ENTRY(lfbMode, passive, passive, 17, FBI_TREX, SYNC, FIFO) // 114 + REGISTER_ENTRY(clipLeftRight, passive, passive, 28, FBI_TREX, SYNC, FIFO) // 118 + REGISTER_ENTRY(clipLowYHighY, passive, passive, 28, FBI_TREX, SYNC, FIFO) // 11c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nopCMD, invalid, nop, 2, FBI_TREX, SYNC, FIFO) // 120 + REGISTER_ENTRY(fastfillCMD, invalid, fastfill, 0, FBI, SYNC, FIFO) // 124 + REGISTER_ENTRY(swapbufferCMD, invalid, swapbuffer, 10, FBI, SYNC, FIFO) // 128 + REGISTER_ENTRY(fogColor, invalid, passive, 24, FBI, SYNC, FIFO) // 12c + REGISTER_ENTRY(zaColor, invalid, passive, 32, FBI, SYNC, FIFO) // 130 + REGISTER_ENTRY(chromaKey, invalid, passive, 24, FBI, SYNC, FIFO) // 134 + REGISTER_ENTRY(chromaRange, invalid, passive, 29, FBI, SYNC, FIFO) // 138 + REGISTER_ENTRY(userIntrCMD, invalid, userintr, 10, FBI, SYNC, FIFO) // 13c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(stipple, passive, passive, 32, FBI, SYNC, FIFO) // 140 + REGISTER_ENTRY(color0, passive, passive, 32, FBI, SYNC, FIFO) // 144 + REGISTER_ENTRY(color1, passive, passive, 32, FBI, SYNC, FIFO) // 148 + REGISTER_ENTRY(fbiPixelsIn, stats, invalid, 24, FBI, NA, NA) // 14c + REGISTER_ENTRY(fbiChromaFail, stats, invalid, 24, FBI, NA, NA) // 150 + REGISTER_ENTRY(fbiZfuncFail, stats, invalid, 24, FBI, NA, NA) // 154 + REGISTER_ENTRY(fbiAfuncFail, stats, invalid, 24, FBI, NA, NA) // 158 + REGISTER_ENTRY(fbiPixelsOut, stats, invalid, 24, FBI, NA, NA) // 15c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[0], invalid, fogtable, 32, FBI, SYNC, FIFO) // 160 + REGISTER_ENTRY(fogTable[1], invalid, fogtable, 32, FBI, SYNC, FIFO) // 164 + REGISTER_ENTRY(fogTable[2], invalid, fogtable, 32, FBI, SYNC, FIFO) // 168 + REGISTER_ENTRY(fogTable[3], invalid, fogtable, 32, FBI, SYNC, FIFO) // 16c + REGISTER_ENTRY(fogTable[4], invalid, fogtable, 32, FBI, SYNC, FIFO) // 170 + REGISTER_ENTRY(fogTable[5], invalid, fogtable, 32, FBI, SYNC, FIFO) // 174 + REGISTER_ENTRY(fogTable[6], invalid, fogtable, 32, FBI, SYNC, FIFO) // 178 + REGISTER_ENTRY(fogTable[7], invalid, fogtable, 32, FBI, SYNC, FIFO) // 17c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[8], invalid, fogtable, 32, FBI, SYNC, FIFO) // 180 + REGISTER_ENTRY(fogTable[9], invalid, fogtable, 32, FBI, SYNC, FIFO) // 184 + REGISTER_ENTRY(fogTable[10], invalid, fogtable, 32, FBI, SYNC, FIFO) // 188 + REGISTER_ENTRY(fogTable[11], invalid, fogtable, 32, FBI, SYNC, FIFO) // 18c + REGISTER_ENTRY(fogTable[12], invalid, fogtable, 32, FBI, SYNC, FIFO) // 190 + REGISTER_ENTRY(fogTable[13], invalid, fogtable, 32, FBI, SYNC, FIFO) // 194 + REGISTER_ENTRY(fogTable[14], invalid, fogtable, 32, FBI, SYNC, FIFO) // 198 + REGISTER_ENTRY(fogTable[15], invalid, fogtable, 32, FBI, SYNC, FIFO) // 19c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[16], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a0 + REGISTER_ENTRY(fogTable[17], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a4 + REGISTER_ENTRY(fogTable[18], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a8 + REGISTER_ENTRY(fogTable[19], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1ac + REGISTER_ENTRY(fogTable[20], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b0 + REGISTER_ENTRY(fogTable[21], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b4 + REGISTER_ENTRY(fogTable[22], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b8 + REGISTER_ENTRY(fogTable[23], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[24], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c0 + REGISTER_ENTRY(fogTable[25], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c4 + REGISTER_ENTRY(fogTable[26], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c8 + REGISTER_ENTRY(fogTable[27], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1cc + REGISTER_ENTRY(fogTable[28], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d0 + REGISTER_ENTRY(fogTable[29], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d4 + REGISTER_ENTRY(fogTable[30], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d8 + REGISTER_ENTRY(fogTable[31], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1dc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(cmdFifoBaseAddr, passive, cmdfifo, 26, FBI, SYNC, NOFIFO) // 1e0 - cmdFIFO mode + REGISTER_ENTRY(cmdFifoBump, passive, unimplemented,16,FBI, SYNC, NOFIFO) // 1e4 - cmdFIFO mode + REGISTER_ENTRY(cmdFifoRdPtr, cmdfifoptr, cmdfifoptr, 32, FBI, SYNC, NOFIFO) // 1e8 - cmdFIFO mode + REGISTER_ENTRY(cmdFifoAMin, passive, cmdfifo, 32, FBI, SYNC, NOFIFO) // 1ec - cmdFIFO mode + REGISTER_ENTRY(cmdFifoAMax, passive, cmdfifo, 32, FBI, SYNC, NOFIFO) // 1f0 - cmdFIFO mode + REGISTER_ENTRY(cmdFifoDepth, cmdfifodepth,cmdfifodepth,16, FBI, SYNC, NOFIFO) // 1f4 - cmdFIFO mode + REGISTER_ENTRY(cmdFifoHoles, cmdfifoholes,cmdfifoholes,16, FBI, SYNC, NOFIFO) // 1f8 - cmdFIFO mode + RESERVED_ENTRY // 1fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fbiInit4, passive, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 200 + REGISTER_ENTRY(vRetrace, vretrace, invalid, 13, FBI, NA, NA) // 204 + REGISTER_ENTRY(backPorch, passive, video2, 25, FBI, NOSYNC, NOFIFO) // 208 + REGISTER_ENTRY(videoDimensions, passive, video2, 27, FBI, NOSYNC, NOFIFO) // 20c + REGISTER_ENTRY(fbiInit0, passive, fbiinit, 31, FBI, NOSYNC, NOFIFO) // 210 + REGISTER_ENTRY(fbiInit1, passive, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 214 + REGISTER_ENTRY(fbiInit2, fbiinit2, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 218 + REGISTER_ENTRY(fbiInit3, passive, fbiinit, 32, FBI, NOSYNC, NOFIFO) // 21c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(hSync, invalid, video2, 27, FBI, NOSYNC, NOFIFO) // 220 + REGISTER_ENTRY(vSync, invalid, video2, 29, FBI, NOSYNC, NOFIFO) // 224 + REGISTER_ENTRY(clutData, invalid, clut, 30, FBI, NOSYNC, NOFIFO) // 228 + REGISTER_ENTRY(dacData, invalid, dac, 14, FBI, NOSYNC, NOFIFO) // 22c + REGISTER_ENTRY(maxRgbDelta, invalid, unimplemented,24,FBI, NOSYNC, NOFIFO) // 230 + REGISTER_ENTRY(hBorder, invalid, unimplemented,25,FBI, NOSYNC, NOFIFO) // 234 - cmdFIFO mode + REGISTER_ENTRY(vBorder, invalid, unimplemented,25,FBI, NOSYNC, NOFIFO) // 238 - cmdFIFO mode + REGISTER_ENTRY(borderColor, invalid, unimplemented,24,FBI, NOSYNC, NOFIFO) // 23c - cmdFIFO mode + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(hvRetrace, hvretrace, invalid, 27, FBI, NA, NA) // 240 + REGISTER_ENTRY(fbiInit5, passive, fbiinit5_7, 32, FBI, NOSYNC, NOFIFO) // 244 - cmdFIFO mode + REGISTER_ENTRY(fbiInit6, passive, fbiinit5_7, 31, FBI, NOSYNC, NOFIFO) // 248 - cmdFIFO mode + REGISTER_ENTRY(fbiInit7, passive, fbiinit5_7, 28, FBI, NOSYNC, NOFIFO) // 24c - cmdFIFO mode + RESERVED_ENTRY // 250 + RESERVED_ENTRY // 254 + REGISTER_ENTRY(fbiSwapHistory, passive, invalid, 32, FBI, NA, NA) // 258 + REGISTER_ENTRY(fbiTrianglesOut, passive, invalid, 24, FBI, NA, NA) // 25c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sSetupMode, invalid, passive, 20, FBI, NOSYNC, FIFO) // 260 + REGISTER_ENTRY(sVx, invalid, passive, 32, FBI, NOSYNC, FIFO) // 264 + REGISTER_ENTRY(sVy, invalid, passive, 32, FBI, NOSYNC, FIFO) // 268 + REGISTER_ENTRY(sARGB, invalid, sargb, 32, FBI, NOSYNC, FIFO) // 26c + REGISTER_ENTRY(sRed, invalid, passive, 32, FBI, NOSYNC, FIFO) // 270 + REGISTER_ENTRY(sGreen, invalid, passive, 32, FBI, NOSYNC, FIFO) // 274 + REGISTER_ENTRY(sBlue, invalid, passive, 32, FBI, NOSYNC, FIFO) // 278 + REGISTER_ENTRY(sAlpha, invalid, passive, 32, FBI, NOSYNC, FIFO) // 27c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sVz, invalid, passive, 32, FBI, NOSYNC, FIFO) // 280 + REGISTER_ENTRY(sWb, invalid, passive, 32, FBI, NOSYNC, FIFO) // 284 + REGISTER_ENTRY(sWtmu0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 288 + REGISTER_ENTRY(sS_W0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 28c + REGISTER_ENTRY(sT_W0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 290 + REGISTER_ENTRY(sWtmu1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 294 + REGISTER_ENTRY(sS_W1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 298 + REGISTER_ENTRY(sT_W1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 29c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sDrawTriCMD, invalid, draw_tri, 1, FBI, NOSYNC, FIFO) // 2a0 + REGISTER_ENTRY(sBeginTriCMD, invalid, begin_tri, 1, FBI, NOSYNC, FIFO) // 2a4 + RESERVED_ENTRY // 2a8 + RESERVED_ENTRY // 2ac + RESERVED_ENTRY // 2b0 + RESERVED_ENTRY // 2b4 + RESERVED_ENTRY // 2b8 + RESERVED_ENTRY // 2bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(bltSrcBaseAddr, passive, passive, 22, FBI, NOSYNC, FIFO) // 2c0 + REGISTER_ENTRY(bltDstBaseAddr, passive, passive, 22, FBI, NOSYNC, FIFO) // 2c4 + REGISTER_ENTRY(bltXYStrides, passive, passive, 28, FBI, NOSYNC, FIFO) // 2c8 + REGISTER_ENTRY(bltSrcChromaRange,passive, passive, 32, FBI, NOSYNC, FIFO) // 2cc + REGISTER_ENTRY(bltDstChromaRange,passive, passive, 32, FBI, NOSYNC, FIFO) // 2d0 + REGISTER_ENTRY(bltClipX, passive, passive, 26, FBI, NOSYNC, FIFO) // 2d4 + REGISTER_ENTRY(bltClipY, passive, passive, 26, FBI, NOSYNC, FIFO) // 2d8 + RESERVED_ENTRY // 2dc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(bltSrcXY, passive, passive, 27, FBI, NOSYNC, FIFO) // 2e0 + REGISTER_ENTRY(bltDstXY, passive, passive, 32, FBI, NOSYNC, FIFO) // 2e4 + REGISTER_ENTRY(bltSize, passive, passive, 32, FBI, NOSYNC, FIFO) // 2e8 + REGISTER_ENTRY(bltRop, passive, passive, 16, FBI, NOSYNC, FIFO) // 2ec + REGISTER_ENTRY(bltColor, passive, passive, 32, FBI, NOSYNC, FIFO) // 2f0 + RESERVED_ENTRY // 2f4 + REGISTER_ENTRY(bltCommand, passive, unimplemented,32,FBI, NOSYNC, FIFO) // 2f8 + REGISTER_ENTRY(bltData, invalid, passive, 32, FBI, NOSYNC, FIFO) // 2fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(textureMode, invalid, texture, 32, TREX, NOSYNC, FIFO) // 300 + REGISTER_ENTRY(tLOD, invalid, texture, 32, TREX, NOSYNC, FIFO) // 304 + REGISTER_ENTRY(tDetail, invalid, texture, 22, TREX, NOSYNC, FIFO) // 308 + REGISTER_ENTRY(texBaseAddr, invalid, texture, 19, TREX, NOSYNC, FIFO) // 30c + REGISTER_ENTRY(texBaseAddr_1, invalid, texture, 19, TREX, NOSYNC, FIFO) // 310 + REGISTER_ENTRY(texBaseAddr_2, invalid, texture, 19, TREX, NOSYNC, FIFO) // 314 + REGISTER_ENTRY(texBaseAddr_3_8, invalid, texture, 19, TREX, NOSYNC, FIFO) // 318 + REGISTER_ENTRY(trexInit0, invalid, passive, 32, TREX, SYNC, FIFO) // 31c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(trexInit1, invalid, passive, 32, TREX, SYNC, FIFO) // 320 + REGISTER_ENTRY(nccTable0[0], invalid, palette, 32, TREX, SYNC, FIFO) // 324 + REGISTER_ENTRY(nccTable0[1], invalid, palette, 32, TREX, SYNC, FIFO) // 328 + REGISTER_ENTRY(nccTable0[2], invalid, palette, 32, TREX, SYNC, FIFO) // 32c + REGISTER_ENTRY(nccTable0[3], invalid, palette, 32, TREX, SYNC, FIFO) // 330 + REGISTER_ENTRY(nccTable0[4], invalid, palette, 32, TREX, SYNC, FIFO) // 334 + REGISTER_ENTRY(nccTable0[5], invalid, palette, 32, TREX, SYNC, FIFO) // 338 + REGISTER_ENTRY(nccTable0[6], invalid, palette, 32, TREX, SYNC, FIFO) // 33c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable0[7], invalid, palette, 32, TREX, SYNC, FIFO) // 340 + REGISTER_ENTRY(nccTable0[8], invalid, palette, 32, TREX, SYNC, FIFO) // 344 + REGISTER_ENTRY(nccTable0[9], invalid, palette, 32, TREX, SYNC, FIFO) // 348 + REGISTER_ENTRY(nccTable0[10], invalid, palette, 32, TREX, SYNC, FIFO) // 34c + REGISTER_ENTRY(nccTable0[11], invalid, palette, 32, TREX, SYNC, FIFO) // 350 + REGISTER_ENTRY(nccTable1[0], invalid, palette, 32, TREX, SYNC, FIFO) // 354 + REGISTER_ENTRY(nccTable1[1], invalid, palette, 32, TREX, SYNC, FIFO) // 358 + REGISTER_ENTRY(nccTable1[2], invalid, palette, 32, TREX, SYNC, FIFO) // 35c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[3], invalid, palette, 32, TREX, SYNC, FIFO) // 360 + REGISTER_ENTRY(nccTable1[4], invalid, palette, 32, TREX, SYNC, FIFO) // 364 + REGISTER_ENTRY(nccTable1[5], invalid, palette, 32, TREX, SYNC, FIFO) // 368 + REGISTER_ENTRY(nccTable1[6], invalid, palette, 32, TREX, SYNC, FIFO) // 36c + REGISTER_ENTRY(nccTable1[7], invalid, palette, 32, TREX, SYNC, FIFO) // 370 + REGISTER_ENTRY(nccTable1[8], invalid, palette, 32, TREX, SYNC, FIFO) // 374 + REGISTER_ENTRY(nccTable1[9], invalid, palette, 32, TREX, SYNC, FIFO) // 378 + REGISTER_ENTRY(nccTable1[10], invalid, palette, 32, TREX, SYNC, FIFO) // 37c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[11], invalid, palette, 32, TREX, SYNC, FIFO) // 380 + RESERVED_ENTRY // 384 + RESERVED_ENTRY // 388 + RESERVED_ENTRY // 38c + RESERVED_ENTRY // 390 + RESERVED_ENTRY // 394 + RESERVED_ENTRY // 398 + RESERVED_ENTRY // 39c + + RESERVED_ENTRY_x8 // 3a0-3bc + RESERVED_ENTRY_x8 // 3c0-3dc + RESERVED_ENTRY_x8 // 3e0-3fc +}; diff --git a/src/devices/video/voodoo_2.h b/src/devices/video/voodoo_2.h new file mode 100644 index 00000000000..9a6f0c9ef01 --- /dev/null +++ b/src/devices/video/voodoo_2.h @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_2.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#ifndef MAME_VIDEO_VOODOO_2_H +#define MAME_VIDEO_VOODOO_2_H + +#pragma once + +#include "voodoo.h" + + +// forward declarations +class voodoo_2_device; + + +//************************************************************************** +// INTERNAL CLASSES +//************************************************************************** + +namespace voodoo +{ + +// ======================> command_fifo + +// command_fifo is a more intelligent FIFO that was introduced with the Voodoo-2 +class command_fifo +{ +public: + // construction + command_fifo(voodoo_2_device &device); + + // initialization + void init(u8 *ram, u32 size) { m_ram = (u32 *)ram; m_mask = (size / 4) - 1; } + + // state saving + void register_save(save_proxy &save); + + // getters + bool enabled() const { return m_enable; } + u32 address_min() const { return m_address_min; } + u32 address_max() const { return m_address_max; } + u32 read_pointer() const { return m_read_index * 4; } + u32 depth() const { return m_depth; } + u32 holes() const { return m_holes; } + + // setters + void set_enable(bool enabled) { m_enable = enabled; } + void set_count_holes(bool count) { m_count_holes = count; } + void set_base(u32 base) { m_ram_base = base; } + void set_end(u32 end) { m_ram_end = end; } + void set_size(u32 size) { m_ram_end = m_ram_base + size; } + void set_read_pointer(u32 ptr) { m_read_index = ptr / 4; } + void set_address_min(u32 addr) { m_address_min = addr; } + void set_address_max(u32 addr) { m_address_max = addr; } + void set_depth(u32 depth) { m_depth = depth; } + void set_holes(u32 holes) { m_holes = holes; } + + // operations + u32 execute_if_ready(); + + // write to the FIFO if within the address range + bool write_if_in_range(offs_t addr, u32 data) + { + if (m_enable && addr >= m_ram_base && addr < m_ram_end) + { + write(addr, data); + return true; + } + return false; + } + + // write directly to the FIFO, relative to the base + void write_direct(offs_t offset, u32 data) + { + write(m_ram_base + offset * 4, data); + } + +private: + // internal helpers + void consume(u32 words) { m_read_index += words; m_depth -= words; } + u32 peek_next() { return m_ram[m_read_index & m_mask]; } + u32 read_next() { u32 result = peek_next(); consume(1); return result; } + float read_next_float() { float result = *(float *)&m_ram[m_read_index & m_mask]; consume(1); return result; } + + // internal operations + u32 words_needed(u32 command); + void write(offs_t addr, u32 data); + + // packet handlers + using packet_handler = u32 (command_fifo::*)(u32); + u32 packet_type_0(u32 command); + u32 packet_type_1(u32 command); + u32 packet_type_2(u32 command); + u32 packet_type_3(u32 command); + u32 packet_type_4(u32 command); + u32 packet_type_5(u32 command); + u32 packet_type_unknown(u32 command); + + // internal state + voodoo_2_device &m_device; // reference to our device + u32 *m_ram; // base of RAM + u32 m_mask; // mask for RAM accesses + bool m_enable; // enabled? + bool m_count_holes; // count holes? + u32 m_ram_base; // base address in framebuffer RAM + u32 m_ram_end; // end address in framebuffer RAM + u32 m_read_index; // current read index into 32-bit RAM + u32 m_address_min; // minimum address + u32 m_address_max; // maximum address + u32 m_depth; // current depth + u32 m_holes; // number of holes + + static packet_handler s_packet_handler[8]; +}; + + +// ======================> setup_vertex + +// setup_vertex a set of coordinates managed by the triangle setup engine +// that was introduced with the Voodoo-2 +struct setup_vertex +{ + // state saving + void register_save(save_proxy &save) + { + save.save_item(NAME(x)); + save.save_item(NAME(y)); + save.save_item(NAME(z)); + save.save_item(NAME(wb)); + save.save_item(NAME(r)); + save.save_item(NAME(g)); + save.save_item(NAME(b)); + save.save_item(NAME(a)); + save.save_item(NAME(s0)); + save.save_item(NAME(t0)); + save.save_item(NAME(w0)); + save.save_item(NAME(s1)); + save.save_item(NAME(t1)); + save.save_item(NAME(w1)); + } + + float x, y; // X, Y coordinates + float z, wb; // Z and broadcast W values + float r, g, b, a; // A, R, G, B values + float s0, t0, w0; // W, S, T for TMU 0 + float s1, t1, w1; // W, S, T for TMU 1 +}; + +} + + +//************************************************************************** +// VOODOO 2 DEVICE +//************************************************************************** + +DECLARE_DEVICE_TYPE(VOODOO_2, voodoo_2_device) + +// ======================> voodoo_2_device + +// voodoo_2_device represents the 2nd generation of 3dfx Voodoo Graphics devices; +// these are pretty similar in architecture to the first generation, with the +// addition of command FIFOs and several other smaller features +class voodoo_2_device : public voodoo_1_device +{ + friend class voodoo::command_fifo; + +protected: + // internal construction + voodoo_2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model); + +public: + // nominal clock value + static constexpr u32 NOMINAL_CLOCK = 90'000'000; + + // construction + voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + voodoo_2_device(mconfig, VOODOO_2, tag, owner, clock, voodoo::voodoo_model::VOODOO_2) { } + + // address map and read/write helpers + virtual void core_map(address_map &map) override; + virtual u32 read(offs_t offset, u32 mem_mask = ~0) override; + virtual void write(offs_t offset, u32 data, u32 mem_mask = ~0) override; + +protected: + // device-level overrides + virtual void device_start() override; + + // system management + virtual void soft_reset() override; + virtual void register_save(voodoo::save_proxy &save, u32 total_allocation) override; + + // mapped writes + void map_register_w(offs_t offset, u32 data, u32 mem_mask = ~0); + + // read/write and FIFO helpers + virtual u32 execute_fifos() override; + + // register read accessors + u32 reg_hvretrace_r(u32 chipmask, u32 regnum); + u32 reg_cmdfifoptr_r(u32 chipmask, u32 regnum); + u32 reg_cmdfifodepth_r(u32 chipmask, u32 regnum); + u32 reg_cmdfifoholes_r(u32 chipmask, u32 regnum); + + // register write accessors + u32 reg_intrctrl_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_video2_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_sargb_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_userintr_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_cmdfifo_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_cmdfifoptr_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_cmdfifodepth_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_cmdfifoholes_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_fbiinit5_7_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_draw_tri_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_begin_tri_w(u32 chipmask, u32 regnum, u32 data); + + // command FIFO-specific write handlers + virtual u32 cmdfifo_register_w(u32 offset, u32 data); + virtual u32 cmdfifo_2d_w(u32 offset, u32 data); + + // VBLANK timing + virtual void vblank_start(void *ptr, s32 param) override; + virtual void vblank_stop(void *ptr, s32 param) override; + + // video timing and updates + virtual void recompute_video_memory() override; + + // rendering + s32 begin_triangle(); + s32 draw_triangle(); + s32 setup_and_draw_triangle(); + + // internal state + u8 m_sverts = 0; // number of vertices ready + voodoo::setup_vertex m_svert[3]; // 3 setup vertices + voodoo::command_fifo m_cmdfifo; // command FIFO + + // register table + static voodoo::static_register_table_entry const s_register_table[256]; +}; + +#endif // MAME_VIDEO_VOODOO_2_H diff --git a/src/devices/video/voodoo_banshee.cpp b/src/devices/video/voodoo_banshee.cpp new file mode 100644 index 00000000000..6ead666df8f --- /dev/null +++ b/src/devices/video/voodoo_banshee.cpp @@ -0,0 +1,1907 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_banshee.cpp + + 3dfx Voodoo Graphics SST-1/2 emulator. + +**************************************************************************** + + Specs: + + Voodoo Banshee (h3): + Integrated VGA support + 2,4,8MB frame buffer RAM + 90MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 32 pixels/clock + + Voodoo 3 ("Avenger"/h4): + Integrated VGA support + 4,8,16MB frame buffer RAM + 143MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 32 pixels/clock + +**************************************************************************/ + +#include "emu.h" +#include "voodoo_banshee.h" + +using namespace voodoo; + + + +//************************************************************************** +// INTERNAL CLASSES +//************************************************************************** + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void banshee_2d_regs::register_save(save_proxy &save) +{ + save.save_item(NAME(m_regs)); +} + + +//------------------------------------------------- +// s_names - table of register names +//------------------------------------------------- + +char const *const banshee_2d_regs::s_names[0x20] = +{ + "reserved00", "reserved04", "clip0Min", "clip0Max", + "dstBaseAddr", "dstFormat", "srcColorkeyMin", "srcColorkeyMax", + "dstColorkeyMin", "dstColorkeyMax", "bresError0", "bresError1", + "rop", "srcBaseAddr", "commandExtra", "lineStipple", + "lineStyle", "pattern0Alias", "pattern1Alias", "clip1Min", + "clip1Max", "srcFormat", "srcSize", "srcXY", + "colorBack", "colorFore", "dstSize", "dstXY", + "command", "reserved74", "reserved78", "reserved7c" +}; + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void banshee_io_regs::register_save(save_proxy &save) +{ + save.save_item(NAME(m_regs)); +} + + +//------------------------------------------------- +// s_names - table of register names +//------------------------------------------------- + +char const *const banshee_io_regs::s_names[0x40] = +{ + "status", "pciInit0", "sipMonitor", "lfbMemoryConfig", + "miscInit0", "miscInit1", "dramInit0", "dramInit1", + "agpInit", "tmuGbeInit", "vgaInit0", "vgaInit1", + "dramCommand", "dramData", "reserved38", "reserved3c", + "pllCtrl0", "pllCtrl1", "pllCtrl2", "dacMode", + "dacAddr", "dacData", "rgbMaxDelta", "vidProcCfg", + "hwCurPatAddr", "hwCurLoc", "hwCurC0", "hwCurC1", + "vidInFormat", "vidInStatus", "vidSerialParallelPort", "vidInXDecimDeltas", + "vidInDecimInitErrs", "vidInYDecimDeltas", "vidPixelBufThold", "vidChromaMin", + "vidChromaMax", "vidCurrentLine", "vidScreenSize", "vidOverlayStartCoords", + "vidOverlayEndScreenCoord", "vidOverlayDudx", "vidOverlayDudxOffsetSrcWidth", "vidOverlayDvdy", + "vga[b0]", "vga[b4]", "vga[b8]", "vga[bc]", + "vga[c0]", "vga[c4]", "vga[c8]", "vga[cc]", + "vga[d0]", "vga[d4]", "vga[d8]", "vga[dc]", + "vidOverlayDvdyOffset", "vidDesktopStartAddr", "vidDesktopOverlayStride", "vidInAddr0", + "vidInAddr1", "vidInAddr2", "vidInStride", "vidCurrOverlayStartAddr" +}; + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void banshee_cmd_agp_regs::register_save(save_proxy &save) +{ + save.save_item(NAME(m_regs)); +} + + +//------------------------------------------------- +// s_names - table of register names +//------------------------------------------------- + +char const *const banshee_cmd_agp_regs::s_names[0x80] = +{ + "agpReqSize", "agpHostAddressLow", "agpHostAddressHigh", "agpGraphicsAddress", + "agpGraphicsStride", "agpMoveCMD", "reserved18", "reserved1c", + "cmdBaseAddr0", "cmdBaseSize0", "cmdBump0", "cmdRdPtrL0", + "cmdRdPtrH0", "cmdAMin0", "reserved38", "cmdAMax0", + "reserved40", "cmdFifoDepth0", "cmdHoleCnt0", "reserved4c", + "cmdBaseAddr1", "cmdBaseSize1", "cmdBump1", "cmdRdPtrL1", + "cmdRdPtrH1", "cmdAMin1", "reserved68", "cmdAMax1", + "reserved70", "cmdFifoDepth1", "cmdHoleCnt1", "reserved7c", + "cmdFifoThresh", "cmdHoleInt", "reserved88", "reserved8c", + "reserved90", "reserved94", "reserved98", "reserved9c", + "reserveda0", "reserveda4", "reserveda8", "reservedac", + "reservedb0", "reservedb4", "reservedb8", "reservedbc", + "reservedc0", "reservedc4", "reservedc8", "reservedcc", + "reservedd0", "reservedd4", "reservedd8", "reserveddc", + "reservede0", "reservede4", "reservede8", "reservedec", + "reservedf0", "reservedf4", "reservedf8", "reservedfc", + "yuvBaseAddress", "yuvStride", "reserved108", "reserved10c", + "reserved110", "reserved114", "reserved118", "reserved11c", + "crc1", "reserved124", "reserved128", "reserved12c", + "crc2", "reserved134", "reserved138", "reserved13c", + "reserved140", "reserved144", "reserved148", "reserved14c", + "reserved150", "reserved154", "reserved158", "reserved15c", + "reserved160", "reserved164", "reserved168", "reserved16c", + "reserved170", "reserved174", "reserved178", "reserved17c", + "reserved180", "reserved184", "reserved188", "reserved18c", + "reserved190", "reserved194", "reserved198", "reserved19c", + "reserved1a0", "reserved1a4", "reserved1a8", "reserved1ac", + "reserved1b0", "reserved1b4", "reserved1b8", "reserved1bc", + "reserved1c0", "reserved1c4", "reserved1c8", "reserved1cc", + "reserved1d0", "reserved1d4", "reserved1d8", "reserved1dc", + "reserved1e0", "reserved1e4", "reserved1e8", "reserved1ec", + "reserved1f0", "reserved1f4", "reserved1f8", "reserved1fc" +}; + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void banshee_vga_regs::register_save(save_proxy &save) +{ + save.save_item(NAME(m_regs)); + save.save_item(NAME(m_crtc)); + save.save_item(NAME(m_seq)); + save.save_item(NAME(m_gc)); + save.save_item(NAME(m_attr)); + save.save_item(NAME(m_attr_flip_flop)); +} + + + +//************************************************************************** +// VOODOO BANSHEE DEVICE +//************************************************************************** + +//------------------------------------------------- +// voodoo_banshee_device - constructor +//------------------------------------------------- + +DEFINE_DEVICE_TYPE(VOODOO_BANSHEE, voodoo_banshee_device, "voodoo_banshee", "3dfx Voodoo Banshee") + +voodoo_banshee_device::voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo_model model) : + voodoo_2_device(mconfig, type, tag, owner, clock, model), + m_cmdfifo2(*this) +{ + for (int index = 0; index < std::size(m_regtable); index++) + m_regtable[index].unpack(s_register_table[index], *this); +} + + +//------------------------------------------------- +// core_map - device map for core memory access +//------------------------------------------------- + +void voodoo_banshee_device::core_map(address_map &map) +{ + // Voodoo Banshee/Voodoo 3 memory map: + // + // 0`00000xxx`xxxxxxxx`xxxxxxxx I/O register remap + // 0`00001xxx`xxxxxxxx`xxxxxxxx CMD/AGP transfer/Misc registers + // 0`0001xxxx`xxxxxxxx`xxxxxxxx 2D registers + // 0`001xxxxx`xxxxxxxx`xxxxxxxx 3D registers + // 0`010xxxxx`xxxxxxxx`xxxxxxxx 3D registers (cont'd) + // 0`011xxxxx`xxxxxxxx`xxxxxxxx Texture TMU 0 download + // 0`100xxxxx`xxxxxxxx`xxxxxxxx Texture TMU 1 download (Voodoo 3 only) + // 0`101xxxxx`xxxxxxxx`xxxxxxxx Reserved + // 0`11xxxxxx`xxxxxxxx`xxxxxxxx YUV planar space + // 1`xxxxxxxx`xxxxxxxx`xxxxxxxx 3D LFB space + // + map(0x0000000, 0x007ffff).rw(FUNC(voodoo_banshee_device::map_io_r), FUNC(voodoo_banshee_device::map_io_w)); + map(0x0080000, 0x00fffff).rw(FUNC(voodoo_banshee_device::map_cmd_agp_r), FUNC(voodoo_banshee_device::map_cmd_agp_w)); + map(0x0100000, 0x01fffff).rw(FUNC(voodoo_banshee_device::map_2d_r), FUNC(voodoo_banshee_device::map_2d_w)); + map(0x0200000, 0x05fffff).rw(FUNC(voodoo_banshee_device::map_register_r), FUNC(voodoo_banshee_device::map_register_w)); + map(0x0600000, 0x07fffff).w(FUNC(voodoo_banshee_device::map_texture_w<0>)); + if (BIT(m_chipmask, 2)) + map(0x0800000, 0x09fffff).w(FUNC(voodoo_banshee_device::map_texture_w<1>)); + map(0x0c00000, 0x0ffffff).w(FUNC(voodoo_banshee_device::map_yuv_w)); + map(0x1000000, 0x1ffffff).w(FUNC(voodoo_banshee_device::map_lfb_w)); +} + + +//------------------------------------------------- +// read - generic read handler until everyone is +// using the memory map +//------------------------------------------------- + +u32 voodoo_banshee_device::read(offs_t offset, u32 mem_mask) +{ + switch (offset >> (19-2)) + { + case 0x0000000 >> 19: + return map_io_r(offset - 0x0000000/4, mem_mask); + + case 0x0080000 >> 19: + return map_cmd_agp_r(offset - 0x0080000/4); + + case 0x0100000 >> 19: case 0x0180000 >> 19: + return map_2d_r(offset - 0x0100000/4); + + case 0x0200000 >> 19: case 0x0280000 >> 19: case 0x0300000 >> 19: case 0x0380000 >> 19: + case 0x0400000 >> 19: case 0x0480000 >> 19: case 0x0500000 >> 19: case 0x0580000 >> 19: + return map_register_r(offset - 0x0200000/4); + + default: + logerror("%s:voodoo_banshee_device::read Address out of range %08X & %08X\n", machine().describe_context(), offset*4, mem_mask); + return 0xffffffff; + } +} + + +//------------------------------------------------- +// write - generic write handler until everyone is +// using the memory map +//------------------------------------------------- + +void voodoo_banshee_device::write(offs_t offset, u32 data, u32 mem_mask) +{ + switch (offset >> (19-2)) + { + case 0x0000000 >> 19: + map_io_w(offset - 0x0000000/4, data, mem_mask); + break; + + case 0x0080000 >> 19: + map_cmd_agp_w(offset - 0x0080000/4, data, mem_mask); + break; + + case 0x0100000 >> 19: case 0x0180000 >> 19: + map_2d_w(offset - 0x0100000/4, data, mem_mask); + break; + + case 0x0200000 >> 19: case 0x0280000 >> 19: case 0x0300000 >> 19: case 0x0380000 >> 19: + case 0x0400000 >> 19: case 0x0480000 >> 19: case 0x0500000 >> 19: case 0x0580000 >> 19: + map_register_w(offset - 0x0200000/4, data, mem_mask); + break; + + case 0x0600000 >> 19: case 0x0680000 >> 19: case 0x0700000 >> 19: case 0x0780000 >> 19: + map_texture_w<0>(offset - 0x0600000, data, mem_mask); + break; + + case 0x0800000 >> 19: case 0x0880000 >> 19: case 0x0900000 >> 19: case 0x0980000 >> 19: + if (BIT(m_chipmask, 2)) + map_texture_w<1>(offset - 0x0800000, data, mem_mask); + break; + + case 0xc000000 >> 19: case 0xc800000 >> 19: case 0xd000000 >> 19: case 0xd800000 >> 19: + case 0xe000000 >> 19: case 0xe800000 >> 19: case 0xf000000 >> 19: case 0xf800000 >> 19: + map_yuv_w(offset - 0xc000000/4, data, mem_mask); + break; + + case 0x1000000 >> 19: case 0x1080000 >> 19: case 0x1100000 >> 19: case 0x1180000 >> 19: + case 0x1200000 >> 19: case 0x1280000 >> 19: case 0x1300000 >> 19: case 0x1380000 >> 19: + case 0x1400000 >> 19: case 0x1480000 >> 19: case 0x1500000 >> 19: case 0x1580000 >> 19: + case 0x1600000 >> 19: case 0x1680000 >> 19: case 0x1700000 >> 19: case 0x1780000 >> 19: + case 0x1800000 >> 19: case 0x1880000 >> 19: case 0x1900000 >> 19: case 0x1980000 >> 19: + case 0x1a00000 >> 19: case 0x1a80000 >> 19: case 0x1b00000 >> 19: case 0x1b80000 >> 19: + case 0x1c00000 >> 19: case 0x1c80000 >> 19: case 0x1d00000 >> 19: case 0x1d80000 >> 19: + case 0x1e00000 >> 19: case 0x1e80000 >> 19: case 0x1f00000 >> 19: case 0x1f80000 >> 19: + map_lfb_w(offset - 0x1000000/4, data, mem_mask); + break; + + default: + logerror("%s:voodoo_banshee_device::write Address out of range %08X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); + break; + } +} + + +//------------------------------------------------- +// lfb_map - device map for LFB space +//------------------------------------------------- + +void voodoo_banshee_device::lfb_map(address_map &map) +{ + map(0x0000000, 0x1ffffff).rw(FUNC(voodoo_banshee_device::read_lfb), FUNC(voodoo_banshee_device::write_lfb)); +} + + +//------------------------------------------------- +// read_lfb - generic LFB space read handler +//------------------------------------------------- + +u32 voodoo_banshee_device::read_lfb(offs_t offset, u32 mem_mask) +{ + prepare_for_read(); + + // above LFB base goes the traditional route + if (offset >= m_lfb_base) + return internal_lfb_r(offset - m_lfb_base); + + // reads below the LFB base are direct? + u32 addr = offset * 4; + if (addr <= m_fbmask) + { + u32 result = *(u32 *)&m_fbram[addr]; + if (LOG_LFB) + logerror("%s:read_lfb(%X) = %08X\n", machine().describe_context(), addr, result); + return result; + } + + // log out-of-bounds accesses + logerror("%s:read_lfb(%X) Access out of bounds\n", machine().describe_context(), addr); + return 0xffffffff; +} + + +//------------------------------------------------- +// write_lfb - generic LFB space write handler +//------------------------------------------------- + +void voodoo_banshee_device::write_lfb(offs_t offset, u32 data, u32 mem_mask) +{ + prepare_for_write(); + + // above LFB base goes the traditional route + if (offset >= m_lfb_base) + return internal_lfb_direct_w(offset - m_lfb_base, data, mem_mask); + + // could be writing to cmdfifo space + u32 addr = offset * 4; + if (m_cmdfifo.write_if_in_range(addr, data) || m_cmdfifo2.write_if_in_range(addr, data)) + return; + + // writes below the LFB base are direct? + if (addr <= m_fbmask) + { + if (LOG_LFB) + logerror("%s:write_lfb(%X) = %08X & %08X\n", machine().describe_context(), addr, data, mem_mask); + COMBINE_DATA((u32 *)&m_fbram[addr]); + } + else + logerror("%s:write_lfb Out of bounds (%X) = %08X & %08X\n", machine().describe_context(), addr, data, mem_mask); +} + + +//------------------------------------------------- +// io_map - device map for I/O space +//------------------------------------------------- + +void voodoo_banshee_device::io_map(address_map &map) +{ + map(0x00, 0xff).rw(FUNC(voodoo_banshee_device::map_io_r), FUNC(voodoo_banshee_device::map_io_w)); +} + + +//------------------------------------------------- +// update - video update +//------------------------------------------------- + +int voodoo_banshee_device::update(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + // if bypassing the clut, don't worry about the rest + u32 config = m_io_regs.read(banshee_io_regs::vidProcCfg); + if (BIT(config, 11)) + return update_common(bitmap, cliprect, m_shared->rgb565); + + // if the CLUT is dirty, recompute the pens array + if (m_clut_dirty) + { + rgb_t const *clutbase = &m_clut[256 * BIT(config, 13)]; + + // compute R/G/B pens first + u8 rtable[32], gtable[64], btable[32]; + for (u32 rawcolor = 0; rawcolor < 32; rawcolor++) + { + // treat X as a 5-bit value, scale up to 8 bits + u32 color = pal5bit(rawcolor); + rtable[rawcolor] = clutbase[color].r(); + btable[rawcolor] = clutbase[color].b(); + + // treat X as a 6-bit value with LSB=0, scale up to 8 bits, and linear interpolate + color = pal6bit(rawcolor * 2 + 0); + gtable[rawcolor * 2 + 0] = clutbase[color].g(); + + // treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate + color = pal6bit(rawcolor * 2 + 1); + gtable[rawcolor * 2 + 1] = clutbase[color].g(); + } + + // now compute the actual pens array + for (u32 pen = 0; pen < 65536; pen++) + m_pen[pen] = rgb_t(rtable[BIT(pen, 11, 5)], gtable[BIT(pen, 5, 6)], btable[BIT(pen, 0, 5)]); + + // no longer dirty + m_clut_dirty = false; + m_video_changed = true; + } + return update_common(bitmap, cliprect, &m_pen[0]); +} + + +//------------------------------------------------- +// device_start - device startup +//------------------------------------------------- + +void voodoo_banshee_device::device_start() +{ + // expand CLUT to 512 entries + m_clut.resize(512); + + // pre-set the chipmask and clear the TMU memory to indicate we're shared + if (m_chipmask == 0x01) + m_chipmask = 0x03; + m_tmumem0_in_mb = m_tmumem1_in_mb = 0; + + // start like a Voodoo-2 + voodoo_2_device::device_start(); + + // texture base address/shift is different compared to previous versions + m_tmu[0].set_baseaddr_mask_shift(0xfffff0, 0); + m_tmu[1].set_baseaddr_mask_shift(0xfffff0, 0); + + // initialize the second cmdfifo + m_cmdfifo2.init(m_fbram, m_fbmask + 1); + + // LFB stride defaualts to 11 on Banshee and later + m_lfb_stride = 11; + + // 512-entry CLUT on Banshee and later + for (int pen = 0; pen < 512; pen++) + m_clut[pen] = rgb_t(pen, pen, pen); + + // initialize banshee registers + m_io_regs.reset(); + m_io_regs.write(banshee_io_regs::pciInit0, 0x01800040); + m_io_regs.write(banshee_io_regs::sipMonitor, 0x40000000); + m_io_regs.write(banshee_io_regs::lfbMemoryConfig, 0x000a2200); + u32 dram0 = 0x00579d29; + if (m_fbmem_in_mb == 16) + dram0 |= 0x0c000000; // Midway Vegas (denver) expects 2 banks of 16MBit SGRAMs + else + dram0 |= 0x08000000; // Konami Viper expects 16MBit SGRAMs + m_io_regs.write(banshee_io_regs::dramInit0, dram0); + m_io_regs.write(banshee_io_regs::dramInit1, 0x00f02200); + m_io_regs.write(banshee_io_regs::tmuGbeInit, 0x00000bfb); +} + + +//------------------------------------------------- +// soft_reset - handle reset when initiated by +// a register write +//------------------------------------------------- + +void voodoo_banshee_device::soft_reset() +{ + voodoo_2_device::soft_reset(); + m_cmdfifo2.set_enable(0); +} + + +//------------------------------------------------- +// register_save - register for save states +//------------------------------------------------- + +void voodoo_banshee_device::register_save(save_proxy &save, u32 total_allocation) +{ + voodoo_2_device::register_save(save, total_allocation); + + // Voodoo Banshee stuff + save.save_class(NAME(m_cmdfifo2)); + save.save_class(NAME(m_io_regs)); + save.save_class(NAME(m_cmd_agp_regs)); + save.save_class(NAME(m_vga_regs)); + save.save_class(NAME(m_2d_regs)); + save.save_item(NAME(m_blt_dst_base)); + save.save_item(NAME(m_blt_dst_x)); + save.save_item(NAME(m_blt_dst_y)); + save.save_item(NAME(m_blt_dst_width)); + save.save_item(NAME(m_blt_dst_height)); + save.save_item(NAME(m_blt_dst_stride)); + save.save_item(NAME(m_blt_dst_bpp)); + save.save_item(NAME(m_blt_cmd)); + save.save_item(NAME(m_blt_src_base)); + save.save_item(NAME(m_blt_src_x)); + save.save_item(NAME(m_blt_src_y)); + save.save_item(NAME(m_blt_src_width)); + save.save_item(NAME(m_blt_src_height)); + save.save_item(NAME(m_blt_src_stride)); + save.save_item(NAME(m_blt_src_bpp)); +} + + +//------------------------------------------------- +// lfb_buffer_indirect - return the buffer base +// for LFB accesses via the classic 3D means +//------------------------------------------------- + +u16 *voodoo_banshee_device::lfb_buffer_indirect(int index) +{ + // LFB access is configured via I/O registers + return (u16 *)(m_fbram + m_lfb_base * 4); +} + + +//------------------------------------------------- +// draw_buffer_indirect - return the buffer base +// for drawing; on Banshee this is always the +// back buffer +//------------------------------------------------- + +u16 *voodoo_banshee_device::draw_buffer_indirect(int index) +{ + // drawing is confined to the back buffer + return back_buffer(); +} + + +//------------------------------------------------- +// map_io_r - handle a mapped read from I/O +// space +//------------------------------------------------- + +u32 voodoo_banshee_device::map_io_r(offs_t offset, u32 mem_mask) +{ + prepare_for_read(); + return internal_io_r(offset, mem_mask); +} + + +//------------------------------------------------- +// map_cmd_agp_r - handle a mapped read from CMD/ +// AGP space +//------------------------------------------------- + +u32 voodoo_banshee_device::map_cmd_agp_r(offs_t offset) +{ + prepare_for_read(); + return internal_cmd_agp_r(offset); +} + + +//------------------------------------------------- +// map_2d_r - handle a mapped read from 2D space +//------------------------------------------------- + +u32 voodoo_banshee_device::map_2d_r(offs_t offset) +{ + prepare_for_read(); + logerror("%s:map_2d_r(%X)\n", machine().describe_context(), (offset*4) & 0xfffff); + return 0xffffffff; +} + + +//------------------------------------------------- +// map_register_r - handle a mapped read from +// regular register space +//------------------------------------------------- + +u32 voodoo_banshee_device::map_register_r(offs_t offset) +{ + prepare_for_read(); + + // extract chipmask and register + u32 chipmask = BIT(offset, 8, 4); + if (chipmask == 0) + chipmask = 0xf; + chipmask &= m_chipmask; + u32 regnum = BIT(offset, 0, 8); + + // look up the register + return m_regtable[regnum].read(*this, chipmask, regnum); +} + + +//------------------------------------------------- +// map_io_w - handle a mapped write to I/O space +//------------------------------------------------- + +void voodoo_banshee_device::map_io_w(offs_t offset, u32 data, u32 mem_mask) +{ + // no mechanism to stall I/O writes + prepare_for_write(); + internal_io_w(offset, data, mem_mask); +} + + +//------------------------------------------------- +// map_agp_cmd_w - handle a mapped write to CMD/ +// AGP space +//------------------------------------------------- + +void voodoo_banshee_device::map_cmd_agp_w(offs_t offset, u32 data, u32 mem_mask) +{ + // no mechanism to stall AGP/CMD writes + prepare_for_write(); + internal_cmd_agp_w(offset, data, mem_mask); +} + + +//------------------------------------------------- +// map_2d_w - handle a mapped write to 2D space +//------------------------------------------------- + +void voodoo_banshee_device::map_2d_w(offs_t offset, u32 data, u32 mem_mask) +{ + // no mechanism to stall 2D writes + prepare_for_write(); + logerror("%s:map_2d_w(%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); +} + + +//------------------------------------------------- +// map_register_w - handle a mapped write to +// regular register space +//------------------------------------------------- + +void voodoo_banshee_device::map_register_w(offs_t offset, u32 data, u32 mem_mask) +{ + bool pending = prepare_for_write(); + + // extract chipmask and register + u32 chipmask = BIT(offset, 8, 4); + if (chipmask == 0) + chipmask = 0xf; + chipmask &= m_chipmask; + u32 regnum = BIT(offset, 0, 8); + + // handle register swizzling + if (BIT(offset, 20-2)) + data = swapendian_int32(data); + + // handle aliasing + if (BIT(offset, 21-2)) + regnum = voodoo_regs::alias(regnum); + + // look up the register + auto const ®entry = m_regtable[regnum]; + + // if this is non-FIFO command, execute immediately + if (!regentry.is_fifo()) + return void(regentry.write(*this, chipmask, regnum, data)); + + // track swap buffers + if (regnum == voodoo_regs::reg_swapbufferCMD) + m_swaps_pending++; + + // if we're busy add to the fifo + if (pending && m_init_enable.enable_pci_fifo()) + return add_to_fifo((chipmask << 4) | regnum | memory_fifo::TYPE_REGISTER, data, mem_mask); + + // if we get a non-zero number of cycles back, mark things pending + int cycles = regentry.write(*this, chipmask, regnum, data); + if (cycles > 0) + { + // if we ended up with cycles, mark the operation pending + m_operation_end = machine().time() + clocks_to_attotime(cycles); + if (LOG_FIFO_VERBOSE) + logerror("VOODOO.FIFO:direct write start at %s end at %s\n", machine().time().as_string(18), m_operation_end.as_string(18)); + } +} + + +//------------------------------------------------- +// map_texture_w - handle a mapped write to +// texture download space +//------------------------------------------------- + +template +void voodoo_banshee_device::map_texture_w(offs_t offset, u32 data, u32 mem_mask) +{ + prepare_for_write(); + logerror("%s:map_texture_w<%d>(%X) = %08X & %08X\n", machine().describe_context(), Which, offset*4, data, mem_mask); +} + + +//------------------------------------------------- +// map_yuv_w - handle a mapped write to YUV space +//------------------------------------------------- + +void voodoo_banshee_device::map_yuv_w(offs_t offset, u32 data, u32 mem_mask) +{ + prepare_for_write(); + logerror("%s:map_yuv_w(%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); +} + + +//------------------------------------------------- +// map_lfb_w - handle a mapped write to LFB space +//------------------------------------------------- + +void voodoo_banshee_device::map_lfb_w(offs_t offset, u32 data, u32 mem_mask) +{ + // if we're busy add to the fifo, else just execute immediately + if (prepare_for_write() && m_init_enable.enable_pci_fifo()) + add_to_fifo(offset | (0x400000/4), data, mem_mask); + else + internal_lfb_w(offset, data, mem_mask); +} + + +//------------------------------------------------- +// internal_io_r - handle reads from the I/O +// registers +//------------------------------------------------- + +u32 voodoo_banshee_device::internal_io_r(offs_t offset, u32 mem_mask) +{ + // by default just return regular data + offset &= 0x3f; + u32 result = m_io_regs.read(offset); + + // handle special offsets + switch (offset) + { + // status reflects the voodoo status + case banshee_io_regs::status: + result = reg_status_r(0, 0); + break; + + // DAC data reads fetch data from the CLUT + case banshee_io_regs::dacData: + result = m_clut[BIT(m_io_regs.read(banshee_io_regs::dacAddr), 0, 9)]; + break; + + // VGA reads are special and byte-wise + case banshee_io_regs::vgab0: case banshee_io_regs::vgab4: case banshee_io_regs::vgab8: case banshee_io_regs::vgabc: + case banshee_io_regs::vgac0: case banshee_io_regs::vgac4: case banshee_io_regs::vgac8: case banshee_io_regs::vgacc: + case banshee_io_regs::vgad0: case banshee_io_regs::vgad4: case banshee_io_regs::vgad8: case banshee_io_regs::vgadc: + result = 0; + if (ACCESSING_BITS_0_7) + result |= internal_vga_r(offset * 4 + 0) << 0; + if (ACCESSING_BITS_8_15) + result |= internal_vga_r(offset * 4 + 1) << 8; + if (ACCESSING_BITS_16_23) + result |= internal_vga_r(offset * 4 + 2) << 16; + if (ACCESSING_BITS_24_31) + result |= internal_vga_r(offset * 4 + 3) << 24; + + // early out to skip extra logging + return result; + } + + if (LOG_REGISTERS) + logerror("%s:internal_io_r(%s) = %08X\n", machine().describe_context(), m_io_regs.name(offset), result); + return result; +} + + +//------------------------------------------------- +// internal_io_w - handle writes to the I/O +// registers +//------------------------------------------------- + +void voodoo_banshee_device::internal_io_w(offs_t offset, u32 data, u32 mem_mask) +{ + // need to block if Y origin is changing; everything else can proceed + offset &= 0x3f; + if (offset == banshee_io_regs::miscInit0) + m_renderer->wait(m_io_regs.name(offset)); + + // fetch original value and compute new value + u32 oldval = m_io_regs.read(offset); + u32 newval = m_io_regs.write(offset, data, mem_mask); + + // handle special cases + switch (offset) + { + // dacData writes indirectly to the CLUT registers; mark dirty if changing + case banshee_io_regs::dacData: + { + u32 dacaddr = BIT(m_io_regs.read(banshee_io_regs::dacAddr), 0, 9); + if (newval != m_clut[dacaddr]) + { + m_clut[dacaddr] = newval; + m_clut_dirty = true; + } + break; + } + + // vidProcCfg can change the CLUT index + case banshee_io_regs::vidProcCfg: + if (BIT(oldval ^ newval, 13)) + m_clut_dirty = true; + break; + + // miscInit0 can alter the rendering Y origin + case banshee_io_regs::miscInit0: + m_renderer->set_yorigin(BIT(newval, 18, 12)); + break; + + // vidScreenSize causes the video to be reconfigured + case banshee_io_regs::vidScreenSize: + if (BIT(newval, 0, 12) != 0) + m_width = BIT(data, 0, 12); + if (BIT(newval, 12, 12) != 0) + m_height = BIT(data, 12, 12); + if (m_width != 0 && m_height != 0 && newval != oldval) + recompute_video(); + break; + + // vidOverlayDudx/vidOverlayDudy impact how we configure the video + case banshee_io_regs::vidOverlayDudx: + case banshee_io_regs::vidOverlayDvdy: + recompute_video(); + break; + + // lfbMemoryConfig affects LFB reads + case banshee_io_regs::lfbMemoryConfig: + m_lfb_base = BIT(newval, 0, 13) << (12-2); + m_lfb_stride = BIT(newval, 13, 3) + 9; + break; + + // VGA is special and byte-wise + case banshee_io_regs::vgab0: case banshee_io_regs::vgab4: case banshee_io_regs::vgab8: case banshee_io_regs::vgabc: + case banshee_io_regs::vgac0: case banshee_io_regs::vgac4: case banshee_io_regs::vgac8: case banshee_io_regs::vgacc: + case banshee_io_regs::vgad0: case banshee_io_regs::vgad4: case banshee_io_regs::vgad8: case banshee_io_regs::vgadc: + if (ACCESSING_BITS_0_7) + internal_vga_w(offset * 4 + 0, BIT(data, 0, 8)); + if (ACCESSING_BITS_8_15) + internal_vga_w(offset * 4 + 1, BIT(data, 8, 8)); + if (ACCESSING_BITS_16_23) + internal_vga_w(offset * 4 + 2, BIT(data, 16, 8)); + if (ACCESSING_BITS_24_31) + internal_vga_w(offset * 4 + 3, BIT(data, 24, 8)); + + // early out to skip extra logging + return; + } + + if (LOG_REGISTERS) + logerror("%s:internal_io_w(%s) = %08X & %08X\n", machine().describe_context(), m_io_regs.name(offset), data, mem_mask); +} + + +//------------------------------------------------- +// internal_cmd_agp_r - handle reads from the +// CMD/AGP registers +//------------------------------------------------- + +u32 voodoo_banshee_device::internal_cmd_agp_r(offs_t offset) +{ + // by default just return regular data + offset &= 0x7f; + u32 result = m_cmd_agp_regs.read(offset); + + // check for special cases + switch (offset) + { + case banshee_cmd_agp_regs::cmdRdPtrL0: + result = m_cmdfifo.read_pointer(); + break; + + case banshee_cmd_agp_regs::cmdFifoDepth0: + result = m_cmdfifo.depth(); + break; + + case banshee_cmd_agp_regs::cmdHoleCnt0: + result = m_cmdfifo.holes(); + break; + + case banshee_cmd_agp_regs::cmdRdPtrL1: + result = m_cmdfifo2.read_pointer(); + break; + + case banshee_cmd_agp_regs::cmdFifoDepth1: + result = m_cmdfifo2.depth(); + break; + + case banshee_cmd_agp_regs::cmdHoleCnt1: + result = m_cmdfifo2.holes(); + break; + } + + if (LOG_REGISTERS) + logerror("%s:internal_cmd_agp_r(%s) = %08X\n", machine().describe_context(), m_cmd_agp_regs.name(offset), result); + return result; +} + + +//------------------------------------------------- +// internal_cmd_agp_w - handle writes to the +// CMD/AGP registers +//------------------------------------------------- + +void voodoo_banshee_device::internal_cmd_agp_w(offs_t offset, u32 data, u32 mem_mask) +{ + offset &= 0x7f; + + // fetch original value and compute new value + u32 newval = m_cmd_agp_regs.write(offset, data, mem_mask); + + // handle special cases + switch (offset) + { + case banshee_cmd_agp_regs::cmdBaseAddr0: + m_cmdfifo.set_base(BIT(newval, 0, 24) << 12); + m_cmdfifo.set_size((BIT(m_cmd_agp_regs.read(banshee_cmd_agp_regs::cmdBaseSize0), 0, 8) + 1) << 12); + break; + + case banshee_cmd_agp_regs::cmdBaseSize0: + m_cmdfifo.set_size((BIT(newval, 0, 8) + 1) << 12); + m_cmdfifo.set_enable(BIT(newval, 8)); + m_cmdfifo.set_count_holes(!BIT(newval, 10)); + break; + + case banshee_cmd_agp_regs::cmdBump0: + fatalerror("%s: Unsupported write to cmdBump0", tag()); + + case banshee_cmd_agp_regs::cmdRdPtrL0: + m_cmdfifo.set_read_pointer(newval); + break; + + case banshee_cmd_agp_regs::cmdAMin0: + m_cmdfifo.set_address_min(newval); + break; + + case banshee_cmd_agp_regs::cmdAMax0: + m_cmdfifo.set_address_max(newval); + break; + + case banshee_cmd_agp_regs::cmdFifoDepth0: + m_cmdfifo.set_depth(newval); + break; + + case banshee_cmd_agp_regs::cmdHoleCnt0: + m_cmdfifo.set_holes(newval); + break; + + case banshee_cmd_agp_regs::cmdBaseAddr1: + m_cmdfifo2.set_base(BIT(newval, 0, 24) << 12); + m_cmdfifo2.set_size((BIT(m_cmd_agp_regs.read(banshee_cmd_agp_regs::cmdBaseSize1), 0, 8) + 1) << 12); + break; + + case banshee_cmd_agp_regs::cmdBaseSize1: + m_cmdfifo2.set_size((BIT(newval, 0, 8) + 1) << 12); + m_cmdfifo2.set_enable(BIT(newval, 8)); + m_cmdfifo2.set_count_holes(!BIT(newval, 10)); + break; + + case banshee_cmd_agp_regs::cmdBump1: + fatalerror("%s: Unsupported write to cmdBump1", tag()); + + case banshee_cmd_agp_regs::cmdRdPtrL1: + m_cmdfifo2.set_read_pointer(newval); + break; + + case banshee_cmd_agp_regs::cmdAMin1: + m_cmdfifo2.set_address_min(newval); + break; + + case banshee_cmd_agp_regs::cmdAMax1: + m_cmdfifo2.set_address_max(newval); + break; + + case banshee_cmd_agp_regs::cmdFifoDepth1: + m_cmdfifo2.set_depth(newval); + break; + + case banshee_cmd_agp_regs::cmdHoleCnt1: + m_cmdfifo2.set_holes(newval); + break; + } + + if (LOG_REGISTERS) + logerror("%s:internal_cmd_agp_w(%s) = %08X & %08X\n", machine().describe_context(), m_io_regs.name(offset), data, mem_mask); +} + + +//------------------------------------------------- +// internal_2d_w - handle writes to the 2D +// registers +//------------------------------------------------- + +s32 voodoo_banshee_device::internal_2d_w(offs_t offset, u32 data) +{ + static u8 const s_format_bpp[16] = { 1,1,1,2,3,4,1,1,2,2,1,1,1,1,1,1 }; + + // by default write through to the register + offset &= 0x3f; + m_2d_regs.write(offset, data); + + // handle special cases + switch (offset) + { + case banshee_2d_regs::command: + if (LOG_BANSHEE_2D) + logerror(" 2D:command: cmd %d, ROP0 %02X\n", data & 0xf, data >> 24); + + m_blt_src_x = BIT(m_2d_regs.read(banshee_2d_regs::srcXY), 0, 12); + m_blt_src_y = BIT(m_2d_regs.read(banshee_2d_regs::srcXY), 16, 12); + m_blt_src_base = BIT(m_2d_regs.read(banshee_2d_regs::srcBaseAddr), 0, 24); + m_blt_src_stride = BIT(m_2d_regs.read(banshee_2d_regs::srcFormat), 0, 14); + m_blt_src_width = BIT(m_2d_regs.read(banshee_2d_regs::srcSize), 0, 12); + m_blt_src_height = BIT(m_2d_regs.read(banshee_2d_regs::srcSize), 16, 12); + m_blt_src_bpp = s_format_bpp[BIT(m_2d_regs.read(banshee_2d_regs::srcFormat), 16, 4)]; + + m_blt_dst_x = BIT(m_2d_regs.read(banshee_2d_regs::dstXY), 0, 12); + m_blt_dst_y = BIT(m_2d_regs.read(banshee_2d_regs::dstXY), 16, 12); + m_blt_dst_base = BIT(m_2d_regs.read(banshee_2d_regs::dstBaseAddr), 0, 24); + m_blt_dst_stride = BIT(m_2d_regs.read(banshee_2d_regs::dstFormat), 0, 14); + m_blt_dst_width = BIT(m_2d_regs.read(banshee_2d_regs::dstSize), 0, 12); + m_blt_dst_height = BIT(m_2d_regs.read(banshee_2d_regs::dstSize), 16, 12); + m_blt_dst_bpp = s_format_bpp[BIT(m_2d_regs.read(banshee_2d_regs::dstFormat), 16, 3)]; + + m_blt_cmd = BIT(data, 0, 4); + break; + + default: + if (offset >= 0x20 && offset < 0x40) + execute_blit(data); + else if (offset >= 0x40 && offset < 0x80) + {} // TODO: colorPattern + break; + } + + return 1; +} + + +//------------------------------------------------- +// internal_texture_w - handle writes to texture +// space +//------------------------------------------------- + +void voodoo_banshee_device::internal_texture_w(offs_t offset, u32 data) +{ + // statistics + if (DEBUG_STATS) + m_stats.m_tex_writes++; + + // point to the right TMU + int tmunum = BIT(offset, 19, 2); + if (!BIT(m_chipmask, 1 + tmunum)) + return; + + // wait for any outstanding work to finish + m_renderer->wait("Texture write"); + + // pull out modes from the TMU and update state + auto ®s = m_tmu[tmunum].regs(); + auto const texlod = regs.texture_lod(); + auto const texmode = regs.texture_mode(); + auto &texture = m_tmu[tmunum].prepare_texture(*m_renderer.get()); + + // swizzle the data + if (texlod.tdata_swizzle()) + data = swapendian_int32(data); + if (texlod.tdata_swap()) + data = (data >> 16) | (data << 16); + + // determine destination pointer + u8 *dest = texture.write_ptr(0, offset * 4, 0, 1); + + // write the four bytes in little-endian order + u32 bytes_per_texel = (texmode.format() < 8) ? 1 : 2; + if (bytes_per_texel == 1) + { + dest[BYTE4_XOR_LE(0)] = (data >> 0) & 0xff; + dest[BYTE4_XOR_LE(1)] = (data >> 8) & 0xff; + dest[BYTE4_XOR_LE(2)] = (data >> 16) & 0xff; + dest[BYTE4_XOR_LE(3)] = (data >> 24) & 0xff; + } + else + { + u16 *dest16 = reinterpret_cast(dest); + dest16[BYTE_XOR_LE(0)] = (data >> 0) & 0xffff; + dest16[BYTE_XOR_LE(1)] = (data >> 16) & 0xffff; + } +} + + +//------------------------------------------------- +// internal_lfb_direct_w - handle "direct" writes +// to LFB space; this is like previous generations +// but ignores the LFB mode and treats everything +// as 16-bit pixel data +//------------------------------------------------- + +void voodoo_banshee_device::internal_lfb_direct_w(offs_t offset, u32 data, u32 mem_mask) +{ + // statistics + if (DEBUG_STATS) + m_stats.m_lfb_writes++; + + // byte swizzling + auto const lfbmode = m_reg.lfb_mode(); + if (lfbmode.byte_swizzle_writes()) + { + data = swapendian_int32(data); + mem_mask = swapendian_int32(mem_mask); + } + + // word swapping + if (lfbmode.word_swap_writes()) + { + data = (data << 16) | (data >> 16); + mem_mask = (mem_mask << 16) | (mem_mask >> 16); + } + + // TODO: This direct write is not verified. + + // no data expansion or pixel pipelines, just raw write of 2 16-bit pixels? + offset <<= 1; + + // compute X,Y + s32 x = offset & ((1 << m_lfb_stride) - 1); + s32 y = offset >> m_lfb_stride; + + // select the target buffers + u16 *dest = lfb_buffer_indirect(0); + u16 *end = ram_end(); + + // advance pointers to the proper row + dest += y * m_renderer->rowpixels() + x; + + // write to the RGB buffer + if (ACCESSING_BITS_0_15 && dest < end) + dest[0] = BIT(data, 0, 16); + if (ACCESSING_BITS_16_31 && dest + 1 < end) + dest[1] = BIT(data, 16, 16); + + // notify that frame buffer has changed + m_video_changed = true; + if (LOG_LFB) + logerror("VOODOO.LFB:write direct (%d,%d) = %08X & %08X\n", x, y, data, mem_mask); +} + + +//------------------------------------------------- +// internal_vga_r - handle reads from VGA register +// space +//------------------------------------------------- + +u8 voodoo_banshee_device::internal_vga_r(offs_t offset) +{ + // by default just return regular data + offset &= 0x1f; + u32 result = m_vga_regs.read(offset); + + // handle special offsets + char const *logtype = "internal_vga_r"; + u32 logoffs = offset + 0x3c0; + switch (offset) + { + // attribute access + case banshee_vga_regs::attributeData: + result = m_vga_regs.read_attr(logoffs = m_vga_regs.attribute_index()); + logtype = "vga_attr_r"; + break; + + // input status 0 + case banshee_vga_regs::inputStatus0: + // bit 7 = Interrupt Status. When its value is ?1?, denotes that an interrupt is pending. + // bit 6:5 = Feature Connector. These 2 bits are readable bits from the feature connector. + // bit 4 = Sense. This bit reflects the state of the DAC monitor sense logic. + // bit 3:0 = Reserved. Read back as 0. + result = 0x00; + break; + + // sequencer access + case banshee_vga_regs::sequencerData: + result = m_vga_regs.read_seq(logoffs = m_vga_regs.sequencer_index()); + logtype = "vga_seq_r"; + break; + + // feature control + case banshee_vga_regs::featureControlR: + result = m_vga_regs.read(banshee_vga_regs::featureControlW); + m_vga_regs.clear_flip_flop(); + break; + + // miscellaneous output + case banshee_vga_regs::miscOutputR: + result = m_vga_regs.read(banshee_vga_regs::miscOutputW); + break; + + // graphics controller access + case banshee_vga_regs::gfxControllerData: + result = m_vga_regs.read_gc(logoffs = m_vga_regs.gfx_controller_index()); + logtype = "vga_gc_r"; + break; + + // CRTC access + case banshee_vga_regs::crtcData: + result = m_vga_regs.read_crtc(logoffs = m_vga_regs.crtc_index()); + logtype = "vga_crtc_r"; + break; + + // input status 1 + case banshee_vga_regs::inputStatus1: + // bit 7:6 = Reserved. These bits read back 0. + // bit 5:4 = Display Status. These 2 bits reflect 2 of the 8 pixel data outputs from the Attribute + // controller, as determined by the Attribute controller index 0x12 bits 4 and 5. + // bit 3 = Vertical sync Status. A ?1? indicates vertical retrace is in progress. + // bit 2:1 = Reserved. These bits read back 0x2. + // bit 0 = Display Disable. When this bit is 1, either horizontal or vertical display end has occurred, + // otherwise video data is being displayed. + result = 0x04; + break; + } + + if (LOG_REGISTERS) + logerror("%s:%s(%X) = %02X\n", machine().describe_context(), logtype, logoffs, result); + return result; +} + + +//------------------------------------------------- +// internal_vga_w - handle writes to VGA register +// space +//------------------------------------------------- + +void voodoo_banshee_device::internal_vga_w(offs_t offset, u8 data) +{ + offset &= 0x1f; + + // fetch original value and compute new value + m_vga_regs.write(offset, data); + + // handle special cases + char const *logtype = "internal_vga_w"; + u32 logoffs = offset + 0x3c0; + switch (offset) + { + // attribute access + case banshee_vga_regs::attributeData: + case banshee_vga_regs::attributeIndex: + if (m_vga_regs.toggle_flip_flop() == 0) + m_vga_regs.write(banshee_vga_regs::attributeIndex, data); + else + { + m_vga_regs.write_attr(logoffs = m_vga_regs.attribute_index(), data); + logtype = "vga_crtc_w"; + } + break; + + // sequencer access + case banshee_vga_regs::sequencerData: + m_vga_regs.write_seq(logoffs = m_vga_regs.sequencer_index(), data); + logtype = "vga_seq_w"; + break; + + // graphics controller access + case banshee_vga_regs::gfxControllerData: + m_vga_regs.write_gc(logoffs = m_vga_regs.gfx_controller_index(), data); + logtype = "vga_gc_w"; + break; + + // CRTC access + case banshee_vga_regs::crtcData: + m_vga_regs.write_crtc(logoffs = m_vga_regs.crtc_index(), data); + logtype = "vga_crtc_w"; + break; + } + + if (LOG_REGISTERS) + logerror("%s:%s(%X) = %02X\n", machine().describe_context(), logtype, logoffs, data); +} + + +//------------------------------------------------- +// execute_fifos - execute commands from the FIFOs +// until a non-zero cycle count operation is run +//------------------------------------------------- + +u32 voodoo_banshee_device::execute_fifos() +{ + // we might be in CMDFIFO mode + if (m_cmdfifo.enabled()) + return m_cmdfifo.execute_if_ready(); + if (m_cmdfifo2.enabled()) + return m_cmdfifo2.execute_if_ready(); + + // otherwise, run the traditional memory FIFOs + return voodoo_1_device::execute_fifos(); +} + + +//------------------------------------------------- +// reg_status_r - status register read +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_status_r(u32 chipmask, u32 offset) +{ + u32 result = 0; + + // bits 5:0 are the PCI FIFO free space + result |= std::min(m_pci_fifo.space() / 2, 0x3f) << 0; + + // bit 6 is the vertical retrace + result |= m_vblank << 6; + + // bit 7 is FBI graphics engine busy + // bit 8 is TREX busy + // bit 9 is overall busy */ + if (operation_pending()) + result |= (1 << 7) | (1 << 8) | (1 << 9); + + // bit 10 is 2D busy + + // bit 11 is cmd FIFO 0 busy + if (m_cmdfifo.enabled() && m_cmdfifo.depth() > 0) + result |= 1 << 11; + + // bit 12 is cmd FIFO 1 busy + if (m_cmdfifo2.enabled() && m_cmdfifo2.depth() > 0) + result |= 1 << 12; + + // bits 30:28 are the number of pending swaps + result |= std::min(m_swaps_pending, 7) << 28; + + // eat some cycles since people like polling here + if (m_status_cycles != 0) + m_cpu->eat_cycles(m_status_cycles); + + // bit 31 is PCI interrupt pending (not implemented) + return result; +} + + +//------------------------------------------------- +// reg_colbufbase_w - colBufferAddr register write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_colbufbase_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_reg.write(regnum, data); + m_rgboffs[1] = data & m_fbmask & ~0x0f; + } + return 0; +} + + +//------------------------------------------------- +// reg_colbufstride_w - colBufferStride register +// write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_colbufstride_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_reg.write(regnum, data); + u32 newpix = BIT(data, 15) ? (BIT(data, 0, 7) << 6) : (BIT(data, 0, 14) >> 1); + if (newpix != m_renderer->rowpixels()) + { + m_renderer->set_rowpixels(newpix); + m_video_changed = true; + } + } + return 0; +} + + +//------------------------------------------------- +// reg_auxbufbase_w - auxBufferAddr register write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_auxbufbase_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_reg.write(regnum, data); + m_auxoffs = data & m_fbmask & ~0x0f; + } + return 0; +} + + +//------------------------------------------------- +// reg_auxbufstride_w - auxBufferStride register +// write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_auxbufstride_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) + { + m_reg.write(regnum, data); + u32 newpix = BIT(data, 15) ? (BIT(data, 0, 7) << 6) : (BIT(data, 0, 14) >> 1); + if (newpix != m_renderer->rowpixels()) + fatalerror("%s: Unsupported aux buffer stride (%d) differs from color buffer stride (%d)", tag(), newpix, m_renderer->rowpixels()); + } + return 0; +} + + +//------------------------------------------------- +// reg_swappending_w - swapPending register write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_swappending_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) m_swaps_pending++; + return 0; +} + + +//------------------------------------------------- +// reg_overbuffer_w - leftOverlayBuf/ +// rightOverlayBuf register write +//------------------------------------------------- + +u32 voodoo_banshee_device::reg_overbuffer_w(u32 chipmask, u32 regnum, u32 data) +{ + if (BIT(chipmask, 0)) m_reg.write(regnum, data); + return 0; +} + + +//------------------------------------------------- +// rotate_buffers -- rotate the buffers according +// to the current buffer config; just update the +// base to the left overlay buffer +//------------------------------------------------- + +void voodoo_banshee_device::rotate_buffers() +{ + m_rgboffs[0] = m_reg.read(voodoo_regs::reg_leftOverlayBuf) & m_fbmask & ~0x0f; +} + + +//------------------------------------------------- +// recompute_video -- determine the video size +// and configuration based on current registers +//------------------------------------------------- + +void voodoo_banshee_device::recompute_video() +{ + u8 crtc7 = m_vga_regs.read_crtc(7); + + // get horizontal total and vertical total from CRTC registers + u32 htotal = (m_vga_regs.read_crtc(0) + 5) * 8; + u32 vtotal = (m_vga_regs.read_crtc(6) | (BIT(crtc7, 0) << 8) | (BIT(crtc7, 5) << 9)) + 2; + if (htotal == 0 || vtotal == 0) + return; + + // compute start/stop for vertical retrace + u32 vstart = m_vga_regs.read_crtc(16) | (BIT(crtc7, 2) << 8) | (BIT(crtc7, 7) << 9); + u32 vstop = m_vga_regs.read_crtc(17) & 0xf; + + // compare to see if vstop is before or after low 4 bits of vstart + if (vstop < (vstart & 0xf)) + vstop |= (vstart + 0x10) & ~0xf; + else + vstop |= vstart & ~0xf; + + // get pll k, m and n from pllCtrl0 + const u32 pll0 = m_io_regs.read(banshee_io_regs::pllCtrl0); + const u32 k = BIT(pll0, 0, 2); + const u32 m = BIT(pll0, 2, 6); + const u32 n = BIT(pll0, 8, 8); + const double video_clock = (XTAL(14'318'181) * (n + 2) / ((m + 2) << k)).dvalue(); + const double frame_period = vtotal * htotal / video_clock; + + // compute scaled screen size, using the overlay fraction if specified + u32 dudx = m_io_regs.read(banshee_io_regs::vidOverlayDudx); + u32 dvdy = m_io_regs.read(banshee_io_regs::vidOverlayDvdy); + u32 width = (dudx != 0) ? ((m_width * dudx) >> 20) : m_width; + u32 height = (dvdy != 0) ? ((m_height * dvdy) >> 20) : m_height; + if (LOG_REGISTERS) + logerror("configure screen: htotal: %d vtotal: %d vstart: %d vstop: %d width: %d height: %d refresh: %f\n", htotal, vtotal, vstart, vstop, width, height, 1.0 / frame_period); + + // configure the screen + rectangle visarea(0, width - 1, 0, height - 1); + screen().configure(htotal, vtotal, visarea, DOUBLE_TO_ATTOSECONDS(frame_period)); + + // set the vsync start and stop + m_vsyncstart = vstart; + m_vsyncstop = vstop; + adjust_vblank_start_timer(); +} + + +//------------------------------------------------- +// cmdfifo_register_w -- handle a register write +// from the cmdfifo +//------------------------------------------------- + +u32 voodoo_banshee_device::cmdfifo_register_w(u32 offset, u32 data) +{ + // bit 11 indicates a write to 2D register space + u32 regnum = BIT(offset, 0, 8); + if (BIT(offset, 11, 1)) + return internal_2d_w(regnum, data); + + // otherwise, just a normal register write + u32 chipmask = chipmask_from_offset(offset); + return m_regtable[regnum].write(*this, chipmask, regnum, data); +} + + +//------------------------------------------------- +// cmdfifo_2d_w -- handle a 2D register write +// from the cmdfifo +//------------------------------------------------- + +u32 voodoo_banshee_device::cmdfifo_2d_w(u32 offset, u32 data) +{ + u32 regnum = banshee_2d_regs::clip0Min + offset; + return internal_2d_w(regnum, data); +} + + +//------------------------------------------------- +// execute_blit -- perform a 2D blitting operation +//------------------------------------------------- + +void voodoo_banshee_device::execute_blit(u32 data) +{ + switch (m_blt_cmd) + { + case 0: // NOP - wait for idle + break; + + case 1: // Screen-to-screen blit + // TODO + if (LOG_BANSHEE_2D) + logerror(" blit_2d:screen_to_screen: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); + break; + + case 2: // Screen-to-screen stretch blit + fatalerror("%s: Unsupported blit_2d:screen_to_screen_stretch: src X %d, src Y %d\n", tag(), data & 0xfff, (data >> 16) & 0xfff); + + case 3: // Host-to-screen blit + { + u32 addr = m_blt_dst_base + m_blt_dst_y * m_blt_dst_stride + m_blt_dst_x * m_blt_dst_bpp; + + if (LOG_BANSHEE_2D) + logerror(" blit_2d:host_to_screen: %08x -> %08x, %d, %d\n", data, addr, m_blt_dst_x, m_blt_dst_y); + + switch (m_blt_dst_bpp) + { + case 1: + m_fbram[addr + 0] = BIT(data, 0, 8); + m_fbram[addr + 1] = BIT(data, 8, 8); + m_fbram[addr + 2] = BIT(data, 16, 8); + m_fbram[addr + 3] = BIT(data, 24, 8); + m_blt_dst_x += 4; + break; + + case 2: + m_fbram[addr + 1] = BIT(data, 0, 8); + m_fbram[addr + 0] = BIT(data, 8, 8); + m_fbram[addr + 3] = BIT(data, 16, 8); + m_fbram[addr + 2] = BIT(data, 24, 8); + m_blt_dst_x += 2; + break; + + case 3: + m_blt_dst_x += 1; + break; + + case 4: + m_fbram[addr + 3] = BIT(data, 0, 8); + m_fbram[addr + 2] = BIT(data, 8, 8); + m_fbram[addr + 1] = BIT(data, 16, 8); + m_fbram[addr + 0] = BIT(data, 24, 8); + m_blt_dst_x += 1; + break; + } + + if (m_blt_dst_x >= m_blt_dst_width) + { + m_blt_dst_x = 0; + m_blt_dst_y++; + } + break; + } + + case 5: // Rectangle fill + fatalerror("%s: Unsupported 2D rectangle_fill: src X %d, src Y %d", tag(), BIT(data, 0, 12), BIT(data, 16, 12)); + + case 6: // Line + fatalerror("%s: Unsupported 2D line: end X %d, end Y %d", tag(), BIT(data, 0, 12), BIT(data, 16, 12)); + + case 7: // Polyline + fatalerror("%s: Unsupported 2D polyline: end X %d, end Y %d", tag(), BIT(data, 0, 12), BIT(data, 16, 12)); + + case 8: // Polygon fill + fatalerror("%s: Unsupported 2D polygon_fill", tag()); + + default: + fatalerror("%s: Unsupported 2D unknown command %d", tag(), m_blt_cmd); + } +} + + +//************************************************************************** +// VOODOO 3 DEVICE +//************************************************************************** + +//------------------------------------------------- +// voodoo_3_device - constructor +//------------------------------------------------- + +DEFINE_DEVICE_TYPE(VOODOO_3, voodoo_3_device, "voodoo_3", "3dfx Voodoo 3") + +voodoo_3_device::voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + voodoo_banshee_device(mconfig, VOODOO_3, tag, owner, clock, voodoo_model::VOODOO_3) +{ +} + + +//------------------------------------------------- +// device_start - device startup +//------------------------------------------------- + +void voodoo_3_device::device_start() +{ + // Voodoo-3 has 2 TMUs standard + if (m_chipmask == 0x01) + m_chipmask = 0x07; + + // start like a Banshee + voodoo_banshee_device::device_start(); +} + + +//************************************************************************** +// VOODOO BANSHEE REGISTER MAP +//************************************************************************** + +#define REGISTER_ENTRY(name, reader, writer, bits, chips, sync, fifo) \ + { static_register_table_entry::make_mask(bits), register_table_entry::CHIPMASK_##chips | register_table_entry::SYNC_##sync | register_table_entry::FIFO_##fifo, #name, &voodoo_banshee_device::reg_##writer##_w, &voodoo_banshee_device::reg_##reader##_r }, + +#define RESERVED_ENTRY REGISTER_ENTRY(reserved, invalid, invalid, 32, FBI, NOSYNC, FIFO) + +#define RESERVED_ENTRY_x8 RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY RESERVED_ENTRY + +static_register_table_entry const voodoo_banshee_device::s_register_table[256] = +{ + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(status, status, invalid, 32, FBI, NOSYNC, FIFO) // 000 + REGISTER_ENTRY(intrCtrl, passive, intrctrl, 32, FBI, NOSYNC, NOFIFO) // 004 - cmdFIFO mode + REGISTER_ENTRY(vertexAx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 008 + REGISTER_ENTRY(vertexAy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 00c + REGISTER_ENTRY(vertexBx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 010 + REGISTER_ENTRY(vertexBy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 014 + REGISTER_ENTRY(vertexCx, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 018 + REGISTER_ENTRY(vertexCy, invalid, passive, 16, FBI_TREX, NOSYNC, FIFO) // 01c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(startR, invalid, passive, 24, FBI, NOSYNC, FIFO) // 020 + REGISTER_ENTRY(startG, invalid, passive, 24, FBI, NOSYNC, FIFO) // 024 + REGISTER_ENTRY(startB, invalid, passive, 24, FBI, NOSYNC, FIFO) // 028 + REGISTER_ENTRY(startZ, invalid, passive, 32, FBI, NOSYNC, FIFO) // 02c + REGISTER_ENTRY(startA, invalid, passive, 24, FBI, NOSYNC, FIFO) // 030 + REGISTER_ENTRY(startS, invalid, starts, 32, TREX, NOSYNC, FIFO) // 034 + REGISTER_ENTRY(startT, invalid, startt, 32, TREX, NOSYNC, FIFO) // 038 + REGISTER_ENTRY(startW, invalid, startw, 32, FBI_TREX, NOSYNC, FIFO) // 03c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 040 + REGISTER_ENTRY(dGdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 044 + REGISTER_ENTRY(dBdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 048 + REGISTER_ENTRY(dZdX, invalid, passive, 32, FBI, NOSYNC, FIFO) // 04c + REGISTER_ENTRY(dAdX, invalid, passive, 24, FBI, NOSYNC, FIFO) // 050 + REGISTER_ENTRY(dSdX, invalid, dsdx, 32, TREX, NOSYNC, FIFO) // 054 + REGISTER_ENTRY(dTdX, invalid, dtdx, 32, TREX, NOSYNC, FIFO) // 058 + REGISTER_ENTRY(dWdX, invalid, dwdx, 32, FBI_TREX, NOSYNC, FIFO) // 05c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(dRdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 060 + REGISTER_ENTRY(dGdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 064 + REGISTER_ENTRY(dBdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 068 + REGISTER_ENTRY(dZdY, invalid, passive, 32, FBI, NOSYNC, FIFO) // 06c + REGISTER_ENTRY(dAdY, invalid, passive, 24, FBI, NOSYNC, FIFO) // 070 + REGISTER_ENTRY(dSdY, invalid, dsdy, 32, TREX, NOSYNC, FIFO) // 074 + REGISTER_ENTRY(dTdY, invalid, dtdy, 32, TREX, NOSYNC, FIFO) // 078 + REGISTER_ENTRY(dWdY, invalid, dwdy, 32, FBI_TREX, NOSYNC, FIFO) // 07c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(triangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 080 + RESERVED_ENTRY // 084 + REGISTER_ENTRY(fvertexAx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 088 + REGISTER_ENTRY(fvertexAy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 08c + REGISTER_ENTRY(fvertexBx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 090 + REGISTER_ENTRY(fvertexBy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 094 + REGISTER_ENTRY(fvertexCx, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 098 + REGISTER_ENTRY(fvertexCy, invalid, fpassive_4, 32, FBI_TREX, NOSYNC, FIFO) // 09c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fstartR, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a0 + REGISTER_ENTRY(fstartG, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a4 + REGISTER_ENTRY(fstartB, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0a8 + REGISTER_ENTRY(fstartZ, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ac + REGISTER_ENTRY(fstartA, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0b0 + REGISTER_ENTRY(fstartS, invalid, fstarts, 32, TREX, NOSYNC, FIFO) // 0b4 + REGISTER_ENTRY(fstartT, invalid, fstartt, 32, TREX, NOSYNC, FIFO) // 0b8 + REGISTER_ENTRY(fstartW, invalid, fstartw, 32, FBI_TREX, NOSYNC, FIFO) // 0bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c0 + REGISTER_ENTRY(fdGdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c4 + REGISTER_ENTRY(fdBdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0c8 + REGISTER_ENTRY(fdZdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0cc + REGISTER_ENTRY(fdAdX, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0d0 + REGISTER_ENTRY(fdSdX, invalid, fdsdx, 32, TREX, NOSYNC, FIFO) // 0d4 + REGISTER_ENTRY(fdTdX, invalid, fdtdx, 32, TREX, NOSYNC, FIFO) // 0d8 + REGISTER_ENTRY(fdWdX, invalid, fdwdx, 32, FBI_TREX, NOSYNC, FIFO) // 0dc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fdRdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e0 + REGISTER_ENTRY(fdGdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e4 + REGISTER_ENTRY(fdBdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0e8 + REGISTER_ENTRY(fdZdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0ec + REGISTER_ENTRY(fdAdY, invalid, fpassive_12, 32, FBI, NOSYNC, FIFO) // 0f0 + REGISTER_ENTRY(fdSdY, invalid, fdsdy, 32, TREX, NOSYNC, FIFO) // 0f4 + REGISTER_ENTRY(fdTdY, invalid, fdtdy, 32, TREX, NOSYNC, FIFO) // 0f8 + REGISTER_ENTRY(fdWdY, invalid, fdwdy, 32, FBI_TREX, NOSYNC, FIFO) // 0fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(ftriangleCMD, invalid, triangle, 32, FBI_TREX, NOSYNC, FIFO) // 100 + REGISTER_ENTRY(fbzColorPath, passive, passive, 30, FBI_TREX, NOSYNC, FIFO) // 104 + REGISTER_ENTRY(fogMode, passive, passive, 8, FBI_TREX, NOSYNC, FIFO) // 108 + REGISTER_ENTRY(alphaMode, passive, passive, 32, FBI_TREX, NOSYNC, FIFO) // 10c + REGISTER_ENTRY(fbzMode, passive, passive, 22, FBI_TREX, SYNC, FIFO) // 110 + REGISTER_ENTRY(lfbMode, passive, passive, 17, FBI_TREX, SYNC, FIFO) // 114 + REGISTER_ENTRY(clipLeftRight, passive, passive, 32, FBI_TREX, SYNC, FIFO) // 118 + REGISTER_ENTRY(clipLowYHighY, passive, passive, 32, FBI_TREX, SYNC, FIFO) // 11c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nopCMD, invalid, nop, 2, FBI_TREX, SYNC, FIFO) // 120 + REGISTER_ENTRY(fastfillCMD, invalid, fastfill, 0, FBI, SYNC, FIFO) // 124 + REGISTER_ENTRY(swapbufferCMD, invalid, swapbuffer, 10, FBI, SYNC, FIFO) // 128 + REGISTER_ENTRY(fogColor, invalid, passive, 24, FBI, SYNC, FIFO) // 12c + REGISTER_ENTRY(zaColor, invalid, passive, 32, FBI, SYNC, FIFO) // 130 + REGISTER_ENTRY(chromaKey, invalid, passive, 24, FBI, SYNC, FIFO) // 134 + REGISTER_ENTRY(chromaRange, invalid, passive, 28, FBI, SYNC, FIFO) // 138 + REGISTER_ENTRY(userIntrCMD, invalid, userintr, 10, FBI, SYNC, FIFO) // 13c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(stipple, passive, passive, 32, FBI, SYNC, FIFO) // 140 + REGISTER_ENTRY(color0, passive, passive, 32, FBI, SYNC, FIFO) // 144 + REGISTER_ENTRY(color1, passive, passive, 32, FBI, SYNC, FIFO) // 148 + REGISTER_ENTRY(fbiPixelsIn, stats, invalid, 24, FBI, NA, NA) // 14c + REGISTER_ENTRY(fbiChromaFail, stats, invalid, 24, FBI, NA, NA) // 150 + REGISTER_ENTRY(fbiZfuncFail, stats, invalid, 24, FBI, NA, NA) // 154 + REGISTER_ENTRY(fbiAfuncFail, stats, invalid, 24, FBI, NA, NA) // 158 + REGISTER_ENTRY(fbiPixelsOut, stats, invalid, 24, FBI, NA, NA) // 15c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[0], invalid, fogtable, 32, FBI, SYNC, FIFO) // 160 + REGISTER_ENTRY(fogTable[1], invalid, fogtable, 32, FBI, SYNC, FIFO) // 164 + REGISTER_ENTRY(fogTable[2], invalid, fogtable, 32, FBI, SYNC, FIFO) // 168 + REGISTER_ENTRY(fogTable[3], invalid, fogtable, 32, FBI, SYNC, FIFO) // 16c + REGISTER_ENTRY(fogTable[4], invalid, fogtable, 32, FBI, SYNC, FIFO) // 170 + REGISTER_ENTRY(fogTable[5], invalid, fogtable, 32, FBI, SYNC, FIFO) // 174 + REGISTER_ENTRY(fogTable[6], invalid, fogtable, 32, FBI, SYNC, FIFO) // 178 + REGISTER_ENTRY(fogTable[7], invalid, fogtable, 32, FBI, SYNC, FIFO) // 17c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[8], invalid, fogtable, 32, FBI, SYNC, FIFO) // 180 + REGISTER_ENTRY(fogTable[9], invalid, fogtable, 32, FBI, SYNC, FIFO) // 184 + REGISTER_ENTRY(fogTable[10], invalid, fogtable, 32, FBI, SYNC, FIFO) // 188 + REGISTER_ENTRY(fogTable[11], invalid, fogtable, 32, FBI, SYNC, FIFO) // 18c + REGISTER_ENTRY(fogTable[12], invalid, fogtable, 32, FBI, SYNC, FIFO) // 190 + REGISTER_ENTRY(fogTable[13], invalid, fogtable, 32, FBI, SYNC, FIFO) // 194 + REGISTER_ENTRY(fogTable[14], invalid, fogtable, 32, FBI, SYNC, FIFO) // 198 + REGISTER_ENTRY(fogTable[15], invalid, fogtable, 32, FBI, SYNC, FIFO) // 19c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[16], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a0 + REGISTER_ENTRY(fogTable[17], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a4 + REGISTER_ENTRY(fogTable[18], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1a8 + REGISTER_ENTRY(fogTable[19], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1ac + REGISTER_ENTRY(fogTable[20], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b0 + REGISTER_ENTRY(fogTable[21], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b4 + REGISTER_ENTRY(fogTable[22], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1b8 + REGISTER_ENTRY(fogTable[23], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1bc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(fogTable[24], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c0 + REGISTER_ENTRY(fogTable[25], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c4 + REGISTER_ENTRY(fogTable[26], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1c8 + REGISTER_ENTRY(fogTable[27], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1cc + REGISTER_ENTRY(fogTable[28], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d0 + REGISTER_ENTRY(fogTable[29], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d4 + REGISTER_ENTRY(fogTable[30], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1d8 + REGISTER_ENTRY(fogTable[31], invalid, fogtable, 32, FBI, SYNC, FIFO) // 1dc + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY // 1e0 + RESERVED_ENTRY // 1e4 + RESERVED_ENTRY // 1e8 + REGISTER_ENTRY(colBufferAddr, passive, colbufbase, 24, FBI, SYNC, FIFO) // 1ec + REGISTER_ENTRY(colBufferStride, passive, colbufstride,16, FBI, SYNC, FIFO) // 1f0 + REGISTER_ENTRY(auxBufferAddr, passive, auxbufbase, 24, FBI, SYNC, FIFO) // 1f4 + REGISTER_ENTRY(auxBufferStride, passive, auxbufstride,16, FBI, SYNC, FIFO) // 1f8 + RESERVED_ENTRY // 1fc + + REGISTER_ENTRY(clipLeftRight1, passive, passive, 32, FBI, SYNC, FIFO) // 200 + REGISTER_ENTRY(clipTopBottom1, passive, passive, 32, FBI, SYNC, FIFO) // 204 + RESERVED_ENTRY // 208 + RESERVED_ENTRY // 20c + RESERVED_ENTRY // 210 + RESERVED_ENTRY // 214 + RESERVED_ENTRY // 218 + RESERVED_ENTRY // 21c + + RESERVED_ENTRY_x8 // 220-23c + + RESERVED_ENTRY // 240 + RESERVED_ENTRY // 244 + RESERVED_ENTRY // 248 + REGISTER_ENTRY(swapPending, invalid, swappending, 32, FBI, NOSYNC, NOFIFO) // 24c + REGISTER_ENTRY(leftOverlayBuf, invalid, overbuffer, 32, FBI, NOSYNC, FIFO) // 250 + REGISTER_ENTRY(rightOverlayBuf, invalid, overbuffer, 32, FBI, NOSYNC, FIFO) // 254 + REGISTER_ENTRY(fbiSwapHistory, passive, invalid, 32, FBI, NA, NA) // 258 + REGISTER_ENTRY(fbiTrianglesOut, passive, invalid, 24, FBI, NA, NA) // 25c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sSetupMode, invalid, passive, 20, FBI, NOSYNC, FIFO) // 260 + REGISTER_ENTRY(sVx, invalid, passive, 32, FBI, NOSYNC, FIFO) // 264 + REGISTER_ENTRY(sVy, invalid, passive, 32, FBI, NOSYNC, FIFO) // 268 + REGISTER_ENTRY(sARGB, invalid, sargb, 32, FBI, NOSYNC, FIFO) // 26c + REGISTER_ENTRY(sRed, invalid, passive, 32, FBI, NOSYNC, FIFO) // 270 + REGISTER_ENTRY(sGreen, invalid, passive, 32, FBI, NOSYNC, FIFO) // 274 + REGISTER_ENTRY(sBlue, invalid, passive, 32, FBI, NOSYNC, FIFO) // 278 + REGISTER_ENTRY(sAlpha, invalid, passive, 32, FBI, NOSYNC, FIFO) // 27c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sVz, invalid, passive, 32, FBI, NOSYNC, FIFO) // 280 + REGISTER_ENTRY(sWb, invalid, passive, 32, FBI, NOSYNC, FIFO) // 284 + REGISTER_ENTRY(sWtmu0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 288 + REGISTER_ENTRY(sS_W0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 28c + REGISTER_ENTRY(sT_W0, invalid, passive, 32, FBI, NOSYNC, FIFO) // 290 + REGISTER_ENTRY(sWtmu1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 294 + REGISTER_ENTRY(sS_W1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 298 + REGISTER_ENTRY(sT_W1, invalid, passive, 32, FBI, NOSYNC, FIFO) // 29c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(sDrawTriCMD, invalid, draw_tri, 32, FBI, NOSYNC, FIFO) // 2a0 + REGISTER_ENTRY(sBeginTriCMD, invalid, begin_tri, 32, FBI, NOSYNC, FIFO) // 2a4 + RESERVED_ENTRY // 2a8 + RESERVED_ENTRY // 2ac + RESERVED_ENTRY // 2b0 + RESERVED_ENTRY // 2b4 + RESERVED_ENTRY // 2b8 + RESERVED_ENTRY // 2bc + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY_x8 // 2c0-2dc + RESERVED_ENTRY_x8 // 2e0-2fc + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(textureMode, invalid, texture, 31, TREX, NOSYNC, FIFO) // 300 + REGISTER_ENTRY(tLOD, invalid, texture, 28, TREX, NOSYNC, FIFO) // 304 + REGISTER_ENTRY(tDetail, invalid, texture, 22, TREX, NOSYNC, FIFO) // 308 + REGISTER_ENTRY(texBaseAddr, invalid, texture, 32, TREX, NOSYNC, FIFO) // 30c + REGISTER_ENTRY(texBaseAddr_1, invalid, texture, 24, TREX, NOSYNC, FIFO) // 310 + REGISTER_ENTRY(texBaseAddr_2, invalid, texture, 24, TREX, NOSYNC, FIFO) // 314 + REGISTER_ENTRY(texBaseAddr_3_8, invalid, texture, 24, TREX, NOSYNC, FIFO) // 318 + REGISTER_ENTRY(trexInit0, invalid, passive, 32, TREX, SYNC, FIFO) // 31c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(trexInit1, invalid, passive, 32, TREX, SYNC, FIFO) // 320 + REGISTER_ENTRY(nccTable0[0], invalid, palette, 32, TREX, SYNC, FIFO) // 324 + REGISTER_ENTRY(nccTable0[1], invalid, palette, 32, TREX, SYNC, FIFO) // 328 + REGISTER_ENTRY(nccTable0[2], invalid, palette, 32, TREX, SYNC, FIFO) // 32c + REGISTER_ENTRY(nccTable0[3], invalid, palette, 32, TREX, SYNC, FIFO) // 330 + REGISTER_ENTRY(nccTable0[4], invalid, palette, 32, TREX, SYNC, FIFO) // 334 + REGISTER_ENTRY(nccTable0[5], invalid, palette, 32, TREX, SYNC, FIFO) // 338 + REGISTER_ENTRY(nccTable0[6], invalid, palette, 32, TREX, SYNC, FIFO) // 33c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable0[7], invalid, palette, 32, TREX, SYNC, FIFO) // 340 + REGISTER_ENTRY(nccTable0[8], invalid, palette, 32, TREX, SYNC, FIFO) // 344 + REGISTER_ENTRY(nccTable0[9], invalid, palette, 32, TREX, SYNC, FIFO) // 348 + REGISTER_ENTRY(nccTable0[10], invalid, palette, 32, TREX, SYNC, FIFO) // 34c + REGISTER_ENTRY(nccTable0[11], invalid, palette, 32, TREX, SYNC, FIFO) // 350 + REGISTER_ENTRY(nccTable1[0], invalid, palette, 32, TREX, SYNC, FIFO) // 354 + REGISTER_ENTRY(nccTable1[1], invalid, palette, 32, TREX, SYNC, FIFO) // 358 + REGISTER_ENTRY(nccTable1[2], invalid, palette, 32, TREX, SYNC, FIFO) // 35c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[3], invalid, palette, 32, TREX, SYNC, FIFO) // 360 + REGISTER_ENTRY(nccTable1[4], invalid, palette, 32, TREX, SYNC, FIFO) // 364 + REGISTER_ENTRY(nccTable1[5], invalid, palette, 32, TREX, SYNC, FIFO) // 368 + REGISTER_ENTRY(nccTable1[6], invalid, palette, 32, TREX, SYNC, FIFO) // 36c + REGISTER_ENTRY(nccTable1[7], invalid, palette, 32, TREX, SYNC, FIFO) // 370 + REGISTER_ENTRY(nccTable1[8], invalid, palette, 32, TREX, SYNC, FIFO) // 374 + REGISTER_ENTRY(nccTable1[9], invalid, palette, 32, TREX, SYNC, FIFO) // 378 + REGISTER_ENTRY(nccTable1[10], invalid, palette, 32, TREX, SYNC, FIFO) // 37c + // name rd handler wr handler bits chips sync? fifo? + REGISTER_ENTRY(nccTable1[11], invalid, palette, 32, TREX, SYNC, FIFO) // 380 + RESERVED_ENTRY // 384 + RESERVED_ENTRY // 388 + RESERVED_ENTRY // 38c + RESERVED_ENTRY // 390 + RESERVED_ENTRY // 394 + RESERVED_ENTRY // 398 + RESERVED_ENTRY // 39c + // name rd handler wr handler bits chips sync? fifo? + RESERVED_ENTRY_x8 // 3a0-3bc + RESERVED_ENTRY_x8 // 3c0-3dc + RESERVED_ENTRY_x8 // 3e0-3fc +}; diff --git a/src/devices/video/voodoo_banshee.h b/src/devices/video/voodoo_banshee.h new file mode 100644 index 00000000000..31afb8289ae --- /dev/null +++ b/src/devices/video/voodoo_banshee.h @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_banshee.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#ifndef MAME_VIDEO_VOODOO_BANSHEE_H +#define MAME_VIDEO_VOODOO_BANSHEE_H + +#pragma once + +#include "voodoo_2.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +namespace voodoo +{ + +// logging +static constexpr bool LOG_BANSHEE_2D = false; + +} + + +//************************************************************************** +// VOODOO DEVICES +//************************************************************************** + +DECLARE_DEVICE_TYPE(VOODOO_BANSHEE, voodoo_banshee_device) + +// ======================> voodoo_banshee_device + +class voodoo_banshee_device : public voodoo_2_device +{ +protected: + // internal construction + voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model); + +public: + // nominal clock values + static constexpr u32 NOMINAL_CLOCK = 90'000'000; + + // construction + voodoo_banshee_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + voodoo_banshee_device(mconfig, VOODOO_BANSHEE, tag, owner, clock, voodoo::voodoo_model::VOODOO_BANSHEE) { } + + // core address map and read/write helpers + virtual void core_map(address_map &map) override; + virtual u32 read(offs_t offset, u32 mem_mask = ~0) override; + virtual void write(offs_t offset, u32 data, u32 mem_mask = ~0) override; + + // LFB address map and read/write helpers + virtual void lfb_map(address_map &map); + virtual u32 read_lfb(offs_t offset, u32 mem_mask = ~0); + virtual void write_lfb(offs_t offset, u32 data, u32 mem_mask = ~0); + + // I/O address map and read/write helpers + virtual void io_map(address_map &map); + virtual u32 read_io(offs_t offset, u32 mem_mask = ~0) { return map_io_r(offset, mem_mask); } + virtual void write_io(offs_t offset, u32 data, u32 mem_mask = ~0) { map_io_w(offset, data, mem_mask); } + + // video update + virtual int update(bitmap_rgb32 &bitmap, const rectangle &cliprect) override; + +protected: + // device-level overrides + virtual void device_start() override; + + // system management + virtual void soft_reset() override; + virtual void register_save(voodoo::save_proxy &save, u32 total_allocation) override; + + // buffer accessors + virtual u16 *lfb_buffer_indirect(int index) override; + virtual u16 *draw_buffer_indirect(int index) override; + + // mapped reads + u32 map_io_r(offs_t offset, u32 mem_mask); + u32 map_cmd_agp_r(offs_t offset); + u32 map_2d_r(offs_t offset); + u32 map_register_r(offs_t offset); + + // mapped writes + void map_io_w(offs_t offset, u32 data, u32 mem_mask); + void map_cmd_agp_w(offs_t offset, u32 data, u32 mem_mask); + void map_2d_w(offs_t offset, u32 data, u32 mem_mask); + void map_register_w(offs_t offset, u32 data, u32 mem_mask); + template void map_texture_w(offs_t offset, u32 data, u32 mem_mask); + void map_yuv_w(offs_t offset, u32 data, u32 mem_mask); + void map_lfb_w(offs_t offset, u32 data, u32 mem_mask); + + // internal reads and writes + u32 internal_io_r(offs_t offset, u32 mem_mask = ~0); + void internal_io_w(offs_t offset, u32 data, u32 mem_mask = ~0); + u32 internal_cmd_agp_r(offs_t offset); + void internal_cmd_agp_w(offs_t offset, u32 data, u32 mem_mask = ~0); + s32 internal_2d_w(offs_t offset, u32 data); + virtual void internal_texture_w(offs_t offset, u32 data) override; + void internal_lfb_direct_w(offs_t offset, u32 data, u32 mem_mask); + u8 internal_vga_r(offs_t offset); + void internal_vga_w(offs_t offset, u8 data); + + // read/write and FIFO helpers + virtual u32 execute_fifos() override; + + // register read accessors + u32 reg_status_r(u32 chipmask, u32 offset); + + // register write accessors + u32 reg_colbufbase_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_colbufstride_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_auxbufbase_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_auxbufstride_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_swappending_w(u32 chipmask, u32 regnum, u32 data); + u32 reg_overbuffer_w(u32 chipmask, u32 regnum, u32 data); + + // VBLANK timing + virtual void rotate_buffers() override; + + // video timing and updates + void recompute_video(); + + // command FIFO-specific write handlers + virtual u32 cmdfifo_register_w(u32 offset, u32 data) override; + virtual u32 cmdfifo_2d_w(u32 offset, u32 data) override; + + // rendering + void execute_blit(u32 data); + + // internal state + u32 m_lfb_base; // configured LFB base + voodoo::command_fifo m_cmdfifo2; // second command FIFO + + + voodoo::banshee_io_regs m_io_regs; // I/O registers + voodoo::banshee_cmd_agp_regs m_cmd_agp_regs; // CMD/AGP registers + voodoo::banshee_vga_regs m_vga_regs; // VGA registers + + voodoo::banshee_2d_regs m_2d_regs; // 2D registers + u32 m_blt_dst_base = 0; + u32 m_blt_dst_x = 0; + u32 m_blt_dst_y = 0; + u32 m_blt_dst_width = 0; + u32 m_blt_dst_height = 0; + u32 m_blt_dst_stride = 0; + u32 m_blt_dst_bpp = 0; + u32 m_blt_cmd = 0; + u32 m_blt_src_base = 0; + u32 m_blt_src_x = 0; + u32 m_blt_src_y = 0; + u32 m_blt_src_width = 0; + u32 m_blt_src_height = 0; + u32 m_blt_src_stride = 0; + u32 m_blt_src_bpp = 0; + + static voodoo::static_register_table_entry const s_register_table[256]; +}; + + +// ======================> voodoo_3_device + +DECLARE_DEVICE_TYPE(VOODOO_3, voodoo_3_device) + +class voodoo_3_device : public voodoo_banshee_device +{ +public: + // nominal clock values + static constexpr u32 NOMINAL_CLOCK = 132'000'000; + + // construction + voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + // device-level overrides + virtual void device_start() override; +}; + +#endif // MAME_VIDEO_VOODOO_BANSHEE_H diff --git a/src/devices/video/voodoo_pci.cpp b/src/devices/video/voodoo_pci.cpp index ed795bd21bc..e27413c8851 100644 --- a/src/devices/video/voodoo_pci.cpp +++ b/src/devices/video/voodoo_pci.cpp @@ -8,28 +8,40 @@ void voodoo_1_pci_device::device_add_mconfig(machine_config &config) { - VOODOO_1(config, m_voodoo, STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo, voodoo_1_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(4); m_voodoo->set_tmumem(1, 0); + m_voodoo->set_status_cycles(m_status_cycles); + m_voodoo->set_cpu(m_cpu); + m_voodoo->set_screen(m_screen); } void voodoo_2_pci_device::device_add_mconfig(machine_config &config) { - VOODOO_2(config, m_voodoo, STD_VOODOO_2_CLOCK); + VOODOO_2(config, m_voodoo, voodoo_2_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(4); m_voodoo->set_tmumem(1, 0); + m_voodoo->set_status_cycles(m_status_cycles); + m_voodoo->set_cpu(m_cpu); + m_voodoo->set_screen(m_screen); } void voodoo_banshee_pci_device::device_add_mconfig(machine_config &config) { - VOODOO_BANSHEE(config, m_voodoo, STD_VOODOO_BANSHEE_CLOCK); + VOODOO_BANSHEE(config, m_voodoo, voodoo_banshee_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(16); + m_voodoo->set_status_cycles(m_status_cycles); + m_voodoo->set_cpu(m_cpu); + m_voodoo->set_screen(m_screen); } void voodoo_3_pci_device::device_add_mconfig(machine_config &config) { - VOODOO_3(config, m_voodoo, STD_VOODOO_3_CLOCK); + VOODOO_3(config, m_voodoo, voodoo_3_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(16); + m_voodoo->set_status_cycles(m_status_cycles); + m_voodoo->set_cpu(m_cpu); + m_voodoo->set_screen(m_screen); } DEFINE_DEVICE_TYPE(VOODOO_1_PCI, voodoo_1_pci_device, "voodoo_1_pci", "Voodoo 1 PCI") @@ -43,74 +55,50 @@ void voodoo_pci_device::config_map(address_map &map) map(0x40, 0x5f).rw(FUNC(voodoo_pci_device::pcictrl_r), FUNC(voodoo_pci_device::pcictrl_w)); } -// VOODOO_1 & VOODOO_2 map -void voodoo_pci_device::voodoo_reg_map(address_map &map) -{ - map(0x0, 0x00ffffff).rw(m_voodoo, FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); -} -// VOODOO_BANSHEE and VOODOO_3 maps -void voodoo_pci_device::banshee_reg_map(address_map &map) -{ - map(0x0, 0x01ffffff).rw(m_voodoo, FUNC(voodoo_banshee_device::banshee_r), FUNC(voodoo_banshee_device::banshee_w)); -} - -void voodoo_pci_device::lfb_map(address_map &map) -{ - map(0x0, 0x01ffffff).rw(m_voodoo, FUNC(voodoo_banshee_device::banshee_fb_r), FUNC(voodoo_banshee_device::banshee_fb_w)); -} - -void voodoo_pci_device::io_map(address_map &map) -{ - map(0x000, 0x0ff).rw(m_voodoo, FUNC(voodoo_banshee_device::banshee_io_r), FUNC(voodoo_banshee_device::banshee_io_w)); -} - -voodoo_pci_device::voodoo_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) +voodoo_pci_device::voodoo_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : pci_device(mconfig, type, tag, owner, clock), - m_voodoo(*this, "voodoo"), m_cpu(*this, finder_base::DUMMY_TAG), m_screen(*this, finder_base::DUMMY_TAG), m_fbmem(2), m_tmumem0(0), m_tmumem1(0) + m_generic_voodoo(*this, "voodoo"), m_cpu(*this, finder_base::DUMMY_TAG), m_screen(*this, finder_base::DUMMY_TAG), m_fbmem(2), m_tmumem0(0), m_tmumem1(0) { } -voodoo_1_pci_device::voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_pci_device(mconfig, VOODOO_1_PCI, tag, owner, clock) +voodoo_1_pci_device::voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : voodoo_pci_device(mconfig, VOODOO_1_PCI, tag, owner, clock), m_voodoo(*this, "voodoo") { } -voodoo_2_pci_device::voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_pci_device(mconfig, VOODOO_2_PCI, tag, owner, clock) +voodoo_2_pci_device::voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : voodoo_pci_device(mconfig, VOODOO_2_PCI, tag, owner, clock), m_voodoo(*this, "voodoo") { } -voodoo_banshee_pci_device::voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_pci_device(mconfig, VOODOO_BANSHEE_PCI, tag, owner, clock) +voodoo_banshee_pci_device::voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : voodoo_pci_device(mconfig, VOODOO_BANSHEE_PCI, tag, owner, clock), m_voodoo(*this, "voodoo") { } -voodoo_3_pci_device::voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : voodoo_pci_device(mconfig, VOODOO_3_PCI, tag, owner, clock) +voodoo_3_pci_device::voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : voodoo_pci_device(mconfig, VOODOO_3_PCI, tag, owner, clock), m_voodoo(*this, "voodoo") { } void voodoo_pci_device::device_start() { - if (m_cpu) - m_voodoo->set_cpu(*m_cpu); - if (m_screen) - m_voodoo->set_screen(*m_screen); - m_voodoo->set_fbmem(m_fbmem); - m_voodoo->set_tmumem(m_tmumem0, m_tmumem1); + m_generic_voodoo->set_fbmem(m_fbmem); + m_generic_voodoo->set_tmumem(m_tmumem0, m_tmumem1); + m_generic_voodoo->set_status_cycles(m_status_cycles); pci_device::device_start(); save_item(NAME(m_pcictrl_reg)); machine().save().register_postload(save_prepost_delegate(FUNC(voodoo_pci_device::postload), this)); } -//void set_ids(uint32_t main_id, uint8_t revision, uint32_t pclass, uint32_t subsystem_id); +//void set_ids(u32 main_id, u8 revision, u32 pclass, u32 subsystem_id); void voodoo_1_pci_device::device_start() { set_ids(0x121a0001, 0x02, 0x030000, 0x000000); voodoo_pci_device::device_start(); - add_map(16 * 1024 * 1024, M_MEM | M_PREF, FUNC(voodoo_pci_device::voodoo_reg_map)); + add_map(16 * 1024 * 1024, M_MEM | M_PREF, *m_voodoo, FUNC(voodoo_1_device::core_map)); bank_infos[0].adr = 0xff000000; } @@ -120,7 +108,7 @@ void voodoo_2_pci_device::device_start() voodoo_pci_device::device_start(); - add_map(16 * 1024 * 1024, M_MEM | M_PREF, FUNC(voodoo_pci_device::voodoo_reg_map)); + add_map(16 * 1024 * 1024, M_MEM | M_PREF, *m_voodoo, FUNC(voodoo_2_device::core_map)); bank_infos[0].adr = 0xff000000; } @@ -130,9 +118,9 @@ void voodoo_banshee_pci_device::device_start() voodoo_pci_device::device_start(); - add_map(32 * 1024 * 1024, M_MEM, FUNC(voodoo_pci_device::banshee_reg_map)); - add_map(32 * 1024 * 1024, M_MEM, FUNC(voodoo_pci_device::lfb_map)); - add_map(256, M_IO, FUNC(voodoo_pci_device::io_map)); + add_map(32 * 1024 * 1024, M_MEM, *m_voodoo, FUNC(voodoo_banshee_device::core_map)); + add_map(32 * 1024 * 1024, M_MEM, *m_voodoo, FUNC(voodoo_banshee_device::lfb_map)); + add_map(256, M_IO, *m_voodoo, FUNC(voodoo_banshee_device::io_map)); bank_infos[0].adr = 0xf8000000; bank_infos[1].adr = 0xf8000008; bank_infos[2].adr = 0xfffffff0; @@ -144,9 +132,12 @@ void voodoo_3_pci_device::device_start() voodoo_pci_device::device_start(); - add_map(32 * 1024 * 1024, M_MEM, FUNC(voodoo_pci_device::banshee_reg_map)); - add_map(32 * 1024 * 1024, M_MEM, FUNC(voodoo_pci_device::lfb_map)); - add_map(256, M_IO, FUNC(voodoo_pci_device::io_map)); + // need to downcast to voodoo_banshee_device because the map functions are shared + // this will cleaner when the PCI interface is implemented as a mix-in + auto &banshee = static_cast(*m_voodoo); + add_map(32 * 1024 * 1024, M_MEM, banshee, FUNC(voodoo_banshee_device::core_map)); + add_map(32 * 1024 * 1024, M_MEM, banshee, FUNC(voodoo_banshee_device::lfb_map)); + add_map(256, M_IO, banshee, FUNC(voodoo_banshee_device::io_map)); bank_infos[0].adr = 0xf8000000; bank_infos[1].adr = 0xf8000008; bank_infos[2].adr = 0xfffffff0; @@ -163,58 +154,61 @@ void voodoo_pci_device::device_reset() pci_device::device_reset(); } -void voodoo_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) +void voodoo_pci_device::map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) { logerror("%s: map_extra\n", this->tag()); } -void voodoo_banshee_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) +void voodoo_banshee_pci_device::map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) { logerror("%s: map_extra\n", this->tag()); // Map VGA legacy access // Should really be dependent on voodoo VGAINIT0 bit 8 and IO base + 0xc3 bit 0 - uint64_t start = io_offset + 0x3b0; - uint64_t end = io_offset + 0x3df; + u64 start = io_offset + 0x3b0; + u64 end = io_offset + 0x3df; io_space->install_readwrite_handler(start, end, read32s_delegate(*this, FUNC(voodoo_pci_device::vga_r)), write32s_delegate(*this, FUNC(voodoo_pci_device::vga_w))); - logerror("%s: map %s at %0*x-%0*x\n", this->tag(), "vga_r/w", 4, uint32_t(start), 4, uint32_t(end)); + logerror("%s: map %s at %0*x-%0*x\n", this->tag(), "vga_r/w", 4, u32(start), 4, u32(end)); } -void voodoo_3_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) +void voodoo_3_pci_device::map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) { logerror("%s: map_extra\n", this->tag()); // Map VGA legacy access // Should really be dependent on voodoo VGAINIT0 bit 8 and IO base + 0xc3 bit 0 - uint64_t start = io_offset + 0x3b0; - uint64_t end = io_offset + 0x3df; + u64 start = io_offset + 0x3b0; + u64 end = io_offset + 0x3df; io_space->install_readwrite_handler(start, end, read32s_delegate(*this, FUNC(voodoo_pci_device::vga_r)), write32s_delegate(*this, FUNC(voodoo_pci_device::vga_w))); - logerror("%s: map %s at %0*x-%0*x\n", this->tag(), "vga_r/w", 4, uint32_t(start), 4, uint32_t(end)); + logerror("%s: map %s at %0*x-%0*x\n", this->tag(), "vga_r/w", 4, u32(start), 4, u32(end)); } -uint32_t voodoo_pci_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +u32 voodoo_pci_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - return m_voodoo->voodoo_update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; + return m_generic_voodoo->update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; } // PCI bus control -uint32_t voodoo_pci_device::pcictrl_r(offs_t offset, uint32_t mem_mask) +u32 voodoo_pci_device::pcictrl_r(offs_t offset, u32 mem_mask) { - uint32_t result = m_pcictrl_reg[offset]; + u32 result = m_pcictrl_reg[offset]; // The address map starts at 0x40 switch (offset + 0x40 / 4) { case 0x40/4: + { // V1: initEnable: 11:0 // V2: initEnable: Fab ID=19:16, Graphics Rev=15:12 // Banshee/V3: fabID: ScratchPad=31:4 fabID=3:0 - if (m_voodoo->vd_type== TYPE_VOODOO_2) + auto model = m_generic_voodoo->model(); + if (model == voodoo::voodoo_model::VOODOO_2) result = (result & ~0xff000) | 0x00044000; // Vegas driver needs this value - else if (m_voodoo->vd_type >= TYPE_VOODOO_BANSHEE) + else if (model >= voodoo::voodoo_model::VOODOO_BANSHEE) result = (result & ~0xf) | 0x1; break; + } case 0x54/4: // V2: SiProcess Register: Osc Force On, Osc Ring Sel, Osc Count Reset, 12 bit PCI Counter, 16 bit Oscillator Counter // V3: AGP Capability Register: 8 bit 0, 4 bit AGP Major, 4 bit AGP Minor, 8 bit Next Ptr, 8 bit Capability ID @@ -227,14 +221,14 @@ uint32_t voodoo_pci_device::pcictrl_r(offs_t offset, uint32_t mem_mask) logerror("%s:voodoo_pci_device pcictrl_r from offset %02X = %08X & %08X\n", machine().describe_context(), offset*4 + 0x40, result, mem_mask); return result; } -void voodoo_pci_device::pcictrl_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void voodoo_pci_device::pcictrl_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_pcictrl_reg[offset]); // The address map starts at 0x40 switch (offset + 0x40 / 4) { case 0x40/4: // HW initEnable - m_voodoo->voodoo_set_init_enable(data); + m_generic_voodoo->set_init_enable(data); logerror("%s:voodoo_pci_device pcictrl_w (initEnable) offset %02X = %08X & %08X\n", machine().describe_context(), offset * 4 + 0x40, data, mem_mask); break; default: @@ -244,32 +238,13 @@ void voodoo_pci_device::pcictrl_w(offs_t offset, uint32_t data, uint32_t mem_mas } // VGA legacy accesses -uint32_t voodoo_pci_device::vga_r(offs_t offset, uint32_t mem_mask) +u32 voodoo_pci_device::vga_r(offs_t offset, u32 mem_mask) { - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_voodoo.target())->banshee_vga_r(offset * 4 + 0 + 0xb0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_voodoo.target())->banshee_vga_r(offset * 4 + 1 + 0xb0) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_voodoo.target())->banshee_vga_r(offset * 4 + 2 + 0xb0) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_voodoo.target())->banshee_vga_r(offset * 4 + 3 + 0xb0) << 24; - if (0) - logerror("%s voodoo_pci_device vga_r from offset %02X = %08X & %08X\n", machine().describe_context(), offset * 4, result, mem_mask); - return result; + // map to I/O space at offset 0xb0 + return m_generic_voodoo->read(0xb0/4 + offset, mem_mask); } -void voodoo_pci_device::vga_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void voodoo_pci_device::vga_w(offs_t offset, u32 data, u32 mem_mask) { - if (ACCESSING_BITS_0_7) - downcast(m_voodoo.target())->banshee_vga_w(offset * 4 + 0 + 0xb0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_voodoo.target())->banshee_vga_w(offset * 4 + 1 + 0xb0, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_voodoo.target())->banshee_vga_w(offset * 4 + 2 + 0xb0, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_voodoo.target())->banshee_vga_w(offset * 4 + 3 + 0xb0, data >> 24); - - if (0) - logerror("%s voodoo_pci_device vga_w to offset %04X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask); + // map to I/O space at offset 0xb0 + m_generic_voodoo->write(0xb0/4 + offset, data, mem_mask); } diff --git a/src/devices/video/voodoo_pci.h b/src/devices/video/voodoo_pci.h index faeb6d4c1c5..c56358b2c2f 100644 --- a/src/devices/video/voodoo_pci.h +++ b/src/devices/video/voodoo_pci.h @@ -9,29 +9,26 @@ #include "machine/pci.h" #include "voodoo.h" +#include "voodoo_banshee.h" class voodoo_pci_device : public pci_device { public: - template void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward(tag)); } - template void set_screen_tag(T &&tag) { m_screen.set_tag(std::forward(tag)); } + template void set_cpu(T &&tag) { m_cpu.set_tag(std::forward(tag)); } + template void set_screen(T &&tag) { m_screen.set_tag(std::forward(tag)); } void set_fbmem(int fbmem) { m_fbmem = fbmem; } void set_tmumem(int tmumem0, int tmumem1) { m_tmumem0 = tmumem0; m_tmumem1 = tmumem1; } - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void set_status_cycles(u32 cycles) { m_status_cycles = cycles; } + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - uint32_t vga_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - - void voodoo_reg_map(address_map &map); - void banshee_reg_map(address_map &map); - void lfb_map(address_map &map); - void io_map(address_map &map); + u32 vga_r(offs_t offset, u32 mem_mask = ~0); + void vga_w(offs_t offset, u32 data, u32 mem_mask = ~0); protected: - voodoo_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + voodoo_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); - virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override; + virtual void map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) override; virtual void config_map(address_map &map) override; @@ -40,93 +37,98 @@ protected: virtual void device_start() override; virtual void device_reset() override; - required_device m_voodoo; + required_device m_generic_voodoo; optional_device m_cpu; optional_device m_screen; int m_fbmem, m_tmumem0, m_tmumem1; + u32 m_status_cycles; - uint32_t m_pcictrl_reg[0x20]; + u32 m_pcictrl_reg[0x20]; - uint32_t pcictrl_r(offs_t offset, uint32_t mem_mask = ~0); - void pcictrl_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + u32 pcictrl_r(offs_t offset, u32 mem_mask = ~0); + void pcictrl_w(offs_t offset, u32 data, u32 mem_mask = ~0); }; class voodoo_1_pci_device : public voodoo_pci_device { public: template - voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag, U &&screen_tag) : voodoo_1_pci_device(mconfig, tag, owner, clock) { - set_cpu_tag(std::forward(cpu_tag)); - set_screen_tag(std::forward(screen_tag)); + set_cpu(std::forward(cpu_tag)); + set_screen(std::forward(screen_tag)); } - voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + voodoo_1_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; virtual void device_add_mconfig(machine_config &config) override; + required_device m_voodoo; }; class voodoo_2_pci_device : public voodoo_pci_device { public: template - voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag, U &&screen_tag) : voodoo_2_pci_device(mconfig, tag, owner, clock) { - set_cpu_tag(std::forward(cpu_tag)); - set_screen_tag(std::forward(screen_tag)); + set_cpu(std::forward(cpu_tag)); + set_screen(std::forward(screen_tag)); } - voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + voodoo_2_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; virtual void device_add_mconfig(machine_config &config) override; + required_device m_voodoo; }; class voodoo_banshee_pci_device : public voodoo_pci_device { public: template - voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag, U &&screen_tag) : voodoo_banshee_pci_device(mconfig, tag, owner, clock) { - set_cpu_tag(std::forward(cpu_tag)); - set_screen_tag(std::forward(screen_tag)); + set_cpu(std::forward(cpu_tag)); + set_screen(std::forward(screen_tag)); } - voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + voodoo_banshee_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; virtual void device_add_mconfig(machine_config &config) override; - virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override; + virtual void map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) override; + required_device m_voodoo; }; class voodoo_3_pci_device : public voodoo_pci_device { public: template - voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag) + voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag, U &&screen_tag) : voodoo_3_pci_device(mconfig, tag, owner, clock) { - set_cpu_tag(std::forward(cpu_tag)); - set_screen_tag(std::forward(screen_tag)); + set_cpu(std::forward(cpu_tag)); + set_screen(std::forward(screen_tag)); } - voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + voodoo_3_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: virtual void device_start() override; virtual void device_add_mconfig(machine_config &config) override; - virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, - uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override; + virtual void map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space, + u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) override; + required_device m_voodoo; }; DECLARE_DEVICE_TYPE(VOODOO_1_PCI, voodoo_1_pci_device) diff --git a/src/devices/video/voodoo_rast.ipp b/src/devices/video/voodoo_rast.ipp deleted file mode 100644 index 849e3990cf4..00000000000 --- a/src/devices/video/voodoo_rast.ipp +++ /dev/null @@ -1,615 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles - -/*************************************************************************** - GAME-SPECIFIC RASTERIZERS -***************************************************************************/ - -/* blitz ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 284269 914846168 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 485421 440309121 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 31606 230753709 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 76742 211701679 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 6188 152109056 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* 1100 108134400 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 6229525 106197740 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x0C261A0F, 0xFFFFFFFF ) /* 905641 75886220 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 205236 53317253 */ -RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* 817356 48881349 */ -RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 37979 41687251 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 26014 41183295 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 2512 37911104 */ -RASTERIZER_ENTRY( 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 28834 15527654 */ -RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 9878 4979429 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 199952 4622064 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 8672 3676949 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515010, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* 616 2743972 */ -RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 81380 2494832 */ -//RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 7670 2235587 */ -//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 210 1639140 */ -//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 108 1154736 */ -//RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* 2152 1150842 */ -//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 152 880560 */ -//RASTERIZER_ENTRY( 0x00008035, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 90848 805730 */ -//RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261AC9, 0xFFFFFFFF ) /* 2024 571406 */ -//RASTERIZER_ENTRY( 0x00012136, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 1792 494592 */ -//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* 256 161280 */ - -/* blitz99 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 6297478 149465839 */ -RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 210693 6285480 */ -RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 20180 2718710 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 360 2425416 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 67059 1480978 */ -RASTERIZER_ENTRY( 0x00008035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 24811 400666 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 10304 324468 */ -RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 1024 112665 */ - -/* blitz2k ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 3880 95344128 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00514110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 148 1785480 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610CF, 0xFFFFFFFF ) /* * 9976 314244 */ - -/* carnevil ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 492 84128082 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 1988398 36166780 */ -RASTERIZER_ENTRY( 0x00486116, 0x00045119, 0x00000000, 0x00030279, 0x0C26180F, 0xFFFFFFFF ) /* * 34424 28788847 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 514 26316800 */ -RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 7346 18805760 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0C26180F, 0xFFFFFFFF ) /* * 130764 18678972 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C2618C9, 0xFFFFFFFF ) /* * 7244 12179040 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 84520 12059721 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 21926 11226112 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C2618C9, 0xFFFFFFFF ) /* * 92115 8926536 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 1730 7629334 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0C26180F, 0xFFFFFFFF ) /* * 37408 5545956 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030679, 0x0C26180F, 0xFFFFFFFF ) /* * 26528 4225026 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 35764 3230884 */ -RASTERIZER_ENTRY( 0x01422409, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 96020 1226438 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C2618C9, 0xFFFFFFFF ) /* * 1020 574649 */ -RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 360 370008 */ -RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 576 334404 */ - -/* calspeed ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 99120 1731923836 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9955804 1526119944 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 1898207 1124776864 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 3487467 1101663125 */ -RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1079277 609256033 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0723, 0x0C261ACF, 0xFFFFFFFF ) /* * 11880 583925760 */ -RASTERIZER_ENTRY( 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 63644 582469888 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 22688 556797972 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 1360254 417068457 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 3427489 405421272 */ -RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 286809 238944049 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 28160 231084818 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 183564 201014424 */ -RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 15275 168207109 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 2856 134400000 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 98551 110417974 */ -RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C2610CF, 0xFFFFFFFF ) /* * 47040 107360728 */ -RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 13128 86876789 */ -RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 257515 76329054 */ -RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 3934 64958208 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 77400 63786236 */ -//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 12500 63151200 */ -//RASTERIZER_ENTRY( 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 8764 57629312 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 3257 32708448 */ -//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A07E3, 0x0C2610CF, 0xFFFFFFFF ) /* * 28364 31195605 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 409001 30699647 */ -//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26100F, 0xFFFFFFFF ) /* * 17669 11214172 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 5844 6064373 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 626 4651080 */ -//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 5887 2945500 */ -//RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 1090 2945093 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 228 1723908 */ -//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C261A0F, 0xFFFFFFFF ) /* * 112 1433600 */ -//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 3091 1165805 */ -//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 620 791202 */ - -/* hyprdriv ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 60860 498565120 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 28688 235012096 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 11844 156499968 */ -RASTERIZER_ENTRY( 0x00580035, 0x00045119, 0x00000001, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 175990 146518715 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 2336 114819072 */ -RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 363325 100404294 */ -RASTERIZER_ENTRY( 0x00582C35, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 40918 96318738 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 54815 94990269 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 123032 91652828 */ -RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 82767 86431997 */ -RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 9874 78101834 */ -RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 102146 72570879 */ -RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 657804 67229658 */ -RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B03F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 10428 63173865 */ -RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 230145 57902926 */ -RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 769654 53992486 */ -RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 85365 51865697 */ -RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* * 454674 46165536 */ -RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 101889 33337987 */ -RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 255952 29810993 */ -//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 106190 25430383 */ -//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 595001 23268601 */ -//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 946410 22589110 */ -//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 330036 21323230 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 40089 13470498 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 90906 12850855 */ -//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 9492 12115280 */ -//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 453515 12013961 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 33829 8384312 */ -//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 83986 7841206 */ -//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 42515 7242660 */ -//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 706 6158684 */ -//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 62051 5819485 */ -//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 135139 5063467 */ -//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 10359 5135837 */ -//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 170159 4449246 */ -//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 19037 4371219 */ -//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 8963 4352501 */ -//RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 47712 4159994 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 47525 4151435 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 34980 3794066 */ -//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6540 2358068 */ -//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 703308 2096781 */ -//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A1F, 0xFFFFFFFF ) /* * 3963 2079440 */ -//RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000001, 0x000B073B, 0x0C261AC9, 0xFFFFFFFF ) /* * 22866 2008397 */ -//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69705 1673671 */ -//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13366 1575120 */ -//RASTERIZER_ENTRY( 0x0142613A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 50625 1408211 */ -//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 1244348 1244346 */ -//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13791 1222735 */ -//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 33064 943590 */ -//RASTERIZER_ENTRY( 0x0142610A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 2041 926507 */ -//RASTERIZER_ENTRY( 0x00480019, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 2722 453924 */ -//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 68232 306869 */ -//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000001, 0x000B0379, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 7164 269002 */ - -/* mace -------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 7204150 1340201579 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0xFFFFFFFF ) /* * 15332 1181663232 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 104456 652582379 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 488613 368880164 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 352924 312417405 */ -RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 15024 291762384 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 711824 279246170 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 735574 171881981 */ -RASTERIZER_ENTRY( 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 943006 154374023 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 103877 101077498 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 710125 87547221 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241ACF, 0xFFFFFFFF ) /* * 9834 79774966 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 17644 70187036 */ -RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 11324 56633925 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 96743 40820171 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100794 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100697 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 6723 29076516 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 53297 23928976 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 10309 19001776 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 22105 17473157 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 11304 17236698 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 1664 17180883 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241A0F, 0xFFFFFFFF ) /* * 148606 12274278 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 80692 9248007 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080994 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000001, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080969 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 536 7930305 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 11965 5118044 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 11923 4662909 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082410CF, 0xFFFFFFFF ) /* * 4422 4624260 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824100F, 0xFFFFFFFF ) /* * 3853 3596375 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 400 3555759 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 3755 3453084 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 4170 2425016 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824184F, 0xFFFFFFFF ) /* * 322 2220073 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082418CF, 0xFFFFFFFF ) /* * 4008 1201335 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 13704 883585 */ - -/* sfrush -----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824101F ) /* * 590139 246714190 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 397774 153418144 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082410DF ) /* * 22732 146975666 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824101F ) /* * 306398 130393278 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 437743 117403881 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 66608 109289500 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082410DF ) /* * 19101 92573085 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824181F ) /* * 258287 78618228 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 61814 68788856 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 149792 61464124 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 109988 55083276 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x00000000 ) /* * 478 46989312 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x0824181F ) /* * 468 46006272 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824181F ) /* * 125204 39023396 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x082410DB ) /* * 394 38731776 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 12890 36333568 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 147995 31086325 */ -RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B077B, 0x00000000, 0x082410DB ) /* * 3576 29294592 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 76059 29282981 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 12632 29173808 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082418DF ) /* * 14040 24318118 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 56586 17643207 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 9130 17277440 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 66302 17049921 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824101F ) /* * 64380 16463672 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 152 14942208 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 8748 13810176 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 216634 10628656 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x00000000, 0x082410DB ) /* * 1282 10502144 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 74636 9758030 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 58652 9353671 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 5242 8038747 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 11048 7538060 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 121630 6906591 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082418DF ) /* * 19553 6864245 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082418DF ) /* * 1287 6648834 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 197766 6617876 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 75470 6231739 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x08241ADF, 0x0824101F ) /* * 180 5898240 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 7692 5743360 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 20128 4980591 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1144 4685824 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 72299 4466336 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 3750 4018176 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DF ) /* * 7533 3692141 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 9484 3610674 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 128660 3216280 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 22214 3172813 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 5094 3099098 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 1954 2850924 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1542 2434304 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x00000000 ) /* * 478 1957888 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 468 1916928 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 11664 1729188 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 1282 1640960 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 388 1589248 */ -//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 1282 1312768 */ -//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 3928 1046582 */ - -/* sfrushrk---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824101F) /* * 27 992960 15063136 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0824101F) /* * 81 1014993 6262343 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824101F, 0x0824101F) /* * 7 283517 3673219 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F) /* * 15 272066 3479808 */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x042210C0) /* * 73 10072 2751593 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082700DF, 0x0824101F) /* * 59 399456 2293575 */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082410DB) /* * 12 94616 1697401 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824181F) /* * 83 197678 1694134 */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F) /* * 38 47356 1655374 */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x042210C0) /* * 94 7526 1449675 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082418DF) /* * 89 58657 1178470 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F) /* * 4 117539 1114862 */ -RASTERIZER_ENTRY(0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x042210C0) /* * 52 30451 905250 */ - -/* vaportrx ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2226138 592165102 */ -RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 53533 281405105 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 314131 219103141 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 216329 95014510 */ -RASTERIZER_ENTRY( 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 317128 92010096 */ -RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B07F9, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 13728 88595930 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 649448 81449105 */ -RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 444231 60067944 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 36057 58970468 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 53147 48856709 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C2610C9, 0xFFFFFFFF ) /* * 447654 47171792 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 207392 38933691 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 2015632 33364173 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 196361 30395218 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 110898 28973006 */ -RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 135107 16301589 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 22375 15797748 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 141539 7513140 */ -RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 621403 5369705 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 30443 4070277 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 22121 3129894 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9187 1864599 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00044110, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 10390 1694950 */ -//RASTERIZER_ENTRY( 0x0142610A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 25366 1624563 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69033 1607970 */ -//RASTERIZER_ENTRY( 0x0142610A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 36316 1084818 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 1813 816763 */ -//RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6602 767221 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2547 646048 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 2394 501590 */ -//RASTERIZER_ENTRY( 0x0142613A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 14078 440086 */ -//RASTERIZER_ENTRY( 0x0142610A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 9877 429160 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 3222 366052 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 5942 285657 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00044119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 2328 239688 */ -//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1129 208448 */ - -/* wg3dh ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0xFFFFFFFF ) /* * 127676 116109477 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824189F, 0xFFFFFFFF ) /* * 96310 112016758 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 1412831 108682642 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0xFFFFFFFF ) /* * 1612798 45952714 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241AD9, 0xFFFFFFFF ) /* * 5960 6103040 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 56512 4856542 */ -RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 8480 2045940 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x0824181F, 0xFFFFFFFF ) /* * 2779 1994317 */ -RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824105F, 0xFFFFFFFF ) /* * 154691 1922774 */ -RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 18114 776139 */ - -/* gauntleg ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24100F ) /* * 157050 668626339 */ -RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 1079126 580272490 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A4F, 0x0C24100F ) /* * 49686 232178144 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24104F, 0x0C24100F ) /* * 1048560 206304396 */ -RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C2240CF, 0x0C241ACF ) /* * 59176 182444375 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A4F ) /* * 66342 179689728 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 72264 109413344 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 281243 75399210 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24104F ) /* * 126384 68412120 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C24100F ) /* * 26864 43754988 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 30510 32759936 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 44783 31884168 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 34946 31359362 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 8006 28367999 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 15430 27908213 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A0F ) /* * 29306 25166802 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27737 24517949 */ -RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 6783 21292092 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 9591 17815763 */ -RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 343966 13864759 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 11842 12126208 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A8F, 0x0C24100F ) /* * 6648 9788508 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C2418CF ) /* * 8444 8646656 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 9677 8365606 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 844920 8289326 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24184F ) /* * 3108 8010176 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x00000000, 0x0C24180F ) /* * 1435 6209238 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 5754 5617499 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 1608 5557253 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 105127 5133321 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3460 4689138 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 7025 4629550 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 7164 4407683 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24188F ) /* * 1922 3924179 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 4116 3733777 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A8F ) /* * 2626 3732809 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24180F ) /* * 778 3202973 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24184F, 0x0C24100F ) /* * 1525 2997446 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C241A0F ) /* * 645 2975266 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C241A0F ) /* * 5212 2491361 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 825 1996513 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241A0F ) /* * 466 1967163 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580000F, 0x0C24180F ) /* * 77400 1883434 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 472 1698177 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 2476 1678760 */ -//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 4054 1541748 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x0C241A0F, 0x0C24180F ) /* * 3132 1509438 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580080F, 0x0C24180F ) /* * 8582 1324196 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24100F ) /* * 1436 1239704 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24100F ) /* * 253 1220316 */ -//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 2433 1014668 */ - -/* gauntdl ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241ACF ) /* * 30860 1128173568 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2631692 1117011118 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2429239 826969012 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 454056 468285142 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2418CF ) /* * 257586 355634672 */ -RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 10898 134362122 */ -RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241A0F ) /* * 32195 126327049 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 855240 123899880 */ -RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 1718 120629204 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 186839 120281357 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 14102 115428820 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2410CF ) /* * 88530 98271949 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 12994 68053222 */ -RASTERIZER_ENTRY( 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 68273 67454880 */ -RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 100026 62271618 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 153285 44411342 */ -RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 157545 40702131 */ -RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 7800 31948800 */ -RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 47623 20321183 */ -RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24188F ) /* * 21570 19324892 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 3698 15147008 */ -//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 19765 12383722 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 662274 10563855 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27909 10462997 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 78671 10286957 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 52038 9928244 */ -//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C224A0F, 0x0C241ACF ) /* * 27469 9239782 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 757116 8072783 */ -//RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 18018 7035833 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C241A0F ) /* * 50339 5976564 */ -//RASTERIZER_ENTRY( 0x00603430, 0x00040219, 0x00000000, 0x000B0379, 0x00000009, 0x0C2410CE ) /* * 29385 5466384 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 423347 5355017 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 162620 4709092 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 463705 4642480 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 280337 4425529 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 212646 3432265 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 5788 2963456 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 460800 2609198 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 251108 2392362 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 297219 2352862 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0584180F, 0x0C2410CF ) /* * 9913 2097069 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 142722 2091569 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 8820 2053325 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 10346 2033427 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24188F, 0x0C241ACF ) /* * 2136 2017241 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 1505 1928490 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 176734 1842440 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 262577 1799080 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 83179 1534171 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 3863 1527077 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 8021 1472661 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241A0F, 0x0C241ACF ) /* * 85416 1342195 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 261360 1335048 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 74811 1320900 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 239331 1268661 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 107769 1244175 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3706 1216182 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24188F ) /* * 49608 1206129 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C241ACF ) /* * 42440 1204109 */ -//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 29584 1168568 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 17729 1152869 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 4052 1108726 */ -//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 7082 1079348 */ -//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 7761 1023855 */ - -/* gradius4 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -//RASTERIZER_ENTRY( 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */ -//RASTERIZER_ENTRY( 0x01420021, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* intro */ -//RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* in-game */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030BFB, 0x14261AC7, 0xFFFFFFFF ) /* 35 1239092 118514052 */ -RASTERIZER_ENTRY( 0x0000303A, 0x00004119, 0x00000000, 0x00030BFB, 0x142610C7, 0xFFFFFFFF ) /* * 72 400122 93801372 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* * 2 1715230 16465427 */ -RASTERIZER_ENTRY( 0x02422E12, 0x00005119, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* 81 404825 14369443 */ -RASTERIZER_ENTRY( 0x00582435, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* * 69 505796 13187254 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* 33 460278 12366856 */ -RASTERIZER_ENTRY( 0x00000015, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* 60 341915 7357317 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030FFB, 0x08241AC7, 0xFFFFFFFF ) /* 70 444582 7071742 */ -RASTERIZER_ENTRY( 0x00580021, 0x00005119, 0x00000000, 0x00030FFB, 0x14261AC7, 0xFFFFFFFF ) /* 51 242000 6018798 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030B7B, 0x14261A07, 0xFFFFFFFF ) /* 28 26700 4497995 */ -RASTERIZER_ENTRY( 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* 5 3817984 3777348 */ -RASTERIZER_ENTRY( 0x01424A11, 0x00000009, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* 31 1140930 3724657 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030BFB, 0x14261A47, 0xFFFFFFFF ) /* 70 165464 3646194 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030BFB, 0x14261A07, 0xFFFFFFFF ) /* 39 25812 3115146 */ -RASTERIZER_ENTRY( 0x00000035, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* * 6 72291 2961233 */ -RASTERIZER_ENTRY( 0x00000015, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* 29 43584 2752299 */ -RASTERIZER_ENTRY( 0x00000005, 0x00001419, 0x00000000, 0x00030B7B, 0x14261A07, 0xFFFFFFFF ) /* 20 15210 2402045 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030B7B, 0x14261AC7, 0xFFFFFFFF ) /* 24 58447 1844641 */ -RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* 59 177334 1792616 */ -RASTERIZER_ENTRY( 0x01420021, 0x00000119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* 72 27090 1632226 */ - -/* nbapbp ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ -//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */ -//RASTERIZER_ENTRY( 0x00002809, 0x00004110, 0x00000001, 0x00030FFB, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ -//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ -//RASTERIZER_ENTRY( 0x0200421A, 0x00001510, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ -/* gtfore06 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x0C261ACD, 0x0C261ACD ) /* 18 1064626 69362127 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x0C261ACD ) /* 47 3272483 31242799 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x00000ACD, 0x0C261ACD ) /* 9 221917 12348555 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* 26 57291 9357989 */ -RASTERIZER_ENTRY( 0x00002429, 0x00000000, 0x000000C1, 0x00010FF9, 0x00000A09, 0x0C261A0F ) /* 12 97156 8530607 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x000000C4, 0x0C261ACD ) /* 55 110144 5265532 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* 61 16644 1079382 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* 5 8332 1065229 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x0C261A0D ) /* 45 8148 505013 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00010F79, 0x0C224A0D, 0x0C261A0D ) /* 84 45233 248267 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x0C261ACD, 0x0C2610C4 ) /* 90 10235 193036 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x0C261ACD, 0x0C261ACD ) /* * 29 3777 83777 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x0C261ACD, 0x042210C0 ) /* 2 24952 66761 */ -RASTERIZER_ENTRY( 0x00002429, 0x00000000, 0x00000000, 0x00010FF9, 0x00000A09, 0x0C261A0F ) /* 24 661 50222 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x0C261ACD, 0x04221AC9 ) /* 92 12504 43720 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x0C261ACD, 0x0C2610C4 ) /* 79 2160 43650 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x000000C4, 0x04221AC9 ) /* 19 2796 30377 */ -RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* 67 1962 14755 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* * 66 74 3951 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x00000ACD, 0x04221AC9 ) /* 70 374 3691 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* * 20 350 7928 */ - -/* virtpool ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0x042210C0 ) /* * 78 2182388 74854175 */ -RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0x042210C0 ) /* * 46 114830 6776826 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0x042210C0 ) /* * 58 1273673 4513463 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A09, 0x042210C0 ) /* * 46 634995 2275612 */ -RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0x042210C0 ) /* * 46 26651 1883507 */ -RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B073B, 0x0C261A0F, 0x042210C0 ) /* * 26 220644 751241 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00445110, 0x00000000, 0x000B073B, 0x0C261A09, 0x042210C0 ) /* * 79 14846 3499120 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A09, 0x042210C0 ) /* * 66 26665 1583363 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C26100F, 0x042210C0 ) /* * 78 33096 957935 */ -//RASTERIZER_ENTRY( 0x00002425, 0x00445110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0x042210C0 ) /* * 38 12494 678029 */ -//RASTERIZER_ENTRY( 0x00800000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000 ) /* * 28 25348 316181 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0x042210C0 ) /* * 13 11344 267903 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A09, 0x042210C0 ) /* * 34 1548 112168 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07FB, 0x0C26100F, 0x042210C0 ) /* * 35 664 25222 */ -//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 33 512 18393 */ -//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07FB, 0x0C261A0F, 0x042210C0 ) /* * 14 216 16842 */ -//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000300, 0x00000800, 0x00000800 ) /* * 87 2 72 */ -//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000200, 0x08241A00, 0x08241A00 ) /* * 92 2 8 */ -//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x08241A00 ) /* * 93 2 8 */ - -/* roadburn ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F) /* * 88 6599666 64554420 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C2418CF) /* * 12 763617 35323533 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C2418CF) /* * 44 1930013 33746169 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0C2418CF) /* * 21 1439267 29935941 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0x0C24100F) /* * 32 6915356 28830506 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0C24180F) /* * 39 4057572 17696631 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0C24100F) /* * 50 4955570 14335742 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0C2418CF) /* * 41 766085 9520801 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C2418CF) /* * 0 534929 7695839 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C24100F) /* * 9 1078501 7419628 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24180F) /* * 77 413387 7228312 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C24180F) /* * 95 353176 7192165 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0x0C2418CF) /* * 52 315430 5154802 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0x0C24100F) /* * 54 1704858 5008909 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F) /* * 13 899639 4953916 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C24188F) /* * 64 277509 4254016 */ -//RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0000088F, 0x0C2418CF) /* * 87 295785 4066338 */ -//RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C241ACF) /* * 7 28140 4056321 */ -//RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C2618CF) /* * 9 9494 3608108 */ -//RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C2418CF, 0x0C2418CF) /* * 77 647531 3223654 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C2410CF, 0x0C24100F) /* * 84 142873 3131813 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F) /* * 2 247541 2880853 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24188F) /* * 11 143650 2430648 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0x0C24180F) /* * 43 686600 2266187 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000088F, 0x0C24180F) /* * 8 526279 1750008 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24188F, 0x0C24100F) /* * 75 158668 1533323 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C2418CF) /* * 66 105179 1324448 */ -//RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C24188F) /* * 76 19479 1150035 */ - -/* cartfury --> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x000000C1, 0x00030F39, 0x0C261A0F, 0x042210C0) /* 55 6897497 95045895 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x000000C1, 0x00030F39, 0x0C26100F, 0x042210C0) /* 92 9680462 62502113 */ -RASTERIZER_ENTRY(0x0142A409, 0x00000000, 0x000000C1, 0x00030F3B, 0x0C261ACF, 0x042210C0) /* 51 3884086 40581793 */ -RASTERIZER_ENTRY(0x00000035, 0x00045119, 0x00000000, 0x00030F39, 0x0C261A0F, 0x042210C0) /* * 94 2263184 30556572 */ -RASTERIZER_ENTRY(0x00422439, 0x00000000, 0x000000C1, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* 93 2520077 30036037 */ -RASTERIZER_ENTRY(0x00582435, 0x00045110, 0x00000000, 0x00030BF9, 0x0C2610C9, 0x042210C0) /* 36 2053030 28006572 */ -RASTERIZER_ENTRY(0x0142A409, 0x00000000, 0x00000000, 0x00030B39, 0x0C261A0F, 0x042210C0) /* 92 4894430 27815796 */ -RASTERIZER_ENTRY(0x00580035, 0x00045119, 0x000000C1, 0x00030B39, 0x0C261A0F, 0x042210C0) /* 69 1813831 25845118 */ -RASTERIZER_ENTRY(0x0142A409, 0x00000000, 0x00000000, 0x00030F3B, 0x0C261ACF, 0x042210C0) /* 47 1906963 20937897 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x00000000, 0x00030FF9, 0x0C261A0F, 0x042210C0) /* 40 152832 19687732 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x00000000, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* 40 2896061 19553336 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x000000C1, 0x00030F39, 0x0C261A0F, 0x042210C0) /* 60 1626437 16446065 */ -RASTERIZER_ENTRY(0x00000035, 0x00045110, 0x000000C1, 0x00030BF9, 0x0C261A0F, 0x042210C0) /* 82 156240 16358632 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x00000000, 0x00030F3B, 0x0C261ACF, 0x042210C0) /* 36 3538654 15204923 */ -RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x00000000, 0x00030F39, 0x0C26100F, 0x042210C0) /* * 7 1899232 14314750 */ -RASTERIZER_ENTRY(0x0142A409, 0x00000000, 0x000000C1, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* 82 1097851 13461074 */ -//RASTERIZER_ENTRY(0x00422439, 0x00000000, 0x00000000, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* 8 1024956 13120753 */ -//RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x00000000, 0x00030F39, 0x0C261A0F, 0x042210C0) /* 72 1641456 11253842 */ -//RASTERIZER_ENTRY(0x0142A409, 0x00000000, 0x00000000, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* 51 742740 10329945 */ -//RASTERIZER_ENTRY(0x00420039, 0x00000000, 0x000000C1, 0x00030F3B, 0x0C261A0F, 0x042210C0) /* * 28 1167364 8450582 */ -//RASTERIZER_ENTRY(0x0042613A, 0x00000000, 0x000000C1, 0x00030FF9, 0xFFFFFFFF, 0xFFFFFFFF) /* 6 29298 7216480 */ - -/* warfa ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY(0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF) /* 5 6988136 185178764 */ -RASTERIZER_ENTRY(0x00602419, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241A0F) /* 92 2423839 61801379 */ -RASTERIZER_ENTRY(0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x00000000) /* 74 5178601 36194132 */ -RASTERIZER_ENTRY(0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0C24180F) /* 57 1267243 26421492 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x104008CF, 0x0C2618CF) /* 13 1461060 22971624 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x10400ACF, 0x0C2618CF) /* 63 1089946 21852830 */ -RASTERIZER_ENTRY(0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF) /* 27 252592 20660816 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x104000CF, 0x0C2618CF) /* 84 796384 20070179 */ -RASTERIZER_ENTRY(0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0C24100F) /* 68 4256201 19630570 */ -RASTERIZER_ENTRY(0x00602439, 0x00044119, 0x000000C1, 0x000B0779, 0x0582480F, 0x0C26180F) /* * 69 137540 18243142 */ -RASTERIZER_ENTRY(0x00602C09, 0x00045119, 0x000000C1, 0x000B0779, 0x0482400F, 0x0C261ACF) /* * 16 377796 16889915 */ - -/* sf2049se --> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C26100F, 0x0000000F) /* * 44 6143319 107636749 */ -RASTERIZER_ENTRY(0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0C26180F, 0x0000080F) /* * 89 5079264 72208948 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C26100F, 0x0000080F) /* * 33 2115327 46427046 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0x0C26100F) /* * 46 1574119 21123488 */ -RASTERIZER_ENTRY(0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0C2610CF, 0x0000080F) /* * 45 1681920 19266314 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0A452A0F, 0x0E47200F) /* * 85 2624894 12845924 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C26180F, 0x0000000F) /* * 22 312805 8560298 */ -RASTERIZER_ENTRY(0x00482435, 0x00045117, 0x000000C1, 0x000B0339, 0x0C26100F, 0x0000000F) /* * 69 567798 7255338 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2618CF, 0x0000000F) /* * 88 201277 7213832 */ -RASTERIZER_ENTRY(0x00602401, 0x00045119, 0x000000C1, 0x00030279, 0x0C2618CF, 0x0000080F) /* * 25 1137620 7146799 */ -RASTERIZER_ENTRY(0x00482435, 0x00045119, 0x000000C1, 0x000B0339, 0x0C26100F, 0x0000000F) /* * 52 567798 7137832 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C261A0F, 0x0000080F) /* * 54 141585 6669637 */ -RASTERIZER_ENTRY(0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0C2618CF, 0x0000080F) /* * 23 357022 6573647 */ -RASTERIZER_ENTRY(0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0C26100F, 0x0000080F) /* * 14 462528 5358791 */ -RASTERIZER_ENTRY(0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0C26188F, 0x0000000F) /* * 57 98945 5300544 */ -RASTERIZER_ENTRY(0x00482405, 0x00045119, 0x00000000, 0x000B0379, 0x0C26180F, 0x0000080F) /* * 77 232584 4197249 */ diff --git a/src/devices/video/voodoo_regs.h b/src/devices/video/voodoo_regs.h new file mode 100644 index 00000000000..4a534bb17cb --- /dev/null +++ b/src/devices/video/voodoo_regs.h @@ -0,0 +1,1436 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_regs.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#ifndef MAME_VIDEO_VOODOO_REGS_H +#define MAME_VIDEO_VOODOO_REGS_H + +#pragma once + + +namespace voodoo +{ + +//************************************************************************** +// SPECIFIC REGISTER TYPES +//************************************************************************** + +// ======================> reg_color + +class reg_color +{ +public: + constexpr reg_color(u32 value) : + m_value(value) { } + + constexpr u32 blue() const { return BIT(m_value, 0, 8); } + constexpr u32 green() const { return BIT(m_value, 8, 8); } + constexpr u32 red() const { return BIT(m_value, 16, 8); } + constexpr u32 alpha() const { return BIT(m_value, 24, 8); } + constexpr rgb_t argb() const { return m_value; } + +private: + u32 m_value; +}; + + +// ======================> reg_clip_minmax + +class reg_clip_minmax +{ +public: + constexpr reg_clip_minmax(u32 value) : + m_value(value) { } + + constexpr u32 min() const { return BIT(m_value, 16, 10); } + constexpr u32 max() const { return BIT(m_value, 0, 10); } + +private: + u32 m_value; +}; + + +// ======================> reg_fbz_colorpath + +class reg_fbz_colorpath +{ +public: + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + constexpr reg_fbz_colorpath(u32 value) : + m_value(value) { } + + constexpr reg_fbz_colorpath(u32 normalized, reg_fbz_colorpath const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 cc_rgbselect() const { return BIT(m_value, 0, 2); } + constexpr u32 cc_aselect() const { return BIT(m_value, 2, 2); } + constexpr u32 cc_localselect() const { return BIT(m_value, 4, 1); } + constexpr u32 cca_localselect() const { return BIT(m_value, 5, 2); } + constexpr u32 cc_localselect_override() const { return BIT(m_value, 7, 1); } + constexpr u32 cc_zero_other() const { return BIT(m_value, 8, 1); } + constexpr u32 cc_sub_clocal() const { return BIT(m_value, 9, 1); } + constexpr u32 cc_mselect() const { return BIT(m_value, 10, 3); } + constexpr u32 cc_reverse_blend() const { return BIT(m_value, 13, 1); } + constexpr u32 cc_add_aclocal() const { return BIT(m_value, 14, 2); } + constexpr u32 cc_invert_output() const { return BIT(m_value, 16, 1); } + constexpr u32 cca_zero_other() const { return BIT(m_value, 17, 1); } + constexpr u32 cca_sub_clocal() const { return BIT(m_value, 18, 1); } + constexpr u32 cca_mselect() const { return BIT(m_value, 19, 3); } + constexpr u32 cca_reverse_blend() const { return BIT(m_value, 22, 1); } + constexpr u32 cca_add_aclocal() const { return BIT(m_value, 23, 2); } + constexpr u32 cca_invert_output() const { return BIT(m_value, 25, 1); } + constexpr u32 cca_subpixel_adjust() const { return BIT(m_value, 26, 1); } + constexpr u32 texture_enable() const { return BIT(m_value, 27, 1); } + constexpr u32 rgbzw_clamp() const { return BIT(m_value, 28, 1); } + constexpr u32 antialias() const { return BIT(m_value, 29, 1); } // not implemented + + constexpr u32 normalize() + { + // ignore the subpixel adjust and texture enable flags + return m_value & ~((1 << 26) | (1 << 27)); + } + +private: + u32 m_value; +}; + + +// ======================> reg_fbz_mode + +class reg_fbz_mode +{ +public: + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + constexpr reg_fbz_mode(u32 value) : + m_value(value) { } + + constexpr reg_fbz_mode(u32 normalized, reg_fbz_mode const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 enable_clipping() const { return BIT(m_value, 0, 1); } + constexpr u32 enable_chromakey() const { return BIT(m_value, 1, 1); } + constexpr u32 enable_stipple() const { return BIT(m_value, 2, 1); } + constexpr u32 wbuffer_select() const { return BIT(m_value, 3, 1); } + constexpr u32 enable_depthbuf() const { return BIT(m_value, 4, 1); } + constexpr u32 depth_function() const { return BIT(m_value, 5, 3); } + constexpr u32 enable_dithering() const { return BIT(m_value, 8, 1); } + constexpr u32 rgb_buffer_mask() const { return BIT(m_value, 9, 1); } + constexpr u32 aux_buffer_mask() const { return BIT(m_value, 10, 1); } + constexpr u32 dither_type() const { return BIT(m_value, 11, 1); } + constexpr u32 stipple_pattern() const { return BIT(m_value, 12, 1); } + constexpr u32 enable_alpha_mask() const { return BIT(m_value, 13, 1); } + constexpr u32 draw_buffer() const { return BIT(m_value, 14, 2); } + constexpr u32 enable_depth_bias() const { return BIT(m_value, 16, 1); } + constexpr u32 y_origin() const { return BIT(m_value, 17, 1); } + constexpr u32 enable_alpha_planes() const { return BIT(m_value, 18, 1); } + constexpr u32 alpha_dither_subtract() const { return BIT(m_value, 19, 1); } + constexpr u32 depth_source_compare() const { return BIT(m_value, 20, 1); } + constexpr u32 depth_float_select() const { return BIT(m_value, 21, 1); } // voodoo 2 only + + constexpr u32 normalize() + { + // ignore the draw buffer + return m_value & ~(3 << 14); + } + +private: + u32 m_value; +}; + + +// ======================> reg_alpha_mode + +class reg_alpha_mode +{ +public: + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + constexpr reg_alpha_mode(u32 value) : + m_value(value) { } + + constexpr reg_alpha_mode(u32 normalized, reg_alpha_mode const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 alphatest() const { return BIT(m_value, 0, 1); } + constexpr u32 alphafunction() const { return BIT(m_value, 1, 3); } + constexpr u32 alphablend() const { return BIT(m_value, 4, 1); } + constexpr u32 antialias() const { return BIT(m_value, 5, 1); } // not implemented + constexpr u32 srcrgbblend() const { return BIT(m_value, 8, 4); } + constexpr u32 dstrgbblend() const { return BIT(m_value, 12, 4); } + constexpr u32 srcalphablend() const { return BIT(m_value, 16, 4); } + constexpr u32 dstalphablend() const { return BIT(m_value, 20, 4); } + constexpr u32 alpharef() const { return BIT(m_value, 24, 8); } + + constexpr u32 normalize() + { + // always ignore the alpha ref; it is stashed in the poly data + u32 result = m_value & ~(0xff << 24); + + // if not doing alpha testing, ignore the alpha function + if (!alphatest()) + result &= ~(7 << 1); + + // if not doing alpha blending, ignore the source and dest blending factors + if (!alphablend()) + result &= ~((15 << 8) | (15 << 12) | (15 << 16) | (15 << 20)); + + return result; + } + +private: + u32 m_value; +}; + + +// ======================> reg_fog_mode + +class reg_fog_mode +{ +public: + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + constexpr reg_fog_mode(u32 value) : + m_value(value) { } + + constexpr reg_fog_mode(u32 normalized, reg_fog_mode const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 enable_fog() const { return BIT(m_value, 0, 1); } + constexpr u32 fog_add() const { return BIT(m_value, 1, 1); } + constexpr u32 fog_mult() const { return BIT(m_value, 2, 1); } + constexpr u32 fog_zalpha() const { return BIT(m_value, 3, 2); } + constexpr u32 fog_constant() const { return BIT(m_value, 5, 1); } + constexpr u32 fog_dither() const { return BIT(m_value, 6, 1); } // voodoo 2 only + constexpr u32 fog_zones() const { return BIT(m_value, 7, 1); } // voodoo 2 only + + constexpr u32 normalize() + { + // only care about the rest if fog is enabled + return enable_fog() ? m_value : 0; + } + +private: + u32 m_value; +}; + + +// ======================> reg_texture_mode + +class reg_texture_mode +{ +public: + static constexpr u32 NONE = 0xffffffff; + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + // these bits are set for special cases in the rasterizer + // (normally they are masked out) + static constexpr u32 TMU_CONFIG_MASK = 0x80000000; + + // mask of equation bits + static constexpr u32 EQUATION_MASK = 0x3ffff000; + + constexpr reg_texture_mode(u32 value) : + m_value(value) { } + + constexpr reg_texture_mode(u32 normalized, reg_texture_mode const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr bool is_none() const { return (m_value == NONE); } + constexpr bool is_live() const { return (m_value == DECODE_LIVE); } + + constexpr u32 raw() const { return m_value; } + constexpr u32 enable_perspective() const { return BIT(m_value, 0, 1); } + constexpr u32 minification_filter() const { return BIT(m_value, 1, 1); } + constexpr u32 magnification_filter() const { return BIT(m_value, 2, 1); } + constexpr u32 clamp_neg_w() const { return BIT(m_value, 3, 1); } + constexpr u32 enable_lod_dither() const { return BIT(m_value, 4, 1); } + constexpr u32 ncc_table_select() const { return BIT(m_value, 5, 1); } + constexpr u32 clamp_s() const { return BIT(m_value, 6, 1); } + constexpr u32 clamp_t() const { return BIT(m_value, 7, 1); } + constexpr u32 format() const { return BIT(m_value, 8, 4); } + constexpr u32 tc_zero_other() const { return BIT(m_value, 12, 1); } + constexpr u32 tc_sub_clocal() const { return BIT(m_value, 13, 1); } + constexpr u32 tc_mselect() const { return BIT(m_value, 14, 3); } + constexpr u32 tc_reverse_blend() const { return BIT(m_value, 17, 1); } + constexpr u32 tc_add_aclocal() const { return BIT(m_value, 18, 2); } + constexpr u32 tc_invert_output() const { return BIT(m_value, 20, 1); } + constexpr u32 tca_zero_other() const { return BIT(m_value, 21, 1); } + constexpr u32 tca_sub_clocal() const { return BIT(m_value, 22, 1); } + constexpr u32 tca_mselect() const { return BIT(m_value, 23, 3); } + constexpr u32 tca_reverse_blend() const { return BIT(m_value, 26, 1); } + constexpr u32 tca_add_aclocal() const { return BIT(m_value, 27, 2); } + constexpr u32 tca_invert_output() const { return BIT(m_value, 29, 1); } + constexpr u32 trilinear() const { return BIT(m_value, 30, 1); } // not implemented + constexpr u32 seq_8_downld() const { return BIT(m_value, 31, 1); } // repurposed as send_config + + constexpr u32 normalize() + { + // ignore the NCC table and seq_8_downld flags + u32 result = m_value & ~((1 << 5) | (1 << 31)); + + // classify texture formats into 3 format categories + if (format() < 8) + result = (result & ~(0xf << 8)) | (0 << 8); + else if (format() >= 10 && format() <= 12) + result = (result & ~(0xf << 8)) | (10 << 8); + else + result = (result & ~(0xf << 8)) | (8 << 8); + + return result; + } + +private: + u32 m_value; +}; + + +// ======================> reg_texture_lod + +class reg_texture_lod +{ +public: + static constexpr u32 DECODE_LIVE = 0xfffffffe; + + constexpr reg_texture_lod(u32 value) : + m_value(value) { } + + constexpr reg_texture_lod(u32 normalized, reg_texture_lod const live) : + m_value((normalized == DECODE_LIVE) ? live.m_value : normalized) { } + + constexpr u32 lod_min() const { return BIT(m_value, 0, 6); } + constexpr u32 lod_max() const { return BIT(m_value, 6, 6); } + constexpr u32 lod_bias() const { return BIT(m_value, 12, 6); } + constexpr u32 lod_odd() const { return BIT(m_value, 18, 1); } + constexpr u32 lod_tsplit() const { return BIT(m_value, 19, 1); } + constexpr u32 lod_s_is_wider() const { return BIT(m_value, 20, 1); } + constexpr u32 lod_aspect() const { return BIT(m_value, 21, 2); } + constexpr u32 lod_zerofrac() const { return BIT(m_value, 23, 1); } + constexpr u32 tmultibaseaddr() const { return BIT(m_value, 24, 1); } + constexpr u32 tdata_swizzle() const { return BIT(m_value, 25, 1); } + constexpr u32 tdata_swap() const { return BIT(m_value, 26, 1); } + constexpr u32 tdirect_write() const { return BIT(m_value, 27, 1); } // Voodoo 2 only + constexpr u32 magic() const { return BIT(m_value, 28, 4); } + constexpr u32 tmirrors() const { return BIT(m_value, 28, 1); } // Voodoo Banshee+ only + constexpr u32 tmirrort() const { return BIT(m_value, 29, 1); } // Voodoo Banshee+ only + + constexpr u32 normalize() + { + // always normalize to 0 for now + return 0; + } + +private: + u32 m_value; +}; + + +// ======================> reg_texture_detail + +class reg_texture_detail +{ +public: + constexpr reg_texture_detail(u32 value) : + m_value(value) { } + + constexpr u32 detail_max() const { return BIT(m_value, 0, 8); } + constexpr u32 detail_bias() const { return BIT(m_value, 8, 6); } + constexpr u32 detail_scale() const { return BIT(m_value, 14, 3); } + constexpr u32 rgb_min_filter() const { return BIT(m_value, 17, 1); } + constexpr u32 rgb_mag_filter() const { return BIT(m_value, 18, 1); } + constexpr u32 alpha_min_filter() const { return BIT(m_value, 19, 1); } + constexpr u32 alpha_mag_filter() const { return BIT(m_value, 20, 1); } + constexpr u32 separate_rgba_filter() const { return BIT(m_value, 21, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_lfb_mode + +class reg_lfb_mode +{ +public: + constexpr reg_lfb_mode(u32 value) : + m_value(value) { } + + constexpr u32 write_format() const { return BIT(m_value, 0, 4); } + constexpr u32 write_buffer_select() const { return BIT(m_value, 4, 2); } + constexpr u32 read_buffer_select() const { return BIT(m_value, 6, 2); } + constexpr u32 enable_pixel_pipeline() const { return BIT(m_value, 8, 1); } + constexpr u32 rgba_lanes() const { return BIT(m_value, 9, 2); } + constexpr u32 word_swap_writes() const { return BIT(m_value, 11, 1); } + constexpr u32 byte_swizzle_writes() const { return BIT(m_value, 12, 1); } + constexpr u32 y_origin() const { return BIT(m_value, 13, 1); } + constexpr u32 write_w_select() const { return BIT(m_value, 14, 1); } + constexpr u32 word_swap_reads() const { return BIT(m_value, 15, 1); } + constexpr u32 byte_swizzle_reads() const { return BIT(m_value, 16, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_chroma_range + +class reg_chroma_range +{ +public: + constexpr reg_chroma_range(u32 value) : + m_value(value) { } + + constexpr u32 blue() const { return BIT(m_value, 0, 8); } + constexpr u32 green() const { return BIT(m_value, 8, 8); } + constexpr u32 red() const { return BIT(m_value, 16, 8); } + constexpr u32 blue_exclusive() const { return BIT(m_value, 24, 1); } + constexpr u32 green_exclusive() const { return BIT(m_value, 25, 1); } + constexpr u32 red_exclusive() const { return BIT(m_value, 26, 1); } + constexpr u32 union_mode() const { return BIT(m_value, 27, 1); } + constexpr u32 enable() const { return BIT(m_value, 28, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_setup_mode + +class reg_setup_mode +{ +public: + constexpr reg_setup_mode(u32 value) : + m_value(value) { } + + constexpr u32 setup_rgb() const { return BIT(m_value, 0, 1); } + constexpr u32 setup_alpha() const { return BIT(m_value, 1, 1); } + constexpr u32 setup_z() const { return BIT(m_value, 2, 1); } + constexpr u32 setup_wb() const { return BIT(m_value, 3, 1); } + constexpr u32 setup_w0() const { return BIT(m_value, 4, 1); } + constexpr u32 setup_st0() const { return BIT(m_value, 5, 1); } + constexpr u32 setup_w1() const { return BIT(m_value, 6, 1); } + constexpr u32 setup_st1() const { return BIT(m_value, 7, 1); } + constexpr u32 fan_mode() const { return BIT(m_value, 16, 1); } + constexpr u32 enable_culling() const { return BIT(m_value, 17, 1); } + constexpr u32 culling_sign() const { return BIT(m_value, 18, 1); } + constexpr u32 disable_ping_pong_correction() const { return BIT(m_value, 19, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_init_en + +class reg_init_en +{ +public: + constexpr reg_init_en(u32 value) : + m_value(value) { } + + constexpr u32 enable_hw_init() const { return BIT(m_value, 0, 1); } + constexpr u32 enable_pci_fifo() const { return BIT(m_value, 1, 1); } + constexpr u32 remap_init_to_dac() const { return BIT(m_value, 2, 1); } + constexpr u32 enable_snoop0() const { return BIT(m_value, 4, 1); } + constexpr u32 snoop0_memory_match() const { return BIT(m_value, 5, 1); } + constexpr u32 snoop0_readwrite_match() const { return BIT(m_value, 6, 1); } + constexpr u32 enable_snoop1() const { return BIT(m_value, 7, 1); } + constexpr u32 snoop1_memory_match() const { return BIT(m_value, 8, 1); } + constexpr u32 snoop1_readwrite_match() const { return BIT(m_value, 9, 1); } + constexpr u32 sli_bus_owner() const { return BIT(m_value, 10, 1); } + constexpr u32 sli_odd_even() const { return BIT(m_value, 11, 1); } + constexpr u32 secondary_rev_id() const { return BIT(m_value, 12, 4); } // voodoo 2 only + constexpr u32 mfctr_fab_id() const { return BIT(m_value, 16, 4); } // voodoo 2 only + constexpr u32 enable_pci_interrupt() const { return BIT(m_value, 20, 1); } // voodoo 2 only + constexpr u32 pci_interrupt_timeout() const { return BIT(m_value, 21, 1); } // voodoo 2 only + constexpr u32 enable_nand_tree_test() const { return BIT(m_value, 22, 1); } // voodoo 2 only + constexpr u32 enable_sli_address_snoop() const { return BIT(m_value, 23, 1); } // voodoo 2 only + constexpr u32 sli_snoop_address() const { return BIT(m_value, 24, 8); } // voodoo 2 only + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init0 + +class reg_fbi_init0 +{ +public: + constexpr reg_fbi_init0(u32 value) : + m_value(value) { } + + constexpr u32 vga_passthru() const { return BIT(m_value, 0, 1); } + constexpr u32 graphics_reset() const { return BIT(m_value, 1, 1); } + constexpr u32 fifo_reset() const { return BIT(m_value, 2, 1); } + constexpr u32 swizzle_reg_writes() const { return BIT(m_value, 3, 1); } + constexpr u32 stall_pcie_for_hwm() const { return BIT(m_value, 4, 1); } + constexpr u32 pci_fifo_lwm() const { return BIT(m_value, 6, 5); } + constexpr u32 lfb_to_memory_fifo() const { return BIT(m_value, 11, 1); } + constexpr u32 texmem_to_memory_fifo() const { return BIT(m_value, 12, 1); } + constexpr u32 enable_memory_fifo() const { return BIT(m_value, 13, 1); } + constexpr u32 memory_fifo_hwm() const { return BIT(m_value, 14, 11); } + constexpr u32 memory_fifo_burst() const { return BIT(m_value, 25, 6); } + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init1 + +class reg_fbi_init1 +{ +public: + constexpr reg_fbi_init1(u32 value) : + m_value(value) { } + + constexpr u32 pci_dev_function() const { return BIT(m_value, 0, 1); } + constexpr u32 pci_write_wait_states() const { return BIT(m_value, 1, 1); } + constexpr u32 multi_sst1() const { return BIT(m_value, 2, 1); } // not on voodoo 2 + constexpr u32 enable_lfb() const { return BIT(m_value, 3, 1); } + constexpr u32 x_video_tiles() const { return BIT(m_value, 4, 4); } + constexpr u32 video_timing_reset() const { return BIT(m_value, 8, 1); } + constexpr u32 software_override() const { return BIT(m_value, 9, 1); } + constexpr u32 software_hsync() const { return BIT(m_value, 10, 1); } + constexpr u32 software_vsync() const { return BIT(m_value, 11, 1); } + constexpr u32 software_blank() const { return BIT(m_value, 12, 1); } + constexpr u32 drive_video_timing() const { return BIT(m_value, 13, 1); } + constexpr u32 drive_video_blank() const { return BIT(m_value, 14, 1); } + constexpr u32 drive_video_sync() const { return BIT(m_value, 15, 1); } + constexpr u32 drive_video_dclk() const { return BIT(m_value, 16, 1); } + constexpr u32 video_timing_vclk() const { return BIT(m_value, 17, 1); } + constexpr u32 video_clk_2x_delay() const { return BIT(m_value, 18, 2); } + constexpr u32 video_timing_source() const { return BIT(m_value, 20, 2); } + constexpr u32 enable_24bpp_output() const { return BIT(m_value, 22, 1); } + constexpr u32 enable_sli() const { return BIT(m_value, 23, 1); } + constexpr u32 x_video_tiles_bit5() const { return BIT(m_value, 24, 1); } // voodoo 2 only + constexpr u32 enable_edge_filter() const { return BIT(m_value, 25, 1); } + constexpr u32 invert_vid_clk_2x() const { return BIT(m_value, 26, 1); } + constexpr u32 vid_clk_2x_sel_delay() const { return BIT(m_value, 27, 2); } + constexpr u32 vid_clk_delay() const { return BIT(m_value, 29, 2); } + constexpr u32 disable_fast_readahead() const { return BIT(m_value, 31, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init2 + +class reg_fbi_init2 +{ +public: + constexpr reg_fbi_init2(u32 value) : + m_value(value) { } + + constexpr u32 disable_dither_sub() const { return BIT(m_value, 0, 1); } + constexpr u32 dram_banking() const { return BIT(m_value, 1, 1); } + constexpr u32 enable_triple_buf() const { return BIT(m_value, 4, 1); } + constexpr u32 enable_fast_ras_read() const { return BIT(m_value, 5, 1); } + constexpr u32 enable_get_dram_oe() const { return BIT(m_value, 6, 1); } + constexpr u32 enable_fast_readwrite() const { return BIT(m_value, 7, 1); } + constexpr u32 enable_passthru_dither() const { return BIT(m_value, 8, 1); } + constexpr u32 swap_buffer_algorithm() const { return BIT(m_value, 9, 2); } + constexpr u32 video_buffer_offset() const { return BIT(m_value, 11, 9); } + constexpr u32 enable_dram_banking() const { return BIT(m_value, 20, 1); } + constexpr u32 enable_dram_read_fifo() const { return BIT(m_value, 21, 1); } + constexpr u32 enable_dram_refresh() const { return BIT(m_value, 22, 1); } + constexpr u32 refresh_load_value() const { return BIT(m_value, 23, 9); } + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init3 + +class reg_fbi_init3 +{ +public: + constexpr reg_fbi_init3(u32 value) : + m_value(value) { } + + constexpr u32 tri_register_remap() const { return BIT(m_value, 0, 1); } + constexpr u32 video_fifo_thresh() const { return BIT(m_value, 1, 5); } + constexpr u32 disable_tmus() const { return BIT(m_value, 6, 1); } + constexpr u32 fbi_memory_type() const { return BIT(m_value, 8, 3); } + constexpr u32 vga_pass_reset_val() const { return BIT(m_value, 11, 1); } + constexpr u32 hardcode_pci_base() const { return BIT(m_value, 12, 1); } + constexpr u32 fbi2trex_delay() const { return BIT(m_value, 13, 4); } + constexpr u32 trex2fbi_delay() const { return BIT(m_value, 17, 5); } + constexpr u32 yorigin_subtract() const { return BIT(m_value, 22, 10); } + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init4 + +class reg_fbi_init4 +{ +public: + constexpr reg_fbi_init4(u32 value) : + m_value(value) { } + + constexpr u32 pci_read_waits() const { return BIT(m_value, 0, 1); } + constexpr u32 enable_lfb_readahead() const { return BIT(m_value, 1, 1); } + constexpr u32 memory_fifo_lwm() const { return BIT(m_value, 2, 6); } + constexpr u32 memory_fifo_start_row() const { return BIT(m_value, 8, 10); } + constexpr u32 memory_fifo_stop_row() const { return BIT(m_value, 18, 10); } + constexpr u32 video_clocking_delay() const { return BIT(m_value, 29, 7); } // voodoo 2 only + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init5 + +class reg_fbi_init5 +{ +public: + constexpr reg_fbi_init5(u32 value) : + m_value(value) { } + + constexpr u32 disable_pci_stop() const { return BIT(m_value, 0, 1); } // voodoo 2 only + constexpr u32 pci_slave_speed() const { return BIT(m_value, 1, 1); } // voodoo 2 only + constexpr u32 dac_data_output_width() const { return BIT(m_value, 2, 1); } // voodoo 2 only + constexpr u32 dac_data_17_output() const { return BIT(m_value, 3, 1); } // voodoo 2 only + constexpr u32 dac_data_18_output() const { return BIT(m_value, 4, 1); } // voodoo 2 only + constexpr u32 generic_strapping() const { return BIT(m_value, 5, 4); } // voodoo 2 only + constexpr u32 buffer_allocation() const { return BIT(m_value, 9, 2); } // voodoo 2 only + constexpr u32 drive_vid_clk_slave() const { return BIT(m_value, 11, 1); } // voodoo 2 only + constexpr u32 drive_dac_data_16() const { return BIT(m_value, 12, 1); } // voodoo 2 only + constexpr u32 vclk_input_select() const { return BIT(m_value, 13, 1); } // voodoo 2 only + constexpr u32 multi_cvg_detect() const { return BIT(m_value, 14, 1); } // voodoo 2 only + constexpr u32 sync_retrace_reads() const { return BIT(m_value, 15, 1); } // voodoo 2 only + constexpr u32 enable_rhborder_color() const { return BIT(m_value, 16, 1); } // voodoo 2 only + constexpr u32 enable_lhborder_color() const { return BIT(m_value, 17, 1); } // voodoo 2 only + constexpr u32 enable_bvborder_color() const { return BIT(m_value, 18, 1); } // voodoo 2 only + constexpr u32 enable_tvborder_color() const { return BIT(m_value, 19, 1); } // voodoo 2 only + constexpr u32 double_horiz() const { return BIT(m_value, 20, 1); } // voodoo 2 only + constexpr u32 double_vert() const { return BIT(m_value, 21, 1); } // voodoo 2 only + constexpr u32 enable_16bit_gamma() const { return BIT(m_value, 22, 1); } // voodoo 2 only + constexpr u32 invert_dac_hsync() const { return BIT(m_value, 23, 1); } // voodoo 2 only + constexpr u32 invert_dac_vsync() const { return BIT(m_value, 24, 1); } // voodoo 2 only + constexpr u32 enable_24bit_dacdata() const { return BIT(m_value, 25, 1); } // voodoo 2 only + constexpr u32 enable_interlacing() const { return BIT(m_value, 26, 1); } // voodoo 2 only + constexpr u32 dac_data_18_control() const { return BIT(m_value, 27, 1); } // voodoo 2 only + constexpr u32 rasterizer_unit_mode() const { return BIT(m_value, 30, 2); } // voodoo 2 only + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init6 + +class reg_fbi_init6 +{ +public: + constexpr reg_fbi_init6(u32 value) : + m_value(value) { } + + constexpr u32 window_active_counter() const { return BIT(m_value, 0, 3); } // voodoo 2 only + constexpr u32 window_drag_counter() const { return BIT(m_value, 3, 5); } // voodoo 2 only + constexpr u32 sli_sync_master() const { return BIT(m_value, 8, 1); } // voodoo 2 only + constexpr u32 dac_data_22_output() const { return BIT(m_value, 9, 2); } // voodoo 2 only + constexpr u32 dac_data_23_output() const { return BIT(m_value, 11, 2); } // voodoo 2 only + constexpr u32 sli_syncin_output() const { return BIT(m_value, 13, 2); } // voodoo 2 only + constexpr u32 sli_syncout_output() const { return BIT(m_value, 15, 2); } // voodoo 2 only + constexpr u32 dac_rd_output() const { return BIT(m_value, 17, 2); } // voodoo 2 only + constexpr u32 dac_wr_output() const { return BIT(m_value, 19, 2); } // voodoo 2 only + constexpr u32 pci_fifo_lwm_rdy() const { return BIT(m_value, 21, 7); } // voodoo 2 only + constexpr u32 vga_pass_n_output() const { return BIT(m_value, 28, 2); } // voodoo 2 only + constexpr u32 x_video_tiles_bit0() const { return BIT(m_value, 30, 1); } // voodoo 2 only + +private: + u32 m_value; +}; + + +// ======================> reg_fbi_init7 + +class reg_fbi_init7 +{ +public: + constexpr reg_fbi_init7(u32 value) : + m_value(value) { } + + constexpr u32 generic_strapping() const { return BIT(m_value, 0, 8); } // voodoo 2 only + constexpr u32 cmdfifo_enable() const { return BIT(m_value, 8, 1); } // voodoo 2 only + constexpr u32 cmdfifo_memory_store() const { return BIT(m_value, 9, 1); } // voodoo 2 only + constexpr u32 disable_cmdfifo_holes() const { return BIT(m_value, 10, 1); } // voodoo 2 only + constexpr u32 cmdfifo_read_thresh() const { return BIT(m_value, 11, 5); } // voodoo 2 only + constexpr u32 sync_cmdfifo_writes() const { return BIT(m_value, 16, 1); } // voodoo 2 only + constexpr u32 sync_cmdfifo_reads() const { return BIT(m_value, 17, 1); } // voodoo 2 only + constexpr u32 reset_pci_packer() const { return BIT(m_value, 18, 1); } // voodoo 2 only + constexpr u32 enable_chroma_stuff() const { return BIT(m_value, 19, 1); } // voodoo 2 only + constexpr u32 cmdfifo_pci_timeout() const { return BIT(m_value, 20, 7); } // voodoo 2 only + constexpr u32 enable_texture_burst() const { return BIT(m_value, 27, 1); } // voodoo 2 only + +private: + u32 m_value; +}; + + +// ======================> reg_intr_ctrl + +class reg_intr_ctrl +{ +public: + static constexpr u32 HSYNC_RISING_GENERATED = 1 << 6; + static constexpr u32 HSYNC_FALLING_GENERATED = 1 << 7; + static constexpr u32 VSYNC_RISING_GENERATED = 1 << 8; + static constexpr u32 VSYNC_FALLING_GENERATED = 1 << 9; + static constexpr u32 PCI_FIFO_FULL_GENERATED = 1 << 10; + static constexpr u32 USER_INTERRUPT_GENERATED = 1 << 11; + static constexpr u32 USER_INTERRUPT_TAG_MASK = 0xff << 12; + static constexpr u32 EXTERNAL_PIN_ACTIVE = 1 << 31; + + constexpr reg_intr_ctrl(u32 value) : + m_value(value) { } + + constexpr u32 hsync_rising_enable() const { return BIT(m_value, 0, 1); } + constexpr u32 hsync_falling_enable() const { return BIT(m_value, 1, 1); } + constexpr u32 vsync_rising_enable() const { return BIT(m_value, 2, 1); } + constexpr u32 vsync_falling_enable() const { return BIT(m_value, 3, 1); } + constexpr u32 pci_fifo_full_enable() const { return BIT(m_value, 4, 1); } + constexpr u32 user_interrupt_enable() const { return BIT(m_value, 5, 1); } + constexpr u32 hsync_rising_generated() const { return BIT(m_value, 6, 1); } + constexpr u32 hsync_falling_generated() const { return BIT(m_value, 7, 1); } + constexpr u32 vsync_rising_generated() const { return BIT(m_value, 8, 1); } + constexpr u32 vsync_falling_generated() const { return BIT(m_value, 9, 1); } + constexpr u32 pci_fifo_full_generated() const { return BIT(m_value, 10, 1); } + constexpr u32 user_interrupt_generated() const { return BIT(m_value, 11, 1); } + constexpr u32 user_interrupt_command_tag() const { return BIT(m_value, 12, 8); } + constexpr u32 external_pin_active() const { return BIT(m_value, 31, 1); } + +private: + u32 m_value; +}; + + +// ======================> reg_hsync + +template +class reg_hsync +{ +public: + constexpr reg_hsync(u32 value) : + m_value(value) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 hsync_on() const { return BIT(m_value, 0, Rev1 ? 8 : 9); } + constexpr u32 hsync_off() const { return BIT(m_value, 16, Rev1 ? 10 : 11); } + +private: + u32 m_value; +}; + + +// ======================> reg_vsync + +template +class reg_vsync +{ +public: + constexpr reg_vsync(u32 value) : + m_value(value) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 vsync_on() const { return BIT(m_value, 0, Rev1 ? 12 : 13); } + constexpr u32 vsync_off() const { return BIT(m_value, 16, Rev1 ? 12 : 13); } + +private: + u32 m_value; +}; + + +// ======================> reg_video_dimensions + +template +class reg_video_dimensions +{ +public: + constexpr reg_video_dimensions(u32 value) : + m_value(value) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 xwidth() const { return BIT(m_value, 0, Rev1 ? 10 : 11); } + constexpr u32 yheight() const { return BIT(m_value, 16, Rev1 ? 10 : 11); } + +private: + u32 m_value; +}; + + +// ======================> reg_back_porch + +template +class reg_back_porch +{ +public: + constexpr reg_back_porch(u32 value) : + m_value(value) { } + + constexpr u32 raw() const { return m_value; } + constexpr u32 horizontal() const { return BIT(m_value, 0, Rev1 ? 8 : 9); } + constexpr u32 vertical() const { return BIT(m_value, 16, Rev1 ? 8 : 9); } + +private: + u32 m_value; +}; + + + +//************************************************************************** +// CORE VOODOO REGISTERS +//************************************************************************** + +// ======================> voodoo_regs + +class voodoo_regs +{ +public: + static constexpr s32 s24(s32 value) { return s32(value << 8) >> 8; } + + // 0x000 + static constexpr u32 reg_vdstatus = 0x000/4; // R P + static constexpr u32 reg_intrCtrl = 0x004/4; // RW P -- Voodoo2/Banshee only + static constexpr u32 reg_vertexAx = 0x008/4; // W PF + static constexpr u32 reg_vertexAy = 0x00c/4; // W PF + static constexpr u32 reg_vertexBx = 0x010/4; // W PF + static constexpr u32 reg_vertexBy = 0x014/4; // W PF + static constexpr u32 reg_vertexCx = 0x018/4; // W PF + static constexpr u32 reg_vertexCy = 0x01c/4; // W PF + static constexpr u32 reg_startR = 0x020/4; // W PF + static constexpr u32 reg_startG = 0x024/4; // W PF + static constexpr u32 reg_startB = 0x028/4; // W PF + static constexpr u32 reg_startZ = 0x02c/4; // W PF + static constexpr u32 reg_startA = 0x030/4; // W PF + static constexpr u32 reg_startS = 0x034/4; // W PF + static constexpr u32 reg_startT = 0x038/4; // W PF + static constexpr u32 reg_startW = 0x03c/4; // W PF + + // 0x040 + static constexpr u32 reg_dRdX = 0x040/4; // W PF + static constexpr u32 reg_dGdX = 0x044/4; // W PF + static constexpr u32 reg_dBdX = 0x048/4; // W PF + static constexpr u32 reg_dZdX = 0x04c/4; // W PF + static constexpr u32 reg_dAdX = 0x050/4; // W PF + static constexpr u32 reg_dSdX = 0x054/4; // W PF + static constexpr u32 reg_dTdX = 0x058/4; // W PF + static constexpr u32 reg_dWdX = 0x05c/4; // W PF + static constexpr u32 reg_dRdY = 0x060/4; // W PF + static constexpr u32 reg_dGdY = 0x064/4; // W PF + static constexpr u32 reg_dBdY = 0x068/4; // W PF + static constexpr u32 reg_dZdY = 0x06c/4; // W PF + static constexpr u32 reg_dAdY = 0x070/4; // W PF + static constexpr u32 reg_dSdY = 0x074/4; // W PF + static constexpr u32 reg_dTdY = 0x078/4; // W PF + static constexpr u32 reg_dWdY = 0x07c/4; // W PF + + // 0x080 + static constexpr u32 reg_triangleCMD = 0x080/4; // W PF + static constexpr u32 reg_fvertexAx = 0x088/4; // W PF + static constexpr u32 reg_fvertexAy = 0x08c/4; // W PF + static constexpr u32 reg_fvertexBx = 0x090/4; // W PF + static constexpr u32 reg_fvertexBy = 0x094/4; // W PF + static constexpr u32 reg_fvertexCx = 0x098/4; // W PF + static constexpr u32 reg_fvertexCy = 0x09c/4; // W PF + static constexpr u32 reg_fstartR = 0x0a0/4; // W PF + static constexpr u32 reg_fstartG = 0x0a4/4; // W PF + static constexpr u32 reg_fstartB = 0x0a8/4; // W PF + static constexpr u32 reg_fstartZ = 0x0ac/4; // W PF + static constexpr u32 reg_fstartA = 0x0b0/4; // W PF + static constexpr u32 reg_fstartS = 0x0b4/4; // W PF + static constexpr u32 reg_fstartT = 0x0b8/4; // W PF + static constexpr u32 reg_fstartW = 0x0bc/4; // W PF + + // 0x0c0 + static constexpr u32 reg_fdRdX = 0x0c0/4; // W PF + static constexpr u32 reg_fdGdX = 0x0c4/4; // W PF + static constexpr u32 reg_fdBdX = 0x0c8/4; // W PF + static constexpr u32 reg_fdZdX = 0x0cc/4; // W PF + static constexpr u32 reg_fdAdX = 0x0d0/4; // W PF + static constexpr u32 reg_fdSdX = 0x0d4/4; // W PF + static constexpr u32 reg_fdTdX = 0x0d8/4; // W PF + static constexpr u32 reg_fdWdX = 0x0dc/4; // W PF + static constexpr u32 reg_fdRdY = 0x0e0/4; // W PF + static constexpr u32 reg_fdGdY = 0x0e4/4; // W PF + static constexpr u32 reg_fdBdY = 0x0e8/4; // W PF + static constexpr u32 reg_fdZdY = 0x0ec/4; // W PF + static constexpr u32 reg_fdAdY = 0x0f0/4; // W PF + static constexpr u32 reg_fdSdY = 0x0f4/4; // W PF + static constexpr u32 reg_fdTdY = 0x0f8/4; // W PF + static constexpr u32 reg_fdWdY = 0x0fc/4; // W PF + + // 0x100 + static constexpr u32 reg_ftriangleCMD = 0x100/4; // W PF + static constexpr u32 reg_fbzColorPath = 0x104/4; // RW PF + static constexpr u32 reg_fogMode = 0x108/4; // RW PF + static constexpr u32 reg_alphaMode = 0x10c/4; // RW PF + static constexpr u32 reg_fbzMode = 0x110/4; // RW F + static constexpr u32 reg_lfbMode = 0x114/4; // RW F + static constexpr u32 reg_clipLeftRight = 0x118/4; // RW F + static constexpr u32 reg_clipLowYHighY = 0x11c/4; // RW F + static constexpr u32 reg_nopCMD = 0x120/4; // W F + static constexpr u32 reg_fastfillCMD = 0x124/4; // W F + static constexpr u32 reg_swapbufferCMD = 0x128/4; // W F + static constexpr u32 reg_fogColor = 0x12c/4; // W F + static constexpr u32 reg_zaColor = 0x130/4; // W F + static constexpr u32 reg_chromaKey = 0x134/4; // W F + static constexpr u32 reg_chromaRange = 0x138/4; // W F -- Voodoo2/Banshee only + static constexpr u32 reg_userIntrCMD = 0x13c/4; // W F -- Voodoo2/Banshee only + + // 0x140 + static constexpr u32 reg_stipple = 0x140/4; // RW F + static constexpr u32 reg_color0 = 0x144/4; // RW F + static constexpr u32 reg_color1 = 0x148/4; // RW F + static constexpr u32 reg_fbiPixelsIn = 0x14c/4; // R + static constexpr u32 reg_fbiChromaFail = 0x150/4; // R + static constexpr u32 reg_fbiZfuncFail = 0x154/4; // R + static constexpr u32 reg_fbiAfuncFail = 0x158/4; // R + static constexpr u32 reg_fbiPixelsOut = 0x15c/4; // R + static constexpr u32 reg_fogTable = 0x160/4; // W F + + // 0x1c0 + static constexpr u32 reg_cmdFifoBaseAddr = 0x1e0/4; // RW -- Voodoo2 only + static constexpr u32 reg_cmdFifoBump = 0x1e4/4; // RW -- Voodoo2 only + static constexpr u32 reg_cmdFifoRdPtr = 0x1e8/4; // RW -- Voodoo2 only + static constexpr u32 reg_cmdFifoAMin = 0x1ec/4; // RW -- Voodoo2 only + static constexpr u32 reg_colBufferAddr = 0x1ec/4; // RW -- Banshee only + static constexpr u32 reg_cmdFifoAMax = 0x1f0/4; // RW -- Voodoo2 only + static constexpr u32 reg_colBufferStride = 0x1f0/4; // RW -- Banshee only + static constexpr u32 reg_cmdFifoDepth = 0x1f4/4; // RW -- Voodoo2 only + static constexpr u32 reg_auxBufferAddr = 0x1f4/4; // RW -- Banshee only + static constexpr u32 reg_cmdFifoHoles = 0x1f8/4; // RW -- Voodoo2 only + static constexpr u32 reg_auxBufferStride = 0x1f8/4; // RW -- Banshee only + + // 0x200 + static constexpr u32 reg_fbiInit4 = 0x200/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_clipLeftRight1 = 0x200/4; // RW -- Banshee only + static constexpr u32 reg_vRetrace = 0x204/4; // R -- Voodoo/Voodoo2 only + static constexpr u32 reg_clipTopBottom1 = 0x204/4; // RW -- Banshee only + static constexpr u32 reg_backPorch = 0x208/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_videoDimensions = 0x20c/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_fbiInit0 = 0x210/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_fbiInit1 = 0x214/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_fbiInit2 = 0x218/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_fbiInit3 = 0x21c/4; // RW -- Voodoo/Voodoo2 only + static constexpr u32 reg_hSync = 0x220/4; // W -- Voodoo/Voodoo2 only + static constexpr u32 reg_vSync = 0x224/4; // W -- Voodoo/Voodoo2 only + static constexpr u32 reg_clutData = 0x228/4; // W F -- Voodoo/Voodoo2 only + static constexpr u32 reg_dacData = 0x22c/4; // W -- Voodoo/Voodoo2 only + static constexpr u32 reg_maxRgbDelta = 0x230/4; // W -- Voodoo/Voodoo2 only + static constexpr u32 reg_hBorder = 0x234/4; // W -- Voodoo2 only + static constexpr u32 reg_vBorder = 0x238/4; // W -- Voodoo2 only + static constexpr u32 reg_borderColor = 0x23c/4; // W -- Voodoo2 only + + // 0x240 + static constexpr u32 reg_hvRetrace = 0x240/4; // R -- Voodoo2 only + static constexpr u32 reg_fbiInit5 = 0x244/4; // RW -- Voodoo2 only + static constexpr u32 reg_fbiInit6 = 0x248/4; // RW -- Voodoo2 only + static constexpr u32 reg_fbiInit7 = 0x24c/4; // RW -- Voodoo2 only + static constexpr u32 reg_swapPending = 0x24c/4; // W -- Banshee only + static constexpr u32 reg_leftOverlayBuf = 0x250/4; // W -- Banshee only + static constexpr u32 reg_rightOverlayBuf = 0x254/4; // W -- Banshee only + static constexpr u32 reg_fbiSwapHistory = 0x258/4; // R -- Voodoo2/Banshee only + static constexpr u32 reg_fbiTrianglesOut = 0x25c/4; // R -- Voodoo2/Banshee only + static constexpr u32 reg_sSetupMode = 0x260/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sVx = 0x264/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sVy = 0x268/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sARGB = 0x26c/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sRed = 0x270/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sGreen = 0x274/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sBlue = 0x278/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sAlpha = 0x27c/4; // W PF -- Voodoo2/Banshee only + + // 0x280 + static constexpr u32 reg_sVz = 0x280/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sWb = 0x284/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sWtmu0 = 0x288/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sS_W0 = 0x28c/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sT_W0 = 0x290/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sWtmu1 = 0x294/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sS_Wtmu1 = 0x298/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sT_Wtmu1 = 0x29c/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sDrawTriCMD = 0x2a0/4; // W PF -- Voodoo2/Banshee only + static constexpr u32 reg_sBeginTriCMD = 0x2a4/4; // W PF -- Voodoo2/Banshee only + + // 0x2c0 + static constexpr u32 reg_bltSrcBaseAddr = 0x2c0/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltDstBaseAddr = 0x2c4/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltXYStrides = 0x2c8/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltSrcChromaRange = 0x2cc/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltDstChromaRange = 0x2d0/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltClipX = 0x2d4/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltClipY = 0x2d8/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltSrcXY = 0x2e0/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltDstXY = 0x2e4/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltSize = 0x2e8/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltRop = 0x2ec/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltColor = 0x2f0/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltCommand = 0x2f8/4; // RW PF -- Voodoo2 only + static constexpr u32 reg_bltData = 0x2fc/4; // W PF -- Voodoo2 only + + // 0x300 + static constexpr u32 reg_textureMode = 0x300/4; // W PF + static constexpr u32 reg_tLOD = 0x304/4; // W PF + static constexpr u32 reg_tDetail = 0x308/4; // W PF + static constexpr u32 reg_texBaseAddr = 0x30c/4; // W PF + static constexpr u32 reg_texBaseAddr_1 = 0x310/4; // W PF + static constexpr u32 reg_texBaseAddr_2 = 0x314/4; // W PF + static constexpr u32 reg_texBaseAddr_3_8 = 0x318/4; // W PF + static constexpr u32 reg_trexInit0 = 0x31c/4; // W F -- Voodoo/Voodoo2 only + static constexpr u32 reg_trexInit1 = 0x320/4; // W F + static constexpr u32 reg_nccTable = 0x324/4; // W F + + // constructor + voodoo_regs() + { + for (int index = 0; index < std::size(m_regs); index++) + m_regs[index].u = 0; + } + + // state saving + void register_save(save_proxy &save); + + // register aliasing + static u32 alias(u32 regnum) { return (regnum < 0x40) ? s_alias_map[regnum] : regnum; } + + // simple readers + u32 read(u32 index) const { return m_regs[index].u; } + float read_float(u32 index) const { return m_regs[index].f; } + s32 ax() const { return s16(m_regs[reg_vertexAx].u); } + s32 ay() const { return s16(m_regs[reg_vertexAy].u); } + s32 bx() const { return s16(m_regs[reg_vertexBx].u); } + s32 by() const { return s16(m_regs[reg_vertexBy].u); } + s32 cx() const { return s16(m_regs[reg_vertexCx].u); } + s32 cy() const { return s16(m_regs[reg_vertexCy].u); } + s32 start_r() const { return s24(m_regs[reg_startR].u); } + s32 start_g() const { return s24(m_regs[reg_startG].u); } + s32 start_b() const { return s24(m_regs[reg_startB].u); } + s32 start_a() const { return s24(m_regs[reg_startA].u); } + s32 start_z() const { return m_regs[reg_startZ].u; } + s64 start_s() const { return m_starts; } + s64 start_t() const { return m_startt; } + s64 start_w() const { return m_startw; } + s32 dr_dx() const { return s24(m_regs[reg_dRdX].u); } + s32 dg_dx() const { return s24(m_regs[reg_dGdX].u); } + s32 db_dx() const { return s24(m_regs[reg_dBdX].u); } + s32 da_dx() const { return s24(m_regs[reg_dAdX].u); } + s32 dz_dx() const { return m_regs[reg_dZdX].u; } + s64 ds_dx() const { return m_dsdx; } + s64 dt_dx() const { return m_dtdx; } + s64 dw_dx() const { return m_dwdx; } + s32 dr_dy() const { return s24(m_regs[reg_dRdY].u); } + s32 dg_dy() const { return s24(m_regs[reg_dGdY].u); } + s32 db_dy() const { return s24(m_regs[reg_dBdY].u); } + s32 da_dy() const { return s24(m_regs[reg_dAdY].u); } + s32 dz_dy() const { return m_regs[reg_dZdY].u; } + s64 ds_dy() const { return m_dsdy; } + s64 dt_dy() const { return m_dtdy; } + s64 dw_dy() const { return m_dwdy; } + reg_fbz_colorpath fbz_colorpath() const { return reg_fbz_colorpath(m_regs[reg_fbzColorPath].u); } + reg_fog_mode fog_mode() const { return reg_fog_mode(m_regs[reg_fogMode].u); } + reg_alpha_mode alpha_mode() const { return reg_alpha_mode(m_regs[reg_alphaMode].u); } + reg_fbz_mode fbz_mode() const { return reg_fbz_mode(m_regs[reg_fbzMode].u); } + reg_lfb_mode lfb_mode() const { return reg_lfb_mode(m_regs[reg_lfbMode].u); } + reg_color fog_color() const { return m_regs[reg_fogColor].u; } + u32 za_color() const { return m_regs[reg_zaColor].u; } + reg_color chroma_key() const { return reg_color(m_regs[reg_chromaKey].u); } + reg_color color0() const { return reg_color(m_regs[reg_color0].u); } + reg_color color1() const { return reg_color(m_regs[reg_color1].u); } + reg_chroma_range chroma_range() const { return m_regs[reg_chromaRange].u; } + u32 stipple() const { return m_regs[reg_stipple].u; } + reg_fbi_init0 fbi_init0() const { return reg_fbi_init0(m_regs[reg_fbiInit0].u); } + reg_fbi_init1 fbi_init1() const { return reg_fbi_init1(m_regs[reg_fbiInit1].u); } + reg_fbi_init2 fbi_init2() const { return reg_fbi_init2(m_regs[reg_fbiInit2].u); } + reg_fbi_init3 fbi_init3() const { return reg_fbi_init3(m_regs[reg_fbiInit3].u); } + reg_fbi_init4 fbi_init4() const { return reg_fbi_init4(m_regs[reg_fbiInit4].u); } + reg_texture_mode texture_mode() const { return reg_texture_mode(m_regs[reg_textureMode].u); } + reg_texture_lod texture_lod() const { return reg_texture_lod(m_regs[reg_tLOD].u); } + reg_texture_detail texture_detail() const { return reg_texture_detail(m_regs[reg_tDetail].u); } + u32 texture_baseaddr() const { return m_regs[reg_texBaseAddr].u; } + u32 texture_baseaddr_1() const { return m_regs[reg_texBaseAddr_1].u; } + u32 texture_baseaddr_2() const { return m_regs[reg_texBaseAddr_2].u; } + u32 texture_baseaddr_3_8() const { return m_regs[reg_texBaseAddr_3_8].u; } + reg_clip_minmax clip_left_right() const { return reg_clip_minmax(m_regs[reg_clipLeftRight].u); } + reg_clip_minmax clip_lowy_highy() const { return reg_clip_minmax(m_regs[reg_clipLowYHighY].u); } + u32 swap_history() const { return m_regs[reg_fbiSwapHistory].u; } + template reg_hsync hsync() const { return reg_hsync(m_regs[reg_hSync].u); } + template reg_vsync vsync() const { return reg_vsync(m_regs[reg_vSync].u); } + template reg_video_dimensions video_dimensions() const { return reg_video_dimensions(m_regs[reg_videoDimensions].u); } + template reg_back_porch back_porch() const { return reg_back_porch(m_regs[reg_backPorch].u); } + + // voodoo-2-specific reads + reg_intr_ctrl intr_ctrl() const { return reg_intr_ctrl(m_regs[reg_intrCtrl].u); } + reg_fbi_init5 fbi_init5() const { return reg_fbi_init5(m_regs[reg_fbiInit5].u); } + reg_fbi_init6 fbi_init6() const { return reg_fbi_init6(m_regs[reg_fbiInit6].u); } + reg_fbi_init7 fbi_init7() const { return reg_fbi_init7(m_regs[reg_fbiInit7].u); } + reg_setup_mode setup_mode() const { return reg_setup_mode(m_regs[reg_sSetupMode].u); } + + // special case for the TMU configuration register, which is otherwise undocumented + u32 trexinit_send_tmu_config() const { return (m_regs[reg_trexInit1].u >> 18) & 1; } + + // easier clip accessors + s32 clip_left() const { return clip_left_right().min(); } + s32 clip_right() const { return clip_left_right().max(); } + s32 clip_top() const { return clip_lowy_highy().min(); } + s32 clip_bottom() const { return clip_lowy_highy().max(); } + + // write access + void write(u32 index, u32 data) { m_regs[index].u = data; } + void add(u32 index, u32 data) { m_regs[index].u += data; } + void clear_set(u32 index, u32 clear, u32 set) { m_regs[index].u &= ~clear; m_regs[index].u |= set; } + void write_float(u32 index, float data) { m_regs[index].f = data; } + void write_start_s(s64 data) { m_starts = data; } + void write_start_t(s64 data) { m_startt = data; } + void write_start_w(s64 data) { m_startw = data; } + void write_ds_dx(s64 data) { m_dsdx = data; } + void write_dt_dx(s64 data) { m_dtdx = data; } + void write_dw_dx(s64 data) { m_dwdx = data; } + void write_ds_dy(s64 data) { m_dsdy = data; } + void write_dt_dy(s64 data) { m_dtdy = data; } + void write_dw_dy(s64 data) { m_dwdy = data; } + + // special swap history helper + void update_swap_history(u32 count) { m_regs[reg_fbiSwapHistory].u = (m_regs[reg_fbiSwapHistory].u << 4) | count; } + + // access to a chunk of registers + u32 *subset(u32 index) { return reinterpret_cast(&m_regs[index]); } + +private: + union register_data + { + u32 u; + float f; + }; + register_data m_regs[0x100]; + s64 m_starts, m_startt; // starting S,T (14.18) + s64 m_startw; // starting W (2.30) -> 16.48 + s64 m_dsdx, m_dtdx; // delta S,T per X + s64 m_dwdx; // delta W per X + s64 m_dsdy, m_dtdy; // delta S,T per Y + s64 m_dwdy; // delta W per Y + static u8 const s_alias_map[0x40]; +}; + + + +//************************************************************************** +// BANSHEE-SPECIFIC REGISTERS +//************************************************************************** + +// ======================> banshee_2d_regs + +class banshee_2d_regs +{ +public: + static constexpr u32 clip0Min = 0x008/4; + static constexpr u32 clip0Max = 0x00c/4; + static constexpr u32 dstBaseAddr = 0x010/4; + static constexpr u32 dstFormat = 0x014/4; + static constexpr u32 srcColorkeyMin = 0x018/4; + static constexpr u32 srcColorkeyMax = 0x01c/4; + static constexpr u32 dstColorkeyMin = 0x020/4; + static constexpr u32 dstColorkeyMax = 0x024/4; + static constexpr u32 bresError0 = 0x028/4; + static constexpr u32 bresError1 = 0x02c/4; + static constexpr u32 rop = 0x030/4; + static constexpr u32 srcBaseAddr = 0x034/4; + static constexpr u32 commandExtra = 0x038/4; + static constexpr u32 lineStipple = 0x03c/4; + static constexpr u32 lineStyle = 0x040/4; + static constexpr u32 pattern0Alias = 0x044/4; + static constexpr u32 pattern1Alias = 0x048/4; + static constexpr u32 clip1Min = 0x04c/4; + static constexpr u32 clip1Max = 0x050/4; + static constexpr u32 srcFormat = 0x054/4; + static constexpr u32 srcSize = 0x058/4; + static constexpr u32 srcXY = 0x05c/4; + static constexpr u32 colorBack = 0x060/4; + static constexpr u32 colorFore = 0x064/4; + static constexpr u32 dstSize = 0x068/4; + static constexpr u32 dstXY = 0x06c/4; + static constexpr u32 command = 0x070/4; + + // constructor + banshee_2d_regs() { reset(); } + + // state saving + void register_save(save_proxy &save); + + // reset + void reset() { std::fill_n(&m_regs[0], std::size(m_regs), 0); } + + // getters + char const *name(u32 index) const + { + if (index < 0x20) + return s_names[index & 0x7f]; + if (index < 0x40) + return "launch"; + return "pattern"; + } + + // simple readers + u32 read(u32 index) const { return m_regs[index & 0x7f]; } + + // write access + u32 write(u32 index, u32 data, u32 mem_mask = 0xffffffff) { return COMBINE_DATA(&m_regs[index & 0x7f]); } + + // special swap history helper +private: + u32 m_regs[0x80]; + static char const * const s_names[0x20]; +}; + + +// ======================> banshee_io_regs + +class banshee_io_regs +{ +public: + static constexpr u32 status = 0x000/4; + static constexpr u32 pciInit0 = 0x004/4; + static constexpr u32 sipMonitor = 0x008/4; + static constexpr u32 lfbMemoryConfig = 0x00c/4; + static constexpr u32 miscInit0 = 0x010/4; + static constexpr u32 miscInit1 = 0x014/4; + static constexpr u32 dramInit0 = 0x018/4; + static constexpr u32 dramInit1 = 0x01c/4; + static constexpr u32 agpInit = 0x020/4; + static constexpr u32 tmuGbeInit = 0x024/4; + static constexpr u32 vgaInit0 = 0x028/4; + static constexpr u32 vgaInit1 = 0x02c/4; + static constexpr u32 dramCommand = 0x030/4; + static constexpr u32 dramData = 0x034/4; + static constexpr u32 pllCtrl0 = 0x040/4; + static constexpr u32 pllCtrl1 = 0x044/4; + static constexpr u32 pllCtrl2 = 0x048/4; + static constexpr u32 dacMode = 0x04c/4; + static constexpr u32 dacAddr = 0x050/4; + static constexpr u32 dacData = 0x054/4; + static constexpr u32 rgbMaxDelta = 0x058/4; + static constexpr u32 vidProcCfg = 0x05c/4; + static constexpr u32 hwCurPatAddr = 0x060/4; + static constexpr u32 hwCurLoc = 0x064/4; + static constexpr u32 hwCurC0 = 0x068/4; + static constexpr u32 hwCurC1 = 0x06c/4; + static constexpr u32 vidInFormat = 0x070/4; + static constexpr u32 vidInStatus = 0x074/4; + static constexpr u32 vidSerialParallelPort = 0x078/4; + static constexpr u32 vidInXDecimDeltas = 0x07c/4; + static constexpr u32 vidInDecimInitErrs = 0x080/4; + static constexpr u32 vidInYDecimDeltas = 0x084/4; + static constexpr u32 vidPixelBufThold = 0x088/4; + static constexpr u32 vidChromaMin = 0x08c/4; + static constexpr u32 vidChromaMax = 0x090/4; + static constexpr u32 vidCurrentLine = 0x094/4; + static constexpr u32 vidScreenSize = 0x098/4; + static constexpr u32 vidOverlayStartCoords = 0x09c/4; + static constexpr u32 vidOverlayEndScreenCoord = 0x0a0/4; + static constexpr u32 vidOverlayDudx = 0x0a4/4; + static constexpr u32 vidOverlayDudxOffsetSrcWidth = 0x0a8/4; + static constexpr u32 vidOverlayDvdy = 0x0ac/4; + static constexpr u32 vgab0 = 0x0b0/4; + static constexpr u32 vgab4 = 0x0b4/4; + static constexpr u32 vgab8 = 0x0b8/4; + static constexpr u32 vgabc = 0x0bc/4; + static constexpr u32 vgac0 = 0x0c0/4; + static constexpr u32 vgac4 = 0x0c4/4; + static constexpr u32 vgac8 = 0x0c8/4; + static constexpr u32 vgacc = 0x0cc/4; + static constexpr u32 vgad0 = 0x0d0/4; + static constexpr u32 vgad4 = 0x0d4/4; + static constexpr u32 vgad8 = 0x0d8/4; + static constexpr u32 vgadc = 0x0dc/4; + static constexpr u32 vidOverlayDvdyOffset = 0x0e0/4; + static constexpr u32 vidDesktopStartAddr = 0x0e4/4; + static constexpr u32 vidDesktopOverlayStride = 0x0e8/4; + static constexpr u32 vidInAddr0 = 0x0ec/4; + static constexpr u32 vidInAddr1 = 0x0f0/4; + static constexpr u32 vidInAddr2 = 0x0f4/4; + static constexpr u32 vidInStride = 0x0f8/4; + static constexpr u32 vidCurrOverlayStartAddr = 0x0fc/4; + + // constructor + banshee_io_regs() { reset(); } + + // state saving + void register_save(save_proxy &save); + + // reset + void reset() { std::fill_n(&m_regs[0], std::size(m_regs), 0); } + + // getters + char const *name(u32 index) const { return s_names[index & 0x3f]; } + + // simple readers + u32 read(u32 index) const { return m_regs[index & 0x3f]; } + + // write access + u32 write(u32 index, u32 data, u32 mem_mask = 0xffffffff) { return COMBINE_DATA(&m_regs[index & 0x3f]); } + + // special swap history helper +private: + u32 m_regs[0x40]; + static char const * const s_names[0x40]; +}; + + +// ======================> banshee_cmd_agp_regs + +class banshee_cmd_agp_regs +{ +public: + static constexpr u32 agpReqSize = 0x000/4; + static constexpr u32 agpHostAddressLow = 0x004/4; + static constexpr u32 agpHostAddressHigh = 0x008/4; + static constexpr u32 agpGraphicsAddress = 0x00c/4; + static constexpr u32 agpGraphicsStride = 0x010/4; + static constexpr u32 agpMoveCMD = 0x014/4; + static constexpr u32 cmdBaseAddr0 = 0x020/4; + static constexpr u32 cmdBaseSize0 = 0x024/4; + static constexpr u32 cmdBump0 = 0x028/4; + static constexpr u32 cmdRdPtrL0 = 0x02c/4; + static constexpr u32 cmdRdPtrH0 = 0x030/4; + static constexpr u32 cmdAMin0 = 0x034/4; + static constexpr u32 cmdAMax0 = 0x03c/4; + static constexpr u32 cmdFifoDepth0 = 0x044/4; + static constexpr u32 cmdHoleCnt0 = 0x048/4; + static constexpr u32 cmdBaseAddr1 = 0x050/4; + static constexpr u32 cmdBaseSize1 = 0x054/4; + static constexpr u32 cmdBump1 = 0x058/4; + static constexpr u32 cmdRdPtrL1 = 0x05c/4; + static constexpr u32 cmdRdPtrH1 = 0x060/4; + static constexpr u32 cmdAMin1 = 0x064/4; + static constexpr u32 cmdAMax1 = 0x06c/4; + static constexpr u32 cmdFifoDepth1 = 0x074/4; + static constexpr u32 cmdHoleCnt1 = 0x078/4; + static constexpr u32 cmdFifoThresh = 0x080/4; + static constexpr u32 cmdHoleInt = 0x084/4; + static constexpr u32 yuvBaseAddress = 0x100/4; + static constexpr u32 yuvStride = 0x104/4; + static constexpr u32 crc1 = 0x120/4; + static constexpr u32 crc2 = 0x130/4; + + // constructor + banshee_cmd_agp_regs() { reset(); } + + // state saving + void register_save(save_proxy &save); + + // reset + void reset() { std::fill_n(&m_regs[0], std::size(m_regs), 0); } + + // getters + char const *name(u32 index) const { return s_names[index & 0x7f]; } + + // simple readers + u32 read(u32 index) const { return m_regs[index & 0x7f]; } + + // write access + u32 write(u32 index, u32 data, u32 mem_mask = 0xffffffff) { return COMBINE_DATA(&m_regs[index & 0x7f]); } + +private: + u32 m_regs[0x80]; + static char const * const s_names[0x80]; +}; + + +// ======================> banshee_cmd_agp_regs + +class banshee_vga_regs +{ +public: + static constexpr u32 attributeData = 0x3c0 & 0x1f; + static constexpr u32 attributeIndex = 0x3c1 & 0x1f; + static constexpr u32 inputStatus0 = 0x3c2 & 0x1f; + static constexpr u32 miscOutputW = 0x3c2 & 0x1f; + static constexpr u32 motherboardEnable = 0x3c3 & 0x1f; + static constexpr u32 sequencerIndex = 0x3c4 & 0x1f; + static constexpr u32 sequencerData = 0x3c5 & 0x1f; + static constexpr u32 pixelMask = 0x3c6 & 0x1f; + static constexpr u32 readIndex = 0x3c7 & 0x1f; + static constexpr u32 readStatus = 0x3c7 & 0x1f; + static constexpr u32 writeIndex = 0x3c8 & 0x1f; + static constexpr u32 data = 0x3c9 & 0x1f; + static constexpr u32 featureControlR = 0x3ca & 0x1f; + static constexpr u32 miscOutputR = 0x3cc & 0x1f; + static constexpr u32 gfxControllerIndex = 0x3ce & 0x1f; + static constexpr u32 gfxControllerData = 0x3cf & 0x1f; + static constexpr u32 crtcIndex = 0x3d4 & 0x1f; + static constexpr u32 crtcData = 0x3d5 & 0x1f; + static constexpr u32 inputStatus1 = 0x3da & 0x1f; + static constexpr u32 featureControlW = 0x3da & 0x1f; + + // constructor + banshee_vga_regs() { reset(); } + + // state saving + void register_save(save_proxy &save); + + // reset + void reset() + { + std::fill_n(&m_regs[0], std::size(m_regs), 0); + std::fill_n(&m_crtc[0], std::size(m_crtc), 0); + std::fill_n(&m_seq[0], std::size(m_seq), 0); + std::fill_n(&m_gc[0], std::size(m_gc), 0); + std::fill_n(&m_attr[0], std::size(m_attr), 0); + m_attr_flip_flop = 0; + } + + // simple readers + u8 read(u32 index) const { return m_regs[index & 0x1f]; } + u8 read_crtc(u32 index) const { return (index < std::size(m_crtc)) ? m_crtc[index] : 0xff; } + u8 read_seq(u32 index) const { return (index < std::size(m_seq)) ? m_seq[index] : 0xff; } + u8 read_gc(u32 index) const { return (index < std::size(m_gc)) ? m_gc[index] : 0xff; } + u8 read_attr(u32 index) const { return (index < std::size(m_attr)) ? m_attr[index] : 0xff; } + + // write access + void write(u32 index, u8 data) { m_regs[index & 0x1f] = data; } + void write_crtc(u32 index, u8 data) { if (index < std::size(m_crtc)) m_crtc[index] = data; } + void write_seq(u32 index, u8 data) { if (index < std::size(m_seq)) m_seq[index] = data; } + void write_gc(u32 index, u8 data) { if (index < std::size(m_gc)) m_gc[index] = data; } + void write_attr(u32 index, u8 data) { if (index < std::size(m_attr)) m_attr[index] = data; } + + // basic accessors + u8 attribute_index() const { return m_regs[attributeIndex & 0x1f]; } + u8 sequencer_index() const { return m_regs[sequencerIndex & 0x1f]; } + u8 gfx_controller_index() const { return m_regs[gfxControllerIndex & 0x1f]; } + u8 crtc_index() const { return m_regs[crtcIndex & 0x1f]; } + + // flip flop + void clear_flip_flop() { m_attr_flip_flop = 0; } + u8 toggle_flip_flop() { u8 old = m_attr_flip_flop; m_attr_flip_flop ^= 1; return old; } + +private: + u8 m_regs[0x20]; // core VGA registers + u8 m_crtc[0x27]; // CRTC registers + u8 m_seq[0x05]; // sequencer registers + u8 m_gc[0x05]; // graphics controller registers + u8 m_attr[0x15]; // attribute registers + u8 m_attr_flip_flop; // attribute flip-flop +}; + +} + +#endif // MAME_VIDEO_VOODOO_REGS_H diff --git a/src/devices/video/voodoo_render.cpp b/src/devices/video/voodoo_render.cpp new file mode 100644 index 00000000000..b4b50fe5a68 --- /dev/null +++ b/src/devices/video/voodoo_render.cpp @@ -0,0 +1,2953 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_render.cpp + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#include "emu.h" +#include "voodoo.h" + +namespace voodoo +{ + +static constexpr bool LOG_RASTERIZERS = false; + + +struct static_rasterizer_info +{ + voodoo_renderer::rasterizer_mfp mfp; + rasterizer_params params; +}; + +extern static_rasterizer_info s_predef_raster_table[]; + + +// fast dither lookup +std::unique_ptr dither_helper::s_dither4_lookup; +std::unique_ptr dither_helper::s_dither2_lookup; +std::unique_ptr dither_helper::s_nodither_lookup; + +u8 const dither_helper::s_dither_matrix_4x4[16] = +{ + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 +}; +// Using this matrix allows iteagle video memory tests to pass +u8 const dither_helper::s_dither_matrix_2x2[16] = +{ + 8, 10, 8, 10, + 11, 9, 11, 9, + 8, 10, 8, 10, + 11, 9, 11, 9 +}; + +static const rectangle global_cliprect(-4096, 4095, -4096, 4095); + + + +//************************************************************************** +// STATIC HELPERS +//************************************************************************** + +//------------------------------------------------- +// compute_wfloat - compute the pseudo-floating +// point version of the iterated W value +//------------------------------------------------- + +static inline s32 ATTR_FORCE_INLINE compute_wfloat(s64 iterw) +{ + int exp = count_leading_zeros_64(iterw) - 16; + if (exp < 0) + return 0x0000; + if (exp >= 16) + return 0xffff; + return ((exp << 12) | ((iterw >> (35 - exp)) ^ 0x1fff)) + 1; +} + + +//------------------------------------------------- +// clamped_argb - clamp the incoming ARGB color +// according to the clamping settings, or do the +// fake pseudo-clamp described in the Voodoo +// manual +//------------------------------------------------- + +static inline rgbaint_t ATTR_FORCE_INLINE clamped_argb(const rgbaint_t &iterargb, reg_fbz_colorpath const fbzcp) +{ + rgbaint_t result(iterargb); + result.shr_imm(20); + + // clamped case is easy + if (fbzcp.rgbzw_clamp() != 0) + { + result.clamp_to_uint8(); + return result; + } + + // for each component: + // result = val & 0xfff; + // if (result == 0xfff) result = 0; + // if (result == 0x100) result = 0xff; + + // check against 0xfff and force to 0 + rgbaint_t temp1(result); + rgbaint_t temp2(result); + temp1.cmpeq_imm(0xfff); + temp2.cmpeq_imm(0x100); + result.andnot_reg(temp1); + result.or_reg(temp2); + result.and_imm(0xff); + return result; +} + + +//------------------------------------------------- +// clamped_z - clamp the Z value according to the +// clamping settings, or do the fake pseudo-clamp +// described in the Voodoo manual +//------------------------------------------------- + +static inline s32 ATTR_FORCE_INLINE clamped_z(s32 iterz, reg_fbz_colorpath const fbzcp) +{ + // clamped case is easy + if (fbzcp.rgbzw_clamp() != 0) + return std::clamp(iterz >> 12, 0, 0xffff); + + // non-clamped case has specific behaviors + u32 result = u32(iterz) >> 12; + if (result == 0xfffff) + return 0; + if (result == 0x10000) + return 0xffff; + return result & 0xffff; +} + + +//------------------------------------------------- +// clamped_w - clamp the W value according to the +// clamping settings, or do the fake pseudo-clamp +// described in the Voodoo manual +//------------------------------------------------- + +static inline s32 ATTR_FORCE_INLINE clamped_w(s64 iterw, reg_fbz_colorpath const fbzcp) +{ + // clamped case is easy + if (fbzcp.rgbzw_clamp() != 0) + return std::clamp(s32(iterw >> 48), 0, 0xff); + + // non-clamped case has specific behaviors + u32 result = u64(iterw) >> 48; + if (result == 0xffff) + return 0; + if (result == 0x100) + return 0xff; + return result & 0xff; +} + + +//------------------------------------------------- +// compute_lodbase - compute the base LOD value +//------------------------------------------------- + +static inline s32 ATTR_FORCE_INLINE compute_lodbase(s64 dsdx, s64 dsdy, s64 dtdx, s64 dtdy) +{ + // compute (ds^2 + dt^2) in both X and Y as 28.36 numbers + dsdx >>= 14; + dsdy >>= 14; + dtdx >>= 14; + dtdy >>= 14; + s64 texdx = dsdx * dsdx + dtdx * dtdx; + s64 texdy = dsdy * dsdy + dtdy * dtdy; + + // pick whichever is larger and shift off some high bits -> 28.20 + s64 maxval = std::max(texdx, texdy) >> 16; + + // use our fast reciprocal/log on this value; it expects input as a + // 16.32 number, and returns the log of the reciprocal, so we have to + // adjust the result: negative to get the log of the original value + // plus 12 to account for the extra exponent, and divided by 2 to + // get the log of the square root of texdx + return (fast_log2(double(maxval), 0) + (12 << 8)) / 2; +} + + + +//************************************************************************** +// RASTERIZER PARAMS +//************************************************************************** + +//------------------------------------------------- +// operator== - compare all values +//------------------------------------------------- + +bool rasterizer_params::operator==(rasterizer_params const &rhs) const +{ + return (m_generic == rhs.m_generic && + m_fbzcp == rhs.m_fbzcp && + m_fbzmode == rhs.m_fbzmode && + m_alphamode == rhs.m_alphamode && + m_fogmode == rhs.m_fogmode && + m_texmode0 == rhs.m_texmode0 && + m_texmode1 == rhs.m_texmode1); +} + + +//------------------------------------------------- +// compute - compute the normalized rasterizer +// parameters based on the current register state +//------------------------------------------------- + +void rasterizer_params::compute(voodoo_regs ®s, voodoo_regs *tmu0regs, voodoo_regs *tmu1regs) +{ + // these values are normalized to ignore irrelevant bits + m_generic = 0; + m_fbzcp = regs.fbz_colorpath().normalize(); + m_fbzmode = regs.fbz_mode().normalize(); + m_alphamode = regs.alpha_mode().normalize(); + m_fogmode = regs.fog_mode().normalize(); + m_texmode0 = reg_texture_mode::NONE; + m_texmode1 = reg_texture_mode::NONE; + if (!regs.fbi_init3().disable_tmus()) + { + if (tmu0regs != nullptr && tmu0regs->texture_lod().lod_min() < 32) + { + m_texmode0 = tmu0regs->texture_mode().normalize(); + m_generic |= GENERIC_TEX0; + if (tmu0regs->trexinit_send_tmu_config()) + m_texmode0 |= reg_texture_mode::TMU_CONFIG_MASK; + } + if (tmu1regs != nullptr && tmu1regs->texture_lod().lod_min() < 32) + { + m_texmode1 = tmu1regs->texture_mode().normalize(); + m_generic |= GENERIC_TEX1; + } + } + compute_equations(); +} + + +//------------------------------------------------- +// compute_equations - compute equations based +// on the captured state +//------------------------------------------------- + +void rasterizer_params::compute_equations() +{ + // start with the color equation + m_color_equation = color_equation::from_fbzcp(m_fbzcp); + + // if it doesn't consume any texels, zap the textures; we're done + if (!m_color_equation.uses_any(color_source::texel0)) + { + m_texmode0 = m_texmode1 = reg_texture_mode::NONE; + m_generic = 0; + return; + } + + // check the TMU1 equation + if (m_generic & GENERIC_TEX1) + { + m_tex1_equation = color_equation::from_texmode(m_texmode1, color_source::texel1, color_source::zero); + + // if it's identity, mark it and clear out the equation mask + if (m_tex1_equation.is_identity(color_source::texel1)) + { + m_generic |= GENERIC_TEX1_IDENTITY; + m_texmode1 &= ~reg_texture_mode::EQUATION_MASK; + } + } + + // check the TMU0 equation + if (m_generic & GENERIC_TEX0) + { + m_tex0_equation = color_equation::from_texmode(m_texmode0, color_source::texel0, (m_generic & GENERIC_TEX1) ? color_source::texel1 : color_source::zero); + + // special case the send configuration + if (!(m_texmode0 & reg_texture_mode::TMU_CONFIG_MASK)) + { + if (m_tex0_equation.is_identity(color_source::texel0)) + { + // if identity returning ourself, the downstream TMU doesn't matter + m_generic = (m_generic & ~(GENERIC_TEX1 | GENERIC_TEX1_IDENTITY)) | GENERIC_TEX0_IDENTITY; + m_texmode0 &= ~reg_texture_mode::EQUATION_MASK; + m_texmode1 = reg_texture_mode::NONE; + } + else if (m_tex0_equation.is_identity(color_source::texel1)) + { + // if identity returning the downstream value, we're just a passthrough and we don't matter + m_generic &= ~GENERIC_TEX0; + m_texmode0 = reg_texture_mode::NONE; + } + } + } +} + + +//------------------------------------------------- +// hash - return a hash of the current values +//------------------------------------------------- + +u32 rasterizer_params::hash() const +{ + return m_generic ^ + rotate(m_alphamode, 0) ^ + rotate(m_fbzmode, 6) ^ + rotate(m_fbzcp, 12) ^ + rotate(m_fogmode, 18) ^ + rotate(m_texmode0, 24) ^ + rotate(m_texmode1, 30); +} + + + +//************************************************************************** +// DITHER HELPER +//************************************************************************** + +//------------------------------------------------- +// init_static - initialize static tables +//------------------------------------------------- + +void dither_helper::init_static() +{ + // create static dithering tables + s_dither4_lookup = std::make_unique(256*4*4*2); + s_dither2_lookup = std::make_unique(256*4*4*2); + s_nodither_lookup = std::make_unique(256*4*2); + for (int val = 0; val < 256*4*4*2; val++) + { + int color = (val >> 0) & 0xff; + int g = (val >> 8) & 1; + int x = (val >> 9) & 3; + int y = (val >> 11) & 3; + + if (!g) + { + s_dither4_lookup[val] = dither_rb(color, s_dither_matrix_4x4[y * 4 + x]); + s_dither2_lookup[val] = dither_rb(color, s_dither_matrix_2x2[y * 4 + x]); + } + else + { + s_dither4_lookup[val] = dither_g(color, s_dither_matrix_4x4[y * 4 + x]); + s_dither2_lookup[val] = dither_g(color, s_dither_matrix_2x2[y * 4 + x]); + } + } + for (int val = 0; val < 256*4*2; val++) + { + int color = (val >> 0) & 0xff; + int g = (val >> 8) & 1; + + if (!g) + s_nodither_lookup[val] = color >> 3; + else + s_nodither_lookup[val] = color >> 2; + } +} + + + +//************************************************************************** +// STW HELPER +//************************************************************************** + +// use SSE on 64-bit implementations, where it can be assumed +#if 1 && ((!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64)) + +#include +#ifdef __SSE4_1__ +#include +#endif + +class stw_helper +{ +public: + stw_helper() { } + stw_helper(stw_helper const &other) = default; + stw_helper &operator=(stw_helper const &other) = default; + + void set(s64 s, s64 t, s64 w) + { + m_st = _mm_set_pd(s << 8, t << 8); + m_w = _mm_set1_pd(w); + } + + bool is_w_neg() const + { + return _mm_comilt_sd(m_w, _mm_set1_pd(0.0)); + } + + void get_st_shiftr(s32 &s, s32 &t, s32 shift) const + { + shift += 8; + s = _mm_cvtsd_si64(_mm_shuffle_pd(m_st, _mm_setzero_pd(), 1)) >> shift; + t = _mm_cvtsd_si64(m_st) >> shift; + } + + void add(stw_helper const &delta) + { + m_st = _mm_add_pd(m_st, delta.m_st); + m_w = _mm_add_pd(m_w, delta.m_w); + } + + void calc_stow(s32 &sow, s32 &tow, s32 &oowlog) const + { + __m128d tmp = _mm_div_pd(m_st, m_w); + __m128i tmp2 = _mm_cvttpd_epi32(tmp); +#ifdef __SSE4_1__ + sow = _mm_extract_epi32(tmp2, 1); + tow = _mm_extract_epi32(tmp2, 0); +#else + sow = _mm_cvtsi128_si32(_mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 0, 1))); + tow = _mm_cvtsi128_si32(tmp2); +#endif + oowlog = -fast_log2(_mm_cvtsd_f64(m_w), 0); + } + +private: + __m128d m_st; + __m128d m_w; +}; + +#else + +class stw_helper +{ +public: + stw_helper() {} + stw_helper(stw_helper const &other) = default; + stw_helper &operator=(stw_helper const &other) = default; + + void set(s64 s, s64 t, s64 w) + { + m_s = s; + m_t = t; + m_w = w; + } + + bool is_w_neg() const + { + return (m_w < 0) ? true : false; + } + + void get_st_shiftr(s32 &s, s32 &t, s32 shift) const + { + s = m_s >> shift; + t = m_t >> shift; + } + + void add(stw_helper const &other) + { + m_s += other.m_s; + m_t += other.m_t; + m_w += other.m_w; + } + + // Computes s/w and t/w and returns log2 of 1/w + // s, t and c are 16.32 values. The results are 24.8. + void calc_stow(s32 &sow, s32 &tow, s32 &oowlog) const + { + double recip = double(1ULL << (47 - 39)) / m_w; + sow = s32(m_s * recip); + tow = tow(m_t * recip); + oowlog = fast_log2(recip, 56); + } + +private: + s64 m_s, m_t, m_w; +}; + +#endif + + + +//************************************************************************** +// COLOR SOURCE +//************************************************************************** + +//------------------------------------------------- +// simplify - simplify the individual values +//------------------------------------------------- + +void color_source::simplify() +{ + // convert inverted zero to one + if (m_rgb == (ZERO | FLAG_INVERTED)) + m_rgb = ONE; + if (m_alpha == (ZERO | FLAG_INVERTED)) + m_alpha = ONE; +} + + +//------------------------------------------------- +// string - return a string version of the +// components +//------------------------------------------------- + +std::string color_source::as_string() const +{ + static char const * const s_names[] = + { + "zero", + "one", + "color0", + "color1", + "iterargb", + "clampz", + "clipw", + "", + "texel0", + "texel1", + "detailfactor", + "lodfrac", + "color/iterargb via texel0 alpha" + }; + static char const * const s_flags[] = + { + "", + ".alphaexpanded", + ".inverted", + ".alphaexpanded.inverted", + }; + std::string result; + + // determine global tags + char const *tag = ""; + if (is_constant()) + tag = "[const]"; + else if (is_constant_or_iterated()) + tag = "[iter]"; + + // simplest case: RGB and alpha are the same and non-ambiguous + if (m_alpha == m_rgb || (is_uniform_alpha() && (alpha_base() == DETAIL_FACTOR || alpha_base() == LOD_FRACTION))) + return string_format("{ %s%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag); + + // slightly less simple: RGB and alpha are both smeared alpha values + if (is_uniform_alpha()) + return string_format("{ %s.alpha%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag); + + // full complexity case + char const *tag_alpha = ""; + char const *tag_rgb = ""; + if (tag[0] == 0) + { + if (is_alpha_constant()) + tag_alpha = "[const]"; + else if (is_alpha_constant_or_iterated()) + tag_alpha = "[iter]"; + if (is_rgb_constant()) + tag_rgb = "[const]"; + else if (is_rgb_constant_or_iterated()) + tag_rgb = "[iter]"; + } + return string_format("{ %s%s%s, %s%s%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag_alpha, s_names[rgb_base()], s_flags[rgb_flags()], tag_rgb, tag); +} + +// constant values +color_source const color_source::zero(color_source::ZERO, color_source::ZERO); +color_source const color_source::one(color_source::ONE, color_source::ONE); +color_source const color_source::iterated_argb(color_source::ITERATED_ARGB, color_source::ITERATED_ARGB); +color_source const color_source::color0(color_source::COLOR0, color_source::COLOR0); +color_source const color_source::color1(color_source::COLOR1, color_source::COLOR1); +color_source const color_source::texel0(color_source::TEXEL0, color_source::TEXEL0); +color_source const color_source::texel1(color_source::TEXEL1, color_source::TEXEL1); + + +//************************************************************************** +// COLOR EQUATION +//************************************************************************** + +//------------------------------------------------- +// simplify - simplify an equation for optimal +// SIMD operations +//------------------------------------------------- + +void color_equation::simplify() +{ + // simplify each internally + m_color.simplify(); + m_subtract.simplify(); + m_multiply.simplify(); + m_add.simplify(); + + // if subtract is zero, we can maybe swap things between color and multiply to + // make things neater + if (m_subtract.is_zero()) + { + bool swap = false; + + // if both are split types and swapping will line one up, do it for sure + if (!m_color.is_uniform() && !m_multiply.is_uniform()) + if (m_multiply.alpha_base() == m_color.rgb_base() || m_multiply.rgb_base() == m_color.alpha_base()) + swap = true; + + // if neither is a constant/iterated and swapping will make one of them into + // a constant/iterated, do it + if (!m_color.is_constant_or_iterated() && !m_multiply.is_constant_or_iterated()) + if (m_color.is_rgb_constant_or_iterated() != m_color.is_alpha_constant_or_iterated() && m_multiply.is_rgb_constant_or_iterated() != m_multiply.is_alpha_constant_or_iterated()) + swap = true; + + // do the swap + if (swap) + { + auto temp = m_color.rgb(); + m_color.set_rgb(m_multiply.rgb()); + m_multiply.set_rgb(temp); + } + + // always prefer the multiply to be constant + if (m_color.is_constant_or_iterated() && !m_multiply.is_constant_or_iterated()) + { + color_source temp = m_color; + m_color = m_multiply; + m_multiply = temp; + } + + // if we're just combining rgb/alpha with constant 0/1, consolidate + if (m_multiply.alpha() == color_source::ONE && m_multiply.is_rgb_zero() && m_add.is_alpha_zero()) + { + m_add.set_alpha(m_color.alpha()); + m_multiply = color_source::zero; + } + if (m_multiply.is_alpha_zero() && m_multiply.is_rgb_one() && m_add.is_rgb_zero()) + { + m_add.set_rgb(m_color.rgb()); + m_multiply = color_source::zero; + } + + if (!m_add.is_zero() && !m_multiply.is_zero()) + { + // if the multiply is RGB and the add is alpha, combine + if (m_multiply.is_alpha_zero() && m_add.is_rgb_zero()) + { + if (m_multiply.rgb_base() == m_add.alpha_base()) + { + m_multiply.set_alpha(m_add.alpha()); + m_add.set_alpha(color_source::ZERO); + m_color.set_alpha(color_source::ONE); + } + else + { + m_color.set_alpha(m_add.alpha()); + m_add.set_alpha(color_source::ZERO); + m_multiply.set_alpha(color_source::ONE); + } + } + + // if the multiply is alpha and the add is RGB, combine + if (m_multiply.is_rgb_zero() && m_add.is_alpha_zero()) + { + if (m_multiply.alpha() == m_add.rgb()) + { + m_multiply.set_rgb(m_add.rgb()); + m_add.set_rgb(color_source::ZERO); + m_color.set_rgb(color_source::ONE); + } + else + { + m_color.set_rgb(m_add.rgb()); + m_add.set_rgb(color_source::ZERO); + m_multiply.set_rgb(color_source::ONE); + } + } + } + } + + // if the alpha multiply is zero, it doesn't matter what the color/subtract alpha is + if (m_multiply.is_alpha_zero()) + { + m_color.set_alpha(m_color.rgb()); + m_subtract.set_alpha(m_subtract.rgb()); + } + if (m_multiply.is_rgb_zero()) + { + m_color.set_rgb(m_color.alpha()); + m_subtract.set_rgb(m_subtract.alpha()); + } + + // if color is zero and subtract is zero, that means the multiply is irrelevant + if (m_color.is_zero() && m_subtract.is_zero()) + m_multiply = color_source::zero; +} + + +//------------------------------------------------- +// as_string - return a string version of the +// equation +//------------------------------------------------- + +std::string color_equation::as_string() const +{ + // attempt to simplify + // blend factor of zero ignores earlier stuff + if (m_multiply.is_zero()) + return m_add.as_string(); + + // blend multiply of one is an add + if (m_multiply.is_one()) + { + std::string result = m_color.as_string(); + if (!m_subtract.is_zero()) + { + result += " - "; + result += m_subtract.as_string(); + } + if (!m_add.is_zero()) + { + result += " + "; + result += m_add.as_string(); + } + return result; + } + + // otherwise a proper blend + std::string result; + if (!m_subtract.is_zero()) + result += "("; + result += m_color.as_string(); + if (!m_subtract.is_zero()) + { + result += " - "; + result += m_subtract.as_string(); + result += ")"; + } + result += " * "; + result += m_multiply.as_string(); + if (!m_add.is_zero()) + { + result += " + "; + result += m_add.as_string(); + } + return result; +} + + +//------------------------------------------------- +// from_fbzcp - compute the color equation based +// on the fbs colorpath +//------------------------------------------------- + +color_equation color_equation::from_fbzcp(reg_fbz_colorpath const fbzcp) +{ + // determine other color + color_source other_color; + switch (fbzcp.cc_rgbselect()) + { + case 0: other_color.set_rgb(color_source::iterated_argb.rgb()); break; + case 1: other_color.set_rgb(color_source::texel0.rgb()); break; + case 2: other_color.set_rgb(color_source::color1.rgb()); break; + } + switch (fbzcp.cc_aselect()) + { + case 0: other_color.set_alpha(color_source::iterated_argb.alpha()); break; + case 1: other_color.set_alpha(color_source::texel0.alpha()); break; + case 2: other_color.set_alpha(color_source::color1.alpha()); break; + } + + // determine local color + color_source local_color; + if (fbzcp.cc_localselect_override() == 0) + local_color.set_rgb((fbzcp.cc_localselect() == 0) ? color_source::iterated_argb.rgb() : color_source::color0.rgb()); + else + local_color.set_rgb(color_source::COLOR0_OR_ITERATED_VIA_TEXEL_ALPHA); + switch (fbzcp.cca_localselect()) + { + case 0: local_color.set_alpha(color_source::iterated_argb.alpha()); break; + case 1: local_color.set_alpha(color_source::color0.alpha()); break; + case 2: local_color.set_alpha(color_source::CLAMPZ); break; + case 3: local_color.set_alpha(color_source::CLAMPW); break; + } + + // select blend color + color_equation equation; + if (!fbzcp.cc_zero_other()) + equation.color().set_rgb(other_color.rgb()); + if (!fbzcp.cca_zero_other()) + equation.color().set_alpha(other_color.alpha()); + + // determine subtraction color + if (fbzcp.cc_sub_clocal()) + equation.subtract().set_rgb(local_color.rgb()); + if (fbzcp.cca_sub_clocal()) + equation.subtract().set_alpha(local_color.alpha()); + + // determine blend factor + switch (fbzcp.cc_mselect()) + { + case 1: equation.multiply().set_rgb(local_color.rgb()); break; + case 2: equation.multiply().set_rgb_from_alpha(other_color.alpha()); break; + case 3: equation.multiply().set_rgb_from_alpha(local_color.alpha()); break; + case 4: equation.multiply().set_rgb_from_alpha(color_source::texel0.alpha()); break; + case 5: /*if (type >= VOODOO_2)*/ equation.multiply().set_rgb(color_source::texel0.rgb()); break; + } + switch (fbzcp.cca_mselect()) + { + case 1: + case 3: equation.multiply().set_alpha(local_color.alpha()); break; + case 2: equation.multiply().set_alpha(other_color.alpha()); break; + case 4: equation.multiply().set_alpha(color_source::texel0.alpha()); break; + } + if (!fbzcp.cc_reverse_blend()) equation.multiply().invert_rgb(); + if (!fbzcp.cca_reverse_blend()) equation.multiply().invert_alpha(); + + // determine add color + switch (fbzcp.cc_add_aclocal()) + { + case 1: equation.add().set_rgb(local_color.rgb()); break; + case 2: equation.add().set_rgb_from_alpha(local_color.alpha()); break; + } + if (fbzcp.cca_add_aclocal()) + equation.add().set_alpha(local_color.alpha()); + + equation.simplify(); + return equation; +} + + +//------------------------------------------------- +// from_texmode - compute the color equation based +// on the fbs colorpath +//------------------------------------------------- + +color_equation color_equation::from_texmode(reg_texture_mode const texmode, color_source texel_color, color_source input_color) +{ + color_source other_color = input_color; + color_source local_color = texel_color; + color_equation equation; + + if (!texmode.tc_zero_other()) + equation.color().set_rgb(other_color.rgb()); + if (!texmode.tca_zero_other()) + equation.color().set_alpha(other_color.alpha()); + + if (texmode.tc_sub_clocal()) + equation.subtract().set_rgb(local_color.rgb()); + if (texmode.tca_sub_clocal()) + equation.subtract().set_alpha(local_color.alpha()); + + switch (texmode.tc_mselect()) + { + case 1: equation.multiply().set_rgb(local_color.rgb()); break; + case 2: equation.multiply().set_rgb_from_alpha(other_color.alpha()); break; + case 3: equation.multiply().set_rgb_from_alpha(local_color.alpha()); break; + case 4: equation.multiply().set_rgb_from_alpha(color_source::DETAIL_FACTOR); break; + case 5: equation.multiply().set_rgb_from_alpha(color_source::LOD_FRACTION); break; + } + switch (texmode.tca_mselect()) + { + case 1: + case 3: equation.multiply().set_alpha(local_color.alpha()); break; + case 2: equation.multiply().set_alpha(other_color.alpha()); break; + case 4: equation.multiply().set_alpha(color_source::DETAIL_FACTOR); break; + case 5: equation.multiply().set_alpha(color_source::LOD_FRACTION); break; + } + if (!texmode.tc_reverse_blend()) equation.multiply().invert_rgb(); + if (!texmode.tca_reverse_blend()) equation.multiply().invert_alpha(); + + switch (texmode.tc_add_aclocal()) + { + case 1: equation.add().set_rgb(local_color.rgb()); break; + case 2: equation.add().set_rgb_from_alpha(local_color.alpha()); break; + } + if (texmode.tca_add_aclocal()) + equation.add().set_alpha(local_color.alpha()); + + equation.simplify(); + return equation; +} + + + +//************************************************************************** +// RASTER TEXTURE +//************************************************************************** + +//------------------------------------------------- +// recompute - recompute state based on parameters +//------------------------------------------------- + +void rasterizer_texture::recompute(voodoo_regs const ®s, u8 *ram, u32 mask, rgb_t const *lookup, u32 addrmask, u8 addrshift) +{ + m_ram = ram; + m_mask = mask; + m_lookup = lookup; + + // extract LOD parameters + auto const texlod = regs.texture_lod(); + m_lodmin = texlod.lod_min() << 6; + m_lodmax = texlod.lod_max() << 6; + m_lodbias = s8(texlod.lod_bias() << 2) << 4; + + // determine which LODs are present + m_lodmask = 0x1ff; + if (texlod.lod_tsplit()) + m_lodmask = texlod.lod_odd() ? 0x0aa : 0x155; + + // determine base texture width/height + m_wmask = m_hmask = 0xff; + if (texlod.lod_s_is_wider()) + m_hmask >>= texlod.lod_aspect(); + else + m_wmask >>= texlod.lod_aspect(); + + // determine the bpp of the texture + auto const texmode = regs.texture_mode(); + int bppscale = texmode.format() >> 3; + + // start with the base of LOD 0 + u32 base = regs.texture_baseaddr(); + if (addrshift == 0 && BIT(base, 0) != 0) + fatalerror("Unsupported tiled texture in Voodoo device"); + base = (base & addrmask) << addrshift; + m_lodoffset[0] = base & mask; + + // LODs 1-3 are different depending on whether we are in multitex mode + // Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think + // they want multitex mode when they really don't -- disable for now + // Enable for Voodoo 3 or Viper breaks - VL. + // Add check for upper nibble not equal to zero to fix funkball -- TG + if (texlod.tmultibaseaddr() && texlod.magic() == 0) + { + base = (regs.texture_baseaddr_1() & addrmask) << addrshift; + m_lodoffset[1] = base & mask; + base = (regs.texture_baseaddr_2() & addrmask) << addrshift; + m_lodoffset[2] = base & mask; + base = (regs.texture_baseaddr_3_8() & addrmask) << addrshift; + m_lodoffset[3] = base & mask; + } + else + { + if (m_lodmask & (1 << 0)) + base += (((m_wmask >> 0) + 1) * ((m_hmask >> 0) + 1)) << bppscale; + m_lodoffset[1] = base & mask; + if (m_lodmask & (1 << 1)) + base += (((m_wmask >> 1) + 1) * ((m_hmask >> 1) + 1)) << bppscale; + m_lodoffset[2] = base & mask; + if (m_lodmask & (1 << 2)) + base += (((m_wmask >> 2) + 1) * ((m_hmask >> 2) + 1)) << bppscale; + m_lodoffset[3] = base & mask; + } + + // remaining LODs make sense + for (int lod = 4; lod <= 8; lod++) + { + if (m_lodmask & (1 << (lod - 1))) + { + u32 size = ((m_wmask >> (lod - 1)) + 1) * ((m_hmask >> (lod - 1)) + 1); + if (size < 4) size = 4; + base += size << bppscale; + } + m_lodoffset[lod] = base & mask; + } + + // compute the detail parameters + auto const texdetail = regs.texture_detail(); + m_detailmax = texdetail.detail_max(); + m_detailbias = s8(texdetail.detail_bias() << 2) << 6; + m_detailscale = texdetail.detail_scale(); +} + + +//------------------------------------------------- +// lookup_single_texel - look up the texel at the +// given S,T coordinate based on the format and +// return a decoded RGB value +//------------------------------------------------- + +inline rgb_t rasterizer_texture::lookup_single_texel(u32 format, u32 texbase, s32 s, s32 t) +{ + if (format < 8) + return m_lookup[*(u8 *)&m_ram[(texbase + t + s) & m_mask]]; + else if (format >= 10 && format <= 12) + return m_lookup[*(u16 *)&m_ram[(texbase + 2*(t + s)) & m_mask]]; + else + { + u32 texel = *(u16 *)&m_ram[(texbase + 2*(t + s)) & m_mask]; + return (m_lookup[texel & 0xff] & 0xffffff) | ((texel & 0xff00) << 16); + } +} + + +//------------------------------------------------- +// fetch_texel - fetch the texel value based on +// the S,T coordinates and LOD +//------------------------------------------------- + +inline rgbaint_t ATTR_FORCE_INLINE rasterizer_texture::fetch_texel(reg_texture_mode const texmode, dither_helper const &dither, s32 x, const stw_helper &iterstw, s32 lodbase, s32 &lod, u8 bilinear_mask) +{ + lod = lodbase; + + // determine the S/T/LOD values for this texture + s32 s, t; + if (texmode.enable_perspective()) + { + s32 wlog; + iterstw.calc_stow(s, t, wlog); + lod += wlog; + } + else + iterstw.get_st_shiftr(s, t, 14 + 10); + + // clamp W + if (texmode.clamp_neg_w() && iterstw.is_w_neg()) + s = t = 0; + + // clamp the LOD + lod += m_lodbias; + if (texmode.enable_lod_dither()) + lod += dither.raw_4x4(x) << 4; + lod = std::clamp(lod, m_lodmin, m_lodmax); + + // now the LOD is in range; if we don't own this LOD, take the next one + s32 ilod = lod >> 8; + ilod += (~m_lodmask >> ilod) & 1; + + // fetch the texture base + u32 texbase = m_lodoffset[ilod]; + + // compute the maximum s and t values at this LOD + s32 smax = m_wmask >> ilod; + s32 tmax = m_hmask >> ilod; + + // determine whether we are point-sampled or bilinear + rgbaint_t result; + if ((lod == m_lodmin && !texmode.magnification_filter()) || (lod != m_lodmin && !texmode.minification_filter())) + { + // adjust S/T for the LOD and strip off the fractions + ilod += 18 - 10; + s >>= ilod; + t >>= ilod; + + // clamp/wrap S/T if necessary + if (texmode.clamp_s()) + s = std::clamp(s, 0, smax); + if (texmode.clamp_t()) + t = std::clamp(t, 0, tmax); + s &= smax; + t &= tmax; + t *= smax + 1; + + // fetch texel data + result.set(lookup_single_texel(texmode.format(), texbase, s, t)); + } + else + { + // adjust S/T for the LOD and strip off all but the low 8 bits of the fraction + s >>= ilod; + t >>= ilod; + + // also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel + s -= 0x80; + t -= 0x80; + + // extract the fractions + u32 sfrac = s & bilinear_mask; + u32 tfrac = t & bilinear_mask; + + // now toss the rest + s >>= 8; + t >>= 8; + s32 s1 = s + 1; + s32 t1 = t + 1; + + // clamp/wrap S/T if necessary + if (texmode.clamp_s()) + { + if (s < 0) + s = s1 = 0; + else if (s >= smax) + s = s1 = smax; + } + s &= smax; + s1 &= smax; + + if (texmode.clamp_t()) + { + if (t < 0) + t = t1 = 0; + else if (t >= tmax) + t = t1 = tmax; + } + t &= tmax; + t1 &= tmax; + t *= smax + 1; + t1 *= smax + 1; + + // fetch texel data + u32 texel0 = lookup_single_texel(texmode.format(), texbase, s, t); + u32 texel1 = lookup_single_texel(texmode.format(), texbase, s1, t); + u32 texel2 = lookup_single_texel(texmode.format(), texbase, s, t1); + u32 texel3 = lookup_single_texel(texmode.format(), texbase, s1, t1); + result.bilinear_filter_rgbaint(texel0, texel1, texel2, texel3, sfrac, tfrac); + } + return result; +} + + +//------------------------------------------------- +// combine_texture - color combine unit for +// texture pixels +//------------------------------------------------- + +inline rgbaint_t ATTR_FORCE_INLINE rasterizer_texture::combine_texture(reg_texture_mode const texmode, rgbaint_t const &c_local, rgbaint_t const &c_other, s32 lod) +{ + // select zero/other for RGB + rgbaint_t blend_color; + if (texmode.tc_zero_other()) + blend_color.zero(); + else + blend_color.set(c_other); + + // select zero/other for alpha + if (texmode.tca_zero_other()) + blend_color.zero_alpha(); + else + blend_color.merge_alpha16(c_other); + + // subtract local color + if (texmode.tc_sub_clocal() || texmode.tca_sub_clocal()) + { + rgbaint_t sub_val; + + // potentially subtract c_local + if (!texmode.tc_sub_clocal()) + sub_val.zero(); + else + sub_val.set(c_local); + + if (!texmode.tca_sub_clocal()) + sub_val.zero_alpha(); + else + sub_val.merge_alpha16(c_local); + + blend_color.sub(sub_val); + } + + // blend RGB + rgbaint_t blend_factor; + switch (texmode.tc_mselect()) + { + default: // reserved + case 0: // zero + blend_factor.zero(); + break; + + case 1: // c_local + blend_factor.set(c_local); + break; + + case 2: // a_other + blend_factor.set(c_other.select_alpha32()); + break; + + case 3: // a_local + blend_factor.set(c_local.select_alpha32()); + break; + + case 4: // LOD (detail factor) + if (m_detailbias <= lod) + blend_factor.zero(); + else + { + u8 tmp; + tmp = (((m_detailbias - lod) << m_detailscale) >> 8); + if (tmp > m_detailmax) + tmp = m_detailmax; + blend_factor.set_all(tmp); + } + break; + + case 5: // LOD fraction + blend_factor.set_all(lod & 0xff); + break; + } + + // blend alpha + switch (texmode.tca_mselect()) + { + default: // reserved + case 0: // zero + blend_factor.zero_alpha(); + break; + + case 1: // c_local + blend_factor.merge_alpha16(c_local); + break; + + case 2: // a_other + blend_factor.merge_alpha16(c_other); + break; + + case 3: // a_local + blend_factor.merge_alpha16(c_local); + break; + + case 4: // LOD (detail factor) + if (m_detailbias <= lod) + blend_factor.zero_alpha(); + else + { + u8 tmp; + tmp = (((m_detailbias - lod) << m_detailscale) >> 8); + if (tmp > m_detailmax) + tmp = m_detailmax; + blend_factor.set_a16(tmp); + } + break; + + case 5: // LOD fraction + blend_factor.set_a16(lod & 0xff); + break; + } + + // reverse the RGB blend + if (!texmode.tc_reverse_blend()) + blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); + + // reverse the alpha blend + if (!texmode.tca_reverse_blend()) + blend_factor.xor_imm_rgba(0xff, 0, 0, 0); + + blend_factor.add_imm(1); + + // add clocal or alocal to RGB + rgbaint_t add_val; + switch (texmode.tc_add_aclocal()) + { + case 3: // reserved + case 0: // nothing + add_val.zero(); + break; + + case 1: // add c_local + add_val.set(c_local); + break; + + case 2: // add_alocal + add_val.set(c_local.select_alpha32()); + break; + } + + // add clocal or alocal to alpha + if (!texmode.tca_add_aclocal()) + add_val.zero_alpha(); + else + add_val.merge_alpha16(c_local); + + // scale add and clamp + blend_color.scale_add_and_clamp(blend_factor, add_val); + + // invert + if (texmode.tc_invert_output()) + blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); + if (texmode.tca_invert_output()) + blend_color.xor_imm_rgba(0xff, 0, 0, 0); + return blend_color; +} + + + +//************************************************************************** +// RASTERIZER NCC TEXELS +//************************************************************************** + +//------------------------------------------------- +// recompute - constructor +//------------------------------------------------- + +void rasterizer_palette::compute_ncc(u32 const *regs) +{ + // generate all 256 possibilities + u8 const *ybase = reinterpret_cast(regs); + for (int index = 0; index < 256; index++) + { + // start with the intensity + s32 y = ybase[BYTE4_XOR_LE(BIT(index, 4, 4))]; + + // look up the I/Q values + s32 i = regs[4 + BIT(index, 2, 2)]; + s32 q = regs[8 + BIT(index, 0, 2)]; + + // add the coloring + s32 r = std::clamp(y + (s32(i << 5) >> 23) + (s32(q << 5) >> 23), 0, 255); + s32 g = std::clamp(y + (s32(i << 14) >> 23) + (s32(q << 14) >> 23), 0, 255); + s32 b = std::clamp(y + (s32(i << 23) >> 23) + (s32(q << 23) >> 23), 0, 255); + + // fill in the table + m_texel[index] = rgb_t(0xff, r, g, b); + } +} + + + +//************************************************************************** +// VOODOO RENDERER +//************************************************************************** + +//------------------------------------------------- +// voodoo_renderer - constructor +//------------------------------------------------- + +voodoo_renderer::voodoo_renderer(running_machine &machine, u16 tmu_config, const rgb_t *rgb565, voodoo_regs &fbi_regs, voodoo_regs *tmu0_regs, voodoo_regs *tmu1_regs) : + poly_manager(machine), + m_bilinear_mask(0xf0), + m_tmu_config(tmu_config), + m_rowpixels(0), + m_yorigin(0), + m_fbi_reg(fbi_regs), + m_tmu0_reg(tmu0_regs), + m_tmu1_reg(tmu1_regs), + m_rgb565(rgb565), + m_fogdelta_mask(0xff), + m_thread_stats(WORK_MAX_THREADS) +{ + // empty the hash table + std::fill(std::begin(m_raster_hash), std::end(m_raster_hash), nullptr); + + // add all predefined rasterizers + for (static_rasterizer_info const *info = s_predef_raster_table; info->params.generic() != 0xffffffff; info++) + add_rasterizer(info->params, info->mfp, false); + + // create entries for the generic rasterizers as well + rasterizer_params dummy_params; + for (int index = 0; index < std::size(m_generic_rasterizer); index++) + m_generic_rasterizer[index] = add_rasterizer(dummy_params, generic_rasterizer(index), true); +} + + +//------------------------------------------------- +// register_save - register for saving states +//------------------------------------------------- + +void voodoo_renderer::register_save(save_proxy &save) +{ + save.save_item(NAME(m_rowpixels)); + save.save_item(NAME(m_yorigin)); + save.save_item(NAME(m_fogblend)); + save.save_item(NAME(m_fogdelta)); +} + + +//------------------------------------------------- +// alloc_poly - allocate a new poly_data object +// and compute the raster parameters +//------------------------------------------------- + +poly_data &voodoo_renderer::alloc_poly() +{ + // allocate poly data and compute the rasterization parameters + poly_data &poly = object_data_alloc(); + poly.raster.compute(m_fbi_reg, m_tmu0_reg, m_tmu1_reg); + return poly; +} + + +//------------------------------------------------- +// enqueue_fastfill - enqueue a fastfill operation +// using a custom renderer +//------------------------------------------------- + +u32 voodoo_renderer::enqueue_fastfill(poly_data &poly) +{ + // if we're not clearing anything, take no time + auto const fbzmode = poly.raster.fbzmode(); + if (!fbzmode.rgb_buffer_mask() && !fbzmode.aux_buffer_mask()) + return 0; + + // generate a dither pattern if clearing the RGB buffer + if (fbzmode.rgb_buffer_mask()) + { + for (int y = 0; y < 4; y++) + { + dither_helper dither(y, fbzmode); + for (int x = 0; x < 4; x++) + poly.dither[y * 4 + x] = dither.pixel(x, poly.color1); + } + } + + // create a block of 64 identical extents + vertex_t v1(poly.clipleft, poly.cliptop); + vertex_t v2(poly.clipright, poly.clipbottom); + return render_tile<0>(global_cliprect, render_delegate(&voodoo_renderer::rasterizer_fastfill, this), v1, v2); +} + + +//------------------------------------------------- +// enqueue_triangle - enqueue a triangle +//------------------------------------------------- + +u32 voodoo_renderer::enqueue_triangle(poly_data &poly, vertex_t const *vert) +{ + // compute the hash of the raster parameters + u32 fullhash = poly.raster.hash(); + u32 hash = fullhash % RASTER_HASH_SIZE; + + // find the appropriate hash entry + rasterizer_info *prev = nullptr; + rasterizer_info *info; + for (info = m_raster_hash[hash]; info != nullptr; prev = info, info = info->next) + if (info->fullhash == fullhash && info->params == poly.raster) + { + // got it, move us to the head of the list + if (prev != nullptr) + { + prev->next = info->next; + info->next = m_raster_hash[hash]; + m_raster_hash[hash] = info; + } + break; + } + + // determine the index of the generic rasterizer + if (info == nullptr) + { + // add a new one if we're logging usage + if (LOG_RASTERIZERS) + info = add_rasterizer(poly.raster, generic_rasterizer(poly.raster.generic()), true); + else + info = m_generic_rasterizer[poly.raster.generic()]; + } + + // set the info and render the triangle + info->polys++; + poly.info = info; + return render_triangle<0>(global_cliprect, poly.info->callback, vert[0], vert[1], vert[2]); +} + + +//------------------------------------------------- +// stipple_test - test against the stipple +// pattern; the enable flag is not checked here, +// so must be checked by the caller +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::stipple_test(thread_stats_block &threadstats, reg_fbz_mode const fbzmode, s32 x, s32 scry, u32 &stipple) +{ + // rotate mode + if (fbzmode.stipple_pattern() == 0) + { + stipple = (stipple >> 1) | (stipple << 31); + if (s32(stipple) >= 0) + { + threadstats.stipple_count++; + return false; + } + } + + // pattern mode + else + { + int stipple_index = ((scry & 3) << 3) | (~x & 7); + if (BIT(stipple, stipple_index) == 0) + { + threadstats.stipple_count++; + return false; + } + } + return true; +} + + +//------------------------------------------------- +// compute_depthval - compute the value for depth +// according to the configured flags +//------------------------------------------------- + +inline s32 ATTR_FORCE_INLINE voodoo_renderer::compute_depthval(poly_data const &poly, reg_fbz_mode const fbzmode, reg_fbz_colorpath const fbzcp, s32 wfloat, s32 iterz) +{ + s32 result; + if (fbzmode.wbuffer_select()) + { + if (!fbzmode.depth_float_select()) + result = wfloat; + else if ((iterz & 0xf0000000) != 0) + result = 0x0000; + else if ((iterz & 0x0ffff000) == 0) + result = 0xffff; + else + { + int exp = count_leading_zeros_32(iterz) - 4; + return ((exp << 12) | ((iterz >> (15 - exp)) ^ 0x1fff)) + 1; + } + } + else + result = clamped_z(iterz, fbzcp); + + if (fbzmode.enable_depth_bias()) + result = std::clamp(result + s16(poly.zacolor), 0, 0xffff); + + return result; +} + + +//------------------------------------------------- +// depth_test - perform depth testing; the enable +// flag is not checked here, so must be checked by +// the caller +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::depth_test(thread_stats_block &threadstats, poly_data const &poly, reg_fbz_mode const fbzmode, s32 depthdest, s32 depthval) +{ + // the source depth is either the iterated W/Z+bias or a constant value + s32 depthsource = (fbzmode.depth_source_compare() == 0) ? depthval : u16(poly.zacolor); + + // test against the depth buffer + switch (fbzmode.depth_function()) + { + case 0: // depthOP = never + threadstats.zfunc_fail++; + return false; + + case 1: // depthOP = less than + if (depthsource >= depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 2: // depthOP = equal + if (depthsource != depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 3: // depthOP = less than or equal + if (depthsource > depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 4: // depthOP = greater than + if (depthsource <= depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 5: // depthOP = not equal + if (depthsource == depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 6: // depthOP = greater than or equal + if (depthsource < depthdest) + { + threadstats.zfunc_fail++; + return false; + } + break; + + case 7: // depthOP = always + break; + } + return true; +} + + +//------------------------------------------------- +// combine_color - core color combining logic +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::combine_color(rgbaint_t &color, thread_stats_block &threadstats, poly_data const &poly, reg_fbz_colorpath const fbzcp, reg_fbz_mode const fbzmode, rgbaint_t texel, s32 iterz, s64 iterw, rgb_t chromakey) +{ + // compute c_other + rgbaint_t c_other; + switch (fbzcp.cc_rgbselect()) + { + case 0: // iterated RGB + c_other.set(color); + break; + + case 1: // texture RGB + c_other.set(texel); + break; + + case 2: // color1 RGB + c_other.set(poly.color1); + break; + + default: // reserved - voodoo3 LFB RGB + c_other.zero(); + break; + } + + // handle chroma key + if (fbzmode.enable_chromakey()) + if (!chroma_key_test(threadstats, c_other, chromakey)) + return false; + + // compute a_other + switch (fbzcp.cc_aselect()) + { + case 0: // iterated alpha + c_other.merge_alpha16(color); + break; + + case 1: // texture alpha + c_other.merge_alpha16(texel); + break; + + case 2: // color1 alpha + c_other.set_a16(poly.color1.a()); + break; + + default: // reserved - voodoo3 LFB Alpha + c_other.zero_alpha(); + break; + } + + // handle alpha mask + if (fbzmode.enable_alpha_mask()) + if (!alpha_mask_test(threadstats, c_other.get_a())) + return false; + + // compute c_local + rgbaint_t c_local; + if (fbzcp.cc_localselect_override() == 0) + { + if (fbzcp.cc_localselect() == 0) // iterated RGB + c_local.set(color); + else // color0 RGB + c_local.set(poly.color0); + } + else + { + if (!(texel.get_a() & 0x80)) // iterated RGB + c_local.set(color); + else // color0 RGB + c_local.set(poly.color0); + } + + // compute a_local + switch (fbzcp.cca_localselect()) + { + default: + case 0: // iterated alpha + c_local.merge_alpha16(color); + break; + + case 1: // color0 alpha + c_local.set_a16(poly.color0.a()); + break; + + case 2: // clamped iterated Z[27:20] + c_local.set_a16(u8(clamped_z(iterz, fbzcp) >> 8)); + break; + + case 3: // clamped iterated W[39:32] (Voodoo 2 only) + c_local.set_a16(u8(clamped_w(iterw, fbzcp))); + break; + } + + // select zero or c_other + rgbaint_t blend_color; + if (fbzcp.cc_zero_other()) + blend_color.zero(); + else + blend_color.set(c_other); + + // select zero or a_other + if (fbzcp.cca_zero_other()) + blend_color.zero_alpha(); + else + blend_color.merge_alpha16(c_other); + + // subtract a/c_local + if (fbzcp.cc_sub_clocal() || fbzcp.cca_sub_clocal()) + { + rgbaint_t sub_val; + + if (!fbzcp.cc_sub_clocal()) + sub_val.zero(); + else + sub_val.set(c_local); + + if (!fbzcp.cca_sub_clocal()) + sub_val.zero_alpha(); + else + sub_val.merge_alpha16(c_local); + + blend_color.sub(sub_val); + } + + // blend RGB + rgbaint_t blend_factor; + switch (fbzcp.cc_mselect()) + { + default: // reserved + case 0: // 0 + blend_factor.zero(); + break; + + case 1: // c_local + blend_factor.set(c_local); + break; + + case 2: // a_other + blend_factor.set(c_other.select_alpha32()); + break; + + case 3: // a_local + blend_factor.set(c_local.select_alpha32()); + break; + + case 4: // texture alpha + blend_factor.set(texel.select_alpha32()); + break; + + case 5: // texture RGB (Voodoo 2 only) + blend_factor.set(texel); + break; + } + + // blend alpha + switch (fbzcp.cca_mselect()) + { + default: // reserved + case 0: // 0 + blend_factor.zero_alpha(); + break; + + case 1: // a_local + case 3: // a_local + blend_factor.merge_alpha16(c_local); + break; + + case 2: // a_other + blend_factor.merge_alpha16(c_other); + break; + + case 4: // texture alpha + blend_factor.merge_alpha16(texel); + break; + } + + // reverse the RGB blend + if (!fbzcp.cc_reverse_blend()) + blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); + + // reverse the alpha blend + if (!fbzcp.cca_reverse_blend()) + blend_factor.xor_imm_rgba(0xff, 0, 0, 0); + + // add clocal or alocal to RGB + rgbaint_t add_val; + switch (fbzcp.cc_add_aclocal()) + { + case 3: // reserved + case 0: // nothing + add_val.zero(); + break; + + case 1: // add c_local + add_val.set(c_local); + break; + + case 2: // add_alocal + add_val.set(c_local.select_alpha32()); + break; + } + + // add clocal or alocal to alpha + if (!fbzcp.cca_add_aclocal()) + add_val.zero_alpha(); + else + add_val.merge_alpha16(c_local); + + // add and clamp + blend_factor.add_imm(1); + blend_color.scale_add_and_clamp(blend_factor, add_val); + + // invert + if (fbzcp.cca_invert_output()) + blend_color.xor_imm_rgba(0xff, 0, 0, 0); + if (fbzcp.cc_invert_output()) + blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); + + color.set(blend_color); + return true; +} + + +//------------------------------------------------- +// alpha_mask_test - perform alpha mask testing; +// the enable flag is not checked here, so must +// be checked by the caller +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::alpha_mask_test(thread_stats_block &threadstats, u32 alpha) +{ + if ((alpha & 1) == 0) + { + threadstats.afunc_fail++; + return false; + } + return true; +} + + +//------------------------------------------------- +// alpha_test - perform alpha testing; the enable +// flag is not checked here, so must be checked +// by the caller +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::alpha_test(thread_stats_block &threadstats, reg_alpha_mode const alphamode, u32 alpha, u32 alpharef) +{ + switch (alphamode.alphafunction()) + { + case 0: // alphaOP = never + threadstats.afunc_fail++; + return false; + + case 1: // alphaOP = less than + if (alpha >= alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 2: // alphaOP = equal + if (alpha != alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 3: // alphaOP = less than or equal + if (alpha > alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 4: // alphaOP = greater than + if (alpha <= alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 5: // alphaOP = not equal + if (alpha == alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 6: // alphaOP = greater than or equal + if (alpha < alpharef) + { + threadstats.afunc_fail++; + return false; + } + break; + + case 7: // alphaOP = always + break; + } + return true; +} + + +//------------------------------------------------- +// chroma_key_test - perform chroma key testing; +// the enable flag is not checked here, so must +// be checked by the caller +//------------------------------------------------- + +inline bool ATTR_FORCE_INLINE voodoo_renderer::chroma_key_test(thread_stats_block &threadstats, rgbaint_t const &colorin, rgb_t chromakey) +{ + rgb_t color = colorin.to_rgba(); + + // non-range version + auto const chromarange = m_fbi_reg.chroma_range(); + if (!chromarange.enable()) + { + if (((color ^ chromakey) & 0xffffff) == 0) + { + threadstats.chroma_fail++; + return false; + } + } + + // tricky range version + else + { + s32 low, high, test; + int results; + + // check blue + low = chromakey.b(); + high = chromarange.blue(); + test = color.b(); + results = (test >= low && test <= high); + results ^= chromarange.blue_exclusive(); + results <<= 1; + + // check green + low = chromakey.g(); + high = chromarange.green(); + test = color.g(); + results |= (test >= low && test <= high); + results ^= chromarange.green_exclusive(); + results <<= 1; + + // check red + low = chromakey.r(); + high = chromarange.red(); + test = color.r(); + results |= (test >= low && test <= high); + results ^= chromarange.red_exclusive(); + + // final result + if (chromarange.union_mode()) + { + if (results != 0) + { + threadstats.chroma_fail++; + return false; + } + } + else + { + if (results == 7) + { + threadstats.chroma_fail++; + return false; + } + } + } + return true; +} + + +//------------------------------------------------- +// apply_fogging - perform fogging; the enable +// flag is not checked here, so must be checked by +// the caller +//------------------------------------------------- + +inline void ATTR_FORCE_INLINE voodoo_renderer::apply_fogging(rgbaint_t &color, poly_data const &poly, reg_fbz_mode const fbzmode, reg_fog_mode const fogmode, reg_fbz_colorpath const fbzcp, s32 x, dither_helper const &dither, s32 wfloat, s32 iterz, s64 iterw, rgbaint_t const &iterargb) +{ + // constant fog bypasses everything else + rgbaint_t fog_color_local(poly.fogcolor); + if (fogmode.fog_constant()) + { + // if fog_mult is 0, we add this to the original color + if (fogmode.fog_mult() == 0) + { + fog_color_local.add(color); + fog_color_local.clamp_to_uint8(); + } + } + + // non-constant fog comes from several sources + else + { + s32 fogblend = 0; + + // if fog_add is zero, we start with the fog color + if (fogmode.fog_add()) + fog_color_local.zero(); + + // if fog_mult is zero, we subtract the incoming color + // Need to check this, manual states 9 bits + if (!fogmode.fog_mult()) + fog_color_local.sub(color); + + // fog blending mode + switch (fogmode.fog_zalpha()) + { + case 0: // fog table + { + s32 fog_depth = wfloat; + + // add the bias for fog selection + if (fbzmode.enable_depth_bias()) + fog_depth = std::clamp(fog_depth + s16(poly.zacolor), 0, 0xffff); + + // perform the multiply against lower 8 bits of wfloat + s32 delta = m_fogdelta[fog_depth >> 10]; + s32 deltaval = (delta & m_fogdelta_mask) * ((fog_depth >> 2) & 0xff); + + // fog zones allow for negating this value + if (fogmode.fog_zones() && (delta & 2)) + deltaval = -deltaval; + deltaval >>= 6; + + // apply dither + if (fogmode.fog_dither()) + deltaval += dither.raw_4x4(x); + deltaval >>= 4; + + // add to the blending factor + fogblend = m_fogblend[fog_depth >> 10] + deltaval; + break; + } + + case 1: // iterated A + fogblend = iterargb.get_a(); + break; + + case 2: // iterated Z + fogblend = clamped_z(iterz, fbzcp) >> 8; + break; + + case 3: // iterated W - Voodoo 2 only + fogblend = clamped_w(iterw, fbzcp); + break; + } + + // perform the blend + fogblend++; + + // if fog_mult is 0, we add this to the original color + fog_color_local.scale_imm_and_clamp(s16(fogblend)); + if (fogmode.fog_mult() == 0) + { + fog_color_local.add(color); + fog_color_local.clamp_to_uint8(); + } + } + + fog_color_local.merge_alpha16(color); + color.set(fog_color_local); +} + + +//------------------------------------------------- +// alpha_blend - perform alpha blending; the +// enable flag is not checked here, so must be +// checked by the caller +//------------------------------------------------- + +inline void ATTR_FORCE_INLINE voodoo_renderer::alpha_blend(rgbaint_t &color, reg_fbz_mode const fbzmode, reg_alpha_mode const alphamode, s32 x, dither_helper const &dither, int dpix, u16 *depth, rgbaint_t const &prefog) +{ + // extract destination pixel + rgbaint_t dst_color(m_rgb565[dpix]); + int da = 0xff; + if (fbzmode.enable_alpha_planes()) + dst_color.set_a16(da = depth[x]); + + // apply dither subtraction + if (fbzmode.alpha_dither_subtract()) + { + int dith = dither.subtract(x); + dst_color.add_imm_rgba(0, dith, dith >> 1, dith); + } + + // compute source portion + int sa = color.get_a(); + int ta; + rgbaint_t src_scale; + switch (alphamode.srcrgbblend()) + { + default: // reserved + case 0: // AZERO + src_scale.zero(); + break; + + case 1: // ASRC_ALPHA + ta = sa + 1; + src_scale.set_all(ta); + break; + + case 2: // A_COLOR + src_scale = dst_color; + src_scale.add_imm(1); + break; + + case 3: // ADST_ALPHA + ta = da + 1; + src_scale.set_all(ta); + break; + + case 4: // AONE + src_scale.set_all(256); + break; + + case 5: // AOMSRC_ALPHA + ta = 0x100 - sa; + src_scale.set_all(ta); + break; + + case 6: // AOM_COLOR + src_scale.set_all(0x100); + src_scale.sub(dst_color); + break; + + case 7: // AOMDST_ALPHA + ta = 0x100 - da; + src_scale.set_all(ta); + break; + + case 15: // ASATURATE + ta = 0x100 - da; + if (sa < ta) + ta = sa; + ta++; + src_scale.set_all(ta); + break; + } + + // set src_scale alpha + int src_alpha_scale = (alphamode.srcalphablend() == 4) ? 256 : 0; + src_scale.set_a16(src_alpha_scale); + + // add in dest portion + rgbaint_t dst_scale; + switch (alphamode.dstrgbblend()) + { + default: // reserved + case 0: // AZERO + dst_scale.zero(); + break; + + case 1: // ASRC_ALPHA + ta = sa + 1; + dst_scale.set_all(ta); + break; + + case 2: // A_COLOR + dst_scale.set(color); + dst_scale.add_imm(1); + break; + + case 3: // ADST_ALPHA + ta = da + 1; + dst_scale.set_all(ta); + break; + + case 4: // AONE + dst_scale.set_all(256); + break; + + case 5: // AOMSRC_ALPHA + ta = 0x100 - sa; + dst_scale.set_all(ta); + break; + + case 6: // AOM_COLOR + dst_scale.set_all(0x100); + dst_scale.sub(color); + break; + + case 7: // AOMDST_ALPHA + ta = 0x100 - da; + dst_scale.set_all(ta); + break; + + case 15: // A_COLORBEFOREFOG + dst_scale.set(prefog); + dst_scale.add_imm(1); + break; + } + + // set dst_scale alpha + int dest_alpha_scale = (alphamode.dstalphablend() == 4) ? 256 : 0; + dst_scale.set_a16(dest_alpha_scale); + + // main blend + color.scale2_add_and_clamp(src_scale, dst_color, dst_scale); +} + + +//------------------------------------------------- +// write_pixel - write the pixel to the +// destination buffer, and the depth to the depth +// buffer +//------------------------------------------------- + +inline void ATTR_FORCE_INLINE voodoo_renderer::write_pixel(thread_stats_block &threadstats, reg_fbz_mode const fbzmode, dither_helper const &dither, u16 *destbase, u16 *depthbase, s32 x, rgbaint_t const &color, s32 depthval) +{ + // write to framebuffer + if (fbzmode.rgb_buffer_mask()) + destbase[x] = dither.pixel(x, color); + + // write to aux buffer + if (fbzmode.aux_buffer_mask()) + { + if (fbzmode.enable_alpha_planes() == 0) + depthbase[x] = depthval; + else + depthbase[x] = color.get_a(); + } + + // track pixel writes to the frame buffer regardless of mask + threadstats.pixels_out++; +} + + +//------------------------------------------------- +// pixel_pipeline - run a pixel through the +// pipeline +//------------------------------------------------- + +void voodoo_renderer::pixel_pipeline(thread_stats_block &threadstats, poly_data const &poly, reg_lfb_mode const lfbmode, s32 x, s32 scry, rgb_t src_color, u16 sz) +{ + auto const fbzcp = poly.raster.fbzcp(); + auto const alphamode = poly.raster.alphamode(); + auto const fbzmode = poly.raster.fbzmode(); + auto const fogmode = poly.raster.fogmode(); + dither_helper dither(scry, fbzmode, fogmode); + u16 *depth = poly.depthbase; + u16 *dest = poly.destbase; + u32 stipple = poly.stipple; + + threadstats.pixels_in++; + + // apply clipping + if (fbzmode.enable_clipping()) + { + if (x < poly.clipleft || x >= poly.clipright || scry < poly.cliptop || scry >= poly.clipbottom) + { + threadstats.clip_fail++; + return; + } + } + + // handle stippling + if (fbzmode.enable_stipple() && !stipple_test(threadstats, fbzmode, x, scry, stipple)) + return; + + // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used + s32 depthval = u32(sz); + + // Perform depth testing + if (fbzmode.enable_depthbuf() && !depth_test(threadstats, poly, fbzmode, depth[x], depthval)) + return; + + // use the RGBA we stashed above + rgbaint_t color(src_color); + + // handle chroma key + if (fbzmode.enable_chromakey() && !chroma_key_test(threadstats, color, poly.chromakey)) + return; + + // handle alpha mask + if (fbzmode.enable_alpha_mask() && !alpha_mask_test(threadstats, color.get_a())) + return; + + // handle alpha test + if (alphamode.alphatest() && !alpha_test(threadstats, alphamode, color.get_a(), poly.alpharef)) + return; + + // perform fogging + rgbaint_t prefog(color); + if (fogmode.enable_fog()) + { + s32 iterz = sz << 12; + s64 iterw = lfbmode.write_w_select() ? u32(poly.zacolor << 16) : u32(sz << 16); + apply_fogging(color, poly, fbzmode, fogmode, fbzcp, x, dither, depthval, iterz, iterw, rgbaint_t(0)); + } + + // wait for any outstanding work to finish + wait("LFB Write"); + + // perform alpha blending + if (alphamode.alphablend()) + alpha_blend(color, fbzmode, alphamode, x, dither, dest[x], depth, prefog); + + // pixel pipeline part 2 handles final output + write_pixel(threadstats, fbzmode, dither, dest, depth, x, color, depthval); +} + + +//------------------------------------------------- +// rasterizer - core scanline rasterizer +//------------------------------------------------- + +template +void voodoo_renderer::rasterizer(s32 y, const voodoo_renderer::extent_t &extent, const poly_data &poly, int threadid) +{ + thread_stats_block &threadstats = m_thread_stats[threadid]; + reg_texture_mode const texmode0(TexMode0, (GenericFlags & rasterizer_params::GENERIC_TEX0) ? poly.raster.texmode0() : 0); + reg_texture_mode const texmode1(TexMode1, (GenericFlags & rasterizer_params::GENERIC_TEX1) ? poly.raster.texmode1() : 0); + reg_fbz_colorpath const fbzcp(FbzCp, poly.raster.fbzcp()); + reg_alpha_mode const alphamode(AlphaMode, poly.raster.alphamode()); + reg_fbz_mode const fbzmode(FbzMode, poly.raster.fbzmode()); + reg_fog_mode const fogmode(FogMode, poly.raster.fogmode()); + stw_helper iterstw0, iterstw1; + stw_helper deltastw0, deltastw1; + u32 stipple = poly.stipple; + + // determine the screen Y + s32 scry = y; + if (fbzmode.y_origin()) + scry = m_yorigin - y; + + // pre-increment the pixels_in unconditionally + s32 startx = extent.startx; + s32 stopx = extent.stopx; + threadstats.pixels_in += stopx - startx; + + // apply clipping + if (fbzmode.enable_clipping()) + { + // Y clipping buys us the whole scanline + if (scry < poly.cliptop || scry >= poly.clipbottom) + { + threadstats.clip_fail += stopx - startx; + return; + } + + // X clipping + s32 tempclip = poly.clipright; + + // check for start outsize of clipping boundary + if (startx >= tempclip) + { + threadstats.clip_fail += stopx - startx; + return; + } + + // clip the right side + if (stopx > tempclip) + { + threadstats.clip_fail += stopx - tempclip; + stopx = tempclip; + } + + // clip the left side + tempclip = poly.clipleft; + if (startx < tempclip) + { + threadstats.clip_fail += tempclip - startx; + startx = tempclip; + } + } + + // get pointers to the target buffer and depth buffer + u16 *dest = poly.destbase + scry * m_rowpixels; + u16 *depth = poly.depthbase + scry * m_rowpixels; + + // compute the starting parameters + s32 dx = startx - (poly.ax >> 4); + s32 dy = y - (poly.ay >> 4); + s32 iterr = (poly.startr + dy * poly.drdy + dx * poly.drdx) << 8; + s32 iterg = (poly.startg + dy * poly.dgdy + dx * poly.dgdx) << 8; + s32 iterb = (poly.startb + dy * poly.dbdy + dx * poly.dbdx) << 8; + s32 itera = (poly.starta + dy * poly.dady + dx * poly.dadx) << 8; + + rgbaint_t iterargb, iterargb_delta; + iterargb.set(itera, iterr, iterg, iterb); + iterargb_delta.set(poly.dadx, poly.drdx, poly.dgdx, poly.dbdx); + iterargb_delta.shl_imm(8); + s32 iterz = poly.startz + dy * poly.dzdy + dx * poly.dzdx; + s64 iterw = (poly.startw + dy * poly.dwdy + dx * poly.dwdx) << 16; + s64 iterw_delta = poly.dwdx << 16; + s32 lodbase0 = 0; + if (GenericFlags & rasterizer_params::GENERIC_TEX0) + { + iterstw0.set( + poly.starts0 + dy * poly.ds0dy + dx * poly.ds0dx, + poly.startt0 + dy * poly.dt0dy + dx * poly.dt0dx, + poly.startw0 + dy * poly.dw0dy + dx * poly.dw0dx); + deltastw0.set(poly.ds0dx, poly.dt0dx, poly.dw0dx); + lodbase0 = compute_lodbase(poly.ds0dx, poly.ds0dy, poly.dt0dx, poly.dt0dy); + } + s32 lodbase1 = 0; + if (GenericFlags & rasterizer_params::GENERIC_TEX1) + { + iterstw1.set( + poly.starts1 + dy * poly.ds1dy + dx * poly.ds1dx, + poly.startt1 + dy * poly.dt1dy + dx * poly.dt1dx, + poly.startw1 + dy * poly.dw1dy + dx * poly.dw1dx); + deltastw1.set(poly.ds1dx, poly.dt1dx, poly.dw1dx); + lodbase1 = compute_lodbase(poly.ds1dx, poly.ds1dy, poly.dt1dx, poly.dt1dy); + } + poly.info->scanlines++; + + // loop in X + dither_helper dither(scry, fbzmode, fogmode); + for (s32 x = startx; x < stopx; x++) + { + do + { + // handle stippling + if (fbzmode.enable_stipple() && !stipple_test(threadstats, fbzmode, x, scry, stipple)) + break; + + // compute "floating point" W value (used for depth and fog) + s32 wfloat = compute_wfloat(iterw); + + // compute depth value (W or Z) for this pixel + s32 depthval = compute_depthval(poly, fbzmode, fbzcp, wfloat, iterz); + + // depth testing + if (fbzmode.enable_depthbuf() && !depth_test(threadstats, poly, fbzmode, depth[x], depthval)) + break; + + // run the texture pipeline on TMU1 to produce a value in texel + rgbaint_t texel(0); + if (GenericFlags & rasterizer_params::GENERIC_TEX1) + { + s32 lod1; + rgbaint_t texel_t1 = poly.tex1->fetch_texel(texmode1, dither, x, iterstw1, lodbase1, lod1, m_bilinear_mask); + if (GenericFlags & rasterizer_params::GENERIC_TEX1_IDENTITY) + texel = texel_t1; + else + texel = poly.tex1->combine_texture(texmode1, texel_t1, texel, lod1); + } + + // run the texture pipeline on TMU0 to produce a final result in texel + if (GenericFlags & rasterizer_params::GENERIC_TEX0) + { + // the seq_8_downld flag is repurposed in the rasterizer to indicate + // we should send the configuration byte + if (!texmode0.seq_8_downld()) + { + s32 lod0; + rgbaint_t texel_t0 = poly.tex0->fetch_texel(texmode0, dither, x, iterstw0, lodbase0, lod0, m_bilinear_mask); + if (GenericFlags & rasterizer_params::GENERIC_TEX0_IDENTITY) + texel = texel_t0; + else + texel = poly.tex0->combine_texture(texmode0, texel_t0, texel, lod0); + } + else + texel.set(m_tmu_config); + } + + // colorpath pipeline selects source colors and does blending + rgbaint_t color = clamped_argb(iterargb, fbzcp); + if (!combine_color(color, threadstats, poly, fbzcp, fbzmode, texel, iterz, iterw, poly.chromakey)) + break; + + // handle alpha test + if (alphamode.alphatest() && !alpha_test(threadstats, alphamode, color.get_a(), poly.alpharef)) + break; + + // perform fogging + rgbaint_t prefog(color); + if (fogmode.enable_fog()) + apply_fogging(color, poly, fbzmode, fogmode, fbzcp, x, dither, wfloat, iterz, iterw, iterargb); + + // perform alpha blending + if (alphamode.alphablend()) + alpha_blend(color, fbzmode, alphamode, x, dither, dest[x], depth, prefog); + + // store the pixel and depth value + write_pixel(threadstats, fbzmode, dither, dest, depth, x, color, depthval); + } while (0); + + // update the iterated parameters + iterargb += iterargb_delta; + iterz += poly.dzdx; + iterw += iterw_delta; + if (GenericFlags & rasterizer_params::GENERIC_TEX0) + iterstw0.add(deltastw0); + if (GenericFlags & rasterizer_params::GENERIC_TEX1) + iterstw1.add(deltastw1); + } +} + + +//------------------------------------------------- +// rasterizer_fastfill - custom scanline +// rasterizer for fastfill operations +//------------------------------------------------- + +void voodoo_renderer::rasterizer_fastfill(s32 y, const voodoo_renderer::extent_t &extent, const poly_data &poly, int threadid) +{ + thread_stats_block &threadstats = m_thread_stats[threadid]; + auto const fbzmode = poly.raster.fbzmode(); + s32 startx = extent.startx; + s32 stopx = extent.stopx; + int x; + + // determine the screen Y + s32 scry = y; + if (fbzmode.y_origin()) + scry = m_yorigin - y; + + // fill this RGB row + if (fbzmode.rgb_buffer_mask()) + { + const u16 *ditherow = &poly.dither[(y & 3) * 4]; + u64 expanded = *(u64 *)ditherow; + u16 *dest = poly.destbase + scry * m_rowpixels; + + for (x = startx; x < stopx && (x & 3) != 0; x++) + dest[x] = ditherow[x & 3]; + for ( ; x < (stopx & ~3); x += 4) + *(u64 *)&dest[x] = expanded; + for ( ; x < stopx; x++) + dest[x] = ditherow[x & 3]; + threadstats.pixels_out += stopx - startx; + } + + // fill this dest buffer row + if (fbzmode.aux_buffer_mask() && poly.depthbase != nullptr) + { + u16 depth = poly.zacolor; + u64 expanded = (u64(depth) << 48) | (u64(depth) << 32) | (u64(depth) << 16) | u64(depth); + u16 *dest = poly.depthbase + scry * m_rowpixels; + + for (x = startx; x < stopx && (x & 3) != 0; x++) + dest[x] = depth; + for ( ; x < (stopx & ~3); x += 4) + *(u64 *)&dest[x] = expanded; + for ( ; x < stopx; x++) + dest[x] = depth; + } +} + + +//------------------------------------------------- +// generic_rasterizer - return a pointer to a +// generic rasterizer based on a texture enable +// mask +//------------------------------------------------- + +voodoo_renderer::rasterizer_mfp voodoo_renderer::generic_rasterizer(u8 texmask) +{ + switch (texmask & 15) + { + default: + case 0: + return &voodoo_renderer::rasterizer<0, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; + case 1: + return &voodoo_renderer::rasterizer<1, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; + case 2: + return &voodoo_renderer::rasterizer<2, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; + case 3: + return &voodoo_renderer::rasterizer<3, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; + case 4: + return &voodoo_renderer::rasterizer<4, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; + case 5: + return &voodoo_renderer::rasterizer<5, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; + case 6: + return &voodoo_renderer::rasterizer<6, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; + case 7: + return &voodoo_renderer::rasterizer<7, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; + case 8: + return &voodoo_renderer::rasterizer<8, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; + case 9: + return &voodoo_renderer::rasterizer<9, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; + case 10: + return &voodoo_renderer::rasterizer<10, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; + case 11: + return &voodoo_renderer::rasterizer<11, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; + case 12: + return &voodoo_renderer::rasterizer<12, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; + case 13: + return &voodoo_renderer::rasterizer<13, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; + case 14: + return &voodoo_renderer::rasterizer<14, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; + case 15: + return &voodoo_renderer::rasterizer<15, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; + } +} + + +//------------------------------------------------- +// add_rasterizer - add a rasterizer to our +// hash table +//------------------------------------------------- + +rasterizer_info *voodoo_renderer::add_rasterizer(rasterizer_params const ¶ms, rasterizer_mfp rasterizer, bool is_generic) +{ + rasterizer_info &info = m_rasterizer_list.emplace_back(); + + // fill in the data + info.next = nullptr; + info.callback = voodoo_renderer::render_delegate(rasterizer, this); + info.display = 0; + info.is_generic = is_generic; + info.scanlines = 0; + info.polys = 0; + info.fullhash = params.hash(); + info.params = params; + + // hook us into the hash table + u32 hash = info.fullhash % RASTER_HASH_SIZE; + if (!is_generic || LOG_RASTERIZERS) + { + info.next = m_raster_hash[hash]; + m_raster_hash[hash] = &info; + } + + if (LOG_RASTERIZERS && params.fbzcp().raw() != 0) + { + osd_printf_info("Adding rasterizer : gen=%02X cp=%08X am=%08X fog=%08X fbz=%08X tm0=%08X tm1=%08X (hash=%d)\n", + params.generic(), params.fbzcp().raw(), params.alphamode().raw(), params.fogmode().raw(), params.fbzmode().raw(), + params.texmode0().raw(), params.texmode1().raw(), hash); + + // explicitly recompute the equations since static rasterizers don't have them + rasterizer_params computed(params); + computed.compute_equations(); + osd_printf_info(" Color: %s\n", computed.colorpath_equation().as_string().c_str()); + if (computed.generic() & rasterizer_params::GENERIC_TEX0) + { + if (computed.generic() & rasterizer_params::GENERIC_TEX0_IDENTITY) + osd_printf_info(" Tex0: Identity\n"); + else + osd_printf_info(" Tex0: %s\n", computed.tex0_equation().as_string().c_str()); + } + if (computed.generic() & rasterizer_params::GENERIC_TEX1) + { + if (computed.generic() & rasterizer_params::GENERIC_TEX1_IDENTITY) + osd_printf_info(" Tex1: Identity\n"); + else + osd_printf_info(" Tex1: %s\n", computed.tex1_equation().as_string().c_str()); + } + } + return &info; +} + + +//------------------------------------------------- +// dump_rasterizer_stats - dump statistics on +// the current rasterizer usage patterns +//------------------------------------------------- + +void voodoo_renderer::dump_rasterizer_stats() +{ + if (!LOG_RASTERIZERS) + return; + + static u8 display_index; + rasterizer_info *cur, *best; + int hash; + + osd_printf_info("----\n"); + display_index++; + + // loop until we've displayed everything + while (1) + { + best = nullptr; + + // find the highest entry + for (hash = 0; hash < RASTER_HASH_SIZE; hash++) + for (cur = m_raster_hash[hash]; cur != nullptr; cur = cur->next) + if (cur->display != display_index && (best == nullptr || cur->scanlines > best->scanlines)) + best = cur; + + // if we're done, we're done + if (best == nullptr || best->scanlines == 0) + break; + + // print it + osd_printf_info("%s RASTERIZER( 0x%02X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) // %8d %10d\n", + best->is_generic ? " " : "// ", + best->params.generic(), + best->params.fbzcp().raw(), + best->params.alphamode().raw(), + best->params.fogmode().raw(), + best->params.fbzmode().raw(), + best->params.texmode0().raw(), + best->params.texmode1().raw(), + best->polys, + best->scanlines); + + // reset + best->display = display_index; + } +} + + +//------------------------------------------------- +// reset_after_wait - handle a reset after a +// wait operation by resetting our allocated +// object queues +//------------------------------------------------- + +void voodoo_renderer::reset_after_wait() +{ + m_textures.reset(); + m_palettes.reset(); +} + + +//************************************************************************** +// GAME-SPECIFIC RASTERIZERS +//************************************************************************** + +#define RASTERIZER(generic, fbzcp, alpha, fog, fbz, tex0, tex1) \ + { &voodoo_renderer::rasterizer, rasterizer_params(generic, fbzcp, alpha, fog, fbz, tex0, tex1) }, + +static_rasterizer_info s_predef_raster_table[] = +{ + // wg3dh + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 3286099 20381549 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000009F, 0xFFFFFFFF ) // 2489030 17200373 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 3014599 13488668 +// RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 698012 11525474 +// RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x00000ADF, 0xFFFFFFFF ) // 119292 6768046 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 218912 6316948 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000089F, 0xFFFFFFFF ) // 176840 6033269 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000005F, 0xFFFFFFFF ) // 272493 1528924 + RASTERIZER( 0x05, 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 11590 1026235 + + // mace + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 6375980 96752762 + RASTERIZER( 0x05, 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 877666 12853963 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 537316 12467938 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 674113 11249705 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 371317 9571618 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000008F, 0xFFFFFFFF ) // 682233 9124733 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x000000CF, 0xFFFFFFFF ) // 498471 8420845 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 90032 5376303 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0000080F, 0xFFFFFFFF ) // 107465 5176593 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x00000ADF, 0xFFFFFFFF ) // 13184 5007304 + + // sfrush + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000001F ) // 1355672 19357520 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 1297788 14089416 + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000081F ) // 607380 12402671 + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000001F ) // 665621 10647858 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 714734 10358977 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 708263 9010666 + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000081F ) // 187026 4932870 + RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0xFFFFFFFF, 0x000000DF ) // 45383 4310253 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 308972 3302296 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0000001F, 0xFFFFFFFF ) // 285502 2946170 + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0000001F ) // 443667 2634580 +// RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 112446 2477427 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 195197 2339499 + RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0000001F ) // 365543 2303916 + + // sfrushrk +// RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000001F ) // 1419527 23908786 +// RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 963906 14481970 + RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0xFFFFFFFF, 0x0000001F ) // 174421 10184608 +// RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000081F ) // 384547 7885615 +// RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 244858 4208409 + RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 206798 3960712 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 153642 3621111 +// RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 108089 3590760 +// RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 219585 2909829 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0000001F, 0xFFFFFFFF ) // 187042 2805524 + RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0xFFFFFFFF, 0x000000DF ) // 25554 2515514 + + // calspeed + RASTERIZER( 0x05, 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 4701502 50735847 + RASTERIZER( 0x05, 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0000000F, 0xFFFFFFFF ) // 1634191 24047354 + RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0000080F, 0xFFFFFFFF ) // 742857 14056518 + RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 1299926 12893822 + RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0000080F, 0xFFFFFFFF ) // 543774 11318818 + RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0000000F, 0xFFFFFFFF ) // 40320 5118555 + RASTERIZER( 0x05, 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 227824 3146670 + RASTERIZER( 0x05, 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 35644 2681027 + RASTERIZER( 0x00, 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) // 24976 2363490 + RASTERIZER( 0x05, 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0000080F, 0xFFFFFFFF ) // 28316 2004570 + + // vaportrx + RASTERIZER( 0x05, 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 1446198 21480806 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x000000CF, 0xFFFFFFFF ) // 1707856 9876920 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x000000C9, 0xFFFFFFFF ) // 739894 9863144 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x00000ACF, 0xFFFFFFFF ) // 460944 9848421 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x00000ACF, 0xFFFFFFFF ) // 219658 4982710 + RASTERIZER( 0x05, 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 268313 4748332 + RASTERIZER( 0x05, 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 283627 3457853 + RASTERIZER( 0x05, 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 34206 2494986 + RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 153391 2048929 + + // blitz + RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5465143 29568854 + RASTERIZER( 0x05, 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 671263 19501211 + RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 239790 17412073 + RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 1174048 13394869 + RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 781255 6391702 + RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 47802 3412779 + RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 79490 3088491 + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 15232 2566323 + RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 177716 2320638 + RASTERIZER( 0x05, 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18686 1741744 + + // blitz99 + RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5757356 35675229 +// RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 270977 16139833 +// RASTERIZER( 0x05, 0x00002C35, 0x64515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 869068 7819874 +// RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 57874 5309214 +// RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 380688 4597915 +// RASTERIZER( 0x05, 0x00006136, 0x40515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18141 2099641 +// RASTERIZER( 0x05, 0x00002C35, 0x40515119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 92655 1928223 +// RASTERIZER( 0x05, 0x00002C35, 0x40515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 131380 1908198 +// RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 86764 1760469 + RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 189197 1504639 + + // blitz2k +// RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5486749 33668808 +// RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 275360 15899691 +// RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 801050 7476260 +// RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 461364 5981963 +// RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 93786 5079967 + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x00000ACF, 0xFFFFFFFF ) // 16252 2943314 + RASTERIZER( 0x05, 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 200589 2563939 +// RASTERIZER( 0x05, 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18221 2335412 +// RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 90486 2212467 + + // carnevil + RASTERIZER( 0x05, 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x00000A0F, 0xFFFFFFFF ) // 420627 4298755 + RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0000080F, 0xFFFFFFFF ) // 112660 2916676 + RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 36468 735846 + RASTERIZER( 0x05, 0x00000035, 0x08045119, 0x00000000, 0x000306F9, 0x00000AC9, 0xFFFFFFFF ) // 6996 212717 + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x00000A0F, 0xFFFFFFFF ) // 754 190433 + + // hyprdriv + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 146568 18142019 + RASTERIZER( 0x05, 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x00000A0F, 0xFFFFFFFF ) // 771521 12744098 + RASTERIZER( 0x05, 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x00000AC9, 0xFFFFFFFF ) // 997666 12173827 + RASTERIZER( 0x00, 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) // 2064812 11818083 + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 67518 8476957 + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x00000A0F, 0xFFFFFFFF ) // 3404038 8059738 + RASTERIZER( 0x00, 0x0142611A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) // 797160 3625519 + RASTERIZER( 0x05, 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x00000A1F, 0xFFFFFFFF ) // 154937 3337816 + RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 19770 2887063 + RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0000000F, 0xFFFFFFFF ) // 392772 2654749 + RASTERIZER( 0x05, 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0000001F, 0xFFFFFFFF ) // 101694 2333476 + RASTERIZER( 0x05, 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x00000A1F, 0xFFFFFFFF ) // 152748 2258208 + RASTERIZER( 0x05, 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0000001F, 0xFFFFFFFF ) // 164822 2100196 + + // gauntleg + RASTERIZER( 0x0B, 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 1846512 77235960 + RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 1733863 14067084 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0000004F, 0xFFFFFFFF ) // 1517970 13213493 +// RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2449825 12337057 + RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000000F ) // 193539 10327282 + RASTERIZER( 0x0B, 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 173388 5900312 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000004F ) // 272048 5557244 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x00000A4F ) // 38452 4404158 + RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000080F ) // 93156 4365283 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000A4F, 0xFFFFFFFF ) // 51416 3857019 + RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 220103 2783489 + + // gauntdl + RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 4613022 100488623 + RASTERIZER( 0x0B, 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 2989550 50643553 + RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 741940 22885885 + RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2843876 16209403 + RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x00000ACF ) // 349018 11700233 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x000000CF, 0xFFFFFFFF ) // 798144 7819799 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x000008CF ) // 217622 7362228 + RASTERIZER( 0x0B, 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0000000F ) // 111605 6859677 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x00000ACF ) // 42994 6006533 + RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 1174759 5414174 + RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0000000F ) // 1358847 5366960 + RASTERIZER( 0x05, 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 1317912 5103516 + + // warfa + RASTERIZER( 0x0B, 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 5549270 83260187 +// RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2450037 34142048 + RASTERIZER( 0x0B, 0x00602419, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000A0F ) // 1406309 22020895 + RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 3121611 13535796 + RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0000000F ) // 3821464 12671381 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x104008CF, 0x000008CF ) // 1045140 10170316 + RASTERIZER( 0x0B, 0x00602439, 0x00044119, 0x000000C1, 0x000B0779, 0x0582480F, 0x0000080F ) // 43674 7349020 +// RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000000F ) // 864570 6795448 + RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0000080F ) // 531132 6584618 + RASTERIZER( 0x0B, 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 169887 6529727 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x10400ACF, 0x000008CF ) // 420204 5602132 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x104000CF, 0x000008CF ) // 306432 4918886 + + // + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 5627690 79723246 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x00000A0F, 0xFFFFFFFF ) // 250480 17957361 + RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0x0000000F ) // 4264955 17065131 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 789463 11602094 + RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x000008CF ) // 452695 11374291 + RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0000080F ) // 2219901 10964372 + RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0000000F ) // 2985476 10576909 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 430488 6729680 + RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x000008CF ) // 317486 5192722 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 551185 3395443 + RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000088F, 0x0000080F ) // 276296 3024329 + + // nbashowt + RASTERIZER( 0x05, 0x00002C35, 0x00045119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 12589303 89992094 + RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 528689 41431369 + RASTERIZER( 0x05, 0x00002C35, 0x00045119, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 4346462 21676464 + RASTERIZER( 0x05, 0x00002C35, 0x00044110, 0x00000000, 0x000A0321, 0x00000A0F, 0xFFFFFFFF ) // 1311258 15990693 + RASTERIZER( 0x05, 0x00582435, 0x00045110, 0x00000000, 0x000B0739, 0x00000AC9, 0xFFFFFFFF ) // 498752 8603534 +// RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 262625 8248367 + RASTERIZER( 0x05, 0x00582C35, 0x00045110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 146310 7881711 + RASTERIZER( 0x05, 0x01424039, 0x00045110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 353983 6698613 + RASTERIZER( 0x05, 0x01422439, 0x00044119, 0x00000000, 0x000A0321, 0x00000A0F, 0xFFFFFFFF ) // 105456 5867982 + + // sf2049 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 4535144 87108835 + RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x000008CF, 0xFFFFFFFF ) // 3460768 36622999 + RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x000000CF, 0xFFFFFFFF ) // 1167220 12527933 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 294802 12127575 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000088F, 0xFFFFFFFF ) // 192929 11588013 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 322059 10421128 + RASTERIZER( 0x03, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0A452A0F, 0x0E47200F ) // 1449341 8868943 + RASTERIZER( 0x05, 0x00482435, 0x00045117, 0x000000C1, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 874920 7250149 + RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x000000C1, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 874920 6973439 + RASTERIZER( 0x05, 0x00602401, 0x00045119, 0x000000C1, 0x00030279, 0x00000A0F, 0xFFFFFFFF ) // 453774 6485154 + RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x00000A0F, 0xFFFFFFFF ) // 220733 5697617 + RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0000000F, 0xFFFFFFFF ) // 348786 4416017 + + // cartfury + RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x000000C1, 0x00030F39, 0x00000A0F, 0xFFFFFFFF ) // 3719502 47429534 + RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x000000C1, 0x00030F39, 0x0000000F, 0xFFFFFFFF ) // 4821876 25433268 + RASTERIZER( 0x05, 0x0142A409, 0x00000000, 0x000000C1, 0x00030F3B, 0x00000ACF, 0xFFFFFFFF ) // 1704143 16287730 + RASTERIZER( 0x05, 0x00580035, 0x00045119, 0x000000C1, 0x00030B39, 0x00000A0F, 0xFFFFFFFF ) // 576134 13181152 + RASTERIZER( 0x05, 0x0142A409, 0x00000000, 0x00000000, 0x00030B39, 0x00000A0F, 0xFFFFFFFF ) // 2447036 13056499 + RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x00000000, 0x00030F39, 0x00000A0F, 0xFFFFFFFF ) // 1597651 11909086 + RASTERIZER( 0x05, 0x00422439, 0x00000000, 0x000000C1, 0x00030F3B, 0x00000A0F, 0xFFFFFFFF ) // 1100912 11879195 + RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x00000000, 0x00030F3B, 0x00000A0F, 0xFFFFFFFF ) // 1714391 11199323 + RASTERIZER( 0x05, 0x00582435, 0x00045110, 0x00000000, 0x00030BF9, 0x000000C9, 0xFFFFFFFF ) // 975518 11030280 + + // gradius4 + RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030BFB, 0x00000AC7, 0xFFFFFFFF ) // 1261361 78858051 + RASTERIZER( 0x05, 0x0000303A, 0x00004119, 0x00000000, 0x00030BFB, 0x000000C7, 0xFFFFFFFF ) // 398143 72518712 + RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x00000A87, 0xFFFFFFFF ) // 1716273 15992169 + RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 812651 15723260 + RASTERIZER( 0x05, 0x00582435, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 595637 13777035 + RASTERIZER( 0x05, 0x00000015, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 675880 12288373 + RASTERIZER( 0x00, 0x02422E12, 0x00005119, 0x00000000, 0x00030F7B, 0xFFFFFFFF, 0xFFFFFFFF ) // 404825 10544497 + RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030FFB, 0x00000AC7, 0xFFFFFFFF ) // 444690 6872107 + RASTERIZER( 0x00, 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0xFFFFFFFF, 0xFFFFFFFF ) // 5455064 5726069 + RASTERIZER( 0x05, 0x00580021, 0x00005119, 0x00000000, 0x00030FFB, 0x00000AC7, 0xFFFFFFFF ) // 242000 5057019 + + // nbapbp + RASTERIZER( 0x05, 0x00426E19, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 2926955 28637513 + RASTERIZER( 0x05, 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 607076 17008880 + RASTERIZER( 0x05, 0x00422809, 0x00004610, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 562460 12415476 + RASTERIZER( 0x05, 0x02004219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC1, 0xFFFFFFFF ) // 79809 7045963 + RASTERIZER( 0x05, 0x02004219, 0x00000000, 0x00000001, 0x00030B7B, 0x00000AC7, 0xFFFFFFFF ) // 94254 6047743 + RASTERIZER( 0x05, 0x00006E19, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 352375 4465810 + RASTERIZER( 0x05, 0x00422A19, 0x00004610, 0x00000001, 0x00030BFB, 0x00000AC7, 0xFFFFFFFF ) // 58835 3500582 + RASTERIZER( 0x05, 0x00004219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 176291 2268659 + RASTERIZER( 0x05, 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x00000AC7, 0xFFFFFFFF ) // 13304 2250402 + + // virtpool + RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 494481 13370166 + RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 45923 3905828 + RASTERIZER( 0x05, 0x00002425, 0x00445110, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 57946 3043998 + RASTERIZER( 0x05, 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 235221 962382 + RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x00000A09, 0xFFFFFFFF ) // 12297 930523 + + // gtfore01 + RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x00000ACD, 0xFFFFFFFF ) // 807566 29151846 + RASTERIZER( 0x0B, 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x00000A0D ) // 2116043 18259224 + RASTERIZER( 0x0B, 0x00002429, 0x00000000, 0x000000C1, 0x00010FF9, 0x00000A09, 0x00000A0F ) // 43784 3594532 + RASTERIZER( 0x0B, 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x00000ACD ) // 14899 1391390 + + { nullptr, rasterizer_params(0xffffffff) } +}; + +} diff --git a/src/devices/video/voodoo_render.h b/src/devices/video/voodoo_render.h new file mode 100644 index 00000000000..de1d03793f9 --- /dev/null +++ b/src/devices/video/voodoo_render.h @@ -0,0 +1,662 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo_render.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#ifndef MAME_VIDEO_VOODOO_RENDER_H +#define MAME_VIDEO_VOODOO_RENDER_H + +#pragma once + +#include "video/poly.h" +#include "video/rgbutil.h" + +// +// To do: +// - split rasterizer into setup (clip/flip) and inner part +// - templatize texture pipeline helpers +// - determine color scale factors up front as start/delta values and use those +// - incorporate type/memory? into constant flags +// - use type for: fog delta mask, bilinear mask +// - multiple rasterizer_textures to save stalls +// - leverage poly clipping? +// + +namespace voodoo +{ + +// forward declarations +struct rasterizer_info; +struct poly_data; +class dither_helper; +class stw_helper; + +// base class for our renderer +using voodoo_poly_manager = poly_manager; + + + +//************************************************************************** +// DITHER HELPER +//************************************************************************** + +// ======================> dither_helper + +// this class provides common code for querying and managing dithering +// effects, which are very particular to the Voodoo +class dither_helper +{ +public: + // constructor to pre-cache based on mode and Y coordinate + dither_helper(int y, reg_fbz_mode const fbzmode, reg_fog_mode const fogmode = reg_fog_mode(0)) : + m_dither_lookup(nullptr), + m_dither_raw(nullptr), + m_dither_raw_4x4(&s_dither_matrix_4x4[(y & 3) * 4]) + { + // still use a lookup for no dithering since it's rare and we + // can avoid yet another conditional on the hot path + if (!fbzmode.enable_dithering()) + m_dither_lookup = &s_nodither_lookup[0]; + else if (fbzmode.dither_type() == 0) + { + m_dither_lookup = &s_dither4_lookup[(y & 3) << 11]; + m_dither_raw = &s_dither_matrix_4x4[(y & 3) * 4]; + } + else + { + m_dither_lookup = &s_dither2_lookup[(y & 3) << 11]; + m_dither_raw = &s_dither_matrix_2x2[(y & 3) * 4]; + } + } + + // apply dithering to a pixel in separate R/G/B format and assemble as 5-6-5 + u16 pixel(s32 x, s32 r, s32 g, s32 b) const + { + u8 const *table = &m_dither_lookup[(x & 3) << 9]; + return (table[r] << 11) | (table[g + 256] << 5) | table[b]; + } + + // apply dithering to a pixel in separate R/G/B format and assemble as 5-6-5 + u16 pixel(s32 x, rgb_t color) const + { + u8 const *table = &m_dither_lookup[(x & 3) << 9]; + return (table[color.r()] << 11) | (table[color.g() + 256] << 5) | table[color.b()]; + } + + // apply dithering to an rgbint_t pixel and assemble as 5-6-5 + u16 pixel(s32 x, rgbaint_t const &color) const + { + u8 const *table = &m_dither_lookup[(x & 3) << 9]; + return (table[color.get_r()] << 11) | (table[color.get_g() + 256] << 5) | table[color.get_b()]; + } + + // return the raw 4x4 dither pattern + u32 raw_4x4(s32 x) const + { + return m_dither_raw_4x4[x & 3]; + } + + // return the subtractive dither value for alpha blending + u32 subtract(s32 x) const + { + return (m_dither_raw != nullptr) ? (15 - (m_dither_raw[x & 3] >> 1)) : 0; + } + + // allocate and initialize static tables + static void init_static(); + +private: + // hardware-verified equation for applying dither to the red/blue components + static constexpr u8 dither_rb(u8 value, u8 dither) + { + return ((value << 1) - (value >> 4) + (value >> 7) + dither) >> (1+3); + } + + // hardware-verified equation for applying dither to the green componenets + static constexpr u8 dither_g(u8 value, u8 dither) + { + return ((value << 2) - (value >> 4) + (value >> 6) + dither) >> (2+2); + } + + // internal state + u8 const *m_dither_lookup; + u8 const *m_dither_raw; + u8 const *m_dither_raw_4x4; + + // static tables + static std::unique_ptr s_dither4_lookup; + static std::unique_ptr s_dither2_lookup; + static std::unique_ptr s_nodither_lookup; + static u8 const s_dither_matrix_4x4[4*4]; + static u8 const s_dither_matrix_2x2[4*4]; +}; + + +// ======================> color_source + +// color_source describes the alpha+RGB components of a color in an +// abstract way +class color_source +{ +public: + // flags + static constexpr u8 FLAG_INVERTED = 0x80; + static constexpr u8 FLAG_ALPHA_EXPANDED = 0x40; + + // constant values (0-3) + static constexpr u8 ZERO = 0; + static constexpr u8 ONE = 1; + static constexpr u8 COLOR0 = 2; + static constexpr u8 COLOR1 = 3; + + // iterated values (4-7) + static constexpr u8 ITERATED_ARGB = 4; + static constexpr u8 CLAMPZ = 5; + static constexpr u8 CLAMPW = 6; + + // dynamic values (8+) + static constexpr u8 TEXEL0 = 8; + static constexpr u8 TEXEL1 = 9; + static constexpr u8 DETAIL_FACTOR = 10; + static constexpr u8 LOD_FRACTION = 11; + static constexpr u8 COLOR0_OR_ITERATED_VIA_TEXEL_ALPHA = 12; + + // constructor + constexpr color_source(u8 alpha = ZERO, u8 rgb = ZERO) : m_alpha(alpha), m_rgb(rgb) { } + + // exact comparisons + bool operator==(color_source const &rhs) const { return m_rgb == rhs.m_rgb && m_alpha == rhs.m_alpha; } + bool operator!=(color_source const &rhs) const { return m_rgb != rhs.m_rgb || m_alpha != rhs.m_alpha; } + + // return the full alpha/RGB value + u8 alpha() const { return m_alpha; } + u8 rgb() const { return m_rgb; } + + // return the base (flag-free) alpha/RGB value + u8 alpha_base() const { return m_alpha & 15; } + u8 rgb_base() const { return m_rgb & 15; } + + // return the alpha/RGB value flags + u8 alpha_flags() const { return m_alpha >> 6; } + u8 rgb_flags() const { return m_rgb >> 6; } + + // helpers + bool is_rgb_zero() const { return m_rgb == ZERO; } + bool is_alpha_zero() const { return m_alpha == ZERO; } + bool is_zero() const { return is_rgb_zero() && is_alpha_zero(); } + bool is_rgb_one() const { return m_rgb == ONE; } + bool is_alpha_one() const { return m_alpha == ONE; } + bool is_one() const { return is_rgb_one() && is_alpha_one(); } + + // uniform is true if RGB and alpha come from the same source + bool is_uniform() const { return (m_alpha == m_rgb); } + + // uniform_alpha is true if RGB and alpha are replication of the same alpha value + bool is_uniform_alpha() const { return ((m_alpha | FLAG_ALPHA_EXPANDED) == m_rgb); } + + // constant is true if both values are constant across a scanline + bool is_rgb_constant() const { return ((m_rgb & 0x0c) == 0x00); } + bool is_alpha_constant() const { return ((m_alpha & 0x0c) == 0x00); } + bool is_constant() const { return is_rgb_constant() && is_alpha_constant(); } + + // partial_constant is true if at least one value is constant across a scanline + bool is_partial_constant() const { return is_rgb_constant() || is_alpha_constant(); } + + // constant_or_iterated is true if values are constant or simply iterated across a scanline + bool is_rgb_constant_or_iterated() const { return ((m_rgb & 0x08) == 0x00); } + bool is_alpha_constant_or_iterated() const { return ((m_alpha & 0x08) == 0x00); } + bool is_constant_or_iterated() const { return is_rgb_constant_or_iterated() && is_alpha_constant_or_iterated(); } + + // uses_any is true if either the RGB or alpha referenecs the given source + bool uses_any(color_source const &src) const { return rgb_base() == src.rgb_base() || alpha_base() == src.alpha_base(); } + + // directly set the alpha/RGB component + void set_alpha(u8 alpha) { m_alpha = alpha; } + void set_rgb(u8 rgb) { m_rgb = rgb; } + + // set the RGB as an expanded single component + void set_rgb_from_alpha(u8 rgb) { m_rgb = rgb | FLAG_ALPHA_EXPANDED; } + + // mark the RGB/alpha component as inverted + void invert_rgb() { m_rgb ^= FLAG_INVERTED; } + void invert_alpha() { m_alpha ^= FLAG_INVERTED; } + + // perform internal simplification + void simplify(); + + // return a string version of the component + std::string as_string() const; + + // constants + static color_source const zero; + static color_source const one; + static color_source const iterated_argb; + static color_source const color0; + static color_source const color1; + static color_source const texel0; + static color_source const texel1; + +private: + // internal state + u8 m_alpha, m_rgb; +}; + + +// ======================> color_equation + +// color_equation describes a set of 4 color sources, intended to be computed +// as clamp((color - sub) * multiply + add) +class color_equation +{ +public: + // construction + constexpr color_equation() { } + + // simple getters + color_source &color() { return m_color; } + color_source &subtract() { return m_subtract; } + color_source &multiply() { return m_multiply; } + color_source &add() { return m_add; } + + // helpers + bool uses_any(color_source color) const { return m_color.uses_any(color) || m_subtract.uses_any(color) || m_multiply.uses_any(color) || m_add.uses_any(color); } + bool is_identity(color_source color) const { return (m_multiply.is_zero() && m_add == color); } + bool is_zero() const { return m_multiply.is_zero() && m_add.is_zero(); } + + // operations + void simplify(); + std::string as_string() const; + + // computation + static color_equation from_fbzcp(reg_fbz_colorpath const fbzcp); + static color_equation from_texmode(reg_texture_mode const texmode, color_source texel_color, color_source input_color); + +private: + // internal state + color_source m_color; + color_source m_subtract; + color_source m_multiply; + color_source m_add; +}; + + +// ======================> rasterizer_params + +// this class holds the representative parameters that characterize a +// specific rasterizer; these are used to index and discover one of +// the special hard-coded rasterizers in voodoo_render.cpp +class rasterizer_params +{ +public: + // generic flags + static constexpr u32 GENERIC_TEX0 = 0x01; + static constexpr u32 GENERIC_TEX1 = 0x02; + static constexpr u32 GENERIC_TEX0_IDENTITY = 0x04; + static constexpr u32 GENERIC_TEX1_IDENTITY = 0x08; + + // construction + constexpr rasterizer_params(u32 generic = 0, u32 fbzcp = 0, u32 alphamode = 0, u32 fogmode = 0, u32 fbzmode = 0, u32 texmode0 = 0, u32 texmode1 = 0) : + m_generic(generic), + m_fbzcp(fbzcp), + m_alphamode(alphamode), + m_fogmode(fogmode), + m_fbzmode(fbzmode), + m_texmode0(texmode0), + m_texmode1(texmode1) { } + + // compare everything directly + bool operator==(rasterizer_params const &rhs) const; + + // compute the parameters given a set of registers + void compute(voodoo_regs ®s, voodoo_regs *tmu0regs = nullptr, voodoo_regs *tmu1regs = nullptr); + void compute_equations(); + + // compute the hash of the settings + u32 hash() const; + + // getters + u32 generic() const { return m_generic; } + reg_fbz_colorpath fbzcp() const { return reg_fbz_colorpath(m_fbzcp); } + reg_alpha_mode alphamode() const { return reg_alpha_mode(m_alphamode); } + reg_fog_mode fogmode() const { return reg_fog_mode(m_fogmode); } + reg_fbz_mode fbzmode() const { return reg_fbz_mode(m_fbzmode); } + reg_texture_mode texmode0() const { return reg_texture_mode(m_texmode0); } + reg_texture_mode texmode1() const { return reg_texture_mode(m_texmode1); } + color_equation const &colorpath_equation() const { return m_color_equation; } + color_equation const &tex0_equation() const { return m_tex0_equation; } + color_equation const &tex1_equation() const { return m_tex1_equation; } + +private: + // internal helpers + static constexpr u32 rotate(u32 value, int count) { return (value << count) | (value >> (32 - count)); } + + // internal state + u32 m_generic; // 4 bits + u32 m_fbzcp; // 30 bits + u32 m_alphamode; // 32 bits + u32 m_fogmode; // 8 bits + u32 m_fbzmode; // 22 bits + u32 m_texmode0; // 31 bits + u32 m_texmode1; // 31 bits + color_equation m_color_equation; + color_equation m_tex0_equation; + color_equation m_tex1_equation; +}; + + +// ======================> rasterizer_texture + +// this class holds TMU-specific decoded data regarding a texture; it is +// encapsulated here, with functions to derive it from register info and +// functions to process it as part of the rendering pipeline +class rasterizer_texture +{ +public: + // recompute internal values based on parameters + void recompute(voodoo_regs const ®s, u8 *ram, u32 mask, rgb_t const *lookup, u32 addrmask, u8 addrshift); + + // look up a texel at the given coordinate + rgb_t lookup_single_texel(u32 format, u32 texbase, s32 s, s32 t); + + // fetch a texel given coordinates and LOD information + rgbaint_t fetch_texel(voodoo::reg_texture_mode const texmode, voodoo::dither_helper const &dither, s32 x, const voodoo::stw_helper &iterstw, s32 lodbase, s32 &lod, u8 bilinear_mask); + + // texture-specific color combination unit + rgbaint_t combine_texture(voodoo::reg_texture_mode const texmode, rgbaint_t const &c_local, rgbaint_t const &c_other, s32 lod); + + // return a write pointer based on the LOD, s/t coordinates, and format + u8 *write_ptr(u32 lod, u32 s, u32 t, u32 scale) const + { + u32 offs = t * ((m_wmask >> lod) + 1) + s; + return m_ram + ((m_lodoffset[lod] + ((scale * offs) & ~3)) & m_mask); + } + +private: + // internal state + rgb_t const *m_lookup; // currently selected lookup + u8 *m_ram; // pointer to base of TMU RAM + u8 m_wmask; // mask for the current texture width + u8 m_hmask; // mask for the current texture height + u8 m_detailscale; // detail scale + s16 m_lodmin; // minimum LOD value + s16 m_lodmax; // maximum LOD value + s16 m_lodbias; // LOD bias + u16 m_lodmask; // mask of available LODs + u32 m_mask; // mask to apply to pointers + s32 m_detailmax; // detail clamp + s32 m_detailbias; // detail bias + u32 m_lodoffset[9]; // offset of texture base for each LOD +}; + + +// ======================> rasterizer_palette + +class rasterizer_palette +{ +public: + // compute from an NCC table + void compute_ncc(u32 const *regs); + + // copy from a table + void copy(rgb_t *texels) { memcpy(&m_texel, texels, sizeof(m_texel)); } + + // simple getters + rgb_t const *texels() const { return &m_texel[0]; } + +private: + // internal state + rgb_t m_texel[256]; +}; + + +// ======================> poly_data + +// this struct contains the polygon-wide shared data used during rendering; +// it is captured here so that further changed can be made to the registers +// without affecting pending operations +struct poly_data +{ + rasterizer_params raster; // normalized rasterizer parameters, for triangles + rasterizer_info *info; // pointer to rasterizer information + u16 *destbase; // destination to write + u16 *depthbase; // depth/aux buffer to write + rasterizer_texture *tex0; // texture 0 information + rasterizer_texture *tex1; // texture 1 information + u16 clipleft, clipright; // x clipping + u16 cliptop, clipbottom; // y clipping + + s16 ax, ay; // vertex A x,y (12.4) + s32 startr, startg, startb, starta; // starting R,G,B,A (12.12) + s32 startz; // starting Z (20.12) + s64 startw; // starting W (16.32) + s32 drdx, dgdx, dbdx, dadx; // delta R,G,B,A per X + s32 dzdx; // delta Z per X + s64 dwdx; // delta W per X + s32 drdy, dgdy, dbdy, dady; // delta R,G,B,A per Y + s32 dzdy; // delta Z per Y + s64 dwdy; // delta W per Y + + s64 starts0, startt0; // starting S,T (14.18) + s64 startw0; // starting W (2.30) + s64 ds0dx, dt0dx; // delta S,T per X + s64 dw0dx; // delta W per X + s64 ds0dy, dt0dy; // delta S,T per Y + s64 dw0dy; // delta W per Y + + s64 starts1, startt1; // starting S,T (14.18) + s64 startw1; // starting W (2.30) + s64 ds1dx, dt1dx; // delta S,T per X + s64 dw1dx; // delta W per X + s64 ds1dy, dt1dy; // delta S,T per Y + s64 dw1dy; // delta W per Y + + rgb_t color0, color1; // colors consumed by the rasterizer + rgb_t chromakey; // chromakey + rgb_t fogcolor; // fogcolor + u32 zacolor; // depth/alpha value consumed by the rasterizer + u32 stipple; // stipple pattern + u32 alpharef; // reference alpha value + + u16 dither[16]; // dither matrix, for fastfill +}; + + +// ======================> rasterizer_info + +// this struct describes a specific rasterizer +struct rasterizer_info +{ + rasterizer_info *next; // pointer to next entry with the same hash + voodoo_poly_manager::render_delegate callback; // callback pointer + u8 is_generic; // is this a generic rasterizer? + u8 display; // display index, used for sorted printing + u32 scanlines; // how many scanlines we've used this for + u32 polys; // how many polys we've used this for + u32 fullhash; // full 32-bit hash + rasterizer_params params; // full copy of the relevant parameters +}; + + +// ======================> thread_stats_block + +// this struct holds a thread-specific chunk of statistics that are combined +// on demand with other threads' data when requested +struct thread_stats_block +{ + void reset() + { + pixels_in = pixels_out = chroma_fail = zfunc_fail = afunc_fail = clip_fail = stipple_count = 0; + } + + s32 pixels_in = 0; // pixels in statistic + s32 pixels_out = 0; // pixels out statistic + s32 chroma_fail = 0; // chroma test fail statistic + s32 zfunc_fail = 0; // z function test fail statistic + s32 afunc_fail = 0; // alpha function test fail statistic + s32 clip_fail = 0; // clipping fail statistic + s32 stipple_count = 0; // stipple statistic + s32 filler[poly_array::CACHE_LINE_SIZE/4 - 7]; // pad this structure to cache line size +}; + + +// ======================> voodoo_renderer + +class voodoo_renderer : public voodoo_poly_manager +{ + static constexpr u32 RASTER_HASH_SIZE = 97; // size of the rasterizer hash table + +public: + using rasterizer_mfp = void (voodoo_renderer::*)(int32_t, const extent_t &, const poly_data &, int); + + // construction + voodoo_renderer(running_machine &machine, u16 tmu_config, const rgb_t *rgb565, voodoo_regs &fbi_regs, voodoo_regs *tmu0_regs, voodoo_regs *tmu1_regs); + + // state saving + void register_save(save_proxy &save); + + // simple getters + s32 yorigin() const { return m_yorigin; } + u32 rowpixels() const { return m_rowpixels; } + u16 tmu_config() const { return m_tmu_config; } + std::vector &thread_stats() { return m_thread_stats; } + + // simple setters + void set_tmu_config(u16 value) { m_tmu_config = value; } + void set_fogdelta_mask(u8 value) { m_fogdelta_mask = value; } + void set_bilinear_mask(u8 value) { m_bilinear_mask = value; } + + // allocate a new poly_data and fill in the rasterizer_params + poly_data &alloc_poly(); + + // enqueue operations + u32 enqueue_fastfill(poly_data &poly); + u32 enqueue_triangle(poly_data &poly, vertex_t const *vert); + + // core triangle rasterizer + template + void rasterizer(s32 y, const voodoo::voodoo_renderer::extent_t &extent, const voodoo::poly_data &extra, int threadid); + + // run the pixel pipeline for LFB writes + void pixel_pipeline(thread_stats_block &threadstats, voodoo::poly_data const &extra, voodoo::reg_lfb_mode const lfbmode, s32 x, s32 scry, rgb_t color, u16 sz); + + // update the fog tables + void write_fog(u32 base, u32 data) + { + wait("Fog write"); + m_fogdelta[base + 0] = (data >> 0) & 0xff; + m_fogblend[base + 0] = (data >> 8) & 0xff; + m_fogdelta[base + 1] = (data >> 16) & 0xff; + m_fogblend[base + 1] = (data >> 24) & 0xff; + } + + // update the Y origin + void set_yorigin(s32 yorigin) + { + wait("Y origin write"); + m_yorigin = yorigin; + } + + // update the rowpixels + void set_rowpixels(u32 rowpixels) + { + wait("Rowpixels write"); + m_rowpixels = rowpixels; + } + + // manage texture instances + rasterizer_texture &alloc_texture(int tmu) { return m_textures.next(tmu); } + rasterizer_texture &last_texture(int tmu) { return m_textures.last(tmu); } + + // manage ncc texel instnaces + rasterizer_palette &alloc_palette(int which) { return m_palettes.next(which); } + rasterizer_palette &last_palette(int which) { return m_palettes.last(which); } + + // dump rasterizer statistics if enabled + void dump_rasterizer_stats(); + +protected: + // overrides + virtual void reset_after_wait() override; + +private: + // pipeline stages, in order + bool stipple_test(thread_stats_block &threadstats, voodoo::reg_fbz_mode const fbzmode, s32 x, s32 y, u32 &stipple); + s32 compute_depthval(voodoo::poly_data const &extra, voodoo::reg_fbz_mode const fbzmode, voodoo::reg_fbz_colorpath const fbzcp, s32 wfloat, s32 iterz); + bool depth_test(thread_stats_block &stats, voodoo::poly_data const &extra, voodoo::reg_fbz_mode const fbzmode, s32 destDepth, s32 biasdepth); + bool combine_color(rgbaint_t &color, thread_stats_block &threadstats, const voodoo::poly_data &extradata, voodoo::reg_fbz_colorpath const fbzcp, voodoo::reg_fbz_mode const fbzmode, rgbaint_t texel, s32 iterz, s64 iterw, rgb_t chromakey); + bool alpha_mask_test(thread_stats_block &stats, u32 alpha); + bool alpha_test(thread_stats_block &stats, voodoo::reg_alpha_mode const alphamode, u32 alpha, u32 alpharef); + bool chroma_key_test(thread_stats_block &stats, rgbaint_t const &colorin, rgb_t chromakey); + void apply_fogging(rgbaint_t &color, voodoo::poly_data const &extra, voodoo::reg_fbz_mode const fbzmode, voodoo::reg_fog_mode const fogmode, voodoo::reg_fbz_colorpath const fbzcp, s32 x, voodoo::dither_helper const &dither, s32 wfloat, s32 iterz, s64 iterw, const rgbaint_t &iterargb); + void alpha_blend(rgbaint_t &color, voodoo::reg_fbz_mode const fbzmode, voodoo::reg_alpha_mode const alphamode, s32 x, voodoo::dither_helper const &dither, int dpix, u16 *depth, rgbaint_t const &prefog); + void write_pixel(thread_stats_block &threadstats, voodoo::reg_fbz_mode const fbzmode, voodoo::dither_helper const &dither, u16 *destbase, u16 *depthbase, s32 x, rgbaint_t const &color, s32 depthval); + + // fastfill rasterizer + void rasterizer_fastfill(s32 scanline, const voodoo::voodoo_renderer::extent_t &extent, const voodoo::poly_data &extradata, int threadid); + + // helpers + static rasterizer_mfp generic_rasterizer(u8 texmask); + voodoo::rasterizer_info *add_rasterizer(voodoo::rasterizer_params const ¶ms, rasterizer_mfp rasterizer, bool is_generic); + + // internal state + u8 m_bilinear_mask; // mask for bilinear resolution (0xf0 for V1, 0xff for V2) + u16 m_tmu_config; // TMU configuration + u32 m_rowpixels; // current pixels per row + s32 m_yorigin; // current Y origin + voodoo_regs &m_fbi_reg; // FBI registers + voodoo_regs *m_tmu0_reg; // TMU #0 registers + voodoo_regs *m_tmu1_reg; // TMU #1 register + rgb_t const *m_rgb565; // 5-6-5 to 8-8-8 lookup table + u8 m_fogblend[64]; // 64-entry fog table + u8 m_fogdelta[64]; // 64-entry fog table + u8 m_fogdelta_mask; // mask for for delta (0xff for V1, 0xfc for V2) + poly_array m_textures; + poly_array m_palettes; + voodoo::rasterizer_info *m_raster_hash[RASTER_HASH_SIZE]; // hash table of rasterizers + voodoo::rasterizer_info *m_generic_rasterizer[16]; + std::list m_rasterizer_list; + std::vector m_thread_stats; +}; + + + +//************************************************************************** +// MATH HELPERS +//************************************************************************** + +//------------------------------------------------- +// fast_log2 - computes the log2 of a double- +// precision value as a 24.8 value +//------------------------------------------------- + +inline s32 fast_log2(double value, int offset) +{ + // negative values return 0 + if (UNEXPECTED(value < 0)) + return 0; + + // convert the value to a raw integer + union { double d; u64 i; } temp; + temp.d = value; + + // we only care about the 11-bit exponent and top 4 bits of mantissa + // (sign is already assured to be 0) + u32 ival = temp.i >> 48; + + // exponent in the upper bits, plus an 8-bit log value from 4 bits of mantissa + s32 exp = (ival >> 4) - 1023 + 32 - offset; + + // the maximum error using a 4 bit lookup from the mantissa is 0.0875, which is + // less than 1/2 lsb (0.125) for 2 bits of fraction + static u8 const s_log2_table[16] = { 0, 22, 44, 63, 82, 100, 118, 134, 150, 165, 179, 193, 207, 220, 232, 244 }; + return (exp << 8) | s_log2_table[ival & 15]; +} + +} + +#endif // MAME_VIDEO_VOODOO_RENDER_H diff --git a/src/devices/video/zeus2.cpp b/src/devices/video/zeus2.cpp index b6626ce933a..cb3d02f7613 100644 --- a/src/devices/video/zeus2.cpp +++ b/src/devices/video/zeus2.cpp @@ -7,6 +7,7 @@ **************************************************************************/ #include "emu.h" #include "zeus2.h" +#include "screen.h" #include @@ -19,7 +20,7 @@ * Constructor *************************************/ zeus2_renderer::zeus2_renderer(zeus2_device *state) - : poly_manager(state->machine()) + : poly_manager(state->machine()) , m_state(state) { } @@ -1827,8 +1828,8 @@ void zeus2_renderer::zeus2_draw_quad(const uint32_t *databuffer, uint32_t texdat } //if (numverts == 3) - // render_triangle(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), 4, vert[0], vert[1], vert[2]); - render_polygon<4>(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), 4, vert); + // render_triangle<4>(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), vert[0], vert[1], vert[2]); + render_polygon<4, 4>(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), vert); } diff --git a/src/devices/video/zeus2.h b/src/devices/video/zeus2.h index 3090c08c620..1b546349468 100644 --- a/src/devices/video/zeus2.h +++ b/src/devices/video/zeus2.h @@ -83,7 +83,7 @@ struct zeus2_poly_extra_data *************************************/ class zeus2_device; -class zeus2_renderer : public poly_manager +class zeus2_renderer : public poly_manager { public: zeus2_renderer(zeus2_device *state); diff --git a/src/emu/video/rgbsse.cpp b/src/emu/video/rgbsse.cpp index 3b9c80273af..d7cabfa19a2 100644 --- a/src/emu/video/rgbsse.cpp +++ b/src/emu/video/rgbsse.cpp @@ -12,7 +12,7 @@ #include "emu.h" -#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))) +#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))) #include "rgbsse.h" diff --git a/src/emu/video/rgbsse.h b/src/emu/video/rgbsse.h index a04145a4d82..ea3bc1e208b 100644 --- a/src/emu/video/rgbsse.h +++ b/src/emu/video/rgbsse.h @@ -271,6 +271,9 @@ public: inline void min(const s32 value) { __m128i val = _mm_set1_epi32(value); +#ifdef __SSE4_1__ + m_value = _mm_min_epi32(m_value, val); +#else __m128i is_greater_than = _mm_cmpgt_epi32(m_value, val); __m128i val_to_set = _mm_and_si128(val, is_greater_than); @@ -278,11 +281,15 @@ public: m_value = _mm_and_si128(m_value, keep_mask); m_value = _mm_or_si128(val_to_set, m_value); +#endif } inline void max(const s32 value) { __m128i val = _mm_set1_epi32(value); +#ifdef __SSE4_1__ + m_value = _mm_max_epi32(m_value, val); +#else __m128i is_less_than = _mm_cmplt_epi32(m_value, val); __m128i val_to_set = _mm_and_si128(val, is_less_than); @@ -290,6 +297,7 @@ public: m_value = _mm_and_si128(m_value, keep_mask); m_value = _mm_or_si128(val_to_set, m_value); +#endif } void blend(const rgbaint_t& other, u8 factor); @@ -324,48 +332,38 @@ public: m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128()); } - // This function needs absolute value of color and scale to be 11 bits or less + // This function needs absolute value of color and scale to be 15 bits or less inline void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) { - // Pack scale into mult a 16 bits - __m128i tmp1 = _mm_packs_epi32(scale.m_value, _mm_setzero_si128()); - // Shift up by 4 - tmp1 = _mm_slli_epi16(tmp1, 4); - // Pack color into mult b 16 bit inputs - m_value = _mm_packs_epi32(m_value, _mm_setzero_si128()); - // Shift up by 4 - m_value = _mm_slli_epi16(m_value, 4); - // Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results - m_value = _mm_mulhi_epi16(m_value, tmp1); - // Unpack up to s32, putting the 16 bit value at the top so the sign bit is set by the 16 bit result - m_value = _mm_unpacklo_epi16(_mm_setzero_si128(), m_value); - // Arithmetic shift down the 16 bit value to the lower 16 bits - sra_imm(16); +#ifdef __SSE4_1__ + m_value = _mm_mullo_epi32(m_value, scale.m_value); +#else + // Mask off the top 16 bits of each 32-bit value + m_value = _mm_and_si128(m_value, _mm_set1_epi32(0x0000ffff)); + // Do 16x16 multiplies and sum into 32-bit pairs; the AND above ensures upper pair is always 0 + m_value = _mm_madd_epi16(m_value, scale.m_value); +#endif + // Arithmetic shift down the result by 8 bits + sra_imm(8); add(other); clamp_to_uint8(); } - // This function needs absolute value of color and scale to be 11 bits or less + // This function needs absolute value of color and scale to be 15 bits or less inline void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2) { - // Pack both scale values into mult a 16 bits - __m128i tmp1 = _mm_packs_epi32(scale.m_value, scale2.m_value); - // Shift up by 4 - tmp1 = _mm_slli_epi16(tmp1, 4); - // Pack both color values into mult b 16 bit inputs - m_value = _mm_packs_epi32(m_value, other.m_value); - // Shift up by 4 - m_value = _mm_slli_epi16(m_value, 4); - // Do the 16 bit multiply, top and bottom 64 bits will contain 16 bit truncated results - tmp1 = _mm_mulhi_epi16(m_value, tmp1); - // Unpack up to s32, putting the 16 bit value at the top so the sign bit is set by the 16 bit result - m_value = _mm_unpacklo_epi16(_mm_setzero_si128(), tmp1); - tmp1 = _mm_unpackhi_epi16(_mm_setzero_si128(), tmp1); - // Arithmetic shift down the 16 bit value to the lower 16 bits - sra_imm(16); - tmp1 = _mm_srai_epi32(tmp1, 16); - // Add the results - m_value = _mm_add_epi32(m_value, tmp1); + // Pack 32-bit values to 16-bit values in low half, and scales in top half + __m128i tmp1 = _mm_packs_epi32(m_value, scale.m_value); + // Same for other and scale2 + __m128i tmp2 = _mm_packs_epi32(other.m_value, scale2.m_value); + // Interleave the low halves (m_value, other) + __m128i tmp3 = _mm_unpacklo_epi16(tmp1, tmp2); + // Interleave the top halves (scale, scale2) + __m128i tmp4 = _mm_unpackhi_epi16(tmp1, tmp2); + // Multiply values by scales and add adjacent pairs + m_value = _mm_madd_epi16(tmp3, tmp4); + // Final shift by 8 + sra_imm(8); clamp_to_uint8(); } diff --git a/src/emu/video/rgbutil.h b/src/emu/video/rgbutil.h index acf7abb8f82..c6ee325c754 100644 --- a/src/emu/video/rgbutil.h +++ b/src/emu/video/rgbutil.h @@ -13,7 +13,7 @@ #define MAME_EMU_VIDEO_RGBUTIL_H // use SSE on 64-bit implementations, where it can be assumed -#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))) +#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))) #define MAME_RGB_HIGH_PRECISION #include "rgbsse.h" diff --git a/src/lib/util/palette.h b/src/lib/util/palette.h index ed9d4eb9311..d21c8ca8125 100644 --- a/src/lib/util/palette.h +++ b/src/lib/util/palette.h @@ -229,7 +229,7 @@ private: //------------------------------------------------- template -inline uint8_t palexpand(uint8_t bits) +constexpr uint8_t palexpand(uint8_t bits) { if (_NumBits == 1) { return (bits & 1) ? 0xff : 0x00; } if (_NumBits == 2) { bits &= 3; return (bits << 6) | (bits << 4) | (bits << 2) | bits; } @@ -246,13 +246,13 @@ inline uint8_t palexpand(uint8_t bits) // palxbit - convert an x-bit value to 8 bits //------------------------------------------------- -inline uint8_t pal1bit(uint8_t bits) { return palexpand<1>(bits); } -inline uint8_t pal2bit(uint8_t bits) { return palexpand<2>(bits); } -inline uint8_t pal3bit(uint8_t bits) { return palexpand<3>(bits); } -inline uint8_t pal4bit(uint8_t bits) { return palexpand<4>(bits); } -inline uint8_t pal5bit(uint8_t bits) { return palexpand<5>(bits); } -inline uint8_t pal6bit(uint8_t bits) { return palexpand<6>(bits); } -inline uint8_t pal7bit(uint8_t bits) { return palexpand<7>(bits); } +constexpr uint8_t pal1bit(uint8_t bits) { return palexpand<1>(bits); } +constexpr uint8_t pal2bit(uint8_t bits) { return palexpand<2>(bits); } +constexpr uint8_t pal3bit(uint8_t bits) { return palexpand<3>(bits); } +constexpr uint8_t pal4bit(uint8_t bits) { return palexpand<4>(bits); } +constexpr uint8_t pal5bit(uint8_t bits) { return palexpand<5>(bits); } +constexpr uint8_t pal6bit(uint8_t bits) { return palexpand<6>(bits); } +constexpr uint8_t pal7bit(uint8_t bits) { return palexpand<7>(bits); } //------------------------------------------------- @@ -261,21 +261,27 @@ inline uint8_t pal7bit(uint8_t bits) { return palexpand<7>(bits); } //------------------------------------------------- template -inline rgb_t rgbexpand(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) +constexpr rgb_t rgbexpand(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgb_t(palexpand<_RBits>(data >> rshift), palexpand<_GBits>(data >> gshift), palexpand<_BBits>(data >> bshift)); } +template +constexpr rgb_t argbexpand(uint32_t data, uint8_t ashift, uint8_t rshift, uint8_t gshift, uint8_t bshift) +{ + return rgb_t(palexpand<_ABits>(data >> ashift), palexpand<_RBits>(data >> rshift), palexpand<_GBits>(data >> gshift), palexpand<_BBits>(data >> bshift)); +} + //------------------------------------------------- // palxxx - create an x-x-x color by extracting // bits from a uint32_t //------------------------------------------------- -inline rgb_t pal332(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<3,3,2>(data, rshift, gshift, bshift); } -inline rgb_t pal444(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<4,4,4>(data, rshift, gshift, bshift); } -inline rgb_t pal555(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,5,5>(data, rshift, gshift, bshift); } -inline rgb_t pal565(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,6,5>(data, rshift, gshift, bshift); } -inline rgb_t pal888(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<8,8,8>(data, rshift, gshift, bshift); } +constexpr rgb_t pal332(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<3,3,2>(data, rshift, gshift, bshift); } +constexpr rgb_t pal444(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<4,4,4>(data, rshift, gshift, bshift); } +constexpr rgb_t pal555(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,5,5>(data, rshift, gshift, bshift); } +constexpr rgb_t pal565(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,6,5>(data, rshift, gshift, bshift); } +constexpr rgb_t pal888(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<8,8,8>(data, rshift, gshift, bshift); } #endif // MAME_UTIL_PALETTE_H diff --git a/src/mame/drivers/atarisy4.cpp b/src/mame/drivers/atarisy4.cpp index 1dfd60758f8..3da66c3099e 100644 --- a/src/mame/drivers/atarisy4.cpp +++ b/src/mame/drivers/atarisy4.cpp @@ -51,7 +51,7 @@ protected: uint16_t *screen_ram; }; - class atarisy4_renderer : public poly_manager + class atarisy4_renderer : public poly_manager { public: atarisy4_renderer(atarisy4_state &state, screen_device &screen); @@ -214,7 +214,7 @@ private: *************************************/ atarisy4_state::atarisy4_renderer::atarisy4_renderer(atarisy4_state &state, screen_device &screen) : - poly_manager(screen, FLAG_NO_WORK_QUEUE), + poly_manager(screen.machine()), m_state(state) { } @@ -359,7 +359,7 @@ void atarisy4_state::atarisy4_renderer::draw_polygon(uint16_t color) v3.x = m_state.m_gpu.points[i].x; v3.y = m_state.m_gpu.points[i].y; - render_triangle(clip, rd_scan, 1, v1, v2, v3); + render_triangle<1>(clip, rd_scan, v1, v2, v3); v2 = v3; } } diff --git a/src/mame/drivers/cobra.cpp b/src/mame/drivers/cobra.cpp index cc5694215d3..da5141650af 100644 --- a/src/mame/drivers/cobra.cpp +++ b/src/mame/drivers/cobra.cpp @@ -328,6 +328,7 @@ #include "sound/rf5c400.h" #include "sound/dmadac.h" #include "emupal.h" +#include "screen.h" #include "speaker.h" #define GFXFIFO_IN_VERBOSE 0 @@ -355,11 +356,12 @@ struct cobra_polydata uint32_t tex_address; }; -class cobra_renderer : public poly_manager +class cobra_renderer : public poly_manager { public: cobra_renderer(screen_device &screen) - : poly_manager(screen) + : poly_manager(screen.machine()) + , m_screen(screen) { m_texture_ram = std::make_unique(0x100000); @@ -386,6 +388,7 @@ public: } } + screen_device &screen() const { return m_screen; } void render_texture_scan(int32_t scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid); void render_color_scan(int32_t scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid); void draw_point(const rectangle &visarea, vertex_t &v, uint32_t color); @@ -403,6 +406,7 @@ public: void display(bitmap_rgb32 *bitmap, const rectangle &cliprect); inline rgb_t texture_fetch(uint32_t *texture, int u, int v, int width, int format); private: + screen_device &m_screen; std::unique_ptr m_framebuffer; std::unique_ptr m_backbuffer; std::unique_ptr m_overlay; @@ -2124,7 +2128,7 @@ void cobra_renderer::gfx_exit() void cobra_renderer::gfx_reset() { - cobra_state *cobra = machine().driver_data(); + cobra_state *cobra = screen().machine().driver_data(); cobra->m_gfx_re_status = RE_STATUS_IDLE; } @@ -2226,7 +2230,7 @@ void cobra_renderer::gfx_write_reg(uint64_t data) void cobra_renderer::gfx_fifo_exec() { - cobra_state *cobra = machine().driver_data(); + cobra_state *cobra = screen().machine().driver_data(); if (cobra->m_gfx_fifo_loopback != 0) return; @@ -2533,7 +2537,7 @@ void cobra_renderer::gfx_fifo_exec() render_delegate rd = render_delegate(&cobra_renderer::render_texture_scan, this); for (int i=2; i < units; i++) { - render_triangle(visarea, rd, 8, vert[i-2], vert[i-1], vert[i]); + render_triangle<8>(visarea, rd, vert[i-2], vert[i-1], vert[i]); } } else @@ -2541,7 +2545,7 @@ void cobra_renderer::gfx_fifo_exec() render_delegate rd = render_delegate(&cobra_renderer::render_color_scan, this); for (int i=2; i < units; i++) { - render_triangle(visarea, rd, 5, vert[i-2], vert[i-1], vert[i]); + render_triangle<5>(visarea, rd, vert[i-2], vert[i-1], vert[i]); } } break; diff --git a/src/mame/drivers/funkball.cpp b/src/mame/drivers/funkball.cpp index 72aefaedcaa..e2587c0e872 100644 --- a/src/mame/drivers/funkball.cpp +++ b/src/mame/drivers/funkball.cpp @@ -154,7 +154,7 @@ void funkball_state::video_start() uint32_t funkball_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ) { - return m_voodoo->voodoo_update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; + return m_voodoo->update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; } uint32_t funkball_state::voodoo_0_pci_r(int function, int reg, uint32_t mem_mask) @@ -195,7 +195,7 @@ void funkball_state::voodoo_0_pci_w(int function, int reg, uint32_t data, uint32 break; case 0x40: m_voodoo_pci_regs.init_enable = data; - m_voodoo->voodoo_set_init_enable(data); + m_voodoo->set_init_enable(data); break; } } @@ -330,7 +330,7 @@ void funkball_state::funkball_map(address_map &map) // map(0x08000000, 0x0fffffff).noprw(); map(0x40008000, 0x400080ff).rw(FUNC(funkball_state::biu_ctrl_r), FUNC(funkball_state::biu_ctrl_w)); map(0x40010e00, 0x40010eff).ram().share("unk_ram"); - map(0xff000000, 0xfffdffff).rw(m_voodoo, FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0xff000000, 0xfffdffff).rw(m_voodoo, FUNC(generic_voodoo_device::read), FUNC(generic_voodoo_device::write)); map(0xfffe0000, 0xffffffff).rom().region("bios", 0); /* System BIOS */ } @@ -781,11 +781,12 @@ void funkball_state::funkball(machine_config &config) ADDRESS_MAP_BANK(config, "flashbank").set_map(&funkball_state::flashbank_map).set_options(ENDIANNESS_LITTLE, 32, 32, 0x10000); /* video hardware */ - VOODOO_1(config, m_voodoo, STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo, voodoo_1_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(2); m_voodoo->set_tmumem(4, 0); - m_voodoo->set_screen_tag("screen"); - m_voodoo->set_cpu_tag(m_maincpu); + m_voodoo->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo->set_screen("screen"); + m_voodoo->set_cpu(m_maincpu); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_refresh_hz(60); diff --git a/src/mame/drivers/gticlub.cpp b/src/mame/drivers/gticlub.cpp index d24e9cc54f7..c21e5ab14ba 100644 --- a/src/mame/drivers/gticlub.cpp +++ b/src/mame/drivers/gticlub.cpp @@ -308,7 +308,7 @@ private: optional_device m_k001005; optional_device_array m_k001006; optional_device_array m_k001604; - optional_device_array m_voodoo; + optional_device_array m_voodoo; required_shared_ptr m_work_ram; required_shared_ptr m_generic_paletteram_32; optional_shared_ptr_array m_sharc_dataram; @@ -559,7 +559,7 @@ void gticlub_state::hangplt_sharc0_map(address_map &map) map(0x0400000, 0x041ffff).rw(m_konppc, FUNC(konppc_device::cgboard_0_shared_sharc_r), FUNC(konppc_device::cgboard_0_shared_sharc_w)); map(0x0500000, 0x05fffff).ram().share(m_sharc_dataram[0]).lr32(NAME([this](offs_t offset) { return m_sharc_dataram[0][offset] & 0xffff; })); map(0x1400000, 0x14fffff).ram(); - map(0x2400000, 0x27fffff).r(m_konppc, FUNC(konppc_device::nwk_voodoo_0_r)).w(m_voodoo[0], FUNC(voodoo_device::voodoo_w)); + map(0x2400000, 0x27fffff).r(m_konppc, FUNC(konppc_device::nwk_voodoo_0_r)).w(m_voodoo[0], FUNC(generic_voodoo_device::write)); map(0x3400000, 0x34000ff).rw(m_konppc, FUNC(konppc_device::cgboard_0_comm_sharc_r), FUNC(konppc_device::cgboard_0_comm_sharc_w)); map(0x3401000, 0x34fffff).w(m_konppc, FUNC(konppc_device::nwk_fifo_0_w)); map(0x3500000, 0x3507fff).rw(m_konppc, FUNC(konppc_device::K033906_0_r), FUNC(konppc_device::K033906_0_w)); @@ -571,7 +571,7 @@ void gticlub_state::hangplt_sharc1_map(address_map &map) map(0x0400000, 0x041ffff).rw(m_konppc, FUNC(konppc_device::cgboard_1_shared_sharc_r), FUNC(konppc_device::cgboard_1_shared_sharc_w)); map(0x0500000, 0x05fffff).ram().share(m_sharc_dataram[1]).lr32(NAME([this](offs_t offset) { return m_sharc_dataram[1][offset] & 0xffff; })); map(0x1400000, 0x14fffff).ram(); - map(0x2400000, 0x27fffff).r(m_konppc, FUNC(konppc_device::nwk_voodoo_1_r)).w(m_voodoo[1], FUNC(voodoo_device::voodoo_w)); + map(0x2400000, 0x27fffff).r(m_konppc, FUNC(konppc_device::nwk_voodoo_1_r)).w(m_voodoo[1], FUNC(generic_voodoo_device::write)); map(0x3400000, 0x34000ff).rw(m_konppc, FUNC(konppc_device::cgboard_1_comm_sharc_r), FUNC(konppc_device::cgboard_1_comm_sharc_w)); map(0x3401000, 0x34fffff).w(m_konppc, FUNC(konppc_device::nwk_fifo_1_w)); map(0x3500000, 0x3507fff).rw(m_konppc, FUNC(konppc_device::K033906_1_r), FUNC(konppc_device::K033906_1_w)); @@ -832,7 +832,7 @@ uint32_t gticlub_state::screen_update_two_screens(screen_device &screen, bitmap_ bitmap.fill(m_palette->pen(0), cliprect); // m_k001604[Which]->draw_back_layer(bitmap, cliprect); - m_voodoo[Which]->voodoo_update(bitmap, cliprect); + m_voodoo[Which]->update(bitmap, cliprect); m_k001604[Which]->draw_front_layer(screen, bitmap, cliprect); return 0; @@ -950,19 +950,21 @@ void gticlub_state::hangplt(machine_config &config) K056230(config, m_k056230, "maincpu"); - VOODOO_1(config, m_voodoo[0], STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo[0], voodoo_1_device::NOMINAL_CLOCK); m_voodoo[0]->set_fbmem(2); m_voodoo[0]->set_tmumem(2,2); - m_voodoo[0]->set_screen_tag("lscreen"); - m_voodoo[0]->set_cpu_tag(m_dsp[0]); + m_voodoo[0]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[0]->set_screen("lscreen"); + m_voodoo[0]->set_cpu(m_dsp[0]); m_voodoo[0]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_voodoo[0]->stall_callback().set(m_dsp[0], FUNC(adsp21062_device::write_stall)); - VOODOO_1(config, m_voodoo[1], STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo[1], voodoo_1_device::NOMINAL_CLOCK); m_voodoo[1]->set_fbmem(2); m_voodoo[1]->set_tmumem(2,2); - m_voodoo[1]->set_screen_tag("rscreen"); - m_voodoo[1]->set_cpu_tag(m_dsp[1]); + m_voodoo[1]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[1]->set_screen("rscreen"); + m_voodoo[1]->set_cpu(m_dsp[1]); m_voodoo[1]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ1); m_voodoo[1]->stall_callback().set(m_dsp[1], FUNC(adsp21062_device::write_stall)); diff --git a/src/mame/drivers/hornet.cpp b/src/mame/drivers/hornet.cpp index de5b47bee55..80abb1d9433 100644 --- a/src/mame/drivers/hornet.cpp +++ b/src/mame/drivers/hornet.cpp @@ -363,7 +363,7 @@ Jumpers set on GFX PCB to scope monitor: #include "sound/k056800.h" #include "sound/rf5c400.h" #include "video/k037122.h" -#include "video/voodoo.h" +#include "video/voodoo_2.h" #include "emupal.h" #include "screen.h" #include "speaker.h" @@ -434,7 +434,7 @@ private: required_device m_adc12138; required_device m_konppc; optional_device m_lan_eeprom; - optional_device_array m_voodoo; + optional_device_array m_voodoo; required_ioport_array<3> m_in; required_ioport m_dsw; optional_ioport m_eepromout; @@ -492,7 +492,7 @@ private: template uint32_t hornet_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - m_voodoo[Which]->voodoo_update(bitmap, cliprect); + m_voodoo[Which]->update(bitmap, cliprect); m_k037122[Which]->tile_draw(screen, bitmap, cliprect); @@ -834,7 +834,7 @@ void hornet_state::sharc0_map(address_map &map) map(0x0400000, 0x041ffff).rw(m_konppc, FUNC(konppc_device::cgboard_0_shared_sharc_r), FUNC(konppc_device::cgboard_0_shared_sharc_w)); map(0x0500000, 0x05fffff).ram().share(m_sharc_dataram[0]).lr32(NAME([this](offs_t offset) { return m_sharc_dataram[0][offset] & 0xffff; })); map(0x1400000, 0x14fffff).ram(); - map(0x2400000, 0x27fffff).rw(m_voodoo[0], FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0x2400000, 0x27fffff).m(m_voodoo[0], FUNC(generic_voodoo_device::core_map)); map(0x3400000, 0x34000ff).rw(m_konppc, FUNC(konppc_device::cgboard_0_comm_sharc_r), FUNC(konppc_device::cgboard_0_comm_sharc_w)); map(0x3500000, 0x35000ff).rw(m_konppc, FUNC(konppc_device::K033906_0_r), FUNC(konppc_device::K033906_0_w)); map(0x3600000, 0x37fffff).bankr("master_cgboard_bank"); @@ -845,7 +845,7 @@ void hornet_state::sharc1_map(address_map &map) map(0x0400000, 0x041ffff).rw(m_konppc, FUNC(konppc_device::cgboard_1_shared_sharc_r), FUNC(konppc_device::cgboard_1_shared_sharc_w)); map(0x0500000, 0x05fffff).ram().share(m_sharc_dataram[1]).lr32(NAME([this](offs_t offset) { return m_sharc_dataram[1][offset] & 0xffff; })); map(0x1400000, 0x14fffff).ram(); - map(0x2400000, 0x27fffff).rw(m_voodoo[1], FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0x2400000, 0x27fffff).m(m_voodoo[1], FUNC(generic_voodoo_device::core_map)); map(0x3400000, 0x34000ff).rw(m_konppc, FUNC(konppc_device::cgboard_1_comm_sharc_r), FUNC(konppc_device::cgboard_1_comm_sharc_w)); map(0x3500000, 0x35000ff).rw(m_konppc, FUNC(konppc_device::K033906_1_r), FUNC(konppc_device::K033906_1_w)); map(0x3600000, 0x37fffff).bankr("slave_cgboard_bank"); @@ -1124,8 +1124,9 @@ void hornet_state::hornet(machine_config &config) VOODOO_1(config, m_voodoo[0], XTAL(50'000'000)); m_voodoo[0]->set_fbmem(2); m_voodoo[0]->set_tmumem(4,0); - m_voodoo[0]->set_screen_tag("screen"); - m_voodoo[0]->set_cpu_tag(m_dsp[0]); + m_voodoo[0]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[0]->set_screen("screen"); + m_voodoo[0]->set_cpu(m_dsp[0]); m_voodoo[0]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_voodoo[0]->stall_callback().set(m_dsp[0], FUNC(adsp21062_device::write_stall)); @@ -1199,13 +1200,14 @@ void hornet_state::sscope(machine_config &config) m_k037122[1]->set_screen("rscreen"); m_k037122[1]->set_palette("palette"); - m_voodoo[0]->set_screen_tag("lscreen"); + m_voodoo[0]->set_screen("lscreen"); VOODOO_1(config, m_voodoo[1], XTAL(50'000'000)); m_voodoo[1]->set_fbmem(2); m_voodoo[1]->set_tmumem(4, 0); - m_voodoo[1]->set_screen_tag("rscreen"); - m_voodoo[1]->set_cpu_tag(m_dsp[1]); + m_voodoo[1]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[1]->set_screen("rscreen"); + m_voodoo[1]->set_cpu(m_dsp[1]); m_voodoo[1]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ1); m_voodoo[1]->stall_callback().set(m_dsp[1], FUNC(adsp21062_device::write_stall)); @@ -1234,19 +1236,21 @@ void hornet_state::sscope_voodoo2(machine_config& config) { sscope(config); - VOODOO_2(config.replace(), m_voodoo[0], STD_VOODOO_2_CLOCK); + VOODOO_2(config.replace(), m_voodoo[0], voodoo_2_device::NOMINAL_CLOCK); m_voodoo[0]->set_fbmem(2); m_voodoo[0]->set_tmumem(4,0); - m_voodoo[0]->set_screen_tag("lscreen"); - m_voodoo[0]->set_cpu_tag(m_dsp[0]); + m_voodoo[0]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[0]->set_screen("lscreen"); + m_voodoo[0]->set_cpu(m_dsp[0]); m_voodoo[0]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_voodoo[0]->stall_callback().set(m_dsp[0], FUNC(adsp21062_device::write_stall)); - VOODOO_2(config.replace(), m_voodoo[1], STD_VOODOO_2_CLOCK); + VOODOO_2(config.replace(), m_voodoo[1], voodoo_2_device::NOMINAL_CLOCK); m_voodoo[1]->set_fbmem(2); m_voodoo[1]->set_tmumem(4,0); - m_voodoo[1]->set_screen_tag("rscreen"); - m_voodoo[1]->set_cpu_tag(m_dsp[1]); + m_voodoo[1]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[1]->set_screen("rscreen"); + m_voodoo[1]->set_cpu(m_dsp[1]); m_voodoo[1]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ1); m_voodoo[1]->stall_callback().set(m_dsp[1], FUNC(adsp21062_device::write_stall)); } diff --git a/src/mame/drivers/iteagle.cpp b/src/mame/drivers/iteagle.cpp index 47d71274c40..ab0990699b9 100644 --- a/src/mame/drivers/iteagle.cpp +++ b/src/mame/drivers/iteagle.cpp @@ -198,7 +198,8 @@ void iteagle_state::iteagle(machine_config &config) voodoo_3_pci_device &voodoo(VOODOO_3_PCI(config, PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(16); - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(m_fpga, FUNC(iteagle_fpga_device::vblank_update)); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(m_fpga, FUNC(iteagle_fpga_device::vblank_update)); ITEAGLE_EEPROM(config, m_eeprom, 0); @@ -299,6 +300,7 @@ void iteagle_state::virtpool(machine_config &config) voodoo_1_pci_device &voodoo(VOODOO_1_PCI(config.replace(), PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(4); voodoo.set_tmumem(4, 4); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status m_fpga->set_init_info(0x01000202, 0x080808); m_eeprom->set_info(0x0202, 0x7); diff --git a/src/mame/drivers/magictg.cpp b/src/mame/drivers/magictg.cpp index f59b82deaf1..4c8726b6549 100644 --- a/src/mame/drivers/magictg.cpp +++ b/src/mame/drivers/magictg.cpp @@ -194,7 +194,7 @@ private: /* 3Dfx Voodoo */ - required_device_array m_voodoo; + required_device_array m_voodoo; struct { @@ -301,7 +301,7 @@ void magictg_state::video_start() uint32_t magictg_state::screen_update_magictg(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - return m_voodoo[0]->voodoo_update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; + return m_voodoo[0]->update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; } @@ -358,7 +358,7 @@ void magictg_state::voodoo_0_pci_w(int function, int reg, uint32_t data, uint32_ break; case 0x40: m_voodoo_pci_regs[0].init_enable = data; - m_voodoo[0]->voodoo_set_init_enable(data); + m_voodoo[0]->set_init_enable(data); break; default: @@ -403,7 +403,7 @@ void magictg_state::voodoo_1_pci_w(int function, int reg, uint32_t data, uint32_ break; case 0x40: m_voodoo_pci_regs[1].init_enable = data; - voodoo_set_init_enable(state->m_voodoo[1], data); + set_init_enable(state->m_voodoo[1], data); break; default: @@ -852,9 +852,9 @@ void magictg_state::magictg_map(address_map &map) { map(0x00000000, 0x007fffff).ram(); // 8MB RAM map(0x00800000, 0x0081003f).ram(); // ? - map(0x0a000000, 0x0affffff).rw("voodoo_0", FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0x0a000000, 0x0affffff).rw("voodoo_0", FUNC(generic_voodoo_device::read), FUNC(generic_voodoo_device::write)); #if defined(USE_TWO_3DFX) - map(0x0b000000, 0x0bffffff).rw("voodoo_1", FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0x0b000000, 0x0bffffff).rw("voodoo_1", FUNC(voodoo_device_base::read), FUNC(voodoo_device_base::write)); map(0x0c000000, 0x0c000fff).rw(FUNC(magictg_state::zr36120_r), FUNC(magictg_state::zr36120_w)); #else map(0x0b000000, 0x0b000fff).rw(FUNC(magictg_state::zr36120_r), FUNC(magictg_state::zr36120_w)); @@ -940,17 +940,19 @@ void magictg_state::magictg(machine_config &config) #endif pcibus.set_device(9, FUNC(magictg_state::zr36120_pci_r), FUNC(magictg_state::zr36120_pci_w)); // TODO: ZR36120 device - VOODOO_1(config, m_voodoo[0], STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo[0], voodoo_1_device::NOMINAL_CLOCK); m_voodoo[0]->set_fbmem(2); m_voodoo[0]->set_tmumem(4,0); - m_voodoo[0]->set_screen_tag("screen"); - m_voodoo[0]->set_cpu_tag(m_mips); + m_voodoo[0]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[0]->set_screen("screen"); + m_voodoo[0]->set_cpu(m_mips); - VOODOO_1(config, m_voodoo[1], STD_VOODOO_1_CLOCK); + VOODOO_1(config, m_voodoo[1], voodoo_1_device::NOMINAL_CLOCK); m_voodoo[1]->set_fbmem(2); m_voodoo[1]->set_tmumem(4,0); - m_voodoo[1]->set_screen_tag("screen"); - m_voodoo[1]->set_cpu_tag(m_mips); + m_voodoo[1]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[1]->set_screen("screen"); + m_voodoo[1]->set_cpu(m_mips); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_refresh_hz(60); diff --git a/src/mame/drivers/namcos23.cpp b/src/mame/drivers/namcos23.cpp index 12d30f9fe01..7c3caeb8a6a 100644 --- a/src/mame/drivers/namcos23.cpp +++ b/src/mame/drivers/namcos23.cpp @@ -1266,6 +1266,7 @@ Notes: #include "sound/c352.h" #include "video/poly.h" #include "emupal.h" +#include "screen.h" #include "speaker.h" #include "tilemap.h" @@ -1327,7 +1328,7 @@ struct namcos23_render_data class namcos23_state; -class namcos23_renderer : public poly_manager +class namcos23_renderer : public poly_manager { public: namcos23_renderer(namcos23_state &state); @@ -1652,7 +1653,7 @@ uint16_t namcos23_state::nthword(const uint32_t *pSource, int offs) ***************************************************************************/ namcos23_renderer::namcos23_renderer(namcos23_state &state) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state) { } @@ -2222,7 +2223,7 @@ void namcos23_state::render_one_model(const namcos23_render_entry *re) namcos23_poly_entry *p = render.polys + render.poly_count; // Should be unnecessary now that frustum clipping happens, but this still culls polys behind the camera - p->vertex_count = render.polymgr->zclip_if_less(ne, pv, p->pv, 4, 0.00001f); + p->vertex_count = render.polymgr->zclip_if_less<4>(ne, pv, p->pv, 0.00001f); // Project if you don't clip on the near plane if(p->vertex_count >= 3) { @@ -2316,13 +2317,13 @@ void namcos23_renderer::render_flush(bitmap_rgb32& bitmap) // We should probably split the polygons into triangles ourselves to insure everything is being rendered properly if (p->vertex_count == 3) - render_triangle(scissor, render_delegate(&namcos23_renderer::render_scanline, this), 4, p->pv[0], p->pv[1], p->pv[2]); + render_triangle<4>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), p->pv[0], p->pv[1], p->pv[2]); else if (p->vertex_count == 4) - render_polygon<4>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), 4, p->pv); + render_polygon<4, 4>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), p->pv); else if (p->vertex_count == 5) - render_polygon<5>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), 4, p->pv); + render_polygon<5, 4>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), p->pv); else if (p->vertex_count == 6) - render_polygon<6>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), 4, p->pv); + render_polygon<6, 4>(scissor, render_delegate(&namcos23_renderer::render_scanline, this), p->pv); } render.poly_count = 0; } diff --git a/src/mame/drivers/nwk-tr.cpp b/src/mame/drivers/nwk-tr.cpp index 72d1e201634..006e69c1bbb 100644 --- a/src/mame/drivers/nwk-tr.cpp +++ b/src/mame/drivers/nwk-tr.cpp @@ -334,7 +334,7 @@ private: required_device_array m_k001604; required_device m_konppc; required_device m_adc12138; - required_device_array m_voodoo; + required_device_array m_voodoo; required_ioport_array<3> m_in; required_ioport m_dsw; required_ioport_array<5> m_analog; @@ -377,7 +377,7 @@ uint32_t nwktr_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, int board = m_exrgb ? 1 : 0; - m_voodoo[board]->voodoo_update(bitmap, cliprect); + m_voodoo[board]->update(bitmap, cliprect); m_k001604[0]->draw_front_layer(screen, bitmap, cliprect); // K001604 on slave board doesn't seem to output anything. Bug or intended? return 0; @@ -688,16 +688,18 @@ void nwktr_state::nwktr(machine_config &config) VOODOO_1(config, m_voodoo[0], XTAL(50'000'000)); m_voodoo[0]->set_fbmem(2); m_voodoo[0]->set_tmumem(2,2); - m_voodoo[0]->set_screen_tag("screen"); - m_voodoo[0]->set_cpu_tag(m_dsp[0]); + m_voodoo[0]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[0]->set_screen("screen"); + m_voodoo[0]->set_cpu(m_dsp[0]); m_voodoo[0]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_voodoo[0]->stall_callback().set(m_dsp[0], FUNC(adsp21062_device::write_stall)); VOODOO_1(config, m_voodoo[1], XTAL(50'000'000)); m_voodoo[1]->set_fbmem(2); m_voodoo[1]->set_tmumem(2,2); - m_voodoo[1]->set_screen_tag("screen"); - m_voodoo[1]->set_cpu_tag(m_dsp[1]); + m_voodoo[1]->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo[1]->set_screen("screen"); + m_voodoo[1]->set_cpu(m_dsp[1]); m_voodoo[1]->vblank_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ1); m_voodoo[1]->stall_callback().set(m_dsp[1], FUNC(adsp21062_device::write_stall)); diff --git a/src/mame/drivers/rollext.cpp b/src/mame/drivers/rollext.cpp index 5aff055ec05..ff7a5b175aa 100644 --- a/src/mame/drivers/rollext.cpp +++ b/src/mame/drivers/rollext.cpp @@ -74,6 +74,7 @@ #include "emu.h" #include "cpu/tms32082/tms32082.h" #include "video/poly.h" +#include "screen.h" struct rollext_polydata { @@ -82,11 +83,11 @@ struct rollext_polydata uint32_t pal; }; -class rollext_renderer : public poly_manager +class rollext_renderer : public poly_manager { public: rollext_renderer(screen_device &screen) - : poly_manager(screen) + : poly_manager(screen.machine()) { m_fb = std::make_unique(1024, 1024); } @@ -95,7 +96,7 @@ public: void set_texture_ram(uint8_t* texture_ram); void set_palette_ram(uint16_t* palette_ram); - void process_display_list(uint32_t* dispram); + void process_display_list(screen_device &screen, uint32_t* dispram); void clear_fb(); void display(bitmap_rgb32 *bitmap, const rectangle &cliprect); @@ -149,9 +150,9 @@ void rollext_renderer::render_texture_scan(int32_t scanline, const extent_t &ext } } -void rollext_renderer::process_display_list(uint32_t* disp_ram) +void rollext_renderer::process_display_list(screen_device &screen, uint32_t* disp_ram) { - const rectangle& visarea = screen().visible_area(); + const rectangle& visarea = screen.visible_area(); render_delegate rd = render_delegate(&rollext_renderer::render_texture_scan, this); @@ -247,8 +248,8 @@ void rollext_renderer::process_display_list(uint32_t* disp_ram) } #endif - render_triangle(visarea, rd, 4, vert[0], vert[1], vert[2]); - render_triangle(visarea, rd, 4, vert[0], vert[2], vert[3]); + render_triangle<4>(visarea, rd, vert[0], vert[1], vert[2]); + render_triangle<4>(visarea, rd, vert[0], vert[2], vert[3]); } @@ -490,7 +491,7 @@ void rollext_state::cmd_callback(address_space &space, uint32_t data) } space.write_dword(0x600ffffc, oldnum+consume_num); - m_renderer->process_display_list(m_disp_ram); + m_renderer->process_display_list(*m_screen, m_disp_ram); space.write_dword(0x600ffffc, 0); diff --git a/src/mame/drivers/savquest.cpp b/src/mame/drivers/savquest.cpp index 674ed351156..b09072e5bab 100644 --- a/src/mame/drivers/savquest.cpp +++ b/src/mame/drivers/savquest.cpp @@ -55,7 +55,7 @@ #include "machine/pckeybrd.h" #include "machine/idectrl.h" #include "video/pc_vga.h" -#include "video/voodoo.h" +#include "video/voodoo_2.h" #include "machine/ds128x.h" #include "bus/isa/sblaster.h" @@ -357,7 +357,7 @@ void savquest_state::vid_3dfx_init() m_pci_3dfx_regs[0x08 / 4] = 2; // revision ID m_pci_3dfx_regs[0x10 / 4] = 0xff000000; m_pci_3dfx_regs[0x40 / 4] = 0x4000; //INITEN_SECONDARY_REV_ID - m_voodoo->voodoo_set_init_enable(0x4000); //INITEN_SECONDARY_REV_ID + m_voodoo->set_init_enable(0x4000); //INITEN_SECONDARY_REV_ID } uint32_t savquest_state::pci_3dfx_r(int function, int reg, uint32_t mem_mask) @@ -376,7 +376,7 @@ osd_printf_warning("PCI write: %x %x\n", reg, data); } else if (reg == 0x40) { - m_voodoo->voodoo_set_init_enable(data); + m_voodoo->set_init_enable(data); } else if (reg == 0x54) { @@ -754,7 +754,7 @@ void savquest_state::savquest_map(address_map &map) map(0x000e8000, 0x000ebfff).bankr("bios_e8000").w(FUNC(savquest_state::bios_e8000_ram_w)); map(0x000ec000, 0x000effff).bankr("bios_ec000").w(FUNC(savquest_state::bios_ec000_ram_w)); map(0x00100000, 0x07ffffff).ram(); // 128MB RAM - map(0xe0000000, 0xe0fbffff).rw(m_voodoo, FUNC(voodoo_device::voodoo_r), FUNC(voodoo_device::voodoo_w)); + map(0xe0000000, 0xe0fbffff).rw(m_voodoo, FUNC(generic_voodoo_device::read), FUNC(generic_voodoo_device::write)); map(0xfffc0000, 0xffffffff).rom().region("bios", 0); /* System BIOS */ } @@ -852,11 +852,12 @@ void savquest_state::savquest(machine_config &config) /* video hardware */ pcvideo_s3_vga(config); - VOODOO_2(config, m_voodoo, STD_VOODOO_2_CLOCK); + VOODOO_2(config, m_voodoo, voodoo_2_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(4); m_voodoo->set_tmumem(4, 4); /* this is the 12Mb card */ - m_voodoo->set_screen_tag("screen"); - m_voodoo->set_cpu_tag(m_maincpu); + m_voodoo->set_status_cycles(1000); // optimization to consume extra cycles when polling status + m_voodoo->set_screen("screen"); + m_voodoo->set_cpu(m_maincpu); m_voodoo->vblank_callback().set(FUNC(savquest_state::vblank_assert)); } diff --git a/src/mame/drivers/seattle.cpp b/src/mame/drivers/seattle.cpp index 1efb08c525a..a82722c4be5 100644 --- a/src/mame/drivers/seattle.cpp +++ b/src/mame/drivers/seattle.cpp @@ -1992,7 +1992,6 @@ INPUT_PORTS_END *************************************/ void seattle_state::seattle_common(machine_config &config) { - // basic machine hardware R5000LE(config, m_maincpu, SYSTEM_CLOCK * 3); m_maincpu->set_icache_size(16384); @@ -2017,9 +2016,10 @@ void seattle_state::seattle_common(machine_config &config) VOODOO_1_PCI(config, m_voodoo, 0, m_maincpu, m_screen); m_voodoo->set_fbmem(2); m_voodoo->set_tmumem(4, 0); + m_voodoo->set_status_cycles(1000); // optimization to consume extra cycles when polling status - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(seattle_state::vblank_assert)); - subdevice(PCI_ID_VIDEO":voodoo")->stall_callback().set(m_galileo, FUNC(gt64xxx_device::pci_stall)); + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(seattle_state::vblank_assert)); + subdevice(PCI_ID_VIDEO":voodoo")->stall_callback().set(m_galileo, FUNC(gt64xxx_device::pci_stall)); NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); @@ -2095,6 +2095,7 @@ void seattle_state::flagstaff(machine_config &config) m_voodoo->set_fbmem(2); m_voodoo->set_tmumem(4, 4); + m_voodoo->set_status_cycles(1000); // optimization to consume extra cycles when polling status } // Per game configurations diff --git a/src/mame/drivers/taitopjc.cpp b/src/mame/drivers/taitopjc.cpp index 633820c614c..a1e896bc547 100644 --- a/src/mame/drivers/taitopjc.cpp +++ b/src/mame/drivers/taitopjc.cpp @@ -91,6 +91,7 @@ #include "video/tc0780fpa.h" #include "machine/nvram.h" #include "emupal.h" +#include "screen.h" #include "tilemap.h" #define LOG_TLCS_TO_PPC_COMMANDS 1 diff --git a/src/mame/drivers/taitotz.cpp b/src/mame/drivers/taitotz.cpp index 5cdbddc3f68..8faac1e4bc4 100644 --- a/src/mame/drivers/taitotz.cpp +++ b/src/mame/drivers/taitotz.cpp @@ -178,6 +178,7 @@ Notes: #include "cpu/tlcs900/tmp95c063.h" #include "machine/nvram.h" #include "video/poly.h" +#include "screen.h" /* Interesting mem areas @@ -638,11 +639,11 @@ private: void tlcs900h_mem(address_map &map); }; -class taitotz_renderer : public poly_manager +class taitotz_renderer : public poly_manager { public: taitotz_renderer(taitotz_state &state, int width, int height, uint32_t *scrram, uint32_t *texram) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state) { m_fb = std::make_unique(width, height); @@ -1344,7 +1345,7 @@ void taitotz_renderer::render_tnl_object(uint32_t address, float scale, uint8_t for (int i=2; i < num_verts; i++) { - render_triangle(m_cliprect, render_delegate(&taitotz_renderer::draw_scanline, this), 6, v[0], v[i-1], v[i]); + render_triangle<6>(m_cliprect, render_delegate(&taitotz_renderer::draw_scanline, this), v[0], v[i-1], v[i]); } } while (!end); @@ -1434,7 +1435,7 @@ void taitotz_renderer::push_direct_poly_fifo(uint32_t data) for (int i=2; i < num_verts; i++) { - render_triangle(m_cliprect, render_delegate(&taitotz_renderer::draw_scanline_noz, this), 3, v[0], v[i-1], v[i]); + render_triangle<3>(m_cliprect, render_delegate(&taitotz_renderer::draw_scanline_noz, this), v[0], v[i-1], v[i]); } m_direct_fifo_ptr = 0; diff --git a/src/mame/drivers/vegas.cpp b/src/mame/drivers/vegas.cpp index d9377f4dd09..37be946e5d1 100644 --- a/src/mame/drivers/vegas.cpp +++ b/src/mame/drivers/vegas.cpp @@ -1924,7 +1924,8 @@ void vegas_state::vegascore(machine_config &config) voodoo_2_pci_device &voodoo(VOODOO_2_PCI(config, PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(2); voodoo.set_tmumem(4, 4); - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); M48T37(config, m_timekeeper); m_timekeeper->reset_cb().set(FUNC(vegas_state::watchdog_reset)); @@ -1968,7 +1969,8 @@ void vegas_state::vegasban(machine_config &config) vegas32m(config); voodoo_banshee_pci_device &voodoo(VOODOO_BANSHEE_PCI(config.replace(), PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(16); - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); } @@ -1982,7 +1984,8 @@ void vegas_state::vegasv3(machine_config &config) voodoo_3_pci_device &voodoo(VOODOO_3_PCI(config.replace(), PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(16); - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); } @@ -1999,7 +2002,8 @@ void vegas_state::denver(machine_config &config) voodoo_3_pci_device &voodoo(VOODOO_3_PCI(config.replace(), PCI_ID_VIDEO, 0, m_maincpu, "screen")); voodoo.set_fbmem(16); - subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); + voodoo.set_status_cycles(1000); // optimization to consume extra cycles when polling status + subdevice(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(vegas_state::vblank_assert)); // TL16C552 UART NS16550(config, m_uart1, XTAL(1'843'200)); diff --git a/src/mame/drivers/viper.cpp b/src/mame/drivers/viper.cpp index 346b2d2eea0..9948acbeb88 100644 --- a/src/mame/drivers/viper.cpp +++ b/src/mame/drivers/viper.cpp @@ -354,7 +354,7 @@ some other components. It will be documented at a later date. #include "machine/lpci.h" #include "machine/timekpr.h" #include "machine/timer.h" -#include "video/voodoo.h" +#include "video/voodoo_banshee.h" #include "emupal.h" #include "screen.h" #include "speaker.h" @@ -582,50 +582,7 @@ private: uint32_t viper_state::screen_update_viper(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - return m_voodoo->voodoo_update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; -} - -#ifdef UNUSED_FUNCTION -static inline uint64_t read64le_with_32smle_device_handler(read32sm_delegate handler, offs_t offset, uint64_t mem_mask) -{ - uint64_t result = 0; - if (ACCESSING_BITS_0_31) - result |= (uint64_t)(handler)(offset * 2 + 0) << 0; - if (ACCESSING_BITS_32_63) - result |= (uint64_t)(handler)(offset * 2 + 1) << 32; - return result; -} - - -static inline uint64_t read64le_with_32sle_device_handler(read32s_delegate handler, offs_t offset, uint64_t mem_mask) -{ - uint64_t result = 0; - if (ACCESSING_BITS_0_31) - result |= (uint64_t)(handler)(offset * 2 + 0, mem_mask >> 0) << 0; - if (ACCESSING_BITS_32_63) - result |= (uint64_t)(handler)(offset * 2 + 1, mem_mask >> 32) << 32; - return result; -} - - -static inline void write64le_with_32sle_device_handler(write32s_delegate handler, offs_t offset, uint64_t data, uint64_t mem_mask) -{ - if (ACCESSING_BITS_0_31) - handler(offset * 2 + 0, data >> 0, mem_mask >> 0); - if (ACCESSING_BITS_32_63) - handler(offset * 2 + 1, data >> 32, mem_mask >> 32); -} -#endif - -static inline uint64_t read64be_with_32smle_device_handler(read32sm_delegate handler, offs_t offset, uint64_t mem_mask) -{ - mem_mask = swapendian_int64(mem_mask); - uint64_t result = 0; - if (ACCESSING_BITS_0_31) - result = (uint64_t)(handler)(offset * 2); - if (ACCESSING_BITS_32_63) - result |= (uint64_t)(handler)(offset * 2 + 1) << 32; - return swapendian_int64(result); + return m_voodoo->update(bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; } static inline uint64_t read64be_with_32sle_device_handler(read32s_delegate handler, offs_t offset, uint64_t mem_mask) @@ -1744,35 +1701,35 @@ void viper_state::voodoo3_pci_w(int function, int reg, uint32_t data, uint32_t m uint64_t viper_state::voodoo3_io_r(offs_t offset, uint64_t mem_mask) { - return read64be_with_32sle_device_handler(read32s_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_io_r)), offset, mem_mask); + return read64be_with_32sle_device_handler(read32s_delegate(*m_voodoo, FUNC(voodoo_3_device::read_io)), offset, mem_mask); } void viper_state::voodoo3_io_w(offs_t offset, uint64_t data, uint64_t mem_mask) { // printf("voodoo3_io_w: %08X%08X, %08X at %08X\n", (uint32_t)(data >> 32), (uint32_t)(data), offset, m_maincpu->pc()); - write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_io_w)), offset, data, mem_mask); + write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::write_io)), offset, data, mem_mask); } uint64_t viper_state::voodoo3_r(offs_t offset, uint64_t mem_mask) { - return read64be_with_32sle_device_handler(read32s_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_r)), offset, mem_mask); + return read64be_with_32sle_device_handler(read32s_delegate(*m_voodoo, FUNC(voodoo_3_device::read)), offset, mem_mask); } void viper_state::voodoo3_w(offs_t offset, uint64_t data, uint64_t mem_mask) { // printf("voodoo3_w: %08X%08X, %08X at %08X\n", (uint32_t)(data >> 32), (uint32_t)(data), offset, m_maincpu->pc()); - write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_w)), offset, data, mem_mask); + write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::write)), offset, data, mem_mask); } uint64_t viper_state::voodoo3_lfb_r(offs_t offset, uint64_t mem_mask) { - return read64be_with_32smle_device_handler(read32sm_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_fb_r)), offset, mem_mask); + return read64be_with_32sle_device_handler(read32s_delegate(*m_voodoo, FUNC(voodoo_3_device::read_lfb)), offset, mem_mask); } void viper_state::voodoo3_lfb_w(offs_t offset, uint64_t data, uint64_t mem_mask) { // printf("voodoo3_lfb_w: %08X%08X, %08X at %08X\n", (uint32_t)(data >> 32), (uint32_t)(data), offset, m_maincpu->pc()); - write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::banshee_fb_w)), offset, data, mem_mask); + write64be_with_32sle_device_handler(write32s_delegate(*m_voodoo, FUNC(voodoo_3_device::write_lfb)), offset, data, mem_mask); } @@ -2457,10 +2414,11 @@ void viper_state::viper(machine_config &config) ATA_INTERFACE(config, m_ata).options(ata_devices, "hdd", nullptr, true); - VOODOO_3(config, m_voodoo, STD_VOODOO_3_CLOCK); + VOODOO_3(config, m_voodoo, voodoo_3_device::NOMINAL_CLOCK); m_voodoo->set_fbmem(8); - m_voodoo->set_screen_tag("screen"); - m_voodoo->set_cpu_tag("maincpu"); + m_voodoo->set_screen("screen"); + m_voodoo->set_cpu("maincpu"); + m_voodoo->set_status_cycles(1000); // optimization to consume extra cycles when polling status m_voodoo->vblank_callback().set(FUNC(viper_state::voodoo_vblank)); m_voodoo->pciint_callback().set(FUNC(viper_state::voodoo_pciint)); diff --git a/src/mame/includes/gaelco3d.h b/src/mame/includes/gaelco3d.h index 24005639cab..d4394d99a0d 100644 --- a/src/mame/includes/gaelco3d.h +++ b/src/mame/includes/gaelco3d.h @@ -74,7 +74,7 @@ private: float z0; }; - class gaelco3d_renderer : public poly_manager + class gaelco3d_renderer : public poly_manager { public: gaelco3d_renderer(gaelco3d_state &state); diff --git a/src/mame/includes/galastrm.h b/src/mame/includes/galastrm.h index f7f96a6a8ba..e4ddf0bc050 100644 --- a/src/mame/includes/galastrm.h +++ b/src/mame/includes/galastrm.h @@ -23,7 +23,7 @@ struct gs_poly_data bitmap_ind16* texbase; }; -class galastrm_renderer : public poly_manager +class galastrm_renderer : public poly_manager { public: galastrm_renderer(galastrm_state &state); diff --git a/src/mame/includes/hng64.h b/src/mame/includes/hng64.h index b6da75a3151..13ed54c51a1 100644 --- a/src/mame/includes/hng64.h +++ b/src/mame/includes/hng64.h @@ -113,7 +113,7 @@ struct hng64_poly_data class hng64_state; -class hng64_poly_renderer : public poly_manager +class hng64_poly_renderer : public poly_manager { public: hng64_poly_renderer(hng64_state& state); diff --git a/src/mame/includes/midvunit.h b/src/mame/includes/midvunit.h index ba4077bb656..b5e3f95cad2 100644 --- a/src/mame/includes/midvunit.h +++ b/src/mame/includes/midvunit.h @@ -28,7 +28,7 @@ struct midvunit_object_data class midvunit_state; -class midvunit_renderer : public poly_manager +class midvunit_renderer : public poly_manager { public: midvunit_renderer(midvunit_state &state); diff --git a/src/mame/includes/midzeus.h b/src/mame/includes/midzeus.h index 9dd11f433e3..e2ae9a1209a 100644 --- a/src/mame/includes/midzeus.h +++ b/src/mame/includes/midzeus.h @@ -42,7 +42,7 @@ struct mz_poly_extra_data class midzeus_state; -class midzeus_renderer : public poly_manager +class midzeus_renderer : public poly_manager { public: midzeus_renderer(midzeus_state &state); diff --git a/src/mame/includes/model2.h b/src/mame/includes/model2.h index 9a0deff5935..79c2b7b31ef 100644 --- a/src/mame/includes/model2.h +++ b/src/mame/includes/model2.h @@ -629,7 +629,7 @@ static inline u16 get_texel( u32 base_x, u32 base_y, int x, int y, u32 *sheet ) } // 0x10000 = size of the tri_sorted_list array -class model2_renderer : public poly_manager +class model2_renderer : public poly_manager { public: typedef void (model2_renderer::*scanline_render_func)(int32_t scanline, const extent_t& extent, const m2_poly_extra_data& object, int threadid); @@ -638,7 +638,7 @@ public: using triangle = model2_state::triangle; model2_renderer(model2_state& state) - : poly_manager(state.machine()) + : poly_manager(state.machine()) , m_state(state) , m_destmap(512, 512) { diff --git a/src/mame/includes/model3.h b/src/mame/includes/model3.h index ed7afad7dbc..af8db0dfacd 100644 --- a/src/mame/includes/model3.h +++ b/src/mame/includes/model3.h @@ -78,11 +78,11 @@ struct model3_polydata class model3_state; -class model3_renderer : public poly_manager +class model3_renderer : public poly_manager { public: model3_renderer(running_machine &machine, int width, int height) - : poly_manager(machine) + : poly_manager(machine) { m_fb = std::make_unique(width, height); m_zb = std::make_unique(width, height); diff --git a/src/mame/includes/namcos22.h b/src/mame/includes/namcos22.h index cc522119297..63b039c0186 100644 --- a/src/mame/includes/namcos22.h +++ b/src/mame/includes/namcos22.h @@ -137,7 +137,7 @@ struct namcos22_object_data class namcos22_state; -class namcos22_renderer : public poly_manager +class namcos22_renderer : public poly_manager { public: namcos22_renderer(namcos22_state &state); diff --git a/src/mame/includes/xbox_nv2a.h b/src/mame/includes/xbox_nv2a.h index 0ba4ec7586f..01a8fdd0672 100644 --- a/src/mame/includes/xbox_nv2a.h +++ b/src/mame/includes/xbox_nv2a.h @@ -348,10 +348,10 @@ objects have methods used to do drawing most methods set parameters, others actually draw */ -class nv2a_rasterizer : public poly_manager +class nv2a_rasterizer : public poly_manager { public: - nv2a_rasterizer(running_machine &machine) : poly_manager(machine) + nv2a_rasterizer(running_machine &machine) : poly_manager(machine) { } }; diff --git a/src/mame/machine/konppc.cpp b/src/mame/machine/konppc.cpp index d7525801d10..c372c29e856 100644 --- a/src/mame/machine/konppc.cpp +++ b/src/mame/machine/konppc.cpp @@ -436,7 +436,7 @@ void konppc_device::nwk_fifo_0_w(offs_t offset, uint32_t data, uint32_t mem_mask } else { - m_voodoo[0]->voodoo_w(offset ^ 0x80000, data, mem_mask); + m_voodoo[0]->write(offset ^ 0x80000, data, mem_mask); } } @@ -453,7 +453,7 @@ void konppc_device::nwk_fifo_1_w(offs_t offset, uint32_t data, uint32_t mem_mask } else { - m_voodoo[1]->voodoo_w(offset ^ 0x80000, data, mem_mask); + m_voodoo[1]->write(offset ^ 0x80000, data, mem_mask); } } @@ -465,7 +465,7 @@ uint32_t konppc_device::nwk_voodoo_0_r(offs_t offset) } else { - return m_voodoo[0]->voodoo_r(offset); + return m_voodoo[0]->read(offset); } } @@ -477,7 +477,7 @@ uint32_t konppc_device::nwk_voodoo_1_r(offs_t offset) } else { - return m_voodoo[1]->voodoo_r(offset); + return m_voodoo[1]->read(offset); } } @@ -494,7 +494,7 @@ void konppc_device::nwk_voodoo_0_w(offs_t offset, uint32_t data, uint32_t mem_ma } else { - m_voodoo[0]->voodoo_w(offset, data, mem_mask); + m_voodoo[0]->write(offset, data, mem_mask); } } @@ -511,6 +511,6 @@ void konppc_device::nwk_voodoo_1_w(offs_t offset, uint32_t data, uint32_t mem_ma } else { - m_voodoo[1]->voodoo_w(offset, data, mem_mask); + m_voodoo[1]->write(offset, data, mem_mask); } } diff --git a/src/mame/machine/konppc.h b/src/mame/machine/konppc.h index c397a02bbd1..41b6e49ad9a 100644 --- a/src/mame/machine/konppc.h +++ b/src/mame/machine/konppc.h @@ -73,7 +73,7 @@ private: // device finders optional_device_array m_dsp; optional_device_array m_k033906; - optional_device_array m_voodoo; + optional_device_array m_voodoo; // internal state uint32_t dsp_comm_ppc[MAX_CG_BOARDS][2]; diff --git a/src/mame/machine/n64.cpp b/src/mame/machine/n64.cpp index 35459505d3b..f157cb104ed 100644 --- a/src/mame/machine/n64.cpp +++ b/src/mame/machine/n64.cpp @@ -4,6 +4,7 @@ #include "emu.h" #include "debugger.h" +#include "screen.h" #include "cpu/mips/mips3.h" #include "cpu/mips/mips3com.h" #include "includes/n64.h" diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 74af8e4eb71..9618cb2f36a 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -13,6 +13,7 @@ #include "debugger.h" #include "romload.h" +#include "screen.h" #include diff --git a/src/mame/video/gaelco3d.cpp b/src/mame/video/gaelco3d.cpp index 241c8da4b22..eb68c90a615 100644 --- a/src/mame/video/gaelco3d.cpp +++ b/src/mame/video/gaelco3d.cpp @@ -26,7 +26,7 @@ gaelco3d_state::gaelco3d_renderer::gaelco3d_renderer(gaelco3d_state &state) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state), m_screenbits(state.m_screen->width(), state.m_screen->height()), m_zbuffer(state.m_screen->width(), state.m_screen->height()), @@ -185,15 +185,15 @@ void gaelco3d_state::gaelco3d_renderer::render_poly(screen_device &screen, uint3 /* special case: no Z buffering and no perspective correction */ if (color != 0x7f00 && z0 < 0 && ooz_dx == 0 && ooz_dy == 0) - render_triangle_fan(visarea, render_delegate(&gaelco3d_renderer::render_noz_noperspective, this), 0, vertnum, &vert[0]); + render_triangle_fan<0>(visarea, render_delegate(&gaelco3d_renderer::render_noz_noperspective, this), vertnum, &vert[0]); /* general case: non-alpha blended */ else if (color != 0x7f00) - render_triangle_fan(visarea, render_delegate(&gaelco3d_renderer::render_normal, this), 0, vertnum, &vert[0]); + render_triangle_fan<0>(visarea, render_delegate(&gaelco3d_renderer::render_normal, this), vertnum, &vert[0]); /* color 0x7f seems to be hard-coded as a 50% alpha blend */ else - render_triangle_fan(visarea, render_delegate(&gaelco3d_renderer::render_alphablend, this), 0, vertnum, &vert[0]); + render_triangle_fan<0>(visarea, render_delegate(&gaelco3d_renderer::render_alphablend, this), vertnum, &vert[0]); m_polygons += vertnum - 2; } diff --git a/src/mame/video/galastrm.cpp b/src/mame/video/galastrm.cpp index 63a1461ed91..e175c134959 100644 --- a/src/mame/video/galastrm.cpp +++ b/src/mame/video/galastrm.cpp @@ -8,7 +8,7 @@ galastrm_renderer::galastrm_renderer(galastrm_state& state) - : poly_manager(state.machine()) + : poly_manager(state.machine()) , m_state(state) , m_screenbits(state.m_screen->width(), state.m_screen->height()) { @@ -406,7 +406,7 @@ void galastrm_renderer::tc0610_rotate_draw(bitmap_ind16 &srcbitmap, const rectan gs_poly_data& extra = object_data_alloc(); extra.texbase = &srcbitmap; - render_polygon<4>(clip, render_delegate(&galastrm_renderer::tc0610_draw_scanline, this), 2, vert); + render_polygon<4, 2>(clip, render_delegate(&galastrm_renderer::tc0610_draw_scanline, this), vert); wait(); } diff --git a/src/mame/video/hng64_3d.hxx b/src/mame/video/hng64_3d.hxx index 68e5210d30c..32e1d31a318 100644 --- a/src/mame/video/hng64_3d.hxx +++ b/src/mame/video/hng64_3d.hxx @@ -7,7 +7,7 @@ // Polygon rasterizer interface hng64_poly_renderer::hng64_poly_renderer(hng64_state& state) - : poly_manager(state.machine()) + : poly_manager(state.machine()) , m_state(state) , m_colorBuffer3d(state.m_screen->visible_area().width(), state.m_screen->visible_area().height()) { @@ -1441,7 +1441,7 @@ void hng64_poly_renderer::drawShaded(polygon *p) pVert[2].p[2] = color.g(); pVert[2].p[3] = color.b(); - render_triangle(visibleArea, render_delegate(&hng64_poly_renderer::render_flat_scanline, this), 4, pVert[0], pVert[1], pVert[2]); + render_triangle<4>(visibleArea, render_delegate(&hng64_poly_renderer::render_flat_scanline, this), pVert[0], pVert[1], pVert[2]); } } else @@ -1497,7 +1497,7 @@ void hng64_poly_renderer::drawShaded(polygon *p) pVert[2].p[5] = pvjp1.texCoords[0]; pVert[2].p[6] = pvjp1.texCoords[1]; - render_triangle(visibleArea, render_delegate(&hng64_poly_renderer::render_texture_scanline, this), 7, pVert[0], pVert[1], pVert[2]); + render_triangle<7>(visibleArea, render_delegate(&hng64_poly_renderer::render_texture_scanline, this), pVert[0], pVert[1], pVert[2]); } } } diff --git a/src/mame/video/k001005.cpp b/src/mame/video/k001005.cpp index 6a3742f266e..d6728ec7281 100644 --- a/src/mame/video/k001005.cpp +++ b/src/mame/video/k001005.cpp @@ -2,6 +2,7 @@ // copyright-holders:David Haywood #include "emu.h" #include "k001005.h" +#include "screen.h" /*****************************************************************************/ /* Konami K001005 Polygon Renderer (KS10071) */ @@ -24,7 +25,7 @@ k001005_renderer::k001005_renderer(device_t &parent, screen_device &screen, device_t *k001006) - : poly_manager(screen) + : poly_manager(screen.machine()) { m_k001006 = k001006; @@ -293,7 +294,7 @@ void k001005_renderer::render_polygons() vertex3 = &v[2]; } - render_triangle(m_cliprect, rd_scan_tex, 6, *vertex1, *vertex2, *vertex3); + render_triangle<6>(m_cliprect, rd_scan_tex, *vertex1, *vertex2, *vertex3); memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); @@ -330,8 +331,8 @@ void k001005_renderer::render_polygons() vertex4 = &v[3]; } - render_triangle(m_cliprect, rd_scan_tex, 6, *vertex1, *vertex2, *vertex3); - render_triangle(m_cliprect, rd_scan_tex, 6, *vertex3, *vertex4, *vertex1); + render_triangle<6>(m_cliprect, rd_scan_tex, *vertex1, *vertex2, *vertex3); + render_triangle<6>(m_cliprect, rd_scan_tex, *vertex3, *vertex4, *vertex1); memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); @@ -418,7 +419,7 @@ void k001005_renderer::render_polygons() if (new_verts == 1) { - render_triangle(m_cliprect, rd_scan_tex, 6, v[0], v[1], v[2]); + render_triangle<6>(m_cliprect, rd_scan_tex, v[0], v[1], v[2]); memcpy(&m_prev_v[1], &v[0], sizeof(vertex_t)); memcpy(&m_prev_v[2], &v[1], sizeof(vertex_t)); @@ -426,8 +427,8 @@ void k001005_renderer::render_polygons() } else if (new_verts == 2) { - render_triangle(m_cliprect, rd_scan_tex, 6, v[0], v[1], v[2]); - render_triangle(m_cliprect, rd_scan_tex, 6, v[2], v[3], v[0]); + render_triangle<6>(m_cliprect, rd_scan_tex, v[0], v[1], v[2]); + render_triangle<6>(m_cliprect, rd_scan_tex, v[2], v[3], v[0]); memcpy(&m_prev_v[0], &v[0], sizeof(vertex_t)); memcpy(&m_prev_v[1], &v[1], sizeof(vertex_t)); @@ -515,7 +516,7 @@ void k001005_renderer::render_polygons() vertex3 = &v[2]; } - render_triangle(m_cliprect, rd_scan, 3, *vertex1, *vertex2, *vertex3); + render_triangle<3>(m_cliprect, rd_scan, *vertex1, *vertex2, *vertex3); memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); @@ -552,8 +553,8 @@ void k001005_renderer::render_polygons() vertex4 = &v[3]; } - render_triangle(m_cliprect, rd_scan, 3, *vertex1, *vertex2, *vertex3); - render_triangle(m_cliprect, rd_scan, 3, *vertex3, *vertex4, *vertex1); + render_triangle<3>(m_cliprect, rd_scan, *vertex1, *vertex2, *vertex3); + render_triangle<3>(m_cliprect, rd_scan, *vertex3, *vertex4, *vertex1); memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); @@ -622,7 +623,7 @@ void k001005_renderer::render_polygons() if (new_verts == 1) { - render_triangle(m_cliprect, rd_scan, 3, v[0], v[1], v[2]); + render_triangle<3>(m_cliprect, rd_scan, v[0], v[1], v[2]); memcpy(&m_prev_v[1], &v[0], sizeof(vertex_t)); memcpy(&m_prev_v[2], &v[1], sizeof(vertex_t)); @@ -630,8 +631,8 @@ void k001005_renderer::render_polygons() } else if (new_verts == 2) { - render_triangle(m_cliprect, rd_scan, 3, v[0], v[1], v[2]); - render_triangle(m_cliprect, rd_scan, 3, v[2], v[3], v[0]); + render_triangle<3>(m_cliprect, rd_scan, v[0], v[1], v[2]); + render_triangle<3>(m_cliprect, rd_scan, v[2], v[3], v[0]); memcpy(&m_prev_v[0], &v[0], sizeof(vertex_t)); memcpy(&m_prev_v[1], &v[1], sizeof(vertex_t)); @@ -684,12 +685,12 @@ void k001005_renderer::render_polygons() if (poly_type == 0) { - render_triangle(m_cliprect, rd_scan_2d, 0, v[0], v[1], v[2]); + render_triangle<0>(m_cliprect, rd_scan_2d, v[0], v[1], v[2]); } else { - render_triangle(m_cliprect, rd_scan_2d, 0, v[0], v[1], v[2]); - render_triangle(m_cliprect, rd_scan_2d, 0, v[2], v[3], v[0]); + render_triangle<0>(m_cliprect, rd_scan_2d, v[0], v[1], v[2]); + render_triangle<0>(m_cliprect, rd_scan_2d, v[2], v[3], v[0]); } } else if (cmd == 0x8000008b) @@ -773,12 +774,12 @@ void k001005_renderer::render_polygons() if (poly_type == 0) { - render_triangle(m_cliprect, rd_scan_tex2d, 5, v[0], v[1], v[2]); + render_triangle<5>(m_cliprect, rd_scan_tex2d, v[0], v[1], v[2]); } else { - render_triangle(m_cliprect, rd_scan_tex2d, 5, v[0], v[1], v[2]); - render_triangle(m_cliprect, rd_scan_tex2d, 5, v[2], v[3], v[0]); + render_triangle<5>(m_cliprect, rd_scan_tex2d, v[0], v[1], v[2]); + render_triangle<5>(m_cliprect, rd_scan_tex2d, v[2], v[3], v[0]); } } else if (cmd == 0x80000106 || cmd == 0x80000121 || cmd == 0x80000126) @@ -826,12 +827,12 @@ void k001005_renderer::render_polygons() if (poly_type == 0) { - render_triangle(m_cliprect, rd_scan_gour_blend, 6, v[0], v[1], v[2]); + render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[0], v[1], v[2]); } else { - render_triangle(m_cliprect, rd_scan_gour_blend, 6, v[0], v[1], v[2]); - render_triangle(m_cliprect, rd_scan_gour_blend, 6, v[2], v[3], v[0]); + render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[0], v[1], v[2]); + render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[2], v[3], v[0]); } // TODO: can this poly type form strips? @@ -945,7 +946,7 @@ void k001005_renderer::render_polygons() vertex3 = &v[2]; } - render_triangle(m_cliprect, rd_scan_tex_gouraud, 10, *vertex1, *vertex2, *vertex3); + render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex1, *vertex2, *vertex3); memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); @@ -982,8 +983,8 @@ void k001005_renderer::render_polygons() vertex4 = &v[3]; } - render_triangle(m_cliprect, rd_scan_tex_gouraud, 10, *vertex1, *vertex2, *vertex3); - render_triangle(m_cliprect, rd_scan_tex_gouraud, 10, *vertex3, *vertex4, *vertex1); + render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex1, *vertex2, *vertex3); + render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex3, *vertex4, *vertex1); memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); @@ -1313,7 +1314,7 @@ void k001005_renderer::draw_scanline_gouraud_blend(int32_t scanline, const exten void k001005_renderer::draw_scanline_tex_gouraud(int32_t scanline, const extent_t& extent, const k001005_polydata& extradata, int threadid) -{ +{ k001006_device* k001006 = downcast(m_k001006); int tex_page = extradata.texture_page * 0x40000; diff --git a/src/mame/video/k001005.h b/src/mame/video/k001005.h index fd6427c4aa8..7ee4dd620a3 100644 --- a/src/mame/video/k001005.h +++ b/src/mame/video/k001005.h @@ -42,7 +42,7 @@ enum k001005_param }; -class k001005_renderer : public poly_manager +class k001005_renderer : public poly_manager { public: k001005_renderer(device_t &parent, screen_device &screen, device_t *k001006); diff --git a/src/mame/video/midvunit.cpp b/src/mame/video/midvunit.cpp index 4d8b8e977b6..389b5385d9c 100644 --- a/src/mame/video/midvunit.cpp +++ b/src/mame/video/midvunit.cpp @@ -26,7 +26,7 @@ midvunit_renderer::midvunit_renderer(midvunit_state &state) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state) { } @@ -365,7 +365,10 @@ void midvunit_renderer::process_dma_queue() objectdata.dither = ((m_state.m_dma_data[0] & 0x2000) != 0); /* render as a quad */ - render_polygon<4>(m_state.m_screen->visible_area(), callback, textured ? 2 : 0, vert); + if (textured) + render_polygon<4, 2>(m_state.m_screen->visible_area(), callback, vert); + else + render_polygon<4, 0>(m_state.m_screen->visible_area(), callback, vert); } diff --git a/src/mame/video/midzeus.cpp b/src/mame/video/midzeus.cpp index 0ae0d8c0233..4d1e518a1da 100644 --- a/src/mame/video/midzeus.cpp +++ b/src/mame/video/midzeus.cpp @@ -200,7 +200,7 @@ static inline uint8_t get_texel_alt_8bit(const void *base, int y, int x, int wid *************************************/ midzeus_renderer::midzeus_renderer(midzeus_state &state) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state) {} @@ -1131,7 +1131,7 @@ void midzeus_renderer::zeus_draw_quad(int long_fmt, const uint32_t *databuffer, } } - numverts = m_state.m_poly->zclip_if_less(4, &vert[0], &clipvert[0], 4, 512.0f); + numverts = m_state.m_poly->zclip_if_less<4>(4, &vert[0], &clipvert[0], 512.0f); if (numverts < 3) return; @@ -1197,15 +1197,14 @@ void midzeus_renderer::zeus_draw_quad(int long_fmt, const uint32_t *databuffer, // Note: Before being upgraded to the new polygon rasterizing code, this function call was // a poly_render_quad_fan. It appears as though the new code defaults to a fan if // the template argument is 4, but keep an eye out for missing quads. - m_state.m_poly->render_polygon<4>(m_state.m_zeus_cliprect, + m_state.m_poly->render_polygon<4, 4>(m_state.m_zeus_cliprect, render_delegate(&midzeus_renderer::render_poly, this), - 4, clipvert); } void midzeus_renderer::zeus_draw_debug_quad(const rectangle& rect, const vertex_t *vert) { - m_state.m_poly->render_polygon<4>(rect, render_delegate(&midzeus_renderer::render_poly_solid_fixedz, this), 0, vert); + m_state.m_poly->render_polygon<4, 0>(rect, render_delegate(&midzeus_renderer::render_poly_solid_fixedz, this), vert); } diff --git a/src/mame/video/model2.cpp b/src/mame/video/model2.cpp index 7749f149bdd..4f97141cb89 100644 --- a/src/mame/video/model2.cpp +++ b/src/mame/video/model2.cpp @@ -811,28 +811,28 @@ void model2_renderer::model2_3d_render(triangle *tri, const rectangle &cliprect) // I was unable to make it work when converting to the new polygon rasterizer interface. switch (renderer) { - case 0: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_0, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 1: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_1, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 2: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_2, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 3: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_3, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 4: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_4, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 5: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_5, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 6: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_6, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; - case 7: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_7, this), 3, tri->v[0], tri->v[1], tri->v[2]); break; + case 0: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_0, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 1: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_1, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 2: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_2, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 3: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_3, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 4: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_4, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 5: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_5, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 6: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_6, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 7: render_triangle<3>(vp, render_delegate(&model2_renderer::model2_3d_render_7, this), tri->v[0], tri->v[1], tri->v[2]); break; } } else { switch (renderer) { - case 0: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_0, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 1: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_1, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 2: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_2, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 3: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_3, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 4: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_4, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 5: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_5, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 6: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_6, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; - case 7: render_triangle(vp, render_delegate(&model2_renderer::model2_3d_render_7, this), 0, tri->v[0], tri->v[1], tri->v[2]); break; + case 0: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_0, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 1: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_1, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 2: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_2, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 3: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_3, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 4: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_4, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 5: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_5, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 6: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_6, this), tri->v[0], tri->v[1], tri->v[2]); break; + case 7: render_triangle<0>(vp, render_delegate(&model2_renderer::model2_3d_render_7, this), tri->v[0], tri->v[1], tri->v[2]); break; } } } diff --git a/src/mame/video/model3.cpp b/src/mame/video/model3.cpp index e8d7e5ed773..8b58c2a2b12 100644 --- a/src/mame/video/model3.cpp +++ b/src/mame/video/model3.cpp @@ -2063,14 +2063,14 @@ void model3_renderer::draw_opaque_triangles(const m3_triangle* tris, int num_tri if (tri->param & TRI_PARAM_ALPHA_TEST) { - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_contour, this), 5, v[0], v[1], v[2]); + render_triangle<5>(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_contour, this), v[0], v[1], v[2]); } else { if (tri->param & TRI_PARAM_COLOR_MOD) - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_colormod, this), 5, v[0], v[1], v[2]); + render_triangle<5>(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_colormod, this), v[0], v[1], v[2]); else - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex, this), 5, v[0], v[1], v[2]); + render_triangle<5>(cliprect, render_delegate(&model3_renderer::draw_scanline_tex, this), v[0], v[1], v[2]); } } else @@ -2086,7 +2086,7 @@ void model3_renderer::draw_opaque_triangles(const m3_triangle* tris, int num_tri model3_polydata &extra = object_data_alloc(); extra.color = tri->color; - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_solid, this), 2, v[0], v[1], v[2]); + render_triangle<2>(cliprect, render_delegate(&model3_renderer::draw_scanline_solid, this), v[0], v[1], v[2]); } } } @@ -2125,7 +2125,7 @@ void model3_renderer::draw_alpha_triangles(const m3_triangle* tris, int num_tris extra.transparency = tri->transparency; extra.texture_param = tri->param; - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_alpha, this), 5, v[0], v[1], v[2]); + render_triangle<5>(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_alpha, this), v[0], v[1], v[2]); } else { @@ -2141,7 +2141,7 @@ void model3_renderer::draw_alpha_triangles(const m3_triangle* tris, int num_tris extra.color = tri->color; extra.transparency = tri->transparency; - render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_solid_trans, this), 2, v[0], v[1], v[2]); + render_triangle<2>(cliprect, render_delegate(&model3_renderer::draw_scanline_solid_trans, this), v[0], v[1], v[2]); } } } diff --git a/src/mame/video/n64.cpp b/src/mame/video/n64.cpp index 88f0548c060..1e4a0a75afe 100644 --- a/src/mame/video/n64.cpp +++ b/src/mame/video/n64.cpp @@ -28,6 +28,7 @@ TODO: #include "includes/n64.h" #include "video/rdpblend.h" #include "video/rdptpipe.h" +#include "screen.h" #include @@ -3140,7 +3141,7 @@ void n64_rdp::process_command_list() /*****************************************************************************/ -n64_rdp::n64_rdp(n64_state &state, uint32_t* rdram, uint32_t* dmem) : poly_manager(state.machine()) +n64_rdp::n64_rdp(n64_state &state, uint32_t* rdram, uint32_t* dmem) : poly_manager(state.machine()) { ignore = false; dolog = false; diff --git a/src/mame/video/n64.h b/src/mame/video/n64.h index 8aaa6d6d6f1..6193514433c 100644 --- a/src/mame/video/n64.h +++ b/src/mame/video/n64.h @@ -131,7 +131,7 @@ typedef void (*rdp_command_t)(uint64_t w1); class n64_state; -class n64_rdp : public poly_manager +class n64_rdp : public poly_manager { public: n64_rdp(n64_state &state, uint32_t* rdram, uint32_t* dmem); diff --git a/src/mame/video/namcos22.cpp b/src/mame/video/namcos22.cpp index ddf12f188dd..c8354a73747 100644 --- a/src/mame/video/namcos22.cpp +++ b/src/mame/video/namcos22.cpp @@ -12,7 +12,7 @@ // poly constructor namcos22_renderer::namcos22_renderer(namcos22_state &state) - : poly_manager(state.machine()), + : poly_manager(state.machine()), m_state(state) { init(); @@ -260,7 +260,7 @@ void namcos22_renderer::poly3d_drawquad(screen_device &screen, bitmap_rgb32 &bit v[vertnum].p[3] = node->data.quad.v[vertnum].bri; } - clipverts = zclip_if_less(4, v, clipv, 4, 10.0f); + clipverts = zclip_if_less<4>(4, v, clipv, 10.0f); assert(clipverts <= std::size(clipv)); if (clipverts < 3) return; @@ -390,7 +390,7 @@ void namcos22_renderer::poly3d_drawquad(screen_device &screen, bitmap_rgb32 &bit } } - render_triangle_fan(m_cliprect, render_delegate(&namcos22_renderer::renderscanline_uvi_full, this), 4, clipverts, clipv); + render_triangle_fan<4>(m_cliprect, render_delegate(&namcos22_renderer::renderscanline_uvi_full, this), clipverts, clipv); } @@ -468,7 +468,7 @@ void namcos22_renderer::poly3d_drawsprite( extra.fogcolor.set(0, m_state.m_fog_r, m_state.m_fog_g, m_state.m_fog_b); } - render_triangle_fan(m_cliprect, render_delegate(&namcos22_renderer::renderscanline_sprite, this), 2, 4, vert); + render_triangle_fan<2>(m_cliprect, render_delegate(&namcos22_renderer::renderscanline_sprite, this), 4, vert); } } diff --git a/src/mame/video/tc0780fpa.cpp b/src/mame/video/tc0780fpa.cpp index 3cc9da0d271..7145c581b7d 100644 --- a/src/mame/video/tc0780fpa.cpp +++ b/src/mame/video/tc0780fpa.cpp @@ -5,13 +5,14 @@ #include "emu.h" #include "tc0780fpa.h" +#include "screen.h" #define POLY_FIFO_SIZE 32 tc0780fpa_renderer::tc0780fpa_renderer(device_t &parent, screen_device &screen, const uint8_t *texture_ram) - : poly_manager(screen) + : poly_manager(screen.machine()) { int width = screen.width(); int height = screen.height(); @@ -220,11 +221,11 @@ void tc0780fpa_renderer::render(uint16_t *polygon_fifo, int length) vert[1].p[1] == vert[2].p[1]) { // optimization: all colours the same -> render solid - render_triangle(m_cliprect, render_delegate(&tc0780fpa_renderer::render_solid_scan, this), 2, vert[0], vert[1], vert[2]); + render_triangle<2>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_solid_scan, this), vert[0], vert[1], vert[2]); } else { - render_triangle(m_cliprect, render_delegate(&tc0780fpa_renderer::render_shade_scan, this), 2, vert[0], vert[1], vert[2]); + render_triangle<2>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_shade_scan, this), vert[0], vert[1], vert[2]); } } break; @@ -275,7 +276,7 @@ void tc0780fpa_renderer::render(uint16_t *polygon_fifo, int length) if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000) { - render_triangle(m_cliprect, render_delegate(&tc0780fpa_renderer::render_texture_scan, this), 4, vert[0], vert[1], vert[2]); + render_triangle<4>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_texture_scan, this), vert[0], vert[1], vert[2]); } break; } @@ -316,11 +317,11 @@ void tc0780fpa_renderer::render(uint16_t *polygon_fifo, int length) vert[2].p[1] == vert[3].p[1]) { // optimization: all colours the same -> render solid - render_polygon<4>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_solid_scan, this), 2, vert); + render_polygon<4, 2>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_solid_scan, this), vert); } else { - render_polygon<4>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_shade_scan, this), 2, vert); + render_polygon<4, 2>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_shade_scan, this), vert); } } break; @@ -377,7 +378,7 @@ void tc0780fpa_renderer::render(uint16_t *polygon_fifo, int length) if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000) { - render_polygon<4>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_texture_scan, this), 4, vert); + render_polygon<4, 4>(m_cliprect, render_delegate(&tc0780fpa_renderer::render_texture_scan, this), vert); } break; } diff --git a/src/mame/video/tc0780fpa.h b/src/mame/video/tc0780fpa.h index 5c1c55f01b8..85b22d0986e 100644 --- a/src/mame/video/tc0780fpa.h +++ b/src/mame/video/tc0780fpa.h @@ -18,7 +18,7 @@ struct tc0780fpa_polydata }; -class tc0780fpa_renderer : public poly_manager +class tc0780fpa_renderer : public poly_manager { public: tc0780fpa_renderer(device_t &parent, screen_device &screen, const uint8_t *texture_ram); diff --git a/src/mame/video/xbox_nv2a.cpp b/src/mame/video/xbox_nv2a.cpp index ab257da94f1..48811fe5afa 100644 --- a/src/mame/video/xbox_nv2a.cpp +++ b/src/mame/video/xbox_nv2a.cpp @@ -2792,7 +2792,7 @@ uint32_t nv2a_renderer::render_triangle_culling(const rectangle &cliprect, nv2av NV2A_GL_CULL_FACE face = NV2A_GL_CULL_FACE::FRONT; if (backface_culling_enabled == false) - return rasterizer.render_triangle(cliprect, render_spans_callback, (int)VERTEX_PARAMETER::ALL, _v1, _v2, _v3); + return rasterizer.render_triangle(cliprect, render_spans_callback, _v1, _v2, _v3); if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT_AND_BACK) { triangles_bfculled++; @@ -2818,10 +2818,10 @@ uint32_t nv2a_renderer::render_triangle_culling(const rectangle &cliprect, nv2av } if (face == NV2A_GL_CULL_FACE::FRONT) if (backface_culling_culled == NV2A_GL_CULL_FACE::BACK) - return rasterizer.render_triangle(cliprect, render_spans_callback, (int)VERTEX_PARAMETER::ALL, _v1, _v2, _v3); + return rasterizer.render_triangle(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(cliprect, render_spans_callback, (int)VERTEX_PARAMETER::ALL, _v1, _v2, _v3); + return rasterizer.render_triangle(cliprect, render_spans_callback, _v1, _v2, _v3); triangles_bfculled++; return 0; } diff --git a/src/osd/osdcore.cpp b/src/osd/osdcore.cpp index fd696706e6b..51a9aaf207c 100644 --- a/src/osd/osdcore.cpp +++ b/src/osd/osdcore.cpp @@ -139,7 +139,13 @@ void osd_vprintf_debug(util::format_argument_pack const &args) osd_ticks_t osd_ticks() { +#ifdef WIN32 + LARGE_INTEGER val; + QueryPerformanceCounter(&val); + return val.QuadPart; +#else return std::chrono::high_resolution_clock::now().time_since_epoch().count(); +#endif } @@ -149,7 +155,13 @@ osd_ticks_t osd_ticks() osd_ticks_t osd_ticks_per_second() { +#ifdef WIN32 + LARGE_INTEGER val; + QueryPerformanceFrequency(&val); + return val.QuadPart; +#else return std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num; +#endif } //============================================================