54 |
54 |
|
55 |
55 |
// Global buffers used for postprocessing
|
56 |
56 |
private final static DistortedFramebuffer[] mBuffer= new DistortedFramebuffer[EffectQuality.LENGTH];
|
|
57 |
private final boolean[] mBufferInitialized;
|
57 |
58 |
|
58 |
59 |
float mDistance, mNear, mMipmap;
|
59 |
60 |
float[] mProjectionMatrix;
|
... | ... | |
105 |
106 |
// round of create(), but before we start rendering.
|
106 |
107 |
// Create an empty FBO and Time here so that setAsOutput() is always safe to call.
|
107 |
108 |
|
|
109 |
mBufferInitialized = new boolean[EffectQuality.LENGTH];
|
|
110 |
|
108 |
111 |
allocateStuffDependantOnNumFBOS();
|
109 |
112 |
createProjection();
|
110 |
113 |
}
|
... | ... | |
218 |
221 |
}
|
219 |
222 |
}
|
220 |
223 |
|
221 |
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
222 |
|
// The postprocessing buffers mBuffer[] are generally speaking too large (there's just one static
|
223 |
|
// set of them) so before we use them for output, we need to adjust the Viewport as if they were
|
224 |
|
// smaller. That takes care of outputting pixels to them. When we use them as input, we have to
|
225 |
|
// adjust the texture coords - see the get{Width|Height}Correction functions.
|
226 |
|
//
|
227 |
|
// Also, adjust the Buffers so their Projection is the same like the surface we are supposed to be
|
228 |
|
// rendering to.
|
229 |
|
|
230 |
|
private static void clonePostprocessingViewportAndProjection(InternalOutputSurface surface, InternalOutputSurface from)
|
231 |
|
{
|
232 |
|
if( surface.mWidth != from.mWidth || surface.mHeight != from.mHeight ||
|
233 |
|
surface.mFOV != from.mFOV || surface.mNear != from.mNear )
|
234 |
|
{
|
235 |
|
surface.mWidth = (int)(from.mWidth *surface.mMipmap);
|
236 |
|
surface.mHeight = (int)(from.mHeight*surface.mMipmap);
|
237 |
|
surface.mFOV = from.mFOV;
|
238 |
|
surface.mNear = from.mNear; // Near plane is independent of the mipmap level
|
239 |
|
|
240 |
|
surface.createProjection();
|
241 |
|
|
242 |
|
int maxw = Math.max(surface.mWidth , surface.mRealWidth );
|
243 |
|
int maxh = Math.max(surface.mHeight, surface.mRealHeight);
|
244 |
|
|
245 |
|
if (maxw > surface.mRealWidth || maxh > surface.mRealHeight)
|
246 |
|
{
|
247 |
|
surface.mRealWidth = maxw;
|
248 |
|
surface.mRealHeight = maxh;
|
249 |
|
|
250 |
|
surface.recreate();
|
251 |
|
surface.create();
|
252 |
|
}
|
253 |
|
}
|
254 |
|
}
|
255 |
|
|
256 |
224 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
257 |
225 |
|
258 |
226 |
private int blitWithDepth(long currTime, InternalOutputSurface buffer, int fbo)
|
... | ... | |
373 |
341 |
mCurrFBO = fbo;
|
374 |
342 |
}
|
375 |
343 |
|
|
344 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
345 |
// Render all children from the current bucket to the buffer, apply the postprocessing once to the
|
|
346 |
// whole buffer (queue.postprocess) and merge it to 'this' (oitBuild or blitWithDepth depending on
|
|
347 |
// the type of rendering)
|
|
348 |
|
|
349 |
private int accumulateAndBlit(EffectQueuePostprocess queue, InternalChildrenList children, DistortedFramebuffer buffer,
|
|
350 |
int begIndex, int endIndex, boolean isFinal, long time, int fbo, boolean oit )
|
|
351 |
{
|
|
352 |
int numRenders = 0;
|
|
353 |
|
|
354 |
for(int j=begIndex; j<endIndex; j++)
|
|
355 |
{
|
|
356 |
DistortedNode node = children.getChild(j);
|
|
357 |
|
|
358 |
if( node.getSurface().setAsInput() )
|
|
359 |
{
|
|
360 |
buffer.setAsOutput();
|
|
361 |
numRenders += queue.preprocess( buffer, node, buffer.mDistance, buffer.mMipmap, buffer.mProjectionMatrix );
|
|
362 |
}
|
|
363 |
}
|
|
364 |
numRenders += queue.postprocess(buffer);
|
|
365 |
|
|
366 |
if( oit )
|
|
367 |
{
|
|
368 |
numRenders += oitBuild(time, buffer, fbo);
|
|
369 |
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
|
370 |
buffer.clearBuffer(fbo);
|
|
371 |
}
|
|
372 |
else
|
|
373 |
{
|
|
374 |
numRenders += blitWithDepth(time, buffer, fbo);
|
|
375 |
if( !isFinal ) buffer.clearBuffer(fbo);
|
|
376 |
}
|
|
377 |
|
|
378 |
return numRenders;
|
|
379 |
}
|
|
380 |
|
|
381 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
382 |
|
|
383 |
private int renderChildToThisOrToBuffer(DistortedNode child, DistortedFramebuffer buffer, long time, boolean oit, boolean toThis)
|
|
384 |
{
|
|
385 |
int numRenders;
|
|
386 |
|
|
387 |
if( toThis )
|
|
388 |
{
|
|
389 |
setAsOutput(time);
|
|
390 |
|
|
391 |
if( oit )
|
|
392 |
{
|
|
393 |
numRenders = child.drawOIT(time, this);
|
|
394 |
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
|
395 |
}
|
|
396 |
else
|
|
397 |
{
|
|
398 |
numRenders = child.draw(time, this);
|
|
399 |
}
|
|
400 |
}
|
|
401 |
else
|
|
402 |
{
|
|
403 |
buffer.setAsOutput(time);
|
|
404 |
numRenders = child.drawNoBlend(time, buffer);
|
|
405 |
}
|
|
406 |
|
|
407 |
return numRenders;
|
|
408 |
}
|
|
409 |
|
|
410 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
411 |
// The postprocessing buffers mBuffer[] are generally speaking too large (there's just one static
|
|
412 |
// set of them) so before we use them for output, we need to adjust the Viewport as if they were
|
|
413 |
// smaller. That takes care of outputting pixels to them. When we use them as input, we have to
|
|
414 |
// adjust the texture coords - see the get{Width|Height}Correction functions.
|
|
415 |
//
|
|
416 |
// Also, adjust the Buffers so their Projection is the same like the surface we are supposed to be
|
|
417 |
// rendering to.
|
|
418 |
|
|
419 |
private void clonePostprocessingViewportAndProjection(InternalOutputSurface surface, InternalOutputSurface from)
|
|
420 |
{
|
|
421 |
if( surface.mWidth != from.mWidth || surface.mHeight != from.mHeight ||
|
|
422 |
surface.mFOV != from.mFOV || surface.mNear != from.mNear )
|
|
423 |
{
|
|
424 |
surface.mWidth = (int)(from.mWidth *surface.mMipmap);
|
|
425 |
surface.mHeight = (int)(from.mHeight*surface.mMipmap);
|
|
426 |
surface.mFOV = from.mFOV;
|
|
427 |
surface.mNear = from.mNear; // Near plane is independent of the mipmap level
|
|
428 |
|
|
429 |
surface.createProjection();
|
|
430 |
|
|
431 |
int maxw = Math.max(surface.mWidth , surface.mRealWidth );
|
|
432 |
int maxh = Math.max(surface.mHeight, surface.mRealHeight);
|
|
433 |
|
|
434 |
if (maxw > surface.mRealWidth || maxh > surface.mRealHeight)
|
|
435 |
{
|
|
436 |
surface.mRealWidth = maxw;
|
|
437 |
surface.mRealHeight = maxh;
|
|
438 |
|
|
439 |
surface.recreate();
|
|
440 |
surface.create();
|
|
441 |
}
|
|
442 |
}
|
|
443 |
}
|
|
444 |
|
|
445 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
446 |
|
|
447 |
private DistortedFramebuffer initializeBuffer(EffectQueuePostprocess queue, int fbo )
|
|
448 |
{
|
|
449 |
int currQuality = queue.getQuality();
|
|
450 |
if( mBuffer[currQuality]==null ) createPostprocessingBuffers(currQuality, mWidth, mHeight, mNear);
|
|
451 |
mBuffer[currQuality].setCurrFBO(fbo);
|
|
452 |
|
|
453 |
if( !mBufferInitialized[currQuality] )
|
|
454 |
{
|
|
455 |
mBufferInitialized[currQuality] = true;
|
|
456 |
clonePostprocessingViewportAndProjection(mBuffer[currQuality],this);
|
|
457 |
}
|
|
458 |
|
|
459 |
return mBuffer[currQuality];
|
|
460 |
}
|
|
461 |
|
376 |
462 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
377 |
463 |
// Render all children, one by one. If there are no postprocessing effects, just render to THIS.
|
378 |
464 |
// Otherwise, render to a buffer and on each change of Postprocessing Bucket, apply the postprocessing
|
... | ... | |
386 |
472 |
DistortedFramebuffer buffer=null;
|
387 |
473 |
EffectQueuePostprocess lastQueue=null, currQueue;
|
388 |
474 |
long lastBucket=0, currBucket;
|
389 |
|
boolean renderDirectly=false;
|
|
475 |
boolean toThis=false;
|
390 |
476 |
|
391 |
477 |
setCurrFBO(fbo);
|
392 |
478 |
if( numChildren==0 ) setAsOutput(time);
|
393 |
|
|
394 |
|
if( oit && numChildren>0 )
|
395 |
|
{
|
396 |
|
oitClear(this);
|
397 |
|
}
|
|
479 |
if( oit && numChildren>0 ) oitClear(this);
|
|
480 |
for(int i=0; i<EffectQuality.LENGTH; i++) mBufferInitialized[i]=false;
|
398 |
481 |
|
399 |
482 |
for(int i=0; i<numChildren; i++)
|
400 |
483 |
{
|
... | ... | |
402 |
485 |
currQueue = (EffectQueuePostprocess)child.getEffects().getQueues()[3];
|
403 |
486 |
currBucket= currQueue.getID();
|
404 |
487 |
|
405 |
|
if( currBucket==0 )
|
|
488 |
if( currBucket!=0 && lastBucket!=currBucket )
|
406 |
489 |
{
|
407 |
|
setAsOutput(time);
|
408 |
|
|
409 |
|
if( oit )
|
410 |
|
{
|
411 |
|
numRenders += child.drawOIT(time, this);
|
412 |
|
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
413 |
|
}
|
414 |
|
else
|
415 |
|
{
|
416 |
|
numRenders += child.draw(time, this);
|
417 |
|
}
|
|
490 |
buffer = initializeBuffer(currQueue,fbo);
|
|
491 |
if( lastBucket!=0 ) numRenders += accumulateAndBlit(lastQueue,children,buffer,bucketChange,i,false,time,fbo,oit);
|
|
492 |
bucketChange= i;
|
|
493 |
toThis = currQueue.getRenderDirectly();
|
418 |
494 |
}
|
419 |
|
else
|
420 |
|
{
|
421 |
|
int currQuality = currQueue.getQuality();
|
422 |
|
|
423 |
|
if( mBuffer[currQuality]==null ) createPostprocessingBuffers(currQuality, mWidth, mHeight, mNear);
|
424 |
|
mBuffer[currQuality].setCurrFBO(fbo);
|
425 |
|
|
426 |
|
if( lastBucket!=currBucket )
|
427 |
|
{
|
428 |
|
if( lastBucket==0 )
|
429 |
|
{
|
430 |
|
clonePostprocessingViewportAndProjection(mBuffer[currQuality],this);
|
431 |
|
}
|
432 |
|
else
|
433 |
|
{
|
434 |
|
for(int j=bucketChange; j<i; j++)
|
435 |
|
{
|
436 |
|
DistortedNode node = children.getChild(j);
|
437 |
|
|
438 |
|
if( node.getSurface().setAsInput() )
|
439 |
|
{
|
440 |
|
buffer.setAsOutput();
|
441 |
|
numRenders += lastQueue.preprocess( buffer, node, buffer.mDistance, buffer.mMipmap, buffer.mProjectionMatrix );
|
442 |
|
}
|
443 |
|
}
|
444 |
|
numRenders += lastQueue.postprocess(buffer);
|
445 |
|
|
446 |
|
if( oit )
|
447 |
|
{
|
448 |
|
numRenders += oitBuild(time, buffer, fbo);
|
449 |
|
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
450 |
|
}
|
451 |
|
else
|
452 |
|
{
|
453 |
|
numRenders += blitWithDepth(time, buffer, fbo);
|
454 |
|
}
|
455 |
|
buffer.clearBuffer(fbo);
|
456 |
|
}
|
457 |
|
|
458 |
|
buffer= mBuffer[currQuality];
|
459 |
|
bucketChange= i;
|
460 |
|
renderDirectly = currQueue.getRenderDirectly();
|
461 |
|
}
|
462 |
|
|
463 |
|
if( renderDirectly )
|
464 |
|
{
|
465 |
|
setAsOutput(time);
|
466 |
|
|
467 |
|
if( oit )
|
468 |
|
{
|
469 |
|
numRenders += child.drawOIT(time, this);
|
470 |
|
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
471 |
|
}
|
472 |
|
else
|
473 |
|
{
|
474 |
|
numRenders += child.draw(time, this);
|
475 |
|
}
|
476 |
|
}
|
477 |
|
else
|
478 |
|
{
|
479 |
|
buffer.setAsOutput(time);
|
480 |
|
child.drawNoBlend(time, buffer);
|
481 |
|
}
|
482 |
|
|
483 |
|
if( i==numChildren-1 )
|
484 |
|
{
|
485 |
|
for(int j=bucketChange; j<numChildren; j++)
|
486 |
|
{
|
487 |
|
DistortedNode node = children.getChild(j);
|
488 |
|
|
489 |
|
if( node.getSurface().setAsInput() )
|
490 |
|
{
|
491 |
|
buffer.setAsOutput();
|
492 |
|
numRenders += currQueue.preprocess( buffer, node, buffer.mDistance, buffer.mMipmap, buffer.mProjectionMatrix );
|
493 |
|
}
|
494 |
|
}
|
495 |
|
numRenders += currQueue.postprocess(buffer);
|
496 |
|
|
497 |
|
if( oit )
|
498 |
|
{
|
499 |
|
numRenders += oitBuild(time, buffer, fbo);
|
500 |
|
GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT | GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT);
|
501 |
|
buffer.clearBuffer(fbo);
|
502 |
|
}
|
503 |
|
else
|
504 |
|
{
|
505 |
|
numRenders += blitWithDepth(time, buffer,fbo);
|
506 |
|
}
|
507 |
|
}
|
508 |
|
} // end else (postprocessed child)
|
|
495 |
numRenders += renderChildToThisOrToBuffer(child,buffer,time,oit,currBucket==0 || toThis);
|
|
496 |
if( currBucket!=0 && i==numChildren-1 ) numRenders += accumulateAndBlit(currQueue,children,buffer,bucketChange,numChildren,true,time,fbo,oit);
|
509 |
497 |
|
510 |
498 |
lastQueue = currQueue;
|
511 |
499 |
lastBucket= currBucket;
|
512 |
|
} // end main for loop
|
513 |
|
|
514 |
|
if( oit && numChildren>0 )
|
515 |
|
{
|
516 |
|
numRenders += oitRender(time, fbo); // merge the OIT linked list
|
517 |
500 |
}
|
518 |
501 |
|
|
502 |
if( oit && numChildren>0 ) numRenders += oitRender(time, fbo); // merge the OIT linked list
|
|
503 |
|
519 |
504 |
return numRenders;
|
520 |
505 |
}
|
521 |
506 |
|
... | ... | |
979 |
964 |
{
|
980 |
965 |
return mHeight;
|
981 |
966 |
}
|
982 |
|
}
|
|
967 |
}
|
Remove the requirement that not-postprocessed children in the render scene must be in the first bucket.
Seriously simplify renderChildren().