New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSdx TC: Peformance improvement by using custom container. Ported erase iterator trick to SW mode. #1944

Merged
merged 8 commits into from Aug 30, 2017

Conversation

@AlessandroVetere
Contributor

AlessandroVetere commented May 13, 2017

This follows #1756.

06/06/2017: Major edit reflecting current status of PR. I will fix errors and clean the PR as soon as possible.
12/06/2017: PR updated.

Some improvements to the existing texture caching system are done:

  • I implemented the template class GSFastList as replacement for std::list in GSdx TC, both HW and SW. In GSdx TC HW (similar applies to SW Texture*), the std::list (double linked list) used for Source* and Target* lists is replaced by the custom GSFastList, double linked list built on top of a compact array, which uses a stack for free indexes and a custom struct as list node (with data, index of previous element and index of next element) to manage list traversal, node insert and node deletion.
    The data content of the node is generic T and also the initial size of the list can be declared via template.
    The list has max size equal to 2^16-1 = 65535, but the head of the list is always present thus only 2^16-2 elements can be added.
    The list automatically resizes by doubling it's size (both the array of nodes and the stack, array, of free indexes are realloc'd) when an insert occurs and the list is full.
    No resizing on deletion of nodes, thus the size in memory of the list only grows with time.
    This list by being compact is not heavily fragmented into memory and thus much more cache friendly than a std::list.
    It should be almost as fast as an std::vector if not faster, and it is optimized for the TC tasks.
    Beware there is no bounds checking for indexes passed to GSFastList functions.
  • I ported the infamous "erase iterator" trick from GSdx TC hardware to software, with serious FPS improvements in the same games that benefit from the trick in hardware mode.
  • I became paranoid and hunted down std::list in other parts of the code, replacing it with the data structure that seemed most stuited for the task.

The performance improvement are measured using standard GSdx-SSE4 32 bit D3D11 without any modification to any config.
My machine is i5-2500k@4.3GHz, GTX770 OC, 16GB DDR3-1600, Win7 64bit

HW Mode Before After
ZoE2 - Anubis 40 42.5
BG:DA - Inn 25 29.5
SW Mode Before After
ZoE2 - Anubis 37 38
BG:DA - Inn 55 65

OGL performances on my machine seemed to be bottlenecked by other factors in ZoE2, while in BG:DA they showed almost the same results of D3D11, but I didn't include those though.
I would be very happy to receive comments and results of other benchmarks if someone is brave enough.

@ramapcsx2

This comment has been minimized.

Member

ramapcsx2 commented May 15, 2017

I'm totally out of league with this impressive work but I noticed this one thing:

Beware there is no bounds checking for indexes passed to FastList functions, nor is checked whether the list is full before adding an element, but the list size should be sufficient for every game out in the wild.

Let me advise you to never assume the boundaries of things going wrong in GSdx.
If at all possible, try to have an indicator of this list overflowing. Maybe a special end node? Maybe a counter?
If it really can't be done, maybe make a debug version of this and then test the hell out of it.

It is nice work though!

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented May 16, 2017

If at all possible, try to have an indicator of this list overflowing. Maybe a special end node? Maybe a counter?

It is possible indeed by checking before InsertFront if the stack of the free indexes is empty and before Erase if it is full.
Maybe this could be added as an ifdef to be enabled only when debug mode is enabled, and print error messages in case an exception happens.

plugins/GSdx/GSTextureCache.h Outdated
@@ -152,7 +152,7 @@ class GSTextureCache
GSTexture* m_from_target;
GIFRegTEX0 m_layer_TEX0[7]; // Detect already loaded value
// Keep a GSTextureCache::m_map iterator to allow fast erase
std::array<uint16, MAX_PAGES> m_erase_it;
uint16 m_erase_it[MAX_PAGES];

This comment has been minimized.

@gregory38

gregory38 May 16, 2017

Contributor

Why ? It shouldn't have any overhead.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere May 17, 2017

Contributor

To uniform usage of arrays vs std::array in the class and also because the functionalities of std::array aren't used (bounds checking and static init).

This comment has been minimized.

@gregory38

gregory38 May 19, 2017

Contributor

Well, personally I like the std::array. Features could still be useful in the future. It would be better to migrate C array to C++ array instead. In order to avoid massive change for small gain, I prefer that new code uses them.

@gregory38

This comment has been minimized.

Contributor

gregory38 commented May 16, 2017

You need to clean this PR first.

  • you need to rebase on master to avoid the merge commit.
  • you need to remove properly the pool stuff. I don't want a commit that adds stuff and a later commit that remove it.
  • you need to use the same style as the file. (bonus: no braces for single line is better)
if ()
{
}
else
{
}

or

if () {
} else{
}

Edit

  • and squash commits that fix previous commit.
@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented May 16, 2017

Will do.
Also forgot the fast path for InsertFront my bad.
I tried using FastList for Target* too, without pooling system as Target objects are quite small, but it didn't lead to visible improvements. At least in the few games I tried. Would you prefer to have FastList also for Target(s), possibly with custom size?

@gregory38

This comment has been minimized.

Contributor

gregory38 commented May 21, 2017

Number of target is rather small for an obvious reason VRAM requirement. Most games are likely max 10 targets. Some games create lots of target (100-1000) but they often crash with out-of-memory.
A target is around 5MB * upscaling^2

plugins/GSdx/GSTextureCache.h Outdated
// The last element of the list has next index equal to END
static const uint16 END = SIZE;
// m_buffer[0] is the head of the list
Element<T> m_buffer[SIZE];

This comment has been minimized.

@turtleli

turtleli May 23, 2017

Member

Does this have to be a fixed size? Would a vector work?

This comment has been minimized.

@AlessandroVetere

AlessandroVetere May 23, 2017

Contributor

A vector does invalidate all the iterators when the underlying array is resized thus would invalidate the iterators saved in the Source objects during list insertion (for future fast deletion).
The vector wouldn't work.
Also the vector does not support random deletion without invalidating all the subsequent iterators (they are downshifted to cover the hole in the underlying array).
And it has to be fixed size beucase I cannot imagine a compact storage with iterators that do not invalidate on list operations and has not fixed size.
Maybe a hierarchy std::list -> m_buffer[SIZE] dynamically managed could work in principle, using a cache friendly SIZE and ensuring that the number or nodes of the std::list are minimized.
Logic would become unfriendly though.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere May 23, 2017

Contributor

Nevermind I was joking.
I implemented an automatically growing FastList which does not invalidate iterators by simply using realloc() and increasing the size of the two underlying arrays.
Benchmarks shows that there is not much decrease in performance wrt the statically allocated / fixed size one, so the latter is for sure a better choice. I need to clean this PR.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented May 24, 2017

gregory38 I will fix the mess don't worry.
Basically I did the following:

  • Thanks to turtleli I implemented the resizable FastList, and moved it in a separate header file named GSFastList.h
  • I ported the "erase iterator" trick also to software mode texture cache system.
  • I used FastList also in software mode for Texture*
  • I used FastList also for Target* in hardware mode
  • Hunted down std::list in other parts of the code (maybe only useful for GSDevice and GSDirtyRect)
  • REMOVED POOLING! I did my benchmark not putting attention to which part of the code was improving performances, and pooling wasn't (or a least it was by a fraction of FPS only in the heavy test cases, but increased code complexity and reduced maintainability were too heavy to burden).

Performance improvement in software mode is real, BG:DA shows +10 fps, ZoE2 +0,5~1 fps, all other games benefit a bit.
Hardware mode didn't like passing to dynamic memory instead of stack memory to save texture pointers but after some optimization it didn't left much of a impact.

@gregory38

This comment has been minimized.

Contributor

gregory38 commented Jun 3, 2017

Please ping me when you have a clean PR. Thanks you. (don't hesitate to ask any question)

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 6, 2017

I basically didn't have time to fix neither the code nor the PR, but I should be able to do both this weekend.
I think I will rebase on master and then redo the commits in a coherent way.
Also I have a question: is _aligned_realloc available under clang?
It seems the only compiler to throw error: "/home/travis/build/PCSX2/pcsx2/plugins/GSdx/./GSFastList.h:57:27: error: use of undeclared identifier '_aligned_realloc'".
The other errors under g++ or clang will be fixed easily.

@AlessandroVetere AlessandroVetere changed the title from GSdx TC: Peformance improvement by using custom container and object pooling. to GSdx TC: Peformance improvement by using custom container. Ported erase iterator trick to SW mode. Jun 6, 2017

@AlessandroVetere AlessandroVetere force-pushed the AlessandroVetere:master branch Jun 11, 2017

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 11, 2017

PR cleaned.
I think _aligned_realloc will still make build under clang fail.

@woj1993

This comment has been minimized.

Contributor

woj1993 commented Jun 12, 2017

@AlessandroVetere You have marge conflict.
Edit: You have to ping Gregory38.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 12, 2017

@woj1993 Should I resolve the conflict? It would result in a "merge commit" which Gregory38 told me to avoid. I'm new to github PR system though, so I don't know what to do exactly.
@gregory38 I cleaned up the PR, almost.

@mirh

This comment has been minimized.

mirh commented Jun 12, 2017

I think that rebasing to over 11ed4de should be enough?

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 12, 2017

@mirh I'll look into that tonight thanks for the tip. I think I can also directly rebase on top of the latest commit on master branch, just to be sure.

@AlessandroVetere AlessandroVetere force-pushed the AlessandroVetere:master branch Jun 12, 2017

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 12, 2017

@gregory38 PR cleaned, AppVeyor build succeeded. Travis doesn't show up though.

plugins/GSdx/GSFastList.h Outdated
class FastList {
public:
// The last Element<T> of the list has next_index equal to END
uint16 END;

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor

Call the variable m_end instead.

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor

Actually, is END really useful ? Couldn't you use the head (i.e. 0) as special index?

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

Ok for the renaming.
The variable I think it's useful also to keep track of the size of the list without adding another class member.
Otherwise it could be used a constant value like 0 (unused "next_index") for the next_index of the last element of the list, and keep a "m_size" uint16 variable for the size.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

Ok it's much much better to use constant value 0 for next_index of last element and rename END to m_size, using it only to manage Full() and Grow().

plugins/GSdx/GSFastList.h Outdated
Element<T>* m_buffer;
FastList() {
m_buffer = NULL;

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor

use nullptr. Same for all occurences

plugins/GSdx/GSFastList.h Outdated
}
}
private:
uint16 m_free_indexes_stack_top;

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor

move private m_* variable at the top. This way, it is easier to find them.

plugins/GSdx/GSFastList.h Outdated
};
// Class size in bytes:
// 2 * sizeof(uint16) + sizeof(Element<T>*) + sizeof(uint16*),

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor
// Class size in bytes:
// 2 * sizeof(uint16) + sizeof(Element<T>*) + sizeof(uint16*),

I don't see the purpose of this comment.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

It's kind of a leftover from design phase: I can remove it.

plugins/GSdx/GSTextureCache.cpp Outdated
for (auto &t : m_dst[type]) delete t;
m_dst[type].clear();
FastTargetPtrList& list = m_dst[type];

This comment has been minimized.

@gregory38

gregory38 Jun 15, 2017

Contributor

Why not provide an iterator for your new container ?

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

I thought of that, but being paranoid I didn't do so: would it introduce overhead? (I think not).

plugins/GSdx/GSFastList.h Outdated
m_buffer[i].next_index = NEW_END;
break;
}
}

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

By using constant value for last next_index, the above piece of code (140-146) could be removed.

plugins/GSdx/GSFastList.h Outdated
}
__forceinline bool Empty() {
return m_free_indexes_stack == 0;

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Jun 15, 2017

Contributor

Obviously it's m_free_indexes_stack_top and not m_free_indexes_stack that should be 0.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 16, 2017

@gregory38 I managed to fix what you requested, leaving the iterator implementation aside (it would require a bit of work). What isn't working now is _aligned_realloc under Linux (both clang and gcc). Can something be done to fix the problem? As I can see _aligned_malloc and _aligned_free are fully functional, and they are of the same family.

@turtleli

This comment has been minimized.

Member

turtleli commented Jun 17, 2017

_aligned_malloc and _aligned_free don't actually exist on Linux - they work in this case due to macros/compatibility functions added to GSdx.

Does _aligned_* actually provide any performance benefit in this case? I think it should be possible to just use two vectors - one to hold Element<T>*, the other to hold the indices of any removed elements.

@gregory38

This comment has been minimized.

Contributor

gregory38 commented Jun 17, 2017

There are available on Linux (C11) but they weren't compatible with GCC 4.9 ASAN hence the macro. However reallloc doesn't exists in the standard. Anyway, I think vector should be as efficient.

I'm leaving for 10 days of vacation :) It gives you time this way to look at iterator. Iterators are quite light so I don't think there is any overhead.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Jun 17, 2017

@turtleli Didn't test if _aligned_* provides significant benefits.

I'll try using only _aligned_malloc, memcpy, and _aligned_free to replace _aligned_realloc in a dirty way.
The only problem would be a slightly average execution time for the Grow() function, which isn't critical as it's both amortized and never called after the first warmup of the texture cache, and more importantly a slightly higher memory fragmentation.

I'll try also the plain realloc and free which should be available under any platform (but makes you lose alignment), and maybe it's better to lose alignment than continuous reallocation.

I would avoid using vector as I don't need their advanced capabilities over plain arrays, and I prefer to get the minimum overhead possible (which for standard library containers I'm not able to precisely evaluate in advance).

@gregory38 Have a nice holiday!
I'll look forward to implement the iterator

@turtleli

This comment has been minimized.

Member

turtleli commented Jun 17, 2017

I would avoid using vector as I don't need their advanced capabilities over plain arrays, and I prefer to get the minimum overhead possible (which for standard library containers I'm not able to precisely evaluate in advance).

Well, main advantage is that it would likely be simpler to implement, and there probably isn't much additional performance overhead (if there is any) compared to your current approach.

plugins/GSdx/GSFastList.h Outdated
__forceinline uint16 InsertFront(const T data) {
if (Full()) {
Grow();
}

This comment has been minimized.

@gregory38

gregory38 Aug 6, 2017

Contributor

again add an empty line

if(++t->m_age > 10)
{
m_textures.erase(j);
i = m_textures.erase(i);

This comment has been minimized.

@gregory38

gregory38 Aug 6, 2017

Contributor

I'm not sure that it will work. Erase should return 1. Tbh I prefer the old code.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 6, 2017

Contributor

The return value of erase is the iterator following the last removed element, according to the standard.

The pattern is the following:

for (auto i = list.begin(); i != list.end(); ) {
    if (condition) {
        i = list.erase(i);
    } else {
        ++i;
    }
}

This comment has been minimized.

@gregory38

gregory38 Aug 6, 2017

Contributor

Sorry, I read the wrong line on the man. Anyway, I still think previous pattern is better. It avoid the else branch and it is more generic. Tbh, a better solution could be something with algortihm/lambda (speed is useless here)

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 6, 2017

Contributor

Just for reference, previous pattern is:

for (auto i = list.begin(); i != list.end(); ) {
    auto j = i++;
    if (condition) {
        list.erase(j);
    }
}

Well this solution has one more variable but no else branch and discards erase return value. Still convinced that it's better? I just thought that the return value of erase should be spoiled, as it let room for optimization, but I let you decide.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 6, 2017

Contributor

By the way I applied the new pattern in all the erase while looping code of the PR, not only here.

This comment has been minimized.

@gregory38

gregory38 Aug 6, 2017

Contributor

This code is only called once by frame so execution time is 0 even without optimization. Honestly micro-optimization is good for hot-path otherwise it is better to ensure readability of code.

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 6, 2017

Contributor

Sure but given that I was trying to keep the same approach in the code, also in the other loops the same pattern has been updated. What do you prefer to do?

This comment has been minimized.

@gregory38

gregory38 Aug 6, 2017

Contributor

Fine, keep the new pattern.

@AlessandroVetere AlessandroVetere force-pushed the AlessandroVetere:master branch 2 times, most recently Aug 6, 2017

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Aug 6, 2017

Updated FastList to support access by T&, which is the default for std containers instead of T, and also updated code formatting.
Kept auto for range loop on pointers.
Kept new erase while looping pattern.

plugins/GSdx/GSTextureCache.cpp Outdated
@@ -842,11 +824,11 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
for(int type = 0; type < 2; type++)
{
for(list<Target*>::iterator i = m_dst[type].begin(); i != m_dst[type].end(); )
// AV: This code should be rewritten to avoid using this much "continue"

This comment has been minimized.

@gregory38

gregory38 Aug 12, 2017

Contributor

IMHO continue doesn't hurt. So better remove your comment or please explain the issue with continue

plugins/GSdx/GSTextureCache.cpp Outdated
@@ -867,7 +849,7 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
}
else
{
m_dst[type].erase(j);
i = list.erase(i);

This comment has been minimized.

@gregory38

gregory38 Aug 12, 2017

Contributor

honestly I found your pattern very error-prone. For short loop it is fine but here code is quite complete and you need to read it carefully (if future branch are created/delete) to properly update the iterator. Speed wise the saving is 0, so for me it isn't a good idea here

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 13, 2017

Contributor

As for this loop I agree with you, the code here is branch-wise so complex that the standard pattern is not suited at all. The "continue" comment was because I already noticed that and I thought that refactoring the code a bit would help. Easiest solution though is to use old erase pattern here.

plugins/GSdx/GSFastList.h Outdated
// The last Element<T> of the list has next_index equal to 0
// All the other Element<T> of the list are chained by next_index and prev_index
// m_buffer has dynamic size m_capacity
// m_buffer[0] is always present as auxiliary Element<T> of the list

This comment has been minimized.

@gregory38

gregory38 Aug 12, 2017

Contributor

Could you add some explanation that due to array re-allocation, pointer to element are invalidated. But fortunately for us the iterator is based on index which protect us from invalidation. (I let you translate in correct English)

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 13, 2017

Contributor

I wrote:

// Due to m_buffer reallocation, the pointers to Element<T> stored into the array
//     are invalidated every time Grow() is executed. But FastListIterator<T> is
//     index based, not pointer based, and the elements are copied in order on Grow(),
//     so there is no iterator invalidation (which is an index invalidation) until 
//     the relevant iterator (or the index alone) are erased from the list.

It's ok?

This comment has been minimized.

@gregory38

gregory38 Aug 21, 2017

Contributor

ok

plugins/GSdx/GSFastList.h Outdated
}
// 32768 is the first number that when doubled overflows uint16
const uint16 new_capacity = m_capacity < 32768 ? m_capacity * 2 : USHRT_MAX;

This comment has been minimized.

@gregory38

gregory38 Aug 12, 2017

Contributor

better use m_capacity < USHRT_MAX / 2 and remove the comment

This comment has been minimized.

@AlessandroVetere

AlessandroVetere Aug 13, 2017

Contributor

I would then say: m_capacity <= (uint16)(USHRT_MAX / 2), as 32768 is (USHRT_MAX / 2) + 1. Do you think the cast is necessary? (not that is makes any difference)

EDIT: it is not.

AlessandroVetere added some commits Aug 4, 2017

GSdx GSTextureCacheSW: Ported erase iterator trick. Using FastList in…
…stead of std::list. Using range loops. Using more efficient erase pattern.
GSdx GSDevice: Using FastList instead of std::list. Using range loops…
… (correctly). Using auto instead of declaring iterator type.
GSdx GSTextureCache: Using FastList instead of std::list. Various oth…
…er improvements.

Using range loops where possible (correctly).
Using auto where possible (minimize code changes whenever it's decided to change back to a std container).
Use more efficient erase pattern (where possible).
Minor code tweaks.

@AlessandroVetere AlessandroVetere force-pushed the AlessandroVetere:master branch to ab4591c Aug 13, 2017

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Aug 13, 2017

Rebased with the suggested changes:

  • Old erase pattern in GSTextureCache::InvalidateVideoMem(...), also removed comment
  • Invalidation explanation comment added in FastList<T>
  • Removed the magic number in FastList<T>::Grow()
@lightningterror

This comment has been minimized.

Member

lightningterror commented Aug 21, 2017

@gregory38 what's the status on this ?

@gregory38

This comment has been minimized.

Contributor

gregory38 commented Aug 21, 2017

Review is fine. I want to run a couple of dump on it. And then we can merge it.

@ssakash ssakash added the Reviewed label Aug 21, 2017

@gregory38

This comment has been minimized.

Contributor

gregory38 commented Aug 30, 2017

Ok let's go. I don't have time to test it more. And I don't want to block PRs. (Sorry for the delay and thanks for you work)

@gregory38 gregory38 merged commit a0aa585 into PCSX2:master Aug 30, 2017

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Aug 30, 2017

Thanks for the approval and the review.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Aug 30, 2017

@gregory38 There's some problem going on with the master branch Travis CI which seems to be unrelated to the merged commits.

Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
The following packages have unmet dependencies:
 libgl1-mesa-dev:i386 : Depends: libgl1-mesa-glx:i386 (= 10.1.3-0ubuntu0.6) or
                                 libgl1-mesa-glx-lts-utopic:i386 but it is not going to be installed or
                                 libgl1-mesa-glx-lts-vivid:i386 but it is not going to be installed or
                                 libgl1-mesa-glx-lts-wily:i386 but it is not going to be installed or
                                 libgl1-mesa-glx-lts-xenial:i386 but it is not going to be installed
 libglu1-mesa-dev:i386 : Depends: libglu1-mesa:i386 (= 9.0.0-2) but it is not going to be installed
 libsdl2-dev:i386 : Depends: libegl1-mesa-dev:i386
                    Depends: libgles2-mesa-dev:i386
 libwxgtk3.0-dev:i386 : Depends: libwxgtk3.0-0:i386 (= 3.0.0-2) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
The command "./travis.sh before_install" failed and exited with 100 during .
Your build has been stopped.
@gregory38

This comment has been minimized.

Contributor

gregory38 commented Aug 30, 2017

Thanks for the copy/past. I didn't manage to access the log from work. I will try to check it tomorrow.

@AlessandroVetere

This comment has been minimized.

Contributor

AlessandroVetere commented Sep 7, 2017

I know the PR is merged but ZoE2 on the most recent build is hitting 43.8 fps here in the bench case, which is +1.3 fps from my local branch (which was behind 3 months of GSdx updates) and ultimately +3.8 fps from the starting point.
Keep up the good work guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment