-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathGpuParrallelReductionApp.cpp
146 lines (122 loc) · 5.3 KB
/
GpuParrallelReductionApp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Query.h"
#include "cinder/CameraUi.h"
#include "cinder/Utilities.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class GpuParrallelReductionApp : public App {
public:
GpuParrallelReductionApp();
void update() override;
void draw() override;
void resize() override;
vec4 findMindMax();
CameraPersp mCamera;
CameraUi mCameraUi;
gl::FboRef mFbo;
double mReductionTime;
double mReadBackTime;
};
GpuParrallelReductionApp::GpuParrallelReductionApp()
{
// create a Camera and a Camera ui
mCamera = CameraPersp( getWindowWidth(), getWindowHeight(), 50.0f, 1.0f, 1000.0f ).calcFraming( Sphere( vec3( 0.0f ), 2.0f ) );
mCameraUi = CameraUi( &mCamera, getWindow(), -1 );
// setup a framebuffer
mFbo = gl::Fbo::create( getWindowWidth(), getWindowHeight() );
}
void GpuParrallelReductionApp::resize()
{
mCamera.setAspectRatio( getWindowAspectRatio() );
mFbo = gl::Fbo::create( getWindowWidth(), getWindowHeight() );
}
void GpuParrallelReductionApp::update()
{
{
gl::ScopedFramebuffer scopedFbo( mFbo );
gl::ScopedViewport scopedViewport( vec2(0), mFbo->getSize() );
gl::ScopedDepth scopedDepth( true );
gl::ScopedBlend scopedBlend( false );
gl::setMatrices( mCamera );
gl::clear( ColorA::gray( 0.0f ) );
gl::drawColorCube( vec3(0), vec3(1) );
gl::drawCube( vec3(0,0,-0.5), vec3(0.1) );
}
}
void GpuParrallelReductionApp::draw()
{
gl::clear( Color( 0, 0, 0 ) );
gl::setMatricesWindow( getWindowSize() );
gl::draw( mFbo->getColorTexture() );
auto max = findMindMax();
gl::drawStringCentered( "Current Max value: " + toString( max ), getWindowCenter() - vec2( 0, 10 ) );
gl::drawStringCentered( "Reduction time " + to_string( mReductionTime ) + " ms", getWindowCenter() + vec2( 0, 12 ) );
gl::drawStringCentered( "Read back time " + to_string( mReadBackTime ) + " ms", getWindowCenter() + vec2( 0, 25 ) );
}
vec4 GpuParrallelReductionApp::findMindMax()
{
// init the programs, fbo and texture used for the parrallel reduction
static gl::FboRef sReductionFbo, sReadFbo;
static gl::Texture2dRef sReductionTexture0;
static gl::GlslProgRef sReductionProg, sCopyProg;
auto startingSize = mFbo->getSize() / 2;
if( !sReductionFbo || sReductionFbo->getSize() != startingSize ) {
sReductionTexture0 = gl::Texture2d::create( startingSize.x, startingSize.y, gl::Texture2d::Format().minFilter( GL_NEAREST_MIPMAP_NEAREST ).magFilter( GL_NEAREST ).mipmap().immutableStorage() );
sReductionFbo = gl::Fbo::create( startingSize.x, startingSize.y, gl::Fbo::Format()
.attachment( GL_COLOR_ATTACHMENT0, sReductionTexture0 )
.disableDepth() );
sReductionProg = gl::GlslProg::create( loadAsset( "minMax.vert" ), loadAsset( "minMax.frag" ) );
}
// start reduction profiling
static auto sTimer0 = gl::QueryTimeSwapped::create();
sTimer0->begin();
// attach the main level of the texture
gl::ScopedFramebuffer scopedFbo( sReductionFbo );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sReductionTexture0->getId(), 0 );
// start by blitting the main fbo into the reduction one
mFbo->blitTo( sReductionFbo, mFbo->getBounds(), sReductionFbo->getBounds(), GL_NEAREST );
// bind the reduction program and texture and disable blending
gl::ScopedMatrices scopedMatrices;
gl::ScopedGlslProg scopedGlsl( sReductionProg );
gl::ScopedBlend scopedBlend( false );
gl::ScopedTextureBind scopedTexBind0( sReductionTexture0, 0 );
sReductionProg->uniform( "uTex0", 0 );
// iterate trough each mipmap level
int numMipMaps = gl::Texture2d::requiredMipLevels( startingSize.x, startingSize.y, 0 );
for( int level = 1; level < numMipMaps; ++level ) {
// attach the current mipmap level to the framebuffer and limit texture sampling to the previous level
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level - 1 );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1 );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sReductionTexture0->getId(), level );
// get the current mipmap size and update uniforms
vec2 size = gl::Texture2d::calcMipLevelSize( level, sReductionFbo->getWidth(), sReductionFbo->getHeight() );
sReductionProg->uniform( "uInvSize", vec2( 1.0f ) / vec2( size ) );
// render a fullscreen quad
gl::ScopedViewport scopedViewport( ivec2( 0 ), size );
gl::setMatricesWindow( size.x, size.y );
gl::drawSolidRect( Rectf( vec2( 0.0f ), vec2( size ) ) );
}
// stop reduction profiling
sTimer0->end();
mReductionTime = sTimer0->getElapsedMilliseconds();
// start readback profiling
static auto sTimer1 = gl::QueryTimeSwapped::create();
sTimer1->begin();
// read back to the cpu and find the max value
vec4 max( 0.0f );
ivec2 readSize = gl::Texture2d::calcMipLevelSize( numMipMaps - 1, startingSize.x, startingSize.y );
Surface8u surface( readSize.x, readSize.y, true );
glGetTexImage( sReductionTexture0->getTarget(), numMipMaps - 1, GL_RGBA, GL_UNSIGNED_BYTE, surface.getData() );
auto it = surface.getIter();
while( it.line() ) { while( it.pixel() ) {
max = glm::max( max, vec4( it.r(), it.g(), it.b(), it.a() ) );
} }
// stop readback profiling
sTimer1->end();
mReadBackTime = sTimer1->getElapsedMilliseconds();
return max;
}
CINDER_APP( GpuParrallelReductionApp, RendererGl )