summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/poly.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/poly.h')
-rw-r--r--src/devices/video/poly.h1206
1 files changed, 683 insertions, 523 deletions
diff --git a/src/devices/video/poly.h b/src/devices/video/poly.h
index c619c50c2a1..e09fb17331a 100644
--- a/src/devices/video/poly.h
+++ b/src/devices/video/poly.h
@@ -37,247 +37,422 @@
#pragma once
-#include "screen.h"
-
-#include <limits.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_NO_WORK_QUEUE = 0x01;
+static constexpr u8 POLY_FLAG_NO_CLIPPING = 0x02;
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
+// base class for poly_array
+class poly_array_base
+{
+public:
+ // construction
+ poly_array_base() { }
+
+ // destruction
+ virtual ~poly_array_base() { }
+
+ // reset
+ virtual void reset() = 0;
+};
+
+
+// class for managing an array of items
+template<class ArrayType, int TrackingCount>
+class poly_array : public poly_array_base
+{
+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
+ virtual ~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)
+ {
+ assert(index < m_next);
+ 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)
+ {
+ assert(index < m_next);
+ assert(index + count <= m_next);
+ 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
+ virtual void reset() override
+ {
+ 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 tracking_index = 0)
+ {
+ // 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)
+ {
+ assert(tracking_index < TrackingCount);
+ m_last[tracking_index] = item;
+ }
+ return *item;
+ }
+
+ // return the last
+ ArrayType &last(int tracking_index = 0) const
+ {
+ assert(tracking_index < TrackingCount);
+ assert(m_last[tracking_index] != nullptr);
+ return *m_last[tracking_index];
+ }
+
+private:
+ // internal helper to make size pointers
+ ArrayType *item_ptr(u32 index)
+ {
+ assert(index < m_allocated);
+ 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 tracking_index = 0; tracking_index < TrackingCount; tracking_index++)
+ if (m_last[tracking_index] != nullptr)
+ {
+ if (m_last[tracking_index] == item_ptr(m_next))
+ m_next++;
+ else
+ next(tracking_index) = *m_last[tracking_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
{
vertex_t() { }
- vertex_t(_BaseType _x, _BaseType _y) { x = _x; y = _y; }
+ vertex_t(BaseType _x, BaseType _y) { x = _x; y = _y; }
- _BaseType x, y; // X, Y coordinates
- _BaseType p[_MaxParams]; // interpolated parameters
+ BaseType x, y; // X, Y coordinates
+ std::array<BaseType, MaxParams> p; // iterated 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];
+ BaseType start; // parameter value at start
+ BaseType dpdx; // dp/dx relative to start
+ };
+ 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;
+ using render_delegate = delegate<void (int32_t, extent_t const &, ObjectType const &, int)>;
+
+ // poly_array of object data
+ using objectdata_array = poly_array<ObjectType, 1>;
// 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");
+ void wait(char const *debug_reason = "general");
+
+ // return a reference to our ObjectType poly_array
+ objectdata_array &object_data() { return m_object; }
- // object data allocators
- _ObjectData &object_data_alloc();
- _ObjectData &object_data_last() const { return m_object.last(); }
+ // register a poly_array to be reset after a wait
+ void register_poly_array(poly_array_base &array) { m_arrays.push_back(&array); }
// 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);
- uint32_t render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents);
+ 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);
// 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(rectangle const &cliprect, render_delegate callback, vertex_t const *v);
+
+ // direct custom extents
+ template<int ParamCount>
+ uint32_t render_extents(rectangle const &cliprect, render_delegate callback, int startscanline, int numscanlines, extent_t const *extents);
// public helpers
- int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, _BaseType clipval);
+ template<int ParamCount>
+ int zclip_if_less(int numverts, vertex_t const *v, vertex_t *outv, BaseType clipval);
private:
- poly_manager(running_machine &machine, screen_device *screen, uint8_t flags);
-
- // turn this on to log the reasons for any long waits
- static constexpr bool POLY_LOG_WAITS = false;
-
// number of profiling ticks before we consider a wait "long"
static constexpr osd_ticks_t POLY_LOG_WAIT_THRESHOLD = 1000;
static constexpr int SCANLINES_PER_BUCKET = 32;
- static constexpr int CACHE_LINE_SIZE = 64; // this is a general guess
static constexpr int TOTAL_BUCKETS = (512 / SCANLINES_PER_BUCKET);
- static constexpr int UNITS_PER_POLY = (100 / SCANLINES_PER_BUCKET);
- // polygon_info describes a single polygon, which includes the poly_params
- struct polygon_info
+ // primitive_info describes a single primitive
+ struct primitive_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
+ primitive_info * primitive; // pointer to primitive
+ 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 primitive_array = poly_array<primitive_info, 0>;
+ using unit_array = poly_array<work_unit, 0>;
// round in a cross-platform consistent manner
- inline int32_t round_coordinate(_BaseType value)
+ inline int32_t round_coordinate(BaseType value)
{
- int32_t result = poly_floor(value);
-
- if ((value > 0) && (result < 0))
- return INT_MAX-1;
- return result + (value - _BaseType(result) > _BaseType(0.5));
+ 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)
+ primitive_info &primitive_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;
- polygon.m_object = &object_data_last();
- polygon.m_callback = callback;
- return polygon;
+ primitive_info &primitive = m_primitive.next();
+ primitive.m_owner = this;
+ primitive.m_object = &m_object.last();
+ primitive.m_callback = callback;
+ return primitive;
+ }
+
+ // 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
+ primitive_array m_primitive; // array of primitives
+ objectdata_array m_object; // array of object data
+ unit_array m_unit; // array of work units
+ std::vector<poly_array_base *> m_arrays; // list of arrays we are managing
// 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_polygons; // number of polygons 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 +461,25 @@ 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_polygons(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));
+ // initialize the buckets to empty
+ std::fill_n(&m_unit_bucket[0], std::size(m_unit_bucket), 0xffffffff);
+
+ // register our arrays for reset
+ register_poly_array(m_primitive);
+ register_poly_array(m_object);
+ register_poly_array(m_unit);
// request a pre-save callback for synchronization
machine.save().register_presave(save_prepost_delegate(FUNC(poly_manager::presave), this));
@@ -334,31 +490,85 @@ poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::poly_manager(runnin
// ~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
{
// accumulate stats over the entire collection
int conflicts = 0, resolved = 0;
- for (int i = 0; i < ARRAY_LENGTH(m_conflicts); i++)
+ for (int i = 0; i < std::size(m_conflicts); i++)
{
conflicts += m_conflicts[i];
resolved += m_resolved[i];
}
// 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 polygons = %d\n", m_polygons);
if (m_pixels > 1000000000)
- printf("Total pixels = %d%09d\n", (uint32_t)(m_pixels / 1000000000), (uint32_t)(m_pixels % 1000000000));
+ osd_printf_info("Total pixels = %d%09d\n", uint32_t(m_pixels / 1000000000), uint32_t(m_pixels % 1000000000));
else
- printf("Total pixels = %d\n", (uint32_t)m_pixels);
+ osd_printf_info("Total pixels = %d\n", uint32_t(m_pixels));
- printf("Conflicts: %d resolved, %d total\n", resolved, conflicts);
- printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), m_unit.waits(), m_unit.itemsize(), m_unit.allocated() * m_unit.itemsize());
- printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_polygon.max(), m_polygon.allocated(), m_polygon.waits(), m_polygon.itemsize(), m_polygon.allocated() * m_polygon.itemsize());
- printf("Object data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), m_object.waits(), m_object.itemsize(), m_object.allocated() * m_object.itemsize());
+ osd_printf_info("Conflicts: %d resolved, %d total\n", resolved, conflicts);
+ osd_printf_info("Units: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), int(m_unit.itemsize()), int(m_unit.allocated() * m_unit.itemsize()));
+ osd_printf_info("Primitives: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_primitive.max(), m_primitive.allocated(), int(m_primitive.itemsize()), int(m_primitive.allocated() * m_primitive.itemsize()));
+ osd_printf_info("Object data: %5d used, %5d allocated, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), int(m_object.itemsize()), int(m_object.allocated() * m_object.itemsize()));
+}
+#endif
+#if TRACK_POLY_WAITS
+{
+ osd_printf_info("Wait summary:\n");
+ osd_printf_info("Cause Cycles Waits Actuals Average <100 100-1k 1k-10k 10k+\n");
+ osd_printf_info("-------------------------- ------- ------- ------- ------- ------- ------- ------- -------\n");
+ while (1)
+ {
+ typename waitmap_t::value_type *biggest = nullptr;
+ for (auto &item : m_waitmap)
+ if (item.second.total_cycles > 0)
+ if (biggest == nullptr || item.second.total_cycles > biggest->second.total_cycles)
+ biggest = &item;
+
+ if (biggest == nullptr)
+ break;
+
+ osd_printf_info("%-28s%-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,37 +582,37 @@ 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;
+ primitive_info &primitive = *unit.primitive;
+ 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 = primitive.m_owner->m_unit.byindex(unit.previtem);
if (prevunit.count_next != 0)
{
- uint32_t unitnum = polygon.m_owner->m_unit.indexof(unit);
+ uint32_t unitnum = primitive.m_owner->m_unit.indexof(unit);
uint32_t new_count_next;
// attempt to atomically swap in this new value
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
// track resolved conflicts
- polygon.m_owner->m_conflicts[threadid]++;
+ primitive.m_owner->m_conflicts[threadid]++;
if (orig_count_next != 0)
- polygon.m_owner->m_resolved[threadid]++;
+ primitive.m_owner->m_resolved[threadid]++;
#endif
// if we succeeded, skip out early so we can do other work
if (orig_count_next != 0)
@@ -412,7 +622,7 @@ void *poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::work_item_cal
// iterate over extents
for (int curscan = 0; curscan < count; curscan++)
- polygon.m_callback(unit.scanline + curscan, unit.extent[curscan], *polygon.m_object, threadid);
+ primitive.m_callback(unit.scanline + curscan, unit.extent[curscan], *primitive.m_object, threadid);
// set our count to 0 and re-fetch the original count value
do
@@ -421,10 +631,10 @@ void *poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::work_item_cal
} 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 = &primitive.m_owner->m_unit.byindex(orig_count_next);
}
return nullptr;
}
@@ -434,14 +644,17 @@ void *poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::work_item_cal
// 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(char const *debug_reason)
{
- osd_ticks_t time;
+ // early out if no units outstanding
+ if (m_unit.count() == 0)
+ return;
- // 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,43 +663,18 @@ void poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::wait(const cha
// 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
- m_polygon.reset();
- m_unit.reset();
- memset(m_unit_bucket, 0xff, sizeof(m_unit_bucket));
+ // clear the buckets
+ std::fill_n(&m_unit_bucket[0], std::size(m_unit_bucket), 0xffffffff);
- // 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();
-}
-
-
-//-------------------------------------------------
-// object_data_alloc - allocate a new _ObjectData
-//-------------------------------------------------
-
-template<typename _BaseType, class _ObjectData, int _MaxParams, int _MaxPolys>
-_ObjectData &poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::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();
+ // reset all the poly arrays
+ for (auto array : m_arrays)
+ array->reset();
}
@@ -494,19 +682,16 @@ _ObjectData &poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::object
// 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;
+ vertex_t const *v1 = &_v1;
+ vertex_t const *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,32 +699,35 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_til
// 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;
+ 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;
- _BaseType maxx = v2->x;
+ BaseType minx = v1->x;
+ BaseType maxx = v2->x;
if (minx > maxx)
return 0;
- // allocate and populate a new polygon
- polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v2yclip, callback);
+ // allocate and populate a new primitive
+ primitive_info &primitive = primitive_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 +737,16 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_til
// force start < stop
if (istartx > istopx)
- {
- int32_t temp = istartx;
- istartx = istopx;
- istopx = temp;
- }
-
- // include the right edge if requested
- if (m_flags & FLAG_INCLUDE_RIGHT_EDGE)
- istopx++;
+ std::swap(istartx, 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,15 +754,15 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_til
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;
+ unit.primitive = &primitive;
unit.count_next = std::min(v2yclip - curscan, scaninc);
unit.scanline = curscan;
unit.previtem = m_unit_bucket[bucketnum];
@@ -590,29 +771,28 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_til
// 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,31 +806,22 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_til
// 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;
- const vertex_t *v3 = &_v3;
+ vertex_t const *v1 = &_v1;
+ vertex_t const *v2 = &_v2;
+ vertex_t const *v3 = &_v3;
// 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,58 +830,57 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// 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;
+ 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);
+ // allocate and populate a new primitive
+ primitive_info &primitive = primitive_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v3yclip, callback);
// compute the slopes for each portion of the triangle
- _BaseType dxdy_v1v2 = (v2->y == v1->y) ? _BaseType(0.0) : (v2->x - v1->x) / (v2->y - v1->y);
- _BaseType dxdy_v1v3 = (v3->y == v1->y) ? _BaseType(0.0) : (v3->x - v1->x) / (v3->y - v1->y);
- _BaseType dxdy_v2v3 = (v3->y == v2->y) ? _BaseType(0.0) : (v3->x - v2->x) / (v3->y - v2->y);
+ BaseType dxdy_v1v2 = (v2->y == v1->y) ? BaseType(0.0) : (v2->x - v1->x) / (v2->y - v1->y);
+ BaseType dxdy_v1v3 = (v3->y == v1->y) ? BaseType(0.0) : (v3->x - v1->x) / (v3->y - v1->y);
+ 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;
- _BaseType a02 = v2->x*v3->y - v3->x*v2->y;
- _BaseType a10 = v3->y - v1->y;
- _BaseType a11 = v1->x - v3->x;
- _BaseType a12 = v3->x*v1->y - v1->x*v3->y;
- _BaseType a20 = v1->y - v2->y;
- _BaseType a21 = v2->x - v1->x;
- _BaseType a22 = v1->x*v2->y - v2->x*v1->y;
- _BaseType det = a02 + a12 + a22;
-
- if (poly_abs(det) < _BaseType(0.00001))
+ BaseType a00 = v2->y - v3->y;
+ BaseType a01 = v3->x - v2->x;
+ BaseType a02 = v2->x*v3->y - v3->x*v2->y;
+ BaseType a10 = v3->y - v1->y;
+ BaseType a11 = v1->x - v3->x;
+ BaseType a12 = v3->x*v1->y - v1->x*v3->y;
+ BaseType a20 = v1->y - v2->y;
+ BaseType a21 = v2->x - v1->x;
+ BaseType a22 = v1->x*v2->y - v2->x*v1->y;
+ BaseType det = a02 + a12 + a22;
+
+ 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);
+ param_dpdx[paramnum] = BaseType(0.0);
+ param_dpdy[paramnum] = BaseType(0.0);
param_start[paramnum] = v1->p[paramnum];
}
}
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 +888,6 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
}
}
}
- 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,15 +895,15 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
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;
+ unit.primitive = &primitive;
unit.count_next = std::min(v3yclip - curscan, scaninc);
unit.scanline = curscan;
unit.previtem = m_unit_bucket[bucketnum];
@@ -749,9 +913,9 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
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);
- _BaseType startx = v1->x + (fully - v1->y) * dxdy_v1v3;
- _BaseType stopx;
+ BaseType fully = BaseType(curscan + extnum) + BaseType(0.5);
+ BaseType startx = v1->x + (fully - v1->y) * dxdy_v1v3;
+ BaseType stopx;
if (fully < v2->y)
stopx = v1->x + (fully - v1->y) * dxdy_v1v2;
else
@@ -763,21 +927,14 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// force start < stop
if (istartx > istopx)
- {
- int32_t temp = istartx;
- istartx = istopx;
- istopx = temp;
- }
-
- // include the right edge if requested
- if (m_flags & FLAG_INCLUDE_RIGHT_EDGE)
- istopx++;
+ std::swap(istartx, 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 +942,11 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
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++)
+ BaseType fullstartx = BaseType(istartx) + BaseType(0.5);
+ 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 +955,7 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
}
// 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 +969,14 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// 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(rectangle const &cliprect, render_delegate callback, int numverts, vertex_t const *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,33 +986,40 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// 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(rectangle const &cliprect, render_delegate callback, int numverts, vertex_t const *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;
}
//-------------------------------------------------
-// render_triangle_custom - perform a custom
-// render of an object, given specific extents
+// render_extents - perform a custom 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>
+template<int ParamCount>
+uint32_t poly_manager<BaseType, ObjectType, MaxParams, Flags>::render_extents(rectangle const &cliprect, render_delegate callback, int startscanline, int numscanlines, extent_t const *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);
+ // allocate and populate a new primitive
+ primitive_info &primitive = primitive_alloc(0, 0, v1yclip, v3yclip, callback);
// compute the X extents for each scanline
int32_t pixels = 0;
@@ -864,15 +1027,15 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
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;
+ unit.primitive = &primitive;
unit.count_next = std::min(v3yclip - curscan, scaninc);
unit.scanline = curscan;
unit.previtem = m_unit_bucket[bucketnum];
@@ -881,18 +1044,17 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// iterate over extents
for (int extnum = 0; extnum < unit.count_next; extnum++)
{
- const extent_t &srcextent = extents[(curscan + extnum) - startscanline];
+ extent_t const &srcextent = extents[(curscan + extnum) - startscanline];
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];
@@ -900,23 +1062,22 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
extent.stopx = istopx;
// fill in the parameters for the extent
- for (int paramnum = 0; paramnum < _MaxParams; paramnum++)
+ for (int paramnum = 0; paramnum < ParamCount; paramnum++)
{
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 +1091,23 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tri
// 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(rectangle const &cliprect, render_delegate callback, vertex_t const *v)
{
// determine min/max Y vertices
- _BaseType minx = v[0].x;
- _BaseType maxx = v[0].x;
+ 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,62 +1116,65 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
// 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;
+ 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);
+ // allocate a new primitive
+ primitive_info &primitive = primitive_alloc(round_coordinate(minx), round_coordinate(maxx), minyclip, maxyclip, callback);
// 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
+ vertex_t const *v1; // pointer to first vertex
+ vertex_t const *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;
}
@@ -1020,7 +1182,7 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
// 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
- const poly_edge *ledge, *redge;
+ poly_edge const *ledge, *redge;
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))
{
@@ -1039,15 +1201,15 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
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;
+ unit.primitive = &primitive;
unit.count_next = std::min(maxyclip - curscan, scaninc);
unit.scanline = curscan;
unit.previtem = m_unit_bucket[bucketnum];
@@ -1057,13 +1219,13 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
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);
+ BaseType fully = BaseType(curscan + extnum) + BaseType(0.5);
while (fully > ledge->v2->y && fully < v[maxv].y)
++ledge;
while (fully > redge->v2->y && fully < v[maxv].y)
++redge;
- _BaseType startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
- _BaseType stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
+ BaseType startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
+ BaseType stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
// clamp to full pixels
int32_t istartx = round_coordinate(startx);
@@ -1071,54 +1233,51 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
// 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 ldy = fully - ledge->v1->y;
+ BaseType rdy = fully - redge->v1->y;
+ 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];
- _BaseType dpdx = (rparam - lparam) * oox;
+ BaseType lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum];
+ BaseType rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum];
+ BaseType dpdx = (rparam - lparam) * oox;
- extent.param[paramnum].start = lparam;// - (_BaseType(istartx) + 0.5f) * dpdx;
+ extent.param[paramnum].start = lparam;// - (BaseType(istartx) + 0.5f) * dpdx;
extent.param[paramnum].dpdx = dpdx;
}
}
- // include the right edge if requested
- if (m_flags & 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++;
+ // return the total number of pixels in the polygon
+ m_polygons++;
m_pixels += pixels;
return pixels;
}
@@ -1129,8 +1288,9 @@ uint32_t poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_pol
// 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, vertex_t const *v, vertex_t *outv, BaseType clipval)
{
bool prevclipped = (v[numverts - 1].p[0] < clipval);
vertex_t *nextout = outv;
@@ -1143,12 +1303,12 @@ int poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::zclip_if_less(i
// if we switched from clipped to non-clipped, interpolate a vertex
if (thisclipped != prevclipped)
{
- const vertex_t &v1 = v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)];
- const vertex_t &v2 = v[vertnum];
- _BaseType frac = (clipval - v1.p[0]) / (v2.p[0] - v1.p[0]);
+ vertex_t const &v1 = v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)];
+ vertex_t const &v2 = v[vertnum];
+ 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;
}
@@ -1164,23 +1324,23 @@ int poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::zclip_if_less(i
}
-template<typename _BaseType, int _MaxParams>
+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)
+template<typename BaseType, int MaxParams>
+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;
- const _BaseType W_PLANE = 0.000001f;
+ const BaseType W_PLANE = 0.000001f;
- frustum_clip_vertex<_BaseType, _MaxParams> clipv[10];
+ frustum_clip_vertex<BaseType, MaxParams> clipv[10];
int clip_verts = 0;
int previ = num_vertices - 1;
@@ -1193,11 +1353,11 @@ int frustum_clip_w(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_
if ((v1_side * v2_side) < 0) // edge goes through W plane
{
// insert vertex at intersection point
- _BaseType wdiv = v[previ].w - v[i].w;
+ BaseType wdiv = v[previ].w - v[i].w;
if (wdiv == 0.0f) // 0 edge means degenerate polygon
return 0;
- _BaseType t = fabs((W_PLANE - v[previ].w) / wdiv);
+ BaseType t = fabs((W_PLANE - v[previ].w) / wdiv);
clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t);
clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t);
@@ -1205,7 +1365,7 @@ int frustum_clip_w(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_
clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t);
// Interpolate the rest of the parameters
- for (int pi = 0; pi < _MaxParams; pi++)
+ for (int pi = 0; pi < MaxParams; pi++)
clipv[clip_verts].p[pi] = v[previ].p[pi] + ((v[i].p[pi] - v[previ].p[pi]) * t);
++clip_verts;
@@ -1224,13 +1384,13 @@ int frustum_clip_w(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_
}
-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)
+template<typename BaseType, int MaxParams>
+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;
- frustum_clip_vertex<_BaseType, _MaxParams> clipv[10];
+ frustum_clip_vertex<BaseType, MaxParams> clipv[10];
int clip_verts = 0;
int previ = num_vertices - 1;
@@ -1238,10 +1398,10 @@ int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_ve
for (int i=0; i < num_vertices; i++)
{
int v1_side, v2_side;
- _BaseType* v1a = (_BaseType*)&v[i];
- _BaseType* v2a = (_BaseType*)&v[previ];
+ BaseType* v1a = (BaseType*)&v[i];
+ BaseType* v2a = (BaseType*)&v[previ];
- _BaseType v1_axis, v2_axis;
+ BaseType v1_axis, v2_axis;
if (sign) // +axis
{
@@ -1260,12 +1420,12 @@ int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_ve
if ((v1_side * v2_side) < 0) // edge goes through W plane
{
// insert vertex at intersection point
- _BaseType wdiv = ((v[previ].w - v2_axis) - (v[i].w - v1_axis));
+ BaseType wdiv = ((v[previ].w - v2_axis) - (v[i].w - v1_axis));
if (wdiv == 0.0f) // 0 edge means degenerate polygon
return 0;
- _BaseType t = fabs((v[previ].w - v2_axis) / wdiv);
+ BaseType t = fabs((v[previ].w - v2_axis) / wdiv);
clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t);
clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t);
@@ -1273,7 +1433,7 @@ int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_ve
clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t);
// Interpolate the rest of the parameters
- for (int pi = 0; pi < _MaxParams; pi++)
+ for (int pi = 0; pi < MaxParams; pi++)
clipv[clip_verts].p[pi] = v[previ].p[pi] + ((v[i].p[pi] - v[previ].p[pi]) * t);
++clip_verts;
@@ -1292,16 +1452,16 @@ int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_ve
}
-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)
+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)
{
- 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
- num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X
- num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y
- num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X
- num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z
- num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z
+ 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
+ num_vertices = frustum_clip<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X
+ num_vertices = frustum_clip<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y
+ num_vertices = frustum_clip<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X
+ num_vertices = frustum_clip<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z
+ num_vertices = frustum_clip<BaseType, MaxParams>(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z
out = clip_vert;
return num_vertices;
}