Jump to content

  • Log In with Google      Sign In   
  • Create Account

Erik Rufelt

Member Since 17 Apr 2002
Offline Last Active Today, 05:50 PM

#5265830 Issues With Sprite Batching

Posted by Erik Rufelt on 10 December 2015 - 10:56 PM

It still only sees the last VBO that's been bound.


Either way you always need one VAO per VBO. But if the same VBO is drawn twice with different shaders then it can share the VAO if the shaders are compatible.


(Though technically a VAO can use more than one VBO, if you don't use interleaved vertex attributes and get some of them from a different VBO, but a VAO will always have "attribute 0" from exactly the last glVertexAttribPointer used on index 0 with the VAO active, any new call for an index will overwrite the old setting for that index)

#5265724 Issues With Sprite Batching

Posted by Erik Rufelt on 10 December 2015 - 07:58 AM

Yes, multiple programs with the same VAO must have the same inputs (vertex attributes), and they must have the same (or compatible) indices.

So if one program has "position" bound to attribute index 0 and another has it on attribute index 1, then it will go wrong.


In general I would have one VAO for each combination of (shaderprogram, vertexbuffer, indexbuffer), or you could share between shaders if you know they use the same attributes.

#5265537 Issues With Sprite Batching

Posted by Erik Rufelt on 08 December 2015 - 11:28 PM

The VAO knows the bindings from your glVertexAttribPointer as well as glEnableVertexAttribArray to the vertex-buffer, so you need a different VAO per batch. Only the last batch created will be the "active" VAO state, as it will overwrite the previous batches created (the glVertexAttribPointer for the same vertex-attrib indices for each batch will overwrite those made for the last batch).

The first long answer here seems to give good explanations: https://stackoverflow.com/questions/26552642/when-is-what-bound-to-a-vao

#5264772 FPS frustrations

Posted by Erik Rufelt on 03 December 2015 - 12:48 PM

That may explain a lot of things. Vsync can't really be perfect in windowed mode.. though it depends on your OS and system settings. On Windows 8 and up (I think) they swap the whole desktop I believe.. so your Present actually just copies to another buffer (which is always RGBA Float16 I think, not sure exactly), and then swaps. Also not sure if this is actually true on desktop always or just on the metro stuff.. perhaps someone else here has done more apps targeting Windows beyond 7 and knows for certain?

There are some articles on MSDN about this stuff if you're targeting those systems.. they changed quite a bit. This is the reason (again, I think, or at least probably partly the reason) why you can't shut off the DWM composition on later Windows...


In general.. what happens if you have two Windows that both present their buffers to the screen, can they be VSynced?

The driver may be able to make this happen.. but it's sortof imperfect.. window mode is not really the target for vsync. There's also the whole frame-buffering issue. In fullscreen the driver will buffer up frames and schedule them for swapping when VSync is approaching, which isn't really enabled in windowed by default (you may be able to use some DXGI functions to override it, not sure, and probably also required latest Windows, as it's dependent on the new composition, again sortof guessing :)).. not sure if it's a technical issue in window mode or just that they don't bother, to avoid having to deal with edge cases when there are two apps running DX etc.


To get window mode VSync as good as possible, I've found the best way is to call Flush or Finish or whatever the function is called in your particular API version to make the driver finish everything on the GPU, then after that call Present with VSync or disable VSync and manually wait for it using DXGI or DirectDraw, to present when the last update is finished (VBlank I think it's called, the slight pause between one screen redraw finishes and the next begins).

Then make sure you wait between frames until that vblank is done so you don't present twice on the same vblank which can happen if your app would run at like 1000 FPS if it was allowed to, so combine with some wait or sleep like you have now.

#5264741 FPS frustrations

Posted by Erik Rufelt on 03 December 2015 - 09:42 AM

Are you doing window mode by the way?

If so that sounds like a pretty good solution, but if you do fullscreen you really should try to use vsync.. it will be quite apparent if the game has any camera movement and isn't vsynced.

#5264631 FPS frustrations

Posted by Erik Rufelt on 02 December 2015 - 02:54 PM

I think your problem is almost certainly in DirectX or related, and not in your app.

Go into DirectX Control Panel (64 bit if your app is 64 bit), and then on the Direct3D 9 tab set all debug levels to max, and choose the Debug version. Then build in debug and run with the VS debugger so you get all debug output in the VS output window, and you should get warnings if you have any.

Once there are no warnings, set everything to release and no warnings in the control panel, then build a release version of your app and run that (without any debugger attached, like from Windows).

Also clean and reinstall your graphics drivers (latest non-beta version) and perhaps the DirectX runtime as well.

(If you don't have debug versions in the control panel you need to install the DirectX SDK I think..)


Also, if you have a bunch of debug prints or something disable all of those and all logging in release mode, such things could interfere. Text output in DirectX probably allocates buffers every frame as well so try disabling them as well just to rule it out.

Many Windows functions work differently and may use different memory allocators when run with a debugger from VS.

#5264422 FPS frustrations

Posted by Erik Rufelt on 01 December 2015 - 10:25 AM

Depending on the GC it may just ignore garbage collection until there is enough to collect.. though it does seem quite strange. Is there something in C# to force the GC to run each frame?

I know on iOS Apple has scoped pools for GC, and recommends running each frame with a pool that is cleaned up immediately after, to avoid any buildup that could cause frame-skipping.


In general your problem isn't uncommon.. lots of people complain about this all the time.. and sometimes gamers get it in games on Steam etc (though rarely what you describe here, mostly like 1 frame skip or similar). What OS/hardware are you running, and do you have anything like auto-switching between discrete/integrated GPU?


Do you run in release mode?

Otherwise try that, like build a release package and run it from outside VS. Could be something much simpler like DirectX outputting debug information. (Also make sure to check all DirectX debug information, and turn on the debug mode in the DirectX control panel, and read all the messages in the output in VS when running with the debugger, some unexpected states there could impact performance in strange ways).


And finally make sure you don't somehow leave any DirectX objects to clean up. It may run its own garbage collection that you probably can't see in VS... for example if you update dynamic buffers every frame then depending on exactly how that is done DX may choose to keep allocating new memory every frame instead of reusing, and then sooner or later run out and have to defragment VRAM or similar. (This especially could be different depending on DX running in debug or not).

#5259630 Drawing with GDI works, but I can't do the same thing in GDI+

Posted by Erik Rufelt on 29 October 2015 - 03:14 PM

Note that it does return the DC correctly, it's just not flagged for update at that time.


For example, if you have a large window of say 500 x 500 pixels with an image in it, and you drag another window above its top left corner covering an area of 100x100 pixels, then WM_PAINT will be sent by Windows and BeginPaint will return a DC that will only paint on those 100x100 pixels that were invalidated by the other window.

The reason for this is so that no unnecessary drawing occurs.


If you want to flag a specific area for update and receive a WM_PAINT you can do so with InvalidateRect.


I would guess that the DefSubclassProc handles WM_PAINT and calls Begin/End-Paint and as such validates the update-rect, so that your BeginPaint call returns a DC with an empty update-rect, clipping all your draw-commands.


You can read about this on MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183362%28v=vs.85%29.aspx

#5259590 Drawing with GDI works, but I can't do the same thing in GDI+

Posted by Erik Rufelt on 29 October 2015 - 10:27 AM

Don't call startup and shutdown on GDI+ on every draw.. call startup once when starting up your program and then shutdown once when the program exits.

Also you call EndPaint twice in your code.


Lastly your working examples use GetDC while the GDI+ version uses BeginPaint, perhaps DefSubclassProc already clears the dirty rect so nothing is left to draw (the DC from Begin/End-Paint will mask to only draw to areas where it thinks the window requires an update, and set that area to not requiring updates anymore so the next draw will do nothing).

#5259119 What mobile OS is easier to develop games for?

Posted by Erik Rufelt on 26 October 2015 - 07:25 AM

Definitely iOS (provided you have a reasonably new Mac that you code on).

#5258632 OpenGL, Still relevant?

Posted by Erik Rufelt on 23 October 2015 - 02:46 AM

If you've been doing XNA for 2 years it should be pretty easy to learn OpenGL.

If you want to stay with C# just Google for C# OpenGL, and either way OpenGL is simple so even if you decide against it in the end it will probably be worth it to try it out for a week or two, shouldn't take you many days to get something going.


If you want to get a game finished efficiently on more than one platform then writing your own framework is not the right thing to do, so if you're not in it for the technical parts but want to release finished products go with an engine (but I still recommend spending those couple of weeks on OpenGL, good to know what it's about :)).

#5257862 Skeletal animation is hella slow

Posted by Erik Rufelt on 19 October 2015 - 01:39 AM

Do you do the final recursive step in matrices?

Try doing it in quaternions instead in that case and only do the matrix-calculation at the end when setting the uniform. You could also try sending quaternions to the shader and calculate the matrices there, which may be almost free (or may not). Depends on where the GPU bottle-neck is.

#5256981 Migrated from VC++ 2008 Express to Visual Studio 2015: Now getting linking er...

Posted by Erik Rufelt on 13 October 2015 - 12:26 AM

I guess those are static libraries built with the 2008 version of the standard library or something like that, or possibly that they or your project are linking to the DLL version of the runtime while the other is linking to the static version. Try looking for new versions from their respective websites built for VS2015.

#5256672 !Collision while (.move() float < 1.0f) ?

Posted by Erik Rufelt on 11 October 2015 - 07:30 AM

Inverse law of bugfixing, the harder it is to find the more trivial the bug :)

#5256658 !Collision while (.move() float < 1.0f) ?

Posted by Erik Rufelt on 11 October 2015 - 06:00 AM

right = rect.getPosition().x; + rect.getSize().x;


Semicolon after getPosition().x ? smile.png

(Check your warning-level if you don't get a warning about this from the compiler).