diff options
author | Karl Berry <karl@freefriends.org> | 2022-01-08 18:39:01 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2022-01-08 18:39:01 +0000 |
commit | bedc9a5694f7c40a2645919601638d2dbef4145b (patch) | |
tree | 22548fd073b3f2f5a287c2487d69bfc656125ef6 /Build/source/utils/asymptote/glrender.cc | |
parent | c2c4540ab1d27a23c085ce5081f6366cfabb31f6 (diff) |
asy 2.75 sources
git-svn-id: svn://tug.org/texlive/trunk@61532 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/glrender.cc')
-rw-r--r-- | Build/source/utils/asymptote/glrender.cc | 672 |
1 files changed, 542 insertions, 130 deletions
diff --git a/Build/source/utils/asymptote/glrender.cc b/Build/source/utils/asymptote/glrender.cc index 822039d934f..7e7504ef61a 100644 --- a/Build/source/utils/asymptote/glrender.cc +++ b/Build/source/utils/asymptote/glrender.cc @@ -26,6 +26,10 @@ #include "interact.h" #include "fpu.h" +extern uint32_t CLZ(uint32_t a); + +bool GPUindexing; + namespace gl { #ifdef HAVE_PTHREAD pthread_t mainthread; @@ -36,6 +40,7 @@ pthread_t mainthread; #include "tr.h" #ifdef HAVE_LIBGLUT + #ifdef __MSDOS__ #ifndef FGAPI #define FGAPI GLUTAPI @@ -46,15 +51,16 @@ pthread_t mainthread; #endif #define GLUT_BUILDING_LIB -#endif // HAVE_LIBGLUT -#ifdef HAVE_LIBGLUT #ifdef FREEGLUT #include <GL/freeglut_ext.h> #endif -#endif + +#endif // HAVE_LIBGLUT #include "shaders.h" +#include "GLTextures.h" +#include "EXRFiles.h" #ifdef HAVE_LIBOPENIMAGEIO #include <OpenImageIO/imageio.h> @@ -63,26 +69,33 @@ pthread_t mainthread; using settings::locateFile; using utils::seconds; +#endif // HAVE_GL + +#ifdef HAVE_LIBGLM + namespace camp { Billboard BB; GLint pixelShader; GLint materialShader; GLint colorShader; +GLint generalShader; +GLint countShader; GLint transparentShader; +GLint blendShader; +GLint zeroShader; +GLint preSumShader; +GLint partialSumShader; +GLint postSumShader; -vertexBuffer material0Data(GL_POINTS); -vertexBuffer material1Data(GL_LINES); -vertexBuffer materialData; -vertexBuffer colorData; -vertexBuffer transparentData; -vertexBuffer triangleData; +GLuint countBuffer; +GLuint offsetBuffer; +GLuint sumBuffer; +GLuint fragmentBuffer; -const size_t Nbuffer=10000; -const size_t nbuffer=1000; } -#endif /* HAVE_GL */ +#endif #ifdef HAVE_LIBGLM using camp::Material; @@ -92,20 +105,58 @@ using camp::nmaterials; using camp::MaterialMap; namespace camp { -std::vector<Material> material; +bool initSSBO; +GLuint maxFragments; + +vertexBuffer material0Data(GL_POINTS); +vertexBuffer material1Data(GL_LINES); +vertexBuffer materialData; +vertexBuffer colorData; +vertexBuffer transparentData; +vertexBuffer triangleData; + +const size_t Nbuffer=10000; +const size_t nbuffer=1000; + +std::vector<Material> materials; MaterialMap materialMap; size_t materialIndex; size_t Maxmaterials; size_t Nmaterials=1; size_t nmaterials=48; + +void clearCenters() +{ + camp::drawElement::centers.clear(); + camp::drawElement::centermap.clear(); +} + +void clearMaterials() +{ + materials.clear(); + materials.reserve(nmaterials); + materialMap.clear(); + + material0Data.partial=false; + material1Data.partial=false; + materialData.partial=false; + colorData.partial=false; + triangleData.partial=false; + transparentData.partial=false; +} + } extern void exitHandler(int); namespace gl { +GLint processors; +GLint steps; + bool outlinemode=false; +bool ibl=false; bool glthread=false; bool glupdate=false; bool glexit=false; @@ -130,11 +181,13 @@ bool firstFit; bool queueExport=false; bool readyAfterExport=false; bool remesh; +bool copied; int Mode; double Aspect; bool View; +bool ViewExport; int Oldpid; string Prefix; const picture* Picture; @@ -168,7 +221,8 @@ static const double pi=acos(-1.0); static const double degrees=180.0/pi; static const double radians=1.0/degrees; -double *Background; +double Background[4]; + size_t Nlights=1; // Maximum number of lights compiled in shader size_t nlights; // Actual number of lights size_t nlights0; @@ -183,6 +237,8 @@ double lastzoom; GLint lastshader=-1; +bool format3dWait=false; + using glm::dvec3; using glm::dmat3; using glm::mat3; @@ -331,7 +387,8 @@ void home(bool webgl=false) #endif #endif dviewMat=dmat4(1.0); - dView=value_ptr(dviewMat); + if(!camp::countShader) + dView=value_ptr(dviewMat); viewMat=mat4(dviewMat); drotateMat=dmat4(1.0); @@ -363,38 +420,65 @@ int window; using utils::statistics; statistics S; +GLint shaderProg,shaderProgColor; -#ifdef HAVE_LIBOPENIMAGEIO -GLuint envMapBuf; +GLTexture2<float,GL_FLOAT> IBLbrdfTex; +GLTexture2<float,GL_FLOAT> irradiance; +GLTexture3<float,GL_FLOAT> reflTextures; -GLuint initHDR() { - GLuint tex; - glGenTextures(1, &tex); +GLTexture2<float,GL_FLOAT> fromEXR(string const& EXRFile, GLTexturesFmt const& fmt, GLint const& textureNumber) +{ + camp::IEXRFile fil(EXRFile); + return GLTexture2<float,GL_FLOAT> {fil.getData(),fil.size(),textureNumber,fmt}; +} - auto imagein = OIIO::ImageInput::open(locateFile("res/studio006.hdr").c_str()); - OIIO::ImageSpec const& imspec = imagein->spec(); +GLTexture3<float,GL_FLOAT> fromEXR3( + mem::vector<string> const& EXRFiles, GLTexturesFmt const& fmt, GLint const& textureNumber) +{ + // 3d reflectance textures + std::vector<float> data; + size_t count=EXRFiles.size(); + int wi=0, ht=0; - // uses GL_TEXTURE1 for now. - glActiveTexture(GL_TEXTURE1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + for (string const& EXRFile : EXRFiles) + { + camp::IEXRFile fil3(EXRFile); + std::tie(wi,ht)=fil3.size(); + size_t imSize=4*wi*ht; + std::copy(fil3.getData(),fil3.getData()+imSize,std::back_inserter(data)); + } - glBindTexture(GL_TEXTURE_2D, tex); - std::vector<float> pixels(imspec.width*imspec.height*3); - imagein->read_image(pixels.data()); + return GLTexture3<float,GL_FLOAT> {data.data(),std::tuple<int,int,int>(wi,ht,count),textureNumber,fmt}; +} - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imspec.width, imspec.height, 0, - GL_RGB, GL_FLOAT, pixels.data()); +void initIBL() +{ + GLTexturesFmt fmt; + fmt.internalFmt=GL_RGB16F; + string imageDir=locateFile(getSetting<string>("imageDir"))+"/"; + string imagePath=imageDir+getSetting<string>("image")+"/"; + irradiance=fromEXR(imagePath+"diffuse.exr",fmt,1); - glGenerateMipmap(GL_TEXTURE_2D); - imagein->close(); + GLTexturesFmt fmtRefl; + fmtRefl.internalFmt=GL_RG16F; + IBLbrdfTex=fromEXR(imageDir+"refl.exr",fmtRefl,2); - glActiveTexture(GL_TEXTURE0); - return tex; -} + GLTexturesFmt fmt3; + fmt3.internalFmt=GL_RGB16F; + fmt3.wrapS=GL_REPEAT; + fmt3.wrapR=GL_CLAMP_TO_EDGE; + fmt3.wrapT=GL_CLAMP_TO_EDGE; -#endif -GLint shaderProg,shaderProgColor; + mem::vector<string> files; + mem::string prefix=imagePath+"refl"; + for(unsigned int i=0; i <= 10; ++i) { + mem::stringstream mss; + mss << prefix << i << ".exr"; + files.emplace_back(mss.str()); + } + + reflTextures=fromEXR3(files,fmt3,3); +} void *glrenderWrapper(void *a); @@ -426,58 +510,155 @@ void wait(pthread_cond_t& signal, pthread_mutex_t& lock) } #endif +void noShaders() +{ + cerr << "GLSL shaders not found." << endl; + exit(-1); +} + void initShaders() { Nlights=nlights == 0 ? 0 : max(Nlights,nlights); Nmaterials=max(Nmaterials,nmaterials); shaderProg=glCreateProgram(); - string vs=locateFile("shaders/vertex.glsl"); - string fs=locateFile("shaders/fragment.glsl"); - if(vs.empty() || fs.empty()) { - cerr << "GLSL shaders not found." << endl; - exit(-1); - } + string zero=locateFile("shaders/count0.glsl"); + string vertex=locateFile("shaders/vertex.glsl"); + string fragment=locateFile("shaders/fragment.glsl"); + string blend=locateFile("shaders/blend.glsl"); + string screen=locateFile("shaders/screen.glsl"); + string pre=locateFile("shaders/presum.glsl"); + string partial=locateFile("shaders/partialsum.glsl"); + string post=locateFile("shaders/postsum.glsl"); + + if(vertex.empty() || fragment.empty() || blend.empty() || screen.empty() || + zero.empty() || pre.empty() || partial.empty() || post.empty()) + noShaders(); + + std::vector<ShaderfileModePair> shaders(1); std::vector<std::string> shaderParams; -#if HAVE_LIBOPENIMAGEIO - if (getSetting<bool>("envmap")) { - shaderParams.push_back("ENABLE_TEXTURE"); - envMapBuf=initHDR(); + if(ibl) { + shaderParams.push_back("USE_IBL"); + initIBL(); + } + +#ifdef HAVE_SSBO + if(GPUindexing) { + shaders[0]=ShaderfileModePair(pre.c_str(),GL_COMPUTE_SHADER); + GLuint rc=compileAndLinkShader(shaders,shaderParams,true,true); + if(rc == 0) { + GPUindexing=false; // Compute shaders are unavailable. + if(settings::verbose > 2) + cout << "No compute shader support" << endl; + } else { + camp::preSumShader=rc; + + ostringstream s; + s << "PROCESSORS " << processors << "u" << endl; + shaderParams.push_back(s.str().c_str()); + shaders[0]=ShaderfileModePair(partial.c_str(),GL_COMPUTE_SHADER); + camp::partialSumShader=compileAndLinkShader(shaders,shaderParams, + true,true); + shaderParams.pop_back(); + + shaders[0]=ShaderfileModePair(post.c_str(),GL_COMPUTE_SHADER); + camp::postSumShader=compileAndLinkShader(shaders,shaderParams,true,true); + } } #endif + string count=locateFile(GPUindexing ? "shaders/offset.glsl" : + "shaders/count.glsl"); + if(count.empty()) + noShaders(); + + shaders.push_back(ShaderfileModePair()); + + shaders[0]=ShaderfileModePair(vertex.c_str(),GL_VERTEX_SHADER); + +#ifdef HAVE_SSBO + shaders[1]=ShaderfileModePair(count.c_str(),GL_FRAGMENT_SHADER); + camp::countShader=compileAndLinkShader(shaders,shaderParams,true); + if(camp::countShader) + shaderParams.push_back("HAVE_SSBO"); + else +#endif + camp::countShader=0; + + if(!camp::countShader && settings::verbose > 2) + cout << "No SSBO support; order-independent transparency unavailable" + << endl; - std::vector<ShaderfileModePair> shaders; - shaders.push_back(ShaderfileModePair(vs.c_str(),GL_VERTEX_SHADER)); - shaders.push_back(ShaderfileModePair(fs.c_str(),GL_FRAGMENT_SHADER)); + shaders[1]=ShaderfileModePair(fragment.c_str(),GL_FRAGMENT_SHADER); + shaderParams.push_back("MATERIAL"); if(orthographic) shaderParams.push_back("ORTHOGRAPHIC"); + ostringstream lights,materials; + lights << "Nlights " << Nlights << endl; + shaderParams.push_back(lights.str().c_str()); + materials << "Nmaterials " << Nmaterials << endl; + shaderParams.push_back(materials.str().c_str()); + shaderParams.push_back("WIDTH"); - camp::pixelShader=compileAndLinkShader(shaders,Nlights,Nmaterials, - shaderParams); + camp::pixelShader=compileAndLinkShader(shaders,shaderParams); shaderParams.pop_back(); shaderParams.push_back("NORMAL"); - camp::materialShader=compileAndLinkShader(shaders,Nlights,Nmaterials, - shaderParams); + camp::materialShader=compileAndLinkShader(shaders,shaderParams); shaderParams.push_back("COLOR"); - camp::colorShader=compileAndLinkShader(shaders,Nlights,Nmaterials, - shaderParams); + camp::colorShader=compileAndLinkShader(shaders,shaderParams); + + shaderParams.push_back("GENERAL"); + if(Mode == 2) + shaderParams.push_back("WIREFRAME"); + camp::generalShader=compileAndLinkShader(shaders,shaderParams); + shaderParams.push_back("TRANSPARENT"); - camp::transparentShader=compileAndLinkShader(shaders,Nlights,Nmaterials, - shaderParams); + camp::transparentShader=compileAndLinkShader(shaders,shaderParams); + shaderParams.clear(); + if(camp::countShader) { + shaders[0]=ShaderfileModePair(screen.c_str(),GL_VERTEX_SHADER); + + if(GPUindexing) + shaderParams.push_back("GPUINDEXING"); + else { + shaders[1]=ShaderfileModePair(zero.c_str(),GL_FRAGMENT_SHADER); + camp::zeroShader=compileAndLinkShader(shaders,shaderParams); + } + + shaders[1]=ShaderfileModePair(blend.c_str(),GL_FRAGMENT_SHADER); + camp::blendShader=compileAndLinkShader(shaders,shaderParams); + } } void deleteShaders() { + if(camp::countShader) { + glDeleteProgram(camp::blendShader); + if(GPUindexing) { + glDeleteProgram(camp::preSumShader); + glDeleteProgram(camp::partialSumShader); + glDeleteProgram(camp::postSumShader); + } else + glDeleteProgram(camp::zeroShader); + glDeleteProgram(camp::countShader); + } + glDeleteProgram(camp::transparentShader); + glDeleteProgram(camp::generalShader); glDeleteProgram(camp::colorShader); glDeleteProgram(camp::materialShader); glDeleteProgram(camp::pixelShader); } +struct Fragment +{ + glm::vec4 color; + glm::vec4 depth; // Pad depth to a glm::vec4 +}; + void setBuffers() { GLuint vao; @@ -489,6 +670,14 @@ void setBuffers() camp::colorData.Reserve(); camp::triangleData.Reserve(); camp::transparentData.Reserve(); + +#ifdef HAVE_SSBO + glGenBuffers(1, &camp::countBuffer); + glGenBuffers(1, &camp::offsetBuffer); + if(GPUindexing) + glGenBuffers(1, &camp::sumBuffer); + glGenBuffers(1, &camp::fragmentBuffer); +#endif } void drawscene(int Width, int Height) @@ -500,6 +689,9 @@ void drawscene(int Width, int Height) endwait(initSignal,initLock); first=false; } + + if(format3dWait) + wait(initSignal,initLock); #endif if((nlights == 0 && Nlights > 0) || nlights > Nlights || @@ -518,7 +710,7 @@ void drawscene(int Width, int Height) double size2=hypot(Width,Height); if(remesh) - camp::drawElement::center.clear(); + camp::clearCenters(); Picture->render(size2,m,M,perspective,remesh); @@ -526,24 +718,30 @@ void drawscene(int Width, int Height) } // Return x divided by y rounded up to the nearest integer. -int Quotient(int x, int y) +int ceilquotient(int x, int y) { return (x+y-1)/y; } +bool exporting=false; + void Export() { + size_t ndata=3*fullWidth*fullHeight; + if(ndata == 0) return; glReadBuffer(GL_BACK_LEFT); glPixelStorei(GL_PACK_ALIGNMENT,1); glFinish(); + exporting=true; try { - size_t ndata=3*fullWidth*fullHeight; unsigned char *data=new unsigned char[ndata]; if(data) { TRcontext *tr=trNew(); - int width=Quotient(fullWidth,Quotient(fullWidth,min(maxTileWidth,Width))); - int height=Quotient(fullHeight,Quotient(fullHeight, - min(maxTileHeight,Height))); + int width=ceilquotient(fullWidth, + ceilquotient(fullWidth,min(maxTileWidth,Width))); + int height=ceilquotient(fullHeight, + ceilquotient(fullHeight, + min(maxTileHeight,Height))); if(settings::verbose > 1) cout << "Exporting " << Prefix << " as " << fullWidth << "x" << fullHeight << " image" << " using tiles of size " @@ -579,11 +777,11 @@ void Export() transform(0.0,0.0,w,0.0,0.0,h), antialias); pic.append(Image); - pic.shipout(NULL,Prefix,Format,false,View); + pic.shipout(NULL,Prefix,Format,false,ViewExport); delete Image; delete[] data; } - } catch(handled_error) { + } catch(handled_error const&) { } catch(std::bad_alloc&) { outOfMemory(); } @@ -602,6 +800,7 @@ void Export() } #endif #endif + exporting=false; } void nodisplay() @@ -657,23 +856,28 @@ void quit() void mode() { remesh=true; + if(camp::countShader) + camp::initSSBO=true; + ++Mode; + if(Mode > 2) Mode=0; + switch(Mode) { case 0: // regular outlinemode=false; + ibl=getSetting<bool>("ibl"); nlights=nlights0; lastshader=-1; glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); - ++Mode; break; case 1: // outline outlinemode=true; - nlights=0; + ibl=false; + nlights=0; // Force shader recompilation glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); - ++Mode; break; case 2: // wireframe outlinemode=false; - Mode=0; + Nlights=1; // Force shader recompilation break; } #ifdef HAVE_LIBGLUT @@ -709,6 +913,8 @@ void reshape0(int width, int height) setProjection(); glViewport(0,0,Width,Height); + if(camp::countShader) + camp::initSSBO=true; } void windowposition(int& x, int& y, int width=Width, int height=Height) @@ -859,8 +1065,9 @@ void display() if(s > 0.0) { double rate=1.0/s; S.add(rate); - cout << "FPS=" << rate << "\t" << S.mean() << " +/- " << S.stdev() - << endl; + if(framecount % 20 == 0) + cout << "FPS=" << rate << "\t" << S.mean() << " +/- " << S.stdev() + << endl; } } ++framecount; @@ -908,7 +1115,8 @@ void update() dviewMat=translate(translate(dmat4(1.0),dvec3(cx,cy,cz))*drotateMat, dvec3(0,0,-cz)); - dView=value_ptr(dviewMat); + if(!camp::countShader) + dView=value_ptr(dviewMat); viewMat=mat4(dviewMat); setProjection(); @@ -1480,6 +1688,7 @@ void init() int argc=cmd.size(); #ifndef __APPLE__ + glutInitContextVersion(4,0); glutInitContextProfile(GLUT_CORE_PROFILE); #endif @@ -1505,10 +1714,24 @@ void init_osmesa() exit(-1); } - ctx = OSMesaCreateContextExt(OSMESA_RGBA,16,0,0,NULL); + const int attribs[]={ + OSMESA_FORMAT,OSMESA_RGBA, + OSMESA_DEPTH_BITS,16, + OSMESA_STENCIL_BITS,0, + OSMESA_ACCUM_BITS,0, + OSMESA_PROFILE,OSMESA_CORE_PROFILE, + OSMESA_CONTEXT_MAJOR_VERSION,4, + OSMESA_CONTEXT_MINOR_VERSION,3, + 0,0 + }; + + ctx=OSMesaCreateContextAttribs(attribs,NULL); if(!ctx) { - cerr << "OSMesaCreateContext failed." << endl; - exit(-1); + ctx=OSMesaCreateContextExt(OSMESA_RGBA,16,0,0,NULL); + if(!ctx) { + cerr << "OSMesaCreateContextExt failed." << endl; + exit(-1); + } } if(!OSMesaMakeCurrent(ctx,osmesa_buffer,GL_UNSIGNED_BYTE, @@ -1534,6 +1757,12 @@ void init_osmesa() #endif /* HAVE_GL */ +// Return ceil(log2(n)) where n is a 32 bit unsigned integer. +uint32_t ceillog2(uint32_t n) +{ + return 32-CLZ(n-1); +} + // angle=0 means orthographic. void glrender(const string& prefix, const picture *pic, const string& format, double width, double height, double angle, double zoom, @@ -1544,6 +1773,12 @@ void glrender(const string& prefix, const picture *pic, const string& format, { Iconify=getSetting<bool>("iconify"); +#if defined(HAVE_COMPUTE_SHADER) && !defined(HAVE_LIBOSMESA) + GPUindexing=getSetting<bool>("GPUindexing"); +#else + GPUindexing=false; +#endif + if(zoom == 0.0) zoom=1.0; Prefix=prefix; @@ -1561,7 +1796,8 @@ void glrender(const string& prefix, const picture *pic, const string& format, Oldpid=oldpid; Shift=shift/zoom; Margin=margin; - Background=background; + for(size_t i=0; i < 4; ++i) + Background[i]=background[i]; Xmin=m.getx(); Xmax=M.getx(); @@ -1574,7 +1810,6 @@ void glrender(const string& prefix, const picture *pic, const string& format, H=orthographic ? 0.0 : -tan(0.5*Angle)*zmax; ignorezoom=false; - Mode=0; Xfactor=Yfactor=1.0; pair maxtile=getSetting<pair>("maxtile"); @@ -1583,7 +1818,9 @@ void glrender(const string& prefix, const picture *pic, const string& format, if(maxTileWidth <= 0) maxTileWidth=1024; if(maxTileHeight <= 0) maxTileHeight=768; - bool webgl=Format == "html"; + bool v3d=format == "v3d"; + bool webgl=format == "html"; + bool format3d=webgl || v3d; #ifdef HAVE_GL #ifdef HAVE_PTHREAD @@ -1607,7 +1844,7 @@ void glrender(const string& prefix, const picture *pic, const string& format, } #else if(glinitialize) { - if(!webgl) init(); + if(!format3d) init(); Fitscreen=1; } #endif @@ -1619,7 +1856,7 @@ void glrender(const string& prefix, const picture *pic, const string& format, getSetting<bool>("animating")))) { antialias=getSetting<Int>("antialias") > 1; double expand; - if(webgl) + if(format3d) expand=1.0; else { expand=getSetting<double>("render"); @@ -1651,7 +1888,7 @@ void glrender(const string& prefix, const picture *pic, const string& format, fullWidth=(int) ceil(expand*width); fullHeight=(int) ceil(expand*height); - if(webgl) { + if(format3d) { Width=fullWidth; Height=fullHeight; } else { @@ -1664,9 +1901,14 @@ void glrender(const string& prefix, const picture *pic, const string& format, Height=min((int) (ceil(Width/Aspect)),screenHeight); } - home(webgl); + home(format3d); setProjection(); - if(webgl) return; + if(format3d) { + remesh=true; + return; + } + + camp::maxFragments=0; ArcballFactor=1+8.0*hypot(Margin.getx(),Margin.gety())/hypot(Width,Height); @@ -1701,7 +1943,10 @@ void glrender(const string& prefix, const picture *pic, const string& format, #endif #endif - camp::clearMaterialBuffer(); + if(glthread && format3d) + format3dWait=true; + + camp::clearMaterials(); #ifndef HAVE_LIBOSMESA @@ -1786,23 +2031,45 @@ void glrender(const string& prefix, const picture *pic, const string& format, GLint val; glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,&val); + + if(GPUindexing) { + glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS,&processors); + if(processors <= 1) + GPUindexing=false; + else + steps=ceillog2(processors); + } + Maxmaterials=val/sizeof(Material); if(nmaterials > Maxmaterials) nmaterials=Maxmaterials; if(glinitialize) { glinitialize=false; + + char *GLSL_VERSION=(char *) glGetString(GL_SHADING_LANGUAGE_VERSION); + GLSLversion=(int) (100*atof(GLSL_VERSION)+0.5); + + if(GLSLversion < 130) { + cerr << "Unsupported GLSL version: " << GLSL_VERSION << "." << endl; + exit(-1); + } + + if(settings::verbose > 2) + cout << "GLSL version " << GLSL_VERSION << endl; + int result = glewInit(); - if (result != GLEW_OK) { + if(result != GLEW_OK) { cerr << "GLEW initialization error." << endl; exit(-1); } + ibl=getSetting<bool>("ibl"); initShaders(); setBuffers(); } - glClearColor(Background[0],Background[1],Background[2],Background[3]); + glClearColor(background[0],background[1],background[2],background[3]); #ifdef HAVE_LIBGLUT #ifndef HAVE_LIBOSMESA @@ -1818,13 +2085,19 @@ void glrender(const string& prefix, const picture *pic, const string& format, #endif #endif - glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glEnable(GL_TEXTURE_3D); + + if(!camp::countShader) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + } - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + Mode=2; mode(); + ViewExport=View; #ifdef HAVE_LIBOSMESA View=false; #endif @@ -1905,6 +2178,125 @@ void registerBuffer(const std::vector<T>& buffervector, GLuint& bufferIndex, } } +void clearCount() +{ + glUseProgram(zeroShader); + glUniform1ui(glGetUniformLocation(zeroShader,"width"),gl::Width); + gl::lastshader=zeroShader; + fpu_trap(false); // Work around FE_INVALID + glDrawArrays(GL_TRIANGLES, 0, 3); + fpu_trap(settings::trap()); + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); +} + +void refreshBuffers() +{ + GLuint zero=0; + GLuint fragments=0; + GLuint pixels=gl::Width*gl::Height; + + if(initSSBO) { + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::offsetBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER,(1+pixels)*sizeof(GLuint),NULL, + GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,1,camp::offsetBuffer); + glClearBufferData(GL_SHADER_STORAGE_BUFFER,GL_R8UI,GL_RED_INTEGER, + GL_UNSIGNED_BYTE,&zero); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::countBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER,pixels*sizeof(GLuint),NULL, + GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,2,camp::countBuffer); + glClearBufferData(GL_SHADER_STORAGE_BUFFER,GL_R8UI,GL_RED_INTEGER, + GL_UNSIGNED_BYTE,&zero); + + if(GPUindexing) { + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::sumBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER,gl::processors*sizeof(GLuint),NULL, + GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,0,camp::sumBuffer); + } + + initSSBO=false; + } + + if(GPUindexing) { + if(gl::exporting) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,1,camp::offsetBuffer); + glClearBufferData(GL_SHADER_STORAGE_BUFFER,GL_R8UI,GL_RED_INTEGER, + GL_UNSIGNED_BYTE,&zero); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,0,camp::sumBuffer); + } + } + + // Determine the fragment offsets + drawBuffer(material0Data,countShader); // TODO: Account for pixel width + drawBuffer(material1Data,countShader); + drawBuffer(materialData,countShader); + drawBuffer(colorData,countShader,true); + drawBuffer(triangleData,countShader,true); + + glDepthMask(GL_FALSE); // Don't write to depth buffer + glDisable(GL_MULTISAMPLE); + drawBuffer(transparentData,countShader,true); + glEnable(GL_MULTISAMPLE); + glDepthMask(GL_TRUE); // Write to depth buffer + + if(GPUindexing) { // Compute partial sums directly on the GPU + glUseProgram(preSumShader); + glUniform1ui(glGetUniformLocation(preSumShader,"elements"),pixels); + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + glDispatchCompute(gl::processors,1,1); + + glUseProgram(partialSumShader); + glUniform1ui(glGetUniformLocation(partialSumShader,"elements"),pixels); + glUniform1ui(glGetUniformLocation(partialSumShader,"steps"),gl::steps); + + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + glDispatchCompute(1,1,1); + + glUseProgram(postSumShader); + glUniform1ui(glGetUniformLocation(postSumShader,"elements"),pixels); + + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER,0,sizeof(GLuint),&fragments); + } else { // Compute partial sums on the CPU + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::countBuffer); + GLuint *countm1=(GLuint *) (glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_READ_ONLY))-1; + + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::offsetBuffer); + GLuint *offset=(GLuint *) glMapBuffer(GL_SHADER_STORAGE_BUFFER,GL_WRITE_ONLY); + size_t Offset=0; + offset[0]=0; + for(size_t i=1; i < pixels; ++i) + offset[i]=Offset += countm1[i]; + fragments=offset[pixels-1]+countm1[pixels]; + + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::offsetBuffer); + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::countBuffer); + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + + clearCount(); + } + + if(fragments > maxFragments) { + // Initialize the alpha buffer + maxFragments=11*fragments/10; + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::fragmentBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER,maxFragments*sizeof(gl::Fragment), + NULL,GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER,3,camp::fragmentBuffer); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER,camp::sumBuffer); + } + + if(GPUindexing) + glDispatchCompute(gl::processors,1,1); + gl::lastshader=-1; +} + void setUniforms(vertexBuffer& data, GLint shader) { bool normal=shader != pixelShader; @@ -1913,7 +2305,9 @@ void setUniforms(vertexBuffer& data, GLint shader) glUseProgram(shader); gl::lastshader=shader; - glUniform1i(glGetUniformLocation(shader,"nlights"),gl::nlights); + if(camp::countShader) // CHECK + glUniform1ui(glGetUniformLocation(shader,"width"),gl::Width); + glUniform1ui(glGetUniformLocation(shader,"nlights"),gl::nlights); for(size_t i=0; i < gl::nlights; ++i) { triple Lighti=gl::Lights[i]; @@ -1929,21 +2323,17 @@ void setUniforms(vertexBuffer& data, GLint shader) (GLfloat) gl::Diffuse[i4+2]); } -#if HAVE_LIBOPENIMAGEIO - // textures - if (settings::getSetting<bool>("envmap")) { - glActiveTexture(GL_TEXTURE1); - glBindBuffer(GL_TEXTURE_2D, gl::envMapBuf); - glUniform1i(glGetUniformLocation(shader, "environmentMap"), 1); - glActiveTexture(GL_TEXTURE0); + if (settings::getSetting<bool>("ibl")) { + gl::IBLbrdfTex.setUniform(glGetUniformLocation(shader,"reflBRDFSampler")); + gl::irradiance.setUniform(glGetUniformLocation(shader,"diffuseSampler")); + gl::reflTextures.setUniform(glGetUniformLocation(shader,"reflImgSampler")); } -#endif } GLuint binding=0; GLint blockindex=glGetUniformBlockIndex(shader,"MaterialBuffer"); glUniformBlockBinding(shader,blockindex,binding); - bool copy=gl::remesh || data.partial || !data.rendered; + bool copy=(gl::remesh || data.partial || !data.rendered) && !gl::copied; registerBuffer(data.materials,data.materialsBuffer,copy,GL_UNIFORM_BUFFER); glBindBufferBase(GL_UNIFORM_BUFFER,binding,data.materialsBuffer); @@ -1957,19 +2347,18 @@ void setUniforms(vertexBuffer& data, GLint shader) value_ptr(gl::normMat)); } -void drawBuffer(vertexBuffer& data, GLint shader) +void drawBuffer(vertexBuffer& data, GLint shader, bool color) { if(data.indices.empty()) return; bool normal=shader != pixelShader; - bool color=shader == colorShader || shader == transparentShader; const size_t size=sizeof(GLfloat); const size_t intsize=sizeof(GLint); const size_t bytestride=color ? sizeof(VertexData) : (normal ? sizeof(vertexData) : sizeof(vertexData0)); - bool copy=gl::remesh || data.partial || !data.rendered; + bool copy=(gl::remesh || data.partial || !data.rendered) && !gl::copied; if(color) registerBuffer(data.Vertices,data.VerticesBuffer,copy); else if(normal) registerBuffer(data.vertices,data.verticesBuffer,copy); else registerBuffer(data.vertices0,data.vertices0Buffer,copy); @@ -1999,7 +2388,7 @@ void drawBuffer(vertexBuffer& data, GLint shader) glEnableVertexAttribArray(materialAttrib); if(color) { - glVertexAttribPointer(colorAttrib,4,GL_UNSIGNED_BYTE,GL_TRUE,bytestride, + glVertexAttribPointer(colorAttrib,4,GL_FLOAT,GL_FALSE,bytestride, (void *) (6*size+intsize)); glEnableVertexAttribArray(colorAttrib); } @@ -2018,7 +2407,6 @@ void drawBuffer(vertexBuffer& data, GLint shader) glDisableVertexAttribArray(colorAttrib); glBindBuffer(GL_UNIFORM_BUFFER,0); - glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); } @@ -2043,50 +2431,74 @@ void drawMaterial() void drawColor() { - drawBuffer(colorData,colorShader); + drawBuffer(colorData,colorShader,true); colorData.clear(); } void drawTriangle() { - drawBuffer(triangleData,transparentShader); - triangleData.rendered=false; // Force copying of sorted triangles to GPU. + drawBuffer(triangleData,generalShader,true); triangleData.clear(); } -void drawTransparent() +void aBufferTransparency() { - sortTriangles(); - glDepthMask(GL_FALSE); // Enable transparency - drawBuffer(transparentData,transparentShader); - transparentData.rendered=false; // Force copying of sorted triangles to GPU. - glDepthMask(GL_TRUE); // Disable transparency + // Collect transparent fragments + glDepthMask(GL_FALSE); // Disregard depth + drawBuffer(transparentData,transparentShader,true); + glDepthMask(GL_TRUE); // Respect depth + + // Blend transparent fragments + glDisable(GL_DEPTH_TEST); + glUseProgram(blendShader); + glUniform1ui(glGetUniformLocation(blendShader,"width"),gl::Width); + glUniform4f(glGetUniformLocation(blendShader,"background"), + gl::Background[0],gl::Background[1],gl::Background[2], + gl::Background[3]); + gl::lastshader=blendShader; + fpu_trap(false); // Work around FE_INVALID + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + glDrawArrays(GL_TRIANGLES, 0, 3); + fpu_trap(settings::trap()); transparentData.clear(); + glEnable(GL_DEPTH_TEST); +} + +void drawTransparent() +{ + if(camp::countShader) { + glDisable(GL_MULTISAMPLE); + aBufferTransparency(); + glEnable(GL_MULTISAMPLE); + } else { + sortTriangles(); + transparentData.rendered=false; // Force copying of sorted triangles to GPU + glDepthMask(GL_FALSE); // Don't write to depth buffer + drawBuffer(transparentData,transparentShader,true); + glDepthMask(GL_TRUE); // Write to depth buffer + transparentData.clear(); + } } void drawBuffers() { + gl::copied=false; + bool transparent=!transparentData.indices.empty(); + if(camp::countShader) { + if(transparent) { + refreshBuffers(); + gl::copied=true; + } + } + drawMaterial0(); drawMaterial1(); drawMaterial(); drawColor(); drawTriangle(); - drawTransparent(); -} -void clearMaterialBuffer() -{ - material.clear(); - material.reserve(nmaterials); - materialMap.clear(); - materialIndex=0; - - material0Data.partial=false; - material1Data.partial=false; - materialData.partial=false; - colorData.partial=false; - triangleData.partial=false; - transparentData.partial=false; + if(transparent) + drawTransparent(); } void setMaterial(vertexBuffer& data, draw_t *draw) @@ -2102,7 +2514,7 @@ void setMaterial(vertexBuffer& data, draw_t *draw) for(size_t i=size0; i < materialIndex; ++i) data.materialTable[i]=-1; data.materialTable[materialIndex]=data.materials.size(); - data.materials.push_back(material[materialIndex]); + data.materials.push_back(materials[materialIndex]); } materialIndex=data.materialTable[materialIndex]; } |