Commit Graph

54 Commits

Author SHA1 Message Date
Arseny Kapoulkine 6b876fc7b6 vcacheoptimizer: Tweak condition to help MSVC generate branchless code (#639)
gcc/clang lower the condition to cmov sequence but MSVC uses branches
here; it's important to use branchless lowering as these branches are
difficult to predict. This change makes optimizeVertexCache ~7% faster
on MSVC on large meshes.
2023-12-08 10:42:41 -08:00
Arseny Kapoulkine 9cc883c581 vcacheoptimizer: Adjust comment to make aliasing more apparent 2023-12-07 15:26:56 -08:00
Guilherme Avila e617d44a42 vcacheoptimizer: Remove redundant live_count buffer (#638)
live_count can alias adjacency.counts as they always contain the same data; this saves a little bit of memory and time.
2023-12-07 15:23:19 -08:00
Arseny Kapoulkine eca51968d9 vcacheoptimizer: Improve meshopt_optimizeVertexCache performance by ~15%
The core of this algorithm has a few branches in the inner loops that
are all difficult to predict. The triangle scoring was already optimized
to cmov by clang/gcc, but the cache copy wasn't - and the result
consumed a surprisingly large fraction of the total compute; making that
code branchless yielded ~7% speedup by itself.

The other ~7% speedup is achieved by a live_triangles check during
scoring update; there's no need to update anything if we aren't going to
use this vertex again. This is likely to be less effective on other
meshes, but it's rather effective on Buddha mesh.

Note: live_triangles is equivalent to adjacency.counts at the point of
cache score update, but checking adjacency.counts generates better code
on clang.
2023-06-22 18:36:58 -07:00
Arseny Kapoulkine 06ec5b4880 Fix "neighbor" spelling to consistently use US variant 2022-11-23 17:01:40 +01:00
Arseny Kapoulkine 6df17a53cd vcacheoptimizer: Update strip tables with recent tuning results
These tables are a tiny bit better on some meshes (1-2%), and are also
slightly better re: ACMR compared to the previous data.
2020-01-26 23:55:49 -08:00
Arseny Kapoulkine 027ab283f9 vcacheoptimizer: Add a separate score table for strip-like sequences
The new score table has been tuned to minimize the encoded index buffer
size. We'll need to re-tune it again after some index codec changes but
it seems to produce longer strips (which are more efficient to compress
post-deflate) so I'm calling this variant "strip".

This also externalizes the table-driven optimizer which will make it
easier to build vcachetuner.
2020-01-26 22:51:42 -08:00
Arseny Kapoulkine 12d404ffa6 vcacheoptimizer: Update score tables using DE run
New tables are retuned using differential evolution, ran over ~1 day on
a 96-core GCP machine. The results are ~0.6% better than the table we
used to have across AMD & NV GPUs.

Also switch default population size to 95 - 100 elements don't
parallelize well across 96 cores which results in poor utilization.
2019-06-19 21:52:42 -07:00
Arseny Kapoulkine 9242c06387 vcacheoptimizer: Remove math.h include
This used to be necessary back when we didn't have a precomputed score
table, but we don't use any fp functions anymore.
2019-01-16 22:47:02 -08:00
Arseny Kapoulkine 10368f56c5 Replace all remaining char types with unsigned char
For cases where the sign doesn't matter, we now consistently use
`unsigned char` to make sure the codebase never uses unadorned `char` as
you can't rely on it being signed or unsigned.

This makes it easy to replace `unsigned char` with uint8_t in the
future.
2018-12-05 20:08:16 -08:00
Arseny Kapoulkine 6acef90c3c Remove constructor from TriangleAdjacency & EdgeAdjacency
Since we don't use meshopt_Buffer anymore, it's just as easy to allocate
the arrays in buildAdjacency functions. This removes the only external
symbol from the library out that's not part of the interface.
2018-11-26 08:44:54 -08:00
Arseny Kapoulkine fcc3c307f9 Replace meshopt_Buffer with meshopt_Allocator
meshopt_Allocator can be used to allocate typed buffers and automatically
deallocate them later. Unlike meshopt_Buffer, the result is a pointer
that can be dereferenced at no additional cost in Debug.

This change migrates from meshopt_Buffer to meshopt_Allocator to
improve performance in Debug. Note that we forgo bounds checking in
Debug by using this type, but we were already inconsistent about using
pointers vs buffers - address sanitizer will help ensure memory safety
and we won't need to compromise Debug performance in regular builds for
that.

The following times are taken in MSVC 2017 x64 Debug using buddha.obj:

meshopt_analyzeOverdraw: 10.1s -> 7.7s
meshopt_analyzeVertexCache: 5.4s -> 0.9s
meshopt_analyzeVertexFetch: 1.2s -> 0.7s
meshopt_optimizeOverdraw: 1.0s -> 0.7s
meshopt_optimizeVertexCache: 26.1s -> 5.6s
meshopt_simplify: 3.7s -> 2.8s
2018-11-12 23:16:21 -08:00
Arseny Kapoulkine 9d1bf03b94 Convert CRLF to LF everywhere
We had a mixture of files that were using LF and files that were using
CRLF. For consistency convert *everything* to LF.

This unfortunately means that for most code blame will become less
useful since you'd need to go past this commit but such is life.
2018-10-17 19:16:18 -07:00
Arseny Kapoulkine 82abacc1ec vcache: Fix global variable naming
All global constant symbols use kPascalCase naming convention, so rename
vcache tables and constants to match.
2018-06-19 21:46:45 -07:00
Arseny Kapoulkine 799c32f708 vcacheoptimizer: Refactor adjacency building
This change renames the adjacency structure/functions to triangle
adjacency to avoid conflicts with edge adjacency structure/functions
we'll need for the simplifier.

Also rename triangle_counts to counts and use memset instead of a for
loop to fill the initial counts.
2018-05-29 08:52:20 -07:00
Arseny Kapoulkine a3c320acec Replace explicit new[] calls with meshopt_Buffer::allocate
We now have no memory allocation operations other than in meshopt_Buffer
and meshopt_IndexAdapter; this makes it easier to replace allocation
functions...
2018-05-07 13:58:08 -07:00
Arseny Kapoulkine 3e231059cd Reformat code with new clang-format 2018-04-04 09:31:48 -07:00
Arseny Kapoulkine 692b4e1e55 vcacheoptimizer: Move table definition to start of the file 2018-02-18 12:56:01 -08:00
Arseny Kapoulkine 18f0220fd5 vcache: Replace score table with results of vcachetuner
The new tables have been generated by a ~3-day 64-core run of
vcachetuner optimizing for AMD GCN & NVidia Pascal profiles. In general
the new tables show small improvements across the board on many meshes
(in the 1-2% range), are mostly flat on other cache profiles (e.g.
Intel), and sometimes have a <1% penalty. The overall gain in terms of
average improvement is around 1% on a test mesh set.

One distinguishing mesh, however, is a regular grid, where the new
tables are ~6% better on NV, ~9% better on AMD, ~10% better on Intel -
with the new tables the results are much closer to FIFO algorithm so
unless optimization time is an issue this algorithm is finally on par or
better than FIFO (it's still slightly worse on regular grids on AMD with
~2% worse ACMR, but it's slightly better on NVidia).

Finally, it's worth noting that since the new tables were learned tabula
rasa, the insight-driven scoring formulas from before need not apply.
It's also possible to retrain the algorithm targeting a particular
hardware to get better results (tuning *just* for AMD ends up producing
even better results).
2017-12-26 16:24:52 -08:00
Arseny Kapoulkine 3c3a953653 Reformat constant tables
Work around clang-format indentation issues by putting the opening brace
at the same line.
2017-12-25 15:36:38 -08:00
Arseny Kapoulkine 5b42203fdc vcache: Trim vcache optimizer tables
We only use first 16 entries from the cache score table so we only need
16.

For valence, most vertices in real meshes have small valences; less than
1% of vertices in the (large) test mesh set have valence>8. Because of
this it is hard to gather good data about how large valences should
behave so we limit the value to 8.

These changes make it a bit easier to tune the tables.
2017-12-25 15:32:50 -08:00
Arseny Kapoulkine 2f2eee1c2f vcache: Convert to meshopt_Buffer<T>
Note that since meshopt_Buffer<T> currently can't be reallocated we
modify the .data member directly.
2017-12-23 18:15:45 -08:00
Arseny Kapoulkine ed4f04238f vcache: Optimize adjacency building a bit
We now pre-allocate adjacency data early for clarity, and don't do a
redundant temporary allocation for adjacency offsets since we can reuse
the existing prefix-sum array and fix it up after we add all triangles
to the lists.
2017-12-22 12:58:29 -08:00
Arseny Kapoulkine 84d5399d9a vcacheoptimizer: Refactor split implementation
Inline vcache optimization algorithms into their only callsites.
2017-11-21 08:43:54 -08:00
Arseny Kapoulkine 1a455cf646 vcache: Cleanly split two vcache algorithms into two functions
meshopt_optimizeVertexCache now doesn't take a cache_size argument and
should be preferred in general because it produces more optimal results
on real meshes & real hardware.

meshopt_optimizeVertexCacheFifo runs up to 3x faster but requires
apriori knowledge of the cache size and additionally requires that the
cache follows strict FIFO replacement policy (which is generally not the
case; in particular, on real GPUs warp boundaries penalize this
algorithm compared to the other one).
2017-11-21 08:40:01 -08:00
Arseny Kapoulkine 40731d15d0 vcacheoptimizer: Fix vertex_score_table_live usage/generation
The clamping logic was off by one and the code to generate the table had
a wrong table declaration.
2017-11-18 23:38:23 -08:00
Arseny Kapoulkine 66462b055a vcacheoptimizer: Fix vertex_score_table_live table
The table had the last entry (corresponding to valence=32) implicitly
initialized to zero instead of the appropriate value.
2017-11-18 23:34:48 -08:00
Arseny Kapoulkine 96ed4021d9 vcacheoptimizer: Minor refactoring
Convert internal functions to work with pointers instead of std::vector;
this makes it easier to remove std::vector.
2017-11-17 23:25:31 -08:00
Arseny Kapoulkine c9ad516d71 Cleanup includes
Separate CRT includes from STL includes to make it clear which files use
STL and which don't; also remove some redundant includes.
2017-09-29 19:51:28 -07:00
Arseny Kapoulkine 7199a582cf vcache: Minor refactoring
Rename functions to match the algorithm they are using instead of the
cache they are modeling.
2017-08-24 20:42:35 -07:00
Arseny Kapoulkine 137d2974bd Move function implementations back into namespace meshopt
This mostly makes profiler output nicer but also works around build
non-determinism for some compilers (that generate unique symbol names
for anonymous namespaces in each compilation attempt).
2017-08-20 18:07:12 +01:00
Arseny Kapoulkine c3521ab1f1 Implement C-style interface
Now all main entrypoints to the library are C-style - they use
non-mangled symbols without any default arguments or other C++ features.
We still have templated wrappers in namespace meshopt.

The implementation currently uses anonymous namespaces to reduce the
amount of differences, which may need some cleanup.
2017-08-20 13:52:37 +01:00
Arseny Kapoulkine 1f253b913c Rename meshoptimizer.hpp to meshoptimizer.h
This is a first step towards making a C-compatible interface.
2017-08-20 13:51:57 +01:00
Arseny Kapoulkine 3aadcc043c vcache: Remove emitted triangles from adjacency data
This makes sure that we don't update the triangle scores for triangles
that are already emitted with minimal cost; this resolves some weird
behavior with scores making it possible for us to set scores of already
emitted triangles to 0, and also speeding up the optimization process.

On most meshes this change makes optimization ~1.2x faster, some meshes
like powerplant.obj see more significant gains (~1.8x).
2017-08-12 09:55:41 +01:00
Arseny Kapoulkine b34f51f617 Fix Tipsify paper reference. 2017-08-07 19:11:17 +01:00
Arseny Kapoulkine 0617a4980d Reformat code 2017-08-07 11:58:32 +01:00
Arseny Kapoulkine 0fa20ffad3 vcache: Minor refactoring of LRU optimizer
Streamline cache management logic by making it similar to that from
cache analyzer.
2017-08-06 14:52:12 +01:00
Arseny Kapoulkine ce93eaf278 vcache: Update tables for linear cache algorithm
The new tables provide marginally better results (1% relative
improvement) on both LRU simulation and NVidia hardware.
2017-08-06 11:20:17 +01:00
Arseny Kapoulkine bf7b5b3a9a vcache: Generate vertex score tables
It seems like the parameters published in the original paper are not
really optimal. To facilitate their tuning, generate them based on the
input configuration so that we can bruteforce the better set of values.

Note that this change also switches to a table-based vertex valence
scoring - this eliminates a potentially expensive sqrt (which is
expensive if it's not inlined). We clamp effective vertex valence to 31
which seems to be enough for all practical uses...
2017-08-05 09:21:10 +01:00
Arseny Kapoulkine 2d099baff4 vcache: Remove faulty assertion 2017-08-03 19:18:06 +01:00
Arseny Kapoulkine 1ba908d296 vcache: Fix MSVC warning 2017-08-03 17:59:32 +01:00
Arseny Kapoulkine 8fbd86c2f4 vcache: Refactor linear cache optimizer
We now use the same adjacency structure/code as Tipsify algorithm, and
also use arrays for all items instead of a struct Vertex.

Instead of a complex std::copy-driven cache update, just copy all
vertices from the old cache to the new cache, unless they refer to
existing vertices. This reuqires much less code, and has the same
performance.

Finally, tweak the code a bit to make it resemble Tipsify more.
2017-08-02 22:53:59 -07:00
Arseny Kapoulkine a01589e72f Reformat code 2017-08-02 20:59:37 -07:00
Arseny Kapoulkine f8dc0387ab vcache: Make sure linear cache optimizer is always linear
The biggest weak spot of the linear optimizer performance-wise is the
best triangle search - it scans over the entire triangle sequence
whenever we hit a dead-end.

When we hit a dead-end this means that we have exhausted all triangle
neighbors of the vertices in the cache, so the next triangle is bound to
be a cache miss and in general will start a new disjoint strip.

It's not clear why we would pick a best score triangle for this, and
just cycling through the triangles in the input order guarantees O(kN)
runtime for the algorithm, with k being the cache size.

The effect of this change on cache efficiency is minimal - some meshes
are slightly better, some are slightly worse.

We might explore dead-end stack similar to Tipsify for this later, as it
seems like it might be beneficial to connect to an existing set of
vertices even if they are not in the cache anymore.
2017-08-02 20:49:24 -07:00
Arseny Kapoulkine fd65978662 vcache: Fix linear cache optimizer to handle degenerate triangles
The code that updated the LRU cache assumed that all triangle indices
are distinct, which is not always the case. This code probably needs to
be rewritten to be shorter/simpler but for now this fixes the issue,
which allows us to run the stats on all meshes in the dataset.
2017-08-02 20:47:18 -07:00
Arseny Kapoulkine be30f46346 vcache: Add linear vertex cache optimization back
This algorithm was originally part of this library, but then it was
removed because on FIFO simulated cache it was consistently worse than
Tipsify, and had comparatively bad performance characteristics.

Based on testing on real hardware, it resembles LRU much more than it
does FIFO, so having this is actually very beneficial, once we solve the
performance issues.

For now just add it back as is; it can be invoked by setting cache_size
to 0 (the algorithm generates sequences that do not depend that much on
the actual hardware cache size; internally we use 16 as it matches the
behavior of AMD/NVidia GPUs reasonably well).
2017-08-02 08:43:17 -07:00
Arseny Kapoulkine fbd6881d93 Remove extra code supporting 16-bit indices
Since index conversion is now performed by C++ inline adapters we don't
need extra complexity inside the implementation.
2017-07-18 09:00:24 -07:00
Arseny Kapoulkine 353e3d1e86 Rename time_stamp to timestamp 2017-07-11 08:49:39 -07:00
Arseny Kapoulkine 35494f614f Add more assertions
Also remove calculateACMR which isn't used any more and slightly
optimize buildAdjacency.
2017-07-10 21:15:03 -07:00
Arseny Kapoulkine eafd83ddc8 Remove clusters from vcacheoptimizer
There are several issues with passing cluster data around from algorithm
to algorithm:

- It complicates the interface, making overdraw optimization slightly
harder to use. There is also some asymmetry in the interface and the
user has to deal with one extra dynamically allocated array if they want
to optimize for overdraw.

- It ties the vertex cache and overdraw optimization algorithms together
- we can't really swap out one algorithm for another easily.

- It uses a specific cluster selection that can in some cases
significantly penalize the post-overdraw ACMR even with threshold=1 -
this is contrary to what Tipsify whitepaper claims.

To solve all these issues, we now generate the cluster information in
the overdraw algorithm. We follow a similar structure where we generate
hard boundaries and then generate soft boundaries based on that; instead
of using vertex cache algorithm flow to generate hard boundaries, we
treat any triangle that has all its three vertices miss the vertex cache
as the hard boundary.

The motivation behind this choice is simple - most vertex cache algorithms
will try to use greedy choices for the next triangle, and will only fall
back to a triangle that's out of the cache as some sort of fallback,
which means that it's likely that a triangle like this starts a
cache-disjoint patch of triangles and as such the penalty for reordering
at this boundary is going to be low.

In practice, while this choice does not mean that we perfectly preserve
ACMR when reordering along hard boundaries, it does result in a closer
match between expected ACMR and real ACMR after overdraw optimization.
2017-07-10 21:14:27 -07:00