Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Jabberwocky

Pages: [1] 2 3 ... 11
1
Graphics / Re: sprite scaling: local-space vs. world-space
« on: April 04, 2017, 01:12:52 pm »
Ok, I'll give that a shot.  Thanks for the quick reply!

2
Graphics / sprite scaling: local-space vs. world-space
« on: April 04, 2017, 12:56:46 pm »
This seems like it should be a remarkably easy thing to solve.  But for some reason it's stumping me.

I have a sprite.  This sprite might be scaled, rotated, or otherwise transformed in any way.
Now, I want to further stretch (scale) this sprite along the x axis of the screen (i.e. stretch left and right) regardless of the sprite's orientation.  I do not want to stretch along the x axis of the sprite itself.

Simply calling this:
sf::Sprite::scale(scaleFactor, 1.f)
doesn't work, because it would only stretch in the proper direction if the sprite was non-rotated.  For example, if I turned the sprite 90 degrees, then it would now be stretched on the screen y axis.  I always want the stretching on the screen x axis.

In other words, the sf::Sprite::scale function works as a local-space scaling factor.  I need a world-space scaling factor.

Is there something simple I can do with an sf::Transform here?  It's no problem if I have to perform a per-frame function call to accomplish this, to account for a rotating sprite.

It seems like I'm missing something obvious.
Thanks!

3
Graphics / Re: Help with sprite animation
« on: February 28, 2017, 11:47:24 am »
Something like this should do it.
   // After you set the animation on your sprite:
   sf::IntRect rectAnimFrame = sprite.getTextureRect();

   // to draw sprite from bottom right:
   sprite.setOrigin(sf::Vector2f(rectAnimFrame.width, rectAnimFrame.height));
   // to draw sprite from bottom center:
   sprite.setOrigin(sf::Vector2f(rectAnimFrame.width / 2.f, rectAnimFrame.height));
 

4
Graphics / Re: SFML graphics perf analysis
« on: February 21, 2017, 06:51:02 pm »
Ok. 

I definitely cast my vote (for whatever that's worth) towards performance being a core consideration with SFML 3.  Although I understand that is likely a long way off. 

I appreciate your insights into some of the performance issues I've encountered, binary1248.  I can probably knock off some low hanging fruit on my own.


5
Graphics / Re: SFML graphics perf analysis
« on: February 21, 2017, 02:47:01 am »
I disagree on some of your points binary1248.  But before I get into it, I just want to say thank you for your always detailed and intelligent responses.  I very much appreciate it.

If after reading this, your mindset remains, "yeah, we just don't care about stock SFML performance with heavy shader use", I understand.  I can deal with it on my own.  But I just wanted to try to do a little more convincing before I fold my cards.  ;)

Reading out of states.shader to set the current program costs a relatively high amount of CPU cycles because of the incurred cache miss. Cache misses ironically also count towards CPU load even though the CPU doesn't actually do anything while it stalls waiting for new data.

Ok, I understand what you're saying.  But based on the perf hit I saw, it looked like way more than just a cache miss.  Something heavier looks like it's going on with those calls.

I think you forgot that the current program state is specific to each context... Your code would break if you rendered to 2 different sf::RenderTargets with the same shader

Yeah.  I thought I addressed that when I said you'd also have to call sf::Shader::bind(NULL) whenever you switch RenderTargets.

(not to mention your static variable would have to be protected by a mutex as well in order to support multi-threaded use).

I thought about that.  This was primarily why I called my solution "hacky" - just to demonstrate the general approach.  It might be nice if you could set a compile flag on whether to support multi-threaded rendering, and if not, compile out these mutexes (default behaviour).  I'd bet the vast majority don't use it.  Anybody advanced enough to actually handle multi-threaded rendering can handle dealing with a compiler flag, in CMake or whatever. 

This is the reason why the state cache is in the sf::RenderTarget itself. Following on from that, accessing the state cache anywhere outside of sf::RenderTarget would make little to no sense, meaning that this is an optimization that applies solely to applyShader. The uniform binding and everything else inside sf::Shader would be unaffected by this and you would still end up with loads of program changing per frame.

Right.  So perhaps a more appropriate place to store this "pLastShaderUsed" pointer would be along with the state cache in the sf::RenderTarget? 

Yes, it is an optimization that would apply solely to applyShader.  Yet it appears to be a significant optimization, at least in my case.

How common is my case?  I don't know.  Maybe most people don't use shaders at all in SFML.  But in almost all non-trivial 3D games, you generally have a shader on every mesh in the game.  And quite often, it is the same shader, to handle lighting and shadows most commonly.  This seems to be becoming more popular in 2D games as well, judging from new 2D games I am seeing released on steam, or devlogs on indie game sites.  As well as tools popping up out there which create normal, spec, and other maps for your 2D sprites. 

e.g.)  sprite dlight
e.g.)  sprite illuminator

... all of which require shaders on every drawable.  And it is in this case that the pLastShaderUsed optimization seems to be a non-trivial improvement.

Let's say you have 100 drawables on screen.  It appears to be much quicker to only bind the shader once, rather than 100 times per frame (or actually, 200 bind calls because you set it to NULL after each use).

I'm not against these kinds of optimizations per se, but I still think that the best batching/caching strategy can only be conceived by the user. It is not the point of SFML to take bad code and make good performance out of it. Taking care of application specific optimizations should be left fully to the user. Building in more and more complex caching just so that the user doesn't have to give any thought to what they are doing isn't going to make the situation better.

What about what I am doing strikes you as being bad code?  If this appears to be a problem I can circumvent in my own code, I'd be happy to do it.  If you have suggestions, I'm all ears.  Again, the simple problem is that I reuse the same shader on lots of draw calls.   I cannot batch everything up into a single large VertexArray because I have to deal with sorting of different drawables which may have different textures.  I use texture atlases, but I can't fit everything I draw into one giant texture.

If your suggestion is to write my own opengl, I guess that's a possibility.  But I'm still not entirely convinced that this optimization is some kind of weird edge case unique to my code.  But rather it would be a useful optimization for SFML as a whole. 

This is one of the reasons SFML is not and will never be a complete game engine. It provides just enough to get people started, but the real meat should still be within their own code. Things like this are so application specific and even dependant on specific circumstances in the application that building them into places as general as sf::RenderTarget just makes something that should have been simple to start with overly complicated. These optimizations always come at a cost, and that cost will always be higher than the gains for the people who actually do optimize in their own code, and the last thing we want to do is punish them for giving more effort than others at making their application run faster.

I understand your point in theory.  But in practice, this appears to be something which would be completely invisible to the user.  No API change.  Everything under the hood.  Except faster.

Perhaps we have a different idea of what SFML is.  I view it as something that can fully support the low-level rendering needs of a complex 2D game, without requiring significant changes to the graphics module.  So far, that has worked out quite well - SFML has been great!  Nobody is saying SFML is meant to be a game engine.  We're talking rendering performance.  But your feedback seems to imply that it is more meant to be base tutorial code, or something similar, where serious users are required to modify the source to get fast performance?  That's not a loaded question, genuinely asking.

The actual reading out of the OpenGL extension variable only happens once...

Yeah, sorry.  I get that.  What I said about checking Shader::isAvailable was misleading.  it's the mutex lock that's the perf problem.  And that does get called potentially hundreds of times per frame.  I guess I can just nuke that in my local copy since I am not multi-threading.  I just wanted you guys to be aware of the perf issue on that, too.

Thanks again for your time.

(edited a couple times for clarity)

6
Graphics / Re: SFML graphics perf analysis
« on: February 20, 2017, 09:34:16 pm »
If you loaded up the CPU side of the driver with commands, switching away from a "full" context will always cause a flush to the GPU, meaning that you are forcing the driver to finally do some of the work it had been piling up for a while.

Gotcha. 
Fully understood. 

These lines take up over 20% of the CPU work done by RenderTarget::Draw:
   applyShader(states.shader)
   applyShader(NULL);
This is mostly due to really horrible CPU cache usage when trying to be smart about caching GL states. Having to hop around memory a lot isn't a fun thing to do.

I'm not sure I understand you here. 

I tried hacking in a fairly simple fix for these unnecessary calls to GLEXT_glUseProgramObject.
Here's the general idea:

void Shader::bind(const Shader* shader)
{
    static const sf::Shader* pLastUsedShader = nullptr;
    bool bNewShader = false;
    if (pLastUsedShader != shader)
    {
       bNewShader = true;
       pLastUsedShader = shader;
    }

    // Only call GLEXT_glUseProgramObject if we're actually changing shaders.
    // If we're using the same shader, that would be a wasteful perf drain.
    if (bNewShader)
    {
       if (shader && shader->m_shaderProgram)
       {
          // Enable the program
          glCheck(GLEXT_glUseProgramObject(castToGlHandle(shader->m_shaderProgram)));
       }
       else
       {
          // Bind no shader
          glCheck(GLEXT_glUseProgramObject(0));
       }
    }

    if (shader && shader->m_shaderProgram)
    {
       // Bind the textures
       shader->bindTextures();

       // Bind the current texture
       if (shader->m_currentTexture != -1)
          glCheck(GLEXT_glUniform1i(shader->m_currentTexture, 0));
    }
}
 

... although some other minor changes were also needed.  You need to call sf::Shader::bind(NULL) whenever you activate a new RenderTarget.  And in RenderTarget::Draw, you call applyShader(states.shader) even if it is NULL, to make sure to remove any previously set shader.

Is there anything particularly wrong with this approach?  It seems to work fine in my game.


The expensive aspects of these applyShader calls are because of:
1.  Shader::isAvailable is called every time, which takes a mutex lock.  This seems very wasteful for each draw call.
Trust me... if you think this is bad, you don't want to know what it looks like inside the driver itself.

Sure.  But if it's an unnecessary drain on CPU perf, why do it?  I mean, shouldn't we only have to check if shaders are supported once?  When the program starts?  And not every draw call?

7
Graphics / SFML graphics perf analysis
« on: February 20, 2017, 04:29:16 pm »
Hello SFML people,

I was doing some CPU perf testing on my game.  As expected, graphics-related stuff takes up quite a bit of the overall CPU usage.  But I did find some interesting hot spots in SFML I wanted to discuss.

Some upfront info:

1.  I am using SFML 2.3 on a new windows 10 laptop, NVIDIA card.

2.  My game is fairly graphically intense, from a usual SFML standpoint.  For example, I use a lot of shaders, I use several render textures which are updated per-frame, and I draw a lot of stuff (using VertexArrays where possible)

So,
sf::RenderTarget::draw(const Vertex* vertices, ...)
is a hotspot, as you might expect.  But what I didn't expect was the following (these are all lines of code from this function):

This line takes up about 20% of the CPU work done by RenderTarget::Draw:
    if (activate(true))
... which is because of a call to WglContext::makeCurrent()
Is this something which needs to be done every time draw is called?
Perhaps with the most recent context changes to SFML 2.4 this is no longer an issue?
Or perhaps this is a symptom of the fact I update several different RenderTextures each frame?  (I ensure to batch up all the operations on a single RenderTexture before moving on to a different one.)

These lines take up over 20% of the CPU work done by RenderTarget::Draw:
   applyShader(states.shader)
   applyShader(NULL);

The expensive aspects of these applyShader calls are because of:
1.  Shader::isAvailable is called every time, which takes a mutex lock.  This seems very wasteful for each draw call.

2.  GLEXT_glUseProgramObject is called first on the shader program, then on NULL for every call.  This is perhaps wasteful for a program which reuses the same shader across many draw calls.  Would it be possible to cache the last used shader, and only call GLEXT_glUseProgramObject if the shader has changed?

This line takes up most of the remaining CPU (~55%), which I would expect:
   glCheck(glDrawArrays(mode, 0, vertexCount));


Thanks for any thoughts you have to share.

8
General discussions / Re: 2.4.2 released!
« on: February 16, 2017, 06:59:02 pm »
Many thanks for the ongoing development work.  Much appreciated!

9
SFML projects / Re: Remnants of Naezith is now on Greenlight!
« on: January 30, 2017, 03:46:32 pm »
Upvoted.
Holy crap, 66 pages of comments on greenlight!  That bodes well.

As other folks mentioned in the reddit thread, definite Super Meatboy vibe going on.  It looks really great, naezith.  Good luck!

10
SFML projects / Re: Last of the Ambaras
« on: January 24, 2017, 12:03:42 pm »
I fact, i'm currently using an altered version of Let There Be Light 2 to have dynamic shadows during nighttime. My plan is to disable this lightning during daytime and draw dropshadows according to the above approach. Those dropshadows may move from left to right, that shouldnt be the problem at all. Dropshadows are not drawn during nighttime.

Heh, that's exactly what I'm doing in my game.  I guess if we both came up with the same idea, we may be on to something.  :)

Quote
It would be better if the shadow would affect the dude walking on it somehow, but not as awkward as in the second pic.

Yep, this is exactly what eXpl0it3r and I were talking about above.  If you come up with a solution to achieve what you have in pic 3, I'd be interested to hear about it.

11
SFML projects / Re: Last of the Ambaras
« on: January 24, 2017, 04:30:35 am »
This works well until a shadow hits another object, then things will "visually" break.

True.  But whenever you're trying to create shadows (a 3D phenomenon) in a 2D game using sprites, there's going to be some things you can't get perfect.  You're basically faking it, with insufficient data to actually calculate the proper shadows, as you would have in a 3D environment with 3D models.



12
SFML projects / Re: Last of the Ambaras
« on: January 24, 2017, 04:19:41 am »
Did anyone implement a shadow system like this in the past and can share some experiences? How did it work? Color the sprite down to black, make it transparent, rotate it a bit and draw it behind its object? Or would you actually handpaint the shadows a load them in as a predefined resource? I would really like to hear some ideas. (Nice visuals > efficiency at the moment)

A lot depends on whether you need dynamic lighting that your shadows must respond to.  Or if you want a day-night cycle.

If these things aren't important, I would definitely just go with hand-painting the shadow.  It's way less complex to code, and you can get your shadows to look perfect by drawing them exactly how you want.  It will almost always look better.

If you do want a day-night cycle, and your shadows need to change position, then you've pretty much gotta go with a progammatic solution.  Drawing a black/transparent version of the sprite for the shadow works pretty good.  You can stretch the sprite too, depending on the time of day, and height of the sun.


13
Feature requests / Re: File system
« on: January 22, 2017, 03:48:39 pm »
I'm with you FRex that games most often should just use one writable directory outside of the install directory.  But the install directory is very often non-writable.  And depending on how you distribute your game (e.g. most major digital distributors), you don't have control of where the install directory is.  So you do need to query the OS on an appropriate writeable directory.  If PHYSFS handles this, then great! 

Sure, with a zip file installation, anything goes.  But that isn't appropriate for any commercial games or applications these days.  Again, especially if you're selling it through a digital distributor like Steam.

Steam also has games save into their own directory somewhere in SteamLibrary/steamapps/common or so. Many installed games do it too.

I think you may be mistaken about this.  Steam, on Windows, by default, installs its games inside the Program Files (x86) directory.  Which is non-writeable.  Any game which tried to save files here would fail.  I think Steam on linux has a similar setup, but I can't remember for sure.

Most of my steam games seem to write their writeable game files inside of the Documents directory or AppData directory.

14
SFML projects / Re: Zeran's Folly
« on: January 21, 2017, 05:43:50 am »
Upvoted.  Good stuff.

15
Feature requests / Re: File system
« on: January 21, 2017, 05:27:36 am »
I'd say that a normal filesystem API is not a good fit for a game since in vast majority of games you don't go beyond own folders, care about rest of the OS, etc.

Almost all games need to read and write save files, configuration/setting files (e.g. user-set graphics options or keyboard mappings), often write logs, often write screenshots, etc.  And these need to go in the appropriate places (outside of the game's own folders) for a bunch of reasons, most notably because game files are often installed into read-only directories.


Pages: [1] 2 3 ... 11
anything