summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/glrender.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-01-08 18:39:01 +0000
committerKarl Berry <karl@freefriends.org>2022-01-08 18:39:01 +0000
commitbedc9a5694f7c40a2645919601638d2dbef4145b (patch)
tree22548fd073b3f2f5a287c2487d69bfc656125ef6 /Build/source/utils/asymptote/glrender.cc
parentc2c4540ab1d27a23c085ce5081f6366cfabb31f6 (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.cc672
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];
}