| 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().