summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Aaron Giles <aaronsgiles@users.noreply.github.com>2021-07-08 18:35:00 -0700
committer GitHub <noreply@github.com>2021-07-09 11:35:00 +1000
commit6ffc98289c9466cb01941c05a5b3088ac022a0b6 (patch)
tree62bc23850838f7f48d47f555292ea409f15f51ae /src
parente9a86fc9fe55d45265b39fa7368e1645629aa314 (diff)
video/voodoo.cpp: Major rewrite: (#8267)
* Changed to use modern poly.h instead of polylgcy.h. * Moved helper classes into separate voodoo namespace. * Derived device classes from video_device_interface. * Split classes so that later versions derive from earlier versions. * Created device maps to be directly included. * Redesigned register mapping to use helper classes and delegates. * Rewrote rasterizers to use C++ templates instead of macros. * Added logic to compute equations for color/texture combine units. * Added special generic identity-texel rasterizer cases. * Removed pipeline stalls on texture and palette changes. * Removed pipeline stalls on most all parameter changes. * Generally re-thought and cleaned up logic throughout. * Parameterized cycle stealing on status reads; updated all existing voodoo consumers to configure it as it was before. -vidoe/poly.h: Various improvements: * Exposed poly_array class for broader use. * Changed poly_array to intelligently determine maximum size. * Added logic to track multiple "last" instances in poly_array. * Extended logic to support up to 16m work items. * Removed MaxPolys parameter from poly_manager template. * Added Flags parameter to poly_manager template. * Added POLY_FLAG_NO_CLIPPING flag to remove clipping code when not needed. * poly_manager now supports a MaxParams value of 0. * Made paramcount a template parameter for render_* functions. * Added reset_after_wait() method to be overridden by derived classes. * Switched to using std:: helpers instead of internal methods. * Removed useless dependency on screen_device. * TRACK_POLY_WAITS now produces more complete statistics. -video/polylgcy.cpp: Removed legacy implementation of polygon renderer. -machine/gt64xxx.cpp: Prevent lockups by disallowing 0-duration timers. -machine/pci.cpp: Added support for adding subdevice maps directly. -emu/video/rgbsse.h: Improved min/max for SSE4.1+ and scale+clamp operations for all. -emu/vidoe/rgbutil.h: Made palette expansion constexpr and added argbexpand function. -osd/osdcore.cpp: Changed osd_ticks to use QueryPerformanceCounter on Windows since the mingw std::chrono::high_resolution_clock is anything but.
Diffstat (limited to 'src')
-rw-r--r--src/devices/machine/gt64xxx.cpp8
-rw-r--r--src/devices/machine/k033906.cpp2
-rw-r--r--src/devices/machine/k033906.h2
-rw-r--r--src/devices/machine/pci.h4
-rw-r--r--src/devices/video/poly.h947
-rw-r--r--src/devices/video/polylgcy.cpp1376
-rw-r--r--src/devices/video/polylgcy.h165
-rw-r--r--src/devices/video/vooddefs.ipp3181
-rw-r--r--src/devices/video/voodoo.cpp8370
-rw-r--r--src/devices/video/voodoo.h2009
-rw-r--r--src/devices/video/voodoo_2.cpp1722
-rw-r--r--src/devices/video/voodoo_2.h249
-rw-r--r--src/devices/video/voodoo_banshee.cpp1907
-rw-r--r--src/devices/video/voodoo_banshee.h185
-rw-r--r--src/devices/video/voodoo_pci.cpp165
-rw-r--r--src/devices/video/voodoo_pci.h76
-rw-r--r--src/devices/video/voodoo_rast.ipp615
-rw-r--r--src/devices/video/voodoo_regs.h1436
-rw-r--r--src/devices/video/voodoo_render.cpp2953
-rw-r--r--src/devices/video/voodoo_render.h662
-rw-r--r--src/devices/video/zeus2.cpp7
-rw-r--r--src/devices/video/zeus2.h2
-rw-r--r--src/emu/video/rgbsse.cpp2
-rw-r--r--src/emu/video/rgbsse.h66
-rw-r--r--src/emu/video/rgbutil.h2
-rw-r--r--src/lib/util/palette.h34
-rw-r--r--src/mame/drivers/atarisy4.cpp6
-rw-r--r--src/mame/drivers/cobra.cpp16
-rw-r--r--src/mame/drivers/funkball.cpp13
-rw-r--r--src/mame/drivers/gticlub.cpp22
-rw-r--r--src/mame/drivers/hornet.cpp36
-rw-r--r--src/mame/drivers/iteagle.cpp4
-rw-r--r--src/mame/drivers/magictg.cpp26
-rw-r--r--src/mame/drivers/namcos23.cpp15
-rw-r--r--src/mame/drivers/nwk-tr.cpp14
-rw-r--r--src/mame/drivers/rollext.cpp17
-rw-r--r--src/mame/drivers/savquest.cpp15
-rw-r--r--src/mame/drivers/seattle.cpp7
-rw-r--r--src/mame/drivers/taitopjc.cpp1
-rw-r--r--src/mame/drivers/taitotz.cpp9
-rw-r--r--src/mame/drivers/vegas.cpp12
-rw-r--r--src/mame/drivers/viper.cpp66
-rw-r--r--src/mame/includes/gaelco3d.h2
-rw-r--r--src/mame/includes/galastrm.h2
-rw-r--r--src/mame/includes/hng64.h2
-rw-r--r--src/mame/includes/midvunit.h2
-rw-r--r--src/mame/includes/midzeus.h2
-rw-r--r--src/mame/includes/model2.h4
-rw-r--r--src/mame/includes/model3.h4
-rw-r--r--src/mame/includes/namcos22.h2
-rw-r--r--src/mame/includes/xbox_nv2a.h4
-rw-r--r--src/mame/machine/konppc.cpp12
-rw-r--r--src/mame/machine/konppc.h2
-rw-r--r--src/mame/machine/n64.cpp1
-rw-r--r--src/mame/machine/xbox.cpp1
-rw-r--r--src/mame/video/gaelco3d.cpp8
-rw-r--r--src/mame/video/galastrm.cpp4
-rw-r--r--src/mame/video/hng64_3d.hxx6
-rw-r--r--src/mame/video/k001005.cpp53
-rw-r--r--src/mame/video/k001005.h2
-rw-r--r--src/mame/video/midvunit.cpp7
-rw-r--r--src/mame/video/midzeus.cpp9
-rw-r--r--src/mame/video/model2.cpp32
-rw-r--r--src/mame/video/model3.cpp12
-rw-r--r--src/mame/video/n64.cpp3
-rw-r--r--src/mame/video/n64.h2
-rw-r--r--src/mame/video/namcos22.cpp8
-rw-r--r--src/mame/video/tc0780fpa.cpp15
-rw-r--r--src/mame/video/tc0780fpa.h2
-rw-r--r--src/mame/video/xbox_nv2a.cpp6
-rw-r--r--src/osd/osdcore.cpp12
71 files changed, 13315 insertions, 13332 deletions
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<voodoo_device> m_voodoo;
+ required_device<generic_voodoo_device> m_voodoo;
std::unique_ptr<u32[]> m_reg;
std::unique_ptr<u32[]> 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<T *>(this));
add_map(size, flags, delegate);
}
+ template <typename T> 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 <climits>
#include <atomic>
+#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 ArrayType, int TrackingCount>
+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<u8 *>(&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<poly_array<ArrayType, 0>>();
+ 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<ArrayType *>(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<u8[]> new_alloc = std::make_unique<u8[]>(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<u8 *>((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<u8[]> m_alloc;
+ std::unique_ptr<poly_array<ArrayType, 0>> m_chain;
+ std::array<ArrayType *, TrackingCount> m_last;
+};
+
+
// poly_manager is a template class
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags = 0>
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<BaseType, MaxParams> 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_t, MaxParams> param; // array of parameter start/delays
void *userdata; // custom per-span data
};
// delegate type for scanline callbacks
- typedef delegate<void (int32_t, const extent_t &, const ObjectData &, int)> render_delegate;
+ typedef delegate<void (int32_t, const extent_t &, const ObjectType &, int)> 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<int ParamCount>
+ 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<int ParamCount>
+ uint32_t render_triangle(rectangle const &cliprect, render_delegate callback, vertex_t const &v1, vertex_t const &v2, vertex_t const &v3);
+ template<int ParamCount>
+ uint32_t render_triangle_fan(rectangle const &cliprect, render_delegate callback, int numverts, vertex_t const *v);
+ template<int ParamCount>
+ 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<int _NumVerts>
- uint32_t render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v);
+ template<int NumVerts, int ParamCount>
+ 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);
-
-private:
- poly_manager(running_machine &machine, screen_device *screen, uint8_t flags);
+ template<int ParamCount>
+ int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, BaseType clipval);
- // turn this on to log the reasons for any long waits
- static constexpr bool POLY_LOG_WAITS = false;
+protected:
+ // optional overrides
+ virtual void reset_after_wait() { }
+private:
// 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
{
- std::atomic<uint32_t> 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; }
-
+ 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");
+ }
- // class for managing an array of items
- template<class _Type, int _Count>
- 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<uint8_t[]>(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<uint8_t *>(&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<uint8_t[]> m_base;
- int m_next;
- int m_max;
- int m_waits;
+ std::atomic<uint32_t> count_next; // number of scanlines and index of next item to process
+ 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_info, MaxPolys> polygon_array;
- typedef poly_array<ObjectData, MaxPolys + 1> objectdata_array;
- typedef poly_array<work_unit, std::min(MaxPolys * UNITS_PER_POLY, 65535)> unit_array;
+ using polygon_array = poly_array<polygon_info, 0>;
+ using objectdata_array = poly_array<ObjectType, 1>;
+ using unit_array = poly_array<work_unit, 0>;
// 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<std::string, wait_tracker>;
+ waitmap_t m_waitmap;
#endif
};
@@ -286,44 +442,19 @@ private:
// poly_manager - constructor
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::poly_manager(running_machine &machine, uint8_t flags)
- : poly_manager(machine, nullptr, flags)
-{
-}
-
-
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::poly_manager(screen_device &screen, uint8_t flags)
- : poly_manager(screen.machine(), &screen, flags)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+poly_manager<BaseType, ObjectType, MaxParams, Flags>::poly_manager(running_machine &machine) :
+ m_queue(nullptr),
+ m_tiles(0),
+ m_triangles(0),
+ m_quads(0),
+ m_pixels(0)
{
-}
-
-
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::poly_manager(running_ma
// ~poly_manager - destructor
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::~poly_manager()
+#if TRACK_POLY_WAITS
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+inline std::string poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+poly_manager<BaseType, ObjectType, MaxParams, Flags>::~poly_manager()
{
#if KEEP_POLY_STATISTICS
{
@@ -348,17 +502,48 @@ poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::~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));
+
+ 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;
- 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());
+ 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<BaseType, ObjectData, MaxParams, MaxPolys>::~poly_manager()
// work_item_callback - process a work item
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-void *poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::work_item_callback(void *param, int threadid)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+void *poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::work_item_callbac
// wait - stall until all work is complete
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-void poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::wait(const char *debug_reason)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+void poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-ObjectData &poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::object_data_alloc()
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+ObjectType &poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::object_data
// render_tile - render a tile
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ParamCount> param_dpdx;
+ std::array<BaseType, ParamCount> 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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::render_tile(co
// given 3 vertexes
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2, const vertex_t &_v3)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ParamCount> param_start;
+ std::array<BaseType, ParamCount> param_dpdx;
+ std::array<BaseType, ParamCount> 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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangl
// triangles in a fan
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<ParamCount>(cliprect, callback, v[0], v[vertnum - 1], v[vertnum]);
return pixels;
}
@@ -830,13 +980,14 @@ uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangl
// triangles in a strip
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<ParamCount>(cliprect, callback, v[vertnum - 2], v[vertnum - 1], v[vertnum]);
return pixels;
}
@@ -846,14 +997,19 @@ uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangl
// render of an object, given specific extents
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::render_triangl
// to 32 vertices
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-template<int _NumVerts>
-uint32_t poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int NumVerts, int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, MaxParams> 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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::render_polygon
// a z coordinate
//-------------------------------------------------
-template<typename BaseType, class ObjectData, int MaxParams, int MaxPolys>
-int poly_manager<BaseType, ObjectData, MaxParams, MaxPolys>::zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, BaseType clipval)
+template<typename BaseType, class ObjectType, int MaxParams, u8 Flags>
+template<int ParamCount>
+int poly_manager<BaseType, ObjectType, MaxParams, Flags>::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<BaseType, ObjectData, MaxParams, MaxPolys>::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<BaseType, ObjectData, MaxParams, MaxPolys>::zclip_if_less(int n
template<typename BaseType, int MaxParams>
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<BaseType, MaxParams> p; // Additional parameters to clip
};
template<typename BaseType, int MaxParams>
-int frustum_clip_w(const frustum_clip_vertex<BaseType, MaxParams>* v, int num_vertices, frustum_clip_vertex<BaseType, MaxParams>* out)
+int frustum_clip_w(frustum_clip_vertex<BaseType, MaxParams> const *v, int num_vertices, frustum_clip_vertex<BaseType, MaxParams> *out)
{
if (num_vertices <= 0)
return 0;
@@ -1225,7 +1382,7 @@ int frustum_clip_w(const frustum_clip_vertex<BaseType, MaxParams>* v, int num_ve
template<typename BaseType, int MaxParams>
-int frustum_clip(const frustum_clip_vertex<BaseType, MaxParams>* v, int num_vertices, frustum_clip_vertex<BaseType, MaxParams>* out, int axis, int sign)
+int frustum_clip(frustum_clip_vertex<BaseType, MaxParams> const *v, int num_vertices, frustum_clip_vertex<BaseType, MaxParams> *out, int axis, int sign)
{
if (num_vertices <= 0)
return 0;
@@ -1293,7 +1450,7 @@ int frustum_clip(const frustum_clip_vertex<BaseType, MaxParams>* v, int num_vert
template<typename BaseType, int MaxParams>
-int frustum_clip_all(frustum_clip_vertex<BaseType, MaxParams>* clip_vert, int num_vertices, frustum_clip_vertex<BaseType, MaxParams>* out)
+int frustum_clip_all(frustum_clip_vertex<BaseType, MaxParams> *clip_vert, int num_vertices, frustum_clip_vertex<BaseType, MaxParams> *out)
{
num_vertices = frustum_clip_w<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert);
num_vertices = frustum_clip<BaseType, MaxParams>(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 <atomic>
-
-
-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<uint32_t> 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<work_unit *> 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_info *> 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<void *> 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<uint8_t> m_work_unit_alloc;
- std::vector<uint8_t> m_polygon_alloc;
- std::vector<uint8_t> 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<typename T>
-static void allocate_array(running_machine &machine, std::vector<uint8_t> &buffer, std::vector<T *> &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<T *>(&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,6489 +105,3299 @@ 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)
+inline s32 float_to_int32(u32 data, int fixedbits)
+{
+ // compute the effective exponent
+ int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits;
-#define MODIFY_PIXEL(VV)
+ // extract the mantissa and return the implied leading 1 bit
+ s32 result = (data & 0x7fffff) | 0x800000;
-// Need to turn off cycle eating when debugging MIPS drc
-// otherwise timer interrupts won't match nodrc debug mode.
-#define EAT_CYCLES (1)
+ // shift by the exponent, handling minimum/maximum
+ if (exponent < 0)
+ {
+ if (exponent > -32)
+ result >>= -exponent;
+ else
+ result = 0;
+ }
+ else
+ {
+ if (exponent < 32)
+ result <<= exponent;
+ else
+ result = 0x7fffffff;
+ }
+ // negate based on the sign
+ return (data & 0x80000000) ? -result : result;
+}
-namespace {
-/*************************************
- *
- * Alias map of the first 64
- * registers when remapped
- *
- *************************************/
+//-------------------------------------------------
+// float_to_int64 - convert a floating-point
+// value in raw IEEE format into an integer with
+// the given number of fractional bits
+//-------------------------------------------------
-const uint8_t register_alias_map[0x40] =
+inline s64 float_to_int64(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,
-
- 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
-};
+ // 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;
-/*************************************
- *
- * 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
-};
+ // shift by the exponent, handling minimum/maximum
+ if (exponent < 0)
+ {
+ if (exponent > -64)
+ result >>= -exponent;
+ else
+ result = 0;
+ }
+ else
+ {
+ if (exponent < 64)
+ result <<= exponent;
+ else
+ result = 0x7fffffffffffffffull;
+ }
-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
-};
+ // negate based on the sign
+ return (data & 0x80000000) ? -result : result;
+}
-/*************************************
- *
- * Register string table for debug
- *
- *************************************/
+//**************************************************************************
+// VOODOO REGISTERS
+//**************************************************************************
-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"
-};
+//-------------------------------------------------
+// register_save - save live state
+//-------------------------------------------------
-const char *const banshee_reg_name[] =
+void voodoo_regs::register_save(save_proxy &save)
{
- /* 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"
-};
+ 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));
+}
-/*************************************
- *
- * Register string table for debug
- *
- *************************************/
+//-------------------------------------------------
+// s_alias_map - remap of first 64 registers
+//-------------------------------------------------
-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"
+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
};
-/*************************************
- *
- * 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
+//**************************************************************************
+// SHARED TABLES
+//**************************************************************************
+//-------------------------------------------------
+// shared_tables - constructor
+//-------------------------------------------------
-struct voodoo_device::poly_extra_data
+shared_tables::shared_tables()
{
- 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
-};
-
-
+ // 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;
-/*************************************
- *
- * Statics
- *
- *************************************/
+ // 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);
-static const rectangle global_cliprect(-4096, 4095, -4096, 4095);
+ // 8-bit alpha
+ alpha8[val] = rgb_t(val, val, val, val);
-/* fast dither lookup */
-static uint8_t dither4_lookup[256*16*2];
-static uint8_t dither2_lookup[256*16*2];
+ // 8-bit intensity
+ int8[val] = rgb_t(0xff, val, val, val);
-/* fast reciprocal+log2 lookup */
-uint32_t voodoo_reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2];
+ // 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);
+ }
+}
-/*************************************
- *
- * Specific rasterizers
- *
- *************************************/
+//**************************************************************************
+// TMU STATE
+//**************************************************************************
-#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)
+//-------------------------------------------------
+// tmu_state - constructor
+//-------------------------------------------------
-#include "voodoo_rast.ipp"
+tmu_state::tmu_state() :
+ m_index(0),
+ m_ram(nullptr),
+ m_mask(0),
+ m_basemask(0xfffff),
+ m_baseshift(3)
+{
+}
-#undef RASTERIZER_ENTRY
+//-------------------------------------------------
+// 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];
+}
-/*************************************
- *
- * 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 },
+//-------------------------------------------------
+// register_save - register for save states
+//-------------------------------------------------
-const voodoo_device::raster_info voodoo_device::predef_raster_table[] =
+void tmu_state::register_save(save_proxy &save)
{
-#include "voodoo_rast.ipp"
- { nullptr }
-};
+ // register state
+ save.save_class(NAME(m_reg));
+ save.save_item(NAME(m_palette));
+}
-#undef RASTERIZER_ENTRY
+//-------------------------------------------------
+// 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;
+}
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-/*************************************
- *
- * Video update
- *
- *************************************/
+//-------------------------------------------------
+// ncc_w - handle a write to the NCC/palette
+// registers
+//-------------------------------------------------
-int voodoo_device::voodoo_update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+void tmu_state::ncc_w(offs_t regnum, u32 data)
{
- int changed = fbi.video_changed;
- int drawbuf = fbi.frontbuf;
- int x, y;
+ u32 regindex = regnum - voodoo_regs::reg_nccTable;
- /* 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))
+ // I/Q entries in NCC 0 reference the palette if the high bit is set
+ if (BIT(data, 31) && regindex >= 4 && regindex < 12)
{
- bitmap.fill(0, cliprect);
- return changed;
- }
+ // extract the palette index
+ int const index = (BIT(data, 24, 7) << 1) | BIT(regindex, 0);
- /* if the CLUT is dirty, recompute the pens array */
- if (fbi.clut_dirty)
- {
- uint8_t rtable[32], gtable[64], btable[32];
+ // compute RGB and ARGB values
+ rgb_t rgb = 0xff000000 | data;
+ rgb_t argb = argbexpand<6,6,6,6>(data, 18, 12, 6, 0);
- /* Voodoo/Voodoo-2 have an internal 33-entry CLUT */
- if (vd_type <= TYPE_VOODOO_2)
+ // set and mark dirty
+ if (m_palette[0][index] != rgb)
{
- /* 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;
- }
+ m_palette[0][index] = rgb;
+ m_palette_dirty[0] = true;
}
-
- /* Banshee and later have a 512-entry CLUT that can be bypassed */
- else
+ if (m_palette[1][index] != argb)
{
- 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();
- }
+ m_palette[1][index] = argb;
+ m_palette_dirty[1] = true;
}
+ return;
+ }
- /* 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);
- }
+ // if no delta, don't mark dirty
+ if (m_reg.read(regnum) == data)
+ return;
- /* no longer dirty */
- fbi.clut_dirty = false;
- changed = true;
- }
+ // write the updated data and mark dirty
+ m_reg.write(regnum, data);
+ m_palette_dirty[2 + regindex / 12] = true;
+}
- /* 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]];
- }
+//-------------------------------------------------
+// prepare_texture - handle updating the texture
+// state if the texture configuration is dirty
+//-------------------------------------------------
- /* update stats display */
- if (DEBUG_STATS)
+inline rasterizer_texture &tmu_state::prepare_texture(voodoo_renderer &renderer)
+{
+ // if the texture parameters are dirty, update them
+ if (m_regdirty)
{
- 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);
- }
+ // determine the lookup
+ auto const texmode = m_reg.texture_mode();
+ u32 const texformat = texmode.format();
+ rgb_t const *lookup = m_texel_lookup[texformat];
- /* update render override */
- if (DEBUG_DEPTH)
- {
- stats.render_override = machine().input().code_pressed(KEYCODE_ENTER);
- if (stats.render_override)
+ // if null lookup, then we need something dynamic
+ if (lookup == nullptr)
{
- for (y = cliprect.min_y; y <= cliprect.max_y; y++)
+ // could be either straight palette or NCC table
+ int palindex;
+ if ((texformat & 7) == 1)
{
- 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);
+ // 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 changed;
+ 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;
- if (LOG_REGISTERS)
- logerror("VOODOO.REG:initEnable write = %08X\n", 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
+//-------------------------------------------------
-/*************************************
- *
- * Common initialization
- *
- *************************************/
-
-void voodoo_device::init_fbi(voodoo_device* vd,fbi_state *f, void *memory, int fbmem)
+inline void memory_fifo::add(u32 data)
{
- /* 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)
- {
- 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);
- }
+ // compute the value of 'in' after we add this item
+ s32 next_in = m_in + 1;
+ if (next_in >= m_size)
+ next_in = 0;
- // build static 16-bit rgb565 to rgb888 conversion table
- for (int val = 0; val < 65536; val++)
+ // as long as it's not equal to the output pointer, we can do it
+ if (next_in != m_out)
{
- int r, g, b;
-
- /* 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);
+ m_base[m_in] = data;
+ m_in = next_in;
}
-
- /* 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
+//-------------------------------------------------
+// remove - remove the next item from the fifo
+//-------------------------------------------------
- /* 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);
+inline u32 memory_fifo::remove()
+{
+ // return invalid data if empty
+ if (m_out == m_in)
+ return 0xffffffff;
- /* 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);
- }
+ // determine next output
+ s32 next_out = m_out + 1;
+ if (next_out >= m_size)
+ next_out = 0;
- rgb565 = nullptr;
+ // fetch current and advance
+ u32 data = m_base[m_out];
+ m_out = next_out;
+ return data;
}
-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<uint8_t *>(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 = &reg[nccTable+0];
- ncc[1].reg = &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;
- }
-}
+//**************************************************************************
+// DEBUG STATS
+//**************************************************************************
+//-------------------------------------------------
+// debug_stats - constructor
+//-------------------------------------------------
-void voodoo_device::voodoo_postload()
+debug_stats::debug_stats() :
+ m_lastkey(false),
+ m_display(false)
{
- 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();
+ reset();
}
-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);
- }
+//-------------------------------------------------
+// add_emulation_stats - add in statistics from
+// the emulation stats
+//-------------------------------------------------
- /* 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));
- }
+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
+//-------------------------------------------------
-/*************************************
- *
- * Statistics management
- *
- *************************************/
-
-void voodoo_device::accumulate_statistics(const stats_block &block)
+void debug_stats::reset()
{
- /* 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;
+ 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);
}
-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]));
- }
+//-------------------------------------------------
+// update_string - compute the string to display
+// all the statistics
+//-------------------------------------------------
- /* accumulate/reset statistics from the LFB */
- if (accumulate)
- accumulate_statistics(fbi.lfb_stats);
- memset(&fbi.lfb_stats, 0, sizeof(fbi.lfb_stats));
+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
+//-------------------------------------------------
-/*************************************
- *
- * VBLANK management
- *
- *************************************/
-
-void voodoo_device::swap_buffers(voodoo_device *vd)
+bool debug_stats::update_display_state(bool key_pressed)
{
- 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)
- {
- 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;
- }
- }
- }
- 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));
+ if (key_pressed && key_pressed != m_lastkey)
+ m_display = !m_display;
+ m_lastkey = key_pressed;
+ return m_display;
}
-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);
-}
+//**************************************************************************
+// GENERIC VOODOO DEVICE
+//**************************************************************************
+//-------------------------------------------------
+// generic_voodoo_device - constructor
+//-------------------------------------------------
-TIMER_CALLBACK_MEMBER( voodoo_device::vblank_off_callback )
+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)
{
- 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
- {
- 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");
+//-------------------------------------------------
+// device_start - device startup
+//-------------------------------------------------
- /* if we're past the swap count, do the swap */
- if (fbi.vblank_swap_pending && fbi.vblank_count >= fbi.vblank_swap)
- swap_buffers(this);
+void generic_voodoo_device::device_start()
+{
+ // resolve callbacks
+ m_vblank_cb.resolve();
+ m_stall_cb.resolve();
+ m_pciint_cb.resolve();
+}
- /* set a timer for the next off state */
- fbi.vsync_stop_timer->adjust(m_screen->time_until_pos(fbi.vsyncstop));
+//**************************************************************************
+// VOODOO 1 DEVICE
+//**************************************************************************
+//-------------------------------------------------
+// voodoo_1_device - constructor
+//-------------------------------------------------
- /* set internal state and call the client */
- fbi.vblank = true;
+DEFINE_DEVICE_TYPE(VOODOO_1, voodoo_1_device, "voodoo_1", "3dfx Voodoo Graphics")
- // 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);
+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
+//-------------------------------------------------
-/*************************************
- *
- * Chip reset
- *
- *************************************/
-
-void voodoo_device::reset_counters()
+voodoo_1_device::~voodoo_1_device()
{
- 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();
-}
+//-------------------------------------------------
+// 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));
+}
-/*************************************
- *
- * Recompute video memory layout
- *
- *************************************/
+//-------------------------------------------------
+// read - generic read handler until everyone is
+// using the memory map
+//-------------------------------------------------
-void voodoo_device::recompute_video_memory()
+u32 voodoo_1_device::read(offs_t offset, u32 mem_mask)
{
- 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)
+ switch (offset >> (22-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;
+ case 0x000000 >> 22:
+ return map_register_r(offset);
-// 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);
+ case 0x400000 >> 22:
+ return map_lfb_r(offset - 0x400000/4);
+
+ default:
+ return 0xffffffff;
+ }
+}
- /* first RGB buffer always starts at 0 */
- fbi.rgboffs[0] = 0;
- /* second RGB buffer starts immediately afterwards */
- fbi.rgboffs[1] = buffer_pages * 0x1000;
+//-------------------------------------------------
+// write - generic write handler until everyone is
+// using the memory map
+//-------------------------------------------------
- /* remaining buffers are based on the config */
- switch (memory_config)
+void voodoo_1_device::write(offs_t offset, u32 data, u32 mem_mask)
+{
+ switch (offset >> (22-2))
{
- 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;
+ case 0x000000 >> 22:
+ map_register_w(offset, data, mem_mask);
break;
- case 1: /* 3 color buffers, 0 aux buffers */
- fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
- fbi.auxoffs = ~0;
+ case 0x400000 >> 22:
+ map_lfb_w(offset - 0x400000/4, data, mem_mask);
break;
- case 2: /* 3 color buffers, 1 aux buffers */
- fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
- fbi.auxoffs = 3 * buffer_pages * 0x1000;
+ case 0x800000 >> 22:
+ case 0xc00000 >> 22:
+ map_texture_w(offset - 0x800000/4, data, mem_mask);
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;
+//-------------------------------------------------
+// set_init_enable - set the externally-controlled
+// init_en register
+//-------------------------------------------------
- /* 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;
- }
+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);
+}
- /* if not, disable the FIFO */
- else
- {
- fbi.fifo.base = nullptr;
- fbi.fifo.size = 0;
- }
- /* reset the FIFO */
- fbi.fifo.reset();
+//-------------------------------------------------
+// update - update the screen bitmap
+//-------------------------------------------------
- /* reset our front/back buffers if they are out of range */
- if (fbi.rgboffs[2] == ~0)
+int voodoo_1_device::update(bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // if we are blank, just fill with black
+ if (m_reg.fbi_init1().software_blank())
{
- if (fbi.frontbuf == 2)
- fbi.frontbuf = 0;
- if (fbi.backbuf == 2)
- fbi.backbuf = 0;
+ bitmap.fill(0, cliprect);
+ int changed = m_video_changed;
+ m_video_changed = false;
+ return changed;
}
-}
-
-
-/*************************************
- *
- * 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)
+ // if the CLUT is dirty, recompute the pens array
+ if (m_clut_dirty)
{
- int const index = ((data >> 23) & 0xfe) | (regnum & 1);
+ rgb_t const *clutbase = &m_clut[0];
- /* set the ARGB for this palette index */
- palette[index] = 0xff000000 | data;
+ // 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;
- /* if we have an ARGB palette as well, compute its value */
- if (palettea)
+ // compute the R/B pens first
+ u8 rtable[32], gtable[64], btable[32];
+ for (u32 rawcolor = 0; rawcolor < 32; rawcolor++)
{
- 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 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;
}
- /* this doesn't dirty the table or go to the registers, so bail */
- return;
- }
-
- /* 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;
- }
+ // then the G pens
+ for (u32 rawcolor = 0; rawcolor < 64; rawcolor++)
+ {
+ // 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;
+ }
- /* 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;
- }
+ // 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)]);
- /* 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;
+ // no longer dirty
+ m_clut_dirty = false;
+ m_video_changed = true;
}
-
- /* mark the table dirty */
- dirty = true;
+ return update_common(bitmap, cliprect, &m_pen[0]);
}
-void voodoo_device::tmu_state::ncc_table::update()
-{
- /* generte all 256 possibilities */
- for (int i = 0; i < 256; i++)
- {
- int vi = (i >> 2) & 0x03;
- int vq = (i >> 0) & 0x03;
-
- /* start with the intensity */
- int r, g, b;
- r = g = b = y[(i >> 4) & 0x0f];
-
- /* add the coloring */
- r += ir[vi] + qr[vq];
- g += ig[vi] + qg[vq];
- b += ib[vi] + qb[vq];
-
- /* 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;
-}
+//-------------------------------------------------
+// device_start - device startup
+//-------------------------------------------------
+void voodoo_1_device::device_start()
+{
+ // resolve configuration-related items
+ generic_voodoo_device::device_start();
+ // 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());
-/*************************************
- *
- * Faux DAC implementation
- *
- *************************************/
-
-void voodoo_device::dac_state::data_w(uint8_t regnum, uint8_t data)
-{
- reg[regnum] = data;
-}
+ // create shared tables
+ m_shared = std::make_unique<shared_tables>();
+ voodoo::dither_helper::init_static();
+ // 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())
+ {
+ if (&scan == this)
+ break;
+ index++;
+ }
+ m_stall_trigger = 51324 + index;
-void voodoo_device::dac_state::data_r(uint8_t regnum)
-{
- uint8_t result = 0xff;
+ // 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);
- /* switch off the DAC register requested */
- switch (regnum)
+ // 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)
{
- 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;
+ m_chipmask |= 2;
+ if (m_tmumem1_in_mb != 0)
+ m_chipmask |= 4;
}
- /* remember the read result; it is fetched elsewhere */
- read_result = result;
-}
-
+ // allocate memory
+ u32 total_allocation = m_fbmem_in_mb + m_tmumem0_in_mb + m_tmumem1_in_mb;
+ m_memory = std::make_unique<u8[]>(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;
-/*************************************
- *
- * 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))
+ // configure texture memory
+ u8 *tmumem[2] = { nullptr, nullptr };
+ u8 tmusize[2] = { m_tmumem0_in_mb, m_tmumem1_in_mb };
+ if (tmusize[0] != 0)
{
- if (!TEXLOD_LOD_ODD(reg[tLOD].u))
- lodmask = 0x155;
- else
- lodmask = 0x0aa;
+ // 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;
}
-
- /* 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();
+ // shared framebuffer and texture RAM (Voodoo Banshee/3)
+ tmumem[0] = tmumem[1] = m_fbram;
+ tmusize[0] = tmusize[1] = m_fbmem_in_mb;
}
- /* no longer dirty */
- regdirty = false;
+ // initialize the frame buffer
+ m_rgboffs[0] = m_rgboffs[1] = m_rgboffs[2] = 0;
+ m_auxoffs = ~0;
- /* check for separate RGBA filtering */
- if (TEXDETAIL_SEPARATE_RGBA_FILTER(reg[tDetail].u))
- fatalerror("Separate RGBA filters!\n");
-}
+ m_frontbuf = 0;
+ m_backbuf = 1;
+ m_swaps_pending = 0;
+ m_video_changed = true;
+ m_lfb_stride = 10;
-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
-}
+ 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();
-/*************************************
- *
- * Command FIFO depth computation
- *
- *************************************/
+ // initialize the memory FIFO
+ m_fbmem_fifo.configure(nullptr, 0);
-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;
+ // 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;
- /* low 3 bits specify the packet type */
- switch (command & 7)
+ // 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))
{
- /*
- 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;
+ m_tmu[1].init(1, *m_shared.get(), tmumem[1], tmusize[1] * 1024 * 1024);
+ tmu_config |= 0xc0;
}
-}
+ // create the renderer
+ m_renderer = std::make_unique<voodoo_renderer>(machine(), tmu_config, m_shared->rgb565, m_reg, &m_tmu[0].regs(), BIT(m_chipmask, 2) ? &m_tmu[1].regs() : nullptr);
+ // 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));
-/*************************************
- *
- * Command FIFO execution
- *
- *************************************/
+ // 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));
-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;
+ // do a soft reset to reset everything else
+ soft_reset();
- /*
- Packet type 1: 1 + N words
+ // register for save states
+ save_proxy save(*this);
+ register_save(save, total_allocation);
+}
- 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;
+//-------------------------------------------------
+// device_stop - device-specific stop
+//-------------------------------------------------
- if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target);
+void voodoo_1_device::device_stop()
+{
+ m_renderer->wait("Destruction");
+}
- 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;
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
- /*
- 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;
+void voodoo_1_device::device_reset()
+{
+ soft_reset();
+}
- /*
- 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();
- }
- }
+//-------------------------------------------------
+// device_post_load - update after loading save
+// state
+//-------------------------------------------------
- /* 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++;
- }
+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();
- /* 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++;
+ // recompute FBI memory FIFO to get the base pointer set
+ if (m_fbmem_fifo.configured())
+ recompute_fbmem_fifo();
+}
- /* 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++;
- }
+//-------------------------------------------------
+// soft_reset - handle reset when initiated by
+// a register write
+//-------------------------------------------------
- /* 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;
- }
+void voodoo_1_device::soft_reset()
+{
+ reset_counters();
+ m_reg.write(voodoo_regs::reg_fbiTrianglesOut, 0);
+ m_pci_fifo.reset();
+ m_fbmem_fifo.reset();
+}
- /* 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;
+//-------------------------------------------------
+// register_save - register items for save states
+//-------------------------------------------------
- /* if we have enough, draw */
- if (++vd->fbi.sverts >= 3)
- cycles += setup_and_draw_triangle(vd);
- }
- }
+ALLOW_SAVE_TYPE(reg_init_en);
+ALLOW_SAVE_TYPE(voodoo_regs::register_data);
+ALLOW_SAVE_TYPE(voodoo_1_device::stall_state);
- /* account for the extra dummy words */
- src += command >> 29;
- break;
+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));
- /*
- Packet type 4: 1 + N words
+ // allocated memory
+ save.save_pointer(NAME(m_fbram), 1024 * 1024 * total_allocation);
+ save.save_class(NAME(*m_renderer.get()));
- 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:
+ // 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));
- /* extract parameters */
- target = (command >> 3) & 0xfff;
+ // linear frame buffer access configuration
+ save.save_item(NAME(m_lfb_stride));
- if (LOG_CMDFIFO) vd->logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", (command >> 15) & 0x3fff, target, command >> 29);
+ // 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));
- if (vd->vd_type >= TYPE_VOODOO_BANSHEE && (target & 0x800))
- {
- // Banshee/Voodoo3 2D register writes
+ // 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));
- /* 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++);
- }
+ // 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));
- /* account for the extra dummy words */
- src += command >> 29;
- break;
+ // memory for PCI FIFO
+ save.save_item(NAME(m_pci_fifo_mem));
- /*
- 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);
+ // pens and CLUT
+ save.save_item(NAME(m_clut));
+}
- 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);
+//-------------------------------------------------
+// draw_buffer_indirect - given a 2-bit index,
+// return the front/back buffer for drawing
+//-------------------------------------------------
- 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);
+u16 *voodoo_1_device::draw_buffer_indirect(int index)
+{
+ switch (index)
+ {
+ case 0: m_video_changed = true; return front_buffer();
+ case 1: return back_buffer();
+ default: return nullptr;
+ }
+}
- /* loop over words */
- for (i = 0; i < count; i++)
- cycles += lfb_w(vd, target++, *src++, 0xffffffff);
- break;
- }
+//-------------------------------------------------
+// lfb_buffer_indirect - given a 2-bit index,
+// return the front/back/depth buffer for LFB
+// access
+//-------------------------------------------------
- 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);
+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;
+ }
+}
- /* just update the pointers for now */
- for (i = 0; i < count; i++)
- {
- target++;
- src++;
- }
- break;
- }
+//-------------------------------------------------
+// prepare_for_read - handle housekeeping before
+// processing a direct PCI read
+//-------------------------------------------------
- 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);
+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());
+}
- /* loop over words */
- for (i = 0; i < count; i++)
- cycles += texture_w(vd, target++, *src++);
- break;
- }
- }
+//-------------------------------------------------
+// prepare_for_write - handle housekeeping before
+// processing a direct PCI write
+//-------------------------------------------------
- break;
+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");
- default:
- fprintf(stderr, "PACKET TYPE %d\n", command & 7);
- break;
+ // 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();
}
-
- /* by default just update the read pointer past all the data we consumed */
- f->rdptr = 4 * (src - fifobase);
- return cycles;
+ return pending;
}
+//-------------------------------------------------
+// recompute_fbmem_fifo - recompute and configure
+// the framebuffer RAM-based FIFO based on the
+// fbiInit registers
+//-------------------------------------------------
-/*************************************
- *
- * Handle execution if we're ready
- *
- *************************************/
-
-int32_t voodoo_device::cmdfifo_execute_if_ready(cmdfifo_info &f)
+void voodoo_1_device::recompute_fbmem_fifo()
{
- /* 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;
-}
+ // 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<u32>((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);
+}
-/*************************************
- *
- * Handle writes to the CMD FIFO
- *
- *************************************/
-void voodoo_device::cmdfifo_w(voodoo_device *vd, cmdfifo_info *f, offs_t offset, uint32_t data)
+//-------------------------------------------------
+// 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)
{
- uint32_t addr = f->base + offset * 4;
- uint32_t *fifobase = (uint32_t *)vd->fbi.ram;
+ // 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 (LOG_CMDFIFO_VERBOSE) vd->logerror("CMDFIFO_w(%04X) = %08X\n", offset, data);
+ // 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());
- /* write the data */
- if (addr < f->end)
- fifobase[addr / 4] = data;
+ // add as offset/data pair
+ m_pci_fifo.add(offset);
+ m_pci_fifo.add(data);
- /* count holes? */
- if (f->count_holes)
+ // 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())
{
- /* in-order, no holes */
- if (f->holes == 0 && addr == f->amin + 4)
- {
- f->amin = f->amax = addr;
- f->depth++;
- }
+ u8 valid[4];
- /* 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++;
- }
+ // 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();
- /* out-of-order, but within the min-max range */
- else if (addr < f->amax)
+ // 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])
{
- f->holes--;
- if (f->holes == 0)
- {
- f->depth += (f->amax - f->amin) / 4;
- f->amin = f->amax;
- }
+ m_fbmem_fifo.add(m_pci_fifo.remove());
+ m_fbmem_fifo.add(m_pci_fifo.remove());
}
- /* out-of-order, bumping max */
- else
+ // 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())
{
- f->holes += (addr - f->amax) / 4 - 1;
- f->amax = addr;
+ if (LOG_FIFO) logerror("VOODOO.FIFO:hit memory FIFO HWM -- stalling\n");
+ stall_cpu(STALLED_UNTIL_FIFO_LWM);
}
}
- /* execute if we can */
- if (!vd->pci.op_pending)
+ // 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())
{
- 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());
- }
- }
+ 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
+//-------------------------------------------------
-/*************************************
- *
- * Stall the active cpu until we are
- * ready
- *
- *************************************/
-
-TIMER_CALLBACK_MEMBER( voodoo_device::stall_cpu_callback )
+void voodoo_1_device::flush_fifos(attotime current_time)
{
- check_stalled_cpu(machine().time());
-}
-
+ // check for recursive calls
+ if (m_flush_flag)
+ return;
+ m_flush_flag = true;
-void voodoo_device::check_stalled_cpu(attotime current_time)
-{
- int resume = false;
+ // should only be called if something is pending
+ assert(operation_pending());
- /* flush anything we can */
- if (pci.op_pending)
- flush_fifos(this, current_time);
+ 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));
- /* if we're just stalled until the LWM is passed, see if we're ok now */
- if (pci.stall_state == STALLED_UNTIL_FIFO_LWM)
+ // loop while we still have cycles to burn
+ while (m_operation_end <= current_time)
{
- /* 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;
- }
+ // execute from the FIFOs until we get something that's non-zero
+ u32 cycles = execute_fifos();
- /* 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 nothing remains, we're done; clear the flags
+ if (cycles == 0)
{
- if (fbi.fifo.empty() && pci.fifo.empty())
- resume = true;
+ clear_pending_operation();
+ if (LOG_FIFO_VERBOSE)
+ logerror("VOODOO.FIFO:flush_fifos end -- FIFOs empty\n");
+ m_flush_flag = false;
+ return;
}
- 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);
- }
+ // account for those cycles
+ m_operation_end += clocks_to_attotime(cycles);
- /* if not, set a timer for the next one */
- else
- {
- pci.continue_timer->adjust(pci.op_end_time - current_time);
+ if (LOG_FIFO_VERBOSE)
+ logerror("VOODOO.FIFO:update -- pending=%s cur=%s\n", m_operation_end.as_string(18), current_time.as_string(18));
}
-}
-
-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);
+ if (LOG_FIFO_VERBOSE)
+ logerror("VOODOO.FIFO:flush_fifos end -- pending command complete at %s\n", m_operation_end.as_string(18));
- /* set a timer to clear the stall */
- pci.continue_timer->adjust(pci.op_end_time - current_time);
+ m_flush_flag = false;
}
+//-------------------------------------------------
+// execute_fifos - execute commands from the FIFOs
+// until a non-zero cycle count operation is run
+//-------------------------------------------------
-/*************************************
- *
- * Voodoo register writes
- *
- *************************************/
-
-int32_t voodoo_device::register_w(voodoo_device *vd, offs_t offset, uint32_t data)
+u32 voodoo_1_device::execute_fifos()
{
- 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)
+ // loop until FIFOs are empty or until we get a non-zero cycle count
+ while (1)
{
- 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;
+ // prioritize framebuffer FIFO over PCI FIFO
+ voodoo::memory_fifo &memfifo = !m_fbmem_fifo.empty() ? m_fbmem_fifo : m_pci_fifo;
- 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;
+ // if empty, return 0
+ if (memfifo.empty())
+ return 0;
- 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;
+ // extract address and data
+ u32 offset = memfifo.remove();
+ u32 data = memfifo.remove();
- /* setup bits */
- case sARGB:
- if (chips & 1)
+ // target the appropriate location
+ switch (offset & memory_fifo::TYPE_MASK)
+ {
+ case memory_fifo::TYPE_REGISTER:
{
- 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();
+ // 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;
}
- 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;
+ case memory_fifo::TYPE_TEXTURE:
+ internal_texture_w(offset & ~memory_fifo::FLAGS_MASK, data);
+ 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 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;
+ }
+ }
+ }
+}
- case fastfillCMD:
- cycles = fastfill(vd);
- break;
- case swapbufferCMD:
- poly_wait(vd->poly, vd->regnames[regnum]);
- cycles = swapbuffer(vd, data);
- break;
+//-------------------------------------------------
+// map_register_r - handle a mapped read from
+// regular register space
+//-------------------------------------------------
- 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;
+u32 voodoo_1_device::map_register_r(offs_t offset)
+{
+ prepare_for_read();
- /* 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;
+ // extract chipmask and register
+ u32 chipmask = chipmask_from_offset(offset);
+ u32 regnum = BIT(offset, 0, 8);
+ return m_regtable[regnum].read(*this, chipmask, regnum);
+}
- /* 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;
+//-------------------------------------------------
+// map_lfb_r - handle a mapped read from LFB space
+//-------------------------------------------------
- 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;
- }
+u32 voodoo_1_device::map_lfb_r(offs_t offset)
+{
+ prepare_for_read();
+ return internal_lfb_r(offset);
+}
- /* 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);
+//-------------------------------------------------
+// map_register_w - handle a mapped write to
+// regular register space
+//-------------------------------------------------
- /* 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;
+void voodoo_1_device::map_register_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ bool pending = prepare_for_write();
- /* 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;
+ // extract chipmask and register
+ u32 chipmask = chipmask_from_offset(offset);
+ u32 regnum = BIT(offset, 0, 8);
- 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);
+ // 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);
- /* 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));
- }
+ // handle aliasing
+ if (BIT(offset, 21-2) && m_reg.fbi_init3().tri_register_remap())
+ regnum = voodoo_regs::alias(regnum);
- /* 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;
+ // look up the register
+ auto const &regentry = m_regtable[regnum];
- /* 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;
+ // if this is non-FIFO command, execute immediately
+ if (!regentry.is_fifo())
+ return void(regentry.write(*this, chipmask, regnum, data));
- /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */
- case fbiInit5:
- case fbiInit6:
- if (vd->vd_type < TYPE_VOODOO_2)
- break;
- [[fallthrough]];
+ // track swap buffer commands seen
+ if (regnum == voodoo_regs::reg_swapbufferCMD)
+ m_swaps_pending++;
- /* 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;
+ // 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);
- 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;
+ // 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));
+ }
+}
- 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;
+//-------------------------------------------------
+// map_lfb_w - handle a mapped write to LFB space
+//-------------------------------------------------
- case cmdFifoBump:
- if (vd->vd_type == TYPE_VOODOO_2 && (chips & 1))
- fatalerror("cmdFifoBump\n");
- break;
+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);
+}
- 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;
+//-------------------------------------------------
+// map_texture_w - handle a mapped write to
+// texture space
+//-------------------------------------------------
- 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;
+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);
+}
- 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;
+//-------------------------------------------------
+// internal_lfb_r - handle a read from the linear
+// frame buffer
+//-------------------------------------------------
- /* 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;
+u32 voodoo_1_device::internal_lfb_r(offs_t offset)
+{
+ // statistics
+ if (DEBUG_STATS)
+ m_stats.m_lfb_reads++;
- 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;
+ // linear frame buffer reads are inherently 16-bit; convert offset to an pixel index
+ offset <<= 1;
- /* 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;
+ // convert offset into X/Y coordinates
+ s32 x = offset & ((1 << m_lfb_stride) - 1);
+ s32 y = offset >> m_lfb_stride;
+ s32 scry = y;
- /* 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;
+ // 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;
- 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;
- }
+ // select the target buffer
+ u16 *buffer = lfb_buffer_indirect(lfbmode.read_buffer_select());
+ if (buffer == nullptr)
+ return 0xffffffff;
- if (LOG_REGISTERS)
+ // advance pointers to the proper row
+ buffer += scry * m_renderer->rowpixels() + x;
+ if (buffer + 1 >= ram_end())
{
- 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));
+ 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;
}
- return cycles;
-}
-
+ // 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);
-/*************************************
- *
- * Voodoo LFB writes
- *
- *************************************/
-int32_t voodoo_device::lfb_direct_w(offs_t offset, uint32_t data, uint32_t mem_mask)
-{
- /* statistics */
- stats.lfb_writes++;
+ // word swapping
+ if (lfbmode.word_swap_reads())
+ data = (data << 16) | (data >> 16);
- /* byte swizzling */
- if (LFBMODE_BYTE_SWIZZLE_WRITES(reg[lfbMode].u))
- {
+ // byte swizzling
+ if (lfbmode.byte_swizzle_reads())
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;
+ if (LOG_LFB)
+ logerror("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data);
+ return data;
}
-int32_t voodoo_device::lfb_w(voodoo_device* vd, offs_t offset, uint32_t data, uint32_t mem_mask)
+
+//-------------------------------------------------
+// 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)
{
- 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))
+ // 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(vd->reg[lfbMode].u))
+ // word swapping
+ if (lfbmode.word_swap_writes())
{
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;
+ // convert the incoming data
+ rgb_t src_color[2];
+ u16 src_depth[2];
+ u32 mask = expand_lfb_data(lfbmode, data, src_color, src_depth);
- 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;
+ // if there are two pixels, then the offset is *2
+ if ((mask & LFB_PIXEL1_MASK) != 0)
+ offset <<= 1;
- 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;
+ // compute X,Y
+ s32 x = offset & ((1 << m_lfb_stride) - 1);
+ s32 y = (offset >> m_lfb_stride) & 0x3ff;
- 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 */
+ // adjust the mask based on which half of the data is written
if (!ACCESSING_BITS_0_15)
- mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW);
+ mask &= ~(LFB_PIXEL0_MASK - LFB_DEPTH_PRESENT_MSW_0);
if (!ACCESSING_BITS_16_31)
- mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW);
+ mask &= ~(LFB_PIXEL1_MASK + LFB_DEPTH_PRESENT_MSW_0);
- /* 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;
+ // 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 */
- if (!LFBMODE_ENABLE_PIXEL_PIPELINE(vd->reg[lfbMode].u))
+ // simple case: no pipeline
+ auto const fbzmode = m_reg.fbz_mode();
+ if (!lfbmode.enable_pixel_pipeline())
{
- 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);
+ if (LOG_LFB)
+ logerror("VOODOO.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", lfbmode.write_format(), x, y, data, mem_mask);
- /* advance pointers to the proper row */
- bufoffs = scry * vd->fbi.rowpixels + x;
+ // determine the screen Y
+ s32 scry = y;
+ if (lfbmode.y_origin())
+ scry = m_renderer->yorigin() - y;
- /* compute dithering */
- COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(vd->reg[fbzMode].u, 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 */
- poly_wait(vd->poly, "LFB Write");
+ // wait for any outstanding work to finish
+ m_renderer->wait("LFB Write");
- /* loop over up to two pixels */
- for (pix = 0; mask; pix++)
+ // 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 & 0x0f)
+ // make sure we care about this pixel
+ if ((mask & LFB_PIXEL0_MASK) != 0)
{
- /* 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];
- }
+ // 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 && bufoffs < depthmax)
+ // make sure we have an aux buffer to write to
+ if (depth != nullptr && depth + pix < end)
{
- /* 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];
+ 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 */
- vd->reg[fbiPixelsOut].u++;
+ // track pixel writes to the frame buffer regardless of mask
+ m_reg.add(voodoo_regs::reg_fbiPixelsOut, 1);
}
- /* advance our pointers */
- bufoffs++;
+ // advance our pointers
x++;
mask >>= 4;
}
}
- /* tricky case: run the full pixel pipeline on the pixel */
+ // 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++)
+ 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 & 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++;
+ // 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]);
- /* 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 */
+ // advance our pointers
x++;
mask >>= 4;
}
}
-
- return 0;
}
+//-------------------------------------------------
+// expand_lfb_data - expand a 32-bit raw data
+// value into 1 or 2 expanded RGBA and depth
+// values
+//-------------------------------------------------
-/*************************************
- *
- * 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;
+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;
}
-
- return 0;
}
+//-------------------------------------------------
+// internal_texture_w - handle writes to texture
+// RAM
+//-------------------------------------------------
-/*************************************
- *
- * Flush data from the FIFOs
- *
- *************************************/
-
-void voodoo_device::flush_fifos(voodoo_device *vd, attotime current_time)
+void voodoo_1_device::internal_texture_w(offs_t offset, u32 data)
{
- static uint8_t in_flush;
+ // statistics
+ if (DEBUG_STATS)
+ m_stats.m_tex_writes++;
- /* check for recursive calls */
- if (in_flush)
+ // point to the right TMU
+ int tmunum = BIT(offset, 19, 2);
+ if (!BIT(m_chipmask, 1 + tmunum))
return;
- in_flush = true;
- if (!vd->pci.op_pending) fatalerror("flush_fifos called with no pending operation\n");
+ // wait for any outstanding work to finish
+ m_renderer->wait("Texture write");
- 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());
- }
+ // 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();
- /* 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;
+ // pull out modes from the TMU and update state
+ auto &regs = 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());
- /* 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);
- }
- }
+ // texture direct not handled (but never seen so far)
+ if (texlod.tdirect_write())
+ fatalerror("%s: Unsupported texture direct write", tag());
- /* accumulate smaller operations */
- if (cycles < ACCUMULATE_THRESHOLD)
- {
- extra_cycles += cycles;
- cycles = 0;
- }
- }
- while (cycles == 0);
+ // swizzle the data
+ if (texlod.tdata_swizzle())
+ data = swapendian_int32(data);
+ if (texlod.tdata_swap())
+ data = (data >> 16) | (data << 16);
- /* account for extra cycles */
- cycles += extra_cycles;
+ // 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;
- /* account for those cycles */
- vd->pci.op_end_time += attotime(0, (attoseconds_t)cycles * vd->attoseconds_per_cycle);
+ // validate parameters
+ if (lod > 8)
+ return;
+ u8 *dest = texture.write_ptr(lod, ts, tt, bytes_per_texel);
- 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());
- }
+ // 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;
}
-
- if (LOG_FIFO_VERBOSE)
+ else
{
- 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());
+ u16 *dest16 = reinterpret_cast<u16 *>(dest);
+ dest16[BYTE_XOR_LE(0)] = (data >> 0) & 0xffff;
+ dest16[BYTE_XOR_LE(1)] = (data >> 16) & 0xffff;
}
-
- in_flush = false;
}
+//-------------------------------------------------
+// reg_invalid_r - generic invalid register read
+//-------------------------------------------------
-/*************************************
- *
- * Handle a write to the Voodoo
- * memory space
- *
- *************************************/
-
-void voodoo_device::voodoo_w(offs_t offset, u32 data, u32 mem_mask)
+u32 voodoo_1_device::reg_invalid_r(u32 chipmask, u32 regnum)
{
- 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;
- }
- }
+ return 0xffffffff;
+}
- /* 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];
+//-------------------------------------------------
+// reg_passive_r - generic passive register read
+//-------------------------------------------------
- /* ignore if writes aren't allowed */
- if (!(access & REGISTER_WRITE))
- {
- g_profiler.stop();
- return;
- }
+u32 voodoo_1_device::reg_passive_r(u32 chipmask, u32 regnum)
+{
+ return m_reg.read(regnum);
+}
- // 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++;
- }
+//-------------------------------------------------
+// reg_status_r - status register read
+//-------------------------------------------------
- /* 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;
+u32 voodoo_1_device::reg_status_r(u32 chipmask, u32 regnum)
+{
+ u32 result = 0;
- /* 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);
+ // bits 5:0 are the PCI FIFO free space
+ result |= std::min(m_pci_fifo.space() / 2, 0x3f) << 0;
- /* 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);
+ // bit 6 is the vertical retrace
+ result |= m_vblank << 6;
- 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;
- }
+ // 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);
- /* 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;
- }
+ // bits 10-11 is displayed buffer
+ result |= m_frontbuf << 10;
- /* 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);
- }
+ // bits 12-27 is memory FIFO free space
+ if (m_reg.fbi_init0().enable_memory_fifo() == 0)
+ result |= 0xffff << 12;
else
- fatalerror("PCI FIFO full\n");
+ result |= std::min(m_fbmem_fifo.space() / 2, 0xffff) << 12;
- /* 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];
+ // bits 30:28 are the number of pending swaps
+ result |= std::min<s32>(m_swaps_pending, 7) << 28;
- /* 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);
+ // eat some cycles since people like polling here
+ if (m_status_cycles != 0)
+ m_cpu->eat_cycles(m_status_cycles);
- /* 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();
+ // bit 31 is PCI interrupt pending (not implemented)
+ return result;
}
+//-------------------------------------------------
+// reg_fbiinit2_r - fbiInit2 register read
+//-------------------------------------------------
-/*************************************
- *
- * Handle a register read
- *
- *************************************/
-
-uint32_t voodoo_device::register_r(voodoo_device *vd, offs_t offset)
+u32 voodoo_1_device::reg_fbiinit2_r(u32 chipmask, u32 regnum)
{
- 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 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);
+}
- /* 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;
+//-------------------------------------------------
+// reg_vretrace_r - vRetrace register read
+//-------------------------------------------------
- /* 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;
+u32 voodoo_1_device::reg_vretrace_r(u32 chipmask, u32 regnum)
+{
+ // return 0 if vblank is active
+ return m_vblank ? 0 : screen().vpos();
+}
- /* 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;
+//-------------------------------------------------
+// reg_stats_r - statistics register reads
+//-------------------------------------------------
- /* bit 12 is cmd FIFO 1 busy */
- if (vd->fbi.cmdfifo[1].enable && vd->fbi.cmdfifo[1].depth > 0)
- result |= 1 << 12;
- }
+u32 voodoo_1_device::reg_stats_r(u32 chipmask, u32 regnum)
+{
+ update_statistics(true);
+ return m_reg.read(regnum);
+}
- /* 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 */
+//-------------------------------------------------
+// reg_invalid_w - generic invalid register write
+//-------------------------------------------------
- /* eat some cycles since people like polling here */
- if (EAT_CYCLES) vd->m_cpu->eat_cycles(1000);
- break;
+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;
+}
- /* 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;
+//-------------------------------------------------
+// reg_status_w - status register write (Voodoo 1)
+//-------------------------------------------------
- /* 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;
+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;
+}
- /* cmdFifo -- Voodoo2 only */
- case cmdFifoRdPtr:
- result = vd->fbi.cmdfifo[0].rdptr;
+//-------------------------------------------------
+// reg_passive_w - generic passive register write
+//-------------------------------------------------
- /* eat some cycles since people like polling here */
- if (EAT_CYCLES) vd->m_cpu->eat_cycles(1000);
- break;
+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;
+}
- case cmdFifoAMin:
- result = vd->fbi.cmdfifo[0].amin;
- break;
- case cmdFifoAMax:
- result = vd->fbi.cmdfifo[0].amax;
- break;
+//-------------------------------------------------
+// reg_fpassive_4_w -- passive write with floating
+// point to x.4 fixed point conversion
+//-------------------------------------------------
- case cmdFifoDepth:
- result = vd->fbi.cmdfifo[0].depth;
- break;
+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));
+}
- 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;
- }
+//-------------------------------------------------
+// reg_fpassive_12_w -- passive write with
+// floating point to x.12 fixed point conversion
+//-------------------------------------------------
- if (LOG_REGISTERS)
- {
- int logit = true;
+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));
+}
- /* 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);
- }
+//-------------------------------------------------
+// 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)
+//-------------------------------------------------
- return result;
+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
+//-------------------------------------------------
-/*************************************
- *
- * Handle an LFB read
- *
- *************************************/
-
-static uint32_t lfb_r(voodoo_device *vd, offs_t offset, bool lfb_3d)
+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)
{
- uint16_t *buffer;
- uint32_t bufmax;
- uint32_t bufoffs;
- uint32_t data;
- int x, y, scry, destbuf;
+ 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;
+}
- /* 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;
+//-------------------------------------------------
+// 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)
+//-------------------------------------------------
- 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;
+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;
+}
- 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;
- }
+//-------------------------------------------------
+// reg_fstartw_w -- write to fstartW
+// reg_fdwdx_w -- write to fdWdX
+// reg_fdwdy_w -- write to fdWdY
+//-------------------------------------------------
- /* 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;
- }
+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;
+}
- /* 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");
+//-------------------------------------------------
+// reg_triangle_w -- write to triangleCMD/
+// ftriangleCMD
+//-------------------------------------------------
- /* compute the data */
- data = buffer[bufoffs + 0] | (buffer[bufoffs + 1] << 16);
+u32 voodoo_1_device::reg_triangle_w(u32 chipmask, u32 regnum, u32 data)
+{
+ return triangle();
+}
- /* 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);
+//-------------------------------------------------
+// reg_nop_w -- write to nopCMD
+//-------------------------------------------------
- if (LOG_LFB) vd->logerror("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data);
- return data;
+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
+//-------------------------------------------------
-/*************************************
- *
- * Handle a read from the Voodoo
- * memory space
- *
- *************************************/
-
-u32 voodoo_device::voodoo_r(offs_t offset)
+u32 voodoo_1_device::reg_fastfill_w(u32 chipmask, u32 regnum, u32 data)
{
- /* if we have something pending, flush the FIFOs up to the current time */
- if (pci.op_pending)
- flush_fifos(this, machine().time());
+ auto &poly = m_renderer->alloc_poly();
- /* target the appropriate location */
- if (!(offset & (0xc00000/4)))
- return register_r(this, offset);
- else if (!(offset & (0x800000/4)))
- return lfb_r(this, offset, true);
+ // 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();
- return 0xffffffff;
+ // 2 pixels per clock
+ return m_renderer->enqueue_fastfill(poly) / 2;
}
+//-------------------------------------------------
+// reg_swapbuffer_w -- write to swapbufferCMD
+//-------------------------------------------------
-/*************************************
- *
- * Handle a read from the Banshee
- * I/O space
- *
- *************************************/
-
-u32 voodoo_banshee_device::banshee_agp_r(offs_t offset)
+u32 voodoo_1_device::reg_swapbuffer_w(u32 chipmask, u32 regnum, u32 data)
{
- uint32_t result;
+ m_renderer->wait("swapbufferCMD");
- offset &= 0x1ff/4;
+ // 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);
- /* switch off the offset */
- switch (offset)
+ // if we're not syncing to the retrace, process the command immediately
+ if (!BIT(data, 0))
{
- 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;
+ swap_buffers();
+ return 0;
}
- if (LOG_REGISTERS)
- logerror("%s:banshee_r(AGP:%s)\n", machine().describe_context(), banshee_agp_reg_name[offset]);
- return result;
+ // 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;
}
-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;
-}
-
+//-------------------------------------------------
+// reg_fogtable_w -- write to fogTable
+//-------------------------------------------------
-u32 voodoo_banshee_device::banshee_fb_r(offs_t offset)
+u32 voodoo_1_device::reg_fogtable_w(u32 chipmask, u32 regnum, u32 data)
{
- 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;
+ if (BIT(chipmask, 0)) m_renderer->write_fog(2 * (regnum - voodoo_regs::reg_fogTable), data);
+ return 0;
}
-u8 voodoo_banshee_device::banshee_vga_r(offs_t offset)
-{
- uint8_t result = 0xff;
-
- offset &= 0x1f;
+//-------------------------------------------------
+// reg_fbiinit_w -- write to an fbiinit register
+//-------------------------------------------------
- /* switch off the offset */
- switch (offset + 0x3c0)
+u32 voodoo_1_device::reg_fbiinit_w(u32 chipmask, u32 regnum, u32 data)
+{
+ if (BIT(chipmask, 0) && m_init_enable.enable_hw_init())
{
- /* 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;
+ m_renderer->wait("fbi_init");
+ m_reg.write(regnum, data);
- /* 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;
+ // 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();
- /* 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;
+ // compute FIFO layout when fbiInit0 or fbiInit4 change
+ if (regnum == voodoo_regs::reg_fbiInit0 || regnum == voodoo_regs::reg_fbiInit4)
+ recompute_fbmem_fifo();
- /* 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;
+ // recompute video memory when fbiInit1 or fbiInit2 change
+ if (regnum == voodoo_regs::reg_fbiInit1 || regnum == voodoo_regs::reg_fbiInit2)
+ recompute_video_memory();
- default:
- result = banshee.vga[offset];
- if (LOG_REGISTERS)
- logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x3c0+offset);
- break;
+ // update Y origina when fbiInit3 changes
+ if (regnum == voodoo_regs::reg_fbiInit3)
+ m_renderer->set_yorigin(m_reg.fbi_init3().yorigin_subtract());
}
- return result;
+ return 0;
}
-u32 voodoo_banshee_device::banshee_io_r(offs_t offset, u32 mem_mask)
-{
- uint32_t result;
-
- offset &= 0xff/4;
+//-------------------------------------------------
+// reg_video_w -- write to a video configuration
+// register; synchronize then recompute everything
+//-------------------------------------------------
- /* switch off the offset */
- switch (offset)
+u32 voodoo_1_device::reg_video_w(u32 chipmask, u32 regnum, u32 data)
+{
+ if (BIT(chipmask, 0))
{
- case io_status:
- result = register_r(this, 0);
- break;
+ m_renderer->wait("video_configuration");
+ m_reg.write(regnum, data);
- 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;
+ auto const hsync = m_reg.hsync<true>();
+ auto const vsync = m_reg.vsync<true>();
+ auto const back_porch = m_reg.back_porch<true>();
+ auto const video_dimensions = m_reg.video_dimensions<true>();
+ 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 result;
+ return 0;
}
-u32 voodoo_banshee_device::banshee_rom_r(offs_t offset)
-{
- logerror("%s:banshee_rom_r(%X)\n", machine().describe_context(), offset*4);
- return 0xffffffff;
-}
+//-------------------------------------------------
+// reg_clut_w -- write to clutData; mark dirty if
+// changed
+//-------------------------------------------------
-static void blit_2d(voodoo_device *vd, uint32_t data)
+u32 voodoo_1_device::reg_clut_w(u32 chipmask, u32 regnum, u32 data)
{
- switch (vd->banshee.blt_cmd)
+ if (BIT(chipmask, 0))
{
- case 0: // NOP - wait for idle
+ m_renderer->wait("clut");
+ if (m_reg.fbi_init1().video_timing_reset() == 0)
{
- break;
+ 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;
+}
- 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);
- }
+//-------------------------------------------------
+// reg_dac_w -- write to dacData
+//-------------------------------------------------
- case 3: // Host-to-screen blit
+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
{
- 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)
+ // this is just to make startup happy
+ m_dac_read_result = m_dac_reg[regnum];
+ switch (m_dac_reg[7])
{
- 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;
+ case 0x01: m_dac_read_result = 0x55; break;
+ case 0x07: m_dac_read_result = 0x71; break;
+ case 0x0b: m_dac_read_result = 0x79; break;
}
-
- if (vd->banshee.blt_dst_x >= vd->banshee.blt_dst_width)
- {
- vd->banshee.blt_dst_x = 0;
- vd->banshee.blt_dst_y++;
- }
- break;
}
+ }
+ return 0;
+}
- 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);
- }
+//-------------------------------------------------
+// reg_texture_w -- passive write to a TMU; mark
+// dirty if changed
+//-------------------------------------------------
- case 8: // Polygon fill
+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))
{
- fatalerror("blit_2d:polygon_fill\n");
+ m_tmu[0].regs().write(regnum, data);
+ m_tmu[0].mark_dirty();
}
-
- default:
+ }
+ if (BIT(chipmask, 2))
+ {
+ if (data != m_tmu[1].regs().read(regnum))
{
- fatalerror("blit_2d: unknown command %d\n", vd->banshee.blt_cmd);
+ m_tmu[1].regs().write(regnum, data);
+ m_tmu[1].mark_dirty();
}
}
+ return 0;
}
-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;
- }
+//-------------------------------------------------
+// reg_palette_w -- passive write to a palette or
+// NCC table; mark dirty if changed
+//-------------------------------------------------
- return 1;
+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_banshee_device::banshee_agp_w(offs_t offset, u32 data, u32 mem_mask)
+void voodoo_1_device::adjust_vblank_start_timer()
{
- offset &= 0x1ff/4;
+ 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());
- /* 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);
+ // 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);
}
-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);
- }
-}
-
+//-------------------------------------------------
+// vblank_start -- timer callback for the start
+// of VBLANK
+//-------------------------------------------------
-void voodoo_banshee_device::banshee_fb_w(offs_t offset, u32 data, u32 mem_mask)
+void voodoo_1_device::vblank_start(void *ptr, s32 param)
{
- uint32_t addr = offset*4;
+ if (LOG_VBLANK_SWAP)
+ logerror("--- vblank start\n");
- /* 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)
+ // flush the pipes
+ if (operation_pending())
{
- 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
- }
+ if (LOG_VBLANK_SWAP)
+ logerror("---- vblank flush begin\n");
+ flush_fifos(machine().time());
+ if (LOG_VBLANK_SWAP)
+ logerror("---- vblank flush end\n");
}
- 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;
+ // increment the count
+ m_vblank_count = std::min(m_vblank_count + 1, 250);
- /* 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;
+ // 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");
- /* 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;
+ // if we're past the swap count, do the swap
+ if (m_vblank_swap_pending && m_vblank_count >= m_vblank_swap)
+ swap_buffers();
- /* 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;
+ // set a timer for the next off state
+ m_vsync_stop_timer->adjust(screen().time_until_pos(m_vsyncstop));
- /* 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;
+ // set internal state and call the client
+ m_vblank = true;
- default:
- banshee.vga[offset] = data;
- if (LOG_REGISTERS)
- logerror("%s:banshee_vga_w(%X) = %02X\n", machine().describe_context(), 0x3c0+offset, data);
- break;
- }
+ // notify external VBLANK handler on all models
+ if (!m_vblank_cb.isnull())
+ m_vblank_cb(true);
}
-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;
+//-------------------------------------------------
+// vblank_stop -- timer callback for the end of
+// VBLANK
+//-------------------------------------------------
- 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;
- }
+void voodoo_1_device::vblank_stop(void *ptr, s32 param)
+{
+ if (LOG_VBLANK_SWAP)
+ logerror("--- vblank end\n");
- 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;
+ // set internal state and call the client
+ m_vblank = false;
- 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;
+ // notify external VBLANK handler on all models
+ if (!m_vblank_cb.isnull())
+ m_vblank_cb(false);
- 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;
- }
+ // 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
+//-------------------------------------------------
-/***************************************************************************
- DEVICE INTERFACE
-***************************************************************************/
-
-/*-------------------------------------------------
- device start callback
--------------------------------------------------*/
-
-void voodoo_device::device_resolve_objects()
+void voodoo_1_device::swap_buffers()
{
- 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());
-}
+ if (LOG_VBLANK_SWAP)
+ logerror("--- swap_buffers @ %d\n", screen().vpos());
-void voodoo_device::device_start()
-{
- if (!m_screen || !m_cpu)
- throw device_missing_dependencies();
+ // force a partial update
+ screen().update_partial(screen().vpos());
+ m_video_changed = true;
- /* validate configuration */
- assert(m_fbmem > 0);
+ // keep a history of swap intervals
+ m_reg.update_swap_history(std::min<u8>(m_vblank_count, 15));
- /* copy config data */
- freq = clock();
- m_vblank.resolve();
- m_stall.resolve();
- m_pciint.resolve();
+ // rotate the buffers; implementation differs between models
+ rotate_buffers();
- /* create a multiprocessor work queue */
- poly_alloc(poly, machine(), 64, sizeof(poly_extra_data), 0);
- thread_stats = std::make_unique<stats_block[]>(WORK_MAX_THREADS);
+ // 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;
- /* 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++)
+ // reset the last_op_time to now and start processing the next command
+ if (operation_pending())
{
- 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));
+ 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");
}
- /* 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;
+ // we may be able to unstall now
+ if (m_stall_state != NOT_STALLED)
+ check_stalled_cpu(machine().time());
- 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
+ // periodically log rasterizer info
+ m_stats.m_swaps++;
+ if (m_stats.m_swaps % 1000 == 0)
+ m_renderer->dump_rasterizer_stats();
- /* configure type-specific values */
- switch (vd_type)
+ // update the statistics (debug)
+ if (DEBUG_STATS)
{
- 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;
- for (device_t &scan : device_enumerator(machine().root_device()))
- if (scan.type() == this->type())
+ if (m_stats.displayed())
{
- if (&scan == this)
- break;
- index++;
+ update_statistics(true);
+ m_stats.update_string(screen().visible_area(), m_reg.swap_history());
}
-
- if (m_tmumem1 != 0)
- tmu_config |= 0xc0; // two TMUs
-
- 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)
- {
- /* separate FB/TMU memory */
- fbmem = (m_fbmem_alloc = std::make_unique<uint8_t[]>(m_fbmem << 20)).get();
- tmumem[0] = (m_tmumem_alloc[0] = std::make_unique<uint8_t[]>(m_tmumem0 << 20)).get();
- tmumem[1] = (m_tmumem1 != 0) ? (m_tmumem_alloc[1] = std::make_unique<uint8_t[]>(m_tmumem1 << 20)).get() : nullptr;
- }
- else
- {
- /* shared memory */
- tmumem[0] = tmumem[1] = fbmem = (m_fbmem_alloc = std::make_unique<uint8_t[]>(m_fbmem << 20)).get();
- tmumem0 = m_fbmem;
- if (vd_type == TYPE_VOODOO_3)
- tmumem1 = m_fbmem;
+ m_stats.reset();
}
+}
- /* set up frame buffer */
- init_fbi(this, &fbi, fbmem, m_fbmem << 20);
- /* build shared TMU tables */
- tmushare.init();
- // Point the rgb565 table to the frame buffer table
- tmushare.rgb565 = fbi.rgb565;
+//-------------------------------------------------
+// rotate_buffers -- rotate the buffers according
+// to the current buffer config; this is split
+// out so later devices can override
+//-------------------------------------------------
- /* set up the TMUs */
- tmu[0].init(vd_type, tmushare, &reg[0x100], tmumem[0], tmumem0 << 20);
- chipmask |= 0x02;
- if (tmumem1 != 0)
+void voodoo_1_device::rotate_buffers()
+{
+ if (!m_vblank_dont_swap)
{
- tmu[1].init(vd_type, tmushare, &reg[0x200], tmumem[1], tmumem1 << 20);
- chipmask |= 0x04;
- tmu_config |= 0x40;
+ u32 buffers = (m_rgboffs[2] == ~0) ? 2 : 3;
+ m_frontbuf = (m_frontbuf + 1) % buffers;
+ m_backbuf = (m_frontbuf + 1) % buffers;
}
-
- /* 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);
-
- /* 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;
-
- /* do a soft reset to reset everything else */
- soft_reset();
-
- /* register for save states */
- init_save_state(this);
}
+//-------------------------------------------------
+// update_common -- shared update function
+//-------------------------------------------------
-/***************************************************************************
- COMMAND HANDLERS
-***************************************************************************/
-
-/*-------------------------------------------------
- fastfill - execute the 'fastfill'
- command
--------------------------------------------------*/
-
-int32_t voodoo_device::fastfill(voodoo_device *vd)
+int voodoo_1_device::update_common(bitmap_rgb32 &bitmap, const rectangle &cliprect, rgb_t const *pens)
{
- 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;
+ // reset the video changed flag
+ bool changed = m_video_changed;
+ m_video_changed = false;
- /* 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;
+ // select the buffer to draw
+ int drawbuf = m_frontbuf;
+ if (DEBUG_BACKBUF && machine().input().code_pressed(KEYCODE_L))
+ drawbuf = m_backbuf;
- case 1: /* back buffer */
- drawbuf = (uint16_t *)(vd->fbi.ram + vd->fbi.rgboffs[vd->fbi.backbuf]);
- break;
+ // 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]];
+ }
- default: /* reserved */
- break;
- }
+ // update stats display
+ if (DEBUG_STATS && m_stats.update_display_state(machine().input().code_pressed(KEYCODE_BACKSLASH)))
+ popmessage(m_stats.string(), 0, 0);
- /* determine the dither pattern */
- for (int y = 0; y < 4; y++)
+ // 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++)
{
- 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;
- }
+ 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);
}
- }
-
- /* 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;
+ return changed;
}
-/*-------------------------------------------------
- swapbuffer - execute the 'swapbuffer'
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// recompute_video_timing -- given hsync and
+// vsync parameter, find the best match for known
+// monitor types and select the best fit
+//-------------------------------------------------
-int32_t voodoo_device::swapbuffer(voodoo_device* vd, uint32_t data)
+void voodoo_1_device::recompute_video_timing(u32 hsyncon, u32 hsyncoff, u32 hvis, u32 hbp, u32 vsyncon, u32 vsyncoff, u32 vvis, u32 vbp)
{
- /* 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;
- }
+ u32 htotal = hsyncoff + 1 + hsyncon + 1;
+ u32 vtotal = vsyncoff + vsyncon;
- /* 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;
-}
+ // 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<s32>(visarea.max_x, htotal - 1);
+ visarea.max_y = std::min<s32>(visarea.max_y, vtotal - 1);
-/*-------------------------------------------------
- triangle - execute the 'triangle'
- command
--------------------------------------------------*/
+ // 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;
-int32_t voodoo_device::triangle(voodoo_device *vd)
-{
- int texcount;
- uint16_t *drawbuf;
- int destbuf;
- int pixels;
+ // 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);
- g_profiler.start(PROFILER_USER2);
+ 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);
- /* determine the number of TMUs involved */
- texcount = 0;
- if (!FBIINIT3_DISABLE_TMUS(vd->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(vd->reg[fbzColorPath].u))
+ // configure the screen based on which one matches the closest
+ if (stddiff < meddiff && stddiff < vgadiff)
{
- texcount = 1;
- if (vd->chipmask & 0x04)
- texcount = 2;
+ screen().configure(htotal, vtotal, visarea, stdperiod);
+ logerror("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
}
-
- /* perform subpixel adjustments */
- if (FBZCP_CCA_SUBPIXEL_ADJUST(vd->reg[fbzColorPath].u))
+ else if (meddiff < vgadiff)
{
- 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;
- }
- }
+ screen().configure(htotal, vtotal, visarea, medperiod);
+ logerror("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
}
-
- /* 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)
+ else
{
- 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;
+ screen().configure(htotal, vtotal, visarea, vgaperiod);
+ logerror("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod));
}
- /* 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();
+ // 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);
- /* 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;
+ adjust_vblank_start_timer();
}
-/*-------------------------------------------------
- begin_triangle - execute the 'beginTri'
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// recompute_video_memory -- compute the layout
+// of video memory
+//-------------------------------------------------
-int32_t voodoo_device::begin_triangle(voodoo_device *vd)
+void voodoo_1_device::recompute_video_memory()
{
- 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;
+ // configuration is either double-buffered (0) or triple-buffered (1)
+ u32 config = m_reg.fbi_init2().enable_triple_buf();
- return 0;
+ // 4-bit tile count; tiles are 64x16
+ u32 xtiles = m_reg.fbi_init1().x_video_tiles();
+ recompute_video_memory_common(config, xtiles * 64);
}
-/*-------------------------------------------------
- draw_triangle - execute the 'DrawTri'
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// recompute_video_memory_common -- core logic
+// for video memory layout based on 2-bit config
+// and the computed rowpixels
+//-------------------------------------------------
-int32_t voodoo_device::draw_triangle(voodoo_device *vd)
+void voodoo_1_device::recompute_video_memory_common(u32 config, u32 rowpixels)
{
- 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;
-}
+ // 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;
-/***************************************************************************
- 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)
+ // remaining buffers are based on the config
+ switch (config)
{
- 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);
- }
+ 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;
- /* 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;
- }
+ case 1: // 3 color buffers, 0 aux buffers
+ m_rgboffs[2] = 2 * buffer_pages * 0x1000;
+ m_auxoffs = ~0;
+ break;
- /* 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;
+ case 2: // 3 color buffers, 1 aux buffers
+ m_rgboffs[2] = 2 * buffer_pages * 0x1000;
+ m_auxoffs = 3 * buffer_pages * 0x1000;
+ break;
}
- /* 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;
- }
+ // 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;
- /* 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;
- }
+ // clamp the aux buffer to video memory
+ if (m_auxoffs != ~0 && m_auxoffs > m_fbmask)
+ m_auxoffs = m_fbmask;
- /* set up S1,T1 */
- if (vd->reg[sSetupMode].u & (1 << 7))
+ // reset our front/back buffers if they are out of range
+ if (m_rgboffs[2] == ~0)
{
- 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;
+ if (m_frontbuf == 2)
+ m_frontbuf = 0;
+ if (m_backbuf == 2)
+ m_backbuf = 0;
}
- /* draw the triangle */
- vd->fbi.cheating_allowed = 1;
- return triangle(vd);
+ // 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_create_work_item - finish triangle
- setup and create the work item
--------------------------------------------------*/
+//-------------------------------------------------
+// triangle - execute the 'triangle' command
+//-------------------------------------------------
-int32_t voodoo_device::triangle_create_work_item(voodoo_device* vd, uint16_t *drawbuf, int texcount)
+s32 voodoo_1_device::triangle()
{
- 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)
+ 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))
{
- 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)]++;
+ 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));
}
}
- /* 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;
+ // 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++;
- /* hook us into the hash table */
- info->next = vd->raster_hash[hash];
- vd->raster_hash[hash] = info;
+ g_profiler.stop();
- 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);
+ if (LOG_REGISTERS)
+ logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels);
- return info;
+ // 1 pixel per clock, plus some setup time
+ return TRIANGLE_SETUP_CLOCKS + pixels;
}
-/*-------------------------------------------------
- find_rasterizer - find a rasterizer that
- matches our current parameters and return
- it, creating a new one if necessary
--------------------------------------------------*/
+//-------------------------------------------------
+// accumulate_statistics - add the statistics
+// from the given thread block to the shared
+// statistics
+//-------------------------------------------------
-voodoo_device::raster_info *voodoo_device::find_rasterizer(voodoo_device *vd, int texcount)
+void voodoo_1_device::accumulate_statistics(thread_stats_block const &block)
{
- 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;
+ // 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);
- return add_rasterizer(vd, &curinfo);
+ // update emulation statistics
+ if (DEBUG_STATS)
+ m_stats.add_emulation_stats(block);
}
-/*-------------------------------------------------
- dump_rasterizer_stats - dump statistics on
- the current rasterizer usage patterns
--------------------------------------------------*/
+//-------------------------------------------------
+// update_statistics - gather statistics from
+// all threads and then reset the thread-local
+// information
+//-------------------------------------------------
-void voodoo_device::dump_rasterizer_stats(voodoo_device *vd)
+void voodoo_1_device::update_statistics(bool accumulate)
{
- static uint8_t display_index;
- raster_info *cur, *best;
- int hash;
-
- printf("----\n");
- display_index++;
-
- /* loop until we've displayed everything */
- while (1)
+ // accumulate/reset statistics from all units
+ for (auto &stats : m_renderer->thread_stats())
{
- 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;
+ if (accumulate)
+ accumulate_statistics(stats);
+ stats.reset();
}
-}
-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)
-{
+ // accumulate/reset statistics from the LFB
+ if (accumulate)
+ accumulate_statistics(m_lfb_stats);
+ m_lfb_stats.reset();
}
-voodoo_device::~voodoo_device()
-{
-}
//-------------------------------------------------
-// device_reset - device-specific reset
+// reset_counters - reset the exposed statistics
+// counters to 0
//-------------------------------------------------
-void voodoo_device::device_reset()
+void voodoo_1_device::reset_counters()
{
- soft_reset();
+ 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);
}
+
//-------------------------------------------------
-// device_stop - device-specific stop
+// check_stalled_cpu - determine if it's time to
+// un-stall a CPU given pending operations
//-------------------------------------------------
-void voodoo_device::device_stop()
+void voodoo_1_device::check_stalled_cpu(attotime current_time)
{
- /* release the work queue, ensuring all work is finished */
- if (poly != nullptr)
- poly_free(poly);
-}
+ bool resume = false;
+ // flush anything we can
+ if (operation_pending())
+ flush_fifos(current_time);
-DEFINE_DEVICE_TYPE(VOODOO_1, voodoo_1_device, "voodoo_1", "3dfx Voodoo Graphics")
+ // 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;
+ }
-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)
-{
-}
+ // 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;
-DEFINE_DEVICE_TYPE(VOODOO_2, voodoo_2_device, "voodoo_2", "3dfx Voodoo 2")
+ // either call the callback, or trigger the trigger
+ if (!m_stall_cb.isnull())
+ m_stall_cb(false);
+ else
+ machine().scheduler().trigger(m_stall_trigger);
+ }
-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)
-{
+ // if not, set a timer for the next one
+ else
+ m_stall_resume_timer->adjust(m_operation_end - current_time);
}
-DEFINE_DEVICE_TYPE(VOODOO_BANSHEE, voodoo_banshee_device, "voodoo_banshee", "3dfx Voodoo Banshee")
-
-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)
-{
-}
+//-------------------------------------------------
+// stall_cpu - stall our associated CPU until
+// operations are complete
+//-------------------------------------------------
-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::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++;
-DEFINE_DEVICE_TYPE(VOODOO_3, voodoo_3_device, "voodoo_3", "3dfx Voodoo 3")
+ // 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);
-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)
-{
+ // 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
+//-------------------------------------------------
-/***************************************************************************
- 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)
+void voodoo_1_device::stall_resume_callback(void *ptr, s32 param)
{
- 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))
- {
- 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;
- }
+ check_stalled_cpu(machine().time());
}
-/*-------------------------------------------------
- generic_0tmu - generic rasterizer for 0 TMUs
--------------------------------------------------*/
-
-RASTERIZER(generic_0tmu, 0, vd->reg[fbzColorPath].u, vd->reg[fbzMode].u, vd->reg[alphaMode].u,
- vd->reg[fogMode].u, 0, 0)
-
-
-/*-------------------------------------------------
- generic_1tmu - generic rasterizer for 1 TMU
--------------------------------------------------*/
-
-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)
-
-
-/*-------------------------------------------------
- generic_2tmu - generic rasterizer for 2 TMUs
--------------------------------------------------*/
-
-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)
+//**************************************************************************
+// VOODOO 1 REGISTER MAP
+//**************************************************************************
+
+#define REGISTER_ENTRY(name, reader, writer, bits, chips, sync, fifo) \
+ { static_register_table_entry<voodoo_1_device>::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<voodoo_1_device> 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
- *
- *************************************/
-
-/* enumeration describing reasons we might be stalled */
-enum
-{
- NOT_STALLED = 0,
- STALLED_UNTIL_FIFO_LWM,
- STALLED_UNTIL_FIFO_EMPTY
-};
+// forward declarations
+class voodoo_1_device;
+namespace voodoo { class save_proxy; }
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
-// Use old table lookup versus straight double divide
-#define USE_FAST_RECIP 0
-
-/* 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
-
-
-
-/*************************************
- *
- * 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] =
+// enumeration specifying which model of Voodoo we are emulating
+enum class voodoo_model : u8
{
- 8, 10, 8, 10,
- 11, 9, 11, 9,
- 8, 10, 8, 10,
- 11, 9, 11, 9
+ VOODOO_1,
+ VOODOO_2,
+ VOODOO_BANSHEE,
+ VOODOO_3
};
-// 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
-};
+// 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
-/*************************************
- *
- * 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
-};
+// 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;
+}
-union voodoo_reg
-{
- int32_t i;
- uint32_t u;
- float f;
- rgba rgb;
-};
+//**************************************************************************
+// INTERNAL CLASSES
+//**************************************************************************
+// include register and render classes
+#include "voodoo_regs.h"
+#include "voodoo_render.h"
+namespace voodoo
+{
+// ======================> save_proxy
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-/* enumeration specifying which model of Voodoo we are emulating */
-enum
+// save_proxy is a helper class to make hierarchical state saving more manageable;
+class save_proxy
{
- TYPE_VOODOO_1,
- TYPE_VOODOO_2,
- TYPE_VOODOO_BANSHEE,
- TYPE_VOODOO_3
-};
+public:
+ // constructor
+ save_proxy(device_t &device) :
+ m_device(device)
+ {
+ }
-#define STD_VOODOO_1_CLOCK 50000000
-#define STD_VOODOO_2_CLOCK 90000000
-#define STD_VOODOO_BANSHEE_CLOCK 90000000
-#define STD_VOODOO_3_CLOCK 132000000
+ // save an item; append the current prefix and pass through
+ template<typename T>
+ void save_item(T &&item, char const *name)
+ {
+ std::string fullname = m_prefix;
+ fullname += name;
+ m_device.save_item(std::forward<T>(item), fullname.c_str());
+ }
+ // save a pointer item; append the current prefix and pass through
+ template<typename T>
+ void save_pointer(T &&item, char const *name, u32 count)
+ {
+ std::string fullname = m_prefix;
+ fullname += name;
+ m_device.save_pointer(std::forward<T>(item), fullname.c_str(), count);
+ }
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+ // save a class; update the prefix then call the register_save method on the class
+ template<typename T>
+ 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;
+ }
-/* ----- device interface ----- */
+private:
+ // internal state
+ device_t &m_device;
+ std::string m_prefix;
+};
-class voodoo_device : public device_t
-{
-public:
- ~voodoo_device();
- void set_fbmem(int value) { m_fbmem = value; }
- void set_tmumem(int value1, int value2) { m_tmumem0 = value1; m_tmumem1 = value2; }
- template <typename T> void set_screen_tag(T &&tag) { m_screen_finder.set_tag(std::forward<T>(tag)); }
- template <typename T> void set_cpu_tag(T &&tag) { m_cpu_finder.set_tag(std::forward<T>(tag)); }
- auto vblank_callback() { return m_vblank.bind(); }
- auto stall_callback() { return m_stall.bind(); }
- auto pciint_callback() { return m_pciint.bind(); }
+// ======================> shared_tables
- void set_screen(screen_device &screen) { assert(!m_screen); m_screen = &screen; }
- void set_cpu(cpu_device &cpu) { assert(!m_cpu); m_cpu = &cpu; }
+// 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
+};
- u32 voodoo_r(offs_t offset);
- void voodoo_w(offs_t offset, u32 data, u32 mem_mask = ~0);
- 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;
+// ======================> tmu_state
- TIMER_CALLBACK_MEMBER( vblank_off_callback );
- TIMER_CALLBACK_MEMBER( stall_cpu_callback );
- TIMER_CALLBACK_MEMBER( vblank_callback );
+// tmu_state holds TMU-specific register and palette state
+class tmu_state
+{
+public:
+ // construction
+ tmu_state();
- void voodoo_postload();
+ // initialization
+ void init(int index, shared_tables const &share, u8 *ram, u32 size);
- 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);
+ // configuration
+ void set_baseaddr_mask_shift(u32 mask, u8 shift) { m_basemask = mask; m_baseshift = shift; }
-protected:
- voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt);
+ // state saving
+ void register_save(save_proxy &save);
+ void post_load();
- // device-level overrides
- virtual void device_resolve_objects() override;
- virtual void device_start() override;
- virtual void device_stop() override;
- virtual void device_reset() override;
+ // simple getters
+ voodoo_regs &regs() { return m_reg; }
+ bool dirty() const { return m_regdirty; }
- struct tmu_shared_state;
+ // simple setters
+ void mark_dirty() { m_regdirty = true; }
- struct voodoo_stats
- {
- voodoo_stats()
- {
- std::fill(std::begin(texture_mode), std::end(texture_mode), 0);
- buffer[0] = 0;
- }
+ // write to the NCC/palette registers
+ void ncc_w(offs_t offset, u32 data);
- 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
- };
+ // 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
+};
- /* 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
- };
+// ======================> memory_fifo
- 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(); }
-
- 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
- };
+// 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
+};
- 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
- };
+// ======================> debug_stats
- 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
- };
+// 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);
- 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
- };
+ // reset the stats
+ void reset();
+ // simple getters
+ bool displayed() const { return m_display; }
+ char const *string() const { return m_string.c_str(); }
- struct tmu_shared_state
- {
- void init();
+ // compute the string to display
+ void update_string(rectangle const &visarea, u32 swap_history);
- 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
+ // based on the current key state, update and return whether stats should be shown
+ bool update_display_state(bool key_pressed);
- 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
- };
+ // 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
+};
- 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 */
- };
+// ======================> static_register_table_entry
- struct dac_state
+// 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<typename BaseType>
+struct static_register_table_entry
+{
+ static constexpr u32 make_mask(int maskbits)
{
- 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
- };
+ 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);
- 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;
- };
-
+ 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
+};
- struct poly_extra_data;
+// ======================> register_table_entry
- struct banshee_info
+// 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<u32 (u32, u32)>;
+ using write_handler = delegate<u32 (u32, u32, u32)>;
+
+ // 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<typename BaseType>
+ void unpack(static_register_table_entry<BaseType> const &source, BaseType &device)
{
- 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;
- };
+ 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
+};
- 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);
- void update_statistics(bool accumulate);
- void reset_counters();
+//**************************************************************************
+// GENERIC VOODOO DEVICE
+//**************************************************************************
- static uint32_t register_r(voodoo_device *vd, offs_t offset);
+// ======================> 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 <typename T> void set_cpu(T &&tag) { m_cpu.set_tag(std::forward<T>(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(); }
- 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);
+ // getters
+ voodoo::voodoo_model model() const { return m_model; }
- static void init_save_state(voodoo_device *vd);
+ // 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;
- 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);
+ // external control
+ virtual void set_init_enable(u32 newval) = 0;
-#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"
+ // video update
+ virtual int update(bitmap_rgb32 &bitmap, const rectangle &cliprect) = 0;
-#undef RASTERIZER_ENTRY
+protected:
+ // internal construction
+ generic_voodoo_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model);
- 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);
+ // device-level overrides
+ virtual void device_start() override;
-// FIXME: this stuff should not be public
-public:
- optional_device<screen_device> m_screen_finder; // the screen we are acting on
- optional_device<cpu_device> m_cpu_finder; // the CPU we interact with
+ // 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<cpu_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
+};
- std::unique_ptr<uint8_t[]> m_fbmem_alloc;
- std::unique_ptr<uint8_t[]> 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 1 DEVICE
+//**************************************************************************
- 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?
+DECLARE_DEVICE_TYPE(VOODOO_1, voodoo_1_device)
- pci_state pci; // PCI state
- dac_state dac; // DAC state
+// ======================> voodoo_1_device
- fbi_state fbi; // FBI states
- tmu_state tmu[MAX_TMU]; // TMU states
- tmu_shared_state tmushare; // TMU shared state
- banshee_info banshee; // Banshee state
+// 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;
- legacy_poly_manager_owner poly; // polygon manager
- std::unique_ptr<stats_block[]> thread_stats; // per-thread statistics
+ // enumeration describing reasons we might be stalled
+ enum stall_state : u8
+ {
+ NOT_STALLED = 0,
+ STALLED_UNTIL_FIFO_LWM,
+ STALLED_UNTIL_FIFO_EMPTY
+ };
- voodoo_stats stats; // internal statistics
+ // 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;
- offs_t last_status_pc; // PC of last status description (for logging)
- uint32_t last_status_value; // value of last status read (for logging)
+ 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;
- 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
+protected:
+ // number of clocks to set up a triangle (just a guess)
+ static constexpr u32 TRIANGLE_SETUP_CLOCKS = 100;
- bool send_config;
- uint32_t tmu_config;
-};
+ // internal construction
+ voodoo_1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model);
-class voodoo_1_device : public voodoo_device
-{
public:
- voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-};
+ // 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) { }
-class voodoo_2_device : public voodoo_device
-{
-public:
- voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-};
+ // 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;
-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);
+ // external control
+ virtual void set_init_enable(u32 newval) override;
-protected:
- voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t vdt);
+ // video update
+ virtual int update(bitmap_rgb32 &bitmap, const rectangle &cliprect) override;
+protected:
// device-level overrides
- u32 banshee_agp_r(offs_t offset);
- void banshee_agp_w(offs_t offset, u32 data, u32 mem_mask = ~0);
-};
+ virtual void device_start() override;
+ virtual void device_stop() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+
+ // system management
+ virtual void soft_reset();
+ virtual void register_save(voodoo::save_proxy &save, u32 total_allocation);
+
+ // 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); }
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ // 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();
+
+ // 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();
+
+ // statistics
+ void accumulate_statistics(const voodoo::thread_stats_block &block);
+ void update_statistics(bool accumulate);
+ void reset_counters();
+
+ // 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);
+ // misc helpers
+ u32 chipmask_from_offset(u32 offset)
+ {
+ u32 chipmask = BIT(offset, 8, 4);
+ if (chipmask == 0)
+ chipmask = 0xf;
+ return chipmask & m_chipmask;
+ }
-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);
+ // 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<u8[]> m_memory; // allocated framebuffer/texture memory
+ std::unique_ptr<voodoo::shared_tables> m_shared; // shared tables
+ std::unique_ptr<voodoo::voodoo_renderer> 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<rgb_t> m_clut; // clut gamma data
+ std::vector<rgb_t> m_pen; // mapping from pixels to pens
+
+ // register table
+ static voodoo::static_register_table_entry<voodoo_1_device> const s_register_table[256];
};
-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)
+//**************************************************************************
+// INLINE FUNCITIONS
+//**************************************************************************
-// 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 <emmintrin.h>
-#ifdef __SSE4_1__
-#include <smmintrin.h>
-#endif
-class voodoo_device::tmu_state::stw_t
+//-------------------------------------------------
+// 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
{
-public:
- stw_t() { }
- stw_t(const stw_t& other) = default;
- stw_t &operator=(const stw_t& other) = default;
+ // statistics if enabled
+ if (DEBUG_STATS)
+ device.m_stats.m_reg_writes++;
- 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
- {
- 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;
- }
- void add(const stw_t& other)
+ // log if enabled
+ if (LOG_REGISTERS)
{
- m_st = _mm_add_pd(m_st, other.m_st);
- m_w = _mm_add_pd(m_w, other.m_w);
+ 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)));
}
- 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
+ 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
{
-public:
- stw_t() {}
- stw_t(const stw_t& other) = default;
- stw_t &operator=(const stw_t& other) = default;
+ // statistics if enabled
+ if (DEBUG_STATS)
+ device.m_stats.m_reg_reads++;
- 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
+ // get the result
+ u32 result = m_read(chipmask & m_chipmask_flags, regnum) & m_mask;
+
+ // log if enabled
+ if (LOG_REGISTERS)
{
- 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;
+ // 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);
}
-private:
- s64 m_s, m_t, m_w;
-};
-#endif
+ 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 &regentry = 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<false>();
+ auto const vsync = m_reg.vsync<false>();
+ auto const back_porch = m_reg.back_porch<false>();
+ auto const video_dimensions = m_reg.video_dimensions<false>();
+ 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<voodoo_2_device>::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<voodoo_2_device> 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<voodoo_2_device> 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 &regentry = 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<int Which>
+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 &regs = 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<u16 *>(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<u32>(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<voodoo_banshee_device>::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<voodoo_banshee_device> 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<int Which> 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<voodoo_banshee_device> 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<voodoo_banshee_device &>(*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<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_r(offset * 4 + 0 + 0xb0) << 0;
- if (ACCESSING_BITS_8_15)
- result |= downcast<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_r(offset * 4 + 1 + 0xb0) << 8;
- if (ACCESSING_BITS_16_23)
- result |= downcast<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_r(offset * 4 + 2 + 0xb0) << 16;
- if (ACCESSING_BITS_24_31)
- result |= downcast<voodoo_banshee_device *>(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<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_w(offset * 4 + 0 + 0xb0, data >> 0);
- if (ACCESSING_BITS_8_15)
- downcast<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_w(offset * 4 + 1 + 0xb0, data >> 8);
- if (ACCESSING_BITS_16_23)
- downcast<voodoo_banshee_device *>(m_voodoo.target())->banshee_vga_w(offset * 4 + 2 + 0xb0, data >> 16);
- if (ACCESSING_BITS_24_31)
- downcast<voodoo_banshee_device *>(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 <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
- template <typename T> void set_screen_tag(T &&tag) { m_screen.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_cpu(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_screen(T &&tag) { m_screen.set_tag(std::forward<T>(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<voodoo_device> m_voodoo;
+ required_device<generic_voodoo_device> m_generic_voodoo;
optional_device<cpu_device> m_cpu;
optional_device<screen_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 <typename T, typename U>
- 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<T>(cpu_tag));
- set_screen_tag(std::forward<U>(screen_tag));
+ set_cpu(std::forward<T>(cpu_tag));
+ set_screen(std::forward<U>(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<voodoo_1_device> m_voodoo;
};
class voodoo_2_pci_device : public voodoo_pci_device
{
public:
template <typename T, typename U>
- 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<T>(cpu_tag));
- set_screen_tag(std::forward<U>(screen_tag));
+ set_cpu(std::forward<T>(cpu_tag));
+ set_screen(std::forward<U>(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<voodoo_2_device> m_voodoo;
};
class voodoo_banshee_pci_device : public voodoo_pci_device
{
public:
template <typename T, typename U>
- 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<T>(cpu_tag));
- set_screen_tag(std::forward<U>(screen_tag));
+ set_cpu(std::forward<T>(cpu_tag));
+ set_screen(std::forward<U>(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<voodoo_banshee_device> m_voodoo;
};
class voodoo_3_pci_device : public voodoo_pci_device
{
public:
template <typename T, typename U>
- 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<T>(cpu_tag));
- set_screen_tag(std::forward<U>(screen_tag));
+ set_cpu(std::forward<T>(cpu_tag));
+ set_screen(std::forward<U>(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<voodoo_3_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<bool Rev1>
+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<bool Rev1>
+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<bool Rev1>
+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<bool Rev1>
+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<bool Rev1> reg_hsync<Rev1> hsync() const { return reg_hsync<Rev1>(m_regs[reg_hSync].u); }
+ template<bool Rev1> reg_vsync<Rev1> vsync() const { return reg_vsync<Rev1>(m_regs[reg_vSync].u); }
+ template<bool Rev1> reg_video_dimensions<Rev1> video_dimensions() const { return reg_video_dimensions<Rev1>(m_regs[reg_videoDimensions].u); }
+ template<bool Rev1> reg_back_porch<Rev1> back_porch() const { return reg_back_porch<Rev1>(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<u32 *>(&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<u8[]> dither_helper::s_dither4_lookup;
+std::unique_ptr<u8[]> dither_helper::s_dither2_lookup;
+std::unique_ptr<u8[]> 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 &regs, 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<u8[]>(256*4*4*2);
+ s_dither2_lookup = std::make_unique<u8[]>(256*4*4*2);
+ s_nodither_lookup = std::make_unique<u8[]>(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 <emmintrin.h>
+#ifdef __SSE4_1__
+#include <smmintrin.h>
+#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 &regs, 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<s32>(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<u8 const *>(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<u32 GenericFlags, u32 FbzCp, u32 FbzMode, u32 AlphaMode, u32 FogMode, u32 TexMode0, u32 TexMode1>
+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 &params, 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<generic, fbzcp, fbz, alpha, fog, tex0, tex1>, 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<float, poly_data, 0, POLY_FLAG_NO_CLIPPING>;
+
+
+
+//**************************************************************************
+// 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<u8[]> s_dither4_lookup;
+ static std::unique_ptr<u8[]> s_dither2_lookup;
+ static std::unique_ptr<u8[]> 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 &regs, 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 &regs, 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<int,1>::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_block> &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<u32 GenericFlags, u32 FbzCp, u32 FbzMode, u32 AlphaMode, u32 FogMode, u32 TexMode0, u32 TexMode1>
+ 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 &params, 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<voodoo::rasterizer_texture, 2> m_textures;
+ poly_array<voodoo::rasterizer_palette, 8> m_palettes;
+ voodoo::rasterizer_info *m_raster_hash[RASTER_HASH_SIZE]; // hash table of rasterizers
+ voodoo::rasterizer_info *m_generic_rasterizer[16];
+ std::list<voodoo::rasterizer_info> m_rasterizer_list;
+ std::vector<thread_stats_block> 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 <algorithm>
@@ -19,7 +20,7 @@
* Constructor
*************************************/
zeus2_renderer::zeus2_renderer(zeus2_device *state)
- : poly_manager<float, zeus2_poly_extra_data, 4, 10000>(state->machine())
+ : poly_manager<float, zeus2_poly_extra_data, 4>(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<float, zeus2_poly_extra_data, 4, 10000>
+class zeus2_renderer : public poly_manager<float, zeus2_poly_extra_data, 4>
{
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<int _NumBits>
-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<int _RBits, int _GBits, int _BBits>
-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<int _ABits, int _RBits, int _GBits, int _BBits>
+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<float, atarisy4_polydata, 2, 8192>
+ class atarisy4_renderer : public poly_manager<float, atarisy4_polydata, 2, POLY_FLAG_NO_WORK_QUEUE>
{
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<float, atarisy4_polydata, 2, 8192>(screen, FLAG_NO_WORK_QUEUE),
+ poly_manager<float, atarisy4_polydata, 2, POLY_FLAG_NO_WORK_QUEUE>(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<float, cobra_polydata, 8, 10000>
+class cobra_renderer : public poly_manager<float, cobra_polydata, 8>
{
public:
cobra_renderer(screen_device &screen)
- : poly_manager<float, cobra_polydata, 8, 10000>(screen)
+ : poly_manager<float, cobra_polydata, 8>(screen.machine())
+ , m_screen(screen)
{
m_texture_ram = std::make_unique<uint32_t[]>(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<bitmap_rgb32> m_framebuffer;
std::unique_ptr<bitmap_rgb32> m_backbuffer;
std::unique_ptr<bitmap_rgb32> 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_state *cobra = screen().machine().driver_data<cobra_state>();
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_state *cobra = screen().machine().driver_data<cobra_state>();
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<k001005_device> m_k001005;
optional_device_array<k001006_device, 2> m_k001006;
optional_device_array<k001604_device, 2> m_k001604;
- optional_device_array<voodoo_device, 2> m_voodoo;
+ optional_device_array<generic_voodoo_device, 2> m_voodoo;
required_shared_ptr<uint32_t> m_work_ram;
required_shared_ptr<uint32_t> m_generic_paletteram_32;
optional_shared_ptr_array<uint32_t, 2> 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<adc12138_device> m_adc12138;
required_device<konppc_device> m_konppc;
optional_device<eeprom_serial_93cxx_device> m_lan_eeprom;
- optional_device_array<voodoo_device, 2> m_voodoo;
+ optional_device_array<generic_voodoo_device, 2> m_voodoo;
required_ioport_array<3> m_in;
required_ioport m_dsw;
optional_ioport m_eepromout;
@@ -492,7 +492,7 @@ private:
template <uint8_t Which>
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<voodoo_device>(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<generic_voodoo_device>(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<voodoo_device, 2> m_voodoo;
+ required_device_array<generic_voodoo_device, 2> 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<float, namcos23_render_data, 4, POLY_MAX_ENTRIES>
+class namcos23_renderer : public poly_manager<float, namcos23_render_data, 4>
{
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<float, namcos23_render_data, 4, POLY_MAX_ENTRIES>(state.machine()),
+ : poly_manager<float, namcos23_render_data, 4>(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<k001604_device, 2> m_k001604;
required_device<konppc_device> m_konppc;
required_device<adc12138_device> m_adc12138;
- required_device_array<voodoo_device, 2> m_voodoo;
+ required_device_array<generic_voodoo_device, 2> 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<float, rollext_polydata, 4, 10000>
+class rollext_renderer : public poly_manager<float, rollext_polydata, 4>
{
public:
rollext_renderer(screen_device &screen)
- : poly_manager<float, rollext_polydata, 4, 10000>(screen)
+ : poly_manager<float, rollext_polydata, 4>(screen.machine())
{
m_fb = std::make_unique<bitmap_rgb32>(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<voodoo_device>(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(seattle_state::vblank_assert));
- subdevice<voodoo_device>(PCI_ID_VIDEO":voodoo")->stall_callback().set(m_galileo, FUNC(gt64xxx_device::pci_stall));
+ subdevice<generic_voodoo_device>(PCI_ID_VIDEO":voodoo")->vblank_callback().set(FUNC(seattle_state::vblank_assert));
+ subdevice<generic_voodoo_device>(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<float, taitotz_polydata, 6, 50000>
+class taitotz_renderer : public poly_manager<float, taitotz_polydata, 6>
{
public:
taitotz_renderer(taitotz_state &state, int width, int height, uint32_t *scrram, uint32_t *texram)
- : poly_manager<float, taitotz_polydata, 6, 50000>(state.machine()),
+ : poly_manager<float, taitotz_polydata, 6>(state.machine()),
m_state(state)
{
m_fb = std::make_unique<bitmap_rgb32>(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<voodoo_device>(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<generic_voodoo_device>(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<voodoo_device>(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<generic_voodoo_device>(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<voodoo_device>(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<generic_voodoo_device>(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<voodoo_device>(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<generic_voodoo_device>(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<float, gaelco3d_object_data, 1, 2000>
+ class gaelco3d_renderer : public poly_manager<float, gaelco3d_object_data, 1>
{
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<float, gs_poly_data, 2, 10000>
+class galastrm_renderer : public poly_manager<float, gs_poly_data, 2>
{
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<float, hng64_poly_data, 7, HNG64_MAX_POLYGONS>
+class hng64_poly_renderer : public poly_manager<float, hng64_poly_data, 7>
{
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<float, midvunit_object_data, 2, 4000>
+class midvunit_renderer : public poly_manager<float, midvunit_object_data, 2>
{
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<float, mz_poly_extra_data, 4, 10000>
+class midzeus_renderer : public poly_manager<float, mz_poly_extra_data, 4>
{
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<float, m2_poly_extra_data, 4, 0x10000>
+class model2_renderer : public poly_manager<float, m2_poly_extra_data, 4>
{
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<float, m2_poly_extra_data, 4, 0x10000>(state.machine())
+ : poly_manager<float, m2_poly_extra_data, 4>(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<float, model3_polydata, 6, 50000>
+class model3_renderer : public poly_manager<float, model3_polydata, 6>
{
public:
model3_renderer(running_machine &machine, int width, int height)
- : poly_manager<float, model3_polydata, 6, 50000>(machine)
+ : poly_manager<float, model3_polydata, 6>(machine)
{
m_fb = std::make_unique<bitmap_rgb32>(width, height);
m_zb = std::make_unique<bitmap_ind32>(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<float, namcos22_object_data, 4, 8000>
+class namcos22_renderer : public poly_manager<float, namcos22_object_data, 4>
{
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<double, nvidia_object_data, 26, 8192>
+class nv2a_rasterizer : public poly_manager<double, nvidia_object_data, 26>
{
public:
- nv2a_rasterizer(running_machine &machine) : poly_manager<double, nvidia_object_data, 26, 8192>(machine)
+ nv2a_rasterizer(running_machine &machine) : poly_manager<double, nvidia_object_data, 26>(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<adsp21062_device, 2> m_dsp;
optional_device_array<k033906_device, 2> m_k033906;
- optional_device_array<voodoo_device, 2> m_voodoo;
+ optional_device_array<generic_voodoo_device, 2> 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 <functional>
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<float, gaelco3d_object_data, 1, 2000>(state.machine()),
+ : poly_manager<float, gaelco3d_object_data, 1>(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<float, gs_poly_data, 2, 10000>(state.machine())
+ : poly_manager<float, gs_poly_data, 2>(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<float, hng64_poly_data, 7, HNG64_MAX_POLYGONS>(state.machine())
+ : poly_manager<float, hng64_poly_data, 7>(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<float, k001005_polydata, 10, 50000>(screen)
+ : poly_manager<float, k001005_polydata, 10>(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<k001006_device*>(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<float, k001005_polydata, 10, 50000>
+class k001005_renderer : public poly_manager<float, k001005_polydata, 10>
{
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<float, midvunit_object_data, 2, 4000>(state.machine()),
+ : poly_manager<float, midvunit_object_data, 2>(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<float, mz_poly_extra_data, 4, 10000>(state.machine()),
+ : poly_manager<float, mz_poly_extra_data, 4>(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 <algorithm>
@@ -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<uint32_t, rdp_poly_state, 8, 32000>(state.machine())
+n64_rdp::n64_rdp(n64_state &state, uint32_t* rdram, uint32_t* dmem) : poly_manager<uint32_t, rdp_poly_state, 8>(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<uint32_t, rdp_poly_state, 8, 32000>
+class n64_rdp : public poly_manager<uint32_t, rdp_poly_state, 8>
{
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<float, namcos22_object_data, 4, 8000>(state.machine()),
+ : poly_manager<float, namcos22_object_data, 4>(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<float, tc0780fpa_polydata, 6, 10000>(screen)
+ : poly_manager<float, tc0780fpa_polydata, 6>(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<float, tc0780fpa_polydata, 6, 10000>
+class tc0780fpa_renderer : public poly_manager<float, tc0780fpa_polydata, 6>
{
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<int(VERTEX_PARAMETER::ALL)>(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<int(VERTEX_PARAMETER::ALL)>(cliprect, render_spans_callback, _v1, _v2, _v3);
if (face == NV2A_GL_CULL_FACE::BACK)
if (backface_culling_culled == NV2A_GL_CULL_FACE::FRONT)
- return rasterizer.render_triangle(cliprect, render_spans_callback, (int)VERTEX_PARAMETER::ALL, _v1, _v2, _v3);
+ return rasterizer.render_triangle<int(VERTEX_PARAMETER::ALL)>(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<std::ostream> 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
}
//============================================================