summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAndreyL ProductEngine <alihatskiy@productengine.com>2018-01-24 21:16:27 +0200
committerAndreyL ProductEngine <alihatskiy@productengine.com>2018-01-24 21:16:27 +0200
commitb654513257ea7e5f74d61c9b4586e480838be23c (patch)
tree2d407d184454cf9dda1b1bf99fcfc5740b43290d /indra/newview
parente6f5aa7f61891395eaf0f376dca88c1d1a951d1b (diff)
MAINT-8197 Fix for crash in gpu_benchmark()
including safety checks and some refactoring
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llglsandbox.cpp192
1 files changed, 118 insertions, 74 deletions
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 1b6494195b..63270e13fe 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -881,8 +881,100 @@ void LLViewerObjectList::renderObjectBeacons()
}
+//-----------------------------------------------------------------------------
+// gpu_benchmark() helper classes
+//-----------------------------------------------------------------------------
+
+// This struct is used to ensure that once we call initProfile(), it will
+// definitely be matched by a corresponding call to finishProfile(). It's
+// a struct rather than a class simply because every member is public.
+struct ShaderProfileHelper
+{
+ ShaderProfileHelper()
+ {
+ LLGLSLShader::initProfile();
+ }
+ ~ShaderProfileHelper()
+ {
+ LLGLSLShader::finishProfile(false);
+ }
+};
+
+// This helper class is used to ensure that each generateTextures() call
+// is matched by a corresponding deleteTextures() call. It also handles
+// the bindManual() calls using those textures.
+class TextureHolder
+{
+public:
+ TextureHolder(U32 unit, U32 size) :
+ texUnit(gGL.getTexUnit(unit)),
+ source(size) // preallocate vector
+ {
+ // takes (count, pointer)
+ // &vector[0] gets pointer to contiguous array
+ LLImageGL::generateTextures(source.size(), &source[0]);
+ }
+
+ ~TextureHolder()
+ {
+ // unbind
+ if (texUnit)
+ {
+ texUnit->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ // ensure that we delete these textures regardless of how we exit
+ LLImageGL::deleteTextures(source.size(), &source[0]);
+ }
+
+ bool bind(U32 index)
+ {
+ if (texUnit) // should always be there with dummy (-1), but just in case
+ {
+ return texUnit->bindManual(LLTexUnit::TT_TEXTURE, source[index]);
+ }
+ return false;
+ }
+
+private:
+ // capture which LLTexUnit we're going to use
+ LLTexUnit* texUnit;
+
+ // use std::vector for implicit resource management
+ std::vector<U32> source;
+};
+
+class ShaderBinder
+{
+public:
+ ShaderBinder(LLGLSLShader& shader) :
+ mShader(shader)
+ {
+ mShader.bind();
+ }
+ ~ShaderBinder()
+ {
+ mShader.unbind();
+ }
+
+private:
+ LLGLSLShader& mShader;
+};
+
+
+//-----------------------------------------------------------------------------
+// gpu_benchmark()
+//-----------------------------------------------------------------------------
F32 gpu_benchmark()
{
+#if LL_WINDOWS
+ if (gGLManager.mIsIntel
+ && std::string::npos != LLOSInfo::instance().getOSStringSimple().find("Microsoft Windows 8")) // or 8.1
+ { // don't run benchmark on Windows 8/8.1 based PCs with Intel GPU (MAINT-8197)
+ LL_WARNS() << "Skipping gpu_benchmark() for Intel graphics on Windows 8." << LL_ENDL;
+ return -1.f;
+ }
+#endif
+
if (!gGLManager.mHasShaderObjects || !gGLManager.mHasTimerQuery)
{ // don't bother benchmarking the fixed function
// or venerable drivers which don't support accurate timing anyway
@@ -922,59 +1014,9 @@ F32 gpu_benchmark()
//number of samples to take
const S32 samples = 64;
-
- // This struct is used to ensure that once we call initProfile(), it will
- // definitely be matched by a corresponding call to finishProfile(). It's
- // a struct rather than a class simply because every member is public.
- struct ShaderProfileHelper
- {
- ShaderProfileHelper()
- {
- LLGLSLShader::initProfile();
- }
- ~ShaderProfileHelper()
- {
- LLGLSLShader::finishProfile(false);
- }
- };
+
ShaderProfileHelper initProfile;
-
- // This helper class is used to ensure that each generateTextures() call
- // is matched by a corresponding deleteTextures() call. It also handles
- // the bindManual() calls using those textures.
- class TextureHolder
- {
- public:
- TextureHolder(U32 unit, U32 size):
- texUnit(gGL.getTexUnit(unit)),
- source(size) // preallocate vector
- {
- // takes (count, pointer)
- // &vector[0] gets pointer to contiguous array
- LLImageGL::generateTextures(source.size(), &source[0]);
- }
-
- ~TextureHolder()
- {
- // unbind
- texUnit->unbind(LLTexUnit::TT_TEXTURE);
- // ensure that we delete these textures regardless of how we exit
- LLImageGL::deleteTextures(source.size(), &source[0]);
- }
-
- void bind(U32 index)
- {
- texUnit->bindManual(LLTexUnit::TT_TEXTURE, source[index]);
- }
-
- private:
- // capture which LLTexUnit we're going to use
- LLTexUnit* texUnit;
-
- // use std::vector for implicit resource management
- std::vector<U32> source;
- };
-
+
std::vector<LLRenderTarget> dest(count);
TextureHolder texHolder(0, count);
std::vector<F32> results;
@@ -987,18 +1029,31 @@ F32 gpu_benchmark()
pixels[i] = (U8) ll_rand(255);
}
-
gGL.setColorMask(true, true);
LLGLDepthTest depth(GL_FALSE);
for (U32 i = 0; i < count; ++i)
- { //allocate render targets and textures
- dest[i].allocate(res,res,GL_RGBA,false, false, LLTexUnit::TT_TEXTURE, true);
+ {
+ //allocate render targets and textures
+ if (!dest[i].allocate(res, res, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true))
+ {
+ LL_WARNS() << "Failed to allocate render target." << LL_ENDL;
+ // abandon the benchmark test
+ delete[] pixels;
+ return -1.f;
+ }
dest[i].bindTarget();
dest[i].clear();
dest[i].flush();
- texHolder.bind(i);
+ if (!texHolder.bind(i))
+ {
+ // can use a dummy value mDummyTexUnit = new LLTexUnit(-1);
+ LL_WARNS() << "Failed to bind tex unit." << LL_ENDL;
+ // abandon the benchmark test
+ delete[] pixels;
+ return -1.f;
+ }
LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA, res,res,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
@@ -1006,7 +1061,13 @@ F32 gpu_benchmark()
//make a dummy triangle to draw with
LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STATIC_DRAW_ARB);
- buff->allocateBuffer(3, 0, true);
+
+ if (!buff->allocateBuffer(3, 0, true))
+ {
+ LL_WARNS() << "Failed to allocate buffer during benchmark." << LL_ENDL;
+ // abandon the benchmark test
+ return -1.f;
+ }
LLStrider<LLVector3> v;
LLStrider<LLVector2> tc;
@@ -1029,22 +1090,6 @@ F32 gpu_benchmark()
buff->flush();
// ensure matched pair of bind() and unbind() calls
- class ShaderBinder
- {
- public:
- ShaderBinder(LLGLSLShader& shader):
- mShader(shader)
- {
- mShader.bind();
- }
- ~ShaderBinder()
- {
- mShader.unbind();
- }
-
- private:
- LLGLSLShader& mShader;
- };
ShaderBinder binder(gBenchmarkProgram);
buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
@@ -1103,4 +1148,3 @@ F32 gpu_benchmark()
return gbps;
}
-