PDA

View Full Version : NVFence question



Gorg
02-06-2002, 10:07 AM
I have dynamic buffers with VAR, but during the runtime of the application, the buffers may be updated :

1. Never
2. Somethimes
3. Almost every frame

And I cannot predict the usage.

3 and 2 does not seem to pose a problem, but the never does, because the application might actually runs for weeks without being stopped.

So the solution I though of is set a fence after each use of the buffer.

After reading the NVFence spec they say that a fence should be left untested or unfinished for a long period time.(they say 2 billion) Obviously if the buffer never gets changed for weeks, then the fence will never be checked or finished.

Does anybody have a solution? Does the warning still applies with the Geforce3?

mcraighead
02-06-2002, 10:30 AM
Fences are fence _objects_. If you reuse a fence object, then you can no longer query whether the old fence is completed.

I don't think anyone will allocate 2 billion fence objects (if they do, it will certainly fail before then). So the only way for this to happen is to keep reusing some fence objects, but leave others outstanding.

I don't see this as proving to be a realistic problem, although it certainly can happen in bizarre circumstances. You should write your app in order to ensure that this problem can't get hit.

Don't overuse fences. Too many fences in the command stream will hurt your performance.

- Matt

Gorg
02-06-2002, 10:40 AM
I am not sure I fully understand. (this was not clear to me from the spec)?

Here is a quick example of my problem :





public: DynamicBuffer
{
void UpdateBuffer(...)
{
glFinishFenceNV(..) }

void SetFence();

void* GetData()

DynamicBuffer()
{
glGenFences(...);
}
private:
GLint myFence;
};


//.. later in rendering code

glVertexPointer( .... dynObj->GetData());
glDraw

dynBuffer->SetFence()


//later in modification code
If ( bufferNeedModifications )
dynBuffer->Update();



From what I from your answer, this situation will give me problems if my buffer never gets updated?

[This message has been edited by Gorg (edited 02-06-2002).]

[This message has been edited by Gorg (edited 02-06-2002).]

mcraighead
02-06-2002, 10:44 AM
No, a fence object is created by GenFences.

Results of TestFence are unreliable when there have been 2 billion intervening SetFence calls since the original SetFence that you are testing. FinishFence may hang your app if there have been 2 billion intervening SetFences.

- Matt

Gorg
02-06-2002, 10:50 AM
Ok. So as long as the application does not run for months in a row, then it should be ok.

I guess I could add code to FinishFenceNV every few frames, but I would have thought that a fence would simply be some sort of reentrant mutex.

You have one, you lock it, and when the condition is met, it unlocks itself. and that's it, no need to test or Finish if you don't need to.




[This message has been edited by Gorg (edited 02-06-2002).]

mcraighead
02-06-2002, 11:20 AM
Or, if a fence has been outstanding for a long time, you could just know that it's done rather than testing it -- something you should probably do anyhow. (For one, fences complete in order, and you should take advantage of this because it can save you tests/finishes.)

Fences are not anything like mutexes.


If your app uses 20 fences per frame (which would be a fairly high number to use), and you run at 60 fps, your app would run for 19 days before using 2 billion fences.

- Matt

Gorg
02-06-2002, 12:07 PM
I thought the 2 billion sets were per fence.

So how do I solve my problem? The simplest solution would be to not use var for those buffers.

Because if I don't know how often I will write to those buffers, then I will need to set a fence that might never be tested.

Do you have any solutions with VAR.




[This message has been edited by Gorg (edited 02-06-2002).]

mcraighead
02-06-2002, 12:14 PM
No, it's 2 billion SetFence calls across all fence objects.

It sounds like your approach will use too many fences, for one thing. Reuse a small number of fence objects and don't use many SetFence calls per frame. Take advantage of the fact that you _do_ know how your app will behave. For example, for static geometry, never use a fence.

You will need to design an approach that doesn't encounter this problem.

- Matt

Korval
02-06-2002, 02:46 PM
If I understand fences correctly, any time you call glFlush, all of the currently set fences will be finished, since that is part of the rendering pipeline.

I was unaware that if you just reused the same fence with glSetFence that you would evern encounter a problem. Although 2 billion is quite a bit, one may want to have several hundred fences set per frame in order to provide good asynchronous rendering.

mcraighead
02-06-2002, 03:17 PM
No, if you call glFinish, all previous fences can be known to have completed. glFlush does not guarantee that anything has completed.

If you reuse just _one_ fence object, the problem can never happen, because only one fence can be outstanding at any given time. It can happen with two or more.

Also note the comment in the extension that you may get fewer than 2 billion because of our internal use of fences.

- Matt

Gorg
02-06-2002, 04:11 PM
Originally posted by mcraighead:
No, it's 2 billion SetFence calls across all fence objects.

It sounds like your approach will use too many fences, for one thing.



I have already changed that.

[QUOTE]
Reuse a small number of fence objects and don't use many SetFence calls per frame.
[\QUOTE]

I am getting confused again.

Does this mean that if during a frame I call SetFence once for a fence, it is ok to no test it and call SetFence again during the next frame?


[QUOTE]
Take advantage of the fact that you _do_ know how your app will behave. For example, for static geometry, never use a fence.
[\QUOTE]

obviously! my problem is just for those stinking don't know when they will change buffer http://www.opengl.org/discussion_boards/ubb/smile.gif




[This message has been edited by Gorg (edited 02-06-2002).]

jwatte
02-06-2002, 06:21 PM
Yes, it is OK to go ahead and re-use a fence that's set sometime previously. You could actually just use some small number of fences, and loop through them if you wish.

Something like the below might work (modulo arguments missing :-). Note that this is not ideal, because you're setting a large number of fences.

struct vertexarray {
void * data;
GLuint fence;
};

draw_vertexarray( vertexarray * va ) {
draw_however( va->data );
va->fence = get_fence();
glSetFenceNV( va->fence );
}

update_vertexarray( vertexarray * va ) {
glFinishFenceNV( va->fence );
memcpy( va->data, whatever );
}

GLuint gFences[ 8 ];
void init( ) {
glGenFences( gFences, 8 );
}
GLuint get_fence() {
gCtr = (gCtr+1)&7;
return gFences[ ctr ];
}


So what will happen if the fence assigned to some buffer gets re-set by some other buffer? Well, you'll wait until that buffer is finished, too, which is OK because that buffer is guaranteed to be finished after the buffer you're waiting on. You may stall the pipeline if you happen to start waiting on a very recently set fence.

There are a gazillion different ways you can structure this, but which one is the best is very dependent on how you use the buffers, and whether you know beforehand whether this buffer is likely to get re-used or not.

Gorg
02-06-2002, 07:00 PM
Originally posted by jwatte:
Yes, it is OK to go ahead and re-use a fence that's set sometime previously.

Yes I understand that, but from the spec it is written that you should not let a fence untested or unfinished for a long period of time.

Like I said in my problem description, I buffers that do not get updated all the time, and I cannot predict when and how often they will be.

So if I do not update them, I thought there was no need to call FinishFence.

My new question now is :

Is is ok to set a fence only once per frame and not call glFinishFenceNV between the frames?

jwatte
02-06-2002, 08:33 PM
Is is ok to set a fence only once per frame and not call glFinishFenceNV between the frames?


Yes. This is equivalent to re-setting a fence which has been set before. There's nothing special or magical about SwapBuffers (well, at least not in the spec :-)

As setting lots of fences will slow you down, you might want to set a fence for every 10 buffers you draw, and just put a counter in each buffer which frame number and which buffer number you last drew it. Then when time comes to update the buffer, wait on the fence you set at or after that counter value.

cass
02-06-2002, 08:43 PM
Gorg,
I'm not sure this is a real problem in practice, but...

I wouldn't set the fence every frame if you don't intend to call glFinishFenceNV on it. If you're worried about waiting too long, why not set the fence every time

a) the object is updated
or
b) every hour since last updated (even if you're not drawing the corresponding geometry)

Of course you need to finish the fence if you need to reclaim the memory that it consumes.

Cass

cass
02-06-2002, 08:46 PM
Ugh.

That should say, "if you need to reclaim the memory that the corresponding geometry consumes".

Cass

Gorg
02-06-2002, 10:28 PM
OK.From everybodys comments I think I finally understand now what the spec means.

Somebody confirm.

If I set a fence(let's called f1), then set 2 billions other fences, then If I check f1 I will get the issues that Matt said described in an earlier post.

It that is true then I had no problem aside from using too many fences.

knackered
02-07-2002, 05:27 AM
This might not be exactly relevant to this topic, but I need to ask somewhere, and don't fancy the idea of starting a new topic only to be shouted down for some reason.
First question:-
SwapBuffers *must* complete all drawing operations before spewing the final image to the monitor - correct? So why use fences, unless you're modifying the same data multiple times within a single frame?

Anyway, I want to describe my water rendering process, so as to gleen some knowledge from you kind people:-
Initialisation Stage: grab some of the AGP memory I allocated at app initialisation time.
Loop:-
...FinishAllFences
...Update y value of all vertices in my AGP array with a new height value
...Render tiles, using the single AGP vertex array, here is the code:-

for (z=0; z<TILECOUNT; z++)
{
glPushMatrix();

for (x=0; x<TILECOUNT; x++)
{ glDrawElements(GL_TRIANGLE_STRIP, m_uiStripIndexCount[HIRES], GL_UNSIGNED_INT, indexpointer[HIRES]);

glSetFenceNV(fences[fencenum], GL_ALL_COMPLETED_NV);

fencenum++;

glTranslatef(m_fTileSize, 0.0f, 0.0f);
}

glPopMatrix();

glTranslatef(0.0f, 0.0f, m_fTileSize);
}

Now, my question(s) is this:-
I seem to have to set a fence for every tile (I'm using the same vertices & indices for every tile).
If I don't, I get splits appearing between the tiles every-so-often.
I think I know why, but it would be nice to have it confirmed.

Another question about general efficiency.
I update the vertices every frame, before rendering. I am targetting this project at a dual P4 1.8ghz, but for some reason, doing a few simple multiplications on every vertex in a 64x64 grid of floats impacts performance severely - why? How can I make full use of these powerful processors?

jwatte
02-07-2002, 09:33 AM
Cass,

I don't understand how your suggestion would work. If I only set a fence when I'm updating the buffer, how would that protect me from messing with vertex data while it's being used. Consider:

Update Buffer
Time Passes
Render Buffer
Update Buffer

I will have to set a fence AFTER any operation that USES the buffer to be sure that I can safely update the buffer. Thus, it doesn't seem to me that setting a fence after updating it will give me anything. I might as well finish the entire vertex array range before each buffer update in that case.