[Contributing] Decals

Any community contributions to libgdx go here! Some may get included in the core API when permission is granted.

Re: [Contributing] Decals

Postby syl » Sun Feb 27, 2011 5:39 pm

yaeh, i will look into this thread :D

besides that, could someone explains the results i'm having ?
also, not that i want to hijack this thread, but it would be clean to get a performance paper in the faqs !
syl
 
Posts: 212
Joined: Mon Nov 01, 2010 10:25 pm
Location: Bordeaux, France

Re: [Contributing] Decals

Postby mzechner » Sun Feb 27, 2011 7:36 pm

what would a "performance paper" consist off?
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: [Contributing] Decals

Postby syl » Sun Feb 27, 2011 7:50 pm

good practices to not blow down performance : * pre- load textures * other points i'm sure
syl
 
Posts: 212
Joined: Mon Nov 01, 2010 10:25 pm
Location: Bordeaux, France

Re: [Contributing] Decals

Postby mzechner » Sun Feb 27, 2011 7:54 pm

Vevusio wrote:
* - setting the depth sort and culling strategy must be accompanied by a flush. Otherwise decals not yet flushed before setting the sort/cull will be rendered with the wrong settings.

i don't really want to do that, i' like to keep the "add stuff, render stuff" principle if somebody wants to use different strategies within one frame i think it is cleaner if they do it like this
Code: Select all
render() {
    renderWorld();
    renderHUD();
}
renderWorld() {
    ActiveCamera.instance().set(this.worldCam).apply(gl);
    DecalBatch.instance().setCullStrategy(firstSphereThenPerPointCulling);
    addWorldObjects();
    DecalBatch.instance().flush();
}
renderHud() {
    ActiveCamera.instance().set(this.screenCam).apply(gl);
    DecalBatch.instance().setCullStrategy(null);
    addHUDObjects();
    DecalBatch.instance().flush();
}

ultimately it has the same effect but the interface is cleaner


I see where you are coming from and i agree. However, what i was refering to is that the setCullStrategy doesn't work as expected. You set a cull strategy and draw a decal (no flush yet), then you set a new cull strategy and draw another decal. Then you flush. The expectation would be that the first decal would be rendered with the first cull strategy and the second decal would be rendered with the second cull strategy. You send both decals in the last flush, but use strategy 2 for the first decal as well. That is wrong. Thus the setCullStrategy should call flush() internally so that anything that is still not flushed and uses the old cull strategy is actually rendered with the strategy.

Vevusio wrote:alright, i don't know how deferred rendering does all the lighting stuff but its obvious that there is no way to make everyone happy with the fixed state changing
i will add another strategy which hooks in before/after rendering opaque/transparent stuff, and implement different versions so there is no problem between different versions, people who want to use something like deferred rendering will just implement their own


It's not about deferred shading. It's about the fact that fetching the states with glGetInteger won't work on Android devices which only support OpenGL ES 1.0 (And there are a lot of those out there). I don't see the need for internal state managment actually. Just remove it and everything is fine. Assume a clean state when flush() is called, as we do in SpriteBatch (and any other library like SFML etc. expects it to be as well).

Vevusio wrote:about the alpha testing, yes - "invisible" pixels don't get written to the z buffer, i don't quite understand why that would disable early z testing? if the pixel "isn't there" it has no business of being in the z buffer in the first place, and if it was, it would be tested against other pixels, which if they don't pass the z test (because of that invis pixel) would not be rendered even though they should (because they are actually visible, instead they are covered by the z-buffer-blocking-fully-transparent-pixel)
but yes, i will merge the transparent/translucent maps together


Most GPUs disable early-z even on the desktop (ATI) if you enable blending and alpha testing. The reason is that the z-write has to be post poned until after the alpha value of the pixel has been determined in the fragment shader (be it fixed function or programmable pipeline). Only after the fragment stage can the CPU decide whether the pixel should be written to the z-buffer or not as it is dependent on the pixel's alpha value (together with the alpha-test threshold). It's sad that GPUs behave like this but it's a reality.

Also, in OpenGL ES 2.0 you'd have to implement alpha testing in the shader yourself via discards. That's bad on mobile GPUs as well. See the Power VR best practices guide, section 1.2, and especially section 2.9. That effect can be easily observed on SGX based hardware as well (the doc is on the mbx, there's a similar doc stating the same for the sgx platform). Adrenos are even worse in that regard.

So to summarize:

  • remove any state managment and instead except a clear state passed to the decal batch by the caller. your state queries are not supported on OpenGL ES 1.0 platforms (which there are a lot out there...)
  • remove alpha testing. while it is technically correct to do it, it has quite some impact on performance when enabled. Maybe make it a flag?
  • Also, alpha testing is not supported in OpenGL ES 2.0, another reason to ditch alpha testing (or at least make it an optional operation

Great work really. Let me know what you think about the license thing i posted earlier. Without your premission we can't include it in libgdx.
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: [Contributing] Decals

Postby Vevusio » Sun Feb 27, 2011 9:22 pm

first - yes i hereby formally agree for you to use and modify this code and run it under the apache 2 license

that being out of the way, now i get what you mean by early z testing, i'm working it out atm, got a nice idea

not gonna do internal flushing on setXStrategy though :)
i understand how some people might expect that the setXXX method affects the next decal which is added, instead of being linked to the flushing, so i will clarify that in the javadoc, but i really want to avoid magic, because this leads to side effects like an unassuming user doing this:
Code: Select all
render() {
    int i, j;
    i = j = 0;
    for(... i++,j++) {
        batch.setStrategy(a);
        batch.addDecal(decals[i]);
        batch.setStrategy(b);
        batch.addDecal(decals[j]);
    }
    batch.flush();
}

and no more batching, just like the setBlending (or even interleaved sprites with different textures) in the SpriteBatch ruin it

i guess half of the users will assume "set affects next flush" and the other half "set affects next add" but none of them will assume "set forces a flush and can ruin performance"
so --> one solution still would have the same effect as the flush-on-set, and that would be to include the current cull strategy in the material

however while colorfully adding sprites is something that can be expected, i don't think switching strategies is

**edit, i'm killing those strategies anyway so.. ye
Vevusio
 
Posts: 13
Joined: Tue Feb 15, 2011 2:12 am

Re: [Contributing] Decals

Postby mzechner » Sun Feb 27, 2011 9:42 pm

I agree to your point completely. I also dislike those sideeffects in SpriteBatch to some extend. Looks like we'll have to consolidate DecalBatch and SpriteBatch once we include DecalBatch. I want them both to work as similar as possible.

Great stuff, keep it up.
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: [Contributing] Decals

Postby Vevusio » Mon Feb 28, 2011 5:44 pm

ok im done

the cull/sort strategies as well as the state management is now gone, the batch class is now a pure batch and render dummy
i added a GroupStrategy which
* the batch delegates the decision which group to put the decal into, to the strategy (previously groups were transparent, translucent, opaque)
* a group is identified by an int
* before rendering anything the batch invokes beforeGroups
* before rendering a group the batch invokes beforeGroup(groupmembers)
* after a group and after all groups analog methods afterGroup and afterGroups are called
* groups are rendered based on their int value, groups with a small value come first

the basic idea is ie. has 2 cameras (or sets of matrices w/e) one for the world, which scrolls around, and one for the HUD which stays fixed
he assigns his opaque world decals fall into group 1, the transparent ones into group 0, the hud into group 2

when the rendering starts the numbers keep rolling in 0,1,2 on 0 he applies the his world camera, on 1 he enables blending, on 2 he applies the hud camera
he can perform view checks on 0 and 1, sort on 1 etc.

this way all the state management, fixed function vs. shaders, billboarding, etc. can be tweaked as needed
for the purpose of identifying decals i added an int into the decal class which does nothing on it's own but can be interpreted when picking a group in the groupstrategy

i implemented 2 really simple strategies that use the fixed function pipeline and provide the functionality the old decal batch had

the batch is no longer a singleton, i figured if people want a singleton they can always simply make a singleton wrapper, call it "dbs" or smth which makes it even quicker to access
i also added a vec2 (null by default) which is public and can be set to affect the pivot point for transformations so when a decal is 100x100 and the offset is set to -50,-50 rotation along the z axis will make it rotate around it's left bot corner instead of the middle, scaling will make it grow from its left lower corner etc.

i did some "benchmarking" again
Code: Select all
   Blending completely disabled:
    @40fps  |  Device
   --------------------
   Sprites# |  ~830
   Decals#  |  ~800 (DefaultGroupStrategy)
   
   Half of the decals use blending:
   @40fps  |  Device
   --------------------
   Sprites# |  ~170
   Decals#  |  ~690 (DefaultGroupStrategy)
   Decals#  |  ~640 (SimpleOrthoGroupStrategy)


for the blending-benchmark i made 2 groups, the first containing all the opaque sprites, the second all the transparent ones
it's begin() renderfirstgroup() enableblending() rendersecondgroup() disableblending() end(), so unless i really screwed up somewhere and just don't see it (which may very well be) i have no idea why spritebatch has this huge performance drop there

i think i've done everything i wanted to, so from here on out i'm handing this over to you for integration (though somewhere along the way i'll probably make an AnimatedDecal)
Attachments
decals_v2.zip
contains the updated files including the benchmarking stuff
(143.33 KiB) Downloaded 569 times
Vevusio
 
Posts: 13
Joined: Tue Feb 15, 2011 2:12 am

Re: [Contributing] Decals

Postby mzechner » Mon Feb 28, 2011 6:48 pm

Great, i'm a little flooded with work for the rest of the week. I'll integrate it asap. Thanks a bunch!

@SpriteBatch performance: z-buffer.
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: [Contributing] Decals

Postby Vevusio » Tue Mar 01, 2011 12:19 am

just noticed i forgot the copy constructor

Code: Select all
   /**
    * Copy constructor
    * @param decal Decal to copy
    */
   public Decal(Decal decal) {
      value = decal.value;
      System.arraycopy(decal.vertices, 0, vertices, 0, SIZE);
      position.set(decal.position);
      rotation.set(decal.rotation);
      scale.set(decal.scale);
      if(decal.transformationOffset != null) {
         transformationOffset = new Vector2(decal.transformationOffset);
      }
      dimensions.set(decal.dimensions);
      material.textureRegion = decal.material.textureRegion;
      material.srcBlendFactor = decal.material.srcBlendFactor;
      material.dstBlendFactor = decal.material.dstBlendFactor;
      updated = decal.updated;
   }

+ there is also a todo tag at the bottom of the decal class which makes no sense at this point
Vevusio
 
Posts: 13
Joined: Tue Feb 15, 2011 2:12 am

Previous

Return to Libgdx Contributions

Who is online

Users browsing this forum: No registered users and 1 guest