diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 95d55c835f0..94ff2dd6e64 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -797,9 +797,8 @@ void LLAvatarAppearance::buildCharacter() LLTimer timer; bool status = loadAvatar(); - stop_glerror(); -// gPrintMessagesThisFrame = true; + // gPrintMessagesThisFrame = true; LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL; if (!status) @@ -870,8 +869,6 @@ void LLAvatarAppearance::buildCharacter() mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); mIsBuilt = true; - stop_glerror(); - } bool LLAvatarAppearance::loadAvatar() diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp index f743f7b5171..15995ee62a5 100644 --- a/indra/llappearance/lllocaltextureobject.cpp +++ b/indra/llappearance/lllocaltextureobject.cpp @@ -47,7 +47,6 @@ LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) mDiscard(MAX_DISCARD_LEVEL+1) { mImage = image; - gGL.getTexUnit(0)->bind(mImage); mID = id; } diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index 613c4081571..6999baf83d9 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -195,6 +195,7 @@ LLAudioEngine::LLAudioPlayState LLAudioEngine::isInternetStreamPlaying() // virtual void LLAudioEngine::setInternetStreamGain(F32 vol) { + LL_PROFILE_ZONE_SCOPED; if (mStreamingAudioImpl) mStreamingAudioImpl->setGain(vol); } @@ -211,6 +212,7 @@ std::string LLAudioEngine::getInternetStreamURL() void LLAudioEngine::updateChannels() { + LL_PROFILE_ZONE_SCOPED; S32 i; for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) { @@ -225,6 +227,7 @@ void LLAudioEngine::updateChannels() void LLAudioEngine::idle() { + LL_PROFILE_ZONE_SCOPED; // "Update" all of our audio sources, clean up dead ones. // Primarily does position updating, cleanup of unused audio sources. // Also does regeneration of the current priority of each audio source. @@ -666,6 +669,7 @@ bool LLAudioEngine::isWindEnabled() void LLAudioEngine::setMuted(bool muted) { + LL_PROFILE_ZONE_SCOPED; if (muted != mMuted) { mMuted = muted; @@ -676,6 +680,7 @@ void LLAudioEngine::setMuted(bool muted) void LLAudioEngine::setMasterGain(const F32 gain) { + LL_PROFILE_ZONE_SCOPED; mMasterGain = gain; F32 internal_gain = getMuted() ? 0.f : gain; if (internal_gain != mInternalGain) @@ -859,6 +864,7 @@ void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVe void LLAudioEngine::setDopplerFactor(F32 factor) { + LL_PROFILE_ZONE_SCOPED; if (mListenerp) { mListenerp->setDopplerFactor(factor); @@ -881,6 +887,7 @@ F32 LLAudioEngine::getDopplerFactor() void LLAudioEngine::setRolloffFactor(F32 factor) { + LL_PROFILE_ZONE_SCOPED; if (mListenerp) { mListenerp->setRolloffFactor(factor); diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h index 1d7e4f8220e..e3e1676801d 100644 --- a/indra/llcommon/llsafehandle.h +++ b/indra/llcommon/llsafehandle.h @@ -170,6 +170,7 @@ class LLSafeHandle } } + public: // Define an LLSingleton whose sole purpose is to hold a "null instance" // of the subject Type: the canonical instance to dereference if this // LLSafeHandle actually holds a null pointer. We use LLSingleton @@ -178,11 +179,10 @@ class LLSafeHandle // Of course, as with any LLSingleton, the "null instance" is only // instantiated on demand -- in this case, if you actually try to // dereference an LLSafeHandle containing null. - class NullInstanceHolder: public LLSingleton + class NullInstanceHolder: public LLSimpleton { - LLSINGLETON_EMPTY_CTOR(NullInstanceHolder); - ~NullInstanceHolder() {} public: + ~NullInstanceHolder() {} Type mNullInstance; }; diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index dc9a87eb805..908ca984295 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -214,7 +214,7 @@ void SampleAccumulator::reset(const SampleAccumulator* other) mMin = mLastValue; mMax = mLastValue; mMean = mLastValue; - llassert(!mHasValue || mMean < 0 || mMean >= 0); + //llassert(!mHasValue || mMean < 0 || mMean >= 0); mSumOfSquares = 0; mLastSampleTimeStamp = LLTimer::getTotalSeconds(); mTotalSamplingTime = 0; diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 3b423f783a0..670359a397a 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -34,13 +34,26 @@ class LLMatrix4a { public: - LL_ALIGN_16(LLVector4a mMatrix[4]); + union + { + LLVector4a mMatrix[4]; + LLMatrix4 mMatrix4; + }; LLMatrix4a() { } + ~LLMatrix4a() + { + } + + LLMatrix4a(const LLMatrix4a& rhs) + { + *this = rhs; + } + explicit LLMatrix4a(const LLMatrix4& val) { loadu(val); @@ -51,6 +64,16 @@ class LLMatrix4a loadu(val); } + inline const LLMatrix4a& operator=(const LLMatrix4a& rhs) + { + mMatrix[0] = rhs.mMatrix[0]; + mMatrix[1] = rhs.mMatrix[1]; + mMatrix[2] = rhs.mMatrix[2]; + mMatrix[3] = rhs.mMatrix[3]; + + return *this; + } + static const LLMatrix4a& identity() { static const F32 v[] = diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 00a56edf686..2e2408f43a3 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2320,6 +2320,7 @@ bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size) bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) { { + mVertexBuffer = nullptr; auto face_count = mdl.size(); if (face_count == 0) @@ -2764,9 +2765,103 @@ bool LLVolume::cacheOptimize(bool gen_tangents) return false; } } + return true; } +extern U32 ll_gl_gen_arrays(); + +static bool validate_vertex_buffer(LLVolume* volume) +{ + if (volume->mVertexBuffer.isNull()) + { + // allowed to be null + return true; + } + + U32 num_verts = 0; + U32 num_indices = 0; + for (auto& face: volume->getVolumeFaces()) + { + num_verts += face.mNumVertices; + num_indices += face.mNumIndices; + } + + bool same_verts = num_verts == volume->mVertexBuffer->getNumVerts(); + bool same_indices = num_indices == volume->mVertexBuffer->getNumIndices(); + + return same_verts && same_indices; +} + +void LLVolume::createVertexBuffer() +{ + if (getNumFaces() && (mVertexBuffer.isNull() || !validate_vertex_buffer(this))) + { + LL_PROFILE_ZONE_SCOPED; + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT; + U32 vert_count = 0; + U32 index_count = 0; + for (auto& face : mVolumeFaces) + { + face.mVBGeomOffset = vert_count; + face.mVBIndexOffset = index_count; + + vert_count += face.mNumVertices; + index_count += face.mNumIndices; + + if (face.mWeights) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + } + + bool large_indices = vert_count >= 65536; + + mVertexBuffer = new LLVertexBuffer(mask); + if (large_indices) + { + mVertexBuffer->setIndicesType(GL_UNSIGNED_INT); + } + mVertexBuffer->allocateBuffer(vert_count, index_count); + + mVertexBuffer->bindBuffer(); + + for (auto& face : mVolumeFaces) + { + face.mVertexBuffer = mVertexBuffer; + // ensure tangents have been created + face.createTangents(); + mVertexBuffer->setPositionData(face.mPositions, face.mVBGeomOffset, face.mNumVertices); + mVertexBuffer->setNormalData(face.mNormals, face.mVBGeomOffset, face.mNumVertices); + mVertexBuffer->setTexCoord0Data(face.mTexCoords, face.mVBGeomOffset, face.mNumVertices); + mVertexBuffer->setTangentData(face.mTangents, face.mVBGeomOffset, face.mNumVertices); + if (face.mWeights) + { + mVertexBuffer->setWeight4Data(face.mWeights, face.mVBGeomOffset, face.mNumVertices); + } + + if (face.mVBGeomOffset > 0) + { + static std::vector indices; + indices.resize(0); + for (S32 i = 0; i < face.mNumIndices; ++i) + { + indices.push_back(face.mIndices[i] + face.mVBGeomOffset); + } + mVertexBuffer->setIndexData(&indices[0], face.mVBIndexOffset, face.mNumIndices); + } + else + { + mVertexBuffer->setIndexData(face.mIndices, face.mVBIndexOffset, face.mNumIndices); + } + } + +#if LL_DARWIN + mVertexBuffer->unmapBuffer(); +#endif + } +} S32 LLVolume::getNumFaces() const { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 3496928f7bb..221dfc7fda5 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -59,6 +59,7 @@ class LLVolumeOctree; #include "llfile.h" #include "llalignedarray.h" #include "llrigginginfo.h" +#include "../llrender/llvertexbuffer.h" //============================================================================ @@ -976,6 +977,13 @@ class LLVolumeFace // mWeights.size() should be empty or match mVertices.size() LLVector4a* mWeights; + // vertex buffer that contains this face's geometry (may be null) + LLPointer mVertexBuffer; + // offset into mVertexBuffer where this face's geometry starts + U32 mVBGeomOffset = 0; + // offset into mVertexBuffe where this face's indices start + U32 mVBIndexOffset = 0; + #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS LLVector4a* mJustWeights; U8* mJointIndices; @@ -1102,6 +1110,8 @@ class LLVolume : public LLRefCount // gen_tangents - if true, generate MikkTSpace tangents if needed before optimizing index buffer bool cacheOptimize(bool gen_tangents = false); + void createVertexBuffer(); + private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); @@ -1141,6 +1151,8 @@ class LLVolume : public LLRefCount face_list_t mVolumeFaces; public: + LLPointer mVertexBuffer; + LLVector4a* mHullPoints; U16* mHullIndices; S32 mNumHullPoints; diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index a0ba3ec5051..b36b81e444d 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -437,4 +437,11 @@ inline std::ostream& operator<<(std::ostream& s, const LLVector2& a) return s; } +// For use with boost containers. +inline size_t hash_value(const LLVector2& v) noexcept +{ + return boost::hash_range(v.mV, v.mV + 1); +} + + #endif diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 3763fc67258..95add73e8cc 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -507,4 +507,11 @@ void LLColor3::write(std::vector& v) const } } +inline size_t hash_value(const LLColor3& c) noexcept +{ + size_t hash = 0; + boost::hash_range(hash, (F32*) c.mV, (F32*) c.mV + 2); + return hash; +} + #endif diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index a26db0428b2..a44e428f8e2 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -674,4 +674,11 @@ void LLColor4::write(std::vector& v) const } } +inline size_t hash_value(const LLColor4& c) noexcept +{ + size_t hash = 0; + boost::hash_range(hash, (F32*)c.mV, (F32*)c.mV + 3); + return hash; +} + #endif diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index e1a02064614..2e6b403a0a5 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -495,4 +495,10 @@ inline void LLColor4U::fromRGBA(U32 aVal) mV[3] = aVal & 0xFF; } +// For use with boost containers. +inline size_t hash_value(const LLColor4U& c) noexcept +{ + return (size_t) *((U32*)c.mV); +} + #endif diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 3d8e02cb16f..dbdd1956324 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -73,14 +73,14 @@ target_link_libraries(llprimitive ) #add unit tests -if (LL_TESTS) - INCLUDE(LLAddBuildTest) - SET(llprimitive_TEST_SOURCE_FILES - llmediaentry.cpp - llprimitive.cpp - llgltfmaterial.cpp - ) - - set_property(SOURCE llprimitive.cpp PROPERTY LL_TEST_ADDITIONAL_LIBRARIES llmessage) - LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") -endif (LL_TESTS) +#if (LL_TESTS) +# INCLUDE(LLAddBuildTest) +# SET(llprimitive_TEST_SOURCE_FILES +# llmediaentry.cpp +# llprimitive.cpp +# llgltfmaterial.cpp +# ) +# +# set_property(SOURCE llprimitive.cpp PROPERTY LL_TEST_ADDITIONAL_LIBRARIES llmessage) +# LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") +#endif (LL_TESTS) diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index cc4921416f6..2d7481fc3af 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -79,6 +79,11 @@ LLGLTFMaterial::LLGLTFMaterial() mAlphaMode = ALPHA_MODE_OPAQUE; // This is 0 mOverrideDoubleSided = mOverrideAlphaMode = false; #endif + + llassert(mAlphaMode == 0); + llassert(!mOverrideDoubleSided); + llassert(!mDoubleSided); + llassert(!mOverrideAlphaMode); } void LLGLTFMaterial::TextureTransform::getPacked(Pack& packed) const @@ -101,12 +106,22 @@ void LLGLTFMaterial::TextureTransform::getPackedTight(PackTight& packed) const packed[4] = mOffset.mV[VY]; } +void LLGLTFMaterial::TextureTransform::getPackedUBO(F32* packed) const +{ + packed[0] = mScale.mV[VX]; + packed[1] = mScale.mV[VY]; + packed[2] = mRotation; + packed[3] = mOffset.mV[VX]; + packed[4] = mOffset.mV[VY]; +} + bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const { return mOffset == other.mOffset && mScale == other.mScale && mRotation == other.mRotation; } LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs) + : LLGLTFMaterial() // call default constructor to zero out padding bytes { *this = rhs; } @@ -876,6 +891,52 @@ LLUUID LLGLTFMaterial::getHash() const sizeof(*this) - offset); } +size_t LLGLTFMaterial::calculateBatchHash() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + size_t hash = 0; + char* begin = (char*)&mTextureId; + char* end = (char*)&mDoubleSided+1; + + if (mAlphaMode == ALPHA_MODE_BLEND && mBaseColor.mV[3] == 0.f) + { // fully transparent materials should not be rendered + return 0; + } +#if 1 + // boost::hash_range + hash = boost::hash_range(begin, end - 1); +#elif 0 + // boost::hash_combine + boost::hash_combine(hash, mTextureId); + boost::hash_combine(hash, mTextureTransform); + boost::hash_combine(hash, mBaseColor); + boost::hash_combine(hash, mEmissiveColor); + boost::hash_combine(hash, mMetallicFactor); + boost::hash_combine(hash, mRoughnessFactor); + boost::hash_combine(hash, mAlphaCutoff); + boost::hash_combine(hash, mDoubleSided); +#else + // xxh64 + HBXXH64 hasher; + hasher.update(begin, (U32)((char*)end - (char*)begin)); + hasher.finalize(); + hash = hasher.digest(); +#endif + + return hash; +} + +void LLGLTFMaterial::updateBatchHash() +{ + mBatchHash = calculateBatchHash(); +} + +size_t LLGLTFMaterial::getBatchHash() const +{ + llassert(mBatchHash == calculateBatchHash()); + return mBatchHash; +} + void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id) { mTrackingIdToLocalTexture[tracking_id] = tex_id; @@ -923,3 +984,39 @@ void LLGLTFMaterial::updateTextureTracking() // setTEGLTFMaterialOverride is responsible for tracking // for material overrides editor will set it } + +void LLGLTFMaterial::packOnto(std::vector& data, F32 glow) +{ + size_t idx = data.size(); + data.resize(data.size() + 8); + + F32* ptr = (F32*)&data[idx]; + + F32* base_color = ptr; + F32* normal = base_color + 8; + F32* metallic_roughness = normal + 8; + F32* emissive = metallic_roughness + 8; + + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + { + mTextureTransform[i].getPackedUBO(ptr); + ptr += 8; + } + + base_color[5] = mBaseColor.mV[0]; + base_color[6] = mBaseColor.mV[1]; + base_color[7] = mBaseColor.mV[2]; + + normal[5] = mBaseColor.mV[3]; + normal[6] = mAlphaCutoff; + normal[7] = glow; + + emissive[5] = mEmissiveColor.mV[0]; + emissive[6] = mEmissiveColor.mV[1]; + emissive[7] = mEmissiveColor.mV[2]; + + metallic_roughness[5] = mRoughnessFactor; + metallic_roughness[6] = mMetallicFactor; +} + + diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 10df4c8ee11..fecb5f9dfd3 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -74,6 +74,7 @@ class LLGLTFMaterial : public LLRefCount using PackTight = F32[PACK_TIGHT_SIZE]; void getPacked(Pack& packed) const; void getPackedTight(PackTight& packed) const; + void getPackedUBO(F32* packed) const; bool operator==(const TextureTransform& other) const; bool operator!=(const TextureTransform& other) const { return !(*this == other); } @@ -118,6 +119,17 @@ class LLGLTFMaterial : public LLRefCount // get a UUID based on a hash of this LLGLTFMaterial LLUUID getHash() const; + // calculate the batch hash and return it + // does not update mBatchHash + size_t calculateBatchHash() const; + + // get the most recent batch hash for this LLGLTFMaterial + // may asserts that the cached hash is up to date + size_t getBatchHash() const; + + // update mBatchHash to reflect the current state of this LLGLTFMaterial + void updateBatchHash(); + //setters for various members (will clamp to acceptable ranges) // for_override - set to true if this value is being set as part of an override (important for handling override to default value) @@ -214,6 +226,10 @@ class LLGLTFMaterial : public LLRefCount bool hasLocalTextures() { return !mTrackingIdToLocalTexture.empty(); } virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID &old_id, const LLUUID& new_id); virtual void updateTextureTracking(); + + // pack onto the end of the given vector for use in a UBO (see pbropaqueV.glsl) + void packOnto(std::vector& data, F32 glow = 0.f); + protected: static LLVector2 vec2FromJson(const std::map& object, const char* key, const LLVector2& default_value); static F32 floatFromJson(const std::map& object, const char* key, const F32 default_value); @@ -237,7 +253,9 @@ class LLGLTFMaterial : public LLRefCount void updateLocalTexDataDigest(); public: - // *TODO: If/when we implement additional GLTF extensions, they may not be + + size_t mBatchHash = 0; +#// *TODO: If/when we implement additional GLTF extensions, they may not be // compatible with our GLTF terrain implementation. We may want to disallow // materials with some features from being set on terrain, if their // implementation on terrain is not compliant with the spec: @@ -276,3 +294,12 @@ class LLGLTFMaterial : public LLRefCount bool mOverrideDoubleSided = false; bool mOverrideAlphaMode = false; }; + + +inline size_t hash_value(const LLGLTFMaterial::TextureTransform& t) noexcept +{ + size_t hash = hash_value(t.mOffset); + boost::hash_combine(hash, t.mRotation); + boost::hash_combine(hash, t.mScale); + return hash; +} diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp index fe1587d1975..ddb9e15430b 100644 --- a/indra/llprimitive/llmaterial.cpp +++ b/indra/llprimitive/llmaterial.cpp @@ -474,3 +474,17 @@ LLUUID LLMaterial::getHash() const return id; } +size_t LLMaterial::getBatchHash() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + size_t hash = 0; + boost::hash_combine(hash, mSpecularLightColor); + boost::hash_combine(hash, mSpecularLightExponent); + boost::hash_combine(hash, mEnvironmentIntensity); + boost::hash_combine(hash, mDiffuseAlphaMode); + boost::hash_combine(hash, mAlphaMaskCutoff); + boost::hash_combine(hash, mNormalID); + boost::hash_combine(hash, mSpecularID); + return hash; +} + diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h index a7719c1475a..3b9b66842ee 100644 --- a/indra/llprimitive/llmaterial.h +++ b/indra/llprimitive/llmaterial.h @@ -125,6 +125,9 @@ class LLMaterial : public LLRefCount U32 getShaderMask(U32 alpha_mode, bool is_alpha); LLUUID getHash() const; + // get a boost::hash for the purposes of render batching + size_t getBatchHash() const; + protected: LLUUID mNormalID; F32 mNormalOffsetX; diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index c89037a2d28..0ec6ba0e5e7 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -65,7 +65,7 @@ class LLMeshSkinInfo : public LLRefCount // cached multiply of mBindShapeMatrix and mInvBindMatrix matrix_list_t mBindPoseMatrix; - LL_ALIGN_16(LLMatrix4a mBindShapeMatrix); + LLMatrix4a mBindShapeMatrix; float mPelvisOffset; bool mLockScaleIfJointPosition; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index c5d6076b984..fd41f7060b0 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -814,222 +814,14 @@ bool LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setChanged(GEOMETRY); - if (!mVolumep) - { - mVolumep = volumep; - //mFaceMask = mVolumep->generateFaceMask(); - setNumTEs(mVolumep->getNumFaces()); - return true; - } - -#if 0 - // #if 0'd out by davep - // this is a lot of cruft to set texture entry values that just stay the same for LOD switch - // or immediately get overridden by an object update message, also crashes occasionally - U32 old_face_mask = mVolumep->mFaceMask; - - S32 face_bit = 0; - S32 cur_mask = 0; - - // Grab copies of the old faces from the original shape, ordered by type. - // We will use these to figure out what old texture info gets mapped to new - // faces in the new shape. - std::vector old_faces; - for (S32 face = 0; face < mVolumep->getNumFaces(); face++) - { - old_faces.push_back(mVolumep->getProfile().mFaces[face]); - } - - // Copy the old texture info off to the side, but not in the order in which - // they live in the mTextureList, rather in order of ther "face id" which - // is the corresponding value of LLVolueParams::LLProfile::mFaces::mIndex. - // - // Hence, some elements of old_tes::mEntryList will be invalid. It is - // initialized to a size of 9 (max number of possible faces on a volume?) - // and only the ones with valid types are filled in. - LLPrimTextureList old_tes; - old_tes.setSize(9); - for (face_bit = 0; face_bit < 9; face_bit++) + if (mVolumep) { - cur_mask = 0x1 << face_bit; - if (old_face_mask & cur_mask) - { - S32 te_index = face_index_from_id(cur_mask, old_faces); - old_tes.copyTexture(face_bit, *(getTE(te_index))); - //LL_INFOS() << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << LL_ENDL; - } + sVolumeManager->unrefVolume(mVolumep); } - - // build the new object - sVolumeManager->unrefVolume(mVolumep); mVolumep = volumep; - - U32 new_face_mask = mVolumep->mFaceMask; - S32 i; - - if (old_face_mask == new_face_mask) - { - // nothing to do - return true; - } - - if (mVolumep->getNumFaces() == 0 && new_face_mask != 0) - { - LL_WARNS() << "Object with 0 faces found...INCORRECT!" << LL_ENDL; - setNumTEs(mVolumep->getNumFaces()); - return true; - } - - // initialize face_mapping - S32 face_mapping[9]; - for (face_bit = 0; face_bit < 9; face_bit++) - { - face_mapping[face_bit] = face_bit; - } - - // The new shape may have more faces than the original, but we can't just - // add them to the end -- the ordering matters and it may be that we must - // insert the new faces in the middle of the list. When we add a face it - // will pick up the texture/color info of one of the old faces an so we - // now figure out which old face info gets mapped to each new face, and - // store in the face_mapping lookup table. - for (face_bit = 0; face_bit < 9; face_bit++) - { - cur_mask = 0x1 << face_bit; - if (!(new_face_mask & cur_mask)) - { - // Face doesn't exist in new map. - face_mapping[face_bit] = -1; - continue; - } - else if (old_face_mask & cur_mask) - { - // Face exists in new and old map. - face_mapping[face_bit] = face_bit; - continue; - } - - // OK, how we've got a mismatch, where we have to fill a new face with one from - // the old face. - if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE)) - { - // It's a top/bottom/hollow interior face. - if (old_face_mask & LL_FACE_PATH_END) - { - face_mapping[face_bit] = 1; - continue; - } - else - { - S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; - for (i = 0; i < 4; i++) - { - if (old_face_mask & cur_outer_mask) - { - face_mapping[face_bit] = 5 + i; - break; - } - cur_outer_mask <<= 1; - } - if (i == 4) - { - LL_WARNS() << "No path end or outer face in volume!" << LL_ENDL; - } - continue; - } - } - - if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) - { - // A cut slice. Use the hollow interior if we have it. - if (old_face_mask & LL_FACE_INNER_SIDE) - { - face_mapping[face_bit] = 2; - continue; - } - - // No interior, use the bottom face. - // Could figure out which of the outer faces was nearest, but that would be harder. - if (old_face_mask & LL_FACE_PATH_END) - { - face_mapping[face_bit] = 1; - continue; - } - else - { - S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; - for (i = 0; i < 4; i++) - { - if (old_face_mask & cur_outer_mask) - { - face_mapping[face_bit] = 5 + i; - break; - } - cur_outer_mask <<= 1; - } - if (i == 4) - { - LL_WARNS() << "No path end or outer face in volume!" << LL_ENDL; - } - continue; - } - } - - // OK, the face that's missing is an outer face... - // Pull from the nearest adjacent outer face (there's always guaranteed to be one... - S32 cur_outer = face_bit - 5; - S32 min_dist = 5; - S32 min_outer_bit = -1; - S32 i; - for (i = 0; i < 4; i++) - { - if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i)) - { - S32 dist = abs(i - cur_outer); - if (dist < min_dist) - { - min_dist = dist; - min_outer_bit = i + 5; - } - } - } - if (-1 == min_outer_bit) - { - LL_INFOS() << (LLVolume *)mVolumep << LL_ENDL; - LL_WARNS() << "Bad! No outer faces, impossible!" << LL_ENDL; - } - face_mapping[face_bit] = min_outer_bit; - } - - setNumTEs(mVolumep->getNumFaces()); - for (face_bit = 0; face_bit < 9; face_bit++) - { - // For each possible face type on the new shape we check to see if that - // face exists and if it does we create a texture entry that is a copy - // of one of the originals. Since the originals might not have a - // matching face, we use the face_mapping lookup table to figure out - // which face information to copy. - cur_mask = 0x1 << face_bit; - if (new_face_mask & cur_mask) - { - if (-1 == face_mapping[face_bit]) - { - LL_WARNS() << "No mapping from old face to new face!" << LL_ENDL; - } - S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces); - setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); - } - } -#else - // build the new object - sVolumeManager->unrefVolume(mVolumep); - mVolumep = volumep; - - setNumTEs(mVolumep->getNumFaces()); -#endif return true; } diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 04401e9bea5..ad5f056513d 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -10,6 +10,7 @@ include(LLImage) include(LLWindow) set(llrender_SOURCE_FILES + glworkqueue.cpp llcubemap.cpp llcubemaparray.cpp llfontbitmapcache.cpp @@ -37,7 +38,7 @@ set(llrender_SOURCE_FILES set(llrender_HEADER_FILES CMakeLists.txt - + glworkqueue.h llcubemap.h llcubemaparray.h llfontgl.h diff --git a/indra/llrender/glworkqueue.cpp b/indra/llrender/glworkqueue.cpp new file mode 100644 index 00000000000..8c001fcec64 --- /dev/null +++ b/indra/llrender/glworkqueue.cpp @@ -0,0 +1,174 @@ +/** + * @file llvertexbuffer.cpp + * @brief LLVertexBuffer implementation + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "glworkqueue.h" + +using namespace LL; + +size_t GLWorkQueue::size() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + std::lock_guard lock(mMutex); + return mQueue.size(); +} + +bool GLWorkQueue::done() +{ + return size() == 0 && isClosed(); +} + +void GLWorkQueue::post(const GLWorkQueue::Work& value) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + { + std::lock_guard lock(mMutex); + mQueue.push(std::move(value)); + } + + mCondition.notify_one(); +} + +// Get the next element from the queue +GLWorkQueue::Work GLWorkQueue::pop() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // Lock the mutex + { + std::unique_lock lock(mMutex); + + // Wait for a new element to become available or for the queue to close + { + mCondition.wait(lock, [this] { return !mQueue.empty() || mClosed; }); + } + } + + Work ret; + + { + std::lock_guard lock(mMutex); + + // Get the next element from the queue + if (mQueue.size() > 0) + { + ret = mQueue.front(); + mQueue.pop(); + } + else + { + ret = []() {}; + } + } + + return ret; +} + +void GLWorkQueue::runOne() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + Work w = pop(); + w(); +} + +void GLWorkQueue::runUntilClose() +{ + // run until the queue is closed + while (!isClosed()) + { + runOne(); + } +} + +void GLWorkQueue::close() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + { + std::lock_guard lock(mMutex); + mClosed = true; + } + + mCondition.notify_all(); +} + +bool GLWorkQueue::isClosed() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + std::lock_guard lock(mMutex); + return mClosed; +} + +GLThreadPool::GLThreadPool(U32 thread_count) +{ + for (U32 i = 0; i < thread_count; ++i) + { + mThreads.push_back(std::thread([this]() { run(); })); + } +} + +GLThreadPool::~GLThreadPool() +{ + mQueue.close(); + for (auto& t : mThreads) + { + t.join(); + } +} + +void GLThreadPool::run() +{ + mQueue.runUntilClose(); +} + +void LL::GLThreadPool::post(const GLWorkQueue::Work& value) +{ + mQueue.post(value); +} + +void LL::GLThreadSync::reset() +{ + std::lock_guard lock(mMutex); + mDone = false; +} + +void LL::GLThreadSync::wait() +{ + LL_PROFILE_ZONE_SCOPED; + std::unique_lock lock(mMutex); + mCondition.wait(lock, [this] { return mDone; }); +} + +void LL::GLThreadSync::start() +{ + mMutex.lock(); +} + +void LL::GLThreadSync::finish() +{ + mDone = true; + mMutex.unlock(); + mCondition.notify_one(); +} diff --git a/indra/llrender/glworkqueue.h b/indra/llrender/glworkqueue.h new file mode 100644 index 00000000000..c34ab2d2568 --- /dev/null +++ b/indra/llrender/glworkqueue.h @@ -0,0 +1,121 @@ +/** + * @file glworkqueue.h + * @brief High performance work queue for usage in real-time rendering work + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include +#include +#include +#include "llsingleton.h" + +namespace LL +{ + //============================================================================ + + // High performance WorkQueue for usage in real-time rendering work + class GLWorkQueue + { + public: + using Work = std::function; + + GLWorkQueue() = default; + + void post(const Work& value); + + size_t size(); + + bool done(); + + Work pop(); + + void runOne(); + + void runUntilClose(); + + void close(); + + bool isClosed(); + + private: + std::mutex mMutex; + std::condition_variable mCondition; + std::queue mQueue; + bool mClosed = false; + }; + + + class GLThreadPool : public LLSimpleton + { + public: + GLThreadPool(U32 thread_count = 1); + + ~GLThreadPool(); + + void run(); + + void post(const GLWorkQueue::Work& value); + + private: + std::vector mThreads; + GLWorkQueue mQueue; + }; + + + // helper for waiting on a job to complete + class GLThreadSync + { + public: + + // reset the sync to the "unfinished" state + void reset(); + + // wait for sync to be set + void wait(); + + // call at start of job + void start(); + + // call when job has finished + void finish(); + + // helper class to automatically call start and finish + class Guard + { + public: + Guard(GLThreadSync& sync) : mSync(sync) { mSync.start(); } + ~Guard() { mSync.finish(); } + + private: + GLThreadSync& mSync; + }; + + private: + std::condition_variable mCondition; + bool mDone = false; + std::mutex mMutex; + + }; +}; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 7bc9124ac1c..a4c1c8e7beb 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -218,22 +218,22 @@ std::list LLGLUpdate::sGLQ; #if LL_WINDOWS // WGL_ARB_create_context -PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; +LL_THREAD_LOCAL_GL PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; // WGL_AMD_gpu_association -PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD = nullptr; -PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD = nullptr; -PFNWGLGETCONTEXTGPUIDAMDPROC wglGetContextGPUIDAMD = nullptr; -PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC wglCreateAssociatedContextAMD = nullptr; -PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC wglCreateAssociatedContextAttribsAMD = nullptr; -PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC wglDeleteAssociatedContextAMD = nullptr; -PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC wglMakeAssociatedContextCurrentAMD = nullptr; -PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC wglGetCurrentAssociatedContextAMD = nullptr; -PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLGETCONTEXTGPUIDAMDPROC wglGetContextGPUIDAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC wglCreateAssociatedContextAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC wglCreateAssociatedContextAttribsAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC wglDeleteAssociatedContextAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC wglMakeAssociatedContextCurrentAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC wglGetCurrentAssociatedContextAMD = nullptr; +LL_THREAD_LOCAL_GL PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD = nullptr; // WGL_EXT_swap_control -PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; -PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; +LL_THREAD_LOCAL_GL PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; +LL_THREAD_LOCAL_GL PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; // GL_VERSION_1_2 //PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = nullptr; @@ -242,742 +242,742 @@ PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; //PFNGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D = nullptr; // GL_VERSION_1_3 -PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr; -PFNGLSAMPLECOVERAGEPROC glSampleCoverage = nullptr; -PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D = nullptr; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D = nullptr; -PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D = nullptr; -PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D = nullptr; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D = nullptr; -PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D = nullptr; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage = nullptr; -PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture = nullptr; -PFNGLMULTITEXCOORD1DPROC glMultiTexCoord1d = nullptr; -PFNGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv = nullptr; -PFNGLMULTITEXCOORD1FPROC glMultiTexCoord1f = nullptr; -PFNGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv = nullptr; -PFNGLMULTITEXCOORD1IPROC glMultiTexCoord1i = nullptr; -PFNGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv = nullptr; -PFNGLMULTITEXCOORD1SPROC glMultiTexCoord1s = nullptr; -PFNGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv = nullptr; -PFNGLMULTITEXCOORD2DPROC glMultiTexCoord2d = nullptr; -PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv = nullptr; -PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f = nullptr; -PFNGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv = nullptr; -PFNGLMULTITEXCOORD2IPROC glMultiTexCoord2i = nullptr; -PFNGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv = nullptr; -PFNGLMULTITEXCOORD2SPROC glMultiTexCoord2s = nullptr; -PFNGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv = nullptr; -PFNGLMULTITEXCOORD3DPROC glMultiTexCoord3d = nullptr; -PFNGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv = nullptr; -PFNGLMULTITEXCOORD3FPROC glMultiTexCoord3f = nullptr; -PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv = nullptr; -PFNGLMULTITEXCOORD3IPROC glMultiTexCoord3i = nullptr; -PFNGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv = nullptr; -PFNGLMULTITEXCOORD3SPROC glMultiTexCoord3s = nullptr; -PFNGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv = nullptr; -PFNGLMULTITEXCOORD4DPROC glMultiTexCoord4d = nullptr; -PFNGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv = nullptr; -PFNGLMULTITEXCOORD4FPROC glMultiTexCoord4f = nullptr; -PFNGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv = nullptr; -PFNGLMULTITEXCOORD4IPROC glMultiTexCoord4i = nullptr; -PFNGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv = nullptr; -PFNGLMULTITEXCOORD4SPROC glMultiTexCoord4s = nullptr; -PFNGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv = nullptr; -PFNGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf = nullptr; -PFNGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd = nullptr; -PFNGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf = nullptr; -PFNGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd = nullptr; +LL_THREAD_LOCAL_GL PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLECOVERAGEPROC glSampleCoverage = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1DPROC glMultiTexCoord1d = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1FPROC glMultiTexCoord1f = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1IPROC glMultiTexCoord1i = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1SPROC glMultiTexCoord1s = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2DPROC glMultiTexCoord2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2IPROC glMultiTexCoord2i = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2SPROC glMultiTexCoord2s = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3DPROC glMultiTexCoord3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3FPROC glMultiTexCoord3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3IPROC glMultiTexCoord3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3SPROC glMultiTexCoord3s = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4DPROC glMultiTexCoord4d = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4FPROC glMultiTexCoord4f = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4IPROC glMultiTexCoord4i = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4SPROC glMultiTexCoord4s = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf = nullptr; +LL_THREAD_LOCAL_GL PFNGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd = nullptr; // GL_VERSION_1_4 -PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = nullptr; -PFNGLMULTIDRAWARRAYSPROC glMultiDrawArrays = nullptr; -PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements = nullptr; -PFNGLPOINTPARAMETERFPROC glPointParameterf = nullptr; -PFNGLPOINTPARAMETERFVPROC glPointParameterfv = nullptr; -PFNGLPOINTPARAMETERIPROC glPointParameteri = nullptr; -PFNGLPOINTPARAMETERIVPROC glPointParameteriv = nullptr; -PFNGLFOGCOORDFPROC glFogCoordf = nullptr; -PFNGLFOGCOORDFVPROC glFogCoordfv = nullptr; -PFNGLFOGCOORDDPROC glFogCoordd = nullptr; -PFNGLFOGCOORDDVPROC glFogCoorddv = nullptr; -PFNGLFOGCOORDPOINTERPROC glFogCoordPointer = nullptr; -PFNGLSECONDARYCOLOR3BPROC glSecondaryColor3b = nullptr; -PFNGLSECONDARYCOLOR3BVPROC glSecondaryColor3bv = nullptr; -PFNGLSECONDARYCOLOR3DPROC glSecondaryColor3d = nullptr; -PFNGLSECONDARYCOLOR3DVPROC glSecondaryColor3dv = nullptr; -PFNGLSECONDARYCOLOR3FPROC glSecondaryColor3f = nullptr; -PFNGLSECONDARYCOLOR3FVPROC glSecondaryColor3fv = nullptr; -PFNGLSECONDARYCOLOR3IPROC glSecondaryColor3i = nullptr; -PFNGLSECONDARYCOLOR3IVPROC glSecondaryColor3iv = nullptr; -PFNGLSECONDARYCOLOR3SPROC glSecondaryColor3s = nullptr; -PFNGLSECONDARYCOLOR3SVPROC glSecondaryColor3sv = nullptr; -PFNGLSECONDARYCOLOR3UBPROC glSecondaryColor3ub = nullptr; -PFNGLSECONDARYCOLOR3UBVPROC glSecondaryColor3ubv = nullptr; -PFNGLSECONDARYCOLOR3UIPROC glSecondaryColor3ui = nullptr; -PFNGLSECONDARYCOLOR3UIVPROC glSecondaryColor3uiv = nullptr; -PFNGLSECONDARYCOLOR3USPROC glSecondaryColor3us = nullptr; -PFNGLSECONDARYCOLOR3USVPROC glSecondaryColor3usv = nullptr; -PFNGLSECONDARYCOLORPOINTERPROC glSecondaryColorPointer = nullptr; -PFNGLWINDOWPOS2DPROC glWindowPos2d = nullptr; -PFNGLWINDOWPOS2DVPROC glWindowPos2dv = nullptr; -PFNGLWINDOWPOS2FPROC glWindowPos2f = nullptr; -PFNGLWINDOWPOS2FVPROC glWindowPos2fv = nullptr; -PFNGLWINDOWPOS2IPROC glWindowPos2i = nullptr; -PFNGLWINDOWPOS2IVPROC glWindowPos2iv = nullptr; -PFNGLWINDOWPOS2SPROC glWindowPos2s = nullptr; -PFNGLWINDOWPOS2SVPROC glWindowPos2sv = nullptr; -PFNGLWINDOWPOS3DPROC glWindowPos3d = nullptr; -PFNGLWINDOWPOS3DVPROC glWindowPos3dv = nullptr; -PFNGLWINDOWPOS3FPROC glWindowPos3f = nullptr; -PFNGLWINDOWPOS3FVPROC glWindowPos3fv = nullptr; -PFNGLWINDOWPOS3IPROC glWindowPos3i = nullptr; -PFNGLWINDOWPOS3IVPROC glWindowPos3iv = nullptr; -PFNGLWINDOWPOS3SPROC glWindowPos3s = nullptr; -PFNGLWINDOWPOS3SVPROC glWindowPos3sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSPROC glMultiDrawArrays = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERFPROC glPointParameterf = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERFVPROC glPointParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERIPROC glPointParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERIVPROC glPointParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLFOGCOORDFPROC glFogCoordf = nullptr; +LL_THREAD_LOCAL_GL PFNGLFOGCOORDFVPROC glFogCoordfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLFOGCOORDDPROC glFogCoordd = nullptr; +LL_THREAD_LOCAL_GL PFNGLFOGCOORDDVPROC glFogCoorddv = nullptr; +LL_THREAD_LOCAL_GL PFNGLFOGCOORDPOINTERPROC glFogCoordPointer = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3BPROC glSecondaryColor3b = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3BVPROC glSecondaryColor3bv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3DPROC glSecondaryColor3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3DVPROC glSecondaryColor3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3FPROC glSecondaryColor3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3FVPROC glSecondaryColor3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3IPROC glSecondaryColor3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3IVPROC glSecondaryColor3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3SPROC glSecondaryColor3s = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3SVPROC glSecondaryColor3sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UBPROC glSecondaryColor3ub = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UBVPROC glSecondaryColor3ubv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UIPROC glSecondaryColor3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UIVPROC glSecondaryColor3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3USPROC glSecondaryColor3us = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3USVPROC glSecondaryColor3usv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORPOINTERPROC glSecondaryColorPointer = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2DPROC glWindowPos2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2DVPROC glWindowPos2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2FPROC glWindowPos2f = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2FVPROC glWindowPos2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2IPROC glWindowPos2i = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2IVPROC glWindowPos2iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2SPROC glWindowPos2s = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2SVPROC glWindowPos2sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3DPROC glWindowPos3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3DVPROC glWindowPos3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3FPROC glWindowPos3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3FVPROC glWindowPos3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3IPROC glWindowPos3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3IVPROC glWindowPos3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3SPROC glWindowPos3s = nullptr; +LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3SVPROC glWindowPos3sv = nullptr; // GL_VERSION_1_5 -PFNGLGENQUERIESPROC glGenQueries = nullptr; -PFNGLDELETEQUERIESPROC glDeleteQueries = nullptr; -PFNGLISQUERYPROC glIsQuery = nullptr; -PFNGLBEGINQUERYPROC glBeginQuery = nullptr; -PFNGLENDQUERYPROC glEndQuery = nullptr; -PFNGLGETQUERYIVPROC glGetQueryiv = nullptr; -PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv = nullptr; -PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv = nullptr; -PFNGLBINDBUFFERPROC glBindBuffer = nullptr; -PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr; -PFNGLGENBUFFERSPROC glGenBuffers = nullptr; -PFNGLISBUFFERPROC glIsBuffer = nullptr; -PFNGLBUFFERDATAPROC glBufferData = nullptr; -PFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr; -PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData = nullptr; -PFNGLMAPBUFFERPROC glMapBuffer = nullptr; -PFNGLUNMAPBUFFERPROC glUnmapBuffer = nullptr; -PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; -PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENQUERIESPROC glGenQueries = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEQUERIESPROC glDeleteQueries = nullptr; +LL_THREAD_LOCAL_GL PFNGLISQUERYPROC glIsQuery = nullptr; +LL_THREAD_LOCAL_GL PFNGLBEGINQUERYPROC glBeginQuery = nullptr; +LL_THREAD_LOCAL_GL PFNGLENDQUERYPROC glEndQuery = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYIVPROC glGetQueryiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDBUFFERPROC glBindBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENBUFFERSPROC glGenBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLISBUFFERPROC glIsBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLBUFFERDATAPROC glBufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLMAPBUFFERPROC glMapBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNMAPBUFFERPROC glUnmapBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv = nullptr; // GL_VERSION_2_0 -PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate = nullptr; -PFNGLDRAWBUFFERSPROC glDrawBuffers = nullptr; -PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate = nullptr; -PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate = nullptr; -PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate = nullptr; -PFNGLATTACHSHADERPROC glAttachShader = nullptr; -PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr; -PFNGLCOMPILESHADERPROC glCompileShader = nullptr; -PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr; -PFNGLCREATESHADERPROC glCreateShader = nullptr; -PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr; -PFNGLDELETESHADERPROC glDeleteShader = nullptr; -PFNGLDETACHSHADERPROC glDetachShader = nullptr; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr; -PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; -PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib = nullptr; -PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform = nullptr; -PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders = nullptr; -PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = nullptr; -PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr; -PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr; -PFNGLGETSHADERIVPROC glGetShaderiv = nullptr; -PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr; -PFNGLGETSHADERSOURCEPROC glGetShaderSource = nullptr; -PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; -PFNGLGETUNIFORMFVPROC glGetUniformfv = nullptr; -PFNGLGETUNIFORMIVPROC glGetUniformiv = nullptr; -PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv = nullptr; -PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv = nullptr; -PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv = nullptr; -PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv = nullptr; -PFNGLISPROGRAMPROC glIsProgram = nullptr; -PFNGLISSHADERPROC glIsShader = nullptr; -PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; -PFNGLSHADERSOURCEPROC glShaderSource = nullptr; -PFNGLUSEPROGRAMPROC glUseProgram = nullptr; -PFNGLUNIFORM1FPROC glUniform1f = nullptr; -PFNGLUNIFORM2FPROC glUniform2f = nullptr; -PFNGLUNIFORM3FPROC glUniform3f = nullptr; -PFNGLUNIFORM4FPROC glUniform4f = nullptr; -PFNGLUNIFORM1IPROC glUniform1i = nullptr; -PFNGLUNIFORM2IPROC glUniform2i = nullptr; -PFNGLUNIFORM3IPROC glUniform3i = nullptr; -PFNGLUNIFORM4IPROC glUniform4i = nullptr; -PFNGLUNIFORM1FVPROC glUniform1fv = nullptr; -PFNGLUNIFORM2FVPROC glUniform2fv = nullptr; -PFNGLUNIFORM3FVPROC glUniform3fv = nullptr; -PFNGLUNIFORM4FVPROC glUniform4fv = nullptr; -PFNGLUNIFORM1IVPROC glUniform1iv = nullptr; -PFNGLUNIFORM2IVPROC glUniform2iv = nullptr; -PFNGLUNIFORM3IVPROC glUniform3iv = nullptr; -PFNGLUNIFORM4IVPROC glUniform4iv = nullptr; -PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv = nullptr; -PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv = nullptr; -PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr; -PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr; -PFNGLVERTEXATTRIB1DPROC glVertexAttrib1d = nullptr; -PFNGLVERTEXATTRIB1DVPROC glVertexAttrib1dv = nullptr; -PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f = nullptr; -PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv = nullptr; -PFNGLVERTEXATTRIB1SPROC glVertexAttrib1s = nullptr; -PFNGLVERTEXATTRIB1SVPROC glVertexAttrib1sv = nullptr; -PFNGLVERTEXATTRIB2DPROC glVertexAttrib2d = nullptr; -PFNGLVERTEXATTRIB2DVPROC glVertexAttrib2dv = nullptr; -PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f = nullptr; -PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv = nullptr; -PFNGLVERTEXATTRIB2SPROC glVertexAttrib2s = nullptr; -PFNGLVERTEXATTRIB2SVPROC glVertexAttrib2sv = nullptr; -PFNGLVERTEXATTRIB3DPROC glVertexAttrib3d = nullptr; -PFNGLVERTEXATTRIB3DVPROC glVertexAttrib3dv = nullptr; -PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f = nullptr; -PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv = nullptr; -PFNGLVERTEXATTRIB3SPROC glVertexAttrib3s = nullptr; -PFNGLVERTEXATTRIB3SVPROC glVertexAttrib3sv = nullptr; -PFNGLVERTEXATTRIB4NBVPROC glVertexAttrib4Nbv = nullptr; -PFNGLVERTEXATTRIB4NIVPROC glVertexAttrib4Niv = nullptr; -PFNGLVERTEXATTRIB4NSVPROC glVertexAttrib4Nsv = nullptr; -PFNGLVERTEXATTRIB4NUBPROC glVertexAttrib4Nub = nullptr; -PFNGLVERTEXATTRIB4NUBVPROC glVertexAttrib4Nubv = nullptr; -PFNGLVERTEXATTRIB4NUIVPROC glVertexAttrib4Nuiv = nullptr; -PFNGLVERTEXATTRIB4NUSVPROC glVertexAttrib4Nusv = nullptr; -PFNGLVERTEXATTRIB4BVPROC glVertexAttrib4bv = nullptr; -PFNGLVERTEXATTRIB4DPROC glVertexAttrib4d = nullptr; -PFNGLVERTEXATTRIB4DVPROC glVertexAttrib4dv = nullptr; -PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f = nullptr; -PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv = nullptr; -PFNGLVERTEXATTRIB4IVPROC glVertexAttrib4iv = nullptr; -PFNGLVERTEXATTRIB4SPROC glVertexAttrib4s = nullptr; -PFNGLVERTEXATTRIB4SVPROC glVertexAttrib4sv = nullptr; -PFNGLVERTEXATTRIB4UBVPROC glVertexAttrib4ubv = nullptr; -PFNGLVERTEXATTRIB4UIVPROC glVertexAttrib4uiv = nullptr; -PFNGLVERTEXATTRIB4USVPROC glVertexAttrib4usv = nullptr; -PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWBUFFERSPROC glDrawBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate = nullptr; +LL_THREAD_LOCAL_GL PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate = nullptr; +LL_THREAD_LOCAL_GL PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate = nullptr; +LL_THREAD_LOCAL_GL PFNGLATTACHSHADERPROC glAttachShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPILESHADERPROC glCompileShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATESHADERPROC glCreateShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETESHADERPROC glDeleteShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLDETACHSHADERPROC glDetachShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr; +LL_THREAD_LOCAL_GL PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSHADERIVPROC glGetShaderiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSHADERSOURCEPROC glGetShaderSource = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMFVPROC glGetUniformfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMIVPROC glGetUniformiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv = nullptr; +LL_THREAD_LOCAL_GL PFNGLISPROGRAMPROC glIsProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLISSHADERPROC glIsShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLSHADERSOURCEPROC glShaderSource = nullptr; +LL_THREAD_LOCAL_GL PFNGLUSEPROGRAMPROC glUseProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1FPROC glUniform1f = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2FPROC glUniform2f = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3FPROC glUniform3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4FPROC glUniform4f = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1IPROC glUniform1i = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2IPROC glUniform2i = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3IPROC glUniform3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4IPROC glUniform4i = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1FVPROC glUniform1fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2FVPROC glUniform2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3FVPROC glUniform3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4FVPROC glUniform4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1IVPROC glUniform1iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2IVPROC glUniform2iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3IVPROC glUniform3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4IVPROC glUniform4iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1DPROC glVertexAttrib1d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1DVPROC glVertexAttrib1dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1SPROC glVertexAttrib1s = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1SVPROC glVertexAttrib1sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2DPROC glVertexAttrib2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2DVPROC glVertexAttrib2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2SPROC glVertexAttrib2s = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2SVPROC glVertexAttrib2sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3DPROC glVertexAttrib3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3DVPROC glVertexAttrib3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3SPROC glVertexAttrib3s = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3SVPROC glVertexAttrib3sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NBVPROC glVertexAttrib4Nbv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NIVPROC glVertexAttrib4Niv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NSVPROC glVertexAttrib4Nsv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUBPROC glVertexAttrib4Nub = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUBVPROC glVertexAttrib4Nubv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUIVPROC glVertexAttrib4Nuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUSVPROC glVertexAttrib4Nusv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4BVPROC glVertexAttrib4bv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4DPROC glVertexAttrib4d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4DVPROC glVertexAttrib4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4IVPROC glVertexAttrib4iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4SPROC glVertexAttrib4s = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4SVPROC glVertexAttrib4sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4UBVPROC glVertexAttrib4ubv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4UIVPROC glVertexAttrib4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4USVPROC glVertexAttrib4usv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr; // GL_VERSION_2_1 -PFNGLUNIFORMMATRIX2X3FVPROC glUniformMatrix2x3fv = nullptr; -PFNGLUNIFORMMATRIX3X2FVPROC glUniformMatrix3x2fv = nullptr; -PFNGLUNIFORMMATRIX2X4FVPROC glUniformMatrix2x4fv = nullptr; -PFNGLUNIFORMMATRIX4X2FVPROC glUniformMatrix4x2fv = nullptr; -PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv = nullptr; -PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X3FVPROC glUniformMatrix2x3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X2FVPROC glUniformMatrix3x2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X4FVPROC glUniformMatrix2x4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X2FVPROC glUniformMatrix4x2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv = nullptr; // GL_VERSION_3_0 -PFNGLCOLORMASKIPROC glColorMaski = nullptr; -PFNGLGETBOOLEANI_VPROC glGetBooleani_v = nullptr; -PFNGLGETINTEGERI_VPROC glGetIntegeri_v = nullptr; -PFNGLENABLEIPROC glEnablei = nullptr; -PFNGLDISABLEIPROC glDisablei = nullptr; -PFNGLISENABLEDIPROC glIsEnabledi = nullptr; -PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = nullptr; -PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = nullptr; -PFNGLBINDBUFFERRANGEPROC glBindBufferRange = nullptr; -PFNGLBINDBUFFERBASEPROC glBindBufferBase = nullptr; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = nullptr; -PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glGetTransformFeedbackVarying = nullptr; -PFNGLCLAMPCOLORPROC glClampColor = nullptr; -PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender = nullptr; -PFNGLENDCONDITIONALRENDERPROC glEndConditionalRender = nullptr; -PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = nullptr; -PFNGLGETVERTEXATTRIBIIVPROC glGetVertexAttribIiv = nullptr; -PFNGLGETVERTEXATTRIBIUIVPROC glGetVertexAttribIuiv = nullptr; -PFNGLVERTEXATTRIBI1IPROC glVertexAttribI1i = nullptr; -PFNGLVERTEXATTRIBI2IPROC glVertexAttribI2i = nullptr; -PFNGLVERTEXATTRIBI3IPROC glVertexAttribI3i = nullptr; -PFNGLVERTEXATTRIBI4IPROC glVertexAttribI4i = nullptr; -PFNGLVERTEXATTRIBI1UIPROC glVertexAttribI1ui = nullptr; -PFNGLVERTEXATTRIBI2UIPROC glVertexAttribI2ui = nullptr; -PFNGLVERTEXATTRIBI3UIPROC glVertexAttribI3ui = nullptr; -PFNGLVERTEXATTRIBI4UIPROC glVertexAttribI4ui = nullptr; -PFNGLVERTEXATTRIBI1IVPROC glVertexAttribI1iv = nullptr; -PFNGLVERTEXATTRIBI2IVPROC glVertexAttribI2iv = nullptr; -PFNGLVERTEXATTRIBI3IVPROC glVertexAttribI3iv = nullptr; -PFNGLVERTEXATTRIBI4IVPROC glVertexAttribI4iv = nullptr; -PFNGLVERTEXATTRIBI1UIVPROC glVertexAttribI1uiv = nullptr; -PFNGLVERTEXATTRIBI2UIVPROC glVertexAttribI2uiv = nullptr; -PFNGLVERTEXATTRIBI3UIVPROC glVertexAttribI3uiv = nullptr; -PFNGLVERTEXATTRIBI4UIVPROC glVertexAttribI4uiv = nullptr; -PFNGLVERTEXATTRIBI4BVPROC glVertexAttribI4bv = nullptr; -PFNGLVERTEXATTRIBI4SVPROC glVertexAttribI4sv = nullptr; -PFNGLVERTEXATTRIBI4UBVPROC glVertexAttribI4ubv = nullptr; -PFNGLVERTEXATTRIBI4USVPROC glVertexAttribI4usv = nullptr; -PFNGLGETUNIFORMUIVPROC glGetUniformuiv = nullptr; -PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation = nullptr; -PFNGLGETFRAGDATALOCATIONPROC glGetFragDataLocation = nullptr; -PFNGLUNIFORM1UIPROC glUniform1ui = nullptr; -PFNGLUNIFORM2UIPROC glUniform2ui = nullptr; -PFNGLUNIFORM3UIPROC glUniform3ui = nullptr; -PFNGLUNIFORM4UIPROC glUniform4ui = nullptr; -PFNGLUNIFORM1UIVPROC glUniform1uiv = nullptr; -PFNGLUNIFORM2UIVPROC glUniform2uiv = nullptr; -PFNGLUNIFORM3UIVPROC glUniform3uiv = nullptr; -PFNGLUNIFORM4UIVPROC glUniform4uiv = nullptr; -PFNGLTEXPARAMETERIIVPROC glTexParameterIiv = nullptr; -PFNGLTEXPARAMETERIUIVPROC glTexParameterIuiv = nullptr; -PFNGLGETTEXPARAMETERIIVPROC glGetTexParameterIiv = nullptr; -PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv = nullptr; -PFNGLCLEARBUFFERIVPROC glClearBufferiv = nullptr; -PFNGLCLEARBUFFERUIVPROC glClearBufferuiv = nullptr; -PFNGLCLEARBUFFERFVPROC glClearBufferfv = nullptr; -PFNGLCLEARBUFFERFIPROC glClearBufferfi = nullptr; -PFNGLGETSTRINGIPROC glGetStringi = nullptr; -PFNGLISRENDERBUFFERPROC glIsRenderbuffer = nullptr; -PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; -PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr; -PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; -PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = nullptr; -PFNGLISFRAMEBUFFERPROC glIsFramebuffer = nullptr; -PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; -PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr; -PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; -PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = nullptr; -PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr; -PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = nullptr; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = nullptr; -PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr; -PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = nullptr; -PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = nullptr; -PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = nullptr; -PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; -PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr; -PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; -PFNGLISVERTEXARRAYPROC glIsVertexArray = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOLORMASKIPROC glColorMaski = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETBOOLEANI_VPROC glGetBooleani_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETINTEGERI_VPROC glGetIntegeri_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLENABLEIPROC glEnablei = nullptr; +LL_THREAD_LOCAL_GL PFNGLDISABLEIPROC glDisablei = nullptr; +LL_THREAD_LOCAL_GL PFNGLISENABLEDIPROC glIsEnabledi = nullptr; +LL_THREAD_LOCAL_GL PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDBUFFERRANGEPROC glBindBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDBUFFERBASEPROC glBindBufferBase = nullptr; +LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glGetTransformFeedbackVarying = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLAMPCOLORPROC glClampColor = nullptr; +LL_THREAD_LOCAL_GL PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender = nullptr; +LL_THREAD_LOCAL_GL PFNGLENDCONDITIONALRENDERPROC glEndConditionalRender = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIIVPROC glGetVertexAttribIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIUIVPROC glGetVertexAttribIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1IPROC glVertexAttribI1i = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2IPROC glVertexAttribI2i = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3IPROC glVertexAttribI3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4IPROC glVertexAttribI4i = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1UIPROC glVertexAttribI1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2UIPROC glVertexAttribI2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3UIPROC glVertexAttribI3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UIPROC glVertexAttribI4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1IVPROC glVertexAttribI1iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2IVPROC glVertexAttribI2iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3IVPROC glVertexAttribI3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4IVPROC glVertexAttribI4iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1UIVPROC glVertexAttribI1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2UIVPROC glVertexAttribI2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3UIVPROC glVertexAttribI3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UIVPROC glVertexAttribI4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4BVPROC glVertexAttribI4bv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4SVPROC glVertexAttribI4sv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UBVPROC glVertexAttribI4ubv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4USVPROC glVertexAttribI4usv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMUIVPROC glGetUniformuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETFRAGDATALOCATIONPROC glGetFragDataLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1UIPROC glUniform1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2UIPROC glUniform2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3UIPROC glUniform3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4UIPROC glUniform4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1UIVPROC glUniform1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2UIVPROC glUniform2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3UIVPROC glUniform3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4UIVPROC glUniform4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXPARAMETERIIVPROC glTexParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXPARAMETERIUIVPROC glTexParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXPARAMETERIIVPROC glGetTexParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERIVPROC glClearBufferiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERUIVPROC glClearBufferuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERFVPROC glClearBufferfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERFIPROC glClearBufferfi = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSTRINGIPROC glGetStringi = nullptr; +LL_THREAD_LOCAL_GL PFNGLISRENDERBUFFERPROC glIsRenderbuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLISFRAMEBUFFERPROC glIsFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = nullptr; +LL_THREAD_LOCAL_GL PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; +LL_THREAD_LOCAL_GL PFNGLISVERTEXARRAYPROC glIsVertexArray = nullptr; // GL_VERSION_3_1 -PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced = nullptr; -PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced = nullptr; -PFNGLTEXBUFFERPROC glTexBuffer = nullptr; -PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = nullptr; -PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData = nullptr; -PFNGLGETUNIFORMINDICESPROC glGetUniformIndices = nullptr; -PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv = nullptr; -PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName = nullptr; -PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex = nullptr; -PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv = nullptr; -PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName = nullptr; -PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXBUFFERPROC glTexBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMINDICESPROC glGetUniformIndices = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding = nullptr; // GL_VERSION_3_2 -PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex = nullptr; -PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glDrawRangeElementsBaseVertex = nullptr; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex = nullptr; -PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glMultiDrawElementsBaseVertex = nullptr; -PFNGLPROVOKINGVERTEXPROC glProvokingVertex = nullptr; -PFNGLFENCESYNCPROC glFenceSync = nullptr; -PFNGLISSYNCPROC glIsSync = nullptr; -PFNGLDELETESYNCPROC glDeleteSync = nullptr; -PFNGLCLIENTWAITSYNCPROC glClientWaitSync = nullptr; -PFNGLWAITSYNCPROC glWaitSync = nullptr; -PFNGLGETINTEGER64VPROC glGetInteger64v = nullptr; -PFNGLGETSYNCIVPROC glGetSynciv = nullptr; -PFNGLGETINTEGER64I_VPROC glGetInteger64i_v = nullptr; -PFNGLGETBUFFERPARAMETERI64VPROC glGetBufferParameteri64v = nullptr; -PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture = nullptr; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = nullptr; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = nullptr; -PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = nullptr; -PFNGLSAMPLEMASKIPROC glSampleMaski = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glDrawRangeElementsBaseVertex = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glMultiDrawElementsBaseVertex = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROVOKINGVERTEXPROC glProvokingVertex = nullptr; +LL_THREAD_LOCAL_GL PFNGLFENCESYNCPROC glFenceSync = nullptr; +LL_THREAD_LOCAL_GL PFNGLISSYNCPROC glIsSync = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETESYNCPROC glDeleteSync = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLIENTWAITSYNCPROC glClientWaitSync = nullptr; +LL_THREAD_LOCAL_GL PFNGLWAITSYNCPROC glWaitSync = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETINTEGER64VPROC glGetInteger64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSYNCIVPROC glGetSynciv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETINTEGER64I_VPROC glGetInteger64i_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETBUFFERPARAMETERI64VPROC glGetBufferParameteri64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLEMASKIPROC glSampleMaski = nullptr; // GL_VERSION_3_3 -PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed = nullptr; -PFNGLGETFRAGDATAINDEXPROC glGetFragDataIndex = nullptr; -PFNGLGENSAMPLERSPROC glGenSamplers = nullptr; -PFNGLDELETESAMPLERSPROC glDeleteSamplers = nullptr; -PFNGLISSAMPLERPROC glIsSampler = nullptr; -PFNGLBINDSAMPLERPROC glBindSampler = nullptr; -PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri = nullptr; -PFNGLSAMPLERPARAMETERIVPROC glSamplerParameteriv = nullptr; -PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf = nullptr; -PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv = nullptr; -PFNGLSAMPLERPARAMETERIIVPROC glSamplerParameterIiv = nullptr; -PFNGLSAMPLERPARAMETERIUIVPROC glSamplerParameterIuiv = nullptr; -PFNGLGETSAMPLERPARAMETERIVPROC glGetSamplerParameteriv = nullptr; -PFNGLGETSAMPLERPARAMETERIIVPROC glGetSamplerParameterIiv = nullptr; -PFNGLGETSAMPLERPARAMETERFVPROC glGetSamplerParameterfv = nullptr; -PFNGLGETSAMPLERPARAMETERIUIVPROC glGetSamplerParameterIuiv = nullptr; -PFNGLQUERYCOUNTERPROC glQueryCounter = nullptr; -PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = nullptr; -PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = nullptr; -PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor = nullptr; -PFNGLVERTEXATTRIBP1UIPROC glVertexAttribP1ui = nullptr; -PFNGLVERTEXATTRIBP1UIVPROC glVertexAttribP1uiv = nullptr; -PFNGLVERTEXATTRIBP2UIPROC glVertexAttribP2ui = nullptr; -PFNGLVERTEXATTRIBP2UIVPROC glVertexAttribP2uiv = nullptr; -PFNGLVERTEXATTRIBP3UIPROC glVertexAttribP3ui = nullptr; -PFNGLVERTEXATTRIBP3UIVPROC glVertexAttribP3uiv = nullptr; -PFNGLVERTEXATTRIBP4UIPROC glVertexAttribP4ui = nullptr; -PFNGLVERTEXATTRIBP4UIVPROC glVertexAttribP4uiv = nullptr; -PFNGLVERTEXP2UIPROC glVertexP2ui = nullptr; -PFNGLVERTEXP2UIVPROC glVertexP2uiv = nullptr; -PFNGLVERTEXP3UIPROC glVertexP3ui = nullptr; -PFNGLVERTEXP3UIVPROC glVertexP3uiv = nullptr; -PFNGLVERTEXP4UIPROC glVertexP4ui = nullptr; -PFNGLVERTEXP4UIVPROC glVertexP4uiv = nullptr; -PFNGLTEXCOORDP1UIPROC glTexCoordP1ui = nullptr; -PFNGLTEXCOORDP1UIVPROC glTexCoordP1uiv = nullptr; -PFNGLTEXCOORDP2UIPROC glTexCoordP2ui = nullptr; -PFNGLTEXCOORDP2UIVPROC glTexCoordP2uiv = nullptr; -PFNGLTEXCOORDP3UIPROC glTexCoordP3ui = nullptr; -PFNGLTEXCOORDP3UIVPROC glTexCoordP3uiv = nullptr; -PFNGLTEXCOORDP4UIPROC glTexCoordP4ui = nullptr; -PFNGLTEXCOORDP4UIVPROC glTexCoordP4uiv = nullptr; -PFNGLMULTITEXCOORDP1UIPROC glMultiTexCoordP1ui = nullptr; -PFNGLMULTITEXCOORDP1UIVPROC glMultiTexCoordP1uiv = nullptr; -PFNGLMULTITEXCOORDP2UIPROC glMultiTexCoordP2ui = nullptr; -PFNGLMULTITEXCOORDP2UIVPROC glMultiTexCoordP2uiv = nullptr; -PFNGLMULTITEXCOORDP3UIPROC glMultiTexCoordP3ui = nullptr; -PFNGLMULTITEXCOORDP3UIVPROC glMultiTexCoordP3uiv = nullptr; -PFNGLMULTITEXCOORDP4UIPROC glMultiTexCoordP4ui = nullptr; -PFNGLMULTITEXCOORDP4UIVPROC glMultiTexCoordP4uiv = nullptr; -PFNGLNORMALP3UIPROC glNormalP3ui = nullptr; -PFNGLNORMALP3UIVPROC glNormalP3uiv = nullptr; -PFNGLCOLORP3UIPROC glColorP3ui = nullptr; -PFNGLCOLORP3UIVPROC glColorP3uiv = nullptr; -PFNGLCOLORP4UIPROC glColorP4ui = nullptr; -PFNGLCOLORP4UIVPROC glColorP4uiv = nullptr; -PFNGLSECONDARYCOLORP3UIPROC glSecondaryColorP3ui = nullptr; -PFNGLSECONDARYCOLORP3UIVPROC glSecondaryColorP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETFRAGDATAINDEXPROC glGetFragDataIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENSAMPLERSPROC glGenSamplers = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETESAMPLERSPROC glDeleteSamplers = nullptr; +LL_THREAD_LOCAL_GL PFNGLISSAMPLERPROC glIsSampler = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDSAMPLERPROC glBindSampler = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIVPROC glSamplerParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIIVPROC glSamplerParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIUIVPROC glSamplerParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIVPROC glGetSamplerParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIIVPROC glGetSamplerParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERFVPROC glGetSamplerParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIUIVPROC glGetSamplerParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLQUERYCOUNTERPROC glQueryCounter = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP1UIPROC glVertexAttribP1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP1UIVPROC glVertexAttribP1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP2UIPROC glVertexAttribP2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP2UIVPROC glVertexAttribP2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP3UIPROC glVertexAttribP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP3UIVPROC glVertexAttribP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP4UIPROC glVertexAttribP4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP4UIVPROC glVertexAttribP4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP2UIPROC glVertexP2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP2UIVPROC glVertexP2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP3UIPROC glVertexP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP3UIVPROC glVertexP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP4UIPROC glVertexP4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXP4UIVPROC glVertexP4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP1UIPROC glTexCoordP1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP1UIVPROC glTexCoordP1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP2UIPROC glTexCoordP2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP2UIVPROC glTexCoordP2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP3UIPROC glTexCoordP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP3UIVPROC glTexCoordP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP4UIPROC glTexCoordP4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXCOORDP4UIVPROC glTexCoordP4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP1UIPROC glMultiTexCoordP1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP1UIVPROC glMultiTexCoordP1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP2UIPROC glMultiTexCoordP2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP2UIVPROC glMultiTexCoordP2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP3UIPROC glMultiTexCoordP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP3UIVPROC glMultiTexCoordP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP4UIPROC glMultiTexCoordP4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP4UIVPROC glMultiTexCoordP4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLNORMALP3UIPROC glNormalP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLNORMALP3UIVPROC glNormalP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOLORP3UIPROC glColorP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOLORP3UIVPROC glColorP3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOLORP4UIPROC glColorP4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOLORP4UIVPROC glColorP4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORP3UIPROC glSecondaryColorP3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORP3UIVPROC glSecondaryColorP3uiv = nullptr; // GL_VERSION_4_0 -PFNGLMINSAMPLESHADINGPROC glMinSampleShading = nullptr; -PFNGLBLENDEQUATIONIPROC glBlendEquationi = nullptr; -PFNGLBLENDEQUATIONSEPARATEIPROC glBlendEquationSeparatei = nullptr; -PFNGLBLENDFUNCIPROC glBlendFunci = nullptr; -PFNGLBLENDFUNCSEPARATEIPROC glBlendFuncSeparatei = nullptr; -PFNGLDRAWARRAYSINDIRECTPROC glDrawArraysIndirect = nullptr; -PFNGLDRAWELEMENTSINDIRECTPROC glDrawElementsIndirect = nullptr; -PFNGLUNIFORM1DPROC glUniform1d = nullptr; -PFNGLUNIFORM2DPROC glUniform2d = nullptr; -PFNGLUNIFORM3DPROC glUniform3d = nullptr; -PFNGLUNIFORM4DPROC glUniform4d = nullptr; -PFNGLUNIFORM1DVPROC glUniform1dv = nullptr; -PFNGLUNIFORM2DVPROC glUniform2dv = nullptr; -PFNGLUNIFORM3DVPROC glUniform3dv = nullptr; -PFNGLUNIFORM4DVPROC glUniform4dv = nullptr; -PFNGLUNIFORMMATRIX2DVPROC glUniformMatrix2dv = nullptr; -PFNGLUNIFORMMATRIX3DVPROC glUniformMatrix3dv = nullptr; -PFNGLUNIFORMMATRIX4DVPROC glUniformMatrix4dv = nullptr; -PFNGLUNIFORMMATRIX2X3DVPROC glUniformMatrix2x3dv = nullptr; -PFNGLUNIFORMMATRIX2X4DVPROC glUniformMatrix2x4dv = nullptr; -PFNGLUNIFORMMATRIX3X2DVPROC glUniformMatrix3x2dv = nullptr; -PFNGLUNIFORMMATRIX3X4DVPROC glUniformMatrix3x4dv = nullptr; -PFNGLUNIFORMMATRIX4X2DVPROC glUniformMatrix4x2dv = nullptr; -PFNGLUNIFORMMATRIX4X3DVPROC glUniformMatrix4x3dv = nullptr; -PFNGLGETUNIFORMDVPROC glGetUniformdv = nullptr; -PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glGetSubroutineUniformLocation = nullptr; -PFNGLGETSUBROUTINEINDEXPROC glGetSubroutineIndex = nullptr; -PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glGetActiveSubroutineUniformiv = nullptr; -PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glGetActiveSubroutineUniformName = nullptr; -PFNGLGETACTIVESUBROUTINENAMEPROC glGetActiveSubroutineName = nullptr; -PFNGLUNIFORMSUBROUTINESUIVPROC glUniformSubroutinesuiv = nullptr; -PFNGLGETUNIFORMSUBROUTINEUIVPROC glGetUniformSubroutineuiv = nullptr; -PFNGLGETPROGRAMSTAGEIVPROC glGetProgramStageiv = nullptr; -PFNGLPATCHPARAMETERIPROC glPatchParameteri = nullptr; -PFNGLPATCHPARAMETERFVPROC glPatchParameterfv = nullptr; -PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback = nullptr; -PFNGLDELETETRANSFORMFEEDBACKSPROC glDeleteTransformFeedbacks = nullptr; -PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks = nullptr; -PFNGLISTRANSFORMFEEDBACKPROC glIsTransformFeedback = nullptr; -PFNGLPAUSETRANSFORMFEEDBACKPROC glPauseTransformFeedback = nullptr; -PFNGLRESUMETRANSFORMFEEDBACKPROC glResumeTransformFeedback = nullptr; -PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback = nullptr; -PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glDrawTransformFeedbackStream = nullptr; -PFNGLBEGINQUERYINDEXEDPROC glBeginQueryIndexed = nullptr; -PFNGLENDQUERYINDEXEDPROC glEndQueryIndexed = nullptr; -PFNGLGETQUERYINDEXEDIVPROC glGetQueryIndexediv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMINSAMPLESHADINGPROC glMinSampleShading = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONIPROC glBlendEquationi = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONSEPARATEIPROC glBlendEquationSeparatei = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDFUNCIPROC glBlendFunci = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLENDFUNCSEPARATEIPROC glBlendFuncSeparatei = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINDIRECTPROC glDrawArraysIndirect = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINDIRECTPROC glDrawElementsIndirect = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1DPROC glUniform1d = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2DPROC glUniform2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3DPROC glUniform3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4DPROC glUniform4d = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM1DVPROC glUniform1dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM2DVPROC glUniform2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM3DVPROC glUniform3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORM4DVPROC glUniform4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2DVPROC glUniformMatrix2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3DVPROC glUniformMatrix3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4DVPROC glUniformMatrix4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X3DVPROC glUniformMatrix2x3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X4DVPROC glUniformMatrix2x4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X2DVPROC glUniformMatrix3x2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X4DVPROC glUniformMatrix3x4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X2DVPROC glUniformMatrix4x2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X3DVPROC glUniformMatrix4x3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMDVPROC glGetUniformdv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glGetSubroutineUniformLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSUBROUTINEINDEXPROC glGetSubroutineIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glGetActiveSubroutineUniformiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glGetActiveSubroutineUniformName = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINENAMEPROC glGetActiveSubroutineName = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNIFORMSUBROUTINESUIVPROC glUniformSubroutinesuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETUNIFORMSUBROUTINEUIVPROC glGetUniformSubroutineuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMSTAGEIVPROC glGetProgramStageiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPATCHPARAMETERIPROC glPatchParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLPATCHPARAMETERFVPROC glPatchParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETETRANSFORMFEEDBACKSPROC glDeleteTransformFeedbacks = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks = nullptr; +LL_THREAD_LOCAL_GL PFNGLISTRANSFORMFEEDBACKPROC glIsTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLPAUSETRANSFORMFEEDBACKPROC glPauseTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLRESUMETRANSFORMFEEDBACKPROC glResumeTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glDrawTransformFeedbackStream = nullptr; +LL_THREAD_LOCAL_GL PFNGLBEGINQUERYINDEXEDPROC glBeginQueryIndexed = nullptr; +LL_THREAD_LOCAL_GL PFNGLENDQUERYINDEXEDPROC glEndQueryIndexed = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYINDEXEDIVPROC glGetQueryIndexediv = nullptr; // GL_VERSION_4_1 -PFNGLRELEASESHADERCOMPILERPROC glReleaseShaderCompiler = nullptr; -PFNGLSHADERBINARYPROC glShaderBinary = nullptr; -PFNGLGETSHADERPRECISIONFORMATPROC glGetShaderPrecisionFormat = nullptr; -PFNGLDEPTHRANGEFPROC glDepthRangef = nullptr; -PFNGLCLEARDEPTHFPROC glClearDepthf = nullptr; -PFNGLGETPROGRAMBINARYPROC glGetProgramBinary = nullptr; -PFNGLPROGRAMBINARYPROC glProgramBinary = nullptr; -PFNGLPROGRAMPARAMETERIPROC glProgramParameteri = nullptr; -PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages = nullptr; -PFNGLACTIVESHADERPROGRAMPROC glActiveShaderProgram = nullptr; -PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv = nullptr; -PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline = nullptr; -PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines = nullptr; -PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines = nullptr; -PFNGLISPROGRAMPIPELINEPROC glIsProgramPipeline = nullptr; -PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv = nullptr; -PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i = nullptr; -PFNGLPROGRAMUNIFORM1IVPROC glProgramUniform1iv = nullptr; -PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f = nullptr; -PFNGLPROGRAMUNIFORM1FVPROC glProgramUniform1fv = nullptr; -PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d = nullptr; -PFNGLPROGRAMUNIFORM1DVPROC glProgramUniform1dv = nullptr; -PFNGLPROGRAMUNIFORM1UIPROC glProgramUniform1ui = nullptr; -PFNGLPROGRAMUNIFORM1UIVPROC glProgramUniform1uiv = nullptr; -PFNGLPROGRAMUNIFORM2IPROC glProgramUniform2i = nullptr; -PFNGLPROGRAMUNIFORM2IVPROC glProgramUniform2iv = nullptr; -PFNGLPROGRAMUNIFORM2FPROC glProgramUniform2f = nullptr; -PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv = nullptr; -PFNGLPROGRAMUNIFORM2DPROC glProgramUniform2d = nullptr; -PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv = nullptr; -PFNGLPROGRAMUNIFORM2UIPROC glProgramUniform2ui = nullptr; -PFNGLPROGRAMUNIFORM2UIVPROC glProgramUniform2uiv = nullptr; -PFNGLPROGRAMUNIFORM3IPROC glProgramUniform3i = nullptr; -PFNGLPROGRAMUNIFORM3IVPROC glProgramUniform3iv = nullptr; -PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f = nullptr; -PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv = nullptr; -PFNGLPROGRAMUNIFORM3DPROC glProgramUniform3d = nullptr; -PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv = nullptr; -PFNGLPROGRAMUNIFORM3UIPROC glProgramUniform3ui = nullptr; -PFNGLPROGRAMUNIFORM3UIVPROC glProgramUniform3uiv = nullptr; -PFNGLPROGRAMUNIFORM4IPROC glProgramUniform4i = nullptr; -PFNGLPROGRAMUNIFORM4IVPROC glProgramUniform4iv = nullptr; -PFNGLPROGRAMUNIFORM4FPROC glProgramUniform4f = nullptr; -PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv = nullptr; -PFNGLPROGRAMUNIFORM4DPROC glProgramUniform4d = nullptr; -PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv = nullptr; -PFNGLPROGRAMUNIFORM4UIPROC glProgramUniform4ui = nullptr; -PFNGLPROGRAMUNIFORM4UIVPROC glProgramUniform4uiv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2FVPROC glProgramUniformMatrix2fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3FVPROC glProgramUniformMatrix3fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2DVPROC glProgramUniformMatrix2dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3DVPROC glProgramUniformMatrix3dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glProgramUniformMatrix2x3fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glProgramUniformMatrix3x2fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glProgramUniformMatrix2x4fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glProgramUniformMatrix4x2fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glProgramUniformMatrix3x4fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glProgramUniformMatrix4x3fv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glProgramUniformMatrix2x3dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glProgramUniformMatrix3x2dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glProgramUniformMatrix2x4dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glProgramUniformMatrix4x2dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glProgramUniformMatrix3x4dv = nullptr; -PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glProgramUniformMatrix4x3dv = nullptr; -PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline = nullptr; -PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog = nullptr; -PFNGLVERTEXATTRIBL1DPROC glVertexAttribL1d = nullptr; -PFNGLVERTEXATTRIBL2DPROC glVertexAttribL2d = nullptr; -PFNGLVERTEXATTRIBL3DPROC glVertexAttribL3d = nullptr; -PFNGLVERTEXATTRIBL4DPROC glVertexAttribL4d = nullptr; -PFNGLVERTEXATTRIBL1DVPROC glVertexAttribL1dv = nullptr; -PFNGLVERTEXATTRIBL2DVPROC glVertexAttribL2dv = nullptr; -PFNGLVERTEXATTRIBL3DVPROC glVertexAttribL3dv = nullptr; -PFNGLVERTEXATTRIBL4DVPROC glVertexAttribL4dv = nullptr; -PFNGLVERTEXATTRIBLPOINTERPROC glVertexAttribLPointer = nullptr; -PFNGLGETVERTEXATTRIBLDVPROC glGetVertexAttribLdv = nullptr; -PFNGLVIEWPORTARRAYVPROC glViewportArrayv = nullptr; -PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf = nullptr; -PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv = nullptr; -PFNGLSCISSORARRAYVPROC glScissorArrayv = nullptr; -PFNGLSCISSORINDEXEDPROC glScissorIndexed = nullptr; -PFNGLSCISSORINDEXEDVPROC glScissorIndexedv = nullptr; -PFNGLDEPTHRANGEARRAYVPROC glDepthRangeArrayv = nullptr; -PFNGLDEPTHRANGEINDEXEDPROC glDepthRangeIndexed = nullptr; -PFNGLGETFLOATI_VPROC glGetFloati_v = nullptr; -PFNGLGETDOUBLEI_VPROC glGetDoublei_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLRELEASESHADERCOMPILERPROC glReleaseShaderCompiler = nullptr; +LL_THREAD_LOCAL_GL PFNGLSHADERBINARYPROC glShaderBinary = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETSHADERPRECISIONFORMATPROC glGetShaderPrecisionFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEFPROC glDepthRangef = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARDEPTHFPROC glClearDepthf = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMBINARYPROC glGetProgramBinary = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMBINARYPROC glProgramBinary = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMPARAMETERIPROC glProgramParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages = nullptr; +LL_THREAD_LOCAL_GL PFNGLACTIVESHADERPROGRAMPROC glActiveShaderProgram = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline = nullptr; +LL_THREAD_LOCAL_GL PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines = nullptr; +LL_THREAD_LOCAL_GL PFNGLISPROGRAMPIPELINEPROC glIsProgramPipeline = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1IVPROC glProgramUniform1iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1FVPROC glProgramUniform1fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1DVPROC glProgramUniform1dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1UIPROC glProgramUniform1ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1UIVPROC glProgramUniform1uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2IPROC glProgramUniform2i = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2IVPROC glProgramUniform2iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2FPROC glProgramUniform2f = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2DPROC glProgramUniform2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2UIPROC glProgramUniform2ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2UIVPROC glProgramUniform2uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3IPROC glProgramUniform3i = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3IVPROC glProgramUniform3iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3DPROC glProgramUniform3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3UIPROC glProgramUniform3ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3UIVPROC glProgramUniform3uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4IPROC glProgramUniform4i = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4IVPROC glProgramUniform4iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4FPROC glProgramUniform4f = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4DPROC glProgramUniform4d = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4UIPROC glProgramUniform4ui = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4UIVPROC glProgramUniform4uiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glProgramUniformMatrix2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glProgramUniformMatrix3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glProgramUniformMatrix2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glProgramUniformMatrix3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glProgramUniformMatrix2x3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glProgramUniformMatrix3x2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glProgramUniformMatrix2x4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glProgramUniformMatrix4x2fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glProgramUniformMatrix3x4fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glProgramUniformMatrix4x3fv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glProgramUniformMatrix2x3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glProgramUniformMatrix3x2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glProgramUniformMatrix2x4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glProgramUniformMatrix4x2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glProgramUniformMatrix3x4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glProgramUniformMatrix4x3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL1DPROC glVertexAttribL1d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL2DPROC glVertexAttribL2d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL3DPROC glVertexAttribL3d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL4DPROC glVertexAttribL4d = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL1DVPROC glVertexAttribL1dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL2DVPROC glVertexAttribL2dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL3DVPROC glVertexAttribL3dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL4DVPROC glVertexAttribL4dv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBLPOINTERPROC glVertexAttribLPointer = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBLDVPROC glGetVertexAttribLdv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVIEWPORTARRAYVPROC glViewportArrayv = nullptr; +LL_THREAD_LOCAL_GL PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf = nullptr; +LL_THREAD_LOCAL_GL PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSCISSORARRAYVPROC glScissorArrayv = nullptr; +LL_THREAD_LOCAL_GL PFNGLSCISSORINDEXEDPROC glScissorIndexed = nullptr; +LL_THREAD_LOCAL_GL PFNGLSCISSORINDEXEDVPROC glScissorIndexedv = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEARRAYVPROC glDepthRangeArrayv = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEINDEXEDPROC glDepthRangeIndexed = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETFLOATI_VPROC glGetFloati_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETDOUBLEI_VPROC glGetDoublei_v = nullptr; // GL_VERSION_4_2 -PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glDrawArraysInstancedBaseInstance = nullptr; -PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glDrawElementsInstancedBaseInstance = nullptr; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glDrawElementsInstancedBaseVertexBaseInstance = nullptr; -PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ = nullptr; -PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glGetActiveAtomicCounterBufferiv = nullptr; -PFNGLBINDIMAGETEXTUREPROC glBindImageTexture = nullptr; -PFNGLMEMORYBARRIERPROC glMemoryBarrier = nullptr; -PFNGLTEXSTORAGE1DPROC glTexStorage1D = nullptr; -PFNGLTEXSTORAGE2DPROC glTexStorage2D = nullptr; -PFNGLTEXSTORAGE3DPROC glTexStorage3D = nullptr; -PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glDrawTransformFeedbackInstanced = nullptr; -PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glDrawTransformFeedbackStreamInstanced = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glDrawArraysInstancedBaseInstance = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glDrawElementsInstancedBaseInstance = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glDrawElementsInstancedBaseVertexBaseInstance = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glGetActiveAtomicCounterBufferiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDIMAGETEXTUREPROC glBindImageTexture = nullptr; +LL_THREAD_LOCAL_GL PFNGLMEMORYBARRIERPROC glMemoryBarrier = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE1DPROC glTexStorage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE2DPROC glTexStorage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE3DPROC glTexStorage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glDrawTransformFeedbackInstanced = nullptr; +LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glDrawTransformFeedbackStreamInstanced = nullptr; // GL_VERSION_4_3 -PFNGLCLEARBUFFERDATAPROC glClearBufferData = nullptr; -PFNGLCLEARBUFFERSUBDATAPROC glClearBufferSubData = nullptr; -PFNGLDISPATCHCOMPUTEPROC glDispatchCompute = nullptr; -PFNGLDISPATCHCOMPUTEINDIRECTPROC glDispatchComputeIndirect = nullptr; -PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData = nullptr; -PFNGLFRAMEBUFFERPARAMETERIPROC glFramebufferParameteri = nullptr; -PFNGLGETFRAMEBUFFERPARAMETERIVPROC glGetFramebufferParameteriv = nullptr; -PFNGLGETINTERNALFORMATI64VPROC glGetInternalformati64v = nullptr; -PFNGLINVALIDATETEXSUBIMAGEPROC glInvalidateTexSubImage = nullptr; -PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage = nullptr; -PFNGLINVALIDATEBUFFERSUBDATAPROC glInvalidateBufferSubData = nullptr; -PFNGLINVALIDATEBUFFERDATAPROC glInvalidateBufferData = nullptr; -PFNGLINVALIDATEFRAMEBUFFERPROC glInvalidateFramebuffer = nullptr; -PFNGLINVALIDATESUBFRAMEBUFFERPROC glInvalidateSubFramebuffer = nullptr; -PFNGLMULTIDRAWARRAYSINDIRECTPROC glMultiDrawArraysIndirect = nullptr; -PFNGLMULTIDRAWELEMENTSINDIRECTPROC glMultiDrawElementsIndirect = nullptr; -PFNGLGETPROGRAMINTERFACEIVPROC glGetProgramInterfaceiv = nullptr; -PFNGLGETPROGRAMRESOURCEINDEXPROC glGetProgramResourceIndex = nullptr; -PFNGLGETPROGRAMRESOURCENAMEPROC glGetProgramResourceName = nullptr; -PFNGLGETPROGRAMRESOURCEIVPROC glGetProgramResourceiv = nullptr; -PFNGLGETPROGRAMRESOURCELOCATIONPROC glGetProgramResourceLocation = nullptr; -PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glGetProgramResourceLocationIndex = nullptr; -PFNGLSHADERSTORAGEBLOCKBINDINGPROC glShaderStorageBlockBinding = nullptr; -PFNGLTEXBUFFERRANGEPROC glTexBufferRange = nullptr; -PFNGLTEXSTORAGE2DMULTISAMPLEPROC glTexStorage2DMultisample = nullptr; -PFNGLTEXSTORAGE3DMULTISAMPLEPROC glTexStorage3DMultisample = nullptr; -PFNGLTEXTUREVIEWPROC glTextureView = nullptr; -PFNGLBINDVERTEXBUFFERPROC glBindVertexBuffer = nullptr; -PFNGLVERTEXATTRIBFORMATPROC glVertexAttribFormat = nullptr; -PFNGLVERTEXATTRIBIFORMATPROC glVertexAttribIFormat = nullptr; -PFNGLVERTEXATTRIBLFORMATPROC glVertexAttribLFormat = nullptr; -PFNGLVERTEXATTRIBBINDINGPROC glVertexAttribBinding = nullptr; -PFNGLVERTEXBINDINGDIVISORPROC glVertexBindingDivisor = nullptr; -PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl = nullptr; -PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert = nullptr; -PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback = nullptr; -PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog = nullptr; -PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup = nullptr; -PFNGLPOPDEBUGGROUPPROC glPopDebugGroup = nullptr; -PFNGLOBJECTLABELPROC glObjectLabel = nullptr; -PFNGLGETOBJECTLABELPROC glGetObjectLabel = nullptr; -PFNGLOBJECTPTRLABELPROC glObjectPtrLabel = nullptr; -PFNGLGETOBJECTPTRLABELPROC glGetObjectPtrLabel = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERDATAPROC glClearBufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERSUBDATAPROC glClearBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLDISPATCHCOMPUTEPROC glDispatchCompute = nullptr; +LL_THREAD_LOCAL_GL PFNGLDISPATCHCOMPUTEINDIRECTPROC glDispatchComputeIndirect = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERPARAMETERIPROC glFramebufferParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETFRAMEBUFFERPARAMETERIVPROC glGetFramebufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETINTERNALFORMATI64VPROC glGetInternalformati64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATETEXSUBIMAGEPROC glInvalidateTexSubImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATEBUFFERSUBDATAPROC glInvalidateBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATEBUFFERDATAPROC glInvalidateBufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATEFRAMEBUFFERPROC glInvalidateFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATESUBFRAMEBUFFERPROC glInvalidateSubFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSINDIRECTPROC glMultiDrawArraysIndirect = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSINDIRECTPROC glMultiDrawElementsIndirect = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMINTERFACEIVPROC glGetProgramInterfaceiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCEINDEXPROC glGetProgramResourceIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCENAMEPROC glGetProgramResourceName = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCEIVPROC glGetProgramResourceiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCELOCATIONPROC glGetProgramResourceLocation = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glGetProgramResourceLocationIndex = nullptr; +LL_THREAD_LOCAL_GL PFNGLSHADERSTORAGEBLOCKBINDINGPROC glShaderStorageBlockBinding = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXBUFFERRANGEPROC glTexBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE2DMULTISAMPLEPROC glTexStorage2DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE3DMULTISAMPLEPROC glTexStorage3DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREVIEWPROC glTextureView = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDVERTEXBUFFERPROC glBindVertexBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBFORMATPROC glVertexAttribFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBIFORMATPROC glVertexAttribIFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBLFORMATPROC glVertexAttribLFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBBINDINGPROC glVertexAttribBinding = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXBINDINGDIVISORPROC glVertexBindingDivisor = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert = nullptr; +LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog = nullptr; +LL_THREAD_LOCAL_GL PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOPDEBUGGROUPPROC glPopDebugGroup = nullptr; +LL_THREAD_LOCAL_GL PFNGLOBJECTLABELPROC glObjectLabel = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETOBJECTLABELPROC glGetObjectLabel = nullptr; +LL_THREAD_LOCAL_GL PFNGLOBJECTPTRLABELPROC glObjectPtrLabel = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETOBJECTPTRLABELPROC glGetObjectPtrLabel = nullptr; // GL_VERSION_4_4 -PFNGLBUFFERSTORAGEPROC glBufferStorage = nullptr; -PFNGLCLEARTEXIMAGEPROC glClearTexImage = nullptr; -PFNGLCLEARTEXSUBIMAGEPROC glClearTexSubImage = nullptr; -PFNGLBINDBUFFERSBASEPROC glBindBuffersBase = nullptr; -PFNGLBINDBUFFERSRANGEPROC glBindBuffersRange = nullptr; -PFNGLBINDTEXTURESPROC glBindTextures = nullptr; -PFNGLBINDSAMPLERSPROC glBindSamplers = nullptr; -PFNGLBINDIMAGETEXTURESPROC glBindImageTextures = nullptr; -PFNGLBINDVERTEXBUFFERSPROC glBindVertexBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLBUFFERSTORAGEPROC glBufferStorage = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARTEXIMAGEPROC glClearTexImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARTEXSUBIMAGEPROC glClearTexSubImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDBUFFERSBASEPROC glBindBuffersBase = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDBUFFERSRANGEPROC glBindBuffersRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDTEXTURESPROC glBindTextures = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDSAMPLERSPROC glBindSamplers = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDIMAGETEXTURESPROC glBindImageTextures = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDVERTEXBUFFERSPROC glBindVertexBuffers = nullptr; // GL_VERSION_4_5 -PFNGLCLIPCONTROLPROC glClipControl = nullptr; -PFNGLCREATETRANSFORMFEEDBACKSPROC glCreateTransformFeedbacks = nullptr; -PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glTransformFeedbackBufferBase = nullptr; -PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glTransformFeedbackBufferRange = nullptr; -PFNGLGETTRANSFORMFEEDBACKIVPROC glGetTransformFeedbackiv = nullptr; -PFNGLGETTRANSFORMFEEDBACKI_VPROC glGetTransformFeedbacki_v = nullptr; -PFNGLGETTRANSFORMFEEDBACKI64_VPROC glGetTransformFeedbacki64_v = nullptr; -PFNGLCREATEBUFFERSPROC glCreateBuffers = nullptr; -PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage = nullptr; -PFNGLNAMEDBUFFERDATAPROC glNamedBufferData = nullptr; -PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData = nullptr; -PFNGLCOPYNAMEDBUFFERSUBDATAPROC glCopyNamedBufferSubData = nullptr; -PFNGLCLEARNAMEDBUFFERDATAPROC glClearNamedBufferData = nullptr; -PFNGLCLEARNAMEDBUFFERSUBDATAPROC glClearNamedBufferSubData = nullptr; -PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer = nullptr; -PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange = nullptr; -PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer = nullptr; -PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange = nullptr; -PFNGLGETNAMEDBUFFERPARAMETERIVPROC glGetNamedBufferParameteriv = nullptr; -PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glGetNamedBufferParameteri64v = nullptr; -PFNGLGETNAMEDBUFFERPOINTERVPROC glGetNamedBufferPointerv = nullptr; -PFNGLGETNAMEDBUFFERSUBDATAPROC glGetNamedBufferSubData = nullptr; -PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers = nullptr; -PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glNamedFramebufferRenderbuffer = nullptr; -PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glNamedFramebufferParameteri = nullptr; -PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture = nullptr; -PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glNamedFramebufferTextureLayer = nullptr; -PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glNamedFramebufferDrawBuffer = nullptr; -PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers = nullptr; -PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer = nullptr; -PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glInvalidateNamedFramebufferData = nullptr; -PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glInvalidateNamedFramebufferSubData = nullptr; -PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv = nullptr; -PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv = nullptr; -PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv = nullptr; -PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glClearNamedFramebufferfi = nullptr; -PFNGLBLITNAMEDFRAMEBUFFERPROC glBlitNamedFramebuffer = nullptr; -PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus = nullptr; -PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glGetNamedFramebufferParameteriv = nullptr; -PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetNamedFramebufferAttachmentParameteriv = nullptr; -PFNGLCREATERENDERBUFFERSPROC glCreateRenderbuffers = nullptr; -PFNGLNAMEDRENDERBUFFERSTORAGEPROC glNamedRenderbufferStorage = nullptr; -PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glNamedRenderbufferStorageMultisample = nullptr; -PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glGetNamedRenderbufferParameteriv = nullptr; -PFNGLCREATETEXTURESPROC glCreateTextures = nullptr; -PFNGLTEXTUREBUFFERPROC glTextureBuffer = nullptr; -PFNGLTEXTUREBUFFERRANGEPROC glTextureBufferRange = nullptr; -PFNGLTEXTURESTORAGE1DPROC glTextureStorage1D = nullptr; -PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D = nullptr; -PFNGLTEXTURESTORAGE3DPROC glTextureStorage3D = nullptr; -PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glTextureStorage2DMultisample = nullptr; -PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glTextureStorage3DMultisample = nullptr; -PFNGLTEXTURESUBIMAGE1DPROC glTextureSubImage1D = nullptr; -PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D = nullptr; -PFNGLTEXTURESUBIMAGE3DPROC glTextureSubImage3D = nullptr; -PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glCompressedTextureSubImage1D = nullptr; -PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glCompressedTextureSubImage2D = nullptr; -PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glCompressedTextureSubImage3D = nullptr; -PFNGLCOPYTEXTURESUBIMAGE1DPROC glCopyTextureSubImage1D = nullptr; -PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D = nullptr; -PFNGLCOPYTEXTURESUBIMAGE3DPROC glCopyTextureSubImage3D = nullptr; -PFNGLTEXTUREPARAMETERFPROC glTextureParameterf = nullptr; -PFNGLTEXTUREPARAMETERFVPROC glTextureParameterfv = nullptr; -PFNGLTEXTUREPARAMETERIPROC glTextureParameteri = nullptr; -PFNGLTEXTUREPARAMETERIIVPROC glTextureParameterIiv = nullptr; -PFNGLTEXTUREPARAMETERIUIVPROC glTextureParameterIuiv = nullptr; -PFNGLTEXTUREPARAMETERIVPROC glTextureParameteriv = nullptr; -PFNGLGENERATETEXTUREMIPMAPPROC glGenerateTextureMipmap = nullptr; -PFNGLBINDTEXTUREUNITPROC glBindTextureUnit = nullptr; -PFNGLGETTEXTUREIMAGEPROC glGetTextureImage = nullptr; -PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glGetCompressedTextureImage = nullptr; -PFNGLGETTEXTURELEVELPARAMETERFVPROC glGetTextureLevelParameterfv = nullptr; -PFNGLGETTEXTURELEVELPARAMETERIVPROC glGetTextureLevelParameteriv = nullptr; -PFNGLGETTEXTUREPARAMETERFVPROC glGetTextureParameterfv = nullptr; -PFNGLGETTEXTUREPARAMETERIIVPROC glGetTextureParameterIiv = nullptr; -PFNGLGETTEXTUREPARAMETERIUIVPROC glGetTextureParameterIuiv = nullptr; -PFNGLGETTEXTUREPARAMETERIVPROC glGetTextureParameteriv = nullptr; -PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays = nullptr; -PFNGLDISABLEVERTEXARRAYATTRIBPROC glDisableVertexArrayAttrib = nullptr; -PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib = nullptr; -PFNGLVERTEXARRAYELEMENTBUFFERPROC glVertexArrayElementBuffer = nullptr; -PFNGLVERTEXARRAYVERTEXBUFFERPROC glVertexArrayVertexBuffer = nullptr; -PFNGLVERTEXARRAYVERTEXBUFFERSPROC glVertexArrayVertexBuffers = nullptr; -PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding = nullptr; -PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat = nullptr; -PFNGLVERTEXARRAYATTRIBIFORMATPROC glVertexArrayAttribIFormat = nullptr; -PFNGLVERTEXARRAYATTRIBLFORMATPROC glVertexArrayAttribLFormat = nullptr; -PFNGLVERTEXARRAYBINDINGDIVISORPROC glVertexArrayBindingDivisor = nullptr; -PFNGLGETVERTEXARRAYIVPROC glGetVertexArrayiv = nullptr; -PFNGLGETVERTEXARRAYINDEXEDIVPROC glGetVertexArrayIndexediv = nullptr; -PFNGLGETVERTEXARRAYINDEXED64IVPROC glGetVertexArrayIndexed64iv = nullptr; -PFNGLCREATESAMPLERSPROC glCreateSamplers = nullptr; -PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines = nullptr; -PFNGLCREATEQUERIESPROC glCreateQueries = nullptr; -PFNGLGETQUERYBUFFEROBJECTI64VPROC glGetQueryBufferObjecti64v = nullptr; -PFNGLGETQUERYBUFFEROBJECTIVPROC glGetQueryBufferObjectiv = nullptr; -PFNGLGETQUERYBUFFEROBJECTUI64VPROC glGetQueryBufferObjectui64v = nullptr; -PFNGLGETQUERYBUFFEROBJECTUIVPROC glGetQueryBufferObjectuiv = nullptr; -PFNGLMEMORYBARRIERBYREGIONPROC glMemoryBarrierByRegion = nullptr; -PFNGLGETTEXTURESUBIMAGEPROC glGetTextureSubImage = nullptr; -PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glGetCompressedTextureSubImage = nullptr; -PFNGLGETGRAPHICSRESETSTATUSPROC glGetGraphicsResetStatus = nullptr; -PFNGLGETNCOMPRESSEDTEXIMAGEPROC glGetnCompressedTexImage = nullptr; -PFNGLGETNTEXIMAGEPROC glGetnTexImage = nullptr; -PFNGLGETNUNIFORMDVPROC glGetnUniformdv = nullptr; -PFNGLGETNUNIFORMFVPROC glGetnUniformfv = nullptr; -PFNGLGETNUNIFORMIVPROC glGetnUniformiv = nullptr; -PFNGLGETNUNIFORMUIVPROC glGetnUniformuiv = nullptr; -PFNGLREADNPIXELSPROC glReadnPixels = nullptr; -PFNGLGETNMAPDVPROC glGetnMapdv = nullptr; -PFNGLGETNMAPFVPROC glGetnMapfv = nullptr; -PFNGLGETNMAPIVPROC glGetnMapiv = nullptr; -PFNGLGETNPIXELMAPFVPROC glGetnPixelMapfv = nullptr; -PFNGLGETNPIXELMAPUIVPROC glGetnPixelMapuiv = nullptr; -PFNGLGETNPIXELMAPUSVPROC glGetnPixelMapusv = nullptr; -PFNGLGETNPOLYGONSTIPPLEPROC glGetnPolygonStipple = nullptr; -PFNGLGETNCOLORTABLEPROC glGetnColorTable = nullptr; -PFNGLGETNCONVOLUTIONFILTERPROC glGetnConvolutionFilter = nullptr; -PFNGLGETNSEPARABLEFILTERPROC glGetnSeparableFilter = nullptr; -PFNGLGETNHISTOGRAMPROC glGetnHistogram = nullptr; -PFNGLGETNMINMAXPROC glGetnMinmax = nullptr; -PFNGLTEXTUREBARRIERPROC glTextureBarrier = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLIPCONTROLPROC glClipControl = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATETRANSFORMFEEDBACKSPROC glCreateTransformFeedbacks = nullptr; +LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glTransformFeedbackBufferBase = nullptr; +LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glTransformFeedbackBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKIVPROC glGetTransformFeedbackiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKI_VPROC glGetTransformFeedbacki_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKI64_VPROC glGetTransformFeedbacki64_v = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEBUFFERSPROC glCreateBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERDATAPROC glNamedBufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYNAMEDBUFFERSUBDATAPROC glCopyNamedBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDBUFFERDATAPROC glClearNamedBufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDBUFFERSUBDATAPROC glClearNamedBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPARAMETERIVPROC glGetNamedBufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glGetNamedBufferParameteri64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPOINTERVPROC glGetNamedBufferPointerv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERSUBDATAPROC glGetNamedBufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glNamedFramebufferRenderbuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glNamedFramebufferParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glNamedFramebufferTextureLayer = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glNamedFramebufferDrawBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glInvalidateNamedFramebufferData = nullptr; +LL_THREAD_LOCAL_GL PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glInvalidateNamedFramebufferSubData = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glClearNamedFramebufferfi = nullptr; +LL_THREAD_LOCAL_GL PFNGLBLITNAMEDFRAMEBUFFERPROC glBlitNamedFramebuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glGetNamedFramebufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetNamedFramebufferAttachmentParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATERENDERBUFFERSPROC glCreateRenderbuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDRENDERBUFFERSTORAGEPROC glNamedRenderbufferStorage = nullptr; +LL_THREAD_LOCAL_GL PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glNamedRenderbufferStorageMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glGetNamedRenderbufferParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATETEXTURESPROC glCreateTextures = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREBUFFERPROC glTextureBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREBUFFERRANGEPROC glTextureBufferRange = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE1DPROC glTextureStorage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE3DPROC glTextureStorage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glTextureStorage2DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glTextureStorage3DMultisample = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE1DPROC glTextureSubImage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE3DPROC glTextureSubImage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glCompressedTextureSubImage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glCompressedTextureSubImage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glCompressedTextureSubImage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE1DPROC glCopyTextureSubImage1D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D = nullptr; +LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE3DPROC glCopyTextureSubImage3D = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERFPROC glTextureParameterf = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERFVPROC glTextureParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIPROC glTextureParameteri = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIIVPROC glTextureParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIUIVPROC glTextureParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIVPROC glTextureParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGENERATETEXTUREMIPMAPPROC glGenerateTextureMipmap = nullptr; +LL_THREAD_LOCAL_GL PFNGLBINDTEXTUREUNITPROC glBindTextureUnit = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTUREIMAGEPROC glGetTextureImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glGetCompressedTextureImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTURELEVELPARAMETERFVPROC glGetTextureLevelParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTURELEVELPARAMETERIVPROC glGetTextureLevelParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERFVPROC glGetTextureParameterfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIIVPROC glGetTextureParameterIiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIUIVPROC glGetTextureParameterIuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIVPROC glGetTextureParameteriv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays = nullptr; +LL_THREAD_LOCAL_GL PFNGLDISABLEVERTEXARRAYATTRIBPROC glDisableVertexArrayAttrib = nullptr; +LL_THREAD_LOCAL_GL PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYELEMENTBUFFERPROC glVertexArrayElementBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYVERTEXBUFFERPROC glVertexArrayVertexBuffer = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYVERTEXBUFFERSPROC glVertexArrayVertexBuffers = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBIFORMATPROC glVertexArrayAttribIFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBLFORMATPROC glVertexArrayAttribLFormat = nullptr; +LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYBINDINGDIVISORPROC glVertexArrayBindingDivisor = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYIVPROC glGetVertexArrayiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYINDEXEDIVPROC glGetVertexArrayIndexediv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYINDEXED64IVPROC glGetVertexArrayIndexed64iv = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATESAMPLERSPROC glCreateSamplers = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines = nullptr; +LL_THREAD_LOCAL_GL PFNGLCREATEQUERIESPROC glCreateQueries = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTI64VPROC glGetQueryBufferObjecti64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTIVPROC glGetQueryBufferObjectiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTUI64VPROC glGetQueryBufferObjectui64v = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTUIVPROC glGetQueryBufferObjectuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLMEMORYBARRIERBYREGIONPROC glMemoryBarrierByRegion = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETTEXTURESUBIMAGEPROC glGetTextureSubImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glGetCompressedTextureSubImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETGRAPHICSRESETSTATUSPROC glGetGraphicsResetStatus = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNCOMPRESSEDTEXIMAGEPROC glGetnCompressedTexImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNTEXIMAGEPROC glGetnTexImage = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMDVPROC glGetnUniformdv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMFVPROC glGetnUniformfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMIVPROC glGetnUniformiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMUIVPROC glGetnUniformuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLREADNPIXELSPROC glReadnPixels = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNMAPDVPROC glGetnMapdv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNMAPFVPROC glGetnMapfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNMAPIVPROC glGetnMapiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPFVPROC glGetnPixelMapfv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPUIVPROC glGetnPixelMapuiv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPUSVPROC glGetnPixelMapusv = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNPOLYGONSTIPPLEPROC glGetnPolygonStipple = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNCOLORTABLEPROC glGetnColorTable = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNCONVOLUTIONFILTERPROC glGetnConvolutionFilter = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNSEPARABLEFILTERPROC glGetnSeparableFilter = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNHISTOGRAMPROC glGetnHistogram = nullptr; +LL_THREAD_LOCAL_GL PFNGLGETNMINMAXPROC glGetnMinmax = nullptr; +LL_THREAD_LOCAL_GL PFNGLTEXTUREBARRIERPROC glTextureBarrier = nullptr; // GL_VERSION_4_6 -PFNGLSPECIALIZESHADERPROC glSpecializeShader = nullptr; -PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glMultiDrawArraysIndirectCount = nullptr; -PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glMultiDrawElementsIndirectCount = nullptr; -PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp = nullptr; +LL_THREAD_LOCAL_GL PFNGLSPECIALIZESHADERPROC glSpecializeShader = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glMultiDrawArraysIndirectCount = nullptr; +LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glMultiDrawElementsIndirectCount = nullptr; +LL_THREAD_LOCAL_GL PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp = nullptr; #endif @@ -2458,6 +2458,7 @@ void LLGLState::dumpStates() void LLGLState::checkStates(GLboolean writeAlpha) { +#if 0 if (!gDebugGL) { return; @@ -2490,6 +2491,7 @@ void LLGLState::checkStates(GLboolean writeAlpha) LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; } } +#endif } /////////////////////////////////////////////////////////////////////// diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 921adc0f8c2..7599f9d760d 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -72,761 +72,763 @@ #include "GL/glext.h" #include "GL/glh_extensions.h" +#define LL_THREAD_LOCAL_GL // thread_local // <-- uncomment to trigger a crash whenever calling a GL function from a non-GL thread + // WGL_AMD_gpu_association -extern PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD; -extern PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD; -extern PFNWGLGETCONTEXTGPUIDAMDPROC wglGetContextGPUIDAMD; -extern PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC wglCreateAssociatedContextAMD; -extern PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC wglCreateAssociatedContextAttribsAMD; -extern PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC wglDeleteAssociatedContextAMD; -extern PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC wglMakeAssociatedContextCurrentAMD; -extern PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC wglGetCurrentAssociatedContextAMD; -extern PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD; +extern LL_THREAD_LOCAL_GL PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD; +extern LL_THREAD_LOCAL_GL PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD; +extern LL_THREAD_LOCAL_GL PFNWGLGETCONTEXTGPUIDAMDPROC wglGetContextGPUIDAMD; +extern LL_THREAD_LOCAL_GL PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC wglCreateAssociatedContextAMD; +extern LL_THREAD_LOCAL_GL PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC wglCreateAssociatedContextAttribsAMD; +extern LL_THREAD_LOCAL_GL PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC wglDeleteAssociatedContextAMD; +extern LL_THREAD_LOCAL_GL PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC wglMakeAssociatedContextCurrentAMD; +extern LL_THREAD_LOCAL_GL PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC wglGetCurrentAssociatedContextAMD; +extern LL_THREAD_LOCAL_GL PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD; // WGL_EXT_swap_control -extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; -extern PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; +extern LL_THREAD_LOCAL_GL PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +extern LL_THREAD_LOCAL_GL PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; // WGL_ARB_create_context -extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; +extern LL_THREAD_LOCAL_GL PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; // GL_VERSION_1_3 -extern PFNGLACTIVETEXTUREPROC glActiveTexture; -extern PFNGLSAMPLECOVERAGEPROC glSampleCoverage; -extern PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D; -extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; -extern PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D; -extern PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D; -extern PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D; -extern PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D; -extern PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage; -extern PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture; -extern PFNGLMULTITEXCOORD1DPROC glMultiTexCoord1d; -extern PFNGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv; -extern PFNGLMULTITEXCOORD1FPROC glMultiTexCoord1f; -extern PFNGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv; -extern PFNGLMULTITEXCOORD1IPROC glMultiTexCoord1i; -extern PFNGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv; -extern PFNGLMULTITEXCOORD1SPROC glMultiTexCoord1s; -extern PFNGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv; -extern PFNGLMULTITEXCOORD2DPROC glMultiTexCoord2d; -extern PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv; -extern PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f; -extern PFNGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv; -extern PFNGLMULTITEXCOORD2IPROC glMultiTexCoord2i; -extern PFNGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv; -extern PFNGLMULTITEXCOORD2SPROC glMultiTexCoord2s; -extern PFNGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv; -extern PFNGLMULTITEXCOORD3DPROC glMultiTexCoord3d; -extern PFNGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv; -extern PFNGLMULTITEXCOORD3FPROC glMultiTexCoord3f; -extern PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv; -extern PFNGLMULTITEXCOORD3IPROC glMultiTexCoord3i; -extern PFNGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv; -extern PFNGLMULTITEXCOORD3SPROC glMultiTexCoord3s; -extern PFNGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv; -extern PFNGLMULTITEXCOORD4DPROC glMultiTexCoord4d; -extern PFNGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv; -extern PFNGLMULTITEXCOORD4FPROC glMultiTexCoord4f; -extern PFNGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv; -extern PFNGLMULTITEXCOORD4IPROC glMultiTexCoord4i; -extern PFNGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv; -extern PFNGLMULTITEXCOORD4SPROC glMultiTexCoord4s; -extern PFNGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv; -extern PFNGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf; -extern PFNGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd; -extern PFNGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf; -extern PFNGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd; +extern LL_THREAD_LOCAL_GL PFNGLACTIVETEXTUREPROC glActiveTexture; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLECOVERAGEPROC glSampleCoverage; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D; +extern LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage; +extern LL_THREAD_LOCAL_GL PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1DPROC glMultiTexCoord1d; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1FPROC glMultiTexCoord1f; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1IPROC glMultiTexCoord1i; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1SPROC glMultiTexCoord1s; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2DPROC glMultiTexCoord2d; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2IPROC glMultiTexCoord2i; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2SPROC glMultiTexCoord2s; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3DPROC glMultiTexCoord3d; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3FPROC glMultiTexCoord3f; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3IPROC glMultiTexCoord3i; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3SPROC glMultiTexCoord3s; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4DPROC glMultiTexCoord4d; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4FPROC glMultiTexCoord4f; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4IPROC glMultiTexCoord4i; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4SPROC glMultiTexCoord4s; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv; +extern LL_THREAD_LOCAL_GL PFNGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf; +extern LL_THREAD_LOCAL_GL PFNGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd; +extern LL_THREAD_LOCAL_GL PFNGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf; +extern LL_THREAD_LOCAL_GL PFNGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd; // GL_VERSION_1_4 -extern PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate; -extern PFNGLMULTIDRAWARRAYSPROC glMultiDrawArrays; -extern PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements; -extern PFNGLPOINTPARAMETERFPROC glPointParameterf; -extern PFNGLPOINTPARAMETERFVPROC glPointParameterfv; -extern PFNGLPOINTPARAMETERIPROC glPointParameteri; -extern PFNGLPOINTPARAMETERIVPROC glPointParameteriv; -extern PFNGLFOGCOORDFPROC glFogCoordf; -extern PFNGLFOGCOORDFVPROC glFogCoordfv; -extern PFNGLFOGCOORDDPROC glFogCoordd; -extern PFNGLFOGCOORDDVPROC glFogCoorddv; -extern PFNGLFOGCOORDPOINTERPROC glFogCoordPointer; -extern PFNGLSECONDARYCOLOR3BPROC glSecondaryColor3b; -extern PFNGLSECONDARYCOLOR3BVPROC glSecondaryColor3bv; -extern PFNGLSECONDARYCOLOR3DPROC glSecondaryColor3d; -extern PFNGLSECONDARYCOLOR3DVPROC glSecondaryColor3dv; -extern PFNGLSECONDARYCOLOR3FPROC glSecondaryColor3f; -extern PFNGLSECONDARYCOLOR3FVPROC glSecondaryColor3fv; -extern PFNGLSECONDARYCOLOR3IPROC glSecondaryColor3i; -extern PFNGLSECONDARYCOLOR3IVPROC glSecondaryColor3iv; -extern PFNGLSECONDARYCOLOR3SPROC glSecondaryColor3s; -extern PFNGLSECONDARYCOLOR3SVPROC glSecondaryColor3sv; -extern PFNGLSECONDARYCOLOR3UBPROC glSecondaryColor3ub; -extern PFNGLSECONDARYCOLOR3UBVPROC glSecondaryColor3ubv; -extern PFNGLSECONDARYCOLOR3UIPROC glSecondaryColor3ui; -extern PFNGLSECONDARYCOLOR3UIVPROC glSecondaryColor3uiv; -extern PFNGLSECONDARYCOLOR3USPROC glSecondaryColor3us; -extern PFNGLSECONDARYCOLOR3USVPROC glSecondaryColor3usv; -extern PFNGLSECONDARYCOLORPOINTERPROC glSecondaryColorPointer; -extern PFNGLWINDOWPOS2DPROC glWindowPos2d; -extern PFNGLWINDOWPOS2DVPROC glWindowPos2dv; -extern PFNGLWINDOWPOS2FPROC glWindowPos2f; -extern PFNGLWINDOWPOS2FVPROC glWindowPos2fv; -extern PFNGLWINDOWPOS2IPROC glWindowPos2i; -extern PFNGLWINDOWPOS2IVPROC glWindowPos2iv; -extern PFNGLWINDOWPOS2SPROC glWindowPos2s; -extern PFNGLWINDOWPOS2SVPROC glWindowPos2sv; -extern PFNGLWINDOWPOS3DPROC glWindowPos3d; -extern PFNGLWINDOWPOS3DVPROC glWindowPos3dv; -extern PFNGLWINDOWPOS3FPROC glWindowPos3f; -extern PFNGLWINDOWPOS3FVPROC glWindowPos3fv; -extern PFNGLWINDOWPOS3IPROC glWindowPos3i; -extern PFNGLWINDOWPOS3IVPROC glWindowPos3iv; -extern PFNGLWINDOWPOS3SPROC glWindowPos3s; -extern PFNGLWINDOWPOS3SVPROC glWindowPos3sv; +extern LL_THREAD_LOCAL_GL PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSPROC glMultiDrawArrays; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements; +extern LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERFPROC glPointParameterf; +extern LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERFVPROC glPointParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERIPROC glPointParameteri; +extern LL_THREAD_LOCAL_GL PFNGLPOINTPARAMETERIVPROC glPointParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLFOGCOORDFPROC glFogCoordf; +extern LL_THREAD_LOCAL_GL PFNGLFOGCOORDFVPROC glFogCoordfv; +extern LL_THREAD_LOCAL_GL PFNGLFOGCOORDDPROC glFogCoordd; +extern LL_THREAD_LOCAL_GL PFNGLFOGCOORDDVPROC glFogCoorddv; +extern LL_THREAD_LOCAL_GL PFNGLFOGCOORDPOINTERPROC glFogCoordPointer; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3BPROC glSecondaryColor3b; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3BVPROC glSecondaryColor3bv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3DPROC glSecondaryColor3d; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3DVPROC glSecondaryColor3dv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3FPROC glSecondaryColor3f; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3FVPROC glSecondaryColor3fv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3IPROC glSecondaryColor3i; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3IVPROC glSecondaryColor3iv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3SPROC glSecondaryColor3s; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3SVPROC glSecondaryColor3sv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UBPROC glSecondaryColor3ub; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UBVPROC glSecondaryColor3ubv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UIPROC glSecondaryColor3ui; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3UIVPROC glSecondaryColor3uiv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3USPROC glSecondaryColor3us; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLOR3USVPROC glSecondaryColor3usv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORPOINTERPROC glSecondaryColorPointer; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2DPROC glWindowPos2d; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2DVPROC glWindowPos2dv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2FPROC glWindowPos2f; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2FVPROC glWindowPos2fv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2IPROC glWindowPos2i; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2IVPROC glWindowPos2iv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2SPROC glWindowPos2s; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS2SVPROC glWindowPos2sv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3DPROC glWindowPos3d; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3DVPROC glWindowPos3dv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3FPROC glWindowPos3f; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3FVPROC glWindowPos3fv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3IPROC glWindowPos3i; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3IVPROC glWindowPos3iv; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3SPROC glWindowPos3s; +extern LL_THREAD_LOCAL_GL PFNGLWINDOWPOS3SVPROC glWindowPos3sv; // GL_VERSION_1_5 -extern PFNGLGENQUERIESPROC glGenQueries; -extern PFNGLDELETEQUERIESPROC glDeleteQueries; -extern PFNGLISQUERYPROC glIsQuery; -extern PFNGLBEGINQUERYPROC glBeginQuery; -extern PFNGLENDQUERYPROC glEndQuery; -extern PFNGLGETQUERYIVPROC glGetQueryiv; -extern PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv; -extern PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv; -extern PFNGLBINDBUFFERPROC glBindBuffer; -extern PFNGLDELETEBUFFERSPROC glDeleteBuffers; -extern PFNGLGENBUFFERSPROC glGenBuffers; -extern PFNGLISBUFFERPROC glIsBuffer; -extern PFNGLBUFFERDATAPROC glBufferData; -extern PFNGLBUFFERSUBDATAPROC glBufferSubData; -extern PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData; -extern PFNGLMAPBUFFERPROC glMapBuffer; -extern PFNGLUNMAPBUFFERPROC glUnmapBuffer; -extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; -extern PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv; +extern LL_THREAD_LOCAL_GL PFNGLGENQUERIESPROC glGenQueries; +extern LL_THREAD_LOCAL_GL PFNGLDELETEQUERIESPROC glDeleteQueries; +extern LL_THREAD_LOCAL_GL PFNGLISQUERYPROC glIsQuery; +extern LL_THREAD_LOCAL_GL PFNGLBEGINQUERYPROC glBeginQuery; +extern LL_THREAD_LOCAL_GL PFNGLENDQUERYPROC glEndQuery; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYIVPROC glGetQueryiv; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv; +extern LL_THREAD_LOCAL_GL PFNGLBINDBUFFERPROC glBindBuffer; +extern LL_THREAD_LOCAL_GL PFNGLDELETEBUFFERSPROC glDeleteBuffers; +extern LL_THREAD_LOCAL_GL PFNGLGENBUFFERSPROC glGenBuffers; +extern LL_THREAD_LOCAL_GL PFNGLISBUFFERPROC glIsBuffer; +extern LL_THREAD_LOCAL_GL PFNGLBUFFERDATAPROC glBufferData; +extern LL_THREAD_LOCAL_GL PFNGLBUFFERSUBDATAPROC glBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLMAPBUFFERPROC glMapBuffer; +extern LL_THREAD_LOCAL_GL PFNGLUNMAPBUFFERPROC glUnmapBuffer; +extern LL_THREAD_LOCAL_GL PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv; // GL_VERSION_2_0 -extern PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate; -extern PFNGLDRAWBUFFERSPROC glDrawBuffers; -extern PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate; -extern PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate; -extern PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate; -extern PFNGLATTACHSHADERPROC glAttachShader; -extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; -extern PFNGLCOMPILESHADERPROC glCompileShader; -extern PFNGLCREATEPROGRAMPROC glCreateProgram; -extern PFNGLCREATESHADERPROC glCreateShader; -extern PFNGLDELETEPROGRAMPROC glDeleteProgram; -extern PFNGLDELETESHADERPROC glDeleteShader; -extern PFNGLDETACHSHADERPROC glDetachShader; -extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; -extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; -extern PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib; -extern PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform; -extern PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders; -extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; -extern PFNGLGETPROGRAMIVPROC glGetProgramiv; -extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; -extern PFNGLGETSHADERIVPROC glGetShaderiv; -extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; -extern PFNGLGETSHADERSOURCEPROC glGetShaderSource; -extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; -extern PFNGLGETUNIFORMFVPROC glGetUniformfv; -extern PFNGLGETUNIFORMIVPROC glGetUniformiv; -extern PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv; -extern PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv; -extern PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv; -extern PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv; -extern PFNGLISPROGRAMPROC glIsProgram; -extern PFNGLISSHADERPROC glIsShader; -extern PFNGLLINKPROGRAMPROC glLinkProgram; -extern PFNGLSHADERSOURCEPROC glShaderSource; -extern PFNGLUSEPROGRAMPROC glUseProgram; -extern PFNGLUNIFORM1FPROC glUniform1f; -extern PFNGLUNIFORM2FPROC glUniform2f; -extern PFNGLUNIFORM3FPROC glUniform3f; -extern PFNGLUNIFORM4FPROC glUniform4f; -extern PFNGLUNIFORM1IPROC glUniform1i; -extern PFNGLUNIFORM2IPROC glUniform2i; -extern PFNGLUNIFORM3IPROC glUniform3i; -extern PFNGLUNIFORM4IPROC glUniform4i; -extern PFNGLUNIFORM1FVPROC glUniform1fv; -extern PFNGLUNIFORM2FVPROC glUniform2fv; -extern PFNGLUNIFORM3FVPROC glUniform3fv; -extern PFNGLUNIFORM4FVPROC glUniform4fv; -extern PFNGLUNIFORM1IVPROC glUniform1iv; -extern PFNGLUNIFORM2IVPROC glUniform2iv; -extern PFNGLUNIFORM3IVPROC glUniform3iv; -extern PFNGLUNIFORM4IVPROC glUniform4iv; -extern PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv; -extern PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv; -extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; -extern PFNGLVALIDATEPROGRAMPROC glValidateProgram; -extern PFNGLVERTEXATTRIB1DPROC glVertexAttrib1d; -extern PFNGLVERTEXATTRIB1DVPROC glVertexAttrib1dv; -extern PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f; -extern PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv; -extern PFNGLVERTEXATTRIB1SPROC glVertexAttrib1s; -extern PFNGLVERTEXATTRIB1SVPROC glVertexAttrib1sv; -extern PFNGLVERTEXATTRIB2DPROC glVertexAttrib2d; -extern PFNGLVERTEXATTRIB2DVPROC glVertexAttrib2dv; -extern PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f; -extern PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv; -extern PFNGLVERTEXATTRIB2SPROC glVertexAttrib2s; -extern PFNGLVERTEXATTRIB2SVPROC glVertexAttrib2sv; -extern PFNGLVERTEXATTRIB3DPROC glVertexAttrib3d; -extern PFNGLVERTEXATTRIB3DVPROC glVertexAttrib3dv; -extern PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f; -extern PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv; -extern PFNGLVERTEXATTRIB3SPROC glVertexAttrib3s; -extern PFNGLVERTEXATTRIB3SVPROC glVertexAttrib3sv; -extern PFNGLVERTEXATTRIB4NBVPROC glVertexAttrib4Nbv; -extern PFNGLVERTEXATTRIB4NIVPROC glVertexAttrib4Niv; -extern PFNGLVERTEXATTRIB4NSVPROC glVertexAttrib4Nsv; -extern PFNGLVERTEXATTRIB4NUBPROC glVertexAttrib4Nub; -extern PFNGLVERTEXATTRIB4NUBVPROC glVertexAttrib4Nubv; -extern PFNGLVERTEXATTRIB4NUIVPROC glVertexAttrib4Nuiv; -extern PFNGLVERTEXATTRIB4NUSVPROC glVertexAttrib4Nusv; -extern PFNGLVERTEXATTRIB4BVPROC glVertexAttrib4bv; -extern PFNGLVERTEXATTRIB4DPROC glVertexAttrib4d; -extern PFNGLVERTEXATTRIB4DVPROC glVertexAttrib4dv; -extern PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f; -extern PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv; -extern PFNGLVERTEXATTRIB4IVPROC glVertexAttrib4iv; -extern PFNGLVERTEXATTRIB4SPROC glVertexAttrib4s; -extern PFNGLVERTEXATTRIB4SVPROC glVertexAttrib4sv; -extern PFNGLVERTEXATTRIB4UBVPROC glVertexAttrib4ubv; -extern PFNGLVERTEXATTRIB4UIVPROC glVertexAttrib4uiv; -extern PFNGLVERTEXATTRIB4USVPROC glVertexAttrib4usv; -extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; +extern LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate; +extern LL_THREAD_LOCAL_GL PFNGLDRAWBUFFERSPROC glDrawBuffers; +extern LL_THREAD_LOCAL_GL PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate; +extern LL_THREAD_LOCAL_GL PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate; +extern LL_THREAD_LOCAL_GL PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate; +extern LL_THREAD_LOCAL_GL PFNGLATTACHSHADERPROC glAttachShader; +extern LL_THREAD_LOCAL_GL PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; +extern LL_THREAD_LOCAL_GL PFNGLCOMPILESHADERPROC glCompileShader; +extern LL_THREAD_LOCAL_GL PFNGLCREATEPROGRAMPROC glCreateProgram; +extern LL_THREAD_LOCAL_GL PFNGLCREATESHADERPROC glCreateShader; +extern LL_THREAD_LOCAL_GL PFNGLDELETEPROGRAMPROC glDeleteProgram; +extern LL_THREAD_LOCAL_GL PFNGLDELETESHADERPROC glDeleteShader; +extern LL_THREAD_LOCAL_GL PFNGLDETACHSHADERPROC glDetachShader; +extern LL_THREAD_LOCAL_GL PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; +extern LL_THREAD_LOCAL_GL PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform; +extern LL_THREAD_LOCAL_GL PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders; +extern LL_THREAD_LOCAL_GL PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMIVPROC glGetProgramiv; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; +extern LL_THREAD_LOCAL_GL PFNGLGETSHADERIVPROC glGetShaderiv; +extern LL_THREAD_LOCAL_GL PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; +extern LL_THREAD_LOCAL_GL PFNGLGETSHADERSOURCEPROC glGetShaderSource; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMFVPROC glGetUniformfv; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMIVPROC glGetUniformiv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv; +extern LL_THREAD_LOCAL_GL PFNGLISPROGRAMPROC glIsProgram; +extern LL_THREAD_LOCAL_GL PFNGLISSHADERPROC glIsShader; +extern LL_THREAD_LOCAL_GL PFNGLLINKPROGRAMPROC glLinkProgram; +extern LL_THREAD_LOCAL_GL PFNGLSHADERSOURCEPROC glShaderSource; +extern LL_THREAD_LOCAL_GL PFNGLUSEPROGRAMPROC glUseProgram; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1FPROC glUniform1f; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2FPROC glUniform2f; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3FPROC glUniform3f; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4FPROC glUniform4f; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1IPROC glUniform1i; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2IPROC glUniform2i; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3IPROC glUniform3i; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4IPROC glUniform4i; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1FVPROC glUniform1fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2FVPROC glUniform2fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3FVPROC glUniform3fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4FVPROC glUniform4fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1IVPROC glUniform1iv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2IVPROC glUniform2iv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3IVPROC glUniform3iv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4IVPROC glUniform4iv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; +extern LL_THREAD_LOCAL_GL PFNGLVALIDATEPROGRAMPROC glValidateProgram; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1DPROC glVertexAttrib1d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1DVPROC glVertexAttrib1dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1SPROC glVertexAttrib1s; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB1SVPROC glVertexAttrib1sv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2DPROC glVertexAttrib2d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2DVPROC glVertexAttrib2dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2SPROC glVertexAttrib2s; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB2SVPROC glVertexAttrib2sv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3DPROC glVertexAttrib3d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3DVPROC glVertexAttrib3dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3SPROC glVertexAttrib3s; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB3SVPROC glVertexAttrib3sv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NBVPROC glVertexAttrib4Nbv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NIVPROC glVertexAttrib4Niv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NSVPROC glVertexAttrib4Nsv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUBPROC glVertexAttrib4Nub; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUBVPROC glVertexAttrib4Nubv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUIVPROC glVertexAttrib4Nuiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4NUSVPROC glVertexAttrib4Nusv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4BVPROC glVertexAttrib4bv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4DPROC glVertexAttrib4d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4DVPROC glVertexAttrib4dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4IVPROC glVertexAttrib4iv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4SPROC glVertexAttrib4s; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4SVPROC glVertexAttrib4sv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4UBVPROC glVertexAttrib4ubv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4UIVPROC glVertexAttrib4uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIB4USVPROC glVertexAttrib4usv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; // GL_VERSION_2_1 -extern PFNGLUNIFORMMATRIX2X3FVPROC glUniformMatrix2x3fv; -extern PFNGLUNIFORMMATRIX3X2FVPROC glUniformMatrix3x2fv; -extern PFNGLUNIFORMMATRIX2X4FVPROC glUniformMatrix2x4fv; -extern PFNGLUNIFORMMATRIX4X2FVPROC glUniformMatrix4x2fv; -extern PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; -extern PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X3FVPROC glUniformMatrix2x3fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X2FVPROC glUniformMatrix3x2fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X4FVPROC glUniformMatrix2x4fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X2FVPROC glUniformMatrix4x2fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X3FVPROC glUniformMatrix4x3fv; // GL_VERSION_3_0 -extern PFNGLCOLORMASKIPROC glColorMaski; -extern PFNGLGETBOOLEANI_VPROC glGetBooleani_v; -extern PFNGLGETINTEGERI_VPROC glGetIntegeri_v; -extern PFNGLENABLEIPROC glEnablei; -extern PFNGLDISABLEIPROC glDisablei; -extern PFNGLISENABLEDIPROC glIsEnabledi; -extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; -extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; -extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; -extern PFNGLBINDBUFFERBASEPROC glBindBufferBase; -extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; -extern PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glGetTransformFeedbackVarying; -extern PFNGLCLAMPCOLORPROC glClampColor; -extern PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender; -extern PFNGLENDCONDITIONALRENDERPROC glEndConditionalRender; -extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; -extern PFNGLGETVERTEXATTRIBIIVPROC glGetVertexAttribIiv; -extern PFNGLGETVERTEXATTRIBIUIVPROC glGetVertexAttribIuiv; -extern PFNGLVERTEXATTRIBI1IPROC glVertexAttribI1i; -extern PFNGLVERTEXATTRIBI2IPROC glVertexAttribI2i; -extern PFNGLVERTEXATTRIBI3IPROC glVertexAttribI3i; -extern PFNGLVERTEXATTRIBI4IPROC glVertexAttribI4i; -extern PFNGLVERTEXATTRIBI1UIPROC glVertexAttribI1ui; -extern PFNGLVERTEXATTRIBI2UIPROC glVertexAttribI2ui; -extern PFNGLVERTEXATTRIBI3UIPROC glVertexAttribI3ui; -extern PFNGLVERTEXATTRIBI4UIPROC glVertexAttribI4ui; -extern PFNGLVERTEXATTRIBI1IVPROC glVertexAttribI1iv; -extern PFNGLVERTEXATTRIBI2IVPROC glVertexAttribI2iv; -extern PFNGLVERTEXATTRIBI3IVPROC glVertexAttribI3iv; -extern PFNGLVERTEXATTRIBI4IVPROC glVertexAttribI4iv; -extern PFNGLVERTEXATTRIBI1UIVPROC glVertexAttribI1uiv; -extern PFNGLVERTEXATTRIBI2UIVPROC glVertexAttribI2uiv; -extern PFNGLVERTEXATTRIBI3UIVPROC glVertexAttribI3uiv; -extern PFNGLVERTEXATTRIBI4UIVPROC glVertexAttribI4uiv; -extern PFNGLVERTEXATTRIBI4BVPROC glVertexAttribI4bv; -extern PFNGLVERTEXATTRIBI4SVPROC glVertexAttribI4sv; -extern PFNGLVERTEXATTRIBI4UBVPROC glVertexAttribI4ubv; -extern PFNGLVERTEXATTRIBI4USVPROC glVertexAttribI4usv; -extern PFNGLGETUNIFORMUIVPROC glGetUniformuiv; -extern PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation; -extern PFNGLGETFRAGDATALOCATIONPROC glGetFragDataLocation; -extern PFNGLUNIFORM1UIPROC glUniform1ui; -extern PFNGLUNIFORM2UIPROC glUniform2ui; -extern PFNGLUNIFORM3UIPROC glUniform3ui; -extern PFNGLUNIFORM4UIPROC glUniform4ui; -extern PFNGLUNIFORM1UIVPROC glUniform1uiv; -extern PFNGLUNIFORM2UIVPROC glUniform2uiv; -extern PFNGLUNIFORM3UIVPROC glUniform3uiv; -extern PFNGLUNIFORM4UIVPROC glUniform4uiv; -extern PFNGLTEXPARAMETERIIVPROC glTexParameterIiv; -extern PFNGLTEXPARAMETERIUIVPROC glTexParameterIuiv; -extern PFNGLGETTEXPARAMETERIIVPROC glGetTexParameterIiv; -extern PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv; -extern PFNGLCLEARBUFFERIVPROC glClearBufferiv; -extern PFNGLCLEARBUFFERUIVPROC glClearBufferuiv; -extern PFNGLCLEARBUFFERFVPROC glClearBufferfv; -extern PFNGLCLEARBUFFERFIPROC glClearBufferfi; -extern PFNGLGETSTRINGIPROC glGetStringi; -extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer; -extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; -extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; -extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; -extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; -extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv; -extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer; -extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; -extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; -extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; -extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D; -extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D; -extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv; -extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; -extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; -extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; -extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer; -extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; -extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -extern PFNGLISVERTEXARRAYPROC glIsVertexArray; +extern LL_THREAD_LOCAL_GL PFNGLCOLORMASKIPROC glColorMaski; +extern LL_THREAD_LOCAL_GL PFNGLGETBOOLEANI_VPROC glGetBooleani_v; +extern LL_THREAD_LOCAL_GL PFNGLGETINTEGERI_VPROC glGetIntegeri_v; +extern LL_THREAD_LOCAL_GL PFNGLENABLEIPROC glEnablei; +extern LL_THREAD_LOCAL_GL PFNGLDISABLEIPROC glDisablei; +extern LL_THREAD_LOCAL_GL PFNGLISENABLEDIPROC glIsEnabledi; +extern LL_THREAD_LOCAL_GL PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLBINDBUFFERRANGEPROC glBindBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLBINDBUFFERBASEPROC glBindBufferBase; +extern LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glGetTransformFeedbackVarying; +extern LL_THREAD_LOCAL_GL PFNGLCLAMPCOLORPROC glClampColor; +extern LL_THREAD_LOCAL_GL PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender; +extern LL_THREAD_LOCAL_GL PFNGLENDCONDITIONALRENDERPROC glEndConditionalRender; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIIVPROC glGetVertexAttribIiv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBIUIVPROC glGetVertexAttribIuiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1IPROC glVertexAttribI1i; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2IPROC glVertexAttribI2i; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3IPROC glVertexAttribI3i; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4IPROC glVertexAttribI4i; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1UIPROC glVertexAttribI1ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2UIPROC glVertexAttribI2ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3UIPROC glVertexAttribI3ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UIPROC glVertexAttribI4ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1IVPROC glVertexAttribI1iv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2IVPROC glVertexAttribI2iv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3IVPROC glVertexAttribI3iv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4IVPROC glVertexAttribI4iv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI1UIVPROC glVertexAttribI1uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI2UIVPROC glVertexAttribI2uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI3UIVPROC glVertexAttribI3uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UIVPROC glVertexAttribI4uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4BVPROC glVertexAttribI4bv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4SVPROC glVertexAttribI4sv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4UBVPROC glVertexAttribI4ubv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBI4USVPROC glVertexAttribI4usv; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMUIVPROC glGetUniformuiv; +extern LL_THREAD_LOCAL_GL PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation; +extern LL_THREAD_LOCAL_GL PFNGLGETFRAGDATALOCATIONPROC glGetFragDataLocation; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1UIPROC glUniform1ui; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2UIPROC glUniform2ui; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3UIPROC glUniform3ui; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4UIPROC glUniform4ui; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1UIVPROC glUniform1uiv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2UIVPROC glUniform2uiv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3UIVPROC glUniform3uiv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4UIVPROC glUniform4uiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXPARAMETERIIVPROC glTexParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXPARAMETERIUIVPROC glTexParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXPARAMETERIIVPROC glGetTexParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERIVPROC glClearBufferiv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERUIVPROC glClearBufferuiv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERFVPROC glClearBufferfv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERFIPROC glClearBufferfi; +extern LL_THREAD_LOCAL_GL PFNGLGETSTRINGIPROC glGetStringi; +extern LL_THREAD_LOCAL_GL PFNGLISRENDERBUFFERPROC glIsRenderbuffer; +extern LL_THREAD_LOCAL_GL PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; +extern LL_THREAD_LOCAL_GL PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; +extern LL_THREAD_LOCAL_GL PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; +extern LL_THREAD_LOCAL_GL PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; +extern LL_THREAD_LOCAL_GL PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLISFRAMEBUFFERPROC glIsFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; +extern LL_THREAD_LOCAL_GL PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +extern LL_THREAD_LOCAL_GL PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; +extern LL_THREAD_LOCAL_GL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGENERATEMIPMAPPROC glGenerateMipmap; +extern LL_THREAD_LOCAL_GL PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer; +extern LL_THREAD_LOCAL_GL PFNGLMAPBUFFERRANGEPROC glMapBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern LL_THREAD_LOCAL_GL PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern LL_THREAD_LOCAL_GL PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern LL_THREAD_LOCAL_GL PFNGLISVERTEXARRAYPROC glIsVertexArray; // GL_VERSION_3_1 -extern PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced; -extern PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced; -extern PFNGLTEXBUFFERPROC glTexBuffer; -extern PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex; -extern PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData; -extern PFNGLGETUNIFORMINDICESPROC glGetUniformIndices; -extern PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv; -extern PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName; -extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; -extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv; -extern PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName; -extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; +extern LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced; +extern LL_THREAD_LOCAL_GL PFNGLTEXBUFFERPROC glTexBuffer; +extern LL_THREAD_LOCAL_GL PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex; +extern LL_THREAD_LOCAL_GL PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMINDICESPROC glGetUniformIndices; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; // GL_VERSION_3_2 -extern PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex; -extern PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glDrawRangeElementsBaseVertex; -extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex; -extern PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glMultiDrawElementsBaseVertex; -extern PFNGLPROVOKINGVERTEXPROC glProvokingVertex; -extern PFNGLFENCESYNCPROC glFenceSync; -extern PFNGLISSYNCPROC glIsSync; -extern PFNGLDELETESYNCPROC glDeleteSync; -extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; -extern PFNGLWAITSYNCPROC glWaitSync; -extern PFNGLGETINTEGER64VPROC glGetInteger64v; -extern PFNGLGETSYNCIVPROC glGetSynciv; -extern PFNGLGETINTEGER64I_VPROC glGetInteger64i_v; -extern PFNGLGETBUFFERPARAMETERI64VPROC glGetBufferParameteri64v; -extern PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture; -extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; -extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; -extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; -extern PFNGLSAMPLEMASKIPROC glSampleMaski; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex; +extern LL_THREAD_LOCAL_GL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glDrawRangeElementsBaseVertex; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glMultiDrawElementsBaseVertex; +extern LL_THREAD_LOCAL_GL PFNGLPROVOKINGVERTEXPROC glProvokingVertex; +extern LL_THREAD_LOCAL_GL PFNGLFENCESYNCPROC glFenceSync; +extern LL_THREAD_LOCAL_GL PFNGLISSYNCPROC glIsSync; +extern LL_THREAD_LOCAL_GL PFNGLDELETESYNCPROC glDeleteSync; +extern LL_THREAD_LOCAL_GL PFNGLCLIENTWAITSYNCPROC glClientWaitSync; +extern LL_THREAD_LOCAL_GL PFNGLWAITSYNCPROC glWaitSync; +extern LL_THREAD_LOCAL_GL PFNGLGETINTEGER64VPROC glGetInteger64v; +extern LL_THREAD_LOCAL_GL PFNGLGETSYNCIVPROC glGetSynciv; +extern LL_THREAD_LOCAL_GL PFNGLGETINTEGER64I_VPROC glGetInteger64i_v; +extern LL_THREAD_LOCAL_GL PFNGLGETBUFFERPARAMETERI64VPROC glGetBufferParameteri64v; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture; +extern LL_THREAD_LOCAL_GL PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLEMASKIPROC glSampleMaski; // GL_VERSION_3_3 -extern PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed; -extern PFNGLGETFRAGDATAINDEXPROC glGetFragDataIndex; -extern PFNGLGENSAMPLERSPROC glGenSamplers; -extern PFNGLDELETESAMPLERSPROC glDeleteSamplers; -extern PFNGLISSAMPLERPROC glIsSampler; -extern PFNGLBINDSAMPLERPROC glBindSampler; -extern PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri; -extern PFNGLSAMPLERPARAMETERIVPROC glSamplerParameteriv; -extern PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf; -extern PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv; -extern PFNGLSAMPLERPARAMETERIIVPROC glSamplerParameterIiv; -extern PFNGLSAMPLERPARAMETERIUIVPROC glSamplerParameterIuiv; -extern PFNGLGETSAMPLERPARAMETERIVPROC glGetSamplerParameteriv; -extern PFNGLGETSAMPLERPARAMETERIIVPROC glGetSamplerParameterIiv; -extern PFNGLGETSAMPLERPARAMETERFVPROC glGetSamplerParameterfv; -extern PFNGLGETSAMPLERPARAMETERIUIVPROC glGetSamplerParameterIuiv; -extern PFNGLQUERYCOUNTERPROC glQueryCounter; -extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; -extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; -extern PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor; -extern PFNGLVERTEXATTRIBP1UIPROC glVertexAttribP1ui; -extern PFNGLVERTEXATTRIBP1UIVPROC glVertexAttribP1uiv; -extern PFNGLVERTEXATTRIBP2UIPROC glVertexAttribP2ui; -extern PFNGLVERTEXATTRIBP2UIVPROC glVertexAttribP2uiv; -extern PFNGLVERTEXATTRIBP3UIPROC glVertexAttribP3ui; -extern PFNGLVERTEXATTRIBP3UIVPROC glVertexAttribP3uiv; -extern PFNGLVERTEXATTRIBP4UIPROC glVertexAttribP4ui; -extern PFNGLVERTEXATTRIBP4UIVPROC glVertexAttribP4uiv; -extern PFNGLVERTEXP2UIPROC glVertexP2ui; -extern PFNGLVERTEXP2UIVPROC glVertexP2uiv; -extern PFNGLVERTEXP3UIPROC glVertexP3ui; -extern PFNGLVERTEXP3UIVPROC glVertexP3uiv; -extern PFNGLVERTEXP4UIPROC glVertexP4ui; -extern PFNGLVERTEXP4UIVPROC glVertexP4uiv; -extern PFNGLTEXCOORDP1UIPROC glTexCoordP1ui; -extern PFNGLTEXCOORDP1UIVPROC glTexCoordP1uiv; -extern PFNGLTEXCOORDP2UIPROC glTexCoordP2ui; -extern PFNGLTEXCOORDP2UIVPROC glTexCoordP2uiv; -extern PFNGLTEXCOORDP3UIPROC glTexCoordP3ui; -extern PFNGLTEXCOORDP3UIVPROC glTexCoordP3uiv; -extern PFNGLTEXCOORDP4UIPROC glTexCoordP4ui; -extern PFNGLTEXCOORDP4UIVPROC glTexCoordP4uiv; -extern PFNGLMULTITEXCOORDP1UIPROC glMultiTexCoordP1ui; -extern PFNGLMULTITEXCOORDP1UIVPROC glMultiTexCoordP1uiv; -extern PFNGLMULTITEXCOORDP2UIPROC glMultiTexCoordP2ui; -extern PFNGLMULTITEXCOORDP2UIVPROC glMultiTexCoordP2uiv; -extern PFNGLMULTITEXCOORDP3UIPROC glMultiTexCoordP3ui; -extern PFNGLMULTITEXCOORDP3UIVPROC glMultiTexCoordP3uiv; -extern PFNGLMULTITEXCOORDP4UIPROC glMultiTexCoordP4ui; -extern PFNGLMULTITEXCOORDP4UIVPROC glMultiTexCoordP4uiv; -extern PFNGLNORMALP3UIPROC glNormalP3ui; -extern PFNGLNORMALP3UIVPROC glNormalP3uiv; -extern PFNGLCOLORP3UIPROC glColorP3ui; -extern PFNGLCOLORP3UIVPROC glColorP3uiv; -extern PFNGLCOLORP4UIPROC glColorP4ui; -extern PFNGLCOLORP4UIVPROC glColorP4uiv; -extern PFNGLSECONDARYCOLORP3UIPROC glSecondaryColorP3ui; -extern PFNGLSECONDARYCOLORP3UIVPROC glSecondaryColorP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed; +extern LL_THREAD_LOCAL_GL PFNGLGETFRAGDATAINDEXPROC glGetFragDataIndex; +extern LL_THREAD_LOCAL_GL PFNGLGENSAMPLERSPROC glGenSamplers; +extern LL_THREAD_LOCAL_GL PFNGLDELETESAMPLERSPROC glDeleteSamplers; +extern LL_THREAD_LOCAL_GL PFNGLISSAMPLERPROC glIsSampler; +extern LL_THREAD_LOCAL_GL PFNGLBINDSAMPLERPROC glBindSampler; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIVPROC glSamplerParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIIVPROC glSamplerParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLSAMPLERPARAMETERIUIVPROC glSamplerParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIVPROC glGetSamplerParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIIVPROC glGetSamplerParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERFVPROC glGetSamplerParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLGETSAMPLERPARAMETERIUIVPROC glGetSamplerParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLQUERYCOUNTERPROC glQueryCounter; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP1UIPROC glVertexAttribP1ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP1UIVPROC glVertexAttribP1uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP2UIPROC glVertexAttribP2ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP2UIVPROC glVertexAttribP2uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP3UIPROC glVertexAttribP3ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP3UIVPROC glVertexAttribP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP4UIPROC glVertexAttribP4ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBP4UIVPROC glVertexAttribP4uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP2UIPROC glVertexP2ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP2UIVPROC glVertexP2uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP3UIPROC glVertexP3ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP3UIVPROC glVertexP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP4UIPROC glVertexP4ui; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXP4UIVPROC glVertexP4uiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP1UIPROC glTexCoordP1ui; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP1UIVPROC glTexCoordP1uiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP2UIPROC glTexCoordP2ui; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP2UIVPROC glTexCoordP2uiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP3UIPROC glTexCoordP3ui; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP3UIVPROC glTexCoordP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP4UIPROC glTexCoordP4ui; +extern LL_THREAD_LOCAL_GL PFNGLTEXCOORDP4UIVPROC glTexCoordP4uiv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP1UIPROC glMultiTexCoordP1ui; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP1UIVPROC glMultiTexCoordP1uiv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP2UIPROC glMultiTexCoordP2ui; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP2UIVPROC glMultiTexCoordP2uiv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP3UIPROC glMultiTexCoordP3ui; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP3UIVPROC glMultiTexCoordP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP4UIPROC glMultiTexCoordP4ui; +extern LL_THREAD_LOCAL_GL PFNGLMULTITEXCOORDP4UIVPROC glMultiTexCoordP4uiv; +extern LL_THREAD_LOCAL_GL PFNGLNORMALP3UIPROC glNormalP3ui; +extern LL_THREAD_LOCAL_GL PFNGLNORMALP3UIVPROC glNormalP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLCOLORP3UIPROC glColorP3ui; +extern LL_THREAD_LOCAL_GL PFNGLCOLORP3UIVPROC glColorP3uiv; +extern LL_THREAD_LOCAL_GL PFNGLCOLORP4UIPROC glColorP4ui; +extern LL_THREAD_LOCAL_GL PFNGLCOLORP4UIVPROC glColorP4uiv; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORP3UIPROC glSecondaryColorP3ui; +extern LL_THREAD_LOCAL_GL PFNGLSECONDARYCOLORP3UIVPROC glSecondaryColorP3uiv; // GL_VERSION_4_0 -extern PFNGLMINSAMPLESHADINGPROC glMinSampleShading; -extern PFNGLBLENDEQUATIONIPROC glBlendEquationi; -extern PFNGLBLENDEQUATIONSEPARATEIPROC glBlendEquationSeparatei; -extern PFNGLBLENDFUNCIPROC glBlendFunci; -extern PFNGLBLENDFUNCSEPARATEIPROC glBlendFuncSeparatei; -extern PFNGLDRAWARRAYSINDIRECTPROC glDrawArraysIndirect; -extern PFNGLDRAWELEMENTSINDIRECTPROC glDrawElementsIndirect; -extern PFNGLUNIFORM1DPROC glUniform1d; -extern PFNGLUNIFORM2DPROC glUniform2d; -extern PFNGLUNIFORM3DPROC glUniform3d; -extern PFNGLUNIFORM4DPROC glUniform4d; -extern PFNGLUNIFORM1DVPROC glUniform1dv; -extern PFNGLUNIFORM2DVPROC glUniform2dv; -extern PFNGLUNIFORM3DVPROC glUniform3dv; -extern PFNGLUNIFORM4DVPROC glUniform4dv; -extern PFNGLUNIFORMMATRIX2DVPROC glUniformMatrix2dv; -extern PFNGLUNIFORMMATRIX3DVPROC glUniformMatrix3dv; -extern PFNGLUNIFORMMATRIX4DVPROC glUniformMatrix4dv; -extern PFNGLUNIFORMMATRIX2X3DVPROC glUniformMatrix2x3dv; -extern PFNGLUNIFORMMATRIX2X4DVPROC glUniformMatrix2x4dv; -extern PFNGLUNIFORMMATRIX3X2DVPROC glUniformMatrix3x2dv; -extern PFNGLUNIFORMMATRIX3X4DVPROC glUniformMatrix3x4dv; -extern PFNGLUNIFORMMATRIX4X2DVPROC glUniformMatrix4x2dv; -extern PFNGLUNIFORMMATRIX4X3DVPROC glUniformMatrix4x3dv; -extern PFNGLGETUNIFORMDVPROC glGetUniformdv; -extern PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glGetSubroutineUniformLocation; -extern PFNGLGETSUBROUTINEINDEXPROC glGetSubroutineIndex; -extern PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glGetActiveSubroutineUniformiv; -extern PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glGetActiveSubroutineUniformName; -extern PFNGLGETACTIVESUBROUTINENAMEPROC glGetActiveSubroutineName; -extern PFNGLUNIFORMSUBROUTINESUIVPROC glUniformSubroutinesuiv; -extern PFNGLGETUNIFORMSUBROUTINEUIVPROC glGetUniformSubroutineuiv; -extern PFNGLGETPROGRAMSTAGEIVPROC glGetProgramStageiv; -extern PFNGLPATCHPARAMETERIPROC glPatchParameteri; -extern PFNGLPATCHPARAMETERFVPROC glPatchParameterfv; -extern PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback; -extern PFNGLDELETETRANSFORMFEEDBACKSPROC glDeleteTransformFeedbacks; -extern PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks; -extern PFNGLISTRANSFORMFEEDBACKPROC glIsTransformFeedback; -extern PFNGLPAUSETRANSFORMFEEDBACKPROC glPauseTransformFeedback; -extern PFNGLRESUMETRANSFORMFEEDBACKPROC glResumeTransformFeedback; -extern PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback; -extern PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glDrawTransformFeedbackStream; -extern PFNGLBEGINQUERYINDEXEDPROC glBeginQueryIndexed; -extern PFNGLENDQUERYINDEXEDPROC glEndQueryIndexed; -extern PFNGLGETQUERYINDEXEDIVPROC glGetQueryIndexediv; +extern LL_THREAD_LOCAL_GL PFNGLMINSAMPLESHADINGPROC glMinSampleShading; +extern LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONIPROC glBlendEquationi; +extern LL_THREAD_LOCAL_GL PFNGLBLENDEQUATIONSEPARATEIPROC glBlendEquationSeparatei; +extern LL_THREAD_LOCAL_GL PFNGLBLENDFUNCIPROC glBlendFunci; +extern LL_THREAD_LOCAL_GL PFNGLBLENDFUNCSEPARATEIPROC glBlendFuncSeparatei; +extern LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINDIRECTPROC glDrawArraysIndirect; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINDIRECTPROC glDrawElementsIndirect; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1DPROC glUniform1d; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2DPROC glUniform2d; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3DPROC glUniform3d; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4DPROC glUniform4d; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM1DVPROC glUniform1dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM2DVPROC glUniform2dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM3DVPROC glUniform3dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORM4DVPROC glUniform4dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2DVPROC glUniformMatrix2dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3DVPROC glUniformMatrix3dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4DVPROC glUniformMatrix4dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X3DVPROC glUniformMatrix2x3dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX2X4DVPROC glUniformMatrix2x4dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X2DVPROC glUniformMatrix3x2dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX3X4DVPROC glUniformMatrix3x4dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X2DVPROC glUniformMatrix4x2dv; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMMATRIX4X3DVPROC glUniformMatrix4x3dv; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMDVPROC glGetUniformdv; +extern LL_THREAD_LOCAL_GL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glGetSubroutineUniformLocation; +extern LL_THREAD_LOCAL_GL PFNGLGETSUBROUTINEINDEXPROC glGetSubroutineIndex; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glGetActiveSubroutineUniformiv; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glGetActiveSubroutineUniformName; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVESUBROUTINENAMEPROC glGetActiveSubroutineName; +extern LL_THREAD_LOCAL_GL PFNGLUNIFORMSUBROUTINESUIVPROC glUniformSubroutinesuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETUNIFORMSUBROUTINEUIVPROC glGetUniformSubroutineuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMSTAGEIVPROC glGetProgramStageiv; +extern LL_THREAD_LOCAL_GL PFNGLPATCHPARAMETERIPROC glPatchParameteri; +extern LL_THREAD_LOCAL_GL PFNGLPATCHPARAMETERFVPROC glPatchParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLDELETETRANSFORMFEEDBACKSPROC glDeleteTransformFeedbacks; +extern LL_THREAD_LOCAL_GL PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks; +extern LL_THREAD_LOCAL_GL PFNGLISTRANSFORMFEEDBACKPROC glIsTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLPAUSETRANSFORMFEEDBACKPROC glPauseTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLRESUMETRANSFORMFEEDBACKPROC glResumeTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback; +extern LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glDrawTransformFeedbackStream; +extern LL_THREAD_LOCAL_GL PFNGLBEGINQUERYINDEXEDPROC glBeginQueryIndexed; +extern LL_THREAD_LOCAL_GL PFNGLENDQUERYINDEXEDPROC glEndQueryIndexed; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYINDEXEDIVPROC glGetQueryIndexediv; // GL_VERSION_4_1 -extern PFNGLRELEASESHADERCOMPILERPROC glReleaseShaderCompiler; -extern PFNGLSHADERBINARYPROC glShaderBinary; -extern PFNGLGETSHADERPRECISIONFORMATPROC glGetShaderPrecisionFormat; -extern PFNGLDEPTHRANGEFPROC glDepthRangef; -extern PFNGLCLEARDEPTHFPROC glClearDepthf; -extern PFNGLGETPROGRAMBINARYPROC glGetProgramBinary; -extern PFNGLPROGRAMBINARYPROC glProgramBinary; -extern PFNGLPROGRAMPARAMETERIPROC glProgramParameteri; -extern PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages; -extern PFNGLACTIVESHADERPROGRAMPROC glActiveShaderProgram; -extern PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv; -extern PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline; -extern PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines; -extern PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines; -extern PFNGLISPROGRAMPIPELINEPROC glIsProgramPipeline; -extern PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv; -extern PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i; -extern PFNGLPROGRAMUNIFORM1IVPROC glProgramUniform1iv; -extern PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f; -extern PFNGLPROGRAMUNIFORM1FVPROC glProgramUniform1fv; -extern PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d; -extern PFNGLPROGRAMUNIFORM1DVPROC glProgramUniform1dv; -extern PFNGLPROGRAMUNIFORM1UIPROC glProgramUniform1ui; -extern PFNGLPROGRAMUNIFORM1UIVPROC glProgramUniform1uiv; -extern PFNGLPROGRAMUNIFORM2IPROC glProgramUniform2i; -extern PFNGLPROGRAMUNIFORM2IVPROC glProgramUniform2iv; -extern PFNGLPROGRAMUNIFORM2FPROC glProgramUniform2f; -extern PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv; -extern PFNGLPROGRAMUNIFORM2DPROC glProgramUniform2d; -extern PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv; -extern PFNGLPROGRAMUNIFORM2UIPROC glProgramUniform2ui; -extern PFNGLPROGRAMUNIFORM2UIVPROC glProgramUniform2uiv; -extern PFNGLPROGRAMUNIFORM3IPROC glProgramUniform3i; -extern PFNGLPROGRAMUNIFORM3IVPROC glProgramUniform3iv; -extern PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f; -extern PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv; -extern PFNGLPROGRAMUNIFORM3DPROC glProgramUniform3d; -extern PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv; -extern PFNGLPROGRAMUNIFORM3UIPROC glProgramUniform3ui; -extern PFNGLPROGRAMUNIFORM3UIVPROC glProgramUniform3uiv; -extern PFNGLPROGRAMUNIFORM4IPROC glProgramUniform4i; -extern PFNGLPROGRAMUNIFORM4IVPROC glProgramUniform4iv; -extern PFNGLPROGRAMUNIFORM4FPROC glProgramUniform4f; -extern PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv; -extern PFNGLPROGRAMUNIFORM4DPROC glProgramUniform4d; -extern PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv; -extern PFNGLPROGRAMUNIFORM4UIPROC glProgramUniform4ui; -extern PFNGLPROGRAMUNIFORM4UIVPROC glProgramUniform4uiv; -extern PFNGLPROGRAMUNIFORMMATRIX2FVPROC glProgramUniformMatrix2fv; -extern PFNGLPROGRAMUNIFORMMATRIX3FVPROC glProgramUniformMatrix3fv; -extern PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv; -extern PFNGLPROGRAMUNIFORMMATRIX2DVPROC glProgramUniformMatrix2dv; -extern PFNGLPROGRAMUNIFORMMATRIX3DVPROC glProgramUniformMatrix3dv; -extern PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv; -extern PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glProgramUniformMatrix2x3fv; -extern PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glProgramUniformMatrix3x2fv; -extern PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glProgramUniformMatrix2x4fv; -extern PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glProgramUniformMatrix4x2fv; -extern PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glProgramUniformMatrix3x4fv; -extern PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glProgramUniformMatrix4x3fv; -extern PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glProgramUniformMatrix2x3dv; -extern PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glProgramUniformMatrix3x2dv; -extern PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glProgramUniformMatrix2x4dv; -extern PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glProgramUniformMatrix4x2dv; -extern PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glProgramUniformMatrix3x4dv; -extern PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glProgramUniformMatrix4x3dv; -extern PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline; -extern PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog; -extern PFNGLVERTEXATTRIBL1DPROC glVertexAttribL1d; -extern PFNGLVERTEXATTRIBL2DPROC glVertexAttribL2d; -extern PFNGLVERTEXATTRIBL3DPROC glVertexAttribL3d; -extern PFNGLVERTEXATTRIBL4DPROC glVertexAttribL4d; -extern PFNGLVERTEXATTRIBL1DVPROC glVertexAttribL1dv; -extern PFNGLVERTEXATTRIBL2DVPROC glVertexAttribL2dv; -extern PFNGLVERTEXATTRIBL3DVPROC glVertexAttribL3dv; -extern PFNGLVERTEXATTRIBL4DVPROC glVertexAttribL4dv; -extern PFNGLVERTEXATTRIBLPOINTERPROC glVertexAttribLPointer; -extern PFNGLGETVERTEXATTRIBLDVPROC glGetVertexAttribLdv; -extern PFNGLVIEWPORTARRAYVPROC glViewportArrayv; -extern PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf; -extern PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv; -extern PFNGLSCISSORARRAYVPROC glScissorArrayv; -extern PFNGLSCISSORINDEXEDPROC glScissorIndexed; -extern PFNGLSCISSORINDEXEDVPROC glScissorIndexedv; -extern PFNGLDEPTHRANGEARRAYVPROC glDepthRangeArrayv; -extern PFNGLDEPTHRANGEINDEXEDPROC glDepthRangeIndexed; -extern PFNGLGETFLOATI_VPROC glGetFloati_v; -extern PFNGLGETDOUBLEI_VPROC glGetDoublei_v; +extern LL_THREAD_LOCAL_GL PFNGLRELEASESHADERCOMPILERPROC glReleaseShaderCompiler; +extern LL_THREAD_LOCAL_GL PFNGLSHADERBINARYPROC glShaderBinary; +extern LL_THREAD_LOCAL_GL PFNGLGETSHADERPRECISIONFORMATPROC glGetShaderPrecisionFormat; +extern LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEFPROC glDepthRangef; +extern LL_THREAD_LOCAL_GL PFNGLCLEARDEPTHFPROC glClearDepthf; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMBINARYPROC glGetProgramBinary; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMBINARYPROC glProgramBinary; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMPARAMETERIPROC glProgramParameteri; +extern LL_THREAD_LOCAL_GL PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages; +extern LL_THREAD_LOCAL_GL PFNGLACTIVESHADERPROGRAMPROC glActiveShaderProgram; +extern LL_THREAD_LOCAL_GL PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv; +extern LL_THREAD_LOCAL_GL PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline; +extern LL_THREAD_LOCAL_GL PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines; +extern LL_THREAD_LOCAL_GL PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines; +extern LL_THREAD_LOCAL_GL PFNGLISPROGRAMPIPELINEPROC glIsProgramPipeline; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1IVPROC glProgramUniform1iv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1FVPROC glProgramUniform1fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1DVPROC glProgramUniform1dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1UIPROC glProgramUniform1ui; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM1UIVPROC glProgramUniform1uiv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2IPROC glProgramUniform2i; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2IVPROC glProgramUniform2iv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2FPROC glProgramUniform2f; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2DPROC glProgramUniform2d; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2UIPROC glProgramUniform2ui; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM2UIVPROC glProgramUniform2uiv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3IPROC glProgramUniform3i; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3IVPROC glProgramUniform3iv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3DPROC glProgramUniform3d; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3UIPROC glProgramUniform3ui; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM3UIVPROC glProgramUniform3uiv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4IPROC glProgramUniform4i; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4IVPROC glProgramUniform4iv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4FPROC glProgramUniform4f; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4DPROC glProgramUniform4d; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4UIPROC glProgramUniform4ui; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORM4UIVPROC glProgramUniform4uiv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glProgramUniformMatrix2fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glProgramUniformMatrix3fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glProgramUniformMatrix2dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glProgramUniformMatrix3dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glProgramUniformMatrix2x3fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glProgramUniformMatrix3x2fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glProgramUniformMatrix2x4fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glProgramUniformMatrix4x2fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glProgramUniformMatrix3x4fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glProgramUniformMatrix4x3fv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glProgramUniformMatrix2x3dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glProgramUniformMatrix3x2dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glProgramUniformMatrix2x4dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glProgramUniformMatrix4x2dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glProgramUniformMatrix3x4dv; +extern LL_THREAD_LOCAL_GL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glProgramUniformMatrix4x3dv; +extern LL_THREAD_LOCAL_GL PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL1DPROC glVertexAttribL1d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL2DPROC glVertexAttribL2d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL3DPROC glVertexAttribL3d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL4DPROC glVertexAttribL4d; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL1DVPROC glVertexAttribL1dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL2DVPROC glVertexAttribL2dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL3DVPROC glVertexAttribL3dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBL4DVPROC glVertexAttribL4dv; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBLPOINTERPROC glVertexAttribLPointer; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXATTRIBLDVPROC glGetVertexAttribLdv; +extern LL_THREAD_LOCAL_GL PFNGLVIEWPORTARRAYVPROC glViewportArrayv; +extern LL_THREAD_LOCAL_GL PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf; +extern LL_THREAD_LOCAL_GL PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv; +extern LL_THREAD_LOCAL_GL PFNGLSCISSORARRAYVPROC glScissorArrayv; +extern LL_THREAD_LOCAL_GL PFNGLSCISSORINDEXEDPROC glScissorIndexed; +extern LL_THREAD_LOCAL_GL PFNGLSCISSORINDEXEDVPROC glScissorIndexedv; +extern LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEARRAYVPROC glDepthRangeArrayv; +extern LL_THREAD_LOCAL_GL PFNGLDEPTHRANGEINDEXEDPROC glDepthRangeIndexed; +extern LL_THREAD_LOCAL_GL PFNGLGETFLOATI_VPROC glGetFloati_v; +extern LL_THREAD_LOCAL_GL PFNGLGETDOUBLEI_VPROC glGetDoublei_v; // GL_VERSION_4_2 -extern PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glDrawArraysInstancedBaseInstance; -extern PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glDrawElementsInstancedBaseInstance; -extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glDrawElementsInstancedBaseVertexBaseInstance; -extern PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ; -extern PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glGetActiveAtomicCounterBufferiv; -extern PFNGLBINDIMAGETEXTUREPROC glBindImageTexture; -extern PFNGLMEMORYBARRIERPROC glMemoryBarrier; -extern PFNGLTEXSTORAGE1DPROC glTexStorage1D; -extern PFNGLTEXSTORAGE2DPROC glTexStorage2D; -extern PFNGLTEXSTORAGE3DPROC glTexStorage3D; -extern PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glDrawTransformFeedbackInstanced; -extern PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glDrawTransformFeedbackStreamInstanced; +extern LL_THREAD_LOCAL_GL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glDrawArraysInstancedBaseInstance; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glDrawElementsInstancedBaseInstance; +extern LL_THREAD_LOCAL_GL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glDrawElementsInstancedBaseVertexBaseInstance; +extern LL_THREAD_LOCAL_GL PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ; +extern LL_THREAD_LOCAL_GL PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glGetActiveAtomicCounterBufferiv; +extern LL_THREAD_LOCAL_GL PFNGLBINDIMAGETEXTUREPROC glBindImageTexture; +extern LL_THREAD_LOCAL_GL PFNGLMEMORYBARRIERPROC glMemoryBarrier; +extern LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE1DPROC glTexStorage1D; +extern LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE2DPROC glTexStorage2D; +extern LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE3DPROC glTexStorage3D; +extern LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glDrawTransformFeedbackInstanced; +extern LL_THREAD_LOCAL_GL PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glDrawTransformFeedbackStreamInstanced; // GL_VERSION_4_3 -extern PFNGLCLEARBUFFERDATAPROC glClearBufferData; -extern PFNGLCLEARBUFFERSUBDATAPROC glClearBufferSubData; -extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute; -extern PFNGLDISPATCHCOMPUTEINDIRECTPROC glDispatchComputeIndirect; -extern PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData; -extern PFNGLFRAMEBUFFERPARAMETERIPROC glFramebufferParameteri; -extern PFNGLGETFRAMEBUFFERPARAMETERIVPROC glGetFramebufferParameteriv; -extern PFNGLGETINTERNALFORMATI64VPROC glGetInternalformati64v; -extern PFNGLINVALIDATETEXSUBIMAGEPROC glInvalidateTexSubImage; -extern PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage; -extern PFNGLINVALIDATEBUFFERSUBDATAPROC glInvalidateBufferSubData; -extern PFNGLINVALIDATEBUFFERDATAPROC glInvalidateBufferData; -extern PFNGLINVALIDATEFRAMEBUFFERPROC glInvalidateFramebuffer; -extern PFNGLINVALIDATESUBFRAMEBUFFERPROC glInvalidateSubFramebuffer; -extern PFNGLMULTIDRAWARRAYSINDIRECTPROC glMultiDrawArraysIndirect; -extern PFNGLMULTIDRAWELEMENTSINDIRECTPROC glMultiDrawElementsIndirect; -extern PFNGLGETPROGRAMINTERFACEIVPROC glGetProgramInterfaceiv; -extern PFNGLGETPROGRAMRESOURCEINDEXPROC glGetProgramResourceIndex; -extern PFNGLGETPROGRAMRESOURCENAMEPROC glGetProgramResourceName; -extern PFNGLGETPROGRAMRESOURCEIVPROC glGetProgramResourceiv; -extern PFNGLGETPROGRAMRESOURCELOCATIONPROC glGetProgramResourceLocation; -extern PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glGetProgramResourceLocationIndex; -extern PFNGLSHADERSTORAGEBLOCKBINDINGPROC glShaderStorageBlockBinding; -extern PFNGLTEXBUFFERRANGEPROC glTexBufferRange; -extern PFNGLTEXSTORAGE2DMULTISAMPLEPROC glTexStorage2DMultisample; -extern PFNGLTEXSTORAGE3DMULTISAMPLEPROC glTexStorage3DMultisample; -extern PFNGLTEXTUREVIEWPROC glTextureView; -extern PFNGLBINDVERTEXBUFFERPROC glBindVertexBuffer; -extern PFNGLVERTEXATTRIBFORMATPROC glVertexAttribFormat; -extern PFNGLVERTEXATTRIBIFORMATPROC glVertexAttribIFormat; -extern PFNGLVERTEXATTRIBLFORMATPROC glVertexAttribLFormat; -extern PFNGLVERTEXATTRIBBINDINGPROC glVertexAttribBinding; -extern PFNGLVERTEXBINDINGDIVISORPROC glVertexBindingDivisor; -extern PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl; -extern PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert; -extern PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback; -extern PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog; -extern PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup; -extern PFNGLPOPDEBUGGROUPPROC glPopDebugGroup; -extern PFNGLOBJECTLABELPROC glObjectLabel; -extern PFNGLGETOBJECTLABELPROC glGetObjectLabel; -extern PFNGLOBJECTPTRLABELPROC glObjectPtrLabel; -extern PFNGLGETOBJECTPTRLABELPROC glGetObjectPtrLabel; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERDATAPROC glClearBufferData; +extern LL_THREAD_LOCAL_GL PFNGLCLEARBUFFERSUBDATAPROC glClearBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLDISPATCHCOMPUTEPROC glDispatchCompute; +extern LL_THREAD_LOCAL_GL PFNGLDISPATCHCOMPUTEINDIRECTPROC glDispatchComputeIndirect; +extern LL_THREAD_LOCAL_GL PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData; +extern LL_THREAD_LOCAL_GL PFNGLFRAMEBUFFERPARAMETERIPROC glFramebufferParameteri; +extern LL_THREAD_LOCAL_GL PFNGLGETFRAMEBUFFERPARAMETERIVPROC glGetFramebufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETINTERNALFORMATI64VPROC glGetInternalformati64v; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATETEXSUBIMAGEPROC glInvalidateTexSubImage; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATEBUFFERSUBDATAPROC glInvalidateBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATEBUFFERDATAPROC glInvalidateBufferData; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATEFRAMEBUFFERPROC glInvalidateFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATESUBFRAMEBUFFERPROC glInvalidateSubFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSINDIRECTPROC glMultiDrawArraysIndirect; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSINDIRECTPROC glMultiDrawElementsIndirect; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMINTERFACEIVPROC glGetProgramInterfaceiv; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCEINDEXPROC glGetProgramResourceIndex; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCENAMEPROC glGetProgramResourceName; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCEIVPROC glGetProgramResourceiv; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCELOCATIONPROC glGetProgramResourceLocation; +extern LL_THREAD_LOCAL_GL PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glGetProgramResourceLocationIndex; +extern LL_THREAD_LOCAL_GL PFNGLSHADERSTORAGEBLOCKBINDINGPROC glShaderStorageBlockBinding; +extern LL_THREAD_LOCAL_GL PFNGLTEXBUFFERRANGEPROC glTexBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE2DMULTISAMPLEPROC glTexStorage2DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLTEXSTORAGE3DMULTISAMPLEPROC glTexStorage3DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREVIEWPROC glTextureView; +extern LL_THREAD_LOCAL_GL PFNGLBINDVERTEXBUFFERPROC glBindVertexBuffer; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBFORMATPROC glVertexAttribFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBIFORMATPROC glVertexAttribIFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBLFORMATPROC glVertexAttribLFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXATTRIBBINDINGPROC glVertexAttribBinding; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXBINDINGDIVISORPROC glVertexBindingDivisor; +extern LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl; +extern LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert; +extern LL_THREAD_LOCAL_GL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback; +extern LL_THREAD_LOCAL_GL PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog; +extern LL_THREAD_LOCAL_GL PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup; +extern LL_THREAD_LOCAL_GL PFNGLPOPDEBUGGROUPPROC glPopDebugGroup; +extern LL_THREAD_LOCAL_GL PFNGLOBJECTLABELPROC glObjectLabel; +extern LL_THREAD_LOCAL_GL PFNGLGETOBJECTLABELPROC glGetObjectLabel; +extern LL_THREAD_LOCAL_GL PFNGLOBJECTPTRLABELPROC glObjectPtrLabel; +extern LL_THREAD_LOCAL_GL PFNGLGETOBJECTPTRLABELPROC glGetObjectPtrLabel; // GL_VERSION_4_4 -extern PFNGLBUFFERSTORAGEPROC glBufferStorage; -extern PFNGLCLEARTEXIMAGEPROC glClearTexImage; -extern PFNGLCLEARTEXSUBIMAGEPROC glClearTexSubImage; -extern PFNGLBINDBUFFERSBASEPROC glBindBuffersBase; -extern PFNGLBINDBUFFERSRANGEPROC glBindBuffersRange; -extern PFNGLBINDTEXTURESPROC glBindTextures; -extern PFNGLBINDSAMPLERSPROC glBindSamplers; -extern PFNGLBINDIMAGETEXTURESPROC glBindImageTextures; -extern PFNGLBINDVERTEXBUFFERSPROC glBindVertexBuffers; +extern LL_THREAD_LOCAL_GL PFNGLBUFFERSTORAGEPROC glBufferStorage; +extern LL_THREAD_LOCAL_GL PFNGLCLEARTEXIMAGEPROC glClearTexImage; +extern LL_THREAD_LOCAL_GL PFNGLCLEARTEXSUBIMAGEPROC glClearTexSubImage; +extern LL_THREAD_LOCAL_GL PFNGLBINDBUFFERSBASEPROC glBindBuffersBase; +extern LL_THREAD_LOCAL_GL PFNGLBINDBUFFERSRANGEPROC glBindBuffersRange; +extern LL_THREAD_LOCAL_GL PFNGLBINDTEXTURESPROC glBindTextures; +extern LL_THREAD_LOCAL_GL PFNGLBINDSAMPLERSPROC glBindSamplers; +extern LL_THREAD_LOCAL_GL PFNGLBINDIMAGETEXTURESPROC glBindImageTextures; +extern LL_THREAD_LOCAL_GL PFNGLBINDVERTEXBUFFERSPROC glBindVertexBuffers; // GL_VERSION_4_5 -extern PFNGLCLIPCONTROLPROC glClipControl; -extern PFNGLCREATETRANSFORMFEEDBACKSPROC glCreateTransformFeedbacks; -extern PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glTransformFeedbackBufferBase; -extern PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glTransformFeedbackBufferRange; -extern PFNGLGETTRANSFORMFEEDBACKIVPROC glGetTransformFeedbackiv; -extern PFNGLGETTRANSFORMFEEDBACKI_VPROC glGetTransformFeedbacki_v; -extern PFNGLGETTRANSFORMFEEDBACKI64_VPROC glGetTransformFeedbacki64_v; -extern PFNGLCREATEBUFFERSPROC glCreateBuffers; -extern PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage; -extern PFNGLNAMEDBUFFERDATAPROC glNamedBufferData; -extern PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData; -extern PFNGLCOPYNAMEDBUFFERSUBDATAPROC glCopyNamedBufferSubData; -extern PFNGLCLEARNAMEDBUFFERDATAPROC glClearNamedBufferData; -extern PFNGLCLEARNAMEDBUFFERSUBDATAPROC glClearNamedBufferSubData; -extern PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer; -extern PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange; -extern PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer; -extern PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange; -extern PFNGLGETNAMEDBUFFERPARAMETERIVPROC glGetNamedBufferParameteriv; -extern PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glGetNamedBufferParameteri64v; -extern PFNGLGETNAMEDBUFFERPOINTERVPROC glGetNamedBufferPointerv; -extern PFNGLGETNAMEDBUFFERSUBDATAPROC glGetNamedBufferSubData; -extern PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers; -extern PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glNamedFramebufferRenderbuffer; -extern PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glNamedFramebufferParameteri; -extern PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture; -extern PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glNamedFramebufferTextureLayer; -extern PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glNamedFramebufferDrawBuffer; -extern PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers; -extern PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer; -extern PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glInvalidateNamedFramebufferData; -extern PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glInvalidateNamedFramebufferSubData; -extern PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv; -extern PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv; -extern PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv; -extern PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glClearNamedFramebufferfi; -extern PFNGLBLITNAMEDFRAMEBUFFERPROC glBlitNamedFramebuffer; -extern PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus; -extern PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glGetNamedFramebufferParameteriv; -extern PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetNamedFramebufferAttachmentParameteriv; -extern PFNGLCREATERENDERBUFFERSPROC glCreateRenderbuffers; -extern PFNGLNAMEDRENDERBUFFERSTORAGEPROC glNamedRenderbufferStorage; -extern PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glNamedRenderbufferStorageMultisample; -extern PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glGetNamedRenderbufferParameteriv; -extern PFNGLCREATETEXTURESPROC glCreateTextures; -extern PFNGLTEXTUREBUFFERPROC glTextureBuffer; -extern PFNGLTEXTUREBUFFERRANGEPROC glTextureBufferRange; -extern PFNGLTEXTURESTORAGE1DPROC glTextureStorage1D; -extern PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D; -extern PFNGLTEXTURESTORAGE3DPROC glTextureStorage3D; -extern PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glTextureStorage2DMultisample; -extern PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glTextureStorage3DMultisample; -extern PFNGLTEXTURESUBIMAGE1DPROC glTextureSubImage1D; -extern PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D; -extern PFNGLTEXTURESUBIMAGE3DPROC glTextureSubImage3D; -extern PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glCompressedTextureSubImage1D; -extern PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glCompressedTextureSubImage2D; -extern PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glCompressedTextureSubImage3D; -extern PFNGLCOPYTEXTURESUBIMAGE1DPROC glCopyTextureSubImage1D; -extern PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D; -extern PFNGLCOPYTEXTURESUBIMAGE3DPROC glCopyTextureSubImage3D; -extern PFNGLTEXTUREPARAMETERFPROC glTextureParameterf; -extern PFNGLTEXTUREPARAMETERFVPROC glTextureParameterfv; -extern PFNGLTEXTUREPARAMETERIPROC glTextureParameteri; -extern PFNGLTEXTUREPARAMETERIIVPROC glTextureParameterIiv; -extern PFNGLTEXTUREPARAMETERIUIVPROC glTextureParameterIuiv; -extern PFNGLTEXTUREPARAMETERIVPROC glTextureParameteriv; -extern PFNGLGENERATETEXTUREMIPMAPPROC glGenerateTextureMipmap; -extern PFNGLBINDTEXTUREUNITPROC glBindTextureUnit; -extern PFNGLGETTEXTUREIMAGEPROC glGetTextureImage; -extern PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glGetCompressedTextureImage; -extern PFNGLGETTEXTURELEVELPARAMETERFVPROC glGetTextureLevelParameterfv; -extern PFNGLGETTEXTURELEVELPARAMETERIVPROC glGetTextureLevelParameteriv; -extern PFNGLGETTEXTUREPARAMETERFVPROC glGetTextureParameterfv; -extern PFNGLGETTEXTUREPARAMETERIIVPROC glGetTextureParameterIiv; -extern PFNGLGETTEXTUREPARAMETERIUIVPROC glGetTextureParameterIuiv; -extern PFNGLGETTEXTUREPARAMETERIVPROC glGetTextureParameteriv; -extern PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays; -extern PFNGLDISABLEVERTEXARRAYATTRIBPROC glDisableVertexArrayAttrib; -extern PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib; -extern PFNGLVERTEXARRAYELEMENTBUFFERPROC glVertexArrayElementBuffer; -extern PFNGLVERTEXARRAYVERTEXBUFFERPROC glVertexArrayVertexBuffer; -extern PFNGLVERTEXARRAYVERTEXBUFFERSPROC glVertexArrayVertexBuffers; -extern PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding; -extern PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat; -extern PFNGLVERTEXARRAYATTRIBIFORMATPROC glVertexArrayAttribIFormat; -extern PFNGLVERTEXARRAYATTRIBLFORMATPROC glVertexArrayAttribLFormat; -extern PFNGLVERTEXARRAYBINDINGDIVISORPROC glVertexArrayBindingDivisor; -extern PFNGLGETVERTEXARRAYIVPROC glGetVertexArrayiv; -extern PFNGLGETVERTEXARRAYINDEXEDIVPROC glGetVertexArrayIndexediv; -extern PFNGLGETVERTEXARRAYINDEXED64IVPROC glGetVertexArrayIndexed64iv; -extern PFNGLCREATESAMPLERSPROC glCreateSamplers; -extern PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines; -extern PFNGLCREATEQUERIESPROC glCreateQueries; -extern PFNGLGETQUERYBUFFEROBJECTI64VPROC glGetQueryBufferObjecti64v; -extern PFNGLGETQUERYBUFFEROBJECTIVPROC glGetQueryBufferObjectiv; -extern PFNGLGETQUERYBUFFEROBJECTUI64VPROC glGetQueryBufferObjectui64v; -extern PFNGLGETQUERYBUFFEROBJECTUIVPROC glGetQueryBufferObjectuiv; -extern PFNGLMEMORYBARRIERBYREGIONPROC glMemoryBarrierByRegion; -extern PFNGLGETTEXTURESUBIMAGEPROC glGetTextureSubImage; -extern PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glGetCompressedTextureSubImage; -extern PFNGLGETGRAPHICSRESETSTATUSPROC glGetGraphicsResetStatus; -extern PFNGLGETNCOMPRESSEDTEXIMAGEPROC glGetnCompressedTexImage; -extern PFNGLGETNTEXIMAGEPROC glGetnTexImage; -extern PFNGLGETNUNIFORMDVPROC glGetnUniformdv; -extern PFNGLGETNUNIFORMFVPROC glGetnUniformfv; -extern PFNGLGETNUNIFORMIVPROC glGetnUniformiv; -extern PFNGLGETNUNIFORMUIVPROC glGetnUniformuiv; -extern PFNGLREADNPIXELSPROC glReadnPixels; -extern PFNGLGETNMAPDVPROC glGetnMapdv; -extern PFNGLGETNMAPFVPROC glGetnMapfv; -extern PFNGLGETNMAPIVPROC glGetnMapiv; -extern PFNGLGETNPIXELMAPFVPROC glGetnPixelMapfv; -extern PFNGLGETNPIXELMAPUIVPROC glGetnPixelMapuiv; -extern PFNGLGETNPIXELMAPUSVPROC glGetnPixelMapusv; -extern PFNGLGETNPOLYGONSTIPPLEPROC glGetnPolygonStipple; -extern PFNGLGETNCOLORTABLEPROC glGetnColorTable; -extern PFNGLGETNCONVOLUTIONFILTERPROC glGetnConvolutionFilter; -extern PFNGLGETNSEPARABLEFILTERPROC glGetnSeparableFilter; -extern PFNGLGETNHISTOGRAMPROC glGetnHistogram; -extern PFNGLGETNMINMAXPROC glGetnMinmax; -extern PFNGLTEXTUREBARRIERPROC glTextureBarrier; +extern LL_THREAD_LOCAL_GL PFNGLCLIPCONTROLPROC glClipControl; +extern LL_THREAD_LOCAL_GL PFNGLCREATETRANSFORMFEEDBACKSPROC glCreateTransformFeedbacks; +extern LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glTransformFeedbackBufferBase; +extern LL_THREAD_LOCAL_GL PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glTransformFeedbackBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKIVPROC glGetTransformFeedbackiv; +extern LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKI_VPROC glGetTransformFeedbacki_v; +extern LL_THREAD_LOCAL_GL PFNGLGETTRANSFORMFEEDBACKI64_VPROC glGetTransformFeedbacki64_v; +extern LL_THREAD_LOCAL_GL PFNGLCREATEBUFFERSPROC glCreateBuffers; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERDATAPROC glNamedBufferData; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLCOPYNAMEDBUFFERSUBDATAPROC glCopyNamedBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDBUFFERDATAPROC glClearNamedBufferData; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDBUFFERSUBDATAPROC glClearNamedBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer; +extern LL_THREAD_LOCAL_GL PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer; +extern LL_THREAD_LOCAL_GL PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPARAMETERIVPROC glGetNamedBufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glGetNamedBufferParameteri64v; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERPOINTERVPROC glGetNamedBufferPointerv; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDBUFFERSUBDATAPROC glGetNamedBufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glNamedFramebufferRenderbuffer; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glNamedFramebufferParameteri; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glNamedFramebufferTextureLayer; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glNamedFramebufferDrawBuffer; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glInvalidateNamedFramebufferData; +extern LL_THREAD_LOCAL_GL PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glInvalidateNamedFramebufferSubData; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv; +extern LL_THREAD_LOCAL_GL PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glClearNamedFramebufferfi; +extern LL_THREAD_LOCAL_GL PFNGLBLITNAMEDFRAMEBUFFERPROC glBlitNamedFramebuffer; +extern LL_THREAD_LOCAL_GL PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glGetNamedFramebufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetNamedFramebufferAttachmentParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLCREATERENDERBUFFERSPROC glCreateRenderbuffers; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDRENDERBUFFERSTORAGEPROC glNamedRenderbufferStorage; +extern LL_THREAD_LOCAL_GL PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glNamedRenderbufferStorageMultisample; +extern LL_THREAD_LOCAL_GL PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glGetNamedRenderbufferParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLCREATETEXTURESPROC glCreateTextures; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREBUFFERPROC glTextureBuffer; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREBUFFERRANGEPROC glTextureBufferRange; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE1DPROC glTextureStorage1D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE3DPROC glTextureStorage3D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glTextureStorage2DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glTextureStorage3DMultisample; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE1DPROC glTextureSubImage1D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTURESUBIMAGE3DPROC glTextureSubImage3D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glCompressedTextureSubImage1D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glCompressedTextureSubImage2D; +extern LL_THREAD_LOCAL_GL PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glCompressedTextureSubImage3D; +extern LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE1DPROC glCopyTextureSubImage1D; +extern LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D; +extern LL_THREAD_LOCAL_GL PFNGLCOPYTEXTURESUBIMAGE3DPROC glCopyTextureSubImage3D; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERFPROC glTextureParameterf; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERFVPROC glTextureParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIPROC glTextureParameteri; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIIVPROC glTextureParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIUIVPROC glTextureParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREPARAMETERIVPROC glTextureParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGENERATETEXTUREMIPMAPPROC glGenerateTextureMipmap; +extern LL_THREAD_LOCAL_GL PFNGLBINDTEXTUREUNITPROC glBindTextureUnit; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTUREIMAGEPROC glGetTextureImage; +extern LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glGetCompressedTextureImage; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTURELEVELPARAMETERFVPROC glGetTextureLevelParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTURELEVELPARAMETERIVPROC glGetTextureLevelParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERFVPROC glGetTextureParameterfv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIIVPROC glGetTextureParameterIiv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIUIVPROC glGetTextureParameterIuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTUREPARAMETERIVPROC glGetTextureParameteriv; +extern LL_THREAD_LOCAL_GL PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays; +extern LL_THREAD_LOCAL_GL PFNGLDISABLEVERTEXARRAYATTRIBPROC glDisableVertexArrayAttrib; +extern LL_THREAD_LOCAL_GL PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYELEMENTBUFFERPROC glVertexArrayElementBuffer; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYVERTEXBUFFERPROC glVertexArrayVertexBuffer; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYVERTEXBUFFERSPROC glVertexArrayVertexBuffers; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBIFORMATPROC glVertexArrayAttribIFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYATTRIBLFORMATPROC glVertexArrayAttribLFormat; +extern LL_THREAD_LOCAL_GL PFNGLVERTEXARRAYBINDINGDIVISORPROC glVertexArrayBindingDivisor; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYIVPROC glGetVertexArrayiv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYINDEXEDIVPROC glGetVertexArrayIndexediv; +extern LL_THREAD_LOCAL_GL PFNGLGETVERTEXARRAYINDEXED64IVPROC glGetVertexArrayIndexed64iv; +extern LL_THREAD_LOCAL_GL PFNGLCREATESAMPLERSPROC glCreateSamplers; +extern LL_THREAD_LOCAL_GL PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines; +extern LL_THREAD_LOCAL_GL PFNGLCREATEQUERIESPROC glCreateQueries; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTI64VPROC glGetQueryBufferObjecti64v; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTIVPROC glGetQueryBufferObjectiv; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTUI64VPROC glGetQueryBufferObjectui64v; +extern LL_THREAD_LOCAL_GL PFNGLGETQUERYBUFFEROBJECTUIVPROC glGetQueryBufferObjectuiv; +extern LL_THREAD_LOCAL_GL PFNGLMEMORYBARRIERBYREGIONPROC glMemoryBarrierByRegion; +extern LL_THREAD_LOCAL_GL PFNGLGETTEXTURESUBIMAGEPROC glGetTextureSubImage; +extern LL_THREAD_LOCAL_GL PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glGetCompressedTextureSubImage; +extern LL_THREAD_LOCAL_GL PFNGLGETGRAPHICSRESETSTATUSPROC glGetGraphicsResetStatus; +extern LL_THREAD_LOCAL_GL PFNGLGETNCOMPRESSEDTEXIMAGEPROC glGetnCompressedTexImage; +extern LL_THREAD_LOCAL_GL PFNGLGETNTEXIMAGEPROC glGetnTexImage; +extern LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMDVPROC glGetnUniformdv; +extern LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMFVPROC glGetnUniformfv; +extern LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMIVPROC glGetnUniformiv; +extern LL_THREAD_LOCAL_GL PFNGLGETNUNIFORMUIVPROC glGetnUniformuiv; +extern LL_THREAD_LOCAL_GL PFNGLREADNPIXELSPROC glReadnPixels; +extern LL_THREAD_LOCAL_GL PFNGLGETNMAPDVPROC glGetnMapdv; +extern LL_THREAD_LOCAL_GL PFNGLGETNMAPFVPROC glGetnMapfv; +extern LL_THREAD_LOCAL_GL PFNGLGETNMAPIVPROC glGetnMapiv; +extern LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPFVPROC glGetnPixelMapfv; +extern LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPUIVPROC glGetnPixelMapuiv; +extern LL_THREAD_LOCAL_GL PFNGLGETNPIXELMAPUSVPROC glGetnPixelMapusv; +extern LL_THREAD_LOCAL_GL PFNGLGETNPOLYGONSTIPPLEPROC glGetnPolygonStipple; +extern LL_THREAD_LOCAL_GL PFNGLGETNCOLORTABLEPROC glGetnColorTable; +extern LL_THREAD_LOCAL_GL PFNGLGETNCONVOLUTIONFILTERPROC glGetnConvolutionFilter; +extern LL_THREAD_LOCAL_GL PFNGLGETNSEPARABLEFILTERPROC glGetnSeparableFilter; +extern LL_THREAD_LOCAL_GL PFNGLGETNHISTOGRAMPROC glGetnHistogram; +extern LL_THREAD_LOCAL_GL PFNGLGETNMINMAXPROC glGetnMinmax; +extern LL_THREAD_LOCAL_GL PFNGLTEXTUREBARRIERPROC glTextureBarrier; // GL_VERSION_4_6 -extern PFNGLSPECIALIZESHADERPROC glSpecializeShader; -extern PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glMultiDrawArraysIndirectCount; -extern PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glMultiDrawElementsIndirectCount; -extern PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp; +extern LL_THREAD_LOCAL_GL PFNGLSPECIALIZESHADERPROC glSpecializeShader; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glMultiDrawArraysIndirectCount; +extern LL_THREAD_LOCAL_GL PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glMultiDrawElementsIndirectCount; +extern LL_THREAD_LOCAL_GL PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp; #elif LL_DARWIN diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index bbbce1965ef..ec15709955f 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -57,6 +57,8 @@ S32 LLGLSLShader::sIndexedTextureChannels = 0; U32 LLGLSLShader::sMaxGLTFMaterials = 0; U32 LLGLSLShader::sMaxGLTFNodes = 0; bool LLGLSLShader::sProfileEnabled = false; +bool LLGLSLShader::sDeferCreation = false; + std::set LLGLSLShader::sInstances; LLGLSLShader::defines_map_t LLGLSLShader::sGlobalDefines; U64 LLGLSLShader::sTotalTimeElapsed = 0; @@ -127,6 +129,9 @@ void LLGLSLShader::finishProfile(boost::json::value& statsv) std::vector sorted(sInstances.begin(), sInstances.end()); std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed()); + // map of total time by shader source files + std::map< std::vector< std::pair< std::string, GLenum > >, U64> source_time; + auto& stats = statsv.as_object(); auto shadersit = stats.emplace("shaders", boost::json::array_kind).first; auto& shaders = shadersit->value().as_array(); @@ -141,7 +146,46 @@ void LLGLSLShader::finishProfile(boost::json::value& statsv) { auto& shaderit = shaders.emplace_back(boost::json::object_kind); ptr->dumpStats(shaderit.as_object()); + + source_time[ptr->mShaderFiles] = 0; + } + } + + for (auto ptr : sorted) + { + if (ptr->mBinds != 0) + { + source_time[ptr->mShaderFiles] += ptr->mTimeElapsed; + } + } + + // output to LL_INFOS the time spent in each shader source file as percent of total time, sorted by time + + // copy the map to a vector for sorting + std::vector>, U64>> source_time_vec; + for (auto& it : source_time) + { + source_time_vec.emplace_back(it); + } + + std::sort(source_time_vec.begin(), source_time_vec.end(), [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }); + + for (auto& it : source_time_vec) + { + auto& files = it.first; + U64 time = it.second; + // pct of total time + float pct = (float)time / (float)sTotalTimeElapsed * 100.f; + // time in ms + float ms = (float)time / 1'000'000.f; + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Shader source files: " << LL_ENDL; + for (auto& file : files) + { + LL_INFOS() << file.first << LL_ENDL; } + + LL_INFOS() << llformat("Time: %.4f ms (%.2f pct of total)", ms, pct) << LL_ENDL; } constexpr float mega = 1'000'000.f; @@ -159,6 +203,7 @@ void LLGLSLShader::finishProfile(boost::json::value& statsv) totals.emplace("triangles", sTotalTrianglesDrawn); auto unusedit = stats.emplace("unused", boost::json::array_kind).first; +#if 0 auto& unused = unusedit->value().as_array(); if (unbound) { @@ -172,6 +217,7 @@ void LLGLSLShader::finishProfile(boost::json::value& statsv) } } } +#endif } } @@ -350,6 +396,11 @@ void LLGLSLShader::unload() mFeatures = LLShaderFeatures(); unloadInternal(); + + if (mRiggedVariant && mRiggedVariant != this) + { + mRiggedVariant->unload(); + } } void LLGLSLShader::unloadInternal() @@ -405,8 +456,12 @@ void LLGLSLShader::unloadInternal() bool LLGLSLShader::createShader() { + if (sDeferCreation) + { + return true; + } LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - + LL_INFOS() << "Compiling: " << mName << LL_ENDL; unloadInternal(); sInstances.insert(this); @@ -451,6 +506,7 @@ bool LLGLSLShader::createShader() vector< pair >::iterator fileIter = mShaderFiles.begin(); for (; fileIter != mShaderFiles.end(); fileIter++) { + LL_INFOS() << fileIter->first << LL_ENDL; GLuint shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels); LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; if (shaderhandle) @@ -573,6 +629,8 @@ void dumpAttachObject(const char* func_name, GLuint program_object, const std::s bool LLGLSLShader::attachVertexObject(std::string object_path) { + LL_INFOS() << object_path << LL_ENDL; + if (LLShaderMgr::instance()->mVertexShaderObjects.count(object_path) > 0) { stop_glerror(); @@ -592,6 +650,7 @@ bool LLGLSLShader::attachVertexObject(std::string object_path) bool LLGLSLShader::attachFragmentObject(std::string object_path) { + LL_INFOS() << object_path << LL_ENDL; if(mUsingBinaryProgram) return true; @@ -999,10 +1058,12 @@ bool LLGLSLShader::mapUniforms() // See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf const char* ubo_names[] = { - "ReflectionProbes", // UB_REFLECTION_PROBES - "GLTFJoints", // UB_GLTF_JOINTS - "GLTFNodes", // UB_GLTF_NODES - "GLTFMaterials", // UB_GLTF_MATERIALS + "ReflectionProbes", // UB_REFLECTION_PROBES + "GLTFJoints", // UB_GLTF_JOINTS + "GLTFNodes", // UB_GLTF_NODES + "GLTFNodeInstanceMap", // UB_GLTF_NODE_INSTANCE_MAP + "GLTFMaterials", // UB_GLTF_MATERIALS + "TextureTransform", // UB_TEXTURE_TRANSFORM }; llassert(LL_ARRAY_SIZE(ubo_names) == NUM_UNIFORM_BLOCKS); @@ -1026,7 +1087,7 @@ bool LLGLSLShader::mapUniforms() bool LLGLSLShader::link(bool suppress_errors) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - + LL_INFOS() << "Linking " << mName << LL_ENDL; bool success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors); if (!success && !suppress_errors) @@ -1046,7 +1107,15 @@ void LLGLSLShader::bind() { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - llassert(mProgramObject != 0); + if (mProgramObject == 0) + { + LL_INFOS() << "JIT Shader creation: " << mName << LL_ENDL; + bool old_defer = sDeferCreation; + sDeferCreation = false; + unbind(); + createShader(); + sDeferCreation = old_defer; + } gGL.flush(); @@ -1189,6 +1258,18 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLRenderTarget* texture, bool depth, return uniform; } +S32 LLGLSLShader::bindTexName(S32 uniform, U32 texName, LLTexUnit::eTextureType mode) +{ + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->bindManualFast(mode, texName); + } + + return uniform; +} + S32 LLGLSLShader::bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -1311,6 +1392,11 @@ void LLGLSLShader::uniform1i(U32 index, GLint x) } } +void LLGLSLShader::uniform1iFast(U32 index, GLint i) +{ + glUniform1i(mUniform[index], i); +} + void LLGLSLShader::uniform1f(U32 index, GLfloat x) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index c24daaf686b..fcee5a27942 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -66,7 +66,6 @@ class LLGLSLShader; class LLShaderUniforms { public: - template struct UniformSetting { @@ -148,10 +147,12 @@ class LLGLSLShader enum UniformBlock : GLuint { - UB_REFLECTION_PROBES, // "ReflectionProbes" - UB_GLTF_JOINTS, // "GLTFJoints" - UB_GLTF_NODES, // "GLTFNodes" - UB_GLTF_MATERIALS, // "GLTFMaterials" + UB_REFLECTION_PROBES, // "ReflectionProbes" + UB_GLTF_JOINTS, // "GLTFJoints" + UB_GLTF_NODES, // "GLTFNodes" + UB_GLTF_NODE_INSTANCE_MAP, // "GLTFNodeInstanceMap" + UB_GLTF_MATERIALS, // "GLTFMaterials" + UB_TEXTURE_TRANSFORM, // "TextureTransform" NUM_UNIFORM_BLOCKS }; @@ -159,6 +160,9 @@ class LLGLSLShader static std::set sInstances; static bool sProfileEnabled; + // if true, createShader() will defer shader creation until the first bind() + static bool sDeferCreation; + LLGLSLShader(); ~LLGLSLShader(); @@ -228,6 +232,12 @@ class LLGLSLShader void uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v); void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v); + // Unsafe but fast versions of uniform setters + // Don't check dirty state or update dirty state + // Don't check for valid uniform location + // Don't check for valid index + void uniform1iFast(U32 index, GLint i); + void setMinimumAlpha(F32 minimum); void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); @@ -268,6 +278,7 @@ class LLGLSLShader S32 bindTextureImageGL(S32 uniform, LLImageGL* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR); S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0); + S32 bindTexName(S32 uniform, U32 texName, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); @@ -354,6 +365,8 @@ class LLGLSLShader std::vector mGLTFVariants; + + //helper to bind GLTF variant void bind(U8 variant); diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index c2298d53772..4039f3614b1 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -410,12 +410,6 @@ F32 LLGLTexture::getTimePassedSinceLastBound() return mGLTexturep->getTimePassedSinceLastBound() ; } -bool LLGLTexture::getMissed() const -{ - llassert(mGLTexturep.notNull()) ; - - return mGLTexturep->getMissed() ; -} bool LLGLTexture::isJustBound() const { diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 22f2ed51315..0bae4e0b032 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -152,7 +152,6 @@ class LLGLTexture : public LLTexture LLTexUnit::eTextureType getTarget(void) const ; bool getMask(const LLVector2 &tc); F32 getTimePassedSinceLastBound(); - bool getMissed() const ; bool isJustBound()const ; void forceUpdateBindStats(void) const; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 05362165ff8..3d224a75970 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -25,7 +25,7 @@ */ -// TODO: create 2 classes for images w/ and w/o discard levels? + // TODO: create 2 classes for images w/ and w/o discard levels? #include "linden_common.h" @@ -60,12 +60,18 @@ U32 wpo2(U32 i); U32 LLImageGL::sFrameCount = 0; +U32 LLImageGL::sTexNames[U16_MAX+1]; +std::stack LLImageGL::sFreeTexIDs; +U16 LLImageGL::sNextTexID = 1; //start at 1... zero is reserved for "no texture" + +std::function LLImageGL::sTexNameReferenceCheck = [](U32) {}; // texture memory accounting (for macOS) static LLMutex sTexMemMutex; static std::unordered_map sTextureAllocs; static U64 sTextureBytes = 0; + // track a texture alloc on the currently bound texture. // asserts that no currently tracked alloc exists void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count) @@ -134,13 +140,13 @@ U64 LLImageGL::getTextureBytesAllocated() //statics -U32 LLImageGL::sUniqueCount = 0; -U32 LLImageGL::sBindCount = 0; -S32 LLImageGL::sCount = 0; +U32 LLImageGL::sUniqueCount = 0; +U32 LLImageGL::sBindCount = 0; +S32 LLImageGL::sCount = 0; -bool LLImageGL::sGlobalUseAnisotropic = false; -F32 LLImageGL::sLastFrameTime = 0.f; -LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; +bool LLImageGL::sGlobalUseAnisotropic = false; +F32 LLImageGL::sLastFrameTime = 0.f; +LLImageGL* LLImageGL::sDefaultGLTexture = NULL; bool LLImageGL::sCompressTextures = false; std::unordered_set LLImageGL::sImageList; @@ -153,9 +159,9 @@ bool LLImageGLThread::sEnabledMedia = false; //**************************************************************************************************** //----------------------- //debug use -S32 LLImageGL::sCurTexSizeBar = -1 ; -S32 LLImageGL::sCurTexPickSize = -1 ; -S32 LLImageGL::sMaxCategories = 1 ; +S32 LLImageGL::sCurTexSizeBar = -1; +S32 LLImageGL::sCurTexPickSize = -1; +S32 LLImageGL::sMaxCategories = 1; //optimization for when we don't need to calculate mIsMask bool LLImageGL::sSkipAnalyzeAlpha; @@ -179,17 +185,17 @@ void LLImageGL::checkTexSize(bool forced) const { { //check viewport - GLint vp[4] ; - glGetIntegerv(GL_VIEWPORT, vp) ; - llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ; + GLint vp[4]; + glGetIntegerv(GL_VIEWPORT, vp); + llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl; } GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); bool error = false; - if (texname != mTexName) + if (texname != getTexName()) { - LL_INFOS() << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << LL_ENDL; + LL_INFOS() << "Bound: " << texname << " Should bind: " << getTexName() << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << LL_ENDL; error = true; if (gDebugSession) @@ -201,18 +207,18 @@ void LLImageGL::checkTexSize(bool forced) const LL_ERRS() << "Invalid texture bound!" << LL_ENDL; } } - stop_glerror() ; - LLGLint x = 0, y = 0 ; + stop_glerror(); + LLGLint x = 0, y = 0; glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_WIDTH, (GLint*)&x); - glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y) ; - stop_glerror() ; - llcallstacks << "w: " << x << " h: " << y << llcallstacksendl ; + glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y); + stop_glerror(); + llcallstacks << "w: " << x << " h: " << y << llcallstacksendl; - if(!x || !y) + if (!x || !y) { - return ; + return; } - if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) + if (x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) { error = true; if (gDebugSession) @@ -223,7 +229,7 @@ void LLImageGL::checkTexSize(bool forced) const else { LL_ERRS() << "wrong texture size and discard level: width: " << - mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << LL_ENDL ; + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << LL_ENDL; } } @@ -240,9 +246,9 @@ void LLImageGL::checkTexSize(bool forced) const bool is_little_endian() { S32 a = 0x12345678; - U8 *c = (U8*)(&a); + U8* c = (U8*)(&a); - return (*c == 0x78) ; + return (*c == 0x78); } //static @@ -251,6 +257,8 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sSkipAnalyzeAlpha = skip_analyze_alpha; + sTexNames[0] = 0; + if (sScratchPBO == 0) { glGenBuffers(1, &sScratchPBO); @@ -367,8 +375,8 @@ S64 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) default: break; } - S64 bytes (((S64)width * (S64)height * (S64)dataFormatBits(dataformat)+7)>>3); - S64 aligned = (bytes+3)&~3; + S64 bytes(((S64)width * (S64)height * (S64)dataFormatBits(dataformat) + 7) >> 3); + S64 aligned = (bytes + 3) & ~3; return aligned; } @@ -377,24 +385,24 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) { switch (dataformat) { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 3; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; - case GL_LUMINANCE: return 1; - case GL_ALPHA: return 1; - case GL_RED: return 1; - case GL_COLOR_INDEX: return 1; - case GL_LUMINANCE_ALPHA: return 2; - case GL_RG: return 2; - case GL_RGB: return 3; - case GL_SRGB: return 3; - case GL_RGBA: return 4; - case GL_SRGB_ALPHA: return 4; - case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac - default: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 3; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; + case GL_LUMINANCE: return 1; + case GL_ALPHA: return 1; + case GL_RED: return 1; + case GL_COLOR_INDEX: return 1; + case GL_LUMINANCE_ALPHA: return 2; + case GL_RG: return 2; + case GL_RGB: return 3; + case GL_SRGB: return 3; + case GL_RGBA: return 4; + case GL_SRGB_ALPHA: return 4; + case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac + default: LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL; return 0; } @@ -456,8 +464,31 @@ bool LLImageGL::create(LLPointer& dest, const LLImageRaw* imageraw, b //---------------------------------------------------------------------------- +// static +U16 LLImageGL::allocTexID() +{ + if (sFreeTexIDs.empty()) + { + llassert_always(sNextTexID < U16_MAX); + return sNextTexID++; + } + else + { + U16 id = sFreeTexIDs.top(); + sFreeTexIDs.pop(); + return id; + } +} + +//static +void LLImageGL::freeTexID(U16 id) +{ + sFreeTexIDs.push(id); +} + + LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true*/) -: mSaveData(0), mExternalTexture(false) + : mSaveData(0), mExternalTexture(false), mTexID(allocTexID()) { init(usemipmaps, allow_compression); setSize(0, 0, 0); @@ -466,9 +497,9 @@ LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true } LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = true*/, bool allow_compression/* = true*/) -: mSaveData(0), mExternalTexture(false) + : mSaveData(0), mExternalTexture(false), mTexID(allocTexID()) { - llassert( components <= 4 ); + llassert(components <= 4); init(usemipmaps, allow_compression); setSize(width, height, components); sImageList.insert(this); @@ -476,7 +507,7 @@ LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = t } LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps/* = true*/, bool allow_compression/* = true*/) -: mSaveData(0), mExternalTexture(false) + : mSaveData(0), mExternalTexture(false), mTexID(allocTexID()) { init(usemipmaps, allow_compression); setSize(0, 0, 0); @@ -494,9 +525,11 @@ LLImageGL::LLImageGL( LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode) + : mTexID(allocTexID()) { init(false, true); - mTexName = texName; + llassert(!gDebugGL || glIsTexture(texName)); + setTexName(texName); mTarget = target; mComponents = components; mAddressMode = addressMode; @@ -508,6 +541,7 @@ LLImageGL::LLImageGL( LLImageGL::~LLImageGL() { + freeTexID(mTexID); if (!mExternalTexture && gGLManager.mInited) { LLImageGL::cleanup(); @@ -537,12 +571,12 @@ void LLImageGL::init(bool usemipmaps, bool allow_compression) mHasExplicitFormat = false; mIsMask = false; - mNeedsAlphaAndPickMask = true ; - mAlphaStride = 0 ; - mAlphaOffset = 0 ; + mNeedsAlphaAndPickMask = true; + mAlphaStride = 0; + mAlphaOffset = 0; - mGLTextureCreated = false ; - mTexName = 0; + mGLTextureCreated = false; + setTexName(0); mWidth = 0; mHeight = 0; mCurrentDiscardLevel = -1; @@ -554,8 +588,6 @@ void LLImageGL::init(bool usemipmaps, bool allow_compression) mHasMipMaps = false; mMipLevels = -1; - mIsResident = 0; - mComponents = 0; mMaxDiscardLevel = MAX_DISCARD_LEVEL; @@ -564,7 +596,7 @@ void LLImageGL::init(bool usemipmaps, bool allow_compression) mFilterOption = LLTexUnit::TFO_ANISOTROPIC; mFormatInternal = -1; - mFormatPrimary = (LLGLenum) 0; + mFormatPrimary = (LLGLenum)0; mFormatType = GL_UNSIGNED_BYTE; mFormatSwapBytes = false; @@ -595,15 +627,15 @@ void LLImageGL::cleanup() //so dim should be a positive number static bool check_power_of_two(S32 dim) { - if(dim < 0) + if (dim < 0) { - return false ; + return false; } - if(!dim)//0 is a power-of-two number + if (!dim)//0 is a power-of-two number { - return true ; + return true; } - return !(dim & (dim - 1)) ; + return !(dim & (dim - 1)); } //static @@ -619,7 +651,7 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve // Check if dimensions are a power of two! if (!checkSize(width, height)) { - LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; + LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d", width, height) << LL_ENDL; return false; } @@ -636,7 +668,7 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve height >>= 1; } - if(discard_level > 0) + if (discard_level > 0) { mMaxDiscardLevel = llmax(mMaxDiscardLevel, (S8)discard_level); } @@ -656,26 +688,25 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve void LLImageGL::dump() { LL_INFOS() << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) - << " mLastBindTime " << mLastBindTime - << " mTarget " << S32(mTarget) - << " mBindTarget " << S32(mBindTarget) - << " mUseMipMaps " << S32(mUseMipMaps) - << " mHasMipMaps " << S32(mHasMipMaps) - << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel) - << " mFormatInternal " << S32(mFormatInternal) - << " mFormatPrimary " << S32(mFormatPrimary) - << " mFormatType " << S32(mFormatType) - << " mFormatSwapBytes " << S32(mFormatSwapBytes) - << " mHasExplicitFormat " << S32(mHasExplicitFormat) + << " mLastBindTime " << mLastBindTime + << " mTarget " << S32(mTarget) + << " mBindTarget " << S32(mBindTarget) + << " mUseMipMaps " << S32(mUseMipMaps) + << " mHasMipMaps " << S32(mHasMipMaps) + << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel) + << " mFormatInternal " << S32(mFormatInternal) + << " mFormatPrimary " << S32(mFormatPrimary) + << " mFormatType " << S32(mFormatType) + << " mFormatSwapBytes " << S32(mFormatSwapBytes) + << " mHasExplicitFormat " << S32(mHasExplicitFormat) #if DEBUG_MISS - << " mMissed " << mMissed + << " mMissed " << mMissed #endif - << LL_ENDL; + << LL_ENDL; LL_INFOS() << " mTextureMemory " << mTextureMemory - << " mTexNames " << mTexName - << " mIsResident " << S32(mIsResident) - << LL_ENDL; + << " mTexNames " << getTexName() + << LL_ENDL; } //---------------------------------------------------------------------------- @@ -686,10 +717,10 @@ void LLImageGL::forceUpdateBindStats(void) const bool LLImageGL::updateBindStats() const { - if (mTexName != 0) + if (getTexName() != 0) { #ifdef DEBUG_MISS - mMissed = ! getIsResident(true); + mMissed = !getIsResident(true); #endif sBindCount++; if (mLastBindTime != sLastFrameTime) @@ -698,31 +729,31 @@ bool LLImageGL::updateBindStats() const sUniqueCount++; mLastBindTime = sLastFrameTime; - return true ; + return true; } } - return false ; + return false; } F32 LLImageGL::getTimePassedSinceLastBound() { - return sLastFrameTime - mLastBindTime ; + return sLastFrameTime - mLastBindTime; } -void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, bool swap_bytes ) +void LLImageGL::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, bool swap_bytes) { // Note: must be called before createTexture() // Note: it's up to the caller to ensure that the format matches the number of components. mHasExplicitFormat = true; mFormatInternal = internal_format; mFormatPrimary = primary_format; - if(type_format == 0) + if (type_format == 0) mFormatType = GL_UNSIGNED_BYTE; else mFormatType = type_format; mFormatSwapBytes = swap_bytes; - calcAlphaChannelOffsetAndStride() ; + calcAlphaChannelOffsetAndStride(); } //---------------------------------------------------------------------------- @@ -731,8 +762,8 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) && - (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && - (imageraw->getComponents() == getComponents())); + (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && + (imageraw->getComponents() == getComponents())); const U8* rawdata = imageraw->getData(); setImage(rawdata, false); } @@ -772,12 +803,12 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 { // NOTE: data_in points to largest image; smaller images // are stored BEFORE the largest image - for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++) + for (S32 d = mCurrentDiscardLevel; d <= mMaxDiscardLevel; d++) { S32 w = getWidth(d); S32 h = getHeight(d); - S32 gl_level = d-mCurrentDiscardLevel; + S32 gl_level = d - mCurrentDiscardLevel; mMipLevels = llmax(mMipLevels, gl_level); @@ -788,12 +819,12 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 if (is_compressed) { GLsizei tex_size = (GLsizei)dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid*)data_in); stop_glerror(); } else { - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); @@ -806,7 +837,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 } updatePickMask(w, h, data_in); - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); @@ -823,7 +854,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 { stop_glerror(); { - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); @@ -843,15 +874,15 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 } LLImageGL::setManualImage(mTarget, 0, mFormatInternal, - w, h, - mFormatPrimary, mFormatType, - data_in, mAllowCompression); + w, h, + mFormatPrimary, mFormatType, + data_in, mAllowCompression); analyzeAlpha(data_in, w, h); stop_glerror(); updatePickMask(w, h, data_in); - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); @@ -885,9 +916,9 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 #endif mMipLevels = nummips; - for (int m=0; m 0 && h > 0 && cur_mip_data); (void)cur_mip_data; { - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); @@ -957,7 +988,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 updatePickMask(w, h, cur_mip_data); } - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); @@ -991,26 +1022,26 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32 if (is_compressed) { GLsizei tex_size = (GLsizei)dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid*)data_in); stop_glerror(); } else { - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); } LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, - mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression); + mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression); analyzeAlpha(data_in, w, h); updatePickMask(w, h, data_in); stop_glerror(); - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); @@ -1116,7 +1147,7 @@ bool LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 { return true; } - LLGLuint tex_name = use_name != 0 ? use_name : mTexName; + LLGLuint tex_name = use_name != 0 ? use_name : getTexName(); if (0 == tex_name) { // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 @@ -1150,13 +1181,13 @@ bool LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 { dump(); LL_ERRS() << "Subimage not wholly in target image!" - << " x_pos " << x_pos - << " y_pos " << y_pos - << " width " << width - << " height " << height - << " getWidth() " << getWidth() - << " getHeight() " << getHeight() - << LL_ENDL; + << " x_pos " << x_pos + << " y_pos " << y_pos + << " width " << width + << " height " << height + << " getWidth() " << getWidth() + << " getHeight() " << getHeight() + << LL_ENDL; } if ((x_pos + width) > data_width || @@ -1164,20 +1195,20 @@ bool LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 { dump(); LL_ERRS() << "Subimage not wholly in source image!" - << " x_pos " << x_pos - << " y_pos " << y_pos - << " width " << width - << " height " << height - << " source_width " << data_width - << " source_height " << data_height - << LL_ENDL; + << " x_pos " << x_pos + << " y_pos " << y_pos + << " width " << width + << " height " << height + << " source_width " << data_width + << " source_height " << data_height + << LL_ENDL; } glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width); stop_glerror(); - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); @@ -1205,7 +1236,7 @@ bool LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 gGL.getTexUnit(0)->disable(); stop_glerror(); - if(mFormatSwapBytes) + if (mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); @@ -1241,7 +1272,7 @@ bool LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static -void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +void LLImageGL::generateTextures(S32 numTextures, U32* textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static constexpr U32 pool_size = 1024; @@ -1276,7 +1307,7 @@ void LLImageGL::updateClass() } // static -void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) +void LLImageGL::deleteTextures(S32 numTextures, const U32* textures) { // wait a few frames before actually deleting the textures to avoid // synchronization issues with the GPU @@ -1290,13 +1321,20 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) for (S32 i = 0; i < numTextures; ++i) { sFreeList[idx].push_back(textures[i]); + +#if 1 //enable for paranoia check on deleting texNames + if (gDebugGL) + { + sTexNameReferenceCheck(textures[i]); + } +#endif } idx = (sFrameCount + 3) % 4; if (!sFreeList[idx].empty()) { - free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data()); + free_tex_images((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); sFreeList[idx].resize(0); } @@ -1494,27 +1532,23 @@ bool LLImageGL::createGLTexture() return false; } - mGLTextureCreated = false ; //do not save this texture when gl is destroyed. + mGLTextureCreated = false; //do not save this texture when gl is destroyed. llassert(gGLManager.mInited); stop_glerror(); - if(mTexName) - { - LLImageGL::deleteTextures(1, (reinterpret_cast(&mTexName))) ; - mTexName = 0; - } - + U32 tmp_texname = 0; + LLImageGL::generateTextures(1, &tmp_texname); + setTexName(tmp_texname, true); - LLImageGL::generateTextures(1, &mTexName); stop_glerror(); - if (!mTexName) + if (!getTexName()) { LL_WARNS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL; return false; } - return true ; + return true; } bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, bool to_create, S32 category, bool defer_copy, LLGLuint* tex_name) @@ -1545,8 +1579,8 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S } // Actual image width/height = raw image width/height * 2^discard_level - S32 raw_w = imageraw->getWidth() ; - S32 raw_h = imageraw->getHeight() ; + S32 raw_w = imageraw->getWidth(); + S32 raw_h = imageraw->getHeight(); S32 w = raw_w << discard_level; S32 h = raw_h << discard_level; @@ -1561,14 +1595,14 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S if (mHasExplicitFormat && ((mFormatPrimary == GL_RGBA && mComponents < 4) || - (mFormatPrimary == GL_RGB && mComponents < 3))) + (mFormatPrimary == GL_RGB && mComponents < 3))) { - LL_WARNS() << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents << LL_ENDL; + LL_WARNS() << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents << LL_ENDL; mHasExplicitFormat = false; } - if( !mHasExplicitFormat ) + if (!mHasExplicitFormat) { switch (mComponents) { @@ -1598,16 +1632,16 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S LL_ERRS() << "Bad number of components for texture: " << (U32)getComponents() << LL_ENDL; } - calcAlphaChannelOffsetAndStride() ; + calcAlphaChannelOffsetAndStride(); } - if(!to_create) //not create a gl texture + if (!to_create) //not create a gl texture { destroyGLTexture(); mCurrentDiscardLevel = discard_level; mLastBindTime = sLastFrameTime; mGLTextureCreated = false; - return true ; + return true; } setCategory(category); @@ -1644,18 +1678,18 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_ if (main_thread // <--- always force creation of new_texname when not on main thread ... && !defer_copy // <--- ... or defer copy is set - && mTexName != 0 && discard_level == mCurrentDiscardLevel) + && getTexName() != 0 && discard_level == mCurrentDiscardLevel) { LL_PROFILE_ZONE_NAMED("cglt - early setImage"); // This will only be true if the size has not changed if (tex_name != nullptr) { - *tex_name = mTexName; + *tex_name = getTexName(); } return setImage(data_in, data_hasmips); } - GLuint old_texname = mTexName; + GLuint old_texname = getTexName(); GLuint new_texname = 0; if (usename != 0) { @@ -1709,12 +1743,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_ } else { - //not on background thread, immediately set mTexName - if (old_texname != 0 && old_texname != new_texname) - { - LLImageGL::deleteTextures(1, &old_texname); - } - mTexName = new_texname; + setTexName(new_texname, true); } } @@ -1783,15 +1812,27 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) } -void LLImageGL::syncTexName(LLGLuint texname) +void LLImageGL::setTexName(GLuint texName, bool delete_old) { - if (texname != 0) + if (texName != getTexName()) { - if (mTexName != 0 && mTexName != texname) + U32 old_texname = mTexName; + mTexName = texName; + sTexNames[mTexID] = mTexName; + + //not on background thread, immediately set mTexName + if (delete_old && old_texname) { - LLImageGL::deleteTextures(1, &mTexName); + LLImageGL::deleteTextures(1, &old_texname); } - mTexName = texname; + } +} + +void LLImageGL::syncTexName(LLGLuint texname) +{ + if (texname != 0) + { + setTexName(texname, true); } } @@ -1804,7 +1845,7 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre discard_level = mCurrentDiscardLevel; } - if (mTexName == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel ) + if (getTexName() == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel) { return false; } @@ -1813,7 +1854,7 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre //explicitly unbind texture gGL.getTexUnit(0)->unbind(mBindTarget); - llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName)); + llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, getTexName())); //debug code, leave it there commented. //checkTexSize() ; @@ -1833,17 +1874,17 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre { return false; } - if(width < glwidth) + if (width < glwidth) { - LL_WARNS() << "texture size is smaller than it should be." << LL_ENDL ; + LL_WARNS() << "texture size is smaller than it should be." << LL_ENDL; LL_WARNS() << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth << - " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << LL_ENDL ; - return false ; + " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << LL_ENDL; + return false; } if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4) { - LL_ERRS() << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << LL_ENDL; + LL_ERRS() << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d", width, height, ncomponents) << LL_ENDL; } LLGLint is_compressed = 0; @@ -1853,10 +1894,10 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre } //----------------------------------------------------------------------------------------------- - GLenum error ; - while((error = glGetError()) != GL_NO_ERROR) + GLenum error; + while ((error = glGetError()) != GL_NO_ERROR) { - LL_WARNS() << "GL Error happens before reading back texture. Error code: " << error << LL_ENDL ; + LL_WARNS() << "GL Error happens before reading back texture. Error code: " << error << LL_ENDL; } //----------------------------------------------------------------------------------------------- @@ -1866,11 +1907,11 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre { LLGLint glbytes; glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes); - if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes)) + if (!imageraw->allocateDataSize(width, height, ncomponents, glbytes)) { - LL_WARNS() << "Memory allocation failed for reading back texture. Size is: " << glbytes << LL_ENDL ; - LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; - return false ; + LL_WARNS() << "Memory allocation failed for reading back texture. Size is: " << glbytes << LL_ENDL; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL; + return false; } glGetCompressedTexImage(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); @@ -1878,11 +1919,11 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre } else { - if(!imageraw->allocateDataSize(width, height, ncomponents)) + if (!imageraw->allocateDataSize(width, height, ncomponents)) { - LL_WARNS() << "Memory allocation failed for reading back texture." << LL_ENDL ; - LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; - return false ; + LL_WARNS() << "Memory allocation failed for reading back texture." << LL_ENDL; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL; + return false; } glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData())); @@ -1890,38 +1931,38 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre } //----------------------------------------------------------------------------------------------- - if((error = glGetError()) != GL_NO_ERROR) + if ((error = glGetError()) != GL_NO_ERROR) { - LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; - imageraw->deleteData() ; + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL; + imageraw->deleteData(); - while((error = glGetError()) != GL_NO_ERROR) + while ((error = glGetError()) != GL_NO_ERROR) { - LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL; } - return false ; + return false; } //----------------------------------------------------------------------------------------------- - return true ; + return true; } void LLImageGL::destroyGLTexture() { checkActiveThread(); - if (mTexName != 0) + if (getTexName() != 0) { - if(mTextureMemory != S64Bytes(0)) + if (mTextureMemory != S64Bytes(0)) { mTextureMemory = (S64Bytes)0; } - LLImageGL::deleteTextures(1, &mTexName); - mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. - mTexName = 0; - mGLTextureCreated = false ; + mCurrentDiscardLevel = -1; //invalidate mCurrentDiscardLevel. + + setTexName(0, true); + mGLTextureCreated = false; } } @@ -1929,13 +1970,13 @@ void LLImageGL::destroyGLTexture() void LLImageGL::forceToInvalidateGLTexture() { checkActiveThread(); - if (mTexName != 0) + if (getTexName() != 0) { destroyGLTexture(); } else { - mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + mCurrentDiscardLevel = -1; //invalidate mCurrentDiscardLevel. } } @@ -1949,7 +1990,7 @@ void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) mAddressMode = mode; } - if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == getTexName()) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode); mTexOptionsDirty = false; @@ -1964,7 +2005,7 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) mFilterOption = option; } - if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + if (getTexName() != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == getTexName()) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); mTexOptionsDirty = false; @@ -1972,23 +2013,6 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) } } -bool LLImageGL::getIsResident(bool test_now) -{ - if (test_now) - { - if (mTexName != 0) - { - glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident); - } - else - { - mIsResident = false; - } - } - - return mIsResident; -} - S32 LLImageGL::getHeight(S32 discard_level) const { if (discard_level < 0) @@ -2017,8 +2041,8 @@ S64 LLImageGL::getBytes(S32 discard_level) const { discard_level = mCurrentDiscardLevel; } - S32 w = mWidth>>discard_level; - S32 h = mHeight>>discard_level; + S32 w = mWidth >> discard_level; + S32 h = mHeight >> discard_level; if (w == 0) w = 1; if (h == 0) h = 1; return dataFormatBytes(mFormatPrimary, w, h); @@ -2030,8 +2054,8 @@ S64 LLImageGL::getMipBytes(S32 discard_level) const { discard_level = mCurrentDiscardLevel; } - S32 w = mWidth>>discard_level; - S32 h = mHeight>>discard_level; + S32 w = mWidth >> discard_level; + S32 h = mHeight >> discard_level; S64 res = dataFormatBytes(mFormatPrimary, w, h); if (mUseMipMaps) { @@ -2067,20 +2091,20 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b mBindTarget = bind_target; } -const S8 INVALID_OFFSET = -99 ; +const S8 INVALID_OFFSET = -99; void LLImageGL::setNeedsAlphaAndPickMask(bool need_mask) { - if(mNeedsAlphaAndPickMask != need_mask) + if (mNeedsAlphaAndPickMask != need_mask) { mNeedsAlphaAndPickMask = need_mask; - if(mNeedsAlphaAndPickMask) + if (mNeedsAlphaAndPickMask) { - mAlphaOffset = 0 ; + mAlphaOffset = 0; } else //do not need alpha mask { - mAlphaOffset = INVALID_OFFSET ; + mAlphaOffset = INVALID_OFFSET; mIsMask = false; } } @@ -2088,12 +2112,12 @@ void LLImageGL::setNeedsAlphaAndPickMask(bool need_mask) void LLImageGL::calcAlphaChannelOffsetAndStride() { - if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask + if (mAlphaOffset == INVALID_OFFSET)//do not need alpha mask { - return ; + return; } - mAlphaStride = -1 ; + mAlphaStride = -1; switch (mFormatPrimary) { case GL_LUMINANCE: @@ -2120,50 +2144,50 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() break; } - mAlphaOffset = -1 ; + mAlphaOffset = -1; if (mFormatType == GL_UNSIGNED_BYTE) { - mAlphaOffset = mAlphaStride - 1 ; + mAlphaOffset = mAlphaStride - 1; } - else if(is_little_endian()) + else if (is_little_endian()) { if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) { - mAlphaOffset = 0 ; + mAlphaOffset = 0; } else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) { - mAlphaOffset = 3 ; + mAlphaOffset = 3; } } else //big endian { if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) { - mAlphaOffset = 3 ; + mAlphaOffset = 3; } else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) { - mAlphaOffset = 0 ; + mAlphaOffset = 0; } } - if( mAlphaStride < 1 || //unsupported format + if (mAlphaStride < 1 || //unsupported format mAlphaOffset < 0 || //unsupported type (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation { LL_WARNS() << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << LL_ENDL; - mNeedsAlphaAndPickMask = false ; + mNeedsAlphaAndPickMask = false; mIsMask = false; } } void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) { - if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) + if (sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) { - return ; + return; } LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -2172,7 +2196,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) U32 alphatotal = 0; U32 sample[16]; - memset(sample, 0, sizeof(U32)*16); + memset(sample, 0, sizeof(U32) * 16); // generate histogram of quantized alpha. // also add-in the histogram of a 2x2 box-sampled version. The idea is @@ -2200,14 +2224,14 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) alphatotal += s4; current += mAlphaStride; - ++sample[s1/16]; - ++sample[s2/16]; - ++sample[s3/16]; - ++sample[s4/16]; + ++sample[s1 / 16]; + ++sample[s2 / 16]; + ++sample[s3 / 16]; + ++sample[s4 / 16]; - const U32 asum = (s1+s2+s3+s4); + const U32 asum = (s1 + s2 + s3 + s4); alphatotal += asum; - sample[asum/(16*4)] += 4; + sample[asum / (16 * 4)] += 4; } rowstart += 2 * w * mAlphaStride; @@ -2216,12 +2240,12 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) } else { - const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; + const GLubyte* current = ((const GLubyte*)data_in) + mAlphaOffset; for (U32 i = 0; i < length; i++) { const U32 s1 = *current; alphatotal += s1; - ++sample[s1/16]; + ++sample[s1 / 16]; current += mAlphaStride; } } @@ -2249,9 +2273,9 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) upperhalftotal += sample[i]; } - if (midrangetotal > length/48 || // lots of midrange, or + if (midrangetotal > length / 48 || // lots of midrange, or (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or - (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque + (upperhalftotal == length && alphatotal != 255 * length)) // all close to opaque but not all totally opaque { mIsMask = false; // not suitable for masking } @@ -2266,8 +2290,8 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; freePickMask(); - U32 pick_width = pWidth/2 + 1; - U32 pick_height = pHeight/2 + 1; + U32 pick_width = pWidth / 2 + 1; + U32 pick_height = pHeight / 2 + 1; U32 size = pick_width * pick_height; size = (size + 7) / 8; // pixelcount-to-bits @@ -2285,7 +2309,7 @@ void LLImageGL::freePickMask() { if (mPickMask != NULL) { - delete [] mPickMask; + delete[] mPickMask; } mPickMask = NULL; mPickMaskWidth = mPickMaskHeight = 0; @@ -2315,14 +2339,14 @@ bool LLImageGL::isCompressed() //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { - if(!mNeedsAlphaAndPickMask) + if (!mNeedsAlphaAndPickMask) { - return ; + return; } if (mFormatType != GL_UNSIGNED_BYTE || ((mFormatPrimary != GL_RGBA) - && (mFormatPrimary != GL_SRGB_ALPHA))) + && (mFormatPrimary != GL_SRGB_ALPHA))) { //cannot generate a pick mask for this texture freePickMask(); @@ -2342,12 +2366,12 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { for (S32 x = 0; x < width; x += 2) { - U8 alpha = data_in[(y*width+x)*4+3]; + U8 alpha = data_in[(y * width + x) * 4 + 3]; if (alpha > 32) { - U32 pick_idx = pick_bit/8; - U32 pick_offset = pick_bit%8; + U32 pick_idx = pick_bit / 8; + U32 pick_offset = pick_bit % 8; llassert(pick_idx < pickSize); mPickMask[pick_idx] |= 1 << pick_offset; @@ -2358,13 +2382,13 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) } } -bool LLImageGL::getMask(const LLVector2 &tc) +bool LLImageGL::getMask(const LLVector2& tc) { bool res = true; if (mPickMask) { - F32 u,v; + F32 u, v; if (LL_LIKELY(tc.isFinite())) { u = tc.mV[0] - floorf(tc.mV[0]); @@ -2379,7 +2403,7 @@ bool LLImageGL::getMask(const LLVector2 &tc) } if (LL_UNLIKELY(u < 0.f || u > 1.f || - v < 0.f || v > 1.f)) + v < 0.f || v > 1.f)) { LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; u = v = 0.f; @@ -2401,10 +2425,10 @@ bool LLImageGL::getMask(const LLVector2 &tc) y = llmax((U16)0, mPickMaskHeight); } - S32 idx = y*mPickMaskWidth+x; - S32 offset = idx%8; + S32 idx = y * mPickMaskWidth + x; + S32 offset = idx % 8; - res = (mPickMask[idx/8] & (1 << offset)) != 0; + res = (mPickMask[idx / 8] & (1 << offset)) != 0; } return res; @@ -2412,21 +2436,21 @@ bool LLImageGL::getMask(const LLVector2 &tc) void LLImageGL::setCurTexSizebar(S32 index, bool set_pick_size) { - sCurTexSizeBar = index ; + sCurTexSizeBar = index; - if(set_pick_size) + if (set_pick_size) { - sCurTexPickSize = (1 << index) ; + sCurTexPickSize = (1 << index); } else { - sCurTexPickSize = -1 ; + sCurTexPickSize = -1; } } void LLImageGL::resetCurTexSizebar() { - sCurTexSizeBar = -1 ; - sCurTexPickSize = -1 ; + sCurTexSizeBar = -1; + sCurTexPickSize = -1; } bool LLImageGL::scaleDown(S32 desired_discard) @@ -2526,7 +2550,6 @@ bool LLImageGL::scaleDown(S32 desired_discard) return true; } - //---------------------------------------------------------------------------- #if LL_IMAGEGL_THREAD_CHECK void LLImageGL::checkActiveThread() @@ -2589,7 +2612,7 @@ void LLImageGL::checkActiveThread() */ LLImageGLThread::LLImageGLThread(LLWindow* window) - // We want exactly one thread. +// We want exactly one thread. : LL::ThreadPool("LLImageGL", 1) , mWindow(window) { @@ -2612,3 +2635,4 @@ void LLImageGLThread::run() mWindow->destroySharedContext(mContext); } + diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 6b4492c09e7..8244046ec0d 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -40,6 +40,7 @@ #include "threadpool.h" #include "workqueue.h" #include +#include #define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL @@ -56,6 +57,7 @@ namespace LLImageGLMemory void free_cur_tex_image(); } + //============================================================================ class LLImageGL : public LLRefCount { @@ -100,6 +102,23 @@ class LLImageGL : public LLRefCount static bool create(LLPointer& dest, U32 width, U32 height, U8 components, bool usemipmaps = true); static bool create(LLPointer& dest, const LLImageRaw* imageraw, bool usemipmaps = true); + // map of mTexID to GL texture names (allows for 16-bit tex names in draw infos) + // Assumes we will never have more than 64k textures resident in memory at a time + // In practice, this should result in fewer cache misses than storing the names in the draw infos, + // especially if care is taken to keep the tex IDs low + static U32 sTexNames[U16_MAX+1]; + + // stack of free'd tex IDs to be reused + static std::stack sFreeTexIDs; + + // next tex ID to use when creating a new texture + // WARNING: if sNextTexID is U16_MAX, allocating an LLImageGL will trigger a crash + static U16 sNextTexID; + + // allocate a new tex ID + static U16 allocTexID(); + static void freeTexID(U16 texID); + public: LLImageGL(bool usemipmaps = true, bool allow_compression = true); LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true, bool allow_compression = true); @@ -173,8 +192,6 @@ class LLImageGL : public LLRefCount bool getIsAlphaMask() const; - bool getIsResident(bool test_now = false); // not const - void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); LLTexUnit::eTextureType getTarget(void) const { return mBindTarget; } @@ -226,6 +243,7 @@ class LLImageGL : public LLRefCount S64Bytes mTextureMemory; mutable F32 mLastBindTime; // last time this was bound, by discard level + const U16 mTexID; // 16-bit texture ID for use in draw infos, will remain constant for the lifetime of this class private: U32 createPickMask(S32 pWidth, S32 pHeight); void freePickMask(); @@ -259,8 +277,6 @@ class LLImageGL : public LLRefCount bool mHasMipMaps; S32 mMipLevels; - LLGLboolean mIsResident; - S8 mComponents; S8 mMaxDiscardLevel; @@ -282,6 +298,10 @@ class LLImageGL : public LLRefCount static U32 sFrameCount; static F32 sLastFrameTime; + // Texture name reference checking callback. Called just before a texture name is deleted so app can verify that the name + // is not referenced. + static std::function sTexNameReferenceCheck; + // Global memory statistics static U32 sBindCount; // Tracks number of texture binds for current frame static U32 sUniqueCount; // Tracks number of unique texture binds for current frame @@ -289,12 +309,6 @@ class LLImageGL : public LLRefCount static LLImageGL* sDefaultGLTexture ; static bool sAutomatedTest; static bool sCompressTextures; //use GL texture compression -#if DEBUG_MISS - bool mMissed; // Missed on last bind? - bool getMissed() const { return mMissed; }; -#else - bool getMissed() const { return false; }; -#endif public: static void initClass(LLWindow* window, S32 num_catagories, bool skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false); @@ -321,7 +335,7 @@ class LLImageGL : public LLRefCount void setCategory(S32 category) {mCategory = category;} S32 getCategory()const {return mCategory;} - void setTexName(GLuint texName) { mTexName = texName; } + void setTexName(GLuint texName, bool delete_old = false); //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname void syncTexName(LLGLuint texname); diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 3b74d360d08..ead4bd38e8d 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -417,6 +417,12 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) return true; } +void LLTexUnit::bindManualFast(LLTexUnit::eTextureType type, U32 texName) +{ + glActiveTexture(GL_TEXTURE0 + mIndex); + glBindTexture(sGLTextureType[type], mCurrTexture); +} + void LLTexUnit::unbind(eTextureType type) { stop_glerror(); @@ -897,6 +903,7 @@ bool LLRender::init(bool needs_vertex_buffer) U32 ret; glGenVertexArrays(1, &ret); glBindVertexArray(ret); + LLVertexBuffer::sDefaultVAO = ret; } if (needs_vertex_buffer) @@ -1716,7 +1723,9 @@ LLVertexBuffer* LLRender::genBuffer(U32 attribute_mask, S32 count) LLVertexBuffer * vb = new LLVertexBuffer(attribute_mask); vb->allocateBuffer(count, 0); +#if !LL_DARWIN vb->setBuffer(); +#endif vb->setPositionData(mVerticesp.get()); diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 8c7126420e1..5473af07055 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -197,6 +197,9 @@ class LLTexUnit // (automatically enables the tex unit for the given texture type) bool bindManual(eTextureType type, U32 texture, bool hasMips = false); + // Manually binds a texture to the texture unit doing absolute minimal work + void bindManualFast(LLTexUnit::eTextureType type, U32 texture); + // Unbinds the currently bound texture of the given type // (only if there's a texture of the given type currently bound) void unbind(eTextureType type); diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 796805e2a57..dcaf1795cb7 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1188,6 +1188,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("occlusion_texcoord"); // (GLTF) mReservedUniforms.push_back("gltf_node_id"); // (GLTF) mReservedUniforms.push_back("gltf_material_id"); // (GLTF) + mReservedUniforms.push_back("gltf_base_instance"); // (GLTF) mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) mReservedUniforms.push_back("terrain_stamp_scale"); @@ -1226,7 +1227,9 @@ void LLShaderMgr::initAttribsAndUniforms() llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1); mReservedUniforms.push_back("color"); + mReservedUniforms.push_back("debug_color"); mReservedUniforms.push_back("emissiveColor"); + mReservedUniforms.push_back("baseColorFactor"); mReservedUniforms.push_back("metallicFactor"); mReservedUniforms.push_back("roughnessFactor"); mReservedUniforms.push_back("mirror_flag"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index ff07ce454ba..bfe8fe47982 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -65,6 +65,7 @@ class LLShaderMgr OCCLUSION_TEXCOORD, // "occlusion_texcoord" (GLTF) GLTF_NODE_ID, // "gltf_node_id" (GLTF) GLTF_MATERIAL_ID, // "gltf_material_id" (GLTF) + GLTF_BASE_INSTANCE, // "gltf_base_instance" (GLTF) TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF) TERRAIN_STAMP_SCALE, // "terrain_stamp_scale" @@ -93,7 +94,9 @@ class LLShaderMgr PROJECTOR_LOD, // "proj_lod" PROJECTOR_AMBIENT_LOD, // "proj_ambient_lod" DIFFUSE_COLOR, // "color" + DEBUG_COLOR, // "debug_color" EMISSIVE_COLOR, // "emissiveColor" + BASE_COLOR_FACTOR, // "baseColorFactor" METALLIC_FACTOR, // "metallicFactor" ROUGHNESS_FACTOR, // "roughnessFactor" MIRROR_FLAG, // "mirror_flag" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index b2aa0eb675d..d09ed5046c9 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -37,13 +37,20 @@ #include "llglslshader.h" #include "llmemory.h" #include +#include "lltracethreadrecorder.h" + +U32 LLVertexBuffer::sDefaultVAO = 0; + +static bool sVBOPooling = true; + //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 U32 nhpo2(U32 v) { U32 r = 1; - while (r < v) { + while (r < v) + { r *= 2; } return r; @@ -71,199 +78,77 @@ struct CompareMappedRegion } }; -#define ENABLE_GL_WORK_QUEUE 0 - -#if ENABLE_GL_WORK_QUEUE - -#define THREAD_COUNT 1 - //============================================================================ +// Pool of reusable VertexBuffer state -// High performance WorkQueue for usage in real-time rendering work -class GLWorkQueue -{ -public: - using Work = std::function; - - GLWorkQueue(); - - void post(const Work& value); - - size_t size(); - - bool done(); - - // Get the next element from the queue - Work pop(); - - void runOne(); - - bool runPending(); - - void runUntilClose(); - - void close(); - - bool isClosed(); - - void syncGL(); - -private: - std::mutex mMutex; - std::condition_variable mCondition; - std::queue mQueue; - bool mClosed = false; -}; - -GLWorkQueue::GLWorkQueue() -{ - -} - -void GLWorkQueue::syncGL() -{ - /*if (mSync) - { - std::lock_guard lock(mMutex); - glWaitSync(mSync, 0, GL_TIMEOUT_IGNORED); - mSync = 0; - }*/ -} - -size_t GLWorkQueue::size() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - std::lock_guard lock(mMutex); - return mQueue.size(); -} - -bool GLWorkQueue::done() -{ - return size() == 0 && isClosed(); -} - -void GLWorkQueue::post(const GLWorkQueue::Work& value) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - { - std::lock_guard lock(mMutex); - mQueue.push(std::move(value)); - } - - mCondition.notify_one(); -} - -// Get the next element from the queue -GLWorkQueue::Work GLWorkQueue::pop() +// batch calls to glGenBuffers +GLuint ll_gl_gen_buffer() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - // Lock the mutex - { - std::unique_lock lock(mMutex); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; - // Wait for a new element to become available or for the queue to close - { - mCondition.wait(lock, [=] { return !mQueue.empty() || mClosed; }); - } - } + GLuint ret = 0; + constexpr U32 pool_size = 4096; - Work ret; + thread_local static GLuint sNamePool[pool_size]; + thread_local static U32 sIndex = 0; + if (sIndex == 0) { - std::lock_guard lock(mMutex); - - // Get the next element from the queue - if (mQueue.size() > 0) + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer"); + sIndex = pool_size; +#if !LL_DARWIN + if (!gGLManager.mIsAMD) { - ret = mQueue.front(); - mQueue.pop(); + glGenBuffers(pool_size, sNamePool); } else - { - ret = []() {}; +#endif + { // work around for AMD driver bug + for (U32 i = 0; i < pool_size; ++i) + { + glGenBuffers(1, sNamePool + i); + } } } + ret = sNamePool[--sIndex]; return ret; } -void GLWorkQueue::runOne() +void ll_gl_delete_buffers(S32 count, GLuint* buffers) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - Work w = pop(); - w(); - //mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -} - -void GLWorkQueue::runUntilClose() -{ - while (!isClosed()) - { - runOne(); - } -} + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + // wait a few frames before actually deleting the buffers to avoid + // synchronization issues with the GPU + static std::vector sFreeList[4]; -void GLWorkQueue::close() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + if (gGLManager.mInited) { - std::lock_guard lock(mMutex); - mClosed = true; - } - - mCondition.notify_all(); -} - -bool GLWorkQueue::isClosed() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - std::lock_guard lock(mMutex); - return mClosed; -} + U32 idx = LLImageGL::sFrameCount % 4; -#include "llwindow.h" + for (S32 i = 0; i < count; ++i) + { + sFreeList[idx].push_back(buffers[i]); + } -class LLGLWorkerThread : public LLThread -{ -public: - LLGLWorkerThread(const std::string& name, GLWorkQueue* queue, LLWindow* window) - : LLThread(name) - { - mWindow = window; - mContext = mWindow->createSharedContext(); - mQueue = queue; - } + idx = (LLImageGL::sFrameCount + 3) % 4; - void run() override - { - mWindow->makeContextCurrent(mContext); - gGL.init(false); - mQueue->runUntilClose(); - gGL.shutdown(); - mWindow->destroySharedContext(mContext); + if (!sFreeList[idx].empty()) + { + glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); + sFreeList[idx].resize(0); + } } +} - GLWorkQueue* mQueue; - LLWindow* mWindow; - void* mContext = nullptr; -}; - - -static LLGLWorkerThread* sVBOThread[THREAD_COUNT]; -static GLWorkQueue* sQueue = nullptr; - -#endif - -//============================================================================ -// Pool of reusable VertexBuffer state // batch calls to glGenBuffers -static GLuint gen_buffer() +GLuint ll_gl_gen_arrays() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; GLuint ret = 0; - constexpr U32 pool_size = 4096; + constexpr U32 pool_size = 1024; thread_local static GLuint sNamePool[pool_size]; thread_local static U32 sIndex = 0; @@ -272,17 +157,15 @@ static GLuint gen_buffer() { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer"); sIndex = pool_size; -#if !LL_DARWIN if (!gGLManager.mIsAMD) { - glGenBuffers(pool_size, sNamePool); + glGenVertexArrays(pool_size, sNamePool); } else -#endif { // work around for AMD driver bug for (U32 i = 0; i < pool_size; ++i) { - glGenBuffers(1, sNamePool + i); + glGenVertexArrays(1, sNamePool + i); } } } @@ -291,7 +174,7 @@ static GLuint gen_buffer() return ret; } -static void delete_buffers(S32 count, GLuint* buffers) +void ll_gl_delete_arrays(S32 count, GLuint* buffers) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; // wait a few frames before actually deleting the buffers to avoid @@ -311,13 +194,12 @@ static void delete_buffers(S32 count, GLuint* buffers) if (!sFreeList[idx].empty()) { - glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); + glDeleteVertexArrays((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); sFreeList[idx].resize(0); } } } - #define ANALYZE_VBO_POOL 0 // VBO Pool interface @@ -377,7 +259,7 @@ class LLAppleVBOPool final: public LLVBOPool STOP_GLERROR; if (name) { - delete_buffers(1, &name); + ll_gl_delete_buffers(1, &name); } STOP_GLERROR; } @@ -450,7 +332,7 @@ class LLDefaultVBOPool final : public LLVBOPool LL_PROFILE_GPU_ZONE("vbo alloc"); mMisses++; - name = gen_buffer(); + name = ll_gl_gen_buffer(); glBindBuffer(type, name); glBufferData(type, size, nullptr, GL_DYNAMIC_DRAW); if (type == GL_ELEMENT_ARRAY_BUFFER) @@ -548,7 +430,7 @@ class LLDefaultVBOPool final : public LLVBOPool LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout"); auto& entry = entries.back(); ll_aligned_free_16(entry.mData); - delete_buffers(1, &entry.mGLName); + ll_gl_delete_buffers(1, &entry.mGLName); llassert(mReserved >= iter->first); mReserved -= iter->first; entries.pop_back(); @@ -584,7 +466,7 @@ class LLDefaultVBOPool final : public LLVBOPool for (auto& entry : entries.second) { ll_aligned_free_16(entry.mData); - delete_buffers(1, &entry.mGLName); + ll_gl_delete_buffers(1, &entry.mGLName); } } @@ -593,7 +475,7 @@ class LLDefaultVBOPool final : public LLVBOPool for (auto& entry : entries.second) { ll_aligned_free_16(entry.mData); - delete_buffers(1, &entry.mGLName); + ll_gl_delete_buffers(1, &entry.mGLName); } } @@ -722,7 +604,7 @@ static const std::string vb_type_name[] = "TYPE_INDEX", }; -const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = +static const GLenum sGLMode[LLRender::NUM_MODES] = { GL_TRIANGLES, GL_TRIANGLE_STRIP, @@ -921,13 +803,11 @@ void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 (GLvoid*)(indices_offset * (size_t)mIndicesStride)); } - void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { drawRange(mode, 0, mNumVerts-1, count, indices_offset); } - void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(first + count <= mNumVerts); @@ -944,11 +824,8 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const void LLVertexBuffer::initClass(LLWindow* window) { llassert(sVBOPool == nullptr); - - LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL; - sVBOPool = new LLAppleVBOPool(); - - if (gGLManager.mIsApple) + sVBOPooling = !gGLManager.mIsApple; + if (!sVBOPooling) { LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL; sVBOPool = new LLAppleVBOPool(); @@ -958,16 +835,6 @@ void LLVertexBuffer::initClass(LLWindow* window) LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL; sVBOPool = new LLDefaultVBOPool(); } - -#if ENABLE_GL_WORK_QUEUE - sQueue = new GLWorkQueue(); - - for (int i = 0; i < THREAD_COUNT; ++i) - { - sVBOThread[i] = new LLGLWorkerThread("VBO Worker", sQueue, window); - sVBOThread[i]->start(); - } -#endif } //static @@ -988,19 +855,6 @@ void LLVertexBuffer::cleanupClass() delete sVBOPool; sVBOPool = nullptr; - -#if ENABLE_GL_WORK_QUEUE - sQueue->close(); - for (int i = 0; i < THREAD_COUNT; ++i) - { - sVBOThread[i]->shutdown(); - delete sVBOThread[i]; - sVBOThread[i] = nullptr; - } - - delete sQueue; - sQueue = nullptr; -#endif } //---------------------------------------------------------------------------- @@ -1016,10 +870,35 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask) } } + +void LLVertexBuffer::setIndicesType(U32 type) +{ + llassert(getNumVerts() == 0); + llassert(getNumIndices() == 0); + llassert(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT); + + mIndicesType = type; + + if (mIndicesType == GL_UNSIGNED_SHORT) + { + mIndicesStride = 2; + } + else + { + mIndicesStride = 4; + } +} // list of mapped buffers // NOTE: must not be LLPointer to avoid breaking non-ref-counted LLVertexBuffer instances static std::vector sMappedBuffers; +//static +void LLVertexBuffer::updateClass() +{ + ll_gl_delete_arrays(0, nullptr); + ll_gl_delete_buffers(0, nullptr); +} + //static void LLVertexBuffer::flushBuffers() { @@ -1086,6 +965,11 @@ LLVertexBuffer::~LLVertexBuffer() destroyGLBuffer(); destroyGLIndices(); + if (mGLVAO) + { + ll_gl_delete_arrays(1, &mGLVAO); + } + if (mMappedData) { LL_ERRS() << "Failed to clear vertex buffer's vertices" << LL_ENDL; @@ -1233,7 +1117,7 @@ bool LLVertexBuffer::updateNumIndices(U32 nindices) bool success = true; - U32 needed_size = sizeof(U16) * nindices; + U32 needed_size = (mIndicesType == GL_UNSIGNED_INT ? sizeof(U32) : sizeof(U16)) * nindices; if (needed_size != mIndicesSize) { @@ -1291,7 +1175,7 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde count = mNumVerts - index; } - if (!gGLManager.mIsApple) + if (sVBOPooling) { U32 start = mOffsets[type] + sTypeSize[type] * index; U32 end = start + sTypeSize[type] * count-1; @@ -1328,7 +1212,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) count = mNumIndices-index; } - if (!gGLManager.mIsApple) + if (sVBOPooling) { U32 start = sizeof(U16) * index; U32 end = start + sizeof(U16) * count-1; @@ -1363,7 +1247,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) // dst -- mMappedData or mMappedIndexData void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst) { - if (gGLManager.mIsApple) + if (!sVBOPooling) { // on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call // _mapBuffer to tag the buffer for flushing to GL @@ -1429,16 +1313,16 @@ void LLVertexBuffer::_unmapBuffer() } }; - if (gGLManager.mIsApple) + if (!sVBOPooling) { STOP_GLERROR; if (mMappedData) { if (mGLBuffer) { - delete_buffers(1, &mGLBuffer); + ll_gl_delete_buffers(1, &mGLBuffer); } - mGLBuffer = gen_buffer(); + mGLBuffer = ll_gl_gen_buffer(); glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); sGLRenderBuffer = mGLBuffer; glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW); @@ -1454,10 +1338,10 @@ void LLVertexBuffer::_unmapBuffer() { if (mGLIndices) { - delete_buffers(1, &mGLIndices); + ll_gl_delete_buffers(1, &mGLIndices); } - mGLIndices = gen_buffer(); + mGLIndices = ll_gl_gen_buffer(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); sGLRenderIndices = mGLIndices; @@ -1659,8 +1543,6 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, U32 in // Set for rendering void LLVertexBuffer::setBuffer() { - STOP_GLERROR; - if (mMapped) { LL_WARNS_ONCE() << "Missing call to unmapBuffer or flushBuffers" << LL_ENDL; @@ -1703,15 +1585,34 @@ void LLVertexBuffer::setBuffer() STOP_GLERROR; } +void LLVertexBuffer::bindBuffer() +{ + sLastMask = 0; + if (sGLRenderBuffer != mGLBuffer) + { + glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); + sGLRenderBuffer = mGLBuffer; + } + + if (mGLIndices != sGLRenderIndices) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); + sGLRenderIndices = mGLIndices; + } +} // virtual (default) void LLVertexBuffer::setupVertexBuffer() { STOP_GLERROR; - U8* base = nullptr; - U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask; + setupVertexBuffer(data_mask); +} + +void LLVertexBuffer::setupVertexBuffer(U32 data_mask) +{ + U8* base = nullptr; if (data_mask & MAP_NORMAL) { AttributeType loc = TYPE_NORMAL; @@ -1806,6 +1707,67 @@ void LLVertexBuffer::setupVertexBuffer() STOP_GLERROR; } +//static +void LLVertexBuffer::bindVBO(U32 vbo, U32 ibo, U32 vcount) +{ + if (sGLRenderBuffer == vbo) + { + return; + } + + // NOTE: this only works for VertexBuffers allocated from inside LLVolume that all have the same attribute mask + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + sGLRenderBuffer = vbo; + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + sGLRenderIndices = ibo; + + U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask; + + U8* base = nullptr; + + U32 offsets[TYPE_MAX]; + + U32 offset = 0; + offsets[TYPE_VERTEX] = offset; offset += sTypeSize[TYPE_VERTEX] * vcount; offset = (offset + 0xF) & ~0xF; + offsets[TYPE_NORMAL] = offset; offset += sTypeSize[TYPE_NORMAL] * vcount; offset = (offset + 0xF) & ~0xF; + offsets[TYPE_TEXCOORD0] = offset; offset += sTypeSize[TYPE_TEXCOORD0] * vcount; offset = (offset + 0xF) & ~0xF; + offsets[TYPE_TANGENT] = offset; offset += sTypeSize[TYPE_TANGENT] * vcount; offset = (offset + 0xF) & ~0xF; + offsets[TYPE_WEIGHT4] = offset; offset += sTypeSize[TYPE_WEIGHT4] * vcount; offset = (offset + 0xF) & ~0xF; + + if (data_mask & MAP_NORMAL) + { + AttributeType loc = TYPE_NORMAL; + void* ptr = (void*)(base + offsets[TYPE_NORMAL]); + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); + } + if (data_mask & MAP_TANGENT) + { + AttributeType loc = TYPE_TANGENT; + void* ptr = (void*)(base + offsets[TYPE_TANGENT]); + glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); + } + if (data_mask & MAP_TEXCOORD0) + { + AttributeType loc = TYPE_TEXCOORD0; + void* ptr = (void*)(base + offsets[TYPE_TEXCOORD0]); + glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); + } + if (data_mask & MAP_WEIGHT4) + { + AttributeType loc = TYPE_WEIGHT4; + void* ptr = (void*)(base + offsets[TYPE_WEIGHT4]); + glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); + } + + { + AttributeType loc = TYPE_VERTEX; + void* ptr = (void*)(base + offsets[TYPE_VERTEX]); + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + } +} + void LLVertexBuffer::setPositionData(const LLVector4a* data) { flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData); @@ -1904,20 +1866,26 @@ void LLVertexBuffer::setJointData(const U64* data, U32 offset, U32 count) void LLVertexBuffer::setIndexData(const U16* data, U32 offset, U32 count) { - flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U16), (offset + count) * sizeof(U16) - 1, (U8*)data, mMappedIndexData); + if (mIndicesType == GL_UNSIGNED_INT) + { // implicitly convert input to 32-bit indices + U32* temp = new U32[count]; + for (U32 i = 0; i < count; ++i) + { + temp[i] = data[i]; + } + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U32), (offset + count) * sizeof(U32) - 1, (U8*)temp, mMappedIndexData); + delete[] temp; + } + else + { + flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U16), (offset + count) * sizeof(U16) - 1, (U8*)data, mMappedIndexData); + } } void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count) { - if (mIndicesType != GL_UNSIGNED_INT) - { // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices - mIndicesType = GL_UNSIGNED_INT; - mIndicesStride = 4; - mNumIndices /= 2; - } + llassert(mIndicesType == GL_UNSIGNED_INT); + llassert(mIndicesStride == 4); flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U32), (offset + count) * sizeof(U32) - 1, (U8*)data, mMappedIndexData); } - - - diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 375ad76fb84..bbd456d7822 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -27,18 +27,17 @@ #ifndef LL_LLVERTEXBUFFER_H #define LL_LLVERTEXBUFFER_H -#include "llgl.h" +#include "llpointer.h" +#include "llglheaders.h" #include "v2math.h" #include "v3math.h" #include "v4math.h" #include "v4coloru.h" #include "llstrider.h" #include "llrender.h" -#include "lltrace.h" -#include #include -#include #include +#include "llrefcount.h" #define LL_MAX_VERTEX_ATTRIB_LOCATION 64 @@ -55,6 +54,13 @@ // base class class LLPrivateMemoryPool; class LLVertexBuffer; +class LLWindow; + +// Equivalent to glGenBuffers, but batches creation of buffers to reduce overhead +GLuint ll_gl_gen_buffer(); + +// Equivalent to glDeleteBuffers, but batches deletion of buffers to reduce overhead +void ll_gl_delete_buffers(S32 count, GLuint* buffers); class LLVertexBufferData { @@ -87,11 +93,13 @@ class LLVertexBufferData glm::mat4 mModelView; glm::mat4 mTexture0; }; -typedef std::list buffer_data_list_t; class LLVertexBuffer final : public LLRefCount { public: + // default VAO to bind for vertex buffers that have no VAO + static U32 sDefaultVAO; + struct MappedRegion { U32 mStart; @@ -117,6 +125,9 @@ class LLVertexBuffer final : public LLRefCount static void unbind(); //unbind any bound vertex buffer + // bind specified VBO (and IBO) for rendering + static void bindVBO(U32 vbo, U32 ibo, U32 vertex_count); + //get the size of a vertex with the given typemask static U32 calcVertexSize(const U32& typemask); @@ -125,6 +136,9 @@ class LLVertexBuffer final : public LLRefCount // indexed by the following enum static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices); + // call once per frame to flush pending deletes + static void updateClass(); + // flush any pending mapped buffers static void flushBuffers(); @@ -180,6 +194,8 @@ class LLVertexBuffer final : public LLRefCount void setupVertexBuffer(); + void setupVertexBuffer(U32 data_mask); + void genBuffer(U32 size); void genIndices(U32 size); bool createGLBuffer(U32 size); @@ -192,6 +208,13 @@ class LLVertexBuffer final : public LLRefCount public: LLVertexBuffer(U32 typemask); + // set the type of indices in the index buffer + // MUST be called before allocateBuffer + // MUST NOT be called after allocateBuffer + // type MUST be either GL_UNSIGNED_SHORT or GL_UNSIGNED_INT + // default is GL_UNSIGNED_SHORT + void setIndicesType(U32 type); + // allocate buffer bool allocateBuffer(U32 nverts, U32 nindices); @@ -209,6 +232,10 @@ class LLVertexBuffer final : public LLRefCount // - This buffer has sufficient attributes within it to satisfy the needs of the currently bound shader void setBuffer(); + // bind the buffer for setting data (not rendering) + // does not set vertex attributes for rendering + void bindBuffer(); + // Only call each getVertexPointer, etc, once before calling unmapBuffer() // call unmapBuffer() after calls to getXXXStrider() before any calls to setBuffer() // example: @@ -285,13 +312,17 @@ class LLVertexBuffer final : public LLRefCount void clone(LLVertexBuffer& target) const; -protected: + U32 mIndicesType = GL_UNSIGNED_SHORT; // type of indices in index buffer + U32 mIndicesStride = 2; // size of each index in bytes + + U32 mGLVAO = 0; // GL VAO handle U32 mGLBuffer = 0; // GL VBO handle U32 mGLIndices = 0; // GL IBO handle + +protected: + U32 mNumVerts = 0; // Number of vertices allocated U32 mNumIndices = 0; // Number of indices allocated - U32 mIndicesType = GL_UNSIGNED_SHORT; // type of indices in index buffer - U32 mIndicesStride = 2; // size of each index in bytes U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped) @@ -333,7 +364,6 @@ class LLVertexBuffer final : public LLRefCount static U64 getBytesAllocated(); static const U32 sTypeSize[TYPE_MAX]; - static const U32 sGLMode[LLRender::NUM_MODES]; static U32 sGLRenderBuffer; static U32 sGLRenderIndices; static U32 sLastMask; @@ -346,5 +376,4 @@ class LLVertexBuffer final : public LLRefCount #define LL_LABEL_VERTEX_BUFFER(buf, name) #endif - #endif // LL_LLVERTEXBUFFER_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6d852e47f81..678b8b611e2 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -323,6 +323,7 @@ set(viewer_SOURCE_FILES llgesturemgr.cpp llgiveinventory.cpp llglsandbox.cpp + llgltfdrawinfo.cpp llgltffolderitem.cpp llgltffoldermodel.cpp llgltfmateriallist.cpp @@ -1002,6 +1003,7 @@ set(viewer_HEADER_FILES llgesturelistener.h llgesturemgr.h llgiveinventory.h + llgltfdrawinfo.h llgltffolderitem.h llgltffoldermodel.h llgltfmateriallist.h @@ -2245,8 +2247,8 @@ if (LL_TESTS) # llremoteparcelrequest.cpp llviewerhelputil.cpp llversioninfo.cpp -# llvocache.cpp - llworldmap.cpp +# llvocache.cpp +# llworldmap.cpp llworldmipmap.cpp ) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8b1df630da6..0483b23857e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7268,13 +7268,13 @@ OctreeStaticObjectSizeFactor Comment - Multiplier on static object size for determining octree node size + Minimum size of octree nodes Persist - 1 + 0 Type S32 Value - 3 + 16 OctreeAlphaDistanceFactor @@ -8770,7 +8770,7 @@ Comment Allow OpenGL to use multiple render contexts for loading textures (may reduce frame stutters, doesn't play nice with Intel drivers). Persist - 1 + 0 Type Boolean Value @@ -8781,7 +8781,7 @@ Comment Allow OpenGL to use multiple render contexts for playing media (may reduce frame stutters, doesn't play nice with Intel drivers) Persist - 1 + 0 Type Boolean Value @@ -9753,7 +9753,7 @@ Type Boolean Value - 1 + 0 RenderAvatarFriendsOnly @@ -16352,6 +16352,28 @@ Value 0 + IdleThread + + Comment + Run "idle" on a background thread. Must be set from command line. + Persist + 0 + Type + Boolean + Value + 0 + + RenderNormalMapsEnabled + + Comment + Enable normal maps on content that supports them. + Persist + 1 + Type + Boolean + Value + 1 + RenderHDREnabled Comment diff --git a/indra/newview/app_settings/shaders/class1/deferred/blinnphongF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blinnphongF.glsl new file mode 100644 index 00000000000..6a93b00f134 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/blinnphongF.glsl @@ -0,0 +1,49 @@ +/** + * @file blinnphongF.glsl + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/*[EXTRA_CODE_HERE]*/ + + +// blinn-phong debug stub +#ifdef OUTPUT_DIFFUSE_ONLY +out vec4 frag_color; +#else +out vec4 frag_data[4]; +#endif + +void main() +{ + +#ifdef OUTPUT_DIFFUSE_ONLY + frag_color = vec4(1,0,1,1); +#else + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = vec4(0); + frag_data[1] = vec4(0); + frag_data[2] = vec4(vec3(0), GBUFFER_FLAG_HAS_PBR); + frag_data[3] = vec4(1,0,1,0); +#endif +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/blinnphongV.glsl b/indra/newview/app_settings/shaders/class1/deferred/blinnphongV.glsl new file mode 100644 index 00000000000..ac24ee7bca8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/blinnphongV.glsl @@ -0,0 +1,290 @@ +/** + * @file blinnphongV.glsl + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; + +in vec3 position; + +#ifdef HAS_TEXTURE +mat4 tex_mat; +in vec2 texcoord0; +#endif + +#ifdef HAS_NORMAL +in vec3 normal; +#endif + +#ifdef HAS_FRAGMENT_NORMAL +out vec3 vary_normal; +#endif + +vec2 bp_texture_transform(vec2 vertex_texcoord, vec4[2] transform, mat4 sl_animation_transform); + +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +#else +#endif + +#ifdef SAMPLE_DIFFUSE_MAP +vec4[2] texture_diffuse_transform; +out vec2 diffuse_texcoord; +#endif + +#ifdef SAMPLE_NORMAL_MAP +in vec4 tangent; +vec4[2] texture_normal_transform; +out vec2 normal_texcoord; +out vec3 vary_tangent; +flat out float vary_sign; +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +#endif + +#ifdef SAMPLE_SPECULAR_MAP +vec4[2] texture_specular_transform; +out vec2 specular_texcoord; +#endif + +#ifdef FRAG_POSITION +out vec3 vary_position; +#endif + +#ifdef ALPHA_BLEND +out vec3 vary_fragcoord; +#endif + +layout (std140) uniform GLTFNodes +{ + mat3x4 gltf_nodes[MAX_NODES_PER_GLTF_OBJECT]; +}; + +#ifdef TEX_ANIM +layout (std140) uniform TextureTransform +{ + mat3x4 texture_matrix[MAX_NODES_PER_GLTF_OBJECT]; +}; +#endif + +layout (std140) uniform GLTFNodeInstanceMap +{ + // .x - gltf_node_id + // .y - gltf_material_id + // .z - texture_matrix_id + ivec4 gltf_node_instance_map[MAX_INSTANCES_PER_GLTF_OBJECT]; +}; + + +#ifdef PLANAR_PROJECTION +vec3 prim_scale; + +void planarProjection(inout vec2 tc) +{ + vec3 binormal; + vec3 vec = position * prim_scale; + + float d = normal.x; + + if (d >= 0.5 || d <= -0.5) + { + if (d < 0.0) + { + binormal = vec3(0,-1,0); + } + else + { + binormal = vec3(0, 1, 0); + } + } + else + { + if (normal.y > 0) + { + binormal = vec3(-1,0,0); + } + else + { + binormal = vec3(1,0,0); + } + } + vec3 tangent; + tangent = cross(binormal, normal); + + tc.y = -(dot(tangent,vec)*2.0 - 0.5); + tc.x = 1.0+(dot(binormal, vec)*2.0 - 0.5); +} +#endif + +uniform int gltf_base_instance; + +#ifdef SAMPLE_MATERIALS_UBO +layout (std140) uniform GLTFMaterials +{ + // index by gltf_material_id + + // [gltf_material_id + [0-1]] - diffuse transform + // [gltf_material_id + [2-3]] - normal transform + // [gltf_material_id + [4-5]] - specular transform + + // Transforms are packed as follows + // packed[0] = vec4(scale.x, scale.y, rotation, offset.x) + // packed[1] = vec4(offset.y, *, *, *) + + // packed[1].yzw varies: + // diffuse transform -- diffuse color + // specular transform -- specular color + // normal transform -- .y - alpha factor, .z - minimum alpha + + vec4 gltf_material_data[MAX_UBO_VEC4S]; +}; + +flat out int gltf_material_id; + +void unpackTextureTransforms() +{ + gltf_material_id = gltf_node_instance_map[gl_InstanceID+gltf_base_instance].y; + + int idx = gltf_material_id; + +#ifdef SAMPLE_DIFFUSE_MAP + texture_diffuse_transform[0] = gltf_material_data[idx+0]; + texture_diffuse_transform[1] = vec4(gltf_material_data[idx+0].w, gltf_material_data[idx+1].x, 0, 0); +#endif + +#ifdef SAMPLE_NORMAL_MAP + texture_normal_transform[0] = gltf_material_data[idx+2]; + texture_normal_transform[1] = vec4(gltf_material_data[idx+2].w, gltf_material_data[idx+3].x, 0, 0); +#endif + +#ifdef SAMPLE_SPECULAR_MAP + texture_specular_transform[0] = gltf_material_data[idx+4]; + texture_specular_transform[1] = vec4(gltf_material_data[idx+4].w, gltf_material_data[idx+5].x, 0, 0); +#endif +} +#else // SAMPLE_MATERIALS_UBO +void unpackTextureTransforms() +{ +} +#endif + +mat4 getGLTFTransform() +{ + unpackTextureTransforms(); + int gltf_node_id = gltf_node_instance_map[gl_InstanceID+gltf_base_instance].x; + + mat4 ret; + mat3x4 src = gltf_nodes[gltf_node_id]; + + ret[0] = vec4(src[0].xyz, 0); + ret[1] = vec4(src[1].xyz, 0); + ret[2] = vec4(src[2].xyz, 0); + ret[3] = vec4(src[0].w, src[1].w, src[2].w, 1); + +#ifndef HAS_SKIN + mat3x4 root = gltf_nodes[0]; + mat4 root4; + root4[0] = vec4(root[0].xyz, 0); + root4[1] = vec4(root[1].xyz, 0); + root4[2] = vec4(root[2].xyz, 0); + root4[3] = vec4(root[0].w, root[1].w, root[2].w, 1); + + ret = root4 * ret; +#endif + +#ifdef PLANAR_PROJECTION + prim_scale = gltf_material_data[gltf_node_instance_map[gl_InstanceID+gltf_base_instance].w].xyz; +#endif + return ret; +} + +void main() +{ + mat4 mat = getGLTFTransform(); +#ifdef HAS_SKIN + // mat should be the BindShapeMatrix for rigged objects + mat = getObjectSkinnedTransform() * mat; +#endif + + mat = modelview_matrix * mat; + vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; + vec4 vert = projection_matrix*vec4(pos,1.0); + gl_Position = vert; + +#ifdef FRAG_POSITION + vary_position = pos; +#endif + +#ifdef ALPHA_BLEND + vary_fragcoord = vert.xyz; +#endif + +#ifdef HAS_TEXTURE + vec2 tc0 = texcoord0; +#ifdef TEX_ANIM + mat3x4 src = texture_matrix[gltf_node_instance_map[gl_InstanceID+gltf_base_instance].z]; + + tex_mat[0] = vec4(src[0].xyz, 0); + tex_mat[1] = vec4(src[1].xyz, 0); + tex_mat[2] = vec4(src[2].xyz, 0); + tex_mat[3] = vec4(src[0].w, src[1].w, src[2].w, 1); +#else + tex_mat[0] = vec4(1,0,0,0); + tex_mat[1] = vec4(0,1,0,0); + tex_mat[2] = vec4(0,0,1,0); + tex_mat[3] = vec4(0,0,0,1); +#endif + +#ifdef PLANAR_PROJECTION + planarProjection(tc0); +#endif + +#endif + +#ifdef SAMPLE_DIFFUSE_MAP + diffuse_texcoord = bp_texture_transform(tc0, texture_diffuse_transform, tex_mat); +#endif + +#ifdef HAS_NORMAL + vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz; +#endif + +#ifdef SAMPLE_NORMAL_MAP + normal_texcoord = bp_texture_transform(tc0, texture_normal_transform, tex_mat); + + vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz; + + n = normalize(n); + + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, tex_mat); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; +#endif +#ifdef HAS_FRAGMENT_NORMAL + vary_normal = n; +#endif + +#ifdef SAMPLE_SPECULAR_MAP + specular_texcoord = bp_texture_transform(tc0, texture_specular_transform, tex_mat); +#endif +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/gltfpbrF.glsl b/indra/newview/app_settings/shaders/class1/deferred/gltfpbrF.glsl new file mode 100644 index 00000000000..90ff24619fe --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/gltfpbrF.glsl @@ -0,0 +1,49 @@ +/** + * @file pbropaqueF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/*[EXTRA_CODE_HERE]*/ + + +// pbr debug stub +#ifdef OUTPUT_BASE_COLOR_ONLY +out vec4 frag_color; +#else +out vec4 frag_data[4]; +#endif + +void main() +{ + +#ifdef OUTPUT_BASE_COLOR_ONLY + frag_color = vec4(1,0,1,1); +#else + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = vec4(0); + frag_data[1] = vec4(0); + frag_data[2] = vec4(vec3(0), GBUFFER_FLAG_HAS_PBR); + frag_data[3] = vec4(1,0,1,0); +#endif +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/gltfpbrV.glsl b/indra/newview/app_settings/shaders/class1/deferred/gltfpbrV.glsl new file mode 100644 index 00000000000..052456d94f5 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/gltfpbrV.glsl @@ -0,0 +1,313 @@ +/** + * @file gltfpbrV.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; + +in vec3 position; + +#ifdef HAS_NORMAL +in vec3 normal; +#endif + +#ifdef HAS_FRAGMENT_NORMAL +out vec3 vary_normal; +#endif + +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +#else +#endif + +#ifdef HAS_TEXTURE +in vec2 texcoord0; +vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +mat4 tex_mat; +#endif + +#ifdef SAMPLE_BASE_COLOR_MAP +vec4[2] texture_base_color_transform; +out vec2 base_color_texcoord; +#endif + +#ifdef SAMPLE_NORMAL_MAP +in vec4 tangent; + +vec4[2] texture_normal_transform; + +out vec2 normal_texcoord; + +out vec3 vary_tangent; +flat out float vary_sign; + +vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +#endif + +#ifdef SAMPLE_ORM_MAP +vec4[2] texture_metallic_roughness_transform; + +out vec2 metallic_roughness_texcoord; +#endif + +#ifdef SAMPLE_EMISSIVE_MAP +vec4[2] texture_emissive_transform; + +out vec2 emissive_texcoord; +#endif + +#ifdef FRAG_POSITION +out vec3 vary_position; +#endif + +#ifdef ALPHA_BLEND +out vec3 vary_fragcoord; +#endif + +layout (std140) uniform GLTFNodes +{ + mat3x4 gltf_nodes[MAX_NODES_PER_GLTF_OBJECT]; +}; + +#ifdef TEX_ANIM +layout (std140) uniform TextureTransform +{ + mat3x4 texture_matrix[MAX_NODES_PER_GLTF_OBJECT]; +}; +#endif + +layout (std140) uniform GLTFNodeInstanceMap +{ + // .x - gltf_node_id + // .y - gltf_material_id + // .z - texture_matrix_id + ivec4 gltf_node_instance_map[MAX_INSTANCES_PER_GLTF_OBJECT]; +}; + + +#ifdef PLANAR_PROJECTION +vec3 prim_scale; + +void planarProjection(inout vec2 tc) +{ + vec3 binormal; + vec3 vec = position * prim_scale; + + float d = normal.x; + + if (d >= 0.5 || d <= -0.5) + { + if (d < 0.0) + { + binormal = vec3(0,-1,0); + } + else + { + binormal = vec3(0, 1, 0); + } + } + else + { + if (normal.y > 0) + { + binormal = vec3(-1,0,0); + } + else + { + binormal = vec3(1,0,0); + } + } + vec3 tangent; + tangent = cross(binormal, normal); + + tc.y = -(dot(tangent,vec)*2.0 - 0.5); + tc.x = 1.0+(dot(binormal, vec)*2.0 - 0.5); +} +#endif + +uniform int gltf_base_instance; + +#ifdef SAMPLE_MATERIALS_UBO +layout (std140) uniform GLTFMaterials +{ + // index by gltf_material_id + + // [gltf_material_id + [0-1]] - base color transform + // [gltf_material_id + [2-3]] - normal transform + // [gltf_material_id + [4-5]] - metallic roughness transform + // [gltf_material_id + [6-7]] - emissive transform + + // Transforms are packed as follows + // packed[0] = vec4(scale.x, scale.y, rotation, offset.x) + // packed[1] = vec4(offset.y, *, *, *) + + // packed[1].yzw varies: + // base color transform -- base color factor + // metallic roughness transform -- .y - roughness factor, .z - metallic factor + // emissive transform -- emissive factor + // normal transform -- .y - alpha factor, .z - minimum alpha + + vec4 gltf_material_data[MAX_UBO_VEC4S]; +}; + +flat out int gltf_material_id; + +void unpackTextureTransforms() +{ + gltf_material_id = gltf_node_instance_map[gl_InstanceID+gltf_base_instance].y; + + int idx = gltf_material_id; + +#ifdef SAMPLE_BASE_COLOR_MAP + texture_base_color_transform[0] = gltf_material_data[idx+0]; + texture_base_color_transform[1] = vec4(gltf_material_data[idx+0].w, gltf_material_data[idx+1].x, 0, 0); +#endif + +#ifdef SAMPLE_NORMAL_MAP + texture_normal_transform[0] = gltf_material_data[idx+2]; + texture_normal_transform[1] = vec4(gltf_material_data[idx+2].w, gltf_material_data[idx+3].x, 0, 0); +#endif + +#ifdef SAMPLE_ORM_MAP + texture_metallic_roughness_transform[0] = gltf_material_data[idx+4]; + texture_metallic_roughness_transform[1] = vec4(gltf_material_data[idx+4].w, gltf_material_data[idx+5].x, 0, 0); +#endif + +#ifdef SAMPLE_EMISSIVE_MAP + texture_emissive_transform[0] = gltf_material_data[idx+6]; + texture_emissive_transform[1] = vec4(gltf_material_data[idx+6].w, gltf_material_data[idx+7].x, 0, 0); +#endif +} +#else // SAMPLE_MATERIALS_UBO +void unpackTextureTransforms() +{ +} +#endif + +mat4 getGLTFTransform() +{ + unpackTextureTransforms(); + int gltf_node_id = gltf_node_instance_map[gl_InstanceID+gltf_base_instance].x; + + mat4 ret; + mat3x4 src = gltf_nodes[gltf_node_id]; + + ret[0] = vec4(src[0].xyz, 0); + ret[1] = vec4(src[1].xyz, 0); + ret[2] = vec4(src[2].xyz, 0); + + ret[3] = vec4(src[0].w, src[1].w, src[2].w, 1); + +#ifndef HAS_SKIN + mat3x4 root = gltf_nodes[0]; + mat4 root4; + root4[0] = vec4(root[0].xyz, 0); + root4[1] = vec4(root[1].xyz, 0); + root4[2] = vec4(root[2].xyz, 0); + root4[3] = vec4(root[0].w, root[1].w, root[2].w, 1); + + ret = root4 * ret; +#endif + +#ifdef PLANAR_PROJECTION + prim_scale = gltf_material_data[gltf_node_instance_map[gl_InstanceID+gltf_base_instance].w].xyz; +#endif + return ret; +} + +void main() +{ + mat4 mat = getGLTFTransform(); +#ifdef HAS_SKIN + // mat should be the BindShapeMatrix for rigged objects + mat = getObjectSkinnedTransform() * mat; +#endif + + mat = modelview_matrix * mat; + vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; + vec4 vert = projection_matrix*vec4(pos,1.0); + gl_Position = vert; + +#ifdef ALPHA_BLEND + vary_fragcoord = vert.xyz; +#endif + +#ifdef HAS_TEXTURE + +#ifdef TEX_ANIM + mat3x4 src = texture_matrix[gltf_node_instance_map[gl_InstanceID+gltf_base_instance].z]; + + tex_mat[0] = vec4(src[0].xyz, 0); + tex_mat[1] = vec4(src[1].xyz, 0); + tex_mat[2] = vec4(src[2].xyz, 0); + tex_mat[3] = vec4(src[0].w, src[1].w, src[2].w, 1); +#else + tex_mat[0] = vec4(1,0,0,0); + tex_mat[1] = vec4(0,1,0,0); + tex_mat[2] = vec4(0,0,1,0); + tex_mat[3] = vec4(0,0,0,1); +#endif + + vec2 tc0 = texcoord0; +#ifdef PLANAR_PROJECTION + planarProjection(tc0); +#endif + +#endif + +#ifdef SAMPLE_BASE_COLOR_MAP + base_color_texcoord = texture_transform(tc0, texture_base_color_transform, tex_mat); +#endif + +#ifdef FRAG_POSITION + vary_position = pos; +#endif + +#ifdef HAS_NORMAL + vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz; +#endif + +#ifdef SAMPLE_NORMAL_MAP + normal_texcoord = texture_transform(tc0, texture_normal_transform, tex_mat); + vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz; + + n = normalize(n); + + vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, tex_mat); + vary_tangent = normalize(transformed_tangent.xyz); + vary_sign = transformed_tangent.w; +#endif + +#ifdef HAS_FRAGMENT_NORMAL + vary_normal = n; +#endif + +#ifdef SAMPLE_ORM_MAP + metallic_roughness_texcoord = texture_transform(tc0, texture_metallic_roughness_transform, tex_mat); +#endif + +#ifdef SAMPLE_EMISSIVE_MAP + emissive_texcoord = texture_transform(tc0, texture_emissive_transform, tex_mat); +#endif +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl deleted file mode 100644 index c0d4c387af3..00000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file pbropaqueF.glsl - * - * $LicenseInfo:firstyear=2022&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2022, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/*[EXTRA_CODE_HERE]*/ - - -#ifndef IS_HUD - -// deferred opaque implementation - -uniform sampler2D diffuseMap; //always in sRGB space - -uniform float metallicFactor; -uniform float roughnessFactor; -uniform vec3 emissiveColor; -uniform sampler2D bumpMap; -uniform sampler2D emissiveMap; -uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness - -out vec4 frag_data[4]; - -in vec3 vary_position; -in vec4 vertex_color; -in vec3 vary_normal; -in vec3 vary_tangent; -flat in float vary_sign; - -in vec2 base_color_texcoord; -in vec2 normal_texcoord; -in vec2 metallic_roughness_texcoord; -in vec2 emissive_texcoord; - -uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() - -vec3 linear_to_srgb(vec3 c); -vec3 srgb_to_linear(vec3 c); - -uniform vec4 clipPlane; -uniform float clipSign; - -void mirrorClip(vec3 pos); -vec4 encodeNormal(vec3 norm, float gbuffer_flag); - -uniform mat3 normal_matrix; - -void main() -{ - mirrorClip(vary_position); - - vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; - basecolor.rgb = srgb_to_linear(basecolor.rgb); - - basecolor *= vertex_color; - - if (basecolor.a < minimum_alpha) - { - discard; - } - - vec3 col = basecolor.rgb; - - // from mikktspace.com - vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0; - float sign = vary_sign; - vec3 vN = vary_normal; - vec3 vT = vary_tangent.xyz; - - vec3 vB = sign * cross(vN, vT); - vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); - - // RGB = Occlusion, Roughness, Metal - // default values, see LLViewerTexture::sDefaultPBRORMImagep - // occlusion 1.0 - // roughness 0.0 - // metal 0.0 - vec3 spec = texture(specularMap, metallic_roughness_texcoord.xy).rgb; - - spec.g *= roughnessFactor; - spec.b *= metallicFactor; - - vec3 emissive = emissiveColor; - emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - - tnorm *= gl_FrontFacing ? 1.0 : -1.0; - - //spec.rgb = vec3(1,1,0); - //col = vec3(0,0,0); - //emissive = vary_tangent.xyz*0.5+0.5; - //emissive = vec3(sign*0.5+0.5); - //emissive = vNt * 0.5 + 0.5; - //emissive = tnorm*0.5+0.5; - // See: C++: addDeferredAttachments(), GLSL: softenLightF - frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse - frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. - frag_data[2] = encodeNormal(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags - frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive -} - -#else - -// forward fullbright implementation for HUDs - -uniform sampler2D diffuseMap; //always in sRGB space - -uniform vec3 emissiveColor; -uniform sampler2D emissiveMap; - -out vec4 frag_color; - -in vec3 vary_position; -in vec4 vertex_color; - -in vec2 base_color_texcoord; -in vec2 emissive_texcoord; - -uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() - -vec3 linear_to_srgb(vec3 c); -vec3 srgb_to_linear(vec3 c); - -void main() -{ - vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; - if (basecolor.a < minimum_alpha) - { - discard; - } - - vec3 col = vertex_color.rgb * srgb_to_linear(basecolor.rgb); - - vec3 emissive = emissiveColor; - emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); - - col += emissive; - - // HUDs are rendered after gamma correction, output in sRGB space - frag_color.rgb = linear_to_srgb(col); - frag_color.a = 0.0; -} - -#endif - diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl deleted file mode 100644 index 0ad9bf5e4b6..00000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl +++ /dev/null @@ -1,143 +0,0 @@ -/** - * @file pbropaqueV.glsl - * - * $LicenseInfo:firstyear=2022&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2022, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#ifndef IS_HUD - -//deferred opaque implementation - -uniform mat4 modelview_matrix; - -#ifdef HAS_SKIN -uniform mat4 projection_matrix; -mat4 getObjectSkinnedTransform(); -#else -uniform mat3 normal_matrix; -uniform mat4 modelview_projection_matrix; -#endif -uniform mat4 texture_matrix0; - -uniform vec4[2] texture_base_color_transform; -uniform vec4[2] texture_normal_transform; -uniform vec4[2] texture_metallic_roughness_transform; -uniform vec4[2] texture_emissive_transform; - -in vec3 position; -in vec4 diffuse_color; -in vec3 normal; -in vec4 tangent; -in vec2 texcoord0; - -out vec2 base_color_texcoord; -out vec2 normal_texcoord; -out vec2 metallic_roughness_texcoord; -out vec2 emissive_texcoord; - -out vec4 vertex_color; - -out vec3 vary_tangent; -flat out float vary_sign; -out vec3 vary_normal; -out vec3 vary_position; - -vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); -vec4 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); - -void main() -{ -#ifdef HAS_SKIN - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - - vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; - vary_position = pos; - gl_Position = projection_matrix*vec4(pos,1.0); - -#else - vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; - //transform vertex - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); -#endif - - base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0); - normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0); - metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0); - emissive_texcoord = texture_transform(texcoord0, texture_emissive_transform, texture_matrix0); - -#ifdef HAS_SKIN - vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz; - vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz; -#else //HAS_SKIN - vec3 n = normal_matrix * normal; - vec3 t = normal_matrix * tangent.xyz; -#endif - - n = normalize(n); - - vec4 transformed_tangent = tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0); - vary_tangent = normalize(transformed_tangent.xyz); - vary_sign = transformed_tangent.w; - vary_normal = n; - - vertex_color = diffuse_color; -} - -#else - -// fullbright HUD implementation - -uniform mat4 modelview_projection_matrix; - -uniform mat4 texture_matrix0; - -uniform vec4[2] texture_base_color_transform; -uniform vec4[2] texture_emissive_transform; - -in vec3 position; -in vec4 diffuse_color; -in vec2 texcoord0; - -out vec2 base_color_texcoord; -out vec2 emissive_texcoord; - -out vec4 vertex_color; - -vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); - -void main() -{ - //transform vertex - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - - base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0); - emissive_texcoord = texture_transform(texcoord0, texture_emissive_transform, texture_matrix0); - - vertex_color = diffuse_color; -} - -#endif - - diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl index 5e1c502822f..c6553bb5028 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl @@ -23,12 +23,14 @@ * $/LicenseInfo$ */ -uniform mat4 modelview_projection_matrix; +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; in vec3 position; void main() { //transform vertex - gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); + vec4 pos = modelview_matrix * vec4(position.xyz, 1.0); + gl_Position = projection_matrix * pos; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl index c75a0e0d5de..c18027cf600 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl @@ -182,3 +182,57 @@ vec4 terrain_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, ve float sign_flip = khr_scale_sign.x * khr_scale_sign.y; return vec4((weights.x * vertex_tangent.xyz) + (weights.y * vertex_binormal.xyz), vertex_tangent.w * sign_flip); } + + +// port of "xform" from LLFace.cpp +void sl_bp_tc_xform(inout vec2 tex_coord, float cosAng, float sinAng, float offS, float offT, float magS, float magT) +{ + // New, good way + float s = tex_coord.x; + float t = tex_coord.y; + + // Texture transforms are done about the center of the face. + s -= 0.5; + t -= 0.5; + + // Handle rotation + float temp = s; + s = s * cosAng + t * sinAng; + t = -temp * sinAng + t * cosAng; + + // Then scale + s *= magS; + t *= magT; + + // Then offset + s += offS + 0.5f; + t += offT + 0.5f; + + tex_coord.x = s; + tex_coord.y = t; +} + + +vec2 sl_bp_texture_transform(vec2 texcoord, vec2 scale, float rotation, vec2 offset) +{ + sl_bp_tc_xform(texcoord, cos(rotation), sin(rotation), offset.x, offset.y, scale.x, scale.y); + return texcoord; +} + +// blinn-phong texture transform +vec2 bp_texture_transform(vec2 vertex_texcoord, vec4[2] transform, mat4 sl_animation_transform) +{ + vec2 texcoord = vertex_texcoord; + + // Apply texture animation first to avoid shearing and other artifacts + texcoord = (sl_animation_transform * vec4(texcoord, 0, 1)).xy; + + texcoord = sl_bp_texture_transform(texcoord, transform[0].xy, transform[0].z, transform[1].xy); + + // To make things more confusing, all SL image assets are upside-down + // We may need an additional sign flip here when we implement a Vulkan backend + + return texcoord; + +} + diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index 1d8a92bac75..5ce6a976e66 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -49,7 +49,7 @@ void unpackMaterial() emissiveColor = gltf_material_data[idx+10].rgb; roughnessFactor = gltf_material_data[idx+11].g; metallicFactor = gltf_material_data[idx+11].b; - minimum_alpha -= gltf_material_data[idx+11].a; + minimum_alpha = gltf_material_data[idx+11].a; } } diff --git a/indra/newview/app_settings/shaders/class1/interface/debugF.glsl b/indra/newview/app_settings/shaders/class1/interface/debugF.glsl index f863d1ad206..43220aa8e01 100644 --- a/indra/newview/app_settings/shaders/class1/interface/debugF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/debugF.glsl @@ -31,3 +31,4 @@ void main() { frag_color = max(color, vec4(0)); } + diff --git a/indra/newview/app_settings/shaders/class2/deferred/blinnphongF.glsl b/indra/newview/app_settings/shaders/class2/deferred/blinnphongF.glsl new file mode 100644 index 00000000000..07c431c7f71 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/blinnphongF.glsl @@ -0,0 +1,452 @@ +/** + * @file blinnphongF.glsl + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// deferred opaque implementation + +#ifdef DEBUG +uniform vec4 debug_color; +#endif + +#ifdef HAS_FRAGMENT_NORMAL +in vec3 vary_normal; +#endif + +vec4 diffuseColor; +float bp_glow; +float emissive; +float emissive_mask; +float env_intensity; +float glossiness; +vec3 specularColor; + +#ifdef ALPHA_MASK +float minimum_alpha; +#endif + +#ifdef SAMPLE_DIFFUSE_MAP +uniform sampler2D diffuseMap; //always in sRGB space +in vec2 diffuse_texcoord; +#endif + +#ifdef SAMPLE_SPECULAR_MAP +uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness +in vec2 specular_texcoord; +#endif + + +#ifdef SAMPLE_NORMAL_MAP +uniform sampler2D bumpMap; +in vec3 vary_tangent; +flat in float vary_sign; +in vec2 normal_texcoord; +#endif + +#ifdef OUTPUT_DIFFUSE_ONLY +out vec4 frag_color; +#else +out vec4 frag_data[4]; +#endif + +#ifdef MIRROR_CLIP +void mirrorClip(vec3 pos); +#endif + +#ifdef FRAG_POSITION +in vec3 vary_position; +#endif + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +#ifdef SAMPLE_MATERIALS_UBO +layout (std140) uniform GLTFMaterials +{ + // index by gltf_material_id + + // [gltf_material_id + [0-1]] - diffuse transform + // [gltf_material_id + [2-3]] - normal transform + // [gltf_material_id + [4-5]] - specular transform + // [gltf_material_id + 6] - .x - emissive factor, .y - emissive mask, .z - glossiness, .w - glow + // Transforms are packed as follows + // packed[0] = vec4(scale.x, scale.y, rotation, offset.x) + // packed[1] = vec4(offset.y, *, *, *) + + // packed[1].yzw varies: + // diffuse transform -- diffuse color + // normal transform -- .y - alpha factor, .z - minimum alpha, .w - environment intensity + // specular transform -- specular color + + + vec4 gltf_material_data[MAX_UBO_VEC4S]; +}; + +flat in int gltf_material_id; + +void unpackMaterial() +{ + int idx = gltf_material_id; + + diffuseColor.rgb = gltf_material_data[idx+1].yzw; + diffuseColor.a = gltf_material_data[idx+3].y; + emissive = gltf_material_data[idx+6].x; + emissive_mask = gltf_material_data[idx+6].y; + bp_glow = gltf_material_data[idx+6].w; + env_intensity = gltf_material_data[idx+3].w; + glossiness = gltf_material_data[idx+6].z; + specularColor = gltf_material_data[idx+5].yzw; + +#ifdef ALPHA_MASK + minimum_alpha = gltf_material_data[idx+3].z; +#endif + +} +#else // SAMPLE_MATERIALS_UBO +void unpackMaterial() +{ +} +#endif + +#ifdef ALPHA_BLEND + +in vec3 vary_fragcoord; + +#ifdef HAS_SUN_SHADOW +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +#endif + +float getShadow(vec3 pos, vec3 norm) +{ +#ifdef HAS_SUN_SHADOW + return sampleDirectionalShadow(pos, norm, vary_fragcoord.xy); +#else + return 1.; +#endif +} + +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); +void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); + +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear); +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); +void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); + +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; + +// Inputs +uniform int sun_up_factor; +uniform vec3 sun_dir; +uniform vec3 moon_dir; + +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec4 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + +vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance) +{ + // SL-14895 inverted attenuation work-around + // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct + // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights() + // to recover the `adjusted_radius` value previously being sent as la. + float falloff_factor = (12.0 * fa) - 9.0; + float inverted_la = falloff_factor / la; + // Yes, it makes me want to cry as well. DJH + + vec3 col = vec3(0); + + //get light vector + vec3 lv = lp.xyz - v; + + //get distance + float dist = length(lv); + float da = 1.0; + + dist /= inverted_la; + + if (dist > 0.0 && inverted_la > 0.0) + { + //normalize light vector + lv = normalize(lv); + + //distance attenuation + float dist_atten = clamp(1.0 - (dist - 1.0*(1.0 - fa)) / fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0f; + + if (dist_atten <= 0.0) + { + return col; + } + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= dot(n, lv); + + float lit = 0.0f; + + float amb_da = ambiance; + if (da >= 0) + { + lit = max(da * dist_atten, 0.0); + col = lit * light_col * diffuse; + amb_da += (da*0.5 + 0.5) * ambiance; + } + amb_da += (da*da*0.5 + 0.5) * ambiance; + amb_da *= dist_atten; + amb_da = min(amb_da, 1.0f - lit); + + // SL-10969 need to see why these are blown out + //col.rgb += amb_da * light_col * diffuse; + + if (spec.a > 0.0) + { + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv + npos); + float nh = dot(n, h); + float nv = dot(n, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da); + vec3 speccol = lit*scol*light_col.rgb*spec.rgb; + speccol = clamp(speccol, vec3(0), vec3(1)); + col += speccol; + + float cur_glare = max(speccol.r, speccol.g); + cur_glare = max(cur_glare, speccol.b); + glare = max(glare, speccol.r); + glare += max(cur_glare, 0.0); + } + } + } + + return max(col, vec3(0.0, 0.0, 0.0)); +} + +#endif + +vec4 getDiffuse() +{ + vec4 diffuse = vec4(1); +#ifdef SAMPLE_DIFFUSE_MAP + diffuse = texture(diffuseMap, diffuse_texcoord.xy).rgba; + emissive = max(emissive, emissive_mask * diffuse.a); + bp_glow *= diffuse.a; +#ifdef ALPHA_MASK + if (diffuse.a * diffuseColor.a < minimum_alpha) + { + discard; + } +#endif +#endif + return diffuse; +} + +vec4 getSpec() +{ + vec4 spec = vec4(0); +#ifdef SAMPLE_SPECULAR_MAP + spec = texture(specularMap, specular_texcoord.xy); + spec.a *= env_intensity; + env_intensity = spec.a; + spec.rgb *= specularColor; + spec.rgb = srgb_to_linear(spec.rgb); +#else + spec = vec4(specularColor, env_intensity); +#endif + return spec; +} + +#ifdef HAS_FRAGMENT_NORMAL +vec3 getNorm() +{ +#ifdef SAMPLE_NORMAL_MAP + // from mikktspace.com + vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0; + float sign = vary_sign; + vec3 vN = vary_normal; + vec3 vT = vary_tangent.xyz; + + vec3 vB = sign * cross(vN, vT); + vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +#else + vec3 tnorm = normalize(vary_normal); +#endif + return tnorm; +} +#endif + +void main() +{ + unpackMaterial(); +#ifdef MIRROR_CLIP + mirrorClip(vary_position); +#endif + + vec4 diffuse = getDiffuse(); + + diffuse.rgb *= diffuseColor.rgb; + +#ifdef HAS_FRAGMENT_NORMAL + vec3 tnorm = getNorm(); +#endif + + vec4 spec = getSpec(); + +#ifdef ALPHA_BLEND + diffuse.rgb = srgb_to_linear(diffuse.rgb); + //forward rendering, output lit linear color + spec.a = glossiness; // pack glossiness into spec alpha for lighting functions + + vec3 pos = vary_position; + + float shadow = getShadow(pos, tnorm); + + vec3 color = vec3(0,0,0); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + float bloom = 0.0; + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + calcAtmosphericVarsLinear(pos.xyz, tnorm.xyz, light_dir, sunlit, amblit, additive, atten); + + vec3 sunlit_linear = srgb_to_linear(sunlit); + vec3 amblit_linear = amblit; + + vec3 ambenv; + vec3 glossenv; + vec3 legacyenv; + sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xy*0.5+0.5, pos.xyz, tnorm.xyz, glossiness, env_intensity, true, amblit_linear); + + color = ambenv; + + float da = clamp(dot(tnorm.xyz, light_dir.xyz), 0.0, 1.0); + vec3 sun_contrib = min(da, shadow) * sunlit_linear; + color.rgb += sun_contrib; + color *= diffuse.rgb; + + vec3 refnormpersp = reflect(pos.xyz, tnorm.xyz); + + float glare = 0.0; + + if (glossiness > 0.0) + { + vec3 lv = light_dir.xyz; + vec3 h, l, v = -normalize(pos.xyz); + float nh, nl, nv, vh, lightDist; + vec3 n = tnorm.xyz; + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); + + if (nl > 0.0 && nh > 0.0) + { + float lit = min(nl*6.0, 1.0); + + float sa = nh; + float fres = pow(1 - vh, 5) * 0.4+0.5; + float gtdenom = 2 * nh; + float gt = max(0,(min(gtdenom * nv / vh, gtdenom * nl / vh))); + + float scol = shadow*fres*texture(lightFunc, vec2(nh, glossiness)).r*gt/(nh*nl); + color.rgb += lit*scol*sunlit_linear.rgb*spec.rgb; + } + + // add radiance map + applyGlossEnv(color, glossenv, spec, pos.xyz, tnorm.xyz); + } + + color = mix(color.rgb, diffuse.rgb, emissive); + + if (env_intensity > 0.0) + { // add environmentmap + applyLegacyEnv(color, legacyenv, spec, pos.xyz, tnorm.xyz, env_intensity); + + float cur_glare = max(max(legacyenv.r, legacyenv.g), legacyenv.b); + cur_glare = clamp(cur_glare, 0, 1); + cur_glare *= env_intensity; + glare += cur_glare; + } + + vec3 npos = normalize(-pos.xyz); + vec3 light = vec3(0, 0, 0); + +#define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, spec, pos.xyz, tnorm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare, light_attenuation[i].w ); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + color += light; + + color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; + + glare *= 1.0-emissive; + glare = min(glare, 1.0); + float al = max(diffuse.a, glare) * diffuseColor.a; + + diffuse.rgb = color.rgb; + diffuse.a = al; +#endif + +#ifdef OUTPUT_DIFFUSE_ONLY +#ifdef OUTPUT_SRGB + diffuse.rgb = linear_to_srgb(diffuse.rgb); +#endif + +#ifdef DEBUG + diffuse = debug_color; +#endif + + frag_color = diffuse; +#else + //diffuse.rgb = vec3(0.85); + //spec.rgb = vec3(0); + //env_intensity = 0; + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = max(vec4(diffuse.rgb, bp_glow), vec4(0)); + frag_data[1] = max(vec4(spec.rgb,glossiness), vec4(0)); + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = max(vec4(env_intensity, emissive, 0, 0), vec4(0)); +#endif +} + diff --git a/indra/newview/app_settings/shaders/class2/deferred/gltfpbrF.glsl b/indra/newview/app_settings/shaders/class2/deferred/gltfpbrF.glsl new file mode 100644 index 00000000000..61bc2695d33 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/gltfpbrF.glsl @@ -0,0 +1,337 @@ +/** + * @file gltfpbrF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// deferred opaque implementation + +#ifdef DEBUG +uniform vec4 debug_color; +#endif + +vec4 baseColorFactor; +float bp_glow; +float metallicFactor; +float roughnessFactor; +vec3 emissiveColor; + +#ifdef ALPHA_MASK +float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() +#endif + +#ifdef SAMPLE_BASE_COLOR_MAP +uniform sampler2D diffuseMap; //always in sRGB space +in vec2 base_color_texcoord; +#endif + + +#ifdef SAMPLE_ORM_MAP +uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness +in vec2 metallic_roughness_texcoord; +#endif + +#ifdef HAS_FRAGMENT_NORMAL +in vec3 vary_normal; +#endif + +#ifdef SAMPLE_NORMAL_MAP +uniform sampler2D bumpMap; +in vec3 vary_tangent; +flat in float vary_sign; +in vec2 normal_texcoord; +#endif + +#ifdef SAMPLE_EMISSIVE_MAP +uniform sampler2D emissiveMap; +in vec2 emissive_texcoord; +#endif + +#ifdef OUTPUT_BASE_COLOR_ONLY +out vec4 frag_color; +#else +out vec4 frag_data[4]; +#endif + +#ifdef FRAG_POSITION +in vec3 vary_position; +#endif + +#ifdef MIRROR_CLIP +void mirrorClip(vec3 pos); +#endif + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +#ifdef SAMPLE_MATERIALS_UBO +layout (std140) uniform GLTFMaterials +{ + // index by gltf_material_id + + // [gltf_material_id + [0-1]] - base color transform + // [gltf_material_id + [2-3]] - normal transform + // [gltf_material_id + [4-5]] - metallic roughness transform + // [gltf_material_id + [6-7]] - emissive transform + + // Transforms are packed as follows + // packed[0] = vec4(scale.x, scale.y, rotation, offset.x) + // packed[1] = vec4(offset.y, *, *, *) + + // packed[1].yzw varies: + // base color transform -- base color factor + // normal transform -- .y - alpha factor, .z - minimum alpha, .w - glow + // metallic roughness transform -- .y - roughness factor, .z - metallic factor + // emissive transform -- emissive factor + + + vec4 gltf_material_data[MAX_UBO_VEC4S]; +}; + +flat in int gltf_material_id; + +void unpackMaterial() +{ + int idx = gltf_material_id; + + baseColorFactor.rgb = gltf_material_data[idx+1].yzw; + baseColorFactor.a = gltf_material_data[idx+3].y; + bp_glow = gltf_material_data[idx+3].w; + roughnessFactor = gltf_material_data[idx+5].y; + metallicFactor = gltf_material_data[idx+5].z; + emissiveColor = gltf_material_data[idx+7].yzw; + +#ifdef ALPHA_MASK + minimum_alpha = gltf_material_data[idx+3].z; +#endif +} +#else // SAMPLE_MATERIALS_UBO +void unpackMaterial() +{ +} +#endif + +#ifdef ALPHA_BLEND +in vec3 vary_fragcoord; + +// Lights +// See: LLRender::syncLightState() + +uniform int sun_up_factor; +uniform vec3 sun_dir; +uniform vec3 moon_dir; + +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; // spot direction +uniform vec4 light_attenuation[8]; // linear, quadratic, is omni, unused, See: LLPipeline::setupHWLights() and syncLightState() +uniform vec3 light_diffuse[8]; +uniform vec2 light_deferred_attenuation[8]; // light size and falloff + +void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); + +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); +float calcLegacyDistanceAttenuation(float distance, float falloff); +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear); + +void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor); + +vec3 pbrBaseLight(vec3 diffuseColor, + vec3 specularColor, + float metallic, + vec3 pos, + vec3 norm, + float perceptualRoughness, + vec3 light_dir, + vec3 sunlit, + float scol, + vec3 radiance, + vec3 irradiance, + vec3 colorEmissive, + float ao, + vec3 additive, + vec3 atten); + +vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, + float metallic, + vec3 n, // normal + vec3 v, // surface point to camera + vec3 l); //surface point to light + +vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, + float metallic, + vec3 n, // normal + vec3 p, // pixel position + vec3 v, // view vector (negative normalized pixel position) + vec3 lp, // light position + vec3 ld, // light direction (for spotlights) + vec3 lightColor, + float lightSize, float falloff, float is_pointlight, float ambiance); +#endif + +void main() +{ + unpackMaterial(); +#ifdef MIRROR_CLIP + mirrorClip(vary_position); +#endif + + vec4 basecolor = vec4(1); +#ifdef SAMPLE_BASE_COLOR_MAP + basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; + +#ifdef GAMMA_CORRECT_BASE_COLOR + basecolor.rgb = srgb_to_linear(basecolor.rgb); +#endif + basecolor *= baseColorFactor; + +#ifdef ALPHA_MASK + if (basecolor.a < minimum_alpha) + { + discard; + } +#endif + +#endif + +#ifdef HAS_FRAGMENT_NORMAL +#ifdef SAMPLE_NORMAL_MAP + // from mikktspace.com + vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0; + float sign = vary_sign; + vec3 vN = vary_normal; + vec3 vT = vary_tangent.xyz; + + vec3 vB = sign * cross(vN, vT); + vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +#else + vec3 tnorm = normalize(vary_normal); +#endif + +#ifdef DOUBLE_SIDED + tnorm *= gl_FrontFacing ? 1.0 : -1.0; +#endif +#endif + + // RGB = Occlusion, Roughness, Metal + // default values, see LLViewerTexture::sDefaultPBRORMImagep + // occlusion 1.0 + // roughness 0.0 + // metal 0.0 + vec3 spec = vec3(1, roughnessFactor, metallicFactor); + +#ifdef SAMPLE_ORM_MAP + spec *= texture(specularMap, metallic_roughness_texcoord.xy).rgb; +#endif + + vec3 emissive = emissiveColor; + +#ifdef SAMPLE_EMISSIVE_MAP + emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); +#endif + +#ifdef OUTPUT_BASE_COLOR_ONLY +#ifdef ALPHA_BLEND + + vec3 pos = vary_position; + float ao = spec.r; + float perceptualRoughness = spec.g; + float metallic = spec.b; + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; + + float scol = 1.0; +#ifdef HAS_SUN_SHADOW + scol = sampleDirectionalShadow(pos.xyz, tnorm.xyz, frag); +#endif + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + calcAtmosphericVarsLinear(pos.xyz, tnorm, light_dir, sunlit, amblit, additive, atten); + + vec3 sunlit_linear = srgb_to_linear(sunlit); + + // PBR IBL + float gloss = 1.0 - perceptualRoughness; + vec3 irradiance = vec3(0); + vec3 radiance = vec3(0); + sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, tnorm.xyz, gloss, true, amblit); + + vec3 diffuseColor; + vec3 specularColor; + calcDiffuseSpecular(basecolor.rgb, metallic, diffuseColor, specularColor); + + vec3 v = -normalize(pos.xyz); + + vec3 color = pbrBaseLight(diffuseColor, specularColor, metallic, v, tnorm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, emissive, ao, additive, atten); + + vec3 light = vec3(0); + + // Punctual lights +#define LIGHT_LOOP(i) light += pbrCalcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, tnorm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + color.rgb += light.rgb; + + color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; + + basecolor.rgb = color.rgb; + +#else // ALPHA_BLEND +#ifdef SAMPLE_EMISSIVE_MAP + basecolor.rgb += emissive; +#endif +#endif + +#ifdef OUTPUT_SRGB + basecolor.rgb = linear_to_srgb(basecolor.rgb); +#endif + +#ifdef DEBUG + basecolor = debug_color; +#endif + + frag_color = basecolor; +#else + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = max(vec4(basecolor.rgb, bp_glow), vec4(0)); + frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); + frag_data[3] = max(vec4(emissive,0), vec4(0)); +#endif +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index f73a0a4fd80..f7cfbde7055 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -127,29 +127,23 @@ void main() vec4 pos = getPositionWithDepth(tc, depth); vec4 norm = getNorm(tc); vec3 colorEmissive = texture(emissiveRect, tc).rgb; - float envIntensity = colorEmissive.r; vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; vec4 baseColor = texture(diffuseRect, tc); - vec4 spec = texture(specularRect, tc); // NOTE: PBR linear Emissive + float bp_glow = baseColor.a; + vec4 spec = texture(specularRect, tc); // NOTE: PBR linear Emissive #if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO) vec2 scol_ambocc = texture(lightMap, vary_fragcoord.xy).rg; #endif -#if defined(HAS_SUN_SHADOW) - float scol = max(scol_ambocc.r, baseColor.a); -#else - float scol = 1.0; -#endif #if defined(HAS_SSAO) - float ambocc = scol_ambocc.g; + float ambocc = scol_ambocc.g; #else float ambocc = 1.0; #endif vec3 color = vec3(0); - float bloom = 0.0; vec3 sunlit; vec3 amblit; @@ -164,8 +158,14 @@ void main() vec3 irradiance = vec3(0); vec3 radiance = vec3(0); + float scol = 1.0; + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { +#if defined(HAS_SUN_SHADOW) + scol = scol_ambocc.r; +#endif + vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; @@ -185,6 +185,9 @@ void main() vec3 v = -normalize(pos.xyz); color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten); + + float lum = max(max(colorEmissive.r, colorEmissive.g), colorEmissive.b); + bp_glow *= lum; } else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_HDRI)) { @@ -200,6 +203,13 @@ void main() } else { + float envIntensity = colorEmissive.r; + float bp_emissive = colorEmissive.g; + +#if defined(HAS_SUN_SHADOW) + scol = max(scol_ambocc.r, bp_emissive); +#endif + // legacy shaders are still writng sRGB to gbuffer baseColor.rgb = srgb_to_linear(baseColor.rgb); @@ -247,17 +257,16 @@ void main() // add radiance map applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz); - } - color.rgb = mix(color.rgb, baseColor.rgb, baseColor.a); + color.rgb = mix(color.rgb, baseColor.rgb, bp_emissive); if (envIntensity > 0.0) { // add environment map applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity); } - } + } frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results - frag_color.a = 0.0; + frag_color.a = bp_glow; } diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 21d04607ca0..fc5a362100e 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -71,7 +71,7 @@ RenderFSAASamples 1 3 RenderMaxTextureIndex 1 16 RenderGLContextCoreProfile 1 1 RenderGLMultiThreadedTextures 1 0 -RenderGLMultiThreadedMedia 1 1 +RenderGLMultiThreadedMedia 1 0 RenderReflectionProbeResolution 1 128 RenderScreenSpaceReflections 1 1 RenderMirrors 1 1 diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index 304eb264323..f3ddde85ab8 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -28,6 +28,7 @@ #include "llvertexbuffer.h" #include "llvolumeoctree.h" +#include "llrender.h" #include "boost/json.hpp" // LL GLTF Implementation diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index f596ce04f8f..7d8f9478410 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -352,6 +352,7 @@ void GLTFSceneManager::renderAlpha() void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) { +#if 0 LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; llassert(obj->getVolume()->getParams().getSculptID() == gltf_id); llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF); @@ -366,6 +367,7 @@ void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) obj->ref(); gAssetStorage->getAssetData(gltf_id, LLAssetType::AT_GLTF, onGLTFLoadComplete, obj); +#endif } //static @@ -373,6 +375,7 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp { LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("GLTF Bin Load Complete"); LLViewerObject* obj = (LLViewerObject*)user_data; llassert(asset_type == LLAssetType::AT_GLTF_BIN); @@ -502,6 +505,7 @@ void GLTFSceneManager::update() LLAppViewer::instance()->postToMainCoro( [=, this]() { + LL_PROFILE_ZONE_NAMED("GLTF Json Upload Finish"); if (mUploadingAsset) { // HACK: save buffer to cache to emulate a successful upload diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3d4f5e10545..93ea33a4cb8 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1078,7 +1078,11 @@ void LLAgent::setRegion(LLViewerRegion *regionp) } // Pass new region along to metrics components that care about this level of detail. - LLAppViewer::metricsUpdateRegion(regionp->getHandle()); + U64 handle = regionp->getHandle(); + LLAppViewer::instance()->postToMainCoro([handle]() + { + LLAppViewer::metricsUpdateRegion(handle); + }); } mRegionp = regionp; diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index d4767e18afb..07f1b1d48f9 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1129,6 +1129,7 @@ void LLAgentCamera::resetPanDiff() //----------------------------------------------------------------------------- void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) { + LL_PROFILE_ZONE_SCOPED; static LLVector3 last_at_axis; if (!isAgentAvatarValid()) return; @@ -1136,8 +1137,8 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) LLQuaternion av_inv_rot = ~gAgentAvatarp->mRoot->getWorldRotation(); LLVector3 root_at = LLVector3::x_axis * gAgentAvatarp->mRoot->getWorldRotation(); - if (LLTrace::get_frame_recording().getLastRecording().getLastValue(*gViewerWindow->getMouseVelocityStat()) < 0.01f - && (root_at * last_at_axis > 0.95f)) + //if (LLTrace::get_frame_recording().getLastRecording().getLastValue(*gViewerWindow->getMouseVelocityStat()) < 0.01f + // && (root_at * last_at_axis > 0.95f)) { LLVector3 vel = gAgentAvatarp->getVelocity(); if (vel.magVecSquared() > 4.f) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 78820802f96..8197d58b10a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -113,6 +113,14 @@ #include "lllocalbitmaps.h" #include "llperfstats.h" #include "llgltfmateriallist.h" +#include "llmaterialmgr.h" +#include "lltoolselectland.h" +#include "lltoolindividual.h" +#include "lltoolcomp.h" +#include "lltoolface.h" +#include "lltoolpipette.h" +#include "glworkqueue.h" +#include "llremoteparcelrequest.h" // Linden library includes #include "fsyspath.h" @@ -569,7 +577,6 @@ static void settings_to_globals() static void settings_modify() { - LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); LLPipeline::sRenderDeferred = true; // false is deprecated LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred; LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); @@ -720,6 +727,75 @@ class LLUITranslationBridge : public LLTranslationBridge } }; +void create_simpletons() +{ + //LLSimpleton creations + LLEnvironment::createInstance(); + LLWorld::createInstance(); + LLViewerStatsRecorder::createInstance(); + LLSelectMgr::createInstance(); + LLViewerCamera::createInstance(); + LL::GLTFSceneManager::createInstance(); + LLDeferredSounds::createInstance(); + LLSafeHandle::NullInstanceHolder::createInstance(); + LLSafeHandle::NullInstanceHolder::createInstance(); + LLMaterialMgr::createInstance(); + LLSpeakerVolumeStorage::createInstance(); + LLToolSelectLand::createInstance(); + LLToolIndividual::createInstance(); + LLToolCompInspect::createInstance(); + LLToolCompTranslate::createInstance(); + LLToolCompScale::createInstance(); + LLToolCompRotate::createInstance(); + LLToolCompCreate::createInstance(); + LLToolCompGun::createInstance(); + LLToolFace::createInstance(); + LLToolPipette::createInstance(); + LLToolMgr::createInstance(); + LLWorldMap::createInstance(); + LLHUDRenderNotifier::createInstance(); + LLRemoteParcelInfoProcessor::createInstance(); + + if (gSavedSettings.getBOOL("IdleThread")) + { + LL::GLThreadPool::createInstance(); + } +} + +void destroy_simpletons() +{ + // LLSimpleton deletions + LL::GLTFSceneManager::deleteSingleton(); + LLEnvironment::deleteSingleton(); + LLSelectMgr::deleteSingleton(); + LLViewerStatsRecorder::deleteSingleton(); + LLViewerEventRecorder::deleteSingleton(); + LLWorld::deleteSingleton(); + LLVoiceClient::deleteSingleton(); + LLUI::deleteSingleton(); + LLDeferredSounds::deleteSingleton(); + LLSafeHandle::NullInstanceHolder::deleteSingleton(); + LLSafeHandle::NullInstanceHolder::deleteSingleton(); + LLMaterialMgr::deleteSingleton(); + LLSpeakerVolumeStorage::deleteSingleton(); + LLToolSelectLand::deleteSingleton(); + LLToolIndividual::deleteSingleton(); + LLToolCompInspect::deleteSingleton(); + LLToolCompTranslate::deleteSingleton(); + LLToolCompScale::deleteSingleton(); + LLToolCompRotate::deleteSingleton(); + LLToolCompCreate::deleteSingleton(); + LLToolCompGun::deleteSingleton(); + LLToolFace::deleteSingleton(); + LLToolPipette::deleteSingleton(); + LLToolMgr::deleteSingleton(); + LLWorldMap::deleteSingleton(); + LLHUDRenderNotifier::deleteSingleton(); + LLRemoteParcelInfoProcessor::deleteSingleton(); + + LL::GLThreadPool::deleteSingleton(); +} + bool LLAppViewer::init() { @@ -884,8 +960,6 @@ bool LLAppViewer::init() ///////////////////////////////////////////////// - LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated - LLViewerFloaterReg::registerFloaters(); ///////////////////////////////////////////////// @@ -1320,14 +1394,7 @@ bool LLAppViewer::init() // Load User's bindings loadKeyBindings(); - //LLSimpleton creations - LLEnvironment::createInstance(); - LLWorld::createInstance(); - LLViewerStatsRecorder::createInstance(); - LLSelectMgr::createInstance(); - LLViewerCamera::createInstance(); - LL::GLTFSceneManager::createInstance(); - + create_simpletons(); #if LL_WINDOWS if (!mSecondInstance) @@ -1469,12 +1536,21 @@ void sendGameControlInput() gAgent.sendMessage(); } +extern bool gShaderProfileFrame; bool LLAppViewer::doFrame() { LL_RECORD_BLOCK_TIME(FTM_FRAME); LL_PROFILE_GPU_ZONE("Frame"); + + if (gShaderProfileFrame) { + LLGLSLShader::initProfile(); + } + + { + LLVertexBuffer::updateClass(); + // and now adjust the visuals from previous frame. if(LLPerfStats::tunables.userAutoTuneEnabled && LLPerfStats::tunables.tuningFlag != LLPerfStats::Tunables::Nothing) { @@ -1586,6 +1662,7 @@ bool LLAppViewer::doFrame() } // Update state based on messages, user input, object idle. + if (!LL::GLThreadPool::instanceExists() || (LLStartUp::getStartupState() != STATE_STARTED)) { { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df pauseMainloopTimeout"); @@ -1604,6 +1681,27 @@ bool LLAppViewer::doFrame() } } + // Update statistics for this frame + update_statistics(); + + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; + + // *TODO: Add configuration controls for this + F32 seconds = report_interval.getElapsedTimeF32(); + if (seconds >= app_metrics_interval) + { + metricsSend(!gDisconnected); + report_interval.reset(); + } + } + + // update agent camera before display() + gAgentCamera.updateCamera(); + + gObjectList.updateGL(); + if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) { pauseMainloopTimeout(); @@ -1632,7 +1730,6 @@ bool LLAppViewer::doFrame() LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Snapshot"); pingMainloopTimeout("Main:Snapshot"); - gPipeline.mReflectionMapManager.update(); LLFloaterSnapshot::update(); // take snapshots LLFloaterSimpleSnapshot::update(); gGLActive = false; @@ -2269,14 +2366,7 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); LLError::LLCallStacks::cleanup(); - LL::GLTFSceneManager::deleteSingleton(); - LLEnvironment::deleteSingleton(); - LLSelectMgr::deleteSingleton(); - LLViewerStatsRecorder::deleteSingleton(); - LLViewerEventRecorder::deleteSingleton(); - LLWorld::deleteSingleton(); - LLVoiceClient::deleteSingleton(); - LLUI::deleteSingleton(); + destroy_simpletons(); // It's not at first obvious where, in this long sequence, a generic cleanup // call OUGHT to go. So let's say this: as we migrate cleanup from @@ -4676,23 +4766,6 @@ void LLAppViewer::saveNameCache() } } - -/*! @brief This class is an LLFrameTimer that can be created with - an elapsed time that starts counting up from the given value - rather than 0.0. - - Otherwise it behaves the same way as LLFrameTimer. -*/ -class LLFrameStatsTimer : public LLFrameTimer -{ -public: - LLFrameStatsTimer(F64 elapsed_already = 0.0) - : LLFrameTimer() - { - mStartTime -= elapsed_already; - } -}; - static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); static LLTrace::BlockTimerStatHandle FTM_CLEANUP("Cleanup"); static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLES("Drawables"); @@ -4859,43 +4932,20 @@ void LLAppViewer::idle() gAgent.resetControlFlags(); } - ////////////////////////////////////// - // - // Manage statistics - // - // + // Print the object debugging stats + static LLFrameTimer object_debug_timer; + if (object_debug_timer.getElapsedTimeF32() > 5.f) { - // Initialize the viewer_stats_timer with an already elapsed time - // of SEND_STATS_PERIOD so that the initial stats report will - // be sent immediately. - static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); - - // Update session stats every large chunk of time - // *FIX: (?) SAMANTHA - if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) + object_debug_timer.reset(); + if (gObjectList.mNumDeadObjectUpdates) { - LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; - bool include_preferences = false; - send_viewer_stats(include_preferences); - viewer_stats_timer.reset(); + LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; + gObjectList.mNumDeadObjectUpdates = 0; } - - // Print the object debugging stats - static LLFrameTimer object_debug_timer; - if (object_debug_timer.getElapsedTimeF32() > 5.f) + if (gObjectList.mNumUnknownUpdates) { - object_debug_timer.reset(); - if (gObjectList.mNumDeadObjectUpdates) - { - LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; - gObjectList.mNumDeadObjectUpdates = 0; - } - if (gObjectList.mNumUnknownUpdates) - { - LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; - gObjectList.mNumUnknownUpdates = 0; - } - + LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; + gObjectList.mNumUnknownUpdates = 0; } } @@ -4913,12 +4963,8 @@ void LLAppViewer::idle() idleNameCache(); idleNetwork(); - // Check for away from keyboard, kick idle agents. idle_afk_check(); - - // Update statistics for this frame - update_statistics(); } //////////////////////////////////////// @@ -4931,30 +4977,13 @@ void LLAppViewer::idle() if (!mQuitRequested) //MAINT-4243 #endif { -// LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); - // Do event notifications if necessary. Yes, we may want to move this elsewhere. gEventNotifier.update(); - gIdleCallbacks.callFunctions(); gInventory.idleNotifyObservers(); LLAvatarTracker::instance().idleNotifyObservers(); } - // Metrics logging (LLViewerAssetStats, etc.) - { - static LLTimer report_interval; - - // *TODO: Add configuration controls for this - F32 seconds = report_interval.getElapsedTimeF32(); - if (seconds >= app_metrics_interval) - { - metricsSend(! gDisconnected); - report_interval.reset(); - } - } - - // Update layonts, handle mouse events, tooltips, e t c // updateUI() needs to be called even in case viewer disconected // since related notification still needs handling and allows @@ -5131,10 +5160,42 @@ void LLAppViewer::idle() { LLViewerJoystick::getInstance()->moveObjects(); } + } + + ////////////////////////////////////// + // + // Update images, using the image stats generated during object update/culling + // + // Can put objects onto the retextured list. + // + // Doing this here gives hardware occlusion queries extra time to complete + LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); + + { + LL_PROFILE_ZONE_NAMED("Update Images"); + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Class"); + LLViewerTexture::updateClass(); + } - gAgentCamera.updateCamera(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("List"); + F32 max_image_decode_time = 0.050f * gFrameIntervalSeconds.value(); // 50 ms/second decode time + max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f); // min 2ms/frame, max 5ms/frame) + gTextureList.updateImages(max_image_decode_time); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("GLTF Materials Cleanup"); + //remove dead gltf materials + gGLTFMaterialList.flushMaterials(); + } } + // update nearby lights to main camera + gPipeline.calcNearbyLights(LLViewerCamera::instance()); + // update media focus LLViewerMediaFocus::getInstance()->update(); @@ -5502,7 +5563,6 @@ void LLAppViewer::idleNetwork() // Retransmit unacknowledged packets. gXferManager->retransmitUnackedPackets(); gAssetStorage->checkForTimeouts(); - gViewerThrottle.updateDynamicThrottle(); // Check that the circuit between the viewer and the agent's current // region is still alive diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 6e02869fba9..d286d027ff9 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -233,6 +233,7 @@ class LLAppViewer : public LLApp // Note: mQuitRequested can be aborted by user. void outOfMemorySoftQuit(); + void idle(); protected: virtual bool initWindow(); // Initialize the viewer's window. virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system @@ -273,7 +274,6 @@ class LLAppViewer : public LLApp static void recordMarkerVersion(LLAPRFile& marker_file); bool markerIsSameVersion(const std::string& marker_name) const; - void idle(); void idleShutdown(); // update avatar SLID and display name caches void idleNameCache(); diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index 97c24c3cba1..f18da9289f9 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -136,12 +136,12 @@ class LLAvatarRenderNotifier : public LLSingleton }; // Class to notify user about heavy set of HUD -class LLHUDRenderNotifier : public LLSingleton +class LLHUDRenderNotifier : public LLSimpleton { - LLSINGLETON(LLHUDRenderNotifier); +public: + LLHUDRenderNotifier(); ~LLHUDRenderNotifier(); -public: void updateNotificationHUD(hud_complexity_list_t complexity); bool isNotificationVisible(); diff --git a/indra/newview/lldeferredsounds.cpp b/indra/newview/lldeferredsounds.cpp index 44f51545dc5..c0a39a8ad82 100644 --- a/indra/newview/lldeferredsounds.cpp +++ b/indra/newview/lldeferredsounds.cpp @@ -35,6 +35,7 @@ void LLDeferredSounds::deferSound(SoundData& sound) } void LLDeferredSounds::playdeferredSounds() { + LL_PROFILE_ZONE_SCOPED; while(soundVector.size()) { if (gAudiop) diff --git a/indra/newview/lldeferredsounds.h b/indra/newview/lldeferredsounds.h index 9f3425fc666..490a6843bf3 100644 --- a/indra/newview/lldeferredsounds.h +++ b/indra/newview/lldeferredsounds.h @@ -30,9 +30,8 @@ #include "llsingleton.h" #include "llaudioengine.h" -class LLDeferredSounds : public LLSingleton +class LLDeferredSounds : public LLSimpleton { - LLSINGLETON_EMPTY_CTOR(LLDeferredSounds); std::vector soundVector; public: //Add sounds to be played once progress bar is hidden (such as after teleport or loading screen) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 70ae4ee13fd..85a133e7fa7 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -173,7 +173,7 @@ void LLDrawable::destroy() // Attempt to catch violations of this in debug, // knowing that some false alarms may result // - llassert(!LLSpatialGroup::sNoDelete); + //llassert(!LLSpatialGroup::sNoDelete); /* cannot be guaranteed and causes crashes on false alarms if (LLSpatialGroup::sNoDelete) @@ -232,6 +232,29 @@ const LLMatrix4& LLDrawable::getRenderMatrix() const return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); } +const LLMatrix4& LLDrawable::getGLTFRenderMatrix(bool local_frame, LLMatrix4* aux_mat) +{ + if (local_frame) + { + // inside an altered coordinate frame, return parent relative transform + mGLTFRenderMatrix.initAll(getScale(), mXform.getRotation(), mXform.getPosition()); + } + else + { + // inside an unaltered coordinate frame, return world relative transform + mXform.updateMatrix(); + mGLTFRenderMatrix.initScale(mVObjp->getScale()); + mGLTFRenderMatrix *= getWorldMatrix(); + } + + if (aux_mat != nullptr) + { + mGLTFRenderMatrix *= *aux_mat; + } + + return mGLTFRenderMatrix; +} + bool LLDrawable::isLight() const { LLViewerObject* objectp = mVObjp; @@ -701,7 +724,6 @@ F32 LLDrawable::updateXform(bool undamped) ((dist_vec_squared(old_pos, target_pos) > 0.f) || (1.f - dot(old_rot, target_rot)) > 0.f)) { //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247 - mVObjp->shrinkWrap(); gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION); } else if (!getVOVolume() && !isAvatar()) @@ -719,6 +741,11 @@ F32 LLDrawable::updateXform(bool undamped) mVObjp->getControlAvatar()->matchVolumeTransform(); } + // update GLTF render matrix + getGLTFRenderMatrix(); + + gPipeline.markTransformDirty(this); + if (mSpatialBridge) { gPipeline.markMoved(mSpatialBridge, false); @@ -1132,6 +1159,8 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp) if (cur_groupp != groupp && getVOVolume()) { + gPipeline.markTransformDirty(cur_groupp); + gPipeline.markTransformDirty((LLSpatialGroup*) groupp); //NULL out vertex buffer references for volumes on spatial group change to maintain //requirement that every face vertex buffer is either NULL or points to a vertex buffer //contained by its drawable's spatial group @@ -1140,6 +1169,7 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp) if (LLFace* facep = getFace(i)) { facep->clearVertexBuffer(); + facep->mGLTFDrawInfo.clear(); } } } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index a7ac9da6186..aac73f91a9c 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -101,6 +101,7 @@ class LLDrawable const LLMatrix4& getWorldMatrix() const { return mXform.getWorldMatrix(); } const LLMatrix4& getRenderMatrix() const; + const LLMatrix4& getGLTFRenderMatrix(bool local_frame = false, LLMatrix4* aux_mat = nullptr); void setPosition(LLVector3 v) const { } const LLVector3& getPosition() const { return mXform.getPosition(); } const LLVector3& getWorldPosition() const { return mXform.getPositionW(); } @@ -287,10 +288,16 @@ class LLDrawable ACTIVE_CHILD = 0x02000000, FOR_UNLOAD = 0x04000000, //should be unload from memory MIRROR = 0x08000000, // Used as a mirror, needs a hero probe position to be calculated. + HAS_GLTF = 0x10000000, // Has a GLTF material on at least 1 face + IN_TRANSFORM_Q = 0x20000000, // in transform rebuild queue } EDrawableFlags; public: LLXformMatrix mXform; + LLMatrix4 mGLTFRenderMatrix; + + U32 mTransformIndex = 0xFFFFFFFF; // index of transform in LLSpatialGroup's transform UBO + U32 mPrimScaleIndex = 0xFFFFFFFF; // index of prim scale in LLSpatialGroup's material UBO // vis data LLPointer mParent; diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 7bd5206453e..33bda017ff6 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -55,6 +55,11 @@ S32 LLDrawPool::sNumDrawPools = 0; +#define USE_VAO 0 + +static U32 gl_indices_type[] = { GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }; +static U32 gl_indices_size[] = { sizeof(U16), sizeof(U32) }; + //============================= // Draw Pool Implementation //============================= @@ -767,149 +772,474 @@ void teardown_texture_matrix(LLDrawInfo& params) } } -void LLRenderPass::pushGLTFBatches(U32 type, bool textured) +static glm::mat4 last_model_matrix; +static U32 transform_ubo = 0; +static size_t last_mat = 0; + +static S32 base_tu = -1; +static S32 norm_tu = -1; +static S32 orm_tu = -1; +static S32 emis_tu = -1; +static S32 diffuse_tu = -1; +static S32 specular_tu = -1; +static U16 cur_base_tex = 0; +static U16 cur_norm_tex = 0; +static U16 cur_orm_tex = 0; +static U16 cur_emis_tex = 0; +static U16 cur_diffuse_tex = 0; +static U16 cur_specular_tex = 0; +static U16 base_instance_index = 0; + +extern LLCullResult* sCull; + +static void pre_push_gltf_batches() +{ + STOP_GLERROR; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(gGLModelView); + gGL.syncMatrices(); + transform_ubo = 0; + last_mat = 0; + + base_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + norm_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::BUMP_MAP); + orm_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::SPECULAR_MAP); + emis_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::EMISSIVE_MAP); + + base_instance_index = LLGLSLShader::sCurBoundShaderPtr->getUniformLocation(LLShaderMgr::GLTF_BASE_INSTANCE); + + cur_emis_tex = cur_orm_tex = cur_norm_tex = cur_base_tex = 0; + + S32 tex[] = { base_tu, norm_tu, orm_tu, emis_tu }; + + for (S32 tu : tex) + { + if (tu != -1) + { + gGL.getTexUnit(tu)->bindManual(LLTexUnit::TT_TEXTURE, 0, true); + } + } + STOP_GLERROR; +} + +void LLRenderPass::pushGLTFBatches(LLGLSLShader& shader, bool rigged, U32 alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim) { - if (textured) + if (rigged) { - pushGLTFBatches(type); + auto& draw_info = sCull->mGLTFBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!draw_info.empty()) + { + shader.bind(rigged); + pushRiggedGLTFBatches(draw_info, planar, tex_anim); + } } else { - pushUntexturedGLTFBatches(type); + auto& draw_info = sCull->mGLTFBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!draw_info.empty()) + { + shader.bind(rigged); + pushGLTFBatches(draw_info, planar, tex_anim); + } } } -void LLRenderPass::pushGLTFBatches(U32 type) +void LLRenderPass::pushBPBatches(LLGLSLShader& shader, bool rigged, U32 alpha_mode, U8 tex_mask, bool planar, bool tex_anim) +{ + if (rigged) + { + auto& draw_info = sCull->mBPBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][0][planar][tex_anim]; + if (!draw_info.empty()) + { + shader.bind(rigged); + pushRiggedGLTFBatches(draw_info, planar, tex_anim); + } + } + else + { + auto& draw_info = sCull->mBPBatches.mDrawInfo[alpha_mode][tex_mask][0][planar][tex_anim]; + if (!draw_info.empty()) + { + shader.bind(rigged); + pushGLTFBatches(draw_info, planar, tex_anim); + } + } +} + +void LLRenderPass::pushGLTFBatches(const std::vector& draw_info, bool planar, bool tex_anim) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + pre_push_gltf_batches(); + + for (auto& params : draw_info) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); + pushGLTFBatch(params, planar, tex_anim); + } - pushGLTFBatch(params); + LLVertexBuffer::unbind(); +} + +void LLRenderPass::pushShadowBatches(const std::vector& draw_info) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + pre_push_gltf_batches(); + + for (auto& params : draw_info) + { + pushShadowBatch(params); } + + LLVertexBuffer::unbind(); } -void LLRenderPass::pushUntexturedGLTFBatches(U32 type) +// static +void LLRenderPass::pushGLTFBatch(const LLGLTFDrawInfo& params, bool planar, bool tex_anim) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + LL_PROFILE_ZONE_NUM(params.mInstanceCount); + llassert(params.mTransformUBO != 0); + STOP_GLERROR; + if (params.mTransformUBO != transform_ubo) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, params.mTransformUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODE_INSTANCE_MAP, params.mInstanceMapUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, params.mMaterialUBO); + if (tex_anim) + { + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_TEXTURE_TRANSFORM, params.mTextureTransformUBO); + } + transform_ubo = params.mTransformUBO; + } + + if (!last_mat || params.mMaterialID != last_mat) + { + last_mat = params.mMaterialID; + if (base_tu != -1 && cur_base_tex != params.mBaseColorMap) + { + glActiveTexture(GL_TEXTURE0 + base_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mBaseColorMap]); + cur_base_tex = params.mBaseColorMap; + } - pushUntexturedGLTFBatch(params); + if (!LLPipeline::sShadowRender) + { + if (norm_tu != -1 && cur_norm_tex != params.mNormalMap) + { + glActiveTexture(GL_TEXTURE0 + norm_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mNormalMap]); + cur_norm_tex = params.mNormalMap; + } + + if (orm_tu != -1 && cur_orm_tex != params.mMetallicRoughnessMap) + { + glActiveTexture(GL_TEXTURE0 + orm_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mMetallicRoughnessMap]); + cur_orm_tex = params.mMetallicRoughnessMap; + } + + if (emis_tu != -1 && cur_emis_tex != params.mEmissiveMap) + { + glActiveTexture(GL_TEXTURE0 + emis_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mEmissiveMap]); + cur_emis_tex = params.mEmissiveMap; + } + } } + + glUniform1i(base_instance_index, params.mBaseInstance); + + STOP_GLERROR; +#if USE_VAO + LLVertexBuffer::bindVAO(params.mVAO); +#else + LLVertexBuffer::bindVBO(params.mVBO, params.mIBO, params.mVBOVertexCount); +#endif + glDrawElementsInstanced(GL_TRIANGLES, params.mElementCount, + gl_indices_type[params.mIndicesSize], (GLvoid*)(size_t)(params.mElementOffset * gl_indices_size[params.mIndicesSize]), + params.mInstanceCount); + STOP_GLERROR; } // static -void LLRenderPass::pushGLTFBatch(LLDrawInfo& params) +void LLRenderPass::pushShadowBatch(const LLGLTFDrawInfo& params) { - auto& mat = params.mGLTFMaterial; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LL_PROFILE_ZONE_NUM(params.mInstanceCount); + llassert(params.mTransformUBO != 0); - if (mat.notNull()) + if (params.mTransformUBO != transform_ubo) { - mat->bind(params.mTexture); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, params.mTransformUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODE_INSTANCE_MAP, params.mInstanceMapUBO); + // NOTE: don't bind the material UBO here, it's not used in shadow pass + transform_ubo = params.mTransformUBO; } - LLGLDisable cull_face(mat.notNull() && mat->mDoubleSided ? GL_CULL_FACE : 0); + glUniform1i(base_instance_index, params.mBaseInstance); - setup_texture_matrix(params); +#if USE_VAO + LLVertexBuffer::bindVAO(params.mVAO); +#else + LLVertexBuffer::bindVBO(params.mVBO, params.mIBO, params.mVBOVertexCount); +#endif + glDrawElementsInstanced(GL_TRIANGLES, params.mElementCount, + gl_indices_type[params.mIndicesSize], (GLvoid*)(size_t)(params.mElementOffset * gl_indices_size[params.mIndicesSize]), + params.mInstanceCount); +} - applyModelMatrix(params); +void LLRenderPass::pushRiggedGLTFBatches(const std::vector& draw_info, bool planar, bool tex_anim) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + pre_push_gltf_batches(); + + const LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + bool skipLastSkin = false; + + for (auto& params : draw_info) + { + pushRiggedGLTFBatch(params, lastAvatar, lastMeshId, skipLastSkin, planar, tex_anim); + } + + LLVertexBuffer::unbind(); +} + +void LLRenderPass::pushRiggedShadowBatches(const std::vector& draw_info) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + pre_push_gltf_batches(); + + const LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + bool skipLastSkin = false; + + for (auto& params : draw_info) + { + pushRiggedShadowBatch(params, lastAvatar, lastMeshId, skipLastSkin); + } + + LLVertexBuffer::unbind(); +} - teardown_texture_matrix(params); +// static +void LLRenderPass::pushRiggedGLTFBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin, bool planar, bool tex_anim) +{ + if (uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) + { + pushGLTFBatch(params, planar, tex_anim); + } } // static -void LLRenderPass::pushUntexturedGLTFBatch(LLDrawInfo& params) +void LLRenderPass::pushRiggedShadowBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin) +{ + if (uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) + { + pushShadowBatch(params); + } +} + + +static void pre_push_bp_batches() { - auto& mat = params.mGLTFMaterial; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(gGLModelView); + gGL.syncMatrices(); + transform_ubo = 0; + last_mat = 0; - LLGLDisable cull_face(mat->mDoubleSided ? GL_CULL_FACE : 0); + diffuse_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + norm_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::BUMP_MAP); + specular_tu = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(LLShaderMgr::SPECULAR_MAP); - applyModelMatrix(params); + base_instance_index = LLGLSLShader::sCurBoundShaderPtr->getUniformLocation(LLShaderMgr::GLTF_BASE_INSTANCE); - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + cur_specular_tex = cur_norm_tex = cur_diffuse_tex = 0; + + S32 tex[] = { diffuse_tu, norm_tu, specular_tu }; + + for (S32 tu : tex) + { + if (tu != -1) + { + gGL.getTexUnit(tu)->bindManual(LLTexUnit::TT_TEXTURE, 0, true); + } + } } -void LLRenderPass::pushRiggedGLTFBatches(U32 type, bool textured) +void LLRenderPass::pushBPBatches(const std::vector& draw_info, bool planar, bool tex_anim) { - if (textured) + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + pre_push_bp_batches(); + + for (auto& params : draw_info) { - pushRiggedGLTFBatches(type); + pushBPBatch(params, planar, tex_anim); } - else + + LLVertexBuffer::unbind(); +} + +// static +void LLRenderPass::pushBPBatch(const LLGLTFDrawInfo& params, bool planar, bool tex_anim) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LL_PROFILE_ZONE_NUM(params.mInstanceCount); + llassert(params.mTransformUBO != 0); + + if (params.mTransformUBO != transform_ubo) { - pushUntexturedRiggedGLTFBatches(type); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, params.mTransformUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODE_INSTANCE_MAP, params.mInstanceMapUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, params.mMaterialUBO); + if (tex_anim) + { + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_TEXTURE_TRANSFORM, params.mTextureTransformUBO); + } + transform_ubo = params.mTransformUBO; } + + if (!last_mat || params.mMaterialID != last_mat) + { + last_mat = params.mMaterialID; + if (diffuse_tu != -1 && cur_diffuse_tex != params.mDiffuseMap) + { + glActiveTexture(GL_TEXTURE0 + diffuse_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mDiffuseMap]); + cur_diffuse_tex = params.mDiffuseMap; + } + + if (!LLPipeline::sShadowRender) + { + if (norm_tu != -1 && cur_norm_tex != params.mNormalMap) + { + glActiveTexture(GL_TEXTURE0 + norm_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mNormalMap]); + cur_norm_tex = params.mNormalMap; + } + + if (specular_tu != -1 && cur_specular_tex != params.mSpecularMap) + { + glActiveTexture(GL_TEXTURE0 + specular_tu); + glBindTexture(GL_TEXTURE_2D, LLImageGL::sTexNames[params.mSpecularMap]); + cur_specular_tex = params.mSpecularMap; + } + } + } + + glUniform1i(base_instance_index, params.mBaseInstance); + +#if USE_VAO + LLVertexBuffer::bindVAO(params.mVAO); +#else + LLVertexBuffer::bindVBO(params.mVBO, params.mIBO, params.mVBOVertexCount); +#endif + glDrawElementsInstanced(GL_TRIANGLES, params.mElementCount, + gl_indices_type[params.mIndicesSize], (GLvoid*)(size_t)(params.mElementOffset * gl_indices_size[params.mIndicesSize]), + params.mInstanceCount); } -void LLRenderPass::pushRiggedGLTFBatches(U32 type) +void LLRenderPass::pushRiggedBPBatches(const std::vector& draw_info, bool planar, bool tex_anim) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + pre_push_bp_batches(); + const LLVOAvatar* lastAvatar = nullptr; U64 lastMeshId = 0; bool skipLastSkin = false; - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + for (auto& params : draw_info) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushRiggedGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); + pushRiggedBPBatch(params, lastAvatar, lastMeshId, skipLastSkin, planar, tex_anim); + } + + LLVertexBuffer::unbind(); +} + +// static +void LLRenderPass::pushRiggedBPBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin, bool planar, bool tex_anim) +{ + if (uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) + { + pushBPBatch(params, planar, tex_anim); + } +} - pushRiggedGLTFBatch(params, lastAvatar, lastMeshId, skipLastSkin); +// static +void LLRenderPass::pushDebugBatches(const std::vector& draw_info) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + pre_push_gltf_batches(); + + for (auto& params : draw_info) + { + pushDebugBatch(params); } + + LLVertexBuffer::unbind(); } -void LLRenderPass::pushUntexturedRiggedGLTFBatches(U32 type) +//static +void LLRenderPass::pushRiggedDebugBatches(const std::vector& draw_info) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + pre_push_gltf_batches(); + const LLVOAvatar* lastAvatar = nullptr; U64 lastMeshId = 0; bool skipLastSkin = false; - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + for (auto& params : draw_info) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushRiggedGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); - - pushUntexturedRiggedGLTFBatch(params, lastAvatar, lastMeshId, skipLastSkin); + pushRiggedDebugBatch(params, lastAvatar, lastMeshId, skipLastSkin); } -} + LLVertexBuffer::unbind(); +} // static -void LLRenderPass::pushRiggedGLTFBatch(LLDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin) +void LLRenderPass::pushDebugBatch(const LLGLTFDrawInfo& params) { - if (uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LL_PROFILE_ZONE_NUM(params.mInstanceCount); + llassert(params.mTransformUBO != 0); + STOP_GLERROR; + if (params.mTransformUBO != transform_ubo) { - pushGLTFBatch(params); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, params.mTransformUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODE_INSTANCE_MAP, params.mInstanceMapUBO); + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, params.mMaterialUBO); + transform_ubo = params.mTransformUBO; } + + glUniform1i(base_instance_index, params.mBaseInstance); + + // use memory address of draw call as a color + size_t index = (size_t)¶ms / sizeof(LLGLTFDrawInfo); + index *= 32; + U8* col = ((U8*)&index); + + LLGLSLShader::sCurBoundShaderPtr->uniform4f(LLShaderMgr::DEBUG_COLOR, col[0] / 255.0f, col[1] / 255.0f, col[2] / 255.0f, 1.f); + + STOP_GLERROR; + LLVertexBuffer::bindVBO(params.mVBO, params.mIBO, params.mVBOVertexCount); + glDrawElementsInstanced(GL_TRIANGLES, params.mElementCount, + gl_indices_type[params.mIndicesSize], (GLvoid*)(size_t)(params.mElementOffset * gl_indices_size[params.mIndicesSize]), + params.mInstanceCount); + STOP_GLERROR; } // static -void LLRenderPass::pushUntexturedRiggedGLTFBatch(LLDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin) +void LLRenderPass::pushRiggedDebugBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin) { if (uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) { - pushUntexturedGLTFBatch(params); + pushDebugBatch(params); } } + diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 34257f98f88..5a19b4dfd14 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -31,6 +31,7 @@ #include "v2math.h" #include "v3math.h" #include "llvertexbuffer.h" +#include "llgltfmaterial.h" class LLFace; class LLViewerTexture; @@ -40,6 +41,8 @@ class LLDrawInfo; class LLVOAvatar; class LLGLSLShader; class LLMeshSkinInfo; +class LLGLTFDrawInfo; +class LLSkinnedGLTFDrawInfo; class LLDrawPool { @@ -358,27 +361,45 @@ class LLRenderPass : public LLDrawPool void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false); void pushUntexturedRiggedBatches(U32 type); + // push described batches off of sCull using given shader + // short ciruits without binding the shader if there are no batches + static void pushGLTFBatches(LLGLSLShader& shader, bool rigged, U32 alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim); + static void pushBPBatches(LLGLSLShader& shader, bool rigged, U32 alpha_mode, U8 tex_mask, bool planar, bool tex_anim); + // push full GLTF batches - // assumes draw infos of given type have valid GLTF materials - void pushGLTFBatches(U32 type); + static void pushGLTFBatches(const std::vector& draw_info, bool planar = false, bool tex_anim = false); + + // push full skinned GLTF batches + static void pushRiggedGLTFBatches(const std::vector& draw_info, bool planar = false, bool tex_anim = false); + + // push shadow pass batches + static void pushShadowBatches(const std::vector& draw_info); + + // push shadow pass skinned batches + static void pushRiggedShadowBatches(const std::vector& draw_info); + + // push debug batches + static void pushDebugBatches(const std::vector& draw_info); + + // push debug skinned batches + static void pushRiggedDebugBatches(const std::vector& draw_info); - // like pushGLTFBatches, but will not bind textures or set up texture transforms - void pushUntexturedGLTFBatches(U32 type); - // helper function for dispatching to textured or untextured pass based on bool - void pushGLTFBatches(U32 type, bool textured); + static void pushGLTFBatch(const LLGLTFDrawInfo& params, bool planar = false, bool tex_anim = false); + static void pushShadowBatch(const LLGLTFDrawInfo& params); + static void pushRiggedGLTFBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin, bool planar = false, bool tex_anim = false); + static void pushRiggedShadowBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin); + static void pushDebugBatch(const LLGLTFDrawInfo& params); + static void pushRiggedDebugBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin); + // push full Blinn-Phong batches + static void pushBPBatches(const std::vector& draw_info, bool planar = false, bool tex_anim = false); - // rigged variants of above - void pushRiggedGLTFBatches(U32 type); - void pushRiggedGLTFBatches(U32 type, bool textured); - void pushUntexturedRiggedGLTFBatches(U32 type); + // push full skinned Blinn-Phong batches + static void pushRiggedBPBatches(const std::vector& draw_info, bool planar = false, bool tex_anim = false); - // push a single GLTF draw call - static void pushGLTFBatch(LLDrawInfo& params); - static void pushRiggedGLTFBatch(LLDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin); - static void pushUntexturedGLTFBatch(LLDrawInfo& params); - static void pushUntexturedRiggedGLTFBatch(LLDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin); + static void pushBPBatch(const LLGLTFDrawInfo& params, bool planar = false, bool tex_anim = false); + static void pushRiggedBPBatch(const LLSkinnedGLTFDrawInfo& params, const LLVOAvatar*& lastAvatar, U64& lastMeshId, bool& skipLastSkin, bool planar = false, bool tex_anim = false); void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false); void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5379bcc985f..da068797d2b 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -85,7 +85,7 @@ void LLDrawPoolAlpha::prerender() S32 LLDrawPoolAlpha::getNumPostDeferredPasses() { - return 1; + return gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_ALPHA) ? 1: 0; } // set some common parameters on the given shader to prepare for alpha rendering @@ -182,18 +182,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) prepare_alpha_shader(simple_shader, true, water_sign); //prime simple shader (loads shadow relevant uniforms) - LLGLSLShader* materialShader = gDeferredMaterialProgram; - for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) - { - prepare_alpha_shader(&materialShader[i], true, water_sign); - } - - pbr_shader = - (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : - &gDeferredPBRAlphaProgram; - - prepare_alpha_shader(pbr_shader, true, water_sign); - // explicitly unbind here so render loop doesn't make assumptions about the last shader // already being setup for rendering LLGLSLShader::unbind(); @@ -228,6 +216,8 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) } } +extern LLCullResult* sCull; + void LLDrawPoolAlpha::forwardRender(bool rigged) { gPipeline.enableLightsDynamic(); @@ -253,13 +243,101 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - if (rigged && mType == LLDrawPool::POOL_ALPHA_POST_WATER) - { // draw GLTF scene to depth buffer before rigged alpha - LL::GLTFSceneManager::instance().render(false, false); - LL::GLTFSceneManager::instance().render(false, true); - LL::GLTFSceneManager::instance().render(false, false, true); - LL::GLTFSceneManager::instance().render(false, true, true); + if (mType == LLDrawPool::POOL_ALPHA_POST_WATER) + { + if (rigged) + { // draw GLTF scene to depth buffer before rigged alpha + LL::GLTFSceneManager::instance().render(false, false); + LL::GLTFSceneManager::instance().render(false, true); + LL::GLTFSceneManager::instance().render(false, false, true); + LL::GLTFSceneManager::instance().render(false, true, true); + + // draw rigged GPU instanced batches to depth buffer + LLGLTFMaterial::AlphaMode alpha_mode = LLGLTFMaterial::ALPHA_MODE_BLEND; + + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + //if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_GLTF_PBR)) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + auto& info = sCull->mGLTFBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!info.empty()) + { + LLGLSLShader& shader = gGLTFPBRShaderPack.mShader[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + gPipeline.bindDeferredShader(*shader.mRiggedVariant); + pushRiggedGLTFBatches(info, planar, tex_anim); + } + } + } + + if (!double_sided) // && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_MATERIALS)) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + auto& info = sCull->mBPBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!info.empty()) + { + LLGLSLShader& shader = gBPShaderPack.mShader[alpha_mode][tex_mask][planar][tex_anim]; + gPipeline.bindDeferredShader(*shader.mRiggedVariant); + pushRiggedBPBatches(info, planar, tex_anim); + } + } + } + } + } + } + } } + else + { + // draw static GPU instanced batches + LLGLTFMaterial::AlphaMode alpha_mode = LLGLTFMaterial::ALPHA_MODE_BLEND; + + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + //if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_GLTF_PBR)) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + auto& info = sCull->mGLTFBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!info.empty()) + { + LLGLSLShader& shader = gGLTFPBRShaderPack.mShader[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + gPipeline.bindDeferredShader(shader); + pushGLTFBatches(info, planar, tex_anim); + } + } + } + + if (!double_sided) // && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_MATERIALS)) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + auto& info = sCull->mBPBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + if (!info.empty()) + { + LLGLSLShader& shader = gBPShaderPack.mShader[alpha_mode][tex_mask][planar][tex_anim]; + gPipeline.bindDeferredShader(shader); + pushBPBatches(info, planar, tex_anim); + } + } + } + } + } + } + } + // If the face is more than 90% transparent, then don't update the Depth buffer for Dof // We don't want the nearly invisible objects to cause of DoF effects @@ -708,10 +786,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) } else if (mat) { - U32 mask = params.mShaderMask; - - llassert(mask < LLMaterial::SHADER_COUNT); - target_shader = &(gDeferredMaterialProgram[mask]); + continue; } else if (!params.mFullbright) { diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 754fcd4c173..5bc8ff5460b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -57,7 +57,7 @@ LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; LL::WorkQueue::weak_t LLBumpImageList::sMainQueue; LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue; -LLRenderTarget LLBumpImageList::sRenderTarget; +static LLRenderTarget sRenderTarget; // static U32 LLStandardBumpmap::sStandardBumpmapCount = 0; @@ -208,79 +208,6 @@ S32 LLDrawPoolBump::numBumpPasses() return 1; } - -//static -void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) -{ - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if( cube_map && !LLPipeline::sReflectionProbesEnabled ) - { - if (shader ) - { - LLMatrix4 mat; - mat.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); - LLVector3 vec = LLVector3(gShinyOrigin) * mat; - LLVector4 vec4(vec, gShinyOrigin.mV[3]); - shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); - if (shader_level > 1) - { - cube_map->setMatrix(1); - // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for - // the cube map in the one pass shiny shaders - cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - cube_map->enableTexture(cube_channel); - diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - else - { - cube_map->setMatrix(0); - cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - diffuse_channel = -1; - cube_map->enable(cube_channel); - } - gGL.getTexUnit(cube_channel)->bind(cube_map); - gGL.getTexUnit(0)->activate(); - } - else - { - cube_channel = 0; - diffuse_channel = -1; - gGL.getTexUnit(0)->disable(); - cube_map->enable(0); - cube_map->setMatrix(0); - gGL.getTexUnit(0)->bind(cube_map); - } - } -} - -//static -void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) -{ - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if( cube_map && !LLPipeline::sReflectionProbesEnabled) - { - if (shader_level > 1) - { - shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - - if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) - { - if (diffuse_channel != 0) - { - shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - } - } - // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0 - // MAINT-755 - cube_map->disable(); - cube_map->restoreMatrix(); - } -} - void LLDrawPoolBump::beginFullbrightShiny() { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 15976884ca3..ef2ad960778 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -31,7 +31,7 @@ #include "llstring.h" #include "lltextureentry.h" #include "lluuid.h" - +#include "workqueue.h" #include class LLImageRaw; @@ -67,9 +67,6 @@ protected : void renderBump(U32 pass = LLRenderPass::PASS_BUMP); void endBump(U32 pass = LLRenderPass::PASS_BUMP); - static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); - static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); - virtual S32 getNumDeferredPasses() override; /*virtual*/ void renderDeferred(S32 pass) override; @@ -154,7 +151,6 @@ class LLBumpImageList bump_image_map_t mDarknessEntries; static LL::WorkQueue::weak_t sMainQueue; static LL::WorkQueue::weak_t sTexUpdateQueue; - static LLRenderTarget sRenderTarget; }; extern LLBumpImageList gBumpImageList; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index e7ec2022d25..a0824355031 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -46,244 +46,17 @@ void LLDrawPoolMaterials::prerender() S32 LLDrawPoolMaterials::getNumDeferredPasses() { - // 12 render passes times 2 (one for each rigged and non rigged) - return 12*2; + return 0; } void LLDrawPoolMaterials::beginDeferredPass(S32 pass) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; - - bool rigged = false; - if (pass >= 12) - { - rigged = true; - pass -= 12; - } - U32 shader_idx[] = - { - 0, //LLRenderPass::PASS_MATERIAL, - //1, //LLRenderPass::PASS_MATERIAL_ALPHA, - 2, //LLRenderPass::PASS_MATERIAL_ALPHA_MASK, - 3, //LLRenderPass::PASS_MATERIAL_ALPHA_GLOW, - 4, //LLRenderPass::PASS_SPECMAP, - //5, //LLRenderPass::PASS_SPECMAP_BLEND, - 6, //LLRenderPass::PASS_SPECMAP_MASK, - 7, //LLRenderPass::PASS_SPECMAP_GLOW, - 8, //LLRenderPass::PASS_NORMMAP, - //9, //LLRenderPass::PASS_NORMMAP_BLEND, - 10, //LLRenderPass::PASS_NORMMAP_MASK, - 11, //LLRenderPass::PASS_NORMMAP_GLOW, - 12, //LLRenderPass::PASS_NORMSPEC, - //13, //LLRenderPass::PASS_NORMSPEC_BLEND, - 14, //LLRenderPass::PASS_NORMSPEC_MASK, - 15, //LLRenderPass::PASS_NORMSPEC_GLOW, - }; - - U32 idx = shader_idx[pass]; - - mShader = &(gDeferredMaterialProgram[idx]); - - if (rigged) - { - llassert(mShader->mRiggedVariant != nullptr); - mShader = mShader->mRiggedVariant; - } - - gPipeline.bindDeferredShader(*mShader); } void LLDrawPoolMaterials::endDeferredPass(S32 pass) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; - - mShader->unbind(); - - LLRenderPass::endRenderPass(pass); } void LLDrawPoolMaterials::renderDeferred(S32 pass) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; - static const U32 type_list[] = - { - LLRenderPass::PASS_MATERIAL, - //LLRenderPass::PASS_MATERIAL_ALPHA, - LLRenderPass::PASS_MATERIAL_ALPHA_MASK, - LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, - LLRenderPass::PASS_SPECMAP, - //LLRenderPass::PASS_SPECMAP_BLEND, - LLRenderPass::PASS_SPECMAP_MASK, - LLRenderPass::PASS_SPECMAP_EMISSIVE, - LLRenderPass::PASS_NORMMAP, - //LLRenderPass::PASS_NORMMAP_BLEND, - LLRenderPass::PASS_NORMMAP_MASK, - LLRenderPass::PASS_NORMMAP_EMISSIVE, - LLRenderPass::PASS_NORMSPEC, - //LLRenderPass::PASS_NORMSPEC_BLEND, - LLRenderPass::PASS_NORMSPEC_MASK, - LLRenderPass::PASS_NORMSPEC_EMISSIVE, - }; - - bool rigged = false; - if (pass >= 12) - { - rigged = true; - pass -= 12; - } - - llassert(pass < sizeof(type_list)/sizeof(U32)); - - U32 type = type_list[pass]; - if (rigged) - { - type += 1; - } - - LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - - F32 lastIntensity = 0.f; - F32 lastFullbright = 0.f; - F32 lastMinimumAlpha = 0.f; - LLVector4 lastSpecular = LLVector4(0, 0, 0, 0); - - GLint intensity = mShader->getUniformLocation(LLShaderMgr::ENVIRONMENT_INTENSITY); - GLint brightness = mShader->getUniformLocation(LLShaderMgr::EMISSIVE_BRIGHTNESS); - GLint minAlpha = mShader->getUniformLocation(LLShaderMgr::MINIMUM_ALPHA); - GLint specular = mShader->getUniformLocation(LLShaderMgr::SPECULAR_COLOR); - - GLint diffuseChannel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP); - GLint specChannel = mShader->enableTexture(LLShaderMgr::SPECULAR_MAP); - GLint normChannel = mShader->enableTexture(LLShaderMgr::BUMP_MAP); - - LLTexture* lastNormalMap = nullptr; - LLTexture* lastSpecMap = nullptr; - LLTexture* lastDiffuse = nullptr; - - gGL.getTexUnit(diffuseChannel)->unbindFast(LLTexUnit::TT_TEXTURE); - - if (intensity > -1) - { - glUniform1f(intensity, lastIntensity); - } - - if (brightness > -1) - { - glUniform1f(brightness, lastFullbright); - } - - if (minAlpha > -1) - { - glUniform1f(minAlpha, lastMinimumAlpha); - } - - if (specular > -1) - { - glUniform4fv(specular, 1, lastSpecular.mV); - } - - const LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - bool skipLastSkin = false; - - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL("materials draw loop"); - LLDrawInfo& params = **i; - - LLCullResult::increment_iterator(i, end); - - if (specular > -1 && params.mSpecColor != lastSpecular) - { - lastSpecular = params.mSpecColor; - glUniform4fv(specular, 1, lastSpecular.mV); - } - - if (intensity != -1 && lastIntensity != params.mEnvIntensity) - { - lastIntensity = params.mEnvIntensity; - glUniform1f(intensity, lastIntensity); - } - - if (minAlpha > -1 && lastMinimumAlpha != params.mAlphaMaskCutoff) - { - lastMinimumAlpha = params.mAlphaMaskCutoff; - glUniform1f(minAlpha, lastMinimumAlpha); - } - - F32 fullbright = params.mFullbright ? 1.f : 0.f; - if (brightness > -1 && lastFullbright != fullbright) - { - lastFullbright = fullbright; - glUniform1f(brightness, lastFullbright); - } - - if (normChannel > -1 && params.mNormalMap != lastNormalMap) - { - lastNormalMap = params.mNormalMap; - llassert(lastNormalMap); - gGL.getTexUnit(normChannel)->bindFast(lastNormalMap); - } - - if (specChannel > -1 && params.mSpecularMap != lastSpecMap) - { - lastSpecMap = params.mSpecularMap; - llassert(lastSpecMap); - gGL.getTexUnit(specChannel)->bindFast(lastSpecMap); - } - - if (params.mTexture != lastDiffuse) - { - lastDiffuse = params.mTexture; - if (lastDiffuse) - { - gGL.getTexUnit(diffuseChannel)->bindFast(lastDiffuse); - } - else - { - gGL.getTexUnit(diffuseChannel)->unbindFast(LLTexUnit::TT_TEXTURE); - } - } - - // upload matrix palette to shader - if (rigged) - { - if (!uploadMatrixPalette(params.mAvatar, params.mSkinInfo, lastAvatar, lastMeshId, skipLastSkin)) - { - continue; - } - } - - applyModelMatrix(params); - - bool tex_setup = false; - - //not batching textures or batch has only 1 texture -- might need a texture matrix - if (params.mTextureMatrix) - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - - gGL.loadMatrix((GLfloat*)params.mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - - tex_setup = true; - } - - /*if (params.mGroup) // TOO LATE - { - params.mGroup->rebuildMesh(); - }*/ - - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - - if (tex_setup) - { - gGL.getTexUnit(0)->activate(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } - } } diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h index 345697ffd15..3da87524192 100644 --- a/indra/newview/lldrawpoolmaterials.h +++ b/indra/newview/lldrawpoolmaterials.h @@ -40,7 +40,6 @@ class LLGLSLShader; class LLDrawPoolMaterials : public LLRenderPass { - LLGLSLShader *mShader; public: LLDrawPoolMaterials(); diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp index 07f8ccb5496..77179bc6d20 100644 --- a/indra/newview/lldrawpoolpbropaque.cpp +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -32,6 +32,8 @@ #include "pipeline.h" #include "gltfscenemanager.h" +extern LLCullResult* sCull; + LLDrawPoolGLTFPBR::LLDrawPoolGLTFPBR(U32 type) : LLRenderPass(type) { @@ -56,18 +58,47 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass) if (mRenderType == LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK) { - LL::GLTFSceneManager::instance().renderOpaque(); + // opaque + LL::GLTFSceneManager::instance().render(true); + // opaque rigged + LL::GLTFSceneManager::instance().render(true, true); } - gDeferredPBROpaqueProgram.bind(); - pushGLTFBatches(mRenderType); + LLGLTFMaterial::AlphaMode alpha_mode = mRenderType == LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK ? LLGLTFMaterial::ALPHA_MODE_MASK : LLGLTFMaterial::ALPHA_MODE_OPAQUE; - LL::GLTFSceneManager::instance().render(true, true); + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + LLGLSLShader& shader = gGLTFPBRShaderPack.mShader[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + for (U32 rigged = 0; rigged < 2; ++rigged) + { + pushGLTFBatches(shader, rigged, alpha_mode, tex_mask, double_sided, planar, tex_anim); + } - gDeferredPBROpaqueProgram.bind(true); - pushRiggedGLTFBatches(mRenderType + 1); + } + if (!double_sided && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_MATERIALS)) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + LLGLSLShader& shader = gBPShaderPack.mShader[alpha_mode][tex_mask][planar][tex_anim]; + for (U32 rigged = 0; rigged < 2; ++rigged) + { + pushBPBatches(shader, rigged, alpha_mode, tex_mask, planar, tex_anim); + } + } + } + } + } + } } + S32 LLDrawPoolGLTFPBR::getNumPostDeferredPasses() { return 1; @@ -78,16 +109,18 @@ void LLDrawPoolGLTFPBR::renderPostDeferred(S32 pass) if (LLPipeline::sRenderingHUDs) { gHUDPBROpaqueProgram.bind(); - pushGLTFBatches(mRenderType); + //pushGLTFBatches(mRenderType); } else if (mRenderType == LLPipeline::RENDER_TYPE_PASS_GLTF_PBR) // HACK -- don't render glow except for the non-alpha masked implementation { +#if 0 gGL.setColorMask(false, true); gPBRGlowProgram.bind(); pushGLTFBatches(LLRenderPass::PASS_GLTF_GLOW); gPBRGlowProgram.bind(true); pushRiggedGLTFBatches(LLRenderPass::PASS_GLTF_GLOW_RIGGED); +#endif gGL.setColorMask(true, false); } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 53d6e528b6d..f0377341d62 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -109,7 +109,8 @@ void LLDrawPoolWater::beginPostDeferredPass(S32 pass) LL_PROFILE_GPU_ZONE("water beginPostDeferredPass") gGL.setColorMask(true, true); - if (LLPipeline::sRenderTransparentWater) + static LLCachedControl render_transparent_water(gSavedSettings, "RenderTransparentWater"); + if (render_transparent_water) { // copy framebuffer contents so far to a texture to be used for // reflections and refractions diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index e6d0b036e0d..3760faffcd6 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -322,18 +322,18 @@ void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 if (cloud_noise && (!cloud_noise_next || (cloud_noise == cloud_noise_next))) { // Bind current and next sun textures - cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise.get(), LLTexUnit::TT_TEXTURE); blend_factor = 0; } else if (cloud_noise_next && !cloud_noise) { - cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise_next, LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise_next.get(), LLTexUnit::TT_TEXTURE); blend_factor = 0; } else if (cloud_noise_next != cloud_noise) { - cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise, LLTexUnit::TT_TEXTURE); - cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP_NEXT, cloud_noise_next, LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP, cloud_noise.get(), LLTexUnit::TT_TEXTURE); + cloudshader->bindTexture(LLShaderMgr::CLOUD_NOISE_MAP_NEXT, cloud_noise_next.get(), LLTexUnit::TT_TEXTURE); } } @@ -387,18 +387,18 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() if (tex_a && (!tex_b || (tex_a == tex_b))) { // Bind current and next sun textures - sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a.get(), LLTexUnit::TT_TEXTURE); blend_factor = 0; } else if (tex_b && !tex_a) { - sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_b.get(), LLTexUnit::TT_TEXTURE); blend_factor = 0; } else if (tex_b != tex_a) { - sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a, LLTexUnit::TT_TEXTURE); - sun_shader->bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, tex_b, LLTexUnit::TT_TEXTURE); + sun_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, tex_a.get(), LLTexUnit::TT_TEXTURE); + sun_shader->bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, tex_b.get(), LLTexUnit::TT_TEXTURE); } LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor()); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index a125dcb7aa1..5f6e69505d4 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2010,6 +2010,7 @@ void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environ { LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLEnvironment::coroRequestEnvironment::apply"); EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); apply(parcel_id, envinfo); }); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index b726e21380f..96ed6e94be7 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1,4 +1,4 @@ -/** + /** * @file llface.cpp * @brief LLFace class implementation * @@ -26,6 +26,8 @@ #include "llviewerprecompiledheaders.h" +#include + #include "lldrawable.h" // lldrawable needs to be included before llface #include "llface.h" #include "llviewertextureanim.h" @@ -164,8 +166,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mImportanceToCamera = 0.f ; mBoundingSphereRadius = 0.0f ; - mTexExtents[0].set(0, 0); - mTexExtents[1].set(1, 1); mHasMedia = false ; mIsMediaAllowed = true; } @@ -209,6 +209,7 @@ void LLFace::destroy() { group->dirtyGeom(); gPipeline.markRebuild(group); + gPipeline.markTransformDirty(group); } } } @@ -283,6 +284,11 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) } mTexture[ch] = tex ; + + if (mGLTFDrawInfo) + { + gPipeline.markTransformDirty(mDrawablep->getSpatialGroup()); + } } void LLFace::setTexture(LLViewerTexture* tex) @@ -752,6 +758,7 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of tex_coord.mV[1] = t; } +#if 0 // Transform the texture coordinates for this face. static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) { @@ -794,7 +801,7 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect // Then offset tex_coord.setAdd(st, offset); } - +#endif bool less_than_max_mag(const LLVector4a& vec) { @@ -868,10 +875,7 @@ bool LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, // convert surface coordinates to texture coordinates, based on -// the values in the texture entry. probably should be -// integrated with getGeometryVolume() for its texture coordinate -// generation - but i'll leave that to someone more familiar -// with the implications. +// the values in the texture entry. LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal) { LLVector2 tc = surface_coord; @@ -1132,966 +1136,6 @@ void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) } } -bool LLFace::getGeometryVolume(const LLVolume& volume, - S32 face_index, - const LLMatrix4& mat_vert_in, - const LLMatrix3& mat_norm_in, - U16 index_offset, - bool force_rebuild, - bool no_debug_assert, - bool rebuild_for_gltf) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; - llassert(verify()); - - if (face_index < 0 || face_index >= volume.getNumVolumeFaces()) - { - if (gDebugGL) - { - LL_WARNS() << "Face index is out of bounds!" << LL_ENDL; - LL_WARNS() << "Attempt get volume face out of range!" - " Total Faces: " << volume.getNumVolumeFaces() << - " Attempt get access to: " << face_index << LL_ENDL; - llassert(no_debug_assert); - } - return false; - } - - bool rigged = isState(RIGGED); - - const LLVolumeFace &vf = volume.getVolumeFace(face_index); - S32 num_vertices = (S32)vf.mNumVertices; - S32 num_indices = (S32) vf.mNumIndices; - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) - { - updateRebuildFlags(); - } - - if (mVertexBuffer.notNull()) - { - if (num_indices + mIndicesIndex > mVertexBuffer->getNumIndices()) - { - if (gDebugGL) - { - LL_WARNS() << "Index buffer overflow!" << LL_ENDL; - LL_WARNS() << "Indices Count: " << mIndicesCount - << " VF Num Indices: " << num_indices - << " Indices Index: " << mIndicesIndex - << " VB Num Indices: " << mVertexBuffer->getNumIndices() << LL_ENDL; - LL_WARNS() << " Face Index: " << face_index - << " Pool Type: " << mPoolType << LL_ENDL; - llassert(no_debug_assert); - } - return false; - } - - if (num_vertices + (U32)mGeomIndex > mVertexBuffer->getNumVerts()) - { - if (gDebugGL) - { - LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; - llassert(no_debug_assert); - } - return false; - } - } - - const LLTextureEntry* tep = mVObjp->getTE(face_index); - llassert(tep); - if (!tep) - return false; - - LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial(); - // To display selection markers (white squares with the rounded cross at the center) - // on faces with GLTF textures we use a special vertex buffer with other transforms - if (gltf_mat && !rebuild_for_gltf && tep->isSelected() && mVertexBuffer.notNull()) - { - // Create a temporary vertex buffer to provide transforms for GLTF textures - if (mVertexBufferGLTF.isNull()) - { - mVertexBufferGLTF = new LLVertexBuffer(mVertexBuffer->getTypeMask()); - } - - // Clone the existing vertex buffer into the temporary one - // TODO: factor out the need for mVertexBufferGLTF and make selection highlight shader work with the existing vertex buffer - mVertexBuffer->clone(*mVertexBufferGLTF); - - // Recursive call the same function with the argument rebuild_for_gltf set to true - // This call will make geometry in mVertexBuffer but in fact for mVertexBufferGLTF - mVertexBufferGLTF.swap(mVertexBufferGLTF, mVertexBuffer); - getGeometryVolume(volume, face_index, mat_vert_in, mat_norm_in, index_offset, force_rebuild, no_debug_assert, true); - mVertexBufferGLTF.swap(mVertexBufferGLTF, mVertexBuffer); - mVertexBufferGLTF->unmapBuffer(); - } - else if (!tep->isSelected() && mVertexBufferGLTF.notNull()) - { - // Free the temporary vertex buffer when it is not needed anymore - mVertexBufferGLTF = nullptr; - } - - LLGLTFMaterial::TextureInfo gltf_info_index = (LLGLTFMaterial::TextureInfo)0; - if (gltf_mat && rebuild_for_gltf) - { - switch (LLPipeline::sRenderHighlightTextureChannel) - { - case LLRender::BASECOLOR_MAP: - gltf_info_index = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; - break; - case LLRender::METALLIC_ROUGHNESS_MAP: - gltf_info_index = LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS; - break; - case LLRender::GLTF_NORMAL_MAP: - gltf_info_index = LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL; - break; - case LLRender::EMISSIVE_MAP: - gltf_info_index = LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE; - break; - default:; // just to make clang happy - } - } - - LLStrider vert; - LLStrider tex_coords0; - LLStrider tex_coords1; - LLStrider tex_coords2; - LLStrider norm; - LLStrider colors; - LLStrider tangent; - LLStrider indicesp; - LLStrider wght; - - bool full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); - - bool global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); - LLVector3 scale; - if (global_volume) - { - scale.setVec(1, 1, 1); - } - else - { - scale = mVObjp->getScale(); - } - - bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); - bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); - bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); - bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); - bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - bool rebuild_tangent = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TANGENT); - bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); - - const U8 bump_code = tep ? tep->getBumpmap() : 0; - - bool is_static = mDrawablep->isStatic(); - bool is_global = is_static; - - LLVector3 center_sum(0.f, 0.f, 0.f); - - if (is_global) - { - setState(GLOBAL); - } - else - { - clearState(GLOBAL); - } - - LLColor4U color{}; - if (tep) - { - color = tep->getColor(); - - if (tep->getGLTFRenderMaterial()) - { - color = tep->getGLTFRenderMaterial()->mBaseColor; - } - } - - if (rebuild_color) - { //decide if shiny goes in alpha channel of color - if (tep && - !isInAlphaPool() && tep->getGLTFRenderMaterial() == nullptr) // <--- alpha channel MUST contain transparency, not shiny - { - LLMaterial* mat = tep->getMaterialParams().get(); - - bool shiny_in_alpha = false; - - //store shiny in alpha if we don't have a specular map - if (!mat || mat->getSpecularID().isNull()) - { - shiny_in_alpha = true; - } - - if (shiny_in_alpha) - { - static const GLfloat SHININESS_TO_ALPHA[4] = - { - 0.0000f, - 0.25f, - 0.5f, - 0.75f - }; - - llassert(tep->getShiny() <= 3); - color.mV[3] = U8 (SHININESS_TO_ALPHA[tep->getShiny()] * 255); - } - } - } - - // INDICES - if (full_rebuild) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices"); - mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount); - - volatile __m128i* dst = (__m128i*) indicesp.get(); - __m128i* src = (__m128i*) vf.mIndices; - __m128i offset = _mm_set1_epi16(index_offset); - - S32 end = num_indices/8; - - for (S32 i = 0; i < end; i++) - { - __m128i res = _mm_add_epi16(src[i], offset); - _mm_storeu_si128((__m128i*) dst++, res); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices tail"); - U16* idx = (U16*) dst; - - for (S32 i = end*8; i < num_indices; ++i) - { - *idx++ = vf.mIndices[i]+index_offset; - } - } - } - - - LLMaterial* mat = tep->getMaterialParams().get(); - - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - - constexpr S32 XFORM_NONE = 0; - constexpr S32 XFORM_BLINNPHONG_COLOR = 1; - constexpr S32 XFORM_BLINNPHONG_NORMAL = 1 << 1; - constexpr S32 XFORM_BLINNPHONG_SPECULAR = 1 << 2; - - S32 xforms = XFORM_NONE; - // For GLTF, transforms will be applied later - if (rebuild_tcoord && tep && (!gltf_mat || rebuild_for_gltf)) - { - if (gltf_mat && rebuild_for_gltf) - { - // Apply special transformations for mVertexBufferGLTF - // They are used only to display a face selection marker - // (white square with a rounded cross at the center) - const auto& tt = gltf_mat->mTextureTransform[gltf_info_index]; - r = -tt.mRotation * 2; - ms = tt.mScale[VX]; - mt = tt.mScale[VY]; - os += tt.mOffset[VX] + (ms - 1) / 2; - ot -= tt.mOffset[VY] + (mt - 1) / 2; - } - else - { - r = tep->getRotation(); - tep->getOffset(&os, &ot); - tep->getScale(&ms, &mt); - } - - cos_ang = cos(r); - sin_ang = sin(r); - - if (cos_ang != 1.f || - sin_ang != 0.f || - os != 0.f || - ot != 0.f || - ms != 1.f || - mt != 1.f) - { - xforms |= XFORM_BLINNPHONG_COLOR; - } - if (mat) - { - F32 r_norm = 0, os_norm = 0, ot_norm = 0, ms_norm = 0, mt_norm = 0, cos_ang_norm = 0, sin_ang_norm = 0; - mat->getNormalOffset(os_norm, ot_norm); - mat->getNormalRepeat(ms_norm, mt_norm); - r_norm = mat->getNormalRotation(); - cos_ang_norm = cos(r_norm); - sin_ang_norm = sin(r_norm); - if (cos_ang_norm != 1.f || - sin_ang_norm != 0.f || - os_norm != 0.f || - ot_norm != 0.f || - ms_norm != 1.f || - mt_norm != 1.f) - { - xforms |= XFORM_BLINNPHONG_NORMAL; - } - } - if (mat) - { - F32 r_spec = 0, os_spec = 0, ot_spec = 0, ms_spec = 0, mt_spec = 0, cos_ang_spec = 0, sin_ang_spec = 0; - mat->getSpecularOffset(os_spec, ot_spec); - mat->getSpecularRepeat(ms_spec, mt_spec); - r_spec = mat->getSpecularRotation(); - cos_ang_spec = cos(r_spec); - sin_ang_spec = sin(r_spec); - if (cos_ang_spec != 1.f || - sin_ang_spec != 0.f || - os_spec != 0.f || - ot_spec != 0.f || - ms_spec != 1.f || - mt_spec != 1.f) - { - xforms |= XFORM_BLINNPHONG_SPECULAR; - } - } - } - - const LLMeshSkinInfo* skin = nullptr; - LLMatrix4a mat_vert; - LLMatrix4a mat_normal; - - // prepare mat_vert - if (rebuild_pos) - { - if (rigged) - { //override with bind shape matrix if rigged - skin = mSkinInfo; - mat_vert = skin->mBindShapeMatrix; - } - else - { - mat_vert.loadu(mat_vert_in); - } - } - - if (rebuild_normal || rebuild_tangent) - { //override mat_normal with inverse of skin->mBindShapeMatrix - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - norm mat override"); - if (rigged) - { - if (skin == nullptr) - { - skin = mSkinInfo; - } - - //TODO -- cache this (check profile marker above)? - glm::mat4 m = glm::make_mat4((F32*)skin->mBindShapeMatrix.getF32ptr()); - m = glm::transpose(glm::inverse(m)); - mat_normal.loadu(glm::value_ptr(m)); - } - else - { - mat_normal.loadu(mat_norm_in); - } - } - - { - //if it's not fullbright and has no normals, bake sunlight based on face normal - //bool bake_sunlight = !getTextureEntry()->getFullbright() && - // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - - if (rebuild_tcoord) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord"); - - //bump setup - LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); - LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); - LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); - - LLQuaternion bump_quat; - if (mDrawablep->isActive()) - { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); - } - - if (bump_code) - { - mVObjp->getVolume()->genTangents(face_index); - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->hasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture[LLRender::DIFFUSE_MAP]->getDiscardLevel(); - S32 max_size = llmax( mTexture[LLRender::DIFFUSE_MAP]->getWidth(), mTexture[LLRender::DIFFUSE_MAP]->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; - - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; - } - - F32 s_scale = tep->getScaleS(); - F32 t_scale = tep->getScaleT(); - - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.mVOSkyp->getMoon().getDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); - bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); - } - - U8 texgen = getTextureEntry()->getTexGen(); - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { //planar texgen needs binormals - mVObjp->getVolume()->genTangents(face_index); - } - - U8 tex_mode = 0; - - bool tex_anim = false; - - LLVOVolume* vobj = (LLVOVolume*)mVObjp.get(); - tex_mode = vobj->mTexAnimMode; - - if (vobj->mTextureAnimp) - { //texture animation is in play, override specular and normal map tex coords with diffuse texcoords - tex_anim = true; - } - - if (isState(TEXTURE_ANIM)) - { - if (!tex_mode) - { - clearState(TEXTURE_ANIM); - } - else - { - os = ot = 0.f; - r = 0.f; - cos_ang = 1.f; - sin_ang = 0.f; - ms = mt = 1.f; - - xforms = XFORM_NONE; - } - - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) // || isState(LLFace::RIGGED)) - { //don't override texture transform during tc bake - tex_mode = 0; - } - } - - LLVector4a scalea; - scalea.load3(scale.mV); - - bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - - if ((mat || gltf_mat) && !do_bump) - { - do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) - || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); - } - - // For GLTF materials: Transforms will be applied later - bool do_tex_mat = tex_mode && mTextureMatrix && !gltf_mat; - - if (!do_bump) - { //not bump mapped, might be able to do a cheap update - mVertexBuffer->getTexCoord0Strider(tex_coords0, mGeomIndex, mGeomCount); - - if (texgen != LLTextureEntry::TEX_GEN_PLANAR) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen"); - if (!do_tex_mat) - { - if (xforms == XFORM_NONE) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 1"); - S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size); - } - else - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 2"); - F32* dst = (F32*) tex_coords0.get(); - LLVector4a* src = (LLVector4a*) vf.mTexCoords; - - LLVector4a trans; - trans.splat(-0.5f); - - LLVector4a rot0; - rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); - - LLVector4a rot1; - rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); - - LLVector4a scale; - scale.set(ms, mt, ms, mt); - - LLVector4a offset; - offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); - - LLVector4Logical mask; - mask.clear(); - mask.setElement<2>(); - mask.setElement<3>(); - - S32 count = num_vertices/2 + num_vertices%2; - - for (S32 i = 0; i < count; i++) - { - LLVector4a res = *src++; - xform4a(res, trans, mask, rot0, rot1, offset, scale); - res.store4a(dst); - dst += 4; - } - } - } - else - { //do tex mat, no texgen, no bump - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - *tex_coords0++ = tc; - } - } - } - else - { //no bump, tex gen planar - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen planar"); - if (do_tex_mat) - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); - - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - - *tex_coords0++ = tc; - } - } - else if (xforms != XFORM_NONE) - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); - - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - - *tex_coords0++ = tc; - } - } - else - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); - - *tex_coords0++ = tc; - } - } - } - } - else - { //bump mapped or has material, just do the whole expensive loop - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default"); - - LLStrider bump_tc; - - if (mat && !mat->getNormalID().isNull()) - { //writing out normal and specular texture coordinates, not bump offsets - do_bump = false; - } - - LLStrider dst; - - for (U32 ch = 0; ch < 3; ++ch) - { - S32 xform_channel = XFORM_NONE; - switch (ch) - { - case 0: - xform_channel = XFORM_BLINNPHONG_COLOR; - mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); - break; - case 1: - xform_channel = XFORM_BLINNPHONG_NORMAL; - if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) - { - mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount); - if (mat && !tex_anim) - { - r = mat->getNormalRotation(); - mat->getNormalOffset(os, ot); - mat->getNormalRepeat(ms, mt); - - cos_ang = cos(r); - sin_ang = sin(r); - - } - } - else - { - continue; - } - break; - case 2: - xform_channel = XFORM_BLINNPHONG_SPECULAR; - if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2)) - { - mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount); - if (mat && !tex_anim) - { - r = mat->getSpecularRotation(); - mat->getSpecularOffset(os, ot); - mat->getSpecularRepeat(ms, mt); - - cos_ang = cos(r); - sin_ang = sin(r); - } - } - else - { - continue; - } - break; - } - const bool do_xform = (xforms & xform_channel) != XFORM_NONE; - - // hold onto strider to front of TC array for use later - bump_tc = dst; - - { - // NOTE: split TEX_GEN_PLANAR implementation to reduce branchiness of inner loop - // These are per-vertex operations and every little bit counts - if (texgen == LLTextureEntry::TEX_GEN_PLANAR) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("tgd - planar"); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - - vec.mul(scalea); - - planarProjection(tc, norm, center, vec); - - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - } - else if (do_xform) - { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - } - - *dst++ = tc; - } - } - else - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("tgd - transform"); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - } - else if (do_xform) - { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - } - - *dst++ = tc; - } - } - } - } - - if ((!mat && !gltf_mat) && do_bump) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("tgd - do bump"); - mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount); - - mVObjp->getVolume()->genTangents(face_index); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a tangent = vf.mTangents[i]; - - LLVector4a binorm; - binorm.setCross3(vf.mNormals[i], tangent); - binorm.mul(tangent.getF32ptr()[3]); - - LLMatrix4a tangent_to_object; - tangent_to_object.setRows(tangent, binorm, vf.mNormals[i]); - LLVector4a t; - tangent_to_object.rotate(binormal_dir, t); - LLVector4a binormal; - mat_normal.rotate(t, binormal); - - //VECTORIZE THIS - if (mDrawablep->isActive()) - { - LLVector3 t; - t.set(binormal.getF32ptr()); - t *= bump_quat; - binormal.load3(t.mV); - } - - binormal.normalize3fast(); - - LLVector2 tc = bump_tc[i]; - tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - - *tex_coords1++ = tc; - } - } - } - } - - if (rebuild_pos) - { - LLVector4a* src = vf.mPositions; - - //_mm_prefetch((char*)src, _MM_HINT_T0); - - LLVector4a* end = src+num_vertices; - //LLVector4a* end_64 = end-4; - - llassert(num_vertices > 0); - - mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount); - - - F32* dst = (F32*) vert.get(); - F32* end_f32 = dst+mGeomCount*4; - - //_mm_prefetch((char*)dst, _MM_HINT_NTA); - //_mm_prefetch((char*)src, _MM_HINT_NTA); - - //_mm_prefetch((char*)dst, _MM_HINT_NTA); - - - LLVector4a res0; //,res1,res2,res3; - - LLVector4a texIdx; - - S32 index = mTextureIndex < FACE_DO_NOT_BATCH_TEXTURES ? mTextureIndex : 0; - - F32 val = 0.f; - S32* vp = (S32*) &val; - *vp = index; - - llassert(index < LLGLSLShader::sIndexedTextureChannels); - - LLVector4Logical mask; - mask.clear(); - mask.setElement<3>(); - - texIdx.set(0,0,0,val); - - LLVector4a tmp; - - - while (src < end) - { - mat_vert.affineTransform(*src++, res0); - tmp.setSelectWithMask(mask, texIdx, res0); - tmp.store4a((F32*) dst); - dst += 4; - } - - while (dst < end_f32) - { - res0.store4a((F32*) dst); - dst += 4; - } - } - - if (rebuild_normal) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal"); - - mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount); - F32* normals = (F32*) norm.get(); - LLVector4a* src = vf.mNormals; - LLVector4a* end = src+num_vertices; - - while (src < end) - { - LLVector4a normal; - mat_normal.rotate(*src++, normal); - normal.store4a(normals); - normals += 4; - } - } - - if (rebuild_tangent) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent"); - mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount); - F32* tangents = (F32*) tangent.get(); - - mVObjp->getVolume()->genTangents(face_index); - - LLVector4Logical mask; - mask.clear(); - mask.setElement<3>(); - - LLVector4a* src = vf.mTangents; - LLVector4a* end = vf.mTangents +num_vertices; - - while (src < end) - { - LLVector4a tangent_out; - mat_normal.rotate(*src, tangent_out); - tangent_out.setSelectWithMask(mask, *src, tangent_out); - tangent_out.store4a(tangents); - - src++; - tangents += 4; - } - } - - if (rebuild_weights && vf.mWeights) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight"); - mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount); - F32* weights = (F32*) wght.get(); - LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); - } - - if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color"); - mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount); - - LLVector4a src; - - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = color.asRGBA(); - - src.loadua((F32*) vec); - - F32* dst = (F32*) colors.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } - - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } - } - - if (rebuild_emissive) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive"); - LLStrider emissive; - mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount); - - U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); - - LLVector4a src; - - - LLColor4U glow4u = LLColor4U(0,0,0,glow); - - U32 glow32 = glow4u.asRGBA(); - - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = glow32; - - src.loadua((F32*) vec); - - F32* dst = (F32*) emissive.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } - - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } - } - } - - if (rebuild_tcoord) - { - mTexExtents[0].setVec(0,0); - mTexExtents[1].setVec(1,1); - xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); - xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); - - F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; - F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; - mTexExtents[0][0] *= es ; - mTexExtents[1][0] *= es ; - mTexExtents[0][1] *= et ; - mTexExtents[1][1] *= et ; - } - - - return true; -} - void LLFace::renderIndexed() { if (mVertexBuffer.notNull()) @@ -2140,17 +1184,8 @@ F32 LLFace::getTextureVirtualSize() return 0.f; } - //get area of circle in texture space - LLVector2 tdim = mTexExtents[1] - mTexExtents[0]; - F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f; - if (texel_area <= 0) - { - // Probably animated, use default - texel_area = 1.f; - } - F32 face_area; - if (mVObjp->isSculpted() && texel_area > 1.f) + if (mVObjp->isSculpted()) { //sculpts can break assumptions about texel area face_area = mPixelArea; @@ -2159,7 +1194,7 @@ F32 LLFace::getTextureVirtualSize() { //apply texel area to face area to get accurate ratio //face_area /= llclamp(texel_area, 1.f/64.f, 16.f); - face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f); + face_area = mPixelArea; } face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area); @@ -2589,6 +1624,151 @@ U64 LLFace::getSkinHash() return mSkinInfo ? mSkinInfo->mHash : 0; } +void LLFace::updateBatchHash() +{ + const LLTextureEntry* te = getTextureEntry(); + auto* gltf_mat = te->getGLTFRenderMaterial(); + if (gltf_mat) + { + gltf_mat->updateBatchHash(); + mBatchHash = gltf_mat->getBatchHash(); + mAlphaMode = gltf_mat->mAlphaMode; + } + else + { + // calculate blinn-phong batch hash and alpha mode + mBatchHash = 0; + + const auto& mat = te->getMaterialParams(); + if (mat.notNull()) + { + if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + boost::hash_combine(mBatchHash, mat->getAlphaMaskCutoff()); + } + + switch (mat->getDiffuseAlphaMode()) + { + case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND: + mAlphaMode = LLGLTFMaterial::ALPHA_MODE_BLEND; + break; + case LLMaterial::DIFFUSE_ALPHA_MODE_MASK: + mAlphaMode = LLGLTFMaterial::ALPHA_MODE_MASK; + break; + default: + mAlphaMode = LLGLTFMaterial::ALPHA_MODE_OPAQUE; + break; + }; + + boost::hash_combine(mBatchHash, mat->getBatchHash()); + } + else + { + if (te->getAlpha() == 0.f && te->getGlow() == 0.f) + { // don't render fully transparent faces + mBatchHash = 0; + return; + } + if (te->getAlpha() < 1.f || getTexture()->getComponents() == 4) + { + mAlphaMode = LLGLTFMaterial::ALPHA_MODE_BLEND; + } + else + { + mAlphaMode = LLGLTFMaterial::ALPHA_MODE_OPAQUE; + } + } + + boost::hash_combine(mBatchHash, te->getID()); + boost::hash_combine(mBatchHash, te->getColor()); + boost::hash_combine(mBatchHash, te->getAlpha()); + boost::hash_combine(mBatchHash, te->getScaleS()); + boost::hash_combine(mBatchHash, te->getScaleT()); + boost::hash_combine(mBatchHash, te->getRotation()); + boost::hash_combine(mBatchHash, te->getOffsetS()); + boost::hash_combine(mBatchHash, te->getOffsetT()); + boost::hash_combine(mBatchHash, te->getFullbright()); + + } + + boost::hash_combine(mBatchHash, te->getGlow()); +} + +void LLFace::packMaterialOnto(std::vector& dst) +{ + auto* gltf_mat = getTextureEntry()->getGLTFRenderMaterial(); + + const LLTextureEntry* te = getTextureEntry(); + F32 glow = te->getGlow(); + if (gltf_mat) + { + gltf_mat->packOnto(dst, glow); + } + { + // pack blinn-phong material + F32 env_intensity = 0.f; + LLColor3 spec = LLColor3::black; + + const LLMaterial* mat = te->getMaterialParams().get(); + + dst.resize(dst.size()+7); + LLVector4a* data = &dst[dst.size()-7]; + + F32 min_alpha = 1.f; + F32 glossiness = 0.f; + F32 emissive = 0.f; + F32 emissive_mask = 0.f; + + LLColor4 col = te->getColor(); + + data[0].set(te->getScaleS(), te->getScaleT(), te->getRotation(), te->getOffsetS()); + data[1].set(te->getOffsetT(), col.mV[0], col.mV[1], col.mV[2]); + + if (mat) + { + env_intensity = mat->getEnvironmentIntensity()/255.f; + spec = mat->getSpecularLightColor(); + + if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + min_alpha = mat->getAlphaMaskCutoff()/255.f; + } + + data[2].set(mat->getNormalRepeatX(), mat->getNormalRepeatY(), mat->getNormalRotation(), mat->getNormalOffsetX()); + data[3].set(mat->getNormalOffsetY(), col.mV[3], min_alpha, env_intensity); + + data[4].set(mat->getSpecularRepeatX(), mat->getSpecularRepeatY(), mat->getSpecularRotation(), mat->getSpecularOffsetX()); + data[5].set(mat->getSpecularOffsetY(), spec.mV[0], spec.mV[1], spec.mV[2]); + + glossiness = mat->getSpecularLightExponent() / 255.f; + + if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE) + { + emissive_mask = 1.f; + } + } + else + { + F32 v[] = { 0.f, 0.25f, 0.5f, 0.75f }; + env_intensity = v[llclamp(te->getShiny(), 0, 4)]; + spec.set(env_intensity, env_intensity, env_intensity); + + data[2].set(1, 1, 0, 0); + data[3].set(0, col.mV[3], min_alpha, env_intensity); + + data[4].set(1, 1, 0, 0); + data[5].set(1, spec.mV[0], spec.mV[1], spec.mV[2]); + } + + if (te->getFullbright()) + { + emissive = 1.f; + } + + data[6].set(emissive, emissive_mask, glossiness, glow); + } +} + bool LLFace::isInAlphaPool() const { return getPoolType() == LLDrawPool::POOL_ALPHA || diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 65637fbf859..c4980e4d5a3 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -39,6 +39,7 @@ #include "llvertexbuffer.h" #include "llviewertexture.h" #include "lldrawable.h" +#include "llgltfdrawinfo.h" class LLFacePool; class LLVolume; @@ -149,20 +150,11 @@ class alignas(16) LLFace void setFaceColor(const LLColor4& color); // override material color void unsetFaceColor(); // switch back to material color - const LLColor4& getFaceColor() const { return mFaceColor; } //for volumes void updateRebuildFlags(); bool canRenderAsMask(); // logic helper - bool getGeometryVolume(const LLVolume& volume, - S32 face_index, - const LLMatrix4& mat_vert, - const LLMatrix3& mat_normal, - U16 index_offset, - bool force_rebuild = false, - bool no_debug_assert = false, - bool rebuild_for_gltf = false); // For avatar U16 getGeometryAvatar( @@ -188,10 +180,8 @@ class alignas(16) LLFace void init(LLDrawable* drawablep, LLViewerObject* objp); void destroy(); - void update(); void updateCenterAgent(); // Update center when xform has changed. - void renderSelectedUV(); void renderSelected(LLViewerTexture *image, const LLColor4 &color); void renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wireframe_selection, bool bRenderHiddenSelections, bool shader); @@ -217,8 +207,6 @@ class alignas(16) LLFace void setMediaAllowed(bool is_media_allowed) { mIsMediaAllowed = is_media_allowed; } bool isMediaAllowed() const { return mIsMediaAllowed; } - bool switchTexture() ; - //vertex buffer tracking void setVertexBuffer(LLVertexBuffer* buffer); void clearVertexBuffer(); //sets mVertexBuffer to NULL @@ -255,7 +243,6 @@ class alignas(16) LLFace LLVector3 mCenterLocal; LLVector3 mCenterAgent; - LLVector2 mTexExtents[2]; F32 mDistance; F32 mLastUpdateTime; F32 mLastSkinTime; @@ -275,6 +262,20 @@ class alignas(16) LLFace // value of gFrameCount the last time the face was touched by LLViewerTextureList::updateImageDecodePriority U32 mLastTextureUpdate = 0; + U32 mMaterialIndex = 0xFFFFFFFF; // index of material in LLSpatialGroup's material UBO + U32 mTextureTransformIndex = 0xFFFFFFFF; // index of texture transform in LLSpatialGroup's texture transform UBO + + LLGLTFDrawInfoHandle mGLTFDrawInfo; // handle to GLTF draw info for this face. + + // hash of material for use in render batch sorting + size_t mBatchHash = 0; + + // cached alpha mode that matches mBatchHash for use in render batch sorting + LLGLTFMaterial::AlphaMode mAlphaMode = LLGLTFMaterial::ALPHA_MODE_OPAQUE; + + void updateBatchHash(); + void packMaterialOnto(std::vector& dst); + private: LLPointer mVertexBuffer; LLPointer mVertexBufferGLTF; diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 69c5a774824..5d4cc82e01e 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -63,17 +63,16 @@ LLFetchedGLTFMaterial& LLFetchedGLTFMaterial::operator=(const LLFetchedGLTFMater void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex) { + LL_PROFILE_ZONE_SCOPED; + bindTextures(media_tex); + // glTF 2.0 Specification 3.9.4. Alpha Coverage // mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK F32 min_alpha = -1.0; LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - // override emissive and base color textures with media tex if present - LLViewerTexture* baseColorTex = media_tex ? media_tex : mBaseColorTexture; - LLViewerTexture* emissiveTex = media_tex ? media_tex : mEmissiveTexture; - - if (!LLPipeline::sShadowRender || (mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)) + if (mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK) { if (mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK) { @@ -82,37 +81,68 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex) shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); } + F32 base_color_packed[8]; + mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); + shader->uniform4fv(LLShaderMgr::BASE_COLOR_FACTOR, 1, mBaseColor.mV); + + if (!LLPipeline::sShadowRender) + { + shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mRoughnessFactor); + shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mMetallicFactor); + shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, mEmissiveColor.mV); + + F32 normal_packed[8]; + mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed); + + F32 metallic_roughness_packed[8]; + mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed); + + F32 emissive_packed[8]; + mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed); + } +} + +void LLFetchedGLTFMaterial::bindTextures(LLViewerTexture* media_tex) +{ + LL_PROFILE_ZONE_SCOPED; + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + // override emissive and base color textures with media tex if present + LLViewerTexture* baseColorTex = media_tex ? media_tex : mBaseColorTexture; + LLViewerTexture* emissiveTex = media_tex ? media_tex : mEmissiveTexture; + if (baseColorTex != nullptr) { shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, baseColorTex); } else { - shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, LLViewerFetchedTexture::sWhiteImagep); + shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, LLViewerFetchedTexture::sWhiteImagep.get()); } - F32 base_color_packed[8]; - mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); - if (!LLPipeline::sShadowRender) { if (mNormalTexture.notNull() && mNormalTexture->getDiscardLevel() <= 4) { - shader->bindTexture(LLShaderMgr::BUMP_MAP, mNormalTexture); + shader->bindTexture(LLShaderMgr::BUMP_MAP, mNormalTexture.get()); } else { - shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep.get()); } if (mMetallicRoughnessTexture.notNull()) { - shader->bindTexture(LLShaderMgr::SPECULAR_MAP, mMetallicRoughnessTexture); // PBR linear packed Occlusion, Roughness, Metal. + shader->bindTexture(LLShaderMgr::SPECULAR_MAP, mMetallicRoughnessTexture.get()); // PBR linear packed Occlusion, Roughness, Metal. } else { - shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); + shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep.get()); } if (emissiveTex != nullptr) @@ -121,29 +151,12 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex) } else { - shader->bindTexture(LLShaderMgr::EMISSIVE_MAP, LLViewerFetchedTexture::sWhiteImagep); + shader->bindTexture(LLShaderMgr::EMISSIVE_MAP, LLViewerFetchedTexture::sWhiteImagep.get()); } - - // NOTE: base color factor is baked into vertex stream - - shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mRoughnessFactor); - shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mMetallicFactor); - shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, mEmissiveColor.mV); - - F32 normal_packed[8]; - mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed); - - F32 metallic_roughness_packed[8]; - mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed); - - F32 emissive_packed[8]; - mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed); } } + LLViewerFetchedTexture* fetch_texture(const LLUUID& id) { LLViewerFetchedTexture* img = nullptr; diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index 074e3fef415..fb6470552c2 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -54,6 +54,9 @@ class LLFetchedGLTFMaterial: public LLGLTFMaterial // media_tex - optional media texture that may override the base color texture void bind(LLViewerTexture* media_tex = nullptr); + // bind textureso only (for use when parameters are stored in a UBO) + void bindTextures(LLViewerTexture* media_tex = nullptr); + bool isFetching() const { return mFetching; } bool isLoaded() const { return !mFetching && mFetchSuccess; } diff --git a/indra/newview/llgltfdrawinfo.cpp b/indra/newview/llgltfdrawinfo.cpp new file mode 100644 index 00000000000..8ea51f6e75a --- /dev/null +++ b/indra/newview/llgltfdrawinfo.cpp @@ -0,0 +1,192 @@ +/** + * @file llgltfdrawinfo.cpp + * @brief LLGLTFDrawInfo implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llgltfdrawinfo.h" + +void LLGLTFBatches::clear() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + mBatchList.clear(); + mSkinnedBatchList.clear(); + + for (U32 alpha_mode = 0; alpha_mode < 3; ++alpha_mode) + { + for (U32 tex_mask = 0; tex_mask < MAX_TEX_MASK; ++tex_mask) + { + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].clear(); + mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].clear(); + } + } + } + } + } +} + +void LLGLTFDrawInfo::texNameCheck(U32 texName) +{ + if (LLImageGL::sTexNames[mBaseColorMap] == texName) + { + LL_WARNS_ONCE("GLTF") << "Base color map (or diffuse map) dangling reference: " << mBaseColorMap << LL_ENDL; + } + + if (LLImageGL::sTexNames[mMetallicRoughnessMap] == texName) + { + LL_WARNS_ONCE("GLTF") << "Metallic roughness map (or specular map) dangling reference: " << mMetallicRoughnessMap << LL_ENDL; + } + + if (LLImageGL::sTexNames[mNormalMap] == texName) + { + LL_WARNS_ONCE("GLTF") << "Normal map dangling reference: " << mNormalMap << LL_ENDL; + } + + if (LLImageGL::sTexNames[mEmissiveMap] == texName) + { + LL_WARNS_ONCE("GLTF") << "Emissive map dangling reference: " << mEmissiveMap << LL_ENDL; + } +} + +LLGLTFDrawInfo* LLGLTFBatches::create(LLGLTFMaterial::AlphaMode alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim, LLGLTFDrawInfoHandle &handle) +{ + auto& draw_info = mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + + if (draw_info.empty()) + { + mBatchList.push_back({ alpha_mode, tex_mask, double_sided, planar, tex_anim, &draw_info }); + } + + handle.mSkinned = false; + handle.mContainer = &draw_info; + handle.mIndex = (S32)draw_info.size(); + + return &draw_info.emplace_back(); +} + +LLSkinnedGLTFDrawInfo* LLGLTFBatches::createSkinned(LLGLTFMaterial::AlphaMode alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim, LLGLTFDrawInfoHandle& handle) +{ + auto& draw_info = mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]; + + if (draw_info.empty()) + { + mSkinnedBatchList.push_back({ alpha_mode, tex_mask, double_sided, planar, tex_anim, &draw_info }); + } + + handle.mSkinned = true; + handle.mSkinnedContainer = &draw_info; + handle.mIndex = (S32)draw_info.size(); + + return &draw_info.emplace_back(); +} + +void LLGLTFBatches::add(const LLGLTFBatches& other) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + for (auto& batch : other.mBatchList) + { + auto& draw_info = mDrawInfo[batch.alpha_mode][batch.tex_mask][batch.double_sided][batch.planar][batch.tex_anim]; + draw_info.insert(draw_info.end(), batch.draw_info->begin(), batch.draw_info->end()); + } + + for (auto& batch : other.mSkinnedBatchList) + { + auto& draw_info = mSkinnedDrawInfo[batch.alpha_mode][batch.tex_mask][batch.double_sided][batch.planar][batch.tex_anim]; + draw_info.insert(draw_info.end(), batch.draw_info->begin(), batch.draw_info->end()); + } +} + +void LLGLTFBatches::addShadow(const LLGLTFBatches& other) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + for (auto& batch : other.mBatchList) + { + if (batch.alpha_mode != LLGLTFMaterial::ALPHA_MODE_OPAQUE) + { + auto& draw_info = mDrawInfo[batch.alpha_mode][batch.tex_mask][batch.double_sided][batch.planar][batch.tex_anim]; + draw_info.insert(draw_info.end(), batch.draw_info->begin(), batch.draw_info->end()); + } + } + + for (auto& batch : other.mSkinnedBatchList) + { + if (batch.alpha_mode != LLGLTFMaterial::ALPHA_MODE_OPAQUE) + { + auto& draw_info = mSkinnedDrawInfo[batch.alpha_mode][batch.tex_mask][batch.double_sided][batch.planar][batch.tex_anim]; + draw_info.insert(draw_info.end(), batch.draw_info->begin(), batch.draw_info->end()); + } + } +} + +void LLGLTFBatches::texNameCheck(U32 texName) +{ + for (auto& batch : mBatchList) + { + for (auto& draw_info : *batch.draw_info) + { + draw_info.texNameCheck(texName); + } + } + + for (auto& batch : mSkinnedBatchList) + { + for (auto& draw_info : *batch.draw_info) + { + draw_info.texNameCheck(texName); + } + } +} + +LLGLTFDrawInfo* LLGLTFDrawInfoHandle::get() +{ + if (mIndex == -1) + { + return nullptr; + } + + if (mSkinned) + { + llassert(mIndex >= 0 && mIndex < mSkinnedContainer->size()); + return &mSkinnedContainer->at(mIndex); + } + else + { + llassert(mIndex >= 0 && mIndex < mContainer->size()); + return &mContainer->at(mIndex); + } +} + +void LLGLTFDrawInfoHandle::clear() +{ + mIndex = -1; +} + diff --git a/indra/newview/llgltfdrawinfo.h b/indra/newview/llgltfdrawinfo.h new file mode 100644 index 00000000000..63a4a6e3ea1 --- /dev/null +++ b/indra/newview/llgltfdrawinfo.h @@ -0,0 +1,229 @@ +/** + * @file llgltfdrawinfo.h + * @brief LLDrawInfo equivalent for GLTF material render pipe + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llvoavatar.h" + +class LLSpatialGroup; + +// Draw call information that fits on a cache line (64 bytes) +// Called LLGLTFDrawInfo, but also used for Blinn-phong but with different data meaning +// Unions used to clarify what means what in which context +class LLGLTFDrawInfo +{ +public: + // put mMaterialID first for cache coherency during sorts + size_t mMaterialID; + + // Use direct values of VBO/IBO and texture names to avoid dereferencing pointers + // NOTE: if these GL resources are freed while still in use, something has gone wrong in LLVertexBuffer/LLImageGL + // The bug is there, not here. + U32 mVBO; + U32 mIBO; + U32 mVBOVertexCount; + union + { + U16 mBaseColorMap; + U16 mDiffuseMap; + }; + U16 mNormalMap; + union + { + U16 mMetallicRoughnessMap; + U16 mSpecularMap; + }; + U16 mEmissiveMap; + U32 mElementCount; + U32 mElementOffset; + U32 mTransformUBO; + U32 mInstanceMapUBO; + U32 mMaterialUBO; + U32 mTextureTransformUBO; + U16 mInstanceCount; + U16 mBaseInstance; + U8 mIndicesSize; // 0 - 2 bytes, 1 - 4 bytes + + void texNameCheck(U32 texName); +}; + +class LLSkinnedGLTFDrawInfo : public LLGLTFDrawInfo +{ +public: + LLPointer mAvatar = nullptr; + LLMeshSkinInfo* mSkinInfo = nullptr; +}; + +class LLGLTFDrawInfoHandle; + +class LLGLTFBatches +{ +public: + + enum TexMask + { + BASE_COLOR_MAP = 1, + DIFFUSE_MAP = 1, + NORMAL_MAP = 2, + SPECULAR_MAP = 4, + METALLIC_ROUGHNESS_MAP = 4, + EMISSIVE_MAP = 8 + }; + + static constexpr U8 MAX_TEX_MASK = 16; + static constexpr U8 MAX_PBR_TEX_MASK = 16; + static constexpr U8 MAX_BP_TEX_MASK = 8; + + typedef std::vector gltf_draw_info_list_t; + typedef std::vector skinned_gltf_draw_info_list_t; + typedef gltf_draw_info_list_t gltf_draw_info_map_t[3][MAX_TEX_MASK][2][2][2]; + typedef skinned_gltf_draw_info_list_t skinned_gltf_draw_info_map_t[3][MAX_TEX_MASK][2][2][2]; + + // collections of GLTFDrawInfo + // indexed by [LLGLTFMaterial::mAlphaMode][texture mask][Double Sided][Planar Projection][Texture Animation] + gltf_draw_info_map_t mDrawInfo; + skinned_gltf_draw_info_map_t mSkinnedDrawInfo; + + struct BatchList + { + LLGLTFMaterial::AlphaMode alpha_mode; + U8 tex_mask; + bool double_sided; + bool planar; + bool tex_anim; + gltf_draw_info_list_t* draw_info; + }; + + struct SkinnedBatchList + { + LLGLTFMaterial::AlphaMode alpha_mode; + U8 tex_mask; + bool double_sided; + bool planar; + bool tex_anim; + skinned_gltf_draw_info_list_t* draw_info; + }; + + // collections that point to non-empty collections in mDrawInfo to accelerate iteration over all draw infos + std::vector mBatchList; + std::vector mSkinnedBatchList; + + // clear all draw infos + void clear(); + + // add a draw info to the appropriate list + LLGLTFDrawInfo* create(LLGLTFMaterial::AlphaMode alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim, LLGLTFDrawInfoHandle& handle); + + // add a sikinned draw info to the appropriate list + LLSkinnedGLTFDrawInfo* createSkinned(LLGLTFMaterial::AlphaMode alpha_mode, U8 tex_mask, bool double_sided, bool planar, bool tex_anim, LLGLTFDrawInfoHandle& handle); + + // add the given LLGLTFBatches to these LLGLTFBatches + void add(const LLGLTFBatches& other); + + // add the alpha blend and alpha mask draw infos to the given list + void addShadow(const LLGLTFBatches& other); + + template + void sort(LLGLTFMaterial::AlphaMode alpha_mode, T comparator) + { + for (U32 tex_mask = 0; tex_mask < MAX_TEX_MASK; ++tex_mask) + { + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + std::sort(mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].begin(), mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].end(), comparator); + } + } + } + } + } + + template + void sortSkinned(LLGLTFMaterial::AlphaMode alpha_mode, T comparator) + { + for (U32 tex_mask = 0; tex_mask < MAX_TEX_MASK; ++tex_mask) + { + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + std::sort(mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].begin(), mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim].end(), comparator); + } + } + } + } + } + + void texNameCheck(U32 texName); +}; + +// handle to a GLTFDrawInfo +// Can be invalidated if mContainer is destroyed or resized +class LLGLTFDrawInfoHandle +{ +public: + // Vector GLTFDrawInfo is stored in + union + { + LLGLTFBatches::gltf_draw_info_list_t* mContainer; + LLGLTFBatches::skinned_gltf_draw_info_list_t* mSkinnedContainer = nullptr; + }; + + LLSpatialGroup* mSpatialGroup = nullptr; + + // whether this is a skinned or non-skinned draw info + bool mSkinned = false; + + // index into that vector + S32 mIndex = -1; + + // get the LLGLTFDrawInfo this handle points to + // Makes an attempt to assert pointer is valid, but does not guarantee safety + // MUST NOT be called unless you are certain the handle is valid + LLGLTFDrawInfo* get(); + + LLGLTFDrawInfo* operator->() + { + return get(); + } + + // return true if this handle was set to a valid draw info at some point + // DOES NOT indicate pointer returned by get() is valid + // MAY be called on an invalid handle + operator bool() const + { + return mIndex >= 0; + } + + // Clear the handle + // Sets mIndex to -1, but maintains other state for debugging + void clear(); +}; diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp index 5ca841f9f12..f4f3e2ac15f 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.cpp +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -379,6 +379,7 @@ PreviewSphere& get_preview_sphere(LLPointer& material, co return preview_sphere; } +#if 0 // Final, direct modifications to shader constants, just before render void fixup_shader_constants(LLGLSLShader& shader) { @@ -397,6 +398,7 @@ void fixup_shader_constants(LLGLSLShader& shader) } } } +#endif // Set a variable to a value temporarily, and restor the variable's old value // when this object leaves scope. @@ -502,8 +504,8 @@ bool LLGLTFPreviewTexture::render() screen.bindTarget(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#if 0 LLGLSLShader& shader = gDeferredPBRAlphaProgram; - gPipeline.bindDeferredShader(shader); fixup_shader_constants(shader); @@ -513,6 +515,7 @@ bool LLGLTFPreviewTexture::render() } gPipeline.unbindDeferredShader(shader); +#endif screen.flush(); } diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 4c02511268f..dcfc8aac562 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1668,6 +1668,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLIMProcessing::processNewMessage"); std::vector local_bin_bucket = bin_bucket; LLHost local_sender = sender; LLIMProcessing::processNewMessage( diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index ceec8bf3912..2e38d7b29ac 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -131,11 +131,11 @@ const char* remove_utf8_bom(const char* buf) return start; } -class LLLogChatTimeScanner: public LLSingleton +class LLLogChatTimeScanner: public LLSimpleton { - LLSINGLETON(LLLogChatTimeScanner); - public: + LLLogChatTimeScanner(); + date getTodayPacificDate() { typedef boost::date_time::local_adjustor pst; @@ -984,6 +984,10 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params if (cut_off_todays_date) { + if (!LLLogChatTimeScanner::instanceExists()) + { + LLLogChatTimeScanner::createInstance(); + } LLLogChatTimeScanner::instance().checkAndCutOffDate(timestamp); } diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index ac4c18d60c9..e1e647ea59e 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -36,12 +36,11 @@ class LLViewerRegion; -class LLMaterialMgr : public LLSingleton +class LLMaterialMgr : public LLSimpleton { - LLSINGLETON(LLMaterialMgr); - virtual ~LLMaterialMgr(); - public: + LLMaterialMgr(); + virtual ~LLMaterialMgr(); typedef std::map material_map_t; typedef boost::signals2::signal get_callback_t; diff --git a/indra/newview/llpbrterrainfeatures.cpp b/indra/newview/llpbrterrainfeatures.cpp index bb771c6963a..7f55085fd15 100644 --- a/indra/newview/llpbrterrainfeatures.cpp +++ b/indra/newview/llpbrterrainfeatures.cpp @@ -144,6 +144,7 @@ void LLPBRTerrainFeatures::queryRegionCoro(std::string cap_url, LLUUID region_id { LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLPBRTerrainFeatures::queryRegionCoro done_callback"); done_callback(region_id, success, *composition); delete composition; }); @@ -191,6 +192,7 @@ void LLPBRTerrainFeatures::modifyRegionCoro(std::string cap_url, LLSD updates, v { LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLPBRTerrainFeatures::modifyRegionCoro done_callback"); done_callback(success); }); } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 1420b4032ed..877f31d5a6e 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -72,12 +72,12 @@ class LLRemoteParcelInfoObserver LLRootHandle mObserverHandle; }; -class LLRemoteParcelInfoProcessor : public LLSingleton +class LLRemoteParcelInfoProcessor : public LLSimpleton { - LLSINGLETON_EMPTY_CTOR(LLRemoteParcelInfoProcessor); +public: virtual ~LLRemoteParcelInfoProcessor() {} -public: + void addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer); void removeObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index a1a67c319cc..b075749c800 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -53,6 +53,8 @@ #include "llvolumemgr.h" #include "llviewershadermgr.h" #include "llcontrolavatar.h" +#include "llskinningutil.h" +#include "llviewertextureanim.h" extern bool gShiftFrame; @@ -67,8 +69,6 @@ static F32 sCurMaxTexPriority = 1.f; // enable expensive sanity checks around redundant drawable and group insertion to LLCullResult #define LL_DEBUG_CULL_RESULT 0 -//static counter for frame to switch LOD on - void sg_assert(bool expr) { #if LL_OCTREE_PARANOIA_CHECK @@ -79,6 +79,26 @@ void sg_assert(bool expr) #endif } +// pack a given LLMatrix4 into a mat4x3 for GLSL +static void pack_transform(const LLMatrix4& mat, F32* mp) +{ + const F32* m = &mat.mMatrix[0][0]; + mp[0] = m[0]; + mp[1] = m[1]; + mp[2] = m[2]; + mp[3] = m[12]; + + mp[4] = m[4]; + mp[5] = m[5]; + mp[6] = m[6]; + mp[7] = m[13]; + + mp[8] = m[8]; + mp[9] = m[9]; + mp[10] = m[10]; + mp[11] = m[14]; +} + //returns: // 0 if sphere and AABB are not intersecting // 1 if they are @@ -128,6 +148,41 @@ LLSpatialGroup::~LLSpatialGroup() sNodeCount--; clearDrawMap(); + + if (mTransformUBO) + { + ll_gl_delete_buffers(1, &mTransformUBO); + } + + if (mInstanceMapUBO) + { + ll_gl_delete_buffers(1, &mInstanceMapUBO); + } + + if (mMaterialUBO) + { + ll_gl_delete_buffers(1, &mMaterialUBO); + } + + if (mTextureTransformUBO) + { + ll_gl_delete_buffers(1, &mTextureTransformUBO); + } + + if (mBPInstanceMapUBO) + { + ll_gl_delete_buffers(1, &mBPInstanceMapUBO); + } + + if (mPrimScaleUBO) + { + ll_gl_delete_buffers(1, &mPrimScaleUBO); + } + + if (mShadowInstanceMapUBO) + { + ll_gl_delete_buffers(1, &mShadowInstanceMapUBO); + } } void LLSpatialGroup::clearDrawMap() @@ -459,6 +514,27 @@ void LLSpatialGroup::shift(const LLVector4a &offset) mObjectExtents[0].add(offset); mObjectExtents[1].add(offset); + if (getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) + { + // add root transform + if (!getSpatialPartition()->asBridge()) + { + LLViewerRegion* regionp = getSpatialPartition()->mRegionp; + LLMatrix4 rootMat; + if (regionp) + { + rootMat.setTranslation(regionp->getOriginAgent()); + } + + F32 mat[12]; + + pack_transform(rootMat, mat); + + glBindBuffer(GL_UNIFORM_BUFFER, mTransformUBO); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(F32) * 12, mat); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } if (!getSpatialPartition()->mRenderByGroup && getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE && getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN && @@ -760,6 +836,8 @@ bool LLSpatialGroup::changeLOD() if (needsUpdate()) { + // perturb hash to avoid clustering of updates + mLODHash = rand() % mSpatialPartition->mLODPeriod; return true; } @@ -861,6 +939,779 @@ void LLSpatialGroup::rebound() } } +void LLSpatialGroup::updateTransformUBOs() +{ + if (mOctreeNode == nullptr) + { + return; + } + + // only valid for volume partitions + if (getSpatialPartition()->mDrawableType != LLPipeline::RENDER_TYPE_VOLUME) + { + return; + } + + STOP_GLERROR; + // build transform UBO and transform intance map UBO + // Each LLVolumeFace contains an LLVertexBuffer of that face's geometry + // It's common for there to be many instances of an LLFace with the same material within a given spatial group + // Each LLSpatialGroup will provide several UBOs to the shader: + // mTransformUBO: a UBO containing a transform from LLVolume space to agent space for each drawable in the group + // mInstanceMapUBO: a UBO mapping gl_InstanceID to the index of the transform in mTransformUBO + // mMaterialUBO: a UBO containing material data for each material used by the group + // mTextureTransformUBO: a UBO containing texture transform data for each texture transform used by the group (if animated textures are present) + + U32 mat_id = 0; + U32 bp_mat_id = 0; + + // map of face mBatchHash to material index in UBO + std::unordered_map materials; + + LL_PROFILE_ZONE_SCOPED; + static std::vector transforms; + transforms.resize(1); + + LLMatrix4 rootMat; + LLMatrix4 rootObjMat; + LLMatrix4 invRootMat; + + LLDrawable* root = nullptr; + + // add root transform + if (getSpatialPartition()->asBridge()) + { + root = getSpatialPartition()->asBridge()->mDrawable; + rootObjMat.initScale(root->getScale()); + rootMat = root->getRenderMatrix(); + } + else + { + LLViewerRegion* regionp = getSpatialPartition()->mRegionp; + if (regionp) + { + rootMat.setTranslation(regionp->getOriginAgent()); + invRootMat.setTranslation(-regionp->getOriginAgent()); + } + } + + transforms[0] = &rootMat; + + static std::vector texture_transforms; + texture_transforms.resize(0); + + U32 max_transforms = LLSkinningUtil::getMaxGLTFJointCount(); + + mGLTFBatches.clear(); + mBPBatches.clear(); + mShadowBatches.clear(); + mVertexBuffers.clear(); + + static std::vector faces; + faces.clear(); + + static std::vector material_data; + material_data.clear(); + + static std::vector bp_faces; + bp_faces.clear(); + + static std::vector shadow_faces; + shadow_faces.clear(); + + static LLCachedControl depth_pre_pass(gSavedSettings, "RenderDepthPrePass"); + bool shadows = LLPipeline::RenderShadowDetail > 0 || depth_pre_pass; + + { + LL_PROFILE_ZONE_NAMED("utubo - collect transforms"); + for (OctreeNode::const_element_iter i = getDataBegin(); i != getDataEnd(); ++i) + { + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + llassert(drawable); // octree nodes are not allowed to contain null drawables + + LLVOVolume* vobj = drawable->getVOVolume(); + + if (!vobj || vobj->isDead()) + { + continue; + } + + // TODO: split transform UBOs when we blow past the UBO size limit + llassert(transforms.size() < max_transforms); + U32 transform_index = (U32)transforms.size(); + if (root != drawable) + { + transforms.push_back(&drawable->getGLTFRenderMatrix(root != nullptr, &invRootMat)); + } + else + { + transforms.push_back(&rootObjMat); + } + + U32 prim_scale_index = (U32)material_data.size(); + const LLVector3& scale = drawable->getScale(); + material_data.push_back(LLVector4a(scale.mV[0], scale.mV[1], scale.mV[2], 0.f)); + + drawable->mTransformIndex = transform_index; + drawable->mPrimScaleIndex = prim_scale_index; + + LLVolume* volume = drawable->getVOVolume()->getVolume(); + volume->createVertexBuffer(); + + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* facep = drawable->getFace(i); + facep->mGLTFDrawInfo.clear(); + + if (!volume || volume->getNumVolumeFaces() != drawable->getNumFaces()) + { // volume is not yet loaded + continue; + } + + LLVolumeFace& vf = volume->getVolumeFace(i); + + if (vf.mVertexBuffer.isNull()) + { + continue; + } + + mVertexBuffers.push_back(vf.mVertexBuffer); + + facep->updateBatchHash(); + + if (facep->mBatchHash == 0) + { // don't render faces that are completely transparent (or otherwise irrelevant) + continue; + } + + if (facep->isState(LLFace::RIGGED) && facep->getSkinHash() != 0) + { + transforms[transforms.size() - 1] = &facep->mSkinInfo->mBindShapeMatrix.mMatrix4; + } + + + if (facep->mTextureMatrix != nullptr) + { + texture_transforms.push_back(facep->mTextureMatrix); + facep->mTextureTransformIndex = (U32)texture_transforms.size() - 1; + } + else + { + facep->mTextureTransformIndex = 0xFFFFFFFF; + } + + LLGLTFMaterial* gltf_mat = facep->getTextureEntry()->getGLTFRenderMaterial(); + + U32 mat_idx = U32(material_data.size()); + + const auto& iter = materials.find(facep->mBatchHash); + if (iter == materials.end()) + { + materials[facep->mBatchHash] = mat_idx; + facep->packMaterialOnto(material_data); + } + else + { + mat_idx = iter->second; + } + + if (gltf_mat) + { + faces.push_back(facep); + } + else + { + bp_faces.push_back(facep); + } + + if (shadows && facep->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE) + { + shadow_faces.push_back(facep); + } + + facep->mMaterialIndex = mat_idx; + } + } + } + + struct InstanceMapEntry + { + U32 transform_index; + U32 material_index; + U32 texture_transform_index; + U32 prim_scale_index; + }; + + U32 transform_ubo_size = (U32)(transforms.size() * 12 * sizeof(F32)); + U32 instance_map_ubo_size = (U32)(faces.size() * sizeof(InstanceMapEntry)); + U32 material_ubo_size = (U32) (material_data.size() * sizeof(LLVector4a)); + U32 bp_instance_map_ubo_size = (U32) bp_faces.size()*sizeof(InstanceMapEntry); + U32 texture_transform_ubo_size = (U32)(texture_transforms.size() * 12 * sizeof(F32)); + U32 shadow_instance_map_ubo_size = (U32)shadow_faces.size() * sizeof(InstanceMapEntry); + + auto alloc_ubo = [&](U32& ubo, bool& new_ubo, U32& new_size, U32& old_size) + { + new_ubo = new_size > old_size || new_size < old_size / 2; + + llassert((S32) new_size <= gGLManager.mMaxUniformBlockSize); + + if (new_ubo) + { + if (ubo) + { + ll_gl_delete_buffers(1, &ubo); + } + + if (new_size > 0) + { + ubo = ll_gl_gen_buffer(); + } + else + { + ubo = 0; + } + } + + }; + + bool new_transform_ubo; + bool new_instance_map_ubo; + bool new_material_ubo; + bool new_texture_transform_ubo; + bool new_bp_instance_map_ubo; + bool new_shadow_instance_map_ubo; + + alloc_ubo(mTransformUBO, new_transform_ubo, transform_ubo_size, mTransformUBOSize); + alloc_ubo(mInstanceMapUBO, new_instance_map_ubo, instance_map_ubo_size, mInstanceMapUBOSize); + alloc_ubo(mMaterialUBO, new_material_ubo, material_ubo_size, mMaterialUBOSize); + alloc_ubo(mBPInstanceMapUBO, new_bp_instance_map_ubo, bp_instance_map_ubo_size, mBPInstanceMapUBOSize); + alloc_ubo(mTextureTransformUBO, new_texture_transform_ubo, texture_transform_ubo_size, mTextureTransformUBOSize); + alloc_ubo(mShadowInstanceMapUBO, new_shadow_instance_map_ubo, shadow_instance_map_ubo_size, mShadowInstanceMapUBOSize); + + if (mTransformUBO != 0 && transform_ubo_size > 0) + { + struct InstanceSort + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { // order such that faces with the same vertex buffer, index offset, and material are adjacent + + LLVolumeFace& lhs_vf = lhs->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(lhs->getTEOffset()); + LLVolumeFace& rhs_vf = rhs->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(rhs->getTEOffset()); + + size_t rhs_hash = rhs->mBatchHash; + size_t lhs_hash = lhs->mBatchHash; + + if (lhs_hash != rhs_hash) + { + if (lhs->mAlphaMode != rhs->mAlphaMode) + { //ensure that materials of a given alpha mode are adjacent in the list + return lhs->mAlphaMode < rhs->mAlphaMode; + } + else + { + return lhs_hash < rhs_hash; + } + } + else if (lhs_vf.mVertexBuffer != rhs_vf.mVertexBuffer) + { + return lhs_vf.mVertexBuffer < rhs_vf.mVertexBuffer; + } + else + { + return lhs_vf.mVBIndexOffset < rhs_vf.mVBIndexOffset; + } + } + }; + + struct ShadowInstanceSort + { + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { // Same as InstanceSort, but ignore material + + LLVolumeFace& lhs_vf = lhs->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(lhs->getTEOffset()); + LLVolumeFace& rhs_vf = rhs->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(rhs->getTEOffset()); + + if (lhs_vf.mVertexBuffer != rhs_vf.mVertexBuffer) + { + return lhs_vf.mVertexBuffer < rhs_vf.mVertexBuffer; + } + else + { + return lhs_vf.mVBIndexOffset < rhs_vf.mVBIndexOffset; + } + } + }; + + static std::vector instance_map; + instance_map.resize(faces.size()); + + { + LL_PROFILE_ZONE_NAMED("utubo - build instances"); + std::sort(faces.begin(), faces.end(), InstanceSort()); + + LLVOAvatar* avatar = nullptr; + U64 skin_hash = 0; + bool planar = false; + bool cur_tex_anim = false; + + LLGLTFDrawInfo* current_info = nullptr; + LLGLTFDrawInfoHandle current_handle; + + current_handle.mSpatialGroup = this; + + for (U32 i = 0; i < faces.size(); ++i) + { + LLFace* facep = faces[i]; + const LLTextureEntry* te = facep->getTextureEntry(); + bool face_planar = te->getTexGen() != LLTextureEntry::TEX_GEN_DEFAULT; + LLGLTFMaterial* gltf_mat = facep->getTextureEntry()->getGLTFRenderMaterial(); + LLVolumeFace& vf = facep->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(facep->getTEOffset()); + U64 current_skin_hash = facep->getSkinHash(); + LLVOAvatar* current_avatar = current_skin_hash ? facep->getDrawable()->getVObj()->getAvatar() : nullptr; + bool tex_anim = facep->mTextureMatrix != nullptr; + + instance_map[i].transform_index = facep->getDrawable()->mTransformIndex; + instance_map[i].material_index = facep->mMaterialIndex; + instance_map[i].texture_transform_index = facep->mTextureTransformIndex; + instance_map[i].prim_scale_index = facep->getDrawable()->mPrimScaleIndex; + + if (current_info && + vf.mVertexBuffer.notNull() && + current_info->mMaterialID == facep->mBatchHash && + current_info->mVBO == vf.mVertexBuffer->mGLBuffer && + current_info->mElementOffset == vf.mVBIndexOffset && + current_avatar == avatar && + current_skin_hash == skin_hash && + planar == face_planar && + tex_anim == cur_tex_anim) + { // another instance of the same LLVolumeFace and material + current_info->mInstanceCount++; + } + else + { + // a new instance + llassert(gltf_mat->mAlphaMode >= 0 && gltf_mat->mAlphaMode <= 2); + + LLFetchedGLTFMaterial* mat = (LLFetchedGLTFMaterial*)gltf_mat; + U8 tex_mask = 0; + + auto* basecolor = mat->mBaseColorTexture.get(); + if (basecolor) + { + tex_mask |= LLGLTFBatches::BASE_COLOR_MAP; + } + auto* normal = mat->mNormalTexture.get(); + if (normal) + { + tex_mask |= LLGLTFBatches::NORMAL_MAP; + } + auto* metallic = mat->mMetallicRoughnessTexture.get(); + if (metallic) + { + tex_mask |= LLGLTFBatches::METALLIC_ROUGHNESS_MAP; + } + auto* emissive = mat->mEmissiveTexture.get(); + if (emissive) + { + tex_mask |= LLGLTFBatches::EMISSIVE_MAP; + } + + planar = face_planar; + cur_tex_anim = tex_anim; + + if (current_skin_hash) + { + auto* info = mGLTFBatches.createSkinned(gltf_mat->mAlphaMode, tex_mask, gltf_mat->mDoubleSided, planar, tex_anim, current_handle); + current_info = info; + + info->mAvatar = current_avatar; + info->mSkinInfo = facep->mSkinInfo; + } + else + { + current_info = mGLTFBatches.create(gltf_mat->mAlphaMode, tex_mask, gltf_mat->mDoubleSided, planar, tex_anim, current_handle); + } + + avatar = current_avatar; + skin_hash = current_skin_hash; + + + // set draw info values + current_info->mMaterialID = gltf_mat->getBatchHash(); + current_info->mBaseColorMap = basecolor ? basecolor->getGLTexture()->mTexID : 0; + current_info->mNormalMap = normal ? normal->getGLTexture()->mTexID : 0; + current_info->mMetallicRoughnessMap = metallic ? metallic->getGLTexture()->mTexID : 0; + current_info->mEmissiveMap = emissive ? emissive->getGLTexture()->mTexID : 0; + + current_info->mVBO = vf.mVertexBuffer->mGLBuffer; + current_info->mIBO = vf.mVertexBuffer->mGLIndices; + current_info->mVBOVertexCount = vf.mVertexBuffer->getNumVerts(); + + current_info->mIndicesSize = vf.mVertexBuffer->mIndicesType == GL_UNSIGNED_INT ? 1 : 0; + current_info->mElementOffset = vf.mVBIndexOffset; + current_info->mElementCount = vf.mNumIndices; + current_info->mTransformUBO = mTransformUBO; + current_info->mTextureTransformUBO = mTextureTransformUBO; + current_info->mInstanceMapUBO = mInstanceMapUBO; + current_info->mMaterialUBO = mMaterialUBO; + current_info->mBaseInstance = i; + current_info->mInstanceCount = 1; + } + facep->mGLTFDrawInfo = current_handle; + llassert(facep->mGLTFDrawInfo.get() != nullptr); + + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mBaseColorMap] || glIsTexture(LLImageGL::sTexNames[current_info->mBaseColorMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mNormalMap] || glIsTexture(LLImageGL::sTexNames[current_info->mNormalMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mMetallicRoughnessMap] || glIsTexture(LLImageGL::sTexNames[current_info->mMetallicRoughnessMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mEmissiveMap] || glIsTexture(LLImageGL::sTexNames[current_info->mEmissiveMap])); + } + } + + static std::vector bp_instance_map; + bp_instance_map.resize(bp_faces.size()); + + { + std::sort(bp_faces.begin(), bp_faces.end(), InstanceSort()); + + LLVOAvatar* avatar = nullptr; + U64 skin_hash = 0; + bool planar = false; + bool cur_tex_anim = false; + bool cur_normal_map = false; + LLGLTFDrawInfo* current_info = nullptr; + LLGLTFDrawInfoHandle current_handle; + current_handle.mSpatialGroup = this; + + for (U32 i = 0; i < bp_faces.size(); ++i) + { + LLFace* facep = bp_faces[i]; + const LLTextureEntry* te = facep->getTextureEntry(); + bool face_planar = te->getTexGen() != LLTextureEntry::TEX_GEN_DEFAULT; + LLVolumeFace& vf = facep->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(facep->getTEOffset()); + U64 current_skin_hash = facep->getSkinHash(); + LLVOAvatar* current_avatar = current_skin_hash ? facep->getDrawable()->getVObj()->getAvatar() : nullptr; + + bool tex_anim = facep->mTextureMatrix != nullptr; + + static LLCachedControl norm_map_enabled(gSavedSettings, "RenderNormalMapsEnabled"); + bool normal_map = norm_map_enabled && facep->getTexture(LLRender::NORMAL_MAP) != nullptr; + + bp_instance_map[i].transform_index = facep->getDrawable()->mTransformIndex; + bp_instance_map[i].material_index = facep->mMaterialIndex; + bp_instance_map[i].texture_transform_index = facep->mTextureTransformIndex; + bp_instance_map[i].prim_scale_index = facep->getDrawable()->mPrimScaleIndex; + + if (current_info && + vf.mVertexBuffer.notNull() && + current_info->mMaterialID == facep->mBatchHash && + current_info->mVBO == vf.mVertexBuffer->mGLBuffer && + current_info->mElementOffset == vf.mVBIndexOffset && + current_avatar == avatar && + current_skin_hash == skin_hash && + planar == face_planar && + tex_anim == cur_tex_anim && + normal_map == cur_normal_map) + { // another instance of the same LLVolumeFace and material + current_info->mInstanceCount++; + } + else + { + // a new instance + llassert(facep->mAlphaMode >= 0 && facep->mAlphaMode <= 2); + U8 tex_mask = 0; + + const LLTextureEntry* te = facep->getTextureEntry(); + + LLViewerTexture* diffuse = facep->getTexture(); + if (diffuse) + { + tex_mask |= LLGLTFBatches::DIFFUSE_MAP; + } + LLViewerTexture* normal = facep->getTexture(LLRender::NORMAL_MAP); + if (normal && (te->getMaterialParams() && te->getMaterialParams()->getNormalID().isNull())) + { + tex_mask |= LLGLTFBatches::NORMAL_MAP; + } + + LLViewerTexture* specular = facep->getTexture(LLRender::SPECULAR_MAP); + if (specular) + { + tex_mask |= LLGLTFBatches::SPECULAR_MAP; + } + + planar = face_planar; + cur_tex_anim = tex_anim; + cur_normal_map = normal_map; + + if (current_skin_hash) + { + auto* info = mBPBatches.createSkinned(facep->mAlphaMode, tex_mask, false, planar, tex_anim, current_handle); + current_info = info; + + info->mAvatar = current_avatar; + info->mSkinInfo = facep->mSkinInfo; + } + else + { + current_info = mBPBatches.create(facep->mAlphaMode, tex_mask, false, planar, tex_anim, current_handle); + } + + avatar = current_avatar; + skin_hash = current_skin_hash; + + current_info->mMaterialID = facep->mBatchHash; + current_info->mDiffuseMap = diffuse ? diffuse->getGLTexture()->mTexID : 0; + current_info->mNormalMap = normal ? normal->getGLTexture()->mTexID : 0; + current_info->mSpecularMap = specular ? specular->getGLTexture()->mTexID : 0; + current_info->mEmissiveMap = 0; // not strictly necessary but helps with debugging at minimal cost + + current_info->mVBO = vf.mVertexBuffer->mGLBuffer; + current_info->mIBO = vf.mVertexBuffer->mGLIndices; + current_info->mVBOVertexCount = vf.mVertexBuffer->getNumVerts(); + + current_info->mIndicesSize = vf.mVertexBuffer->mIndicesType == GL_UNSIGNED_INT ? 1 : 0; + current_info->mElementOffset = vf.mVBIndexOffset; + current_info->mElementCount = vf.mNumIndices; + current_info->mTransformUBO = mTransformUBO; + current_info->mTextureTransformUBO = mTextureTransformUBO; + current_info->mInstanceMapUBO = mBPInstanceMapUBO; + current_info->mMaterialUBO = mMaterialUBO; + current_info->mBaseInstance = i; + current_info->mInstanceCount = 1; + } + facep->mGLTFDrawInfo = current_handle; + llassert(facep->mGLTFDrawInfo.get() != nullptr); + + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mDiffuseMap] || glIsTexture(LLImageGL::sTexNames[current_info->mDiffuseMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mNormalMap] || glIsTexture(LLImageGL::sTexNames[current_info->mNormalMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mSpecularMap] || glIsTexture(LLImageGL::sTexNames[current_info->mSpecularMap])); + } + } + + static std::vector shadow_instance_map; + shadow_instance_map.resize(shadow_faces.size()); + + { + std::sort(shadow_faces.begin(), shadow_faces.end(), ShadowInstanceSort()); + + LLVOAvatar* avatar = nullptr; + U64 skin_hash = 0; + + LLGLTFDrawInfo* current_info = nullptr; + LLGLTFDrawInfoHandle current_handle; + current_handle.mSpatialGroup = this; + + for (U32 i = 0; i < shadow_faces.size(); ++i) + { + LLFace* facep = shadow_faces[i]; + const LLTextureEntry* te = facep->getTextureEntry(); + bool face_planar = te->getTexGen() != LLTextureEntry::TEX_GEN_DEFAULT; + LLVolumeFace& vf = facep->getDrawable()->getVOVolume()->getVolume()->getVolumeFace(facep->getTEOffset()); + U64 current_skin_hash = facep->getSkinHash(); + LLVOAvatar* current_avatar = current_skin_hash ? facep->getDrawable()->getVObj()->getAvatar() : nullptr; + + shadow_instance_map[i].transform_index = facep->getDrawable()->mTransformIndex; + shadow_instance_map[i].material_index = 0; + shadow_instance_map[i].texture_transform_index = 0; + shadow_instance_map[i].prim_scale_index = 0; + + if (current_info && + vf.mVertexBuffer.notNull() && + current_info->mVBO == vf.mVertexBuffer->mGLBuffer && + current_info->mElementOffset == vf.mVBIndexOffset && + current_avatar == avatar && + current_skin_hash == skin_hash) + { // another instance of the same LLVolumeFace and material + current_info->mInstanceCount++; + } + else + { + // a new instance + llassert(facep->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE); + + if (current_skin_hash) + { + auto* info = mShadowBatches.createSkinned(facep->mAlphaMode, 0, false, 0, 0, current_handle); + current_info = info; + + info->mAvatar = current_avatar; + info->mSkinInfo = facep->mSkinInfo; + } + else + { + current_info = mShadowBatches.create(facep->mAlphaMode, 0, false, 0, 0, current_handle); + } + + avatar = current_avatar; + skin_hash = current_skin_hash; + + current_info->mMaterialID = 0; + current_info->mDiffuseMap = 0; + current_info->mNormalMap = 0; + current_info->mSpecularMap = 0; + current_info->mEmissiveMap = 0; + + current_info->mVBO = vf.mVertexBuffer->mGLBuffer; + current_info->mIBO = vf.mVertexBuffer->mGLIndices; + current_info->mVBOVertexCount = vf.mVertexBuffer->getNumVerts(); + + current_info->mIndicesSize = vf.mVertexBuffer->mIndicesType == GL_UNSIGNED_INT ? 1 : 0; + current_info->mElementOffset = vf.mVBIndexOffset; + current_info->mElementCount = vf.mNumIndices; + current_info->mTransformUBO = mTransformUBO; + current_info->mTextureTransformUBO = 0; + current_info->mInstanceMapUBO = mShadowInstanceMapUBO; + current_info->mMaterialUBO = 0; + current_info->mBaseInstance = i; + current_info->mInstanceCount = 1; + } + + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mDiffuseMap] || glIsTexture(LLImageGL::sTexNames[current_info->mDiffuseMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mNormalMap] || glIsTexture(LLImageGL::sTexNames[current_info->mNormalMap])); + llassert(!gDebugGL || !LLImageGL::sTexNames[current_info->mSpecularMap] || glIsTexture(LLImageGL::sTexNames[current_info->mSpecularMap])); + } + } + + { + STOP_GLERROR; + LL_PROFILE_ZONE_NAMED("utubo - update UBO data"); + + auto pack_transforms = [](const std::vector& src, U32 ubo, U32& old_size, U32 new_size, bool new_ubo) + { + if (ubo) + { + static std::vector glmp; + glmp.resize(src.size() * 12); + + F32* mp = glmp.data(); + + for (U32 i = 0; i < src.size(); ++i) + { + U32 idx = i * 12; + + pack_transform(*src[i], mp + idx); + } + + STOP_GLERROR; + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + size_t data_size = glmp.size() * sizeof(F32); + + if (new_ubo) + { + old_size = new_size; + llassert(data_size <= old_size); + glBufferData(GL_UNIFORM_BUFFER, data_size, glmp.data(), GL_DYNAMIC_DRAW); + } + else + { + llassert(data_size <= old_size); + glBufferSubData(GL_UNIFORM_BUFFER, 0, data_size, glmp.data()); + } + STOP_GLERROR; + } + }; + + pack_transforms(transforms, mTransformUBO, mTransformUBOSize, transform_ubo_size, new_transform_ubo); + pack_transforms(texture_transforms, mTextureTransformUBO, mTextureTransformUBOSize, texture_transform_ubo_size, new_texture_transform_ubo); + + auto pack_ubo = [&](U32 ubo, bool new_ubo, U32 new_size, U32& old_size, void* data) + { + if (ubo) + { + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + size_t data_size = new_size; + + if (new_ubo) + { + old_size = new_size; + llassert(data_size <= old_size); + glBufferData(GL_UNIFORM_BUFFER, data_size, data, GL_DYNAMIC_DRAW); + } + else + { + llassert(data_size <= old_size); + glBufferSubData(GL_UNIFORM_BUFFER, 0, data_size, data); + } + STOP_GLERROR; + } + }; + + pack_ubo(mInstanceMapUBO, new_instance_map_ubo, instance_map_ubo_size, mInstanceMapUBOSize, instance_map.data()); + pack_ubo(mMaterialUBO, new_material_ubo, material_ubo_size, mMaterialUBOSize, material_data.data()); + pack_ubo(mBPInstanceMapUBO, new_bp_instance_map_ubo, bp_instance_map_ubo_size, mBPInstanceMapUBOSize, bp_instance_map.data()); + pack_ubo(mShadowInstanceMapUBO, new_shadow_instance_map_ubo, shadow_instance_map_ubo_size, mShadowInstanceMapUBOSize, shadow_instance_map.data()); + } + } + + STOP_GLERROR; +} + +void LLSpatialGroup::updateTransform(LLDrawable* drawablep) +{ + LL_PROFILE_ZONE_SCOPED; + if (!drawablep->isState(LLDrawable::RIGGED) && + getSpatialPartition()->mDrawableType == LLPipeline::RENDER_TYPE_VOLUME && + !hasState(LLSpatialGroup::IN_TRANSFORM_BUILD_Q)) + { + U32 offset = drawablep->mTransformIndex * 3 * sizeof(LLVector4a); + + if (drawablep->mTransformIndex == 0xFFFFFFFF || + (offset + 3 * sizeof(LLVector4a)) > mTransformUBOSize) + { + // slow path, schedule a full rebuild of UBOs + gPipeline.markTransformDirty(this); + } + else + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("updateTransform -- pack ubo"); + + // fast path, just update the transform for this drawable + F32 mat[12]; + + if (getSpatialPartition()->asBridge()) + { + if (getSpatialPartition()->asBridge()->mDrawable == drawablep) + { + pack_transform(drawablep->getRenderMatrix(), mat); + // root transform has updated, update root transform for all spatial groups in this partition + class UpdateTransform : public OctreeTraveler + { + public: + LLDrawable* mDrawable; + F32* mMat; + UpdateTransform(LLDrawable* drawable, F32* mat) : mDrawable(drawable), mMat(mat) {} + + virtual void visit(const OctreeNode* branch) + { + LLSpatialGroup* group = (LLSpatialGroup*)branch->getListener(0); + if (group && group->mTransformUBO && group->mTransformUBOSize > 12 * sizeof(F32)) + { + glBindBuffer(GL_UNIFORM_BUFFER, group->mTransformUBO); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(F32) * 12, mMat); + } + } + }; + + UpdateTransform ut(drawablep, mat); + + ut.traverse(getSpatialPartition()->mOctree); + + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } + else + { + pack_transform(drawablep->getGLTFRenderMatrix(), mat); + // just update the transform for this drawable + glBindBuffer(GL_UNIFORM_BUFFER, mTransformUBO); + glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(F32) * 12, mat); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } + } +} + + void LLSpatialGroup::destroyGLState(bool keep_occlusion) { setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); @@ -3453,6 +4304,36 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera) pusher.traverse(mOctree); } + +// asserts that the given texname isn't referenced +class LLOctreeTexNameCheck : public OctreeTraveler +{ +public: + U32 mTexName = 0; + + LLOctreeTexNameCheck(U32 texname) + { + mTexName = texname; + } + + virtual void visit(const OctreeNode* node) + { + LLSpatialGroup* group = (LLSpatialGroup*)node->getListener(0); + + group->mGLTFBatches.texNameCheck(mTexName); + group->mBPBatches.texNameCheck(mTexName); + } +}; + +void LLSpatialPartition::checkTexNameReferences(U32 texname) +{ + if (gDebugGL) + { + LLOctreeTexNameCheck check(texname); + check.traverse(mOctree); + } +} + class LLOctreeStateCheck : public OctreeTraveler { public: @@ -3868,10 +4749,9 @@ LLColor4U LLDrawInfo::getDebugColor() const { LLColor4U color; - LLCRC hash; - hash.update((U8*)this + sizeof(S32), sizeof(LLDrawInfo) - sizeof(S32)); - - *((U32*) color.mV) = hash.getCRC(); + // take last 4 bytes of pointer as color + U64 ptr = (U64)this; + *((U32*)color.mV) = (U32)ptr; color.mV[3] = 200; @@ -3888,6 +4768,7 @@ U64 LLDrawInfo::getSkinHash() return mSkinInfo ? mSkinInfo->mHash : 0; } + LLCullResult::LLCullResult() { mVisibleGroupsAllocated = 0; @@ -3962,6 +4843,9 @@ void LLCullResult::clear() mVisibleBridgeSize = 0; mVisibleBridgeEnd = &mVisibleBridge[0]; + mGLTFBatches.clear(); + mBPBatches.clear(); + mShadowBatches.clear(); for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) { diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 016ebff8270..b2f0a5bbf81 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -42,6 +42,7 @@ #include "llvector4a.h" #include "llvoavatar.h" #include "llfetchedgltfmaterial.h" +#include "llgltfdrawinfo.h" #include #include @@ -82,7 +83,7 @@ class LLDrawInfo final : public LLRefCount return *this; } - // return a hash of this LLDrawInfo as a debug color + // return a hash of this LLDrawInfo address as a debug color LLColor4U getDebugColor() const; LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, @@ -101,6 +102,10 @@ class LLDrawInfo final : public LLRefCount U32 mCount = 0; U32 mOffset = 0; + // UBO and index for transform data + U32 mTransformUBO = 0; + S32 mTransformIndex = -1; + LLPointer mTexture; LLPointer mSpecularMap; LLPointer mNormalMap; @@ -123,7 +128,7 @@ class LLDrawInfo final : public LLRefCount std::vector > mTextureList; - LLUUID mMaterialHash; // hash of LLGLTFMaterial or LLMaterial applied to this draw info + size_t mMaterialID; // result of getBatchHash of LLGLTFMaterial or LLMaterial (plus diffuse texture id) applied to this draw info U32 mShaderMask = 0; F32 mEnvIntensity = 0.f; @@ -196,8 +201,31 @@ class LLDrawInfo final : public LLRefCount && (lhs.isNull() || (rhs.notNull() && lhs->mBump > rhs->mBump)); } }; + + struct CompareMaterialID + { + bool operator()(const LLDrawInfo* lhs, const LLDrawInfo* rhs) + { + // sort by mMaterialID, lhs and rhs must never be null + // DO NOT ADD NULL CHECKS HERE, this is a performance critical path + // If you suspect a null dereference here, add assertions around insertions to the container + // that uses this comparator + return lhs->mMaterialID < rhs->mMaterialID; + } + }; + + struct InstanceSort + { + bool operator()(const LLDrawInfo* lhs, const LLDrawInfo* rhs) + { + // sort by mMaterialID first, vertex buffer second + return lhs->mMaterialID < rhs->mMaterialID || + lhs->mVertexBuffer < rhs->mVertexBuffer; + } + }; }; + LL_ALIGN_PREFIX(16) class LLSpatialGroup : public LLOcclusionCullingGroup { @@ -274,6 +302,8 @@ class LLSpatialGroup : public LLOcclusionCullingGroup MESH_DIRTY = (IMAGE_DIRTY << 1), IN_BUILD_Q1 = (MESH_DIRTY << 1), IN_BUILD_Q2 = (IN_BUILD_Q1 << 1), + HAS_GLTF = (IN_BUILD_Q2 << 1), + IN_TRANSFORM_BUILD_Q = (HAS_GLTF << 1), STATE_MASK = 0x0000FFFF, } eSpatialState; @@ -336,6 +366,12 @@ class LLSpatialGroup : public LLOcclusionCullingGroup // LLViewerOctreeGroup virtual void rebound(); + // Update UBOs + void updateTransformUBOs(); + + // update the transform UBO for a single drawable + void updateTransform(LLDrawable* drawablep); + public: LL_ALIGN_16(LLVector4a mViewAngle); LL_ALIGN_16(LLVector4a mLastUpdateViewAngle); @@ -347,6 +383,14 @@ class LLSpatialGroup : public LLOcclusionCullingGroup LLPointer mVertexBuffer; draw_map_t mDrawMap; + LLGLTFBatches mGLTFBatches; + LLGLTFBatches mBPBatches; + LLGLTFBatches mShadowBatches; + + // references to vertex buffers that are in use (avoid deletion while in use) + std::vector> mVertexBuffers; + + bridge_list_t mBridgeList; buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers @@ -366,6 +410,38 @@ class LLSpatialGroup : public LLOcclusionCullingGroup //used by LLVOAVatar to set render order in alpha draw pool to preserve legacy render order behavior LLVOAvatar* mAvatarp = nullptr; U32 mRenderOrder = 0; + + // UBO for transform data + // One transform for each Drawable, indexed by gltf_node_id in the shader + U32 mTransformUBO = 0; + U32 mTransformUBOSize = 0; + // UBO for instance map + // Indexed by instance id + base instance + // stores gltf_node_id and material_id + U32 mInstanceMapUBO = 0; + U32 mInstanceMapUBOSize = 0; + // UBO for materials + // Indexed by material_id + U32 mMaterialUBO = 0; + U32 mMaterialUBOSize = 0; + + // UBO for blinn-phong instance map + U32 mBPInstanceMapUBO = 0; + U32 mBPInstanceMapUBOSize = 0; + + // UBO for shadow instance map + U32 mShadowInstanceMapUBO = 0; + U32 mShadowInstanceMapUBOSize = 0; + + // UBO for prim scales + // Used for planar projection, indexed by gltf_node_id + U32 mPrimScaleUBO = 0; + U32 mPrimScaleUBOSize = 0; + + // UBO used for texture animation transforms + U32 mTextureTransformUBO = 0; + U32 mTextureTransformUBOSize = 0; + // Reflection Probe associated with this node (if any) LLPointer mReflectionProbe = nullptr; } LL_ALIGN_POSTFIX(16); @@ -430,6 +506,7 @@ class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManag bool getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax); + void checkTexNameReferences(U32 texname); public: LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this // use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe @@ -484,6 +561,8 @@ class LLCullResult typedef std::vector drawable_list_t; typedef std::vector bridge_list_t; typedef std::vector drawinfo_list_t; + typedef std::vector gltf_drawinfo_list_t; + typedef std::vector skinned_gltf_drawinfo_list_t; typedef LLSpatialGroup** sg_iterator; typedef LLSpatialBridge** bridge_iterator; @@ -553,6 +632,15 @@ class LLCullResult void assertDrawMapsEmpty(); + // list of GLTF draw infos + LLGLTFBatches mGLTFBatches; + + // list of blinn-phong draw infos + LLGLTFBatches mBPBatches; + + // list of shadow draw infos + LLGLTFBatches mShadowBatches; + private: template void pushBack(T &head, U32& count, V* val); @@ -592,7 +680,6 @@ class LLCullResult drawinfo_list_t mRenderMap[LLRenderPass::NUM_RENDER_TYPES]; U32 mRenderMapAllocated[LLRenderPass::NUM_RENDER_TYPES]; drawinfo_iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES]; - }; @@ -677,22 +764,6 @@ class LLVolumeGeometryManager: public LLGeometryManager virtual void rebuildMesh(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); virtual void addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count); - U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, bool distance_sort = false, bool batch_textures = false, bool rigged = false); - void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); - -private: - void allocateFaces(U32 pMaxFaceCount); - void freeFaces(); - - static int32_t sInstanceCount; - static LLFace** sFullbrightFaces[2]; - static LLFace** sBumpFaces[2]; - static LLFace** sSimpleFaces[2]; - static LLFace** sNormFaces[2]; - static LLFace** sSpecFaces[2]; - static LLFace** sNormSpecFaces[2]; - static LLFace** sPbrFaces[2]; - static LLFace** sAlphaFaces[2]; }; //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index dd8c6d989ed..b6977ecac11 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -333,6 +333,7 @@ void set_flags_and_update_appearance() // in non-thread-safe classes, post to main loop auto work = []() { + LL_PROFILE_ZONE_NAMED("set_flags_and_update_appearance"); LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index bda53f66eb8..fd99604a596 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -312,7 +312,7 @@ void LLTextureBar::draw() last_event = mImagep->getTimePassedSinceLastBound(); if (last_event < 1.f) { - clr = mImagep->getMissed() ? LLColor4::red : LLColor4::magenta1; + clr = LLColor4::magenta1; clr.setAlpha(1.f - last_event); gGL.color4fv(clr.mV); gl_rect_2d(pip_x, top, pip_x + pip_width, bottom); @@ -526,7 +526,7 @@ void LLGLTexMemBar::draw() F64 saved_raw_image_bytes_MB = saved_raw_image_bytes / (1024.0 * 1024.0); F64 aux_raw_image_bytes_MB = aux_raw_image_bytes / (1024.0 * 1024.0); F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0; - F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 512.0; + F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 1024.0; F64 render_bytes_alloc = LLRenderTarget::sBytesAllocated / 1024.0 / 512.0; //---------------------------------------------------------------------------- diff --git a/indra/newview/lltoolcomp.h b/indra/newview/lltoolcomp.h index 4b945967d16..d456c280f46 100644 --- a/indra/newview/lltoolcomp.h +++ b/indra/newview/lltoolcomp.h @@ -101,11 +101,11 @@ class LLToolComposite : public LLTool //----------------------------------------------------------------------- // LLToolCompTranslate -class LLToolCompInspect : public LLToolComposite, public LLSingleton +class LLToolCompInspect : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompInspect); - virtual ~LLToolCompInspect(); public: + LLToolCompInspect(); + virtual ~LLToolCompInspect(); // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -126,11 +126,11 @@ class LLToolCompInspect : public LLToolComposite, public LLSingleton +class LLToolCompTranslate : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompTranslate); - virtual ~LLToolCompTranslate(); public: + LLToolCompTranslate(); + virtual ~LLToolCompTranslate(); // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -147,11 +147,11 @@ class LLToolCompTranslate : public LLToolComposite, public LLSingleton +class LLToolCompScale : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompScale); - virtual ~LLToolCompScale(); public: + LLToolCompScale(); + virtual ~LLToolCompScale(); // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -169,11 +169,12 @@ class LLToolCompScale : public LLToolComposite, public LLSingleton +class LLToolCompRotate : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompRotate); - virtual ~LLToolCompRotate(); public: + LLToolCompRotate(); + virtual ~LLToolCompRotate(); + // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -192,11 +193,11 @@ class LLToolCompRotate : public LLToolComposite, public LLSingleton +class LLToolCompCreate : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompCreate); - virtual ~LLToolCompCreate(); public: + LLToolCompCreate(); + virtual ~LLToolCompCreate(); // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -217,11 +218,11 @@ class LLToolGun; class LLToolGrabBase; class LLToolSelect; -class LLToolCompGun : public LLToolComposite, public LLSingleton +class LLToolCompGun : public LLToolComposite, public LLSimpleton { - LLSINGLETON(LLToolCompGun); - virtual ~LLToolCompGun(); public: + LLToolCompGun(); + virtual ~LLToolCompGun(); // Overridden from LLToolComposite virtual bool handleHover(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolface.h b/indra/newview/lltoolface.h index 18d42da1e1e..4320b157655 100644 --- a/indra/newview/lltoolface.h +++ b/indra/newview/lltoolface.h @@ -33,11 +33,11 @@ class LLViewerObject; class LLPickInfo; class LLToolFace -: public LLTool, public LLSingleton +: public LLTool, public LLSimpleton { - LLSINGLETON(LLToolFace); - virtual ~LLToolFace(); public: + LLToolFace(); + virtual ~LLToolFace(); virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolindividual.h b/indra/newview/lltoolindividual.h index baf687d183d..6ed74ea607b 100644 --- a/indra/newview/lltoolindividual.h +++ b/indra/newview/lltoolindividual.h @@ -37,12 +37,11 @@ class LLPickInfo; // A tool to select individual objects rather than linked sets. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLToolIndividual : public LLTool, public LLSingleton +class LLToolIndividual : public LLTool, public LLSimpleton { - LLSINGLETON(LLToolIndividual); - virtual ~LLToolIndividual(); public: - + LLToolIndividual(); + virtual ~LLToolIndividual(); virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override; virtual void handleSelect() override; diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 6cfdbaac06e..10e480f61bc 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -40,11 +40,11 @@ const MASK MASK_ORBIT = MASK_CONTROL; const MASK MASK_PAN = MASK_CONTROL | MASK_SHIFT; const MASK MASK_COPY = MASK_SHIFT; -class LLToolMgr : public LLSingleton +class LLToolMgr : public LLSimpleton { - LLSINGLETON(LLToolMgr); - ~LLToolMgr(); public: + LLToolMgr(); + virtual ~LLToolMgr(); // Must be called after gSavedSettings set up. void initTools(); diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h index 0f1574f2d53..7b06e4cbcdd 100644 --- a/indra/newview/lltoolpipette.h +++ b/indra/newview/lltoolpipette.h @@ -41,12 +41,12 @@ class LLViewerObject; class LLPickInfo; class LLToolPipette -: public LLTool, public LLSingleton +: public LLTool, public LLSimpleton { - LLSINGLETON(LLToolPipette); +public: + LLToolPipette(); virtual ~LLToolPipette(); -public: virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override; virtual bool handleHover(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolselectland.h b/indra/newview/lltoolselectland.h index 15672aa7d4e..10c39ca122d 100644 --- a/indra/newview/lltoolselectland.h +++ b/indra/newview/lltoolselectland.h @@ -33,12 +33,12 @@ class LLParcelSelection; class LLToolSelectLand -: public LLTool, public LLSingleton +: public LLTool, public LLSimpleton { - LLSINGLETON(LLToolSelectLand); +public: + LLToolSelectLand(); virtual ~LLToolSelectLand(); -public: /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) override; /*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask) override; /*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index b3b4f43e57c..87718dd411f 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -257,6 +257,7 @@ void LLViewerAudio::startFading() F32 LLViewerAudio::getFadeVolume() { + LL_PROFILE_ZONE_SCOPED; F32 fade_volume = 1.0f; if (stream_fade_timer.hasExpired()) @@ -397,6 +398,7 @@ void init_audio() void audio_update_volume(bool force_update) { + LL_PROFILE_ZONE_SCOPED; F32 master_volume = gSavedSettings.getF32("AudioLevelMaster"); bool mute_audio = gSavedSettings.getBOOL("MuteAudio"); @@ -417,7 +419,7 @@ void audio_update_volume(bool force_update) if (gAudiop) { // Sound Effects - + LL_PROFILE_ZONE_NAMED("Sound Effects"); gAudiop->setMasterGain ( master_volume ); const F32 AUDIO_LEVEL_DOPPLER = 1.f; @@ -500,6 +502,7 @@ void audio_update_volume(bool force_update) void audio_update_listener() { + LL_PROFILE_ZONE_SCOPED; if (gAudiop) { // update listener position because agent has moved @@ -531,6 +534,7 @@ void audio_update_listener() void audio_update_wind(bool force_update) { + LL_PROFILE_ZONE_SCOPED; #ifdef kAUDIO_ENABLE_WIND LLViewerRegion* region = gAgent.getRegion(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index e9e231db596..d11b548e134 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -212,7 +212,6 @@ bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { if (gPipeline.isInit()) { - gPipeline.updateRenderTransparentWater(); gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); LLViewerShaderMgr::instance()->setShaders(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 94ebca77e21..f85c76b7d1c 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -86,6 +86,7 @@ #include "llvograss.h" #include "llworld.h" #include "pipeline.h" +#include "glworkqueue.h" #include @@ -410,6 +411,13 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering. + // execute idle callbacks + // some of these invoke OpenGL commands, so call from display() instead of idle() + { + LL_PROFILE_ZONE_NAMED("Idle Callbacks"); + gIdleCallbacks.callFunctions(); + } + if (gWindowResized) { //skip render on frames where window has been resized LL_DEBUGS("Window") << "Resizing window" << LL_ENDL; @@ -550,14 +558,6 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) return; } - - if (gShaderProfileFrame) - { - LLGLSLShader::initProfile(); - } - - //LLGLState::verify(false); - ///////////////////////////////////////////////// // // Update GL Texture statistics (used for discard logic?) @@ -708,6 +708,9 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) { // Render mirrors and associated hero probes before we render the rest of the scene. // This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it. + + gPipeline.mReflectionMapManager.update(); + if (gPipeline.RenderMirrors && !gSnapshot) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes"); @@ -830,42 +833,13 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) glClear(GL_DEPTH_BUFFER_BIT); } - ////////////////////////////////////// - // - // Update images, using the image stats generated during object update/culling - // - // Can put objects onto the retextured list. - // - // Doing this here gives hardware occlusion queries extra time to complete - LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); - { - LL_PROFILE_ZONE_NAMED("Update Images"); - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Class"); - LLViewerTexture::updateClass(); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Image Update Bump"); - gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("List"); - F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds.value(); // 50 ms/second decode time - max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) - gTextureList.updateImages(max_image_decode_time); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("GLTF Materials Cleanup"); - //remove dead gltf materials - gGLTFMaterialList.flushMaterials(); - } + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Image Update Bump"); + gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. } + gTextureList.updateGL(); + LLGLState::checkStates(); /////////////////////////////////// @@ -995,29 +969,6 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - static LLCachedControl render_depth_pre_pass(gSavedSettings, "RenderDepthPrePass", false); - if (render_depth_pre_pass) - { - gGL.setColorMask(false, false); - - constexpr U32 types[] = { - LLRenderPass::PASS_SIMPLE, - LLRenderPass::PASS_FULLBRIGHT, - LLRenderPass::PASS_SHINY - }; - - U32 num_types = LL_ARRAY_SIZE(types); - gOcclusionProgram.bind(); - for (U32 i = 0; i < num_types; i++) - { - gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, false); - } - - gOcclusionProgram.unbind(); - - } - - gGL.setColorMask(true, true); gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true); } @@ -1072,7 +1023,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot) gShiftFrame = false; - if (gShaderProfileFrame) + if (LLGLSLShader::sProfileEnabled) { gShaderProfileFrame = false; boost::json::value stats{ boost::json::object_kind }; @@ -1556,16 +1507,39 @@ void render_ui(F32 zoom_factor, int subfield) } } + + void swap() { - LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU - LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Swap"); - LL_PROFILE_GPU_ZONE("swap"); - if (gDisplaySwapBuffers) + static LL::GLThreadSync sync; + + bool threaded = LL::GLThreadPool::instanceExists() && (LLStartUp::getStartupState() == STATE_STARTED); + + if (threaded) + { // post idle to worker thread + sync.reset(); + LL::GLThreadPool::getInstance()->post([&] + { + LL::GLThreadSync::Guard guard(sync); + LLAppViewer::instance()->idle(); + }); + } + { - gViewerWindow->getWindow()->swapBuffers(); + LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_SWAP); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Swap"); + LL_PROFILE_GPU_ZONE("swap"); + if (gDisplaySwapBuffers) + { + gViewerWindow->getWindow()->swapBuffers(); + } + gDisplaySwapBuffers = true; + } + + if (threaded) + { // wait for idle to complete + sync.wait(); } - gDisplaySwapBuffers = true; } void renderCoordinateAxes() diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9633e54f29f..cb9754f55f1 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -452,6 +452,7 @@ bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMedia::setVolume(F32 volume) { + LL_PROFILE_ZONE_SCOPED; if(volume != sGlobalVolume || sForceUpdate) { sGlobalVolume = volume; @@ -1259,6 +1260,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) { LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLViewerMedia::getOpenIDCookieCoro::postToMainCoro"); LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents"); if (media_instance) { @@ -2682,6 +2684,7 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url) ref(); LLAppViewer::instance()->postToMainCoro([this]() { + LL_PROFILE_ZONE_NAMED("LLViewerMediaImpl::mimeDiscoveryCoro::loadURI"); loadURI(); unref(); }); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index bfab0c54b43..f2a42ada4bf 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -849,6 +849,10 @@ U32 render_type_from_string(std::string_view render_type) { return LLPipeline::RENDER_TYPE_GLTF_PBR; } + else if ("pbr alpha mask" == render_type) + { + return LLPipeline::RENDER_TYPE_GLTF_PBR_ALPHA_MASK; + } else { return 0; @@ -1102,6 +1106,10 @@ U64 info_display_from_string(std::string_view info_display) { return LLPipeline::RENDER_DEBUG_BATCH_SIZE; } + else if ("shadow batches" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHADOW_BATCH_SIZE; + } else if ("update type" == info_display) { return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 84a97f9d25c..01da14f6553 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5226,6 +5226,7 @@ void LLViewerObject::setTE(const U8 te, const LLTextureEntry& texture_entry) void LLViewerObject::updateTEMaterialTextures(U8 te) { + LL_PROFILE_ZONE_SCOPED; if (getTE(te)->getMaterialParams().notNull()) { const LLUUID& norm_id = getTE(te)->getMaterialParams()->getNormalID(); @@ -7193,8 +7194,11 @@ void LLViewerObject::dirtySpatialGroup() const { group->dirtyGeom(); gPipeline.markRebuild(group); + gPipeline.markTransformDirty(group); } } + + } void LLViewerObject::dirtyMesh() diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 7d68a57eb70..03ce3e5fc1c 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -942,12 +942,6 @@ void LLViewerObjectList::update(LLAgent &agent) //update flexible objects LLVolumeImplFlexible::updateClass(); - - //update animated textures - if (gAnimateTextures) - { - LLViewerTextureAnim::updateClass(); - } } @@ -1018,6 +1012,16 @@ void LLViewerObjectList::update(LLAgent &agent) sample(LLStatViewer::NUM_ACTIVE_OBJECTS, idle_count); } +void LLViewerObjectList::updateGL() +{ + LL_PROFILE_ZONE_SCOPED; + //update animated textures + if (gAnimateTextures) + { + LLViewerTextureAnim::updateClass(); + } +} + void LLViewerObjectList::fetchObjectCosts() { // issue http request for stale object physics costs diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index dc31995eb1a..d3ded6c69d3 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -88,8 +88,13 @@ class LLViewerObjectList void processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type); void processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type); void updateApparentAngles(LLAgent &agent); + + // update called from idle thread void update(LLAgent &agent); + // update called from GL thread + void updateGL(); + void fetchObjectCosts(); void fetchPhysicsFlags(); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index b1673d2232e..56b13791137 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1303,8 +1303,8 @@ LLViewerOctreePartition::LLViewerOctreePartition() : mRegionp(NULL), mOcclusionEnabled(true), mDrawableType(0), - mLODSeed(0), - mLODPeriod(1) + mLODSeed(rand()), + mLODPeriod(16) { LLVector4a center, size; center.splat(0.f); diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 5b26f9f031d..0fb9d0ed6f4 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -81,12 +81,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_ } // Create a texture to hold color information. - // 4 components - // Use mipmaps = false, clamped, NEAREST filter, for sharp edges mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS); - mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), false); - mTexture->setAddressMode(LLTexUnit::TAM_CLAMP); - mTexture->setFilteringOption(LLTexUnit::TFO_POINT); // // Initialize the GL texture with empty data. @@ -98,7 +93,6 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_ { raw[i] = 0; } - //mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge); // Create storage for ownership information from simulator // and initialize it. @@ -653,6 +647,15 @@ void LLViewerParcelOverlay::setDirty() void LLViewerParcelOverlay::updateGL() { LL_PROFILE_ZONE_SCOPED; + + if (mTexture.isNull()) + { + mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), false); + // Use mipmaps = false, clamped, NEAREST filter, for sharp edges + mTexture->setAddressMode(LLTexUnit::TAM_CLAMP); + mTexture->setFilteringOption(LLTexUnit::TFO_POINT); + } + updateOverlayTexture(); } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 109e4e54f2e..f15039d4a46 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2455,6 +2455,7 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) auto work = [=]() { + LL_PROFILE_ZONE_NAMED("SimulatorFeatures"); // if region has MaxTextureResolution, set max_texture_dimension settings, otherwise use default if (features.has("MaxTextureResolution")) { diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 36bc0aa6470..5735815c95b 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -169,7 +169,6 @@ LLGLSLShader gDeferredSkinnedShadowProgram; LLGLSLShader gDeferredShadowCubeProgram; LLGLSLShader gDeferredShadowAlphaMaskProgram; LLGLSLShader gDeferredSkinnedShadowAlphaMaskProgram; -LLGLSLShader gDeferredShadowGLTFAlphaMaskProgram; LLGLSLShader gDeferredSkinnedShadowGLTFAlphaMaskProgram; LLGLSLShader gDeferredShadowGLTFAlphaBlendProgram; LLGLSLShader gDeferredSkinnedShadowGLTFAlphaBlendProgram; @@ -228,16 +227,17 @@ LLGLSLShader gNormalMapGenProgram; LLGLSLShader gDeferredGenBrdfLutProgram; LLGLSLShader gDeferredBufferVisualProgram; + + // Deferred materials shaders -LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; LLGLSLShader gHUDPBROpaqueProgram; +LLGLSLShader gHUDPBRAlphaProgram; LLGLSLShader gPBRGlowProgram; LLGLSLShader gPBRGlowSkinnedProgram; -LLGLSLShader gDeferredPBROpaqueProgram; -LLGLSLShader gDeferredSkinnedPBROpaqueProgram; -LLGLSLShader gHUDPBRAlphaProgram; -LLGLSLShader gDeferredPBRAlphaProgram; -LLGLSLShader gDeferredSkinnedPBRAlphaProgram; + +LLGLTFShaderPack gGLTFPBRShaderPack; +LLBPShaderPack gBPShaderPack; + LLGLSLShader gDeferredPBRTerrainProgram[TERRAIN_PAINT_TYPE_COUNT]; LLGLSLShader gGLTFPBRMetallicRoughnessProgram; @@ -434,7 +434,6 @@ void LLViewerShaderMgr::finalizeShaderList() mShaderList.push_back(&gDeferredWLCloudProgram); mShaderList.push_back(&gDeferredWLMoonProgram); mShaderList.push_back(&gDeferredWLSunProgram); - mShaderList.push_back(&gDeferredPBRAlphaProgram); mShaderList.push_back(&gHUDPBRAlphaProgram); mShaderList.push_back(&gDeferredPostTonemapProgram); mShaderList.push_back(&gNoPostTonemapProgram); @@ -442,7 +441,6 @@ void LLViewerShaderMgr::finalizeShaderList() mShaderList.push_back(&gCASLegacyGammaProgram); // for gamma mShaderList.push_back(&gDeferredDiffuseProgram); mShaderList.push_back(&gDeferredBumpProgram); - mShaderList.push_back(&gDeferredPBROpaqueProgram); if (gSavedSettings.getBOOL("GLTFEnabled")) { @@ -461,6 +459,9 @@ void LLViewerShaderMgr::finalizeShaderList() mShaderList.push_back(&gDeferredNonIndexedDiffuseAlphaMaskProgram); mShaderList.push_back(&gDeferredTreeProgram); + gGLTFPBRShaderPack.registerWLShaders(mShaderList); + gBPShaderPack.registerWLShaders(mShaderList); + // make sure there are no redundancies llassert(no_redundant_shaders(mShaderList)); } @@ -878,6 +879,8 @@ bool LLViewerShaderMgr::loadShadersWater() bool success = true; bool terrainWaterSuccess = true; + static LLCachedControl render_transparent_water(gSavedSettings, "RenderTransparentWater"); + bool use_sun_shadow = mShaderLevel[SHADER_DEFERRED] > 1 && gSavedSettings.getS32("RenderShadowDetail") > 0; @@ -903,7 +906,7 @@ bool LLViewerShaderMgr::loadShadersWater() gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER)); gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER)); gWaterProgram.clearPermutations(); - if (LLPipeline::sRenderTransparentWater) + if (render_transparent_water) { gWaterProgram.addPermutation("TRANSPARENT_WATER", "1"); } @@ -934,7 +937,7 @@ bool LLViewerShaderMgr::loadShadersWater() gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER)); gWaterEdgeProgram.clearPermutations(); gWaterEdgeProgram.addPermutation("WATER_EDGE", "1"); - if (LLPipeline::sRenderTransparentWater) + if (render_transparent_water) { gWaterEdgeProgram.addPermutation("TRANSPARENT_WATER", "1"); } @@ -961,7 +964,7 @@ bool LLViewerShaderMgr::loadShadersWater() gUnderWaterProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gUnderWaterProgram.clearPermutations(); - if (LLPipeline::sRenderTransparentWater) + if (render_transparent_water) { gUnderWaterProgram.addPermutation("TRANSPARENT_WATER", "1"); } @@ -1087,8 +1090,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowCubeProgram.unload(); gDeferredShadowAlphaMaskProgram.unload(); gDeferredSkinnedShadowAlphaMaskProgram.unload(); - gDeferredShadowGLTFAlphaMaskProgram.unload(); - gDeferredSkinnedShadowGLTFAlphaMaskProgram.unload(); gDeferredShadowFullbrightAlphaMaskProgram.unload(); gDeferredSkinnedShadowFullbrightAlphaMaskProgram.unload(); gDeferredAvatarShadowProgram.unload(); @@ -1145,18 +1146,11 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredGenBrdfLutProgram.unload(); gDeferredBufferVisualProgram.unload(); - for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) - { - gDeferredMaterialProgram[i].unload(); - } - gHUDPBROpaqueProgram.unload(); gPBRGlowProgram.unload(); - gDeferredPBROpaqueProgram.unload(); + gGLTFPBRShaderPack.unload(); + gBPShaderPack.unload(); gGLTFPBRMetallicRoughnessProgram.unload(); - gDeferredSkinnedPBROpaqueProgram.unload(); - gDeferredPBRAlphaProgram.unload(); - gDeferredSkinnedPBRAlphaProgram.unload(); for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type) { gDeferredPBRTerrainProgram[paint_type].unload(); @@ -1236,117 +1230,469 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } - gDeferredMaterialProgram[1].mFeatures.hasLighting = false; - gDeferredMaterialProgram[5].mFeatures.hasLighting = false; - gDeferredMaterialProgram[9].mFeatures.hasLighting = false; - gDeferredMaterialProgram[13].mFeatures.hasLighting = false; - gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + // there are over a thousand variants of the PBR/Blinn-Phong shaders, defer creation until needed + LLGLSLShader::sDeferCreation = true; + + U32 node_size = 16 * 3; + U32 max_nodes = gGLManager.mMaxUniformBlockSize / node_size; + + U32 instance_map_size = 4 * 4; + U32 max_instances = gGLManager.mMaxUniformBlockSize / instance_map_size; - for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) + U32 max_vec4s = gGLManager.mMaxUniformBlockSize / sizeof(LLVector4a); + if (success) { - if (success) - { - bool has_skin = i & 0x10; + std::string alpha_mode_names[3] = { "Opaque", "Alpha Blend", "Alpha Mask" }; + std::string double_sided_names[2] = { "Single Sided", "Double Sided" }; + std::string planar_names[2] = { "Non-Planar", "Planar" }; + std::string tex_anim_names[2] = { "No Tex Anim", "Tex Anim" }; + std::string tex_mask_names[4] = { "Base Color", "Normal", "Metallic-Roughness", "Emissive" }; - if (!has_skin) - { - mShaderList.push_back(&gDeferredMaterialProgram[i]); - gDeferredMaterialProgram[i].mName = llformat("Material Shader %d", i); - } - else - { - gDeferredMaterialProgram[i].mName = llformat("Skinned Material Shader %d", i); - } + { // debug shader + LLGLSLShader& shader = gGLTFPBRShaderPack.mDebugShader; + LLGLSLShader& skinned_shader = gGLTFPBRShaderPack.mSkinnedDebugShader; - U32 alpha_mode = i & 0x3; + shader.mName = "GLTF PBR Debug Shader"; - gDeferredMaterialProgram[i].mShaderFiles.clear(); - gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER)); - gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER)); - gDeferredMaterialProgram[i].mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.mShaderFiles.clear(); - gDeferredMaterialProgram[i].clearPermutations(); + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); - bool has_normal_map = (i & 0x8) > 0; - bool has_specular_map = (i & 0x4) > 0; + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + shader.addPermutation("OUTPUT_BASE_COLOR_ONLY", "1"); + shader.addPermutation("DEBUG", "1"); - if (has_normal_map) + success = make_rigged_variant(shader, skinned_shader); + if (success) { - gDeferredMaterialProgram[i].addPermutation("HAS_NORMAL_MAP", "1"); + success = shader.createShader(); } + llassert(success); + } - if (has_specular_map) + for (U32 i = 0; i < 3; ++i) + { + LLGLTFMaterial::AlphaMode alpha_mode = (LLGLTFMaterial::AlphaMode)i; + + for (U32 j = 0; j < 2; ++j) { - gDeferredMaterialProgram[i].addPermutation("HAS_SPECULAR_MAP", "1"); + bool double_sided = j == 1; + + for (U32 k = 0; k < 2; ++k) + { + bool planar_projection = k == 1; + + for (U32 l = 0; l < 2; ++l) + { + bool tex_anim = l == 1; + + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + if (success) + { // main view shader + + std::string textures = " "; + for (U8 t = 0; t < 4; ++t) + { + if (tex_mask & (1 << t)) + { + textures += tex_mask_names[t] + " "; + } + } + std::string name = llformat("GLTF PBR %s %s %s %s %s Shader", alpha_mode_names[i].c_str(), textures.c_str(), double_sided_names[j].c_str(), planar_names[k].c_str(), tex_anim_names[l].c_str()); + + LLGLSLShader& shader = gGLTFPBRShaderPack.mShader[i][tex_mask][j][k][l]; + LLGLSLShader& skinned_shader = gGLTFPBRShaderPack.mSkinnedShader[i][tex_mask][j][k][l]; + + shader.mName = name; + shader.mFeatures.hasSrgb = true; + + shader.mShaderFiles.clear(); + + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); + + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + + if (tex_mask != 0) + { + shader.addPermutation("HAS_TEXTURE", "1"); + } + + if (tex_mask & LLGLTFBatches::BASE_COLOR_MAP) + { + shader.addPermutation("SAMPLE_BASE_COLOR_MAP", "1"); + shader.addPermutation("GAMMA_CORRECT_BASE_COLOR", "1"); + } + + if (tex_mask & LLGLTFBatches::NORMAL_MAP) + { + shader.addPermutation("SAMPLE_NORMAL_MAP", "1"); + } + + if (tex_mask & LLGLTFBatches::METALLIC_ROUGHNESS_MAP) + { + shader.addPermutation("SAMPLE_ORM_MAP", "1"); + } + + if (tex_mask & LLGLTFBatches::EMISSIVE_MAP) + { + shader.addPermutation("SAMPLE_EMISSIVE_MAP", "1"); + } + + shader.addPermutation("SAMPLE_MATERIALS_UBO", "1"); + shader.addPermutation("HAS_NORMAL", "1"); + shader.addPermutation("HAS_FRAGMENT_NORMAL", "1"); + + bool frag_position = false; + + if (alpha_mode == LLGLTFMaterial::ALPHA_MODE_MASK) + { + shader.addPermutation("ALPHA_MASK", "1"); + } + else if (alpha_mode == LLGLTFMaterial::ALPHA_MODE_BLEND) + { + shader.mFeatures.calculatesLighting = false; + shader.mFeatures.hasLighting = false; + shader.mFeatures.isAlphaLighting = true; + shader.mFeatures.hasSrgb = true; + shader.mFeatures.calculatesAtmospherics = true; + shader.mFeatures.hasAtmospherics = true; + shader.mFeatures.hasGamma = true; + shader.mFeatures.hasShadows = use_sun_shadow; + shader.mFeatures.isDeferred = true; // include deferredUtils + shader.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED]; + + shader.addPermutation("ALPHA_BLEND", "1"); + shader.addPermutation("OUTPUT_BASE_COLOR_ONLY", "1"); + frag_position = true; + + if (use_sun_shadow) + { + shader.addPermutation("HAS_SUN_SHADOW", "1"); + } + } + + if (double_sided) + { + shader.addPermutation("DOUBLE_SIDED", "1"); + } + + if (planar_projection) + { + shader.addPermutation("PLANAR_PROJECTION", "1"); + } + + if (tex_anim) + { + shader.addPermutation("TEX_ANIM", "1"); + } + + if (gSavedSettings.getBOOL("RenderMirrors")) + { + shader.addPermutation("MIRROR_CLIP", "1"); + frag_position = true; + } + + if (frag_position) + { + shader.addPermutation("FRAG_POSITION", "1"); + } + success = make_rigged_variant(shader, skinned_shader); + if (success) + { + success = shader.createShader(); + } + llassert(success); + + } + } + + if (success) + { // shadow shader + std::string name = llformat("GLTF PBR %s %s Shadow Shader", alpha_mode_names[i].c_str(), double_sided_names[j].c_str()); + + LLGLSLShader& shader = gGLTFPBRShaderPack.mShadowShader[i][j][k][l]; + LLGLSLShader& skinned_shader = gGLTFPBRShaderPack.mSkinnedShadowShader[i][j][k][l]; + + shader.mName = name; + + shader.mShaderFiles.clear(); + + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/gltfpbrF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); + + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + + shader.addPermutation("OUTPUT_BASE_COLOR_ONLY", "1"); + + if (alpha_mode != LLGLTFMaterial::ALPHA_MODE_OPAQUE) + { + shader.addPermutation("HAS_TEXTURE", "1"); + shader.addPermutation("ALPHA_MASK", "1"); + shader.addPermutation("SAMPLE_MATERIALS_UBO", "1"); + shader.addPermutation("SAMPLE_BASE_COLOR_MAP", "1"); + if (planar_projection) + { + shader.addPermutation("HAS_NORMAL", "1"); + shader.addPermutation("PLANAR_PROJECTION", "1"); + } + } + + if (double_sided) + { + shader.addPermutation("DOUBLE_SIDED", "1"); + } + + if (tex_anim) + { + shader.addPermutation("TEX_ANIM", "1"); + } + + success = make_rigged_variant(shader, skinned_shader); + if (success) + { + success = shader.createShader(); + } + llassert(success); + } + } + } } + } + } - gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); + if (success) + { + { // debug shader + LLGLSLShader& shader = gBPShaderPack.mDebugShader; + LLGLSLShader& skinned_shader = gBPShaderPack.mSkinnedDebugShader; - if (alpha_mode != 0) - { - gDeferredMaterialProgram[i].mFeatures.hasAlphaMask = true; - gDeferredMaterialProgram[i].addPermutation("HAS_ALPHA_MASK", "1"); - } + shader.mName = "Blinn-Phong Debug Shader"; - if (use_sun_shadow) - { - gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", "1"); - } + shader.mShaderFiles.clear(); + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); - gDeferredMaterialProgram[i].mFeatures.hasSrgb = true; - gDeferredMaterialProgram[i].mFeatures.calculatesAtmospherics = true; - gDeferredMaterialProgram[i].mFeatures.hasAtmospherics = true; - gDeferredMaterialProgram[i].mFeatures.hasGamma = true; - gDeferredMaterialProgram[i].mFeatures.hasShadows = use_sun_shadow; - gDeferredMaterialProgram[i].mFeatures.hasReflectionProbes = true; + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + shader.addPermutation("OUTPUT_DIFFUSE_ONLY", "1"); + shader.addPermutation("DEBUG", "1"); - if (has_skin) - { - gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1"); - gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true; - } - else + success = make_rigged_variant(shader, skinned_shader); + if (success) { - gDeferredMaterialProgram[i].mRiggedVariant = &gDeferredMaterialProgram[i + 0x10]; + success = shader.createShader(); } - - success = gDeferredMaterialProgram[i].createShader(); llassert(success); } - } - - gDeferredMaterialProgram[1].mFeatures.hasLighting = true; - gDeferredMaterialProgram[5].mFeatures.hasLighting = true; - gDeferredMaterialProgram[9].mFeatures.hasLighting = true; - gDeferredMaterialProgram[13].mFeatures.hasLighting = true; - gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - if (success) - { - gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader"; - gDeferredPBROpaqueProgram.mFeatures.hasSrgb = true; + std::string alpha_mode_names[3] = { "Opaque", "Alpha Blend", "Alpha Mask" }; + std::string planar_names[2] = { "Non-Planar", "Planar" }; + std::string tex_anim_names[2] = { "No Tex Anim", "Tex Anim" }; + std::string tex_mask_names[3] = { "Diffuse", "Normal", "Specular"}; + for (U32 i = 0; i < 3; ++i) + { + LLGLTFMaterial::AlphaMode alpha_mode = (LLGLTFMaterial::AlphaMode)i; - gDeferredPBROpaqueProgram.mShaderFiles.clear(); - gDeferredPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueV.glsl", GL_VERTEX_SHADER)); - gDeferredPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueF.glsl", GL_FRAGMENT_SHADER)); - gDeferredPBROpaqueProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredPBROpaqueProgram.clearPermutations(); + for (U32 k = 0; k < 2; ++k) + { + bool planar_projection = k == 1; - success = make_rigged_variant(gDeferredPBROpaqueProgram, gDeferredSkinnedPBROpaqueProgram); - if (success) - { - success = gDeferredPBROpaqueProgram.createShader(); + for (U32 l = 0; l < 2; ++l) + { + bool tex_anim = l == 1; + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + if (success) + { // main view shader + std::string textures = " "; + for (U32 t = 0; t < 3; ++t) + { + U8 bit = 1 << t; + if (tex_mask & bit) + { + textures += tex_mask_names[t]; + textures += " "; + } + } + std::string name = llformat("Blinn-Phong %s %s %s %s Shader", alpha_mode_names[i].c_str(), textures.c_str(), planar_names[k].c_str(), tex_anim_names[l].c_str()); + + LLGLSLShader& shader = gBPShaderPack.mShader[i][tex_mask][k][l]; + LLGLSLShader& skinned_shader = gBPShaderPack.mSkinnedShader[i][tex_mask][k][l]; + + shader.mName = name; + shader.mFeatures.hasSrgb = true; + + shader.mShaderFiles.clear(); + + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); + + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + + if (tex_mask != 0) + { + shader.addPermutation("HAS_TEXTURE", "1"); + } + + if (tex_mask & LLGLTFBatches::DIFFUSE_MAP) + { + shader.addPermutation("SAMPLE_DIFFUSE_MAP", "1"); + } + + if (tex_mask & LLGLTFBatches::NORMAL_MAP) + { + shader.addPermutation("SAMPLE_NORMAL_MAP", "1"); + } + + if (tex_mask & LLGLTFBatches::SPECULAR_MAP) + { + shader.addPermutation("SAMPLE_SPECULAR_MAP", "1"); + } + + shader.addPermutation("SAMPLE_MATERIALS_UBO", "1"); + + shader.addPermutation("HAS_NORMAL", "1"); + shader.addPermutation("HAS_FRAGMENT_NORMAL", "1"); + + bool frag_position = false; + + if (alpha_mode == LLGLTFMaterial::ALPHA_MODE_MASK) + { + shader.addPermutation("ALPHA_MASK", "1"); + } + else if (alpha_mode == LLGLTFMaterial::ALPHA_MODE_BLEND) + { + shader.mFeatures.calculatesLighting = false; + shader.mFeatures.hasLighting = false; + shader.mFeatures.isAlphaLighting = true; + shader.mFeatures.hasSrgb = true; + shader.mFeatures.calculatesAtmospherics = true; + shader.mFeatures.hasAtmospherics = true; + shader.mFeatures.hasGamma = true; + shader.mFeatures.hasShadows = use_sun_shadow; + shader.mFeatures.isDeferred = true; // include deferredUtils + shader.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED]; + + shader.addPermutation("ALPHA_BLEND", "1"); + shader.addPermutation("OUTPUT_DIFFUSE_ONLY", "1"); + frag_position = true; + + if (use_sun_shadow) + { + shader.addPermutation("HAS_SUN_SHADOW", "1"); + } + } + + if (planar_projection) + { + shader.addPermutation("PLANAR_PROJECTION", "1"); + } + + if (tex_anim) + { + shader.addPermutation("TEX_ANIM", "1"); + } + + if (gSavedSettings.getBOOL("RenderMirrors")) + { + shader.addPermutation("MIRROR_CLIP", "1"); + frag_position = true; + } + + if (frag_position) + { + shader.addPermutation("FRAG_POSITION", "1"); + } + + success = make_rigged_variant(shader, skinned_shader); + if (success) + { + success = shader.createShader(); + } + llassert(success); + } + } + + if (success) + { // shadow shader + std::string name = llformat("Blinn-Phong %s %s %s Shadow Shader", alpha_mode_names[i].c_str(), + planar_names[k].c_str(), + tex_anim_names[l].c_str()); + + LLGLSLShader& shader = gBPShaderPack.mShadowShader[i][k][l]; + LLGLSLShader& skinned_shader = gBPShaderPack.mSkinnedShadowShader[i][k][l]; + + shader.mName = name; + + shader.mShaderFiles.clear(); + + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongV.glsl", GL_VERTEX_SHADER)); + shader.mShaderFiles.push_back(make_pair("deferred/blinnphongF.glsl", GL_FRAGMENT_SHADER)); + shader.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader.clearPermutations(); + + shader.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + + shader.addPermutation("OUTPUT_DIFFUSE_ONLY", "1"); + + if (alpha_mode != LLGLTFMaterial::ALPHA_MODE_OPAQUE) + { + shader.addPermutation("HAS_TEXTURE", "1"); + shader.addPermutation("ALPHA_MASK", "1"); + shader.addPermutation("SAMPLE_MATERIALS_UBO", "1"); + shader.addPermutation("SAMPLE_DIFFUSE_MAP", "1"); + + if (planar_projection) + { + shader.addPermutation("PLANAR_PROJECTION", "1"); + shader.addPermutation("HAS_NORMAL", "1"); // shadow shaders only need the normal for planar projection + } + } + + if (tex_anim) + { + shader.addPermutation("TEX_ANIM", "1"); + } + + success = make_rigged_variant(shader, skinned_shader); + if (success) + { + success = shader.createShader(); + } + llassert(success); + } + } + } } - llassert(success); } + LLGLSLShader::sDeferCreation = false; + if (gSavedSettings.getBOOL("GLTFEnabled")) { if (success) @@ -1395,68 +1741,23 @@ bool LLViewerShaderMgr::loadShadersDeferred() gHUDPBROpaqueProgram.mName = "HUD PBR Opaque Shader"; gHUDPBROpaqueProgram.mFeatures.hasSrgb = true; gHUDPBROpaqueProgram.mShaderFiles.clear(); - gHUDPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueV.glsl", GL_VERTEX_SHADER)); - gHUDPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueF.glsl", GL_FRAGMENT_SHADER)); + gHUDPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/gltfpbrV.glsl", GL_VERTEX_SHADER)); + gHUDPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/gltfpbrF.glsl", GL_FRAGMENT_SHADER)); gHUDPBROpaqueProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gHUDPBROpaqueProgram.clearPermutations(); - gHUDPBROpaqueProgram.addPermutation("IS_HUD", "1"); - - success = gHUDPBROpaqueProgram.createShader(); - llassert(success); - } - - - - if (success) - { - LLGLSLShader* shader = &gDeferredPBRAlphaProgram; - shader->mName = "Deferred PBR Alpha Shader"; - - shader->mFeatures.calculatesLighting = false; - shader->mFeatures.hasLighting = false; - shader->mFeatures.isAlphaLighting = true; - shader->mFeatures.hasSrgb = true; - shader->mFeatures.calculatesAtmospherics = true; - shader->mFeatures.hasAtmospherics = true; - shader->mFeatures.hasGamma = true; - shader->mFeatures.hasShadows = use_sun_shadow; - shader->mFeatures.isDeferred = true; // include deferredUtils - shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED]; + gHUDPBROpaqueProgram.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + gHUDPBROpaqueProgram.addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + gHUDPBROpaqueProgram.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); + gHUDPBROpaqueProgram.addPermutation("OUTPUT_BASE_COLOR_ONLY", "1"); + gHUDPBROpaqueProgram.addPermutation("HAS_TEXTURE", "1"); + gHUDPBROpaqueProgram.addPermutation("SAMPLE_BASE_COLOR_MAP", "1"); + gHUDPBROpaqueProgram.addPermutation("SAMPLE_EMISSIVE_MAP", "1"); + gHUDPBROpaqueProgram.addPermutation("OUTPUT_SRGB", "1"); - shader->mShaderFiles.clear(); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER)); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER)); - - shader->clearPermutations(); - - U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; - shader->addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); - shader->addPermutation("HAS_NORMAL_MAP", "1"); - shader->addPermutation("HAS_SPECULAR_MAP", "1"); // PBR: Packed: Occlusion, Metal, Roughness - shader->addPermutation("HAS_EMISSIVE_MAP", "1"); - shader->addPermutation("USE_VERTEX_COLOR", "1"); - - if (use_sun_shadow) - { - shader->addPermutation("HAS_SUN_SHADOW", "1"); - } + success = gHUDPBROpaqueProgram.createShader(); - shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaProgram); - if (success) - { - success = shader->createShader(); - } llassert(success); - - // Alpha Shader Hack - // See: LLRender::syncMatrices() - shader->mFeatures.calculatesLighting = true; - shader->mFeatures.hasLighting = true; - - shader->mRiggedVariant->mFeatures.calculatesLighting = true; - shader->mRiggedVariant->mFeatures.hasLighting = true; } if (success) @@ -1467,12 +1768,19 @@ bool LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasSrgb = true; shader->mShaderFiles.clear(); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER)); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER)); + shader->mShaderFiles.push_back(make_pair("deferred/gltfpbrV.glsl", GL_VERTEX_SHADER)); + shader->mShaderFiles.push_back(make_pair("deferred/gltfpbrF.glsl", GL_FRAGMENT_SHADER)); shader->clearPermutations(); + shader->addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes)); + shader->addPermutation("MAX_INSTANCES_PER_GLTF_OBJECT", std::to_string(max_instances)); + shader->addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s)); - shader->addPermutation("IS_HUD", "1"); + shader->addPermutation("HAS_TEXTURE", "1"); + shader->addPermutation("OUTPUT_BASE_COLOR_ONLY", "1"); + shader->addPermutation("SAMPLE_BASE_COLOR_MAP", "1"); + shader->addPermutation("SAMPLE_EMISSIVE_MAP", "1"); + shader->addPermutation("OUTPUT_SRGB", "1"); shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; success = shader->createShader(); @@ -2155,20 +2463,6 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } - - if (success) - { - gDeferredShadowGLTFAlphaMaskProgram.mName = "Deferred GLTF Shadow Alpha Mask Shader"; - gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.clear(); - gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/pbrShadowAlphaMaskV.glsl", GL_VERTEX_SHADER)); - gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/pbrShadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); - gDeferredShadowGLTFAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredShadowGLTFAlphaMaskProgram.clearPermutations(); - success = make_rigged_variant(gDeferredShadowGLTFAlphaMaskProgram, gDeferredSkinnedShadowGLTFAlphaMaskProgram); - success = success && gDeferredShadowGLTFAlphaMaskProgram.createShader(); - llassert(success); - } - if (success) { gDeferredShadowGLTFAlphaBlendProgram.mName = "Deferred GLTF Shadow Alpha Blend Shader"; @@ -3363,3 +3657,87 @@ LLViewerShaderMgr::shader_iter LLViewerShaderMgr::endShaders() const return mShaderList.end(); } +void LLGLTFShaderPack::unload() +{ + for (U32 i = 0; i < 3; i++) + { + for (U32 j = 0; j < 2; j++) + { + for (U32 k = 0; k < 2; ++k) + { + for (U32 l = 0; l < 2; ++l) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_TEX_MASK; ++tex_mask) + { + mShader[i][tex_mask][j][k][l].unload(); + mSkinnedShader[i][tex_mask][j][k][l].unload(); + } + mShadowShader[i][j][k][l].unload(); + mSkinnedShadowShader[i][j][k][l].unload(); + } + } + } + } + + mDebugShader.unload(); + mSkinnedDebugShader.unload(); +} + + +void LLGLTFShaderPack::registerWLShaders(std::vector& shader_list) +{ + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_TEX_MASK; ++tex_mask) + { + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + shader_list.push_back(&mShader[LLGLTFMaterial::ALPHA_MODE_BLEND][tex_mask][double_sided][planar][tex_anim]); + } + } + } + } +} + +void LLBPShaderPack::unload() +{ + for (U32 alpha_mode = 0; alpha_mode < 3; ++alpha_mode) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + mShader[alpha_mode][tex_mask][planar][tex_anim].unload(); + mSkinnedShader[alpha_mode][tex_mask][planar][tex_anim].unload(); + } + + mShadowShader[alpha_mode][planar][tex_anim].unload(); + mSkinnedShadowShader[alpha_mode][planar][tex_anim].unload(); + } + } + } + + mDebugShader.unload(); + mSkinnedDebugShader.unload(); +} + +void LLBPShaderPack::registerWLShaders(std::vector& shader_list) +{ + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_BP_TEX_MASK; ++tex_mask) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + + shader_list.push_back(&mShader[LLGLTFMaterial::ALPHA_MODE_BLEND][tex_mask][planar][tex_anim]); + } + } + } +} + + diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 36cf2e3ba8f..ff0f9a659c6 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -29,6 +29,7 @@ #include "llshadermgr.h" #include "llmaterial.h" +#include "llgltfdrawinfo.h" #define LL_DEFERRED_MULTI_LIGHT_COUNT 16 @@ -148,6 +149,51 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade return a.mIter != b.mIter; } +// shader pack for use with GLTF materials +class LLGLTFShaderPack +{ +public: + // variants are indexed by [Alpha Mode][tex_mask][Double Sided][Planar Projection][Texture Animation] + LLGLSLShader mShader[3][LLGLTFBatches::MAX_TEX_MASK][2][2][2]; + LLGLSLShader mSkinnedShader[3][LLGLTFBatches::MAX_TEX_MASK][2][2][2]; + + // shadow variantes are indexed by [Alpha Mode][Double Sided][Planar Projection][Texture Animation] + LLGLSLShader mShadowShader[3][2][2][2]; + LLGLSLShader mSkinnedShadowShader[3][2][2][2]; + + LLGLSLShader mDebugShader; + LLGLSLShader mSkinnedDebugShader; + + // unload all shaders in this pack + void unload(); + + // push shaders that need WL params into shader_list + void registerWLShaders(std::vector& shader_list); +}; + +// Blinn-Phong Shader Pack +class LLBPShaderPack +{ +public: + // variants are indexed by [Alpha Mode][tex_mask][Planar Projection][Texture Animation] + LLGLSLShader mShader[3][LLGLTFBatches::MAX_BP_TEX_MASK][2][2]; + LLGLSLShader mSkinnedShader[3][LLGLTFBatches::MAX_BP_TEX_MASK][2][2]; + + // shadow variants are indexed by [Alpha Mode][Planar Projection][Texture Animation] + LLGLSLShader mShadowShader[3][2][2]; + LLGLSLShader mSkinnedShadowShader[3][2][2]; + + LLGLSLShader mDebugShader; + LLGLSLShader mSkinnedDebugShader; + + // unload all shaders in this pack + void unload(); + + // push shaders that need WL params into shader_list + void registerWLShaders(std::vector& shader_list); + +}; + extern LLVector4 gShinyOrigin; //utility shaders @@ -290,14 +336,11 @@ extern LLGLSLShader gNormalMapGenProgram; extern LLGLSLShader gDeferredGenBrdfLutProgram; extern LLGLSLShader gDeferredBufferVisualProgram; -// Deferred materials shaders -extern LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; - extern LLGLSLShader gHUDPBROpaqueProgram; -extern LLGLSLShader gPBRGlowProgram; -extern LLGLSLShader gDeferredPBROpaqueProgram; -extern LLGLSLShader gDeferredPBRAlphaProgram; extern LLGLSLShader gHUDPBRAlphaProgram; +extern LLGLSLShader gPBRGlowProgram; +extern LLGLTFShaderPack gGLTFPBRShaderPack; +extern LLBPShaderPack gBPShaderPack; // GLTF shaders extern LLGLSLShader gGLTFPBRMetallicRoughnessProgram; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 1dea66b07da..bb88084137a 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -332,6 +332,7 @@ void update_statistics() { LL_PROFILE_ZONE_SCOPED; + gViewerThrottle.updateDynamicThrottle(); gTotalWorldData += gVLManager.getTotalBytes(); gTotalObjectData += gObjectData; @@ -497,6 +498,45 @@ void update_statistics() perf_stats_timer.reset(); } } + + gTextureList.updateStats(); + + ////////////////////////////////////// + // + // Manage statistics + // + // + { + /*! @brief This class is an LLFrameTimer that can be created with + an elapsed time that starts counting up from the given value + rather than 0.0. + + Otherwise it behaves the same way as LLFrameTimer. +*/ + class LLFrameStatsTimer : public LLFrameTimer + { + public: + LLFrameStatsTimer(F64 elapsed_already = 0.0) + : LLFrameTimer() + { + mStartTime -= elapsed_already; + } + }; + + // Initialize the viewer_stats_timer with an already elapsed time + // of SEND_STATS_PERIOD so that the initial stats report will + // be sent immediately. + static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD); + + // Update session stats every large chunk of time + if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) + { + LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; + bool include_preferences = false; + send_viewer_stats(include_preferences); + viewer_stats_timer.reset(); + } + } } /* @@ -510,6 +550,7 @@ void update_statistics() */ void send_viewer_stats(bool include_preferences) { + LL_PROFILE_ZONE_SCOPED; // IW 9/23/02 I elected not to move this into LLViewerStats // because it depends on too many viewer.cpp globals. // Someday we may want to merge all our stats into a central place diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 33ca5237378..ebe09056e4c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1162,7 +1162,6 @@ void LLViewerFetchedTexture::init(bool firstinit) LLViewerFetchedTexture::~LLViewerFetchedTexture() { - assert_main_thread(); //*NOTE getTextureFetch can return NULL when Viewer is shutting down. // This is due to LLWearableList is singleton and is destroyed after // LLAppViewer::cleanup() was called. (see ticket EXT-177) diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 9bee9d45a48..816faa5edfd 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -725,7 +725,6 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - assert_main_thread(); llassert_always(mInitialized) ; llassert(image); if (image->isInImageList()) @@ -745,7 +744,6 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - assert_main_thread(); llassert_always(mInitialized) ; llassert(image); @@ -834,6 +832,29 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) /////////////////////////////////////////////////////////////////////////////// +void LLViewerTextureList::updateStats() +{ + LLAppViewer::getTextureFetch()->setTextureBandwidth((F32)LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED).value()); + + { + using namespace LLStatViewer; + sample(NUM_IMAGES, sNumImages); + sample(NUM_RAW_IMAGES, LLImageRaw::sRawImageCount); + sample(FORMATTED_MEM, F64Bytes(LLImageFormatted::sGlobalFormattedMemory)); + } +} + +void LLViewerTextureList::updateGL() +{ + //handle results from decode threads + static LLCachedControl texture_gl_time(gSavedSettings, "TextureUpdateGLTime", 0.005f); + updateImagesCreateTextures(texture_gl_time); + + // Label all images (if enabled) + updateImagesNameTextures(); + labelAll(); +} + void LLViewerTextureList::updateImages(F32 max_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -859,15 +880,6 @@ void LLViewerTextureList::updateImages(F32 max_time) cleared = false; } - LLAppViewer::getTextureFetch()->setTextureBandwidth((F32)LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED).value()); - - { - using namespace LLStatViewer; - sample(NUM_IMAGES, sNumImages); - sample(NUM_RAW_IMAGES, LLImageRaw::sRawImageCount); - sample(FORMATTED_MEM, F64Bytes(LLImageFormatted::sGlobalFormattedMemory)); - } - // make sure each call below gets at least its "fair share" of time F32 min_time = max_time * 0.33f; F32 remaining_time = max_time; @@ -880,13 +892,6 @@ void LLViewerTextureList::updateImages(F32 max_time) remaining_time -= updateImagesFetchTextures(remaining_time); remaining_time = llmax(remaining_time, min_time); - //handle results from decode threads - updateImagesCreateTextures(remaining_time); - - // Label all images (if enabled) - updateImagesNameTextures(); - labelAll(); - bool didone = false; for (image_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 08dd2d0f7f0..eaa14b27954 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -122,8 +122,14 @@ class LLViewerTextureList LLViewerFetchedTexture *findImage(const LLUUID &image_id, ETexListType tex_type); LLViewerFetchedTexture *findImage(const LLTextureKey &search_key); + void updateStats(); + // Using image stats, determine what images are necessary, and perform image updates. void updateImages(F32 max_time); + + // update GL images (downscale via GPU, copy decoded textures to GPU) + void updateGL(); + void forceImmediateUpdate(LLViewerFetchedTexture* imagep) ; // Decode and create textures for all images currently in list. diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 31be509b0bd..7f1b4f3d77a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2133,8 +2133,6 @@ void LLVOAvatar::buildCharacter() processAnimationStateChanges(); mIsBuilt = true; - stop_glerror(); - mMeshValid = true; } @@ -3239,7 +3237,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() } deleteParticleSource(); - updateLOD(); + //updateLOD(); } else { @@ -5691,19 +5689,9 @@ void LLVOAvatar::updateTextures() } std::vector layer_baked; - // GL NOT ACTIVE HERE - *TODO for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex)); - // bind the texture so that they'll be decoded slightly - // inefficient, we can short-circuit this if we have to - if (render_avatar && !gGLManager.mIsDisabled) - { - if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded) - { - gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 )); - } - } } mMaxPixelArea = 0.f; @@ -6075,8 +6063,6 @@ void LLVOAvatar::processAnimationStateChanges() } } } - - stop_glerror(); } diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 27c105c8d60..af492c243ef 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -994,6 +994,7 @@ void LLVOCachePartition::selectBackObjects(LLCamera &camera, F32 pixel_threshold #ifndef LL_TEST S32 LLVOCachePartition::cull(LLCamera &camera, bool do_occlusion) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; static LLCachedControl use_object_cache_occlusion(gSavedSettings,"UseObjectCacheOcclusion"); if(!LLViewerRegion::sVOCacheCullingEnabled) diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index dcfff2dc7c8..6e8e91f3f8f 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -568,12 +568,14 @@ LLVoiceP2POutgoingCallInterface *LLVoiceClient::getOutgoingCallInterface(const L void LLVoiceClient::setVoiceVolume(F32 volume) { + LL_PROFILE_ZONE_SCOPED; LLWebRTCVoiceClient::getInstance()->setVoiceVolume(volume); LLVivoxVoiceClient::getInstance()->setVoiceVolume(volume); } void LLVoiceClient::setMicGain(F32 gain) { + LL_PROFILE_ZONE_SCOPED; LLWebRTCVoiceClient::getInstance()->setMicGain(gain); LLVivoxVoiceClient::getInstance()->setMicGain(gain); } @@ -653,6 +655,7 @@ void LLVoiceClient::updateMicMuteLogic() void LLVoiceClient::setMuteMic(bool muted) { + LL_PROFILE_ZONE_SCOPED; if (mMuteMic != muted) { mMuteMic = muted; @@ -996,11 +999,6 @@ LLSpeakerVolumeStorage::LLSpeakerVolumeStorage() } LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage() -{ -} - -//virtual -void LLSpeakerVolumeStorage::cleanupSingleton() { save(); } diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index d1d88c408dc..d29e313db04 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -545,16 +545,13 @@ class LLVoiceClient: public LLParamSingleton /** * Speaker volume storage helper class **/ -class LLSpeakerVolumeStorage : public LLSingleton +class LLSpeakerVolumeStorage : public LLSimpleton { - LLSINGLETON(LLSpeakerVolumeStorage); - ~LLSpeakerVolumeStorage(); LOG_CLASS(LLSpeakerVolumeStorage); -protected: - virtual void cleanupSingleton() override; - public: + LLSpeakerVolumeStorage(); + ~LLSpeakerVolumeStorage(); /** * Stores volume level for specified user. diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 87196b7a857..8b19879dcc1 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6323,7 +6323,11 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta if (voice_status) { - LLAppViewer::instance()->postToMainCoro([=]() { LLFirstUse::speak(true); }); + LLAppViewer::instance()->postToMainCoro([=]() + { + LL_PROFILE_ZONE_NAMED("Voice:LLFirstUse::speak"); + LLFirstUse::speak(true); + }); } } } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2dd6dc0c045..811b6a3fe98 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -532,7 +532,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { if (mDrawable) { //on the fly TE updates break batches, isolate in octree - shrinkWrap(); + //shrinkWrap(); } } if (result & TEM_CHANGE_MEDIA) @@ -591,9 +591,10 @@ void LLVOVolume::onDrawableUpdateFromServer() void LLVOVolume::animateTextures() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; if (!mDead) { - shrinkWrap(); + //shrinkWrap(); F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f; S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot); @@ -670,6 +671,38 @@ void LLVOVolume::animateTextures() tex_mat *= mat; tex_mat.translate(trans); + + if (facep->mTextureTransformIndex != 0xFFFFFFFF) + { + // update texture transform UBO + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group && group->mTextureTransformUBO != 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("animateTextures - update UBO"); + F32 mp[12]; + const F32* m = (const F32*) &tex_mat.mMatrix[0][0]; + + mp[0] = m[0]; + mp[1] = m[1]; + mp[2] = m[2]; + mp[3] = m[12]; + + mp[4] = m[4]; + mp[5] = m[5]; + mp[6] = m[6]; + mp[7] = m[13]; + + mp[8] = m[8]; + mp[9] = m[9]; + mp[10] = m[10]; + mp[11] = m[14]; + + glBindBuffer(GL_UNIFORM_BUFFER, group->mTextureTransformUBO); + glBufferSubData(GL_UNIFORM_BUFFER, facep->mTextureTransformIndex * 48, 48, mp); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } + } } else @@ -838,31 +871,6 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) mPixelArea = llmax(mPixelArea, face->getPixelArea()); - // if the face has gotten small enough to turn off texture animation and texture - // animation is running, rebuild the render batch for this face to turn off - // texture animation - // Do the opposite when the face gets big enough. - // If a face is animatable, it will always have non-null mTextureMatrix - // pointer defined after the first call to LLVOVolume::animateTextures, - // although the animation is not always turned on. - if (face->mTextureMatrix != NULL) - { - if ((vsize > MIN_TEX_ANIM_SIZE) != (old_size > MIN_TEX_ANIM_SIZE)) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - // dirtyGeom+markRebuild tells the engine to call - // LLVolumeGeometryManager::rebuildGeom, which rebuilds the - // LLDrawInfo for the spatial group containing this LLFace, - // safely copying the mTextureMatrix from the LLFace the the - // LLDrawInfo. While it's not ideal to call it here, prims with - // animated faces get moved to a smaller partition to reduce - // side-effects of their updates (see shrinkWrap in - // LLVOVolume::animateTextures). - mDrawable->getSpatialGroup()->dirtyGeom(); - gPipeline.markRebuild(mDrawable->getSpatialGroup()); - } - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ; @@ -980,13 +988,9 @@ void LLVOVolume::setScale(const LLVector3 &scale, bool damped) updateRadius(); - //since drawable transforms do not include scale, changing volume scale - //requires an immediate rebuild of volume verts. - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); - if (mDrawable) { - shrinkWrap(); + //shrinkWrap(); } } } @@ -1065,6 +1069,7 @@ void LLVOVolume::unregisterOldMeshAndSkin() bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + LLVolumeParams volume_params = params_in; S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1; @@ -1137,7 +1142,6 @@ bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo if (isSculpted()) { - updateSculptTexture(); // if it's a mesh if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { @@ -1255,7 +1259,11 @@ void LLVOVolume::updateVisualComplexity() void LLVOVolume::notifyMeshLoaded() { mSculptChanged = true; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY); + if (mDrawable) + { + markForUpdate(); + gPipeline.markTransformDirty(mDrawable->getSpatialGroup()); + } if (!mSkinInfo && !mSkinInfoUnavaliable) { @@ -1279,7 +1287,6 @@ void LLVOVolume::notifyMeshLoaded() cav->addAttachmentOverridesForObject(this); cav->notifyAttachmentMeshLoaded(); } - updateVisualComplexity(); } void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin) @@ -1519,12 +1526,38 @@ bool LLVOVolume::calcLOD() } else { +#if 0 + // EXPERIMENTAL -- use spatial partition node for LoD calculation to make all objects in a given octree node + // switch LoD at the same time. + glm::vec3 eye = glm::make_vec3(LLViewerCamera::getInstance()->getOrigin().mV); + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (!group) + { + return false; + } + const LLVector4a* extents = group->getExtents(); + glm::vec3 minp = glm::make_vec3(extents[0].getF32ptr()); + glm::vec3 maxp = glm::make_vec3(extents[1].getF32ptr()); + glm::vec3 center = (minp + maxp) * 0.5f; + radius = glm::distance(center, maxp); + + if (group->getSpatialPartition()->isBridge()) + { + glm::mat4 mat = glm::make_mat4((F32*) &mDrawable->getRenderMatrix().mMatrix[0][0]); + + center = glm::vec3(mat * glm::vec4(center, 1.0f)); + } + + distance = llmax(glm::distance(eye, center) - radius, 0.1f); +#else distance = mDrawable->mDistanceWRTCamera; radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length(); +#endif if (distance <= 0.f || radius <= 0.f) { return false; } + } //hold onto unmodified distance for debugging @@ -1635,6 +1668,7 @@ bool LLVOVolume::updateLOD() if (lod_changed) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME); + gPipeline.markTransformDirty(mDrawable->getSpatialGroup()); mLODChanged = true; } else @@ -1664,7 +1698,7 @@ bool LLVOVolume::setDrawableParent(LLDrawable* parentp) { // rebuild vertices in parent relative space gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME); - + gPipeline.markTransformDirty(mDrawable->getSpatialGroup()); if (mDrawable->isActive() && !parentp->isActive()) { parentp->makeActive(); @@ -1716,6 +1750,7 @@ bool LLVOVolume::setParent(LLViewerObject* parent) { gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME); + gPipeline.markTransformDirty(mDrawable->getSpatialGroup()); } onReparent(old_parent, parent); } @@ -2276,7 +2311,7 @@ S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid) if (mDrawable) { // dynamic texture changes break batches, isolate in octree - shrinkWrap(); + //shrinkWrap(); gPipeline.markTextured(mDrawable); } mFaceMappingChanged = true; @@ -2313,7 +2348,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color) // These should only happen on updates which are not the initial update. mColorChanged = true; mDrawable->setState(LLDrawable::REBUILD_COLOR); - shrinkWrap(); + //shrinkWrap(); dirtyMesh(); } } @@ -2406,7 +2441,7 @@ S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow) if (mDrawable) { gPipeline.markTextured(mDrawable); - shrinkWrap(); + //shrinkWrap(); } mFaceMappingChanged = true; } @@ -4495,6 +4530,27 @@ void LLVOVolume::updateReflectionProbePtr() void LLVOVolume::setSelected(bool sel) { LLViewerObject::setSelected(sel); + getBinRadius(); + + /*if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE)) + { + std::ostringstream str; + + for (S32 i = 0; i < mDrawable->getNumFaces(); ++i) + { + LLFace* face = mDrawable->getFace(i); + LLGLTFDrawInfo* info = face->mGLTFDrawInfo.get(); + + if (info) + { + str << info->mInstanceCount << " "; + } + } + + setDebugText(str.str()); + }*/ + + if (isAnimatedObject()) { getRootEdit()->recursiveMarkForUpdate(); @@ -4512,62 +4568,18 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { } +// next highest power of two +U32 nhpo2(U32 v); + F32 LLVOVolume::getBinRadius() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - F32 radius; static LLCachedControl octree_size_factor(gSavedSettings, "OctreeStaticObjectSizeFactor", 3); - static LLCachedControl octree_attachment_size_factor(gSavedSettings, "OctreeAttachmentSizeFactor", 4); - static LLCachedControl octree_distance_factor(gSavedSettings, "OctreeDistanceFactor", LLVector3(0.01f, 0.f, 0.f)); - static LLCachedControl octree_alpha_distance_factor(gSavedSettings, "OctreeAlphaDistanceFactor", LLVector3(0.1f, 0.f, 0.f)); - - S32 size_factor = llmax((S32)octree_size_factor, 1); - LLVector3 alpha_distance_factor = octree_alpha_distance_factor; - - //const LLVector4a* ext = mDrawable->getSpatialExtents(); - bool shrink_wrap = mShouldShrinkWrap || mDrawable->isAnimating(); - bool alpha_wrap = false; - - if (!isHUDAttachment() && mDrawable->mDistanceWRTCamera < alpha_distance_factor[2]) - { - for (S32 i = 0; i < mDrawable->getNumFaces(); i++) - { - LLFace* face = mDrawable->getFace(i); - if (!face) continue; - if (face->isInAlphaPool() && - !face->canRenderAsMask()) - { - alpha_wrap = true; - break; - } - } - } - else - { - shrink_wrap = false; - } + S32 size_factor = llmax(octree_size_factor, 1); - if (alpha_wrap) - { - LLVector3 bounds = getScale(); - radius = llmin(bounds.mV[1], bounds.mV[2]); - radius = llmin(radius, bounds.mV[0]); - radius *= 0.5f; - //radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1]; - //radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0]; - } - else if (shrink_wrap) - { - radius = mDrawable->getRadius() * 0.25f; - } - else - { - F32 szf = (F32)size_factor; - radius = llmax(mDrawable->getRadius(), szf); - //radius = llmax(radius, mDrawable->mDistanceWRTCamera * distance_factor[0]); - } + F32 radius = (F32) nhpo2(llmax((S32)mDrawable->getRadius(), size_factor)); return llclamp(radius, 0.5f, 256.f); } @@ -4604,7 +4616,7 @@ void LLVOVolume::markForUpdate() { if (mDrawable) { - shrinkWrap(); + //shrinkWrap(); } LLViewerObject::markForUpdate(); @@ -5195,386 +5207,17 @@ bool can_batch_texture(LLFace* facep) return true; } -const static U32 MAX_FACE_COUNT = 4096U; -int32_t LLVolumeGeometryManager::sInstanceCount = 0; -LLFace** LLVolumeGeometryManager::sFullbrightFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sBumpFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sSimpleFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sNormFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sSpecFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sNormSpecFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sPbrFaces[2] = { NULL }; -LLFace** LLVolumeGeometryManager::sAlphaFaces[2] = { NULL }; - LLVolumeGeometryManager::LLVolumeGeometryManager() : LLGeometryManager() { - llassert(sInstanceCount >= 0); - if (sInstanceCount == 0) - { - allocateFaces(MAX_FACE_COUNT); - } - - ++sInstanceCount; } LLVolumeGeometryManager::~LLVolumeGeometryManager() { - llassert(sInstanceCount > 0); - --sInstanceCount; - - if (sInstanceCount <= 0) - { - freeFaces(); - sInstanceCount = 0; - } -} - -void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount) -{ - for (int i = 0; i < 2; ++i) - { - sFullbrightFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sBumpFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sSimpleFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sNormFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sSpecFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sNormSpecFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sPbrFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - sAlphaFaces[i] = static_cast(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); - } -} - -void LLVolumeGeometryManager::freeFaces() -{ - for (int i = 0; i < 2; ++i) - { - ll_aligned_free<64>(sFullbrightFaces[i]); - ll_aligned_free<64>(sBumpFaces[i]); - ll_aligned_free<64>(sSimpleFaces[i]); - ll_aligned_free<64>(sNormFaces[i]); - ll_aligned_free<64>(sSpecFaces[i]); - ll_aligned_free<64>(sNormSpecFaces[i]); - ll_aligned_free<64>(sPbrFaces[i]); - ll_aligned_free<64>(sAlphaFaces[i]); - - sFullbrightFaces[i] = NULL; - sBumpFaces[i] = NULL; - sSimpleFaces[i] = NULL; - sNormFaces[i] = NULL; - sSpecFaces[i] = NULL; - sNormSpecFaces[i] = NULL; - sPbrFaces[i] = NULL; - sAlphaFaces[i] = NULL; - } -} - -void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - if ( type == LLRenderPass::PASS_ALPHA - && facep->getTextureEntry()->getMaterialParams().notNull() - && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT) - && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1) - { - LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; - } - - bool selected = facep->getViewerObject()->isSelected(); - - if (selected && LLSelectMgr::getInstance()->mHideSelectedObjects) - { - return; - } - - LL_LABEL_VERTEX_BUFFER(facep->getVertexBuffer(), LLRenderPass::lookupPassName(type)); - - U32 passType = type; - - bool rigged = facep->isState(LLFace::RIGGED); - - if (rigged) - { - // hacky, should probably clean up -- if this face is rigged, put it in "type + 1" - // See LLRenderPass PASS_foo enum - passType += 1; - } - //add face to drawmap - LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[passType]; - - S32 idx = static_cast(draw_vec.size()) - 1; - - bool fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) || - (type == LLRenderPass::PASS_INVISIBLE) || - (type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) || - (type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) || - (facep->getTextureEntry()->getFullbright()); - - if (!fullbright && - type != LLRenderPass::PASS_GLOW && - !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL)) - { - llassert(false); - LL_WARNS() << "Non fullbright face has no normals!" << LL_ENDL; - return; - } - - const LLMatrix4* tex_mat = NULL; - if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) - { - tex_mat = facep->mTextureMatrix; - } - - const LLMatrix4* model_mat = NULL; - - LLDrawable* drawable = facep->getDrawable(); - - if (rigged) - { - // rigged meshes ignore their model matrix - model_mat = nullptr; - } - else if (drawable->isState(LLDrawable::ANIMATED_CHILD)) - { - model_mat = &drawable->getWorldMatrix(); - } - else if (drawable->isActive()) - { - model_mat = &drawable->getRenderMatrix(); - } - else - { - model_mat = &(drawable->getRegion()->mRenderMatrix); - } - - //drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD))); - - const LLTextureEntry* te = facep->getTextureEntry(); - U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? te->getBumpmap() : 0; - U8 shiny = te->getShiny(); - - LLViewerTexture* tex = facep->getTexture(); - - U8 index = facep->getTextureIndex(); - - LLMaterial* mat = nullptr; - - LLUUID mat_id; - - auto* gltf_mat = (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial(); - llassert(gltf_mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr); - if (gltf_mat != nullptr) - { - mat_id = gltf_mat->getHash(); // TODO: cache this hash - if (!facep->hasMedia() || (tex && tex->getType() != LLViewerTexture::MEDIA_TEXTURE)) - { // no media texture, face texture will be unused - tex = nullptr; - } - } - else - { - mat = te->getMaterialParams().get(); - if (mat) - { - mat_id = te->getMaterialParams()->getHash(); - } - } - - bool batchable = false; - - U32 shader_mask = 0xFFFFFFFF; //no shader - - if (mat) - { - bool is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (te->getColor().mV[3] < 0.999f); - if (type == LLRenderPass::PASS_ALPHA) - { - shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, is_alpha); - } - else - { - shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha); - } - } - - if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0) - { - if (mat || gltf_mat || draw_vec[idx]->mMaterial) - { //can't batch textures when materials are present (yet) - batchable = false; - } - else if (index < draw_vec[idx]->mTextureList.size()) - { - if (draw_vec[idx]->mTextureList[index].isNull()) - { - batchable = true; - draw_vec[idx]->mTextureList[index] = tex; - } - else if (draw_vec[idx]->mTextureList[index] == tex) - { //this face's texture index can be used with this batch - batchable = true; - } - } - else - { //texture list can be expanded to fit this texture index - batchable = true; - } - } - - LLDrawInfo* info = idx >= 0 ? draw_vec[idx] : nullptr; - - if (info && - info->mVertexBuffer == facep->getVertexBuffer() && - info->mEnd == facep->getGeomIndex()-1 && - (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) && -#if LL_DARWIN - info->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && - info->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && -#endif - info->mMaterialHash == mat_id && - info->mFullbright == fullbright && - info->mBump == bump && - (!mat || (info->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different - info->mTextureMatrix == tex_mat && - info->mModelMatrix == model_mat && - info->mShaderMask == shader_mask && - info->mAvatar == facep->mAvatar && - info->getSkinHash() == facep->getSkinHash()) - { - info->mCount += facep->getIndicesCount(); - info->mEnd += facep->getGeomCount(); - - if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= info->mTextureList.size()) - { - info->mTextureList.resize(index+1); - info->mTextureList[index] = tex; - } - info->validate(); - } - else - { - U32 start = facep->getGeomIndex(); - U32 end = start + facep->getGeomCount()-1; - U32 offset = facep->getIndicesStart(); - U32 count = facep->getIndicesCount(); - LLPointer draw_info = new LLDrawInfo(start,end,count,offset, tex, - facep->getVertexBuffer(), fullbright, bump); - - info = draw_info; - - draw_vec.push_back(draw_info); - draw_info->mTextureMatrix = tex_mat; - draw_info->mModelMatrix = model_mat; - - draw_info->mBump = bump; - draw_info->mShiny = shiny; - - static const float alpha[4] = - { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; - float spec = alpha[shiny & TEM_SHINY_MASK]; - LLVector4 specColor(spec, spec, spec, spec); - draw_info->mSpecColor = specColor; - draw_info->mEnvIntensity = spec; - draw_info->mSpecularMap = NULL; - draw_info->mMaterial = mat; - draw_info->mGLTFMaterial = gltf_mat; - draw_info->mShaderMask = shader_mask; - draw_info->mAvatar = facep->mAvatar; - draw_info->mSkinInfo = facep->mSkinInfo; - - if (gltf_mat) - { - // just remember the material ID, render pools will reference the GLTF material - draw_info->mMaterialHash = mat_id; - } - else if (mat) - { - draw_info->mMaterialHash = mat_id; - - // We have a material. Update our draw info accordingly. - - if (!mat->getSpecularID().isNull()) - { - LLVector4 specColor; - specColor.mV[0] = mat->getSpecularLightColor().mV[0] * (1.f / 255.f); - specColor.mV[1] = mat->getSpecularLightColor().mV[1] * (1.f / 255.f); - specColor.mV[2] = mat->getSpecularLightColor().mV[2] * (1.f / 255.f); - specColor.mV[3] = mat->getSpecularLightExponent() * (1.f / 255.f); - draw_info->mSpecColor = specColor; - draw_info->mEnvIntensity = mat->getEnvironmentIntensity() * (1.f / 255.f); - draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTEOffset()); - } - - draw_info->mAlphaMaskCutoff = mat->getAlphaMaskCutoff() * (1.f / 255.f); - draw_info->mDiffuseAlphaMode = mat->getDiffuseAlphaMode(); - draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTEOffset()); - } - else - { - if (type == LLRenderPass::PASS_GRASS) - { - draw_info->mAlphaMaskCutoff = 0.5f; - } - else - { - draw_info->mAlphaMaskCutoff = 0.33f; - } - } - - // This backpointer is used by alpha sorting and avatar attachment - // accounting. - // To be safe, always populate the draw_info ptr. - facep->setDrawInfo(draw_info); - - if (index < FACE_DO_NOT_BATCH_TEXTURES) - { //initialize texture list for texture batching - draw_info->mTextureList.resize(index+1); - draw_info->mTextureList[index] = tex; - } - draw_info->validate(); - } - - llassert(info->mGLTFMaterial == nullptr || (info->mVertexBuffer->getTypeMask() & LLVertexBuffer::MAP_TANGENT) != 0); - llassert(type != LLPipeline::RENDER_TYPE_PASS_GLTF_PBR || info->mGLTFMaterial != nullptr); - llassert(type != LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_RIGGED || info->mGLTFMaterial != nullptr); - llassert(type != LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK || info->mGLTFMaterial != nullptr); - llassert(type != LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK_RIGGED || info->mGLTFMaterial != nullptr); - - llassert(type != LLRenderPass::PASS_BUMP || (info->mVertexBuffer->getTypeMask() & LLVertexBuffer::MAP_TANGENT) != 0); - llassert(type != LLRenderPass::PASS_NORMSPEC || info->mNormalMap.notNull()); - llassert(type != LLRenderPass::PASS_SPECMAP || (info->mVertexBuffer->getTypeMask() & LLVertexBuffer::MAP_TEXCOORD2) != 0); } void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) { - -} - -// add a face pointer to a list of face pointers without going over MAX_COUNT faces -template -static inline void add_face(T*** list, U32* count, T* face) -{ - if (face->isState(LLFace::RIGGED)) - { - if (count[1] < MAX_FACE_COUNT) - { - face->setDrawOrderIndex(count[1]); - list[1][count[1]++] = face; - } - } - else - { - if (count[0] < MAX_FACE_COUNT) - { - face->setDrawOrderIndex(count[0]); - list[0][count[0]++] = face; - } - } } void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) @@ -5614,10 +5257,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) vobj = bridge->mDrawable->getVObj(); vol_obj = dynamic_cast(vobj); } - if (vol_obj) - { - vol_obj->updateVisualComplexity(); - } group->mGeometryBytes = 0; group->mSurfaceArea = 0; @@ -5628,32 +5267,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->clearDrawMap(); - U32 fullbright_count[2] = { 0 }; - U32 bump_count[2] = { 0 }; - U32 simple_count[2] = { 0 }; - U32 alpha_count[2] = { 0 }; - U32 norm_count[2] = { 0 }; - U32 spec_count[2] = { 0 }; - U32 normspec_count[2] = { 0 }; - U32 pbr_count[2] = { 0 }; - - static LLCachedControl max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); - static LLCachedControl max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); - U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); - U32 max_total = (max_node_size * 1024) / LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); - max_vertices = llmin(max_vertices, (U32) 65535); - - U32 cur_total = 0; - - bool emissive = false; - - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. -#if 0 - bool pelvisGotSet = false; -#endif - { LL_PROFILE_ZONE_NAMED("rebuildGeom - face list"); @@ -5712,7 +5325,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) vobj->updateControlAvatar(); llassert_always(vobj); - vobj->updateTextureVirtualSize(true); vobj->preRebuild(); drawablep->clearState(LLDrawable::HAS_ALPHA); @@ -5751,6 +5363,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool any_rigged_face = false; //for each face + drawablep->clearState(LLDrawable::HAS_GLTF); for (S32 i = 0; i < drawablep->getNumFaces(); i++) { LLFace* facep = drawablep->getFace(i); @@ -5764,6 +5377,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (is_pbr) { + drawablep->setState(LLDrawable::HAS_GLTF); // tell texture streaming system to ignore blinn-phong textures facep->setTexture(LLRender::DIFFUSE_MAP, nullptr); facep->setTexture(LLRender::NORMAL_MAP, nullptr); @@ -5780,9 +5394,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) // batch, it will recover its vertex buffer reference from the spatial group facep->setVertexBuffer(NULL); - //sum up face verts and indices - drawablep->updateFaceSize(i); - if (rigged) { if (!facep->isState(LLFace::RIGGED)) @@ -5811,24 +5422,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) - { - facep->clearVertexBuffer(); - continue; - } - if (facep->hasGeometry()) { - cur_total += facep->getGeomCount(); - const LLTextureEntry* te = facep->getTextureEntry(); LLViewerTexture* tex = facep->getTexture(); - if (te->getGlow() > 0.f) - { - emissive = true; - } - if (facep->isState(LLFace::TEXTURE_ANIM)) { if (!vobj->mTexAnimMode) @@ -5880,35 +5478,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (type == LLDrawPool::POOL_ALPHA) { - if (facep->canRenderAsMask()) - { //can be treated as alpha mask - add_face(sSimpleFaces, simple_count, facep); - } - else - { - F32 alpha; - if (is_pbr) - { - alpha = gltf_mat ? gltf_mat->mBaseColor.mV[3] : 1.0f; - } - else - { - alpha = te->getColor().mV[3]; - } - if (alpha > 0.f || te->getGlow() > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - add_face(sAlphaFaces, alpha_count, facep); - } - else if (LLDrawPoolAlpha::sShowDebugAlpha || - (gPipeline.sRenderHighlight && !drawablep->getParent() && - //only root objects are highlighted with red color in this case - drawablep->getVObj() && drawablep->getVObj()->flagScripted() && - (LLPipeline::getRenderScriptedBeacons() || - (LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch())))) - { //draw the transparent face for debugging purposes using a custom texture - add_face(sAlphaFaces, alpha_count, facep); - } + if (!facep->canRenderAsMask()) + { //can't be treated as alpha mask + drawablep->setState(LLDrawable::HAS_ALPHA); } } else @@ -5917,72 +5489,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { facep->mLastUpdateTime = gFrameTimeSeconds; } - - { - LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial(); - - if (gltf_mat != nullptr || (te->getMaterialParams().notNull())) - { - if (gltf_mat != nullptr) - { - // In theory, we should never actually get here with alpha blending. - // How this is supposed to work is we check if the surface is alpha blended, and we assign it to the alpha draw pool. - // For rigged meshes, this apparently may not happen consistently. - // For now, just discard it here if the alpha is 0 (fully transparent) to achieve parity with blinn-phong materials in function. - - bool should_render = true; - if (gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) - { - if (gltf_mat->mBaseColor.mV[3] == 0.0f) - { - should_render = false; - } - } - - if (should_render) - { - add_face(sPbrFaces, pbr_count, facep); - } - } - else - { - LLMaterial* mat = te->getMaterialParams().get(); - if (mat->getNormalID().notNull() || // <-- has a normal map, needs tangents - (te->getBumpmap() && (te->getBumpmap() < 18))) // <-- has an emboss bump map, needs tangents - { - if (mat->getSpecularID().notNull()) - { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) - add_face(sNormSpecFaces, normspec_count, facep); - } - else - { //has normal map (needs texcoord1 and tangent) - add_face(sNormFaces, norm_count, facep); - } - } - else if (mat->getSpecularID().notNull()) - { //has specular map but no normal map, needs texcoord2 - add_face(sSpecFaces, spec_count, facep); - } - else - { //has neither specular map nor normal map, only needs texcoord0 - add_face(sSimpleFaces, simple_count, facep); - } - } - } - else if (te->getBumpmap()) - { //needs normal + tangent - add_face(sBumpFaces, bump_count, facep); - } - else if (te->getShiny() || !te->getFullbright()) - { //needs normal - add_face(sSimpleFaces, simple_count, facep); - } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - add_face(sFullbrightFaces, fullbright_count, facep); - } - } } } else @@ -6015,848 +5521,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - //PROCESS NON-ALPHA FACES - U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO - U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - - U32 norm_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TANGENT; - U32 normspec_mask = norm_mask | LLVertexBuffer::MAP_TEXCOORD2; - U32 spec_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD2; - - U32 pbr_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TANGENT; - - if (emissive) - { //emissive faces are present, include emissive byte to preserve batching - simple_mask = simple_mask | LLVertexBuffer::MAP_EMISSIVE; - alpha_mask = alpha_mask | LLVertexBuffer::MAP_EMISSIVE; - bump_mask = bump_mask | LLVertexBuffer::MAP_EMISSIVE; - fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_EMISSIVE; - norm_mask = norm_mask | LLVertexBuffer::MAP_EMISSIVE; - normspec_mask = normspec_mask | LLVertexBuffer::MAP_EMISSIVE; - spec_mask = spec_mask | LLVertexBuffer::MAP_EMISSIVE; - pbr_mask = pbr_mask | LLVertexBuffer::MAP_EMISSIVE; - } - - bool batch_textures = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; - - // add extra vertex data for deferred rendering (not necessarily for batching textures) - if (batch_textures) - { - bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT; - simple_mask = simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX; - alpha_mask = alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2; - fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX; - } - - group->mGeometryBytes = 0; - - U32 geometryBytes = 0; - - // generate render batches for static geometry - U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX; - bool alpha_sort = true; - bool rigged = false; - for (int i = 0; i < 2; ++i) //two sets, static and rigged) - { - geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], false, batch_textures, rigged); - geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], false, batch_textures, rigged); - geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged); - geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], false, false, rigged); - geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], false, false, rigged); - geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], false, false, rigged); - geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], false, false, rigged); - geometryBytes += genDrawInfo(group, pbr_mask | extra_mask, sPbrFaces[i], pbr_count[i], false, false, rigged); - - // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer) - extra_mask |= LLVertexBuffer::MAP_WEIGHT4; - rigged = true; - } - - group->mGeometryBytes = geometryBytes; - - { - //drawables have been rebuilt, clear rebuild status - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) - { - LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if(drawablep) - { - drawablep->clearState(LLDrawable::REBUILD_ALL); - } - } - } - - group->mLastUpdateTime = gFrameTimeSeconds; - group->mBuilt = 1.f; - group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY); -} + group->mLastUpdateTime = gFrameTimeSeconds; + group->mBuilt = 1.f; + group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY); +} void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - llassert(group); - if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY)) - { - { - LL_PROFILE_ZONE_NAMED("rebuildMesh - gen draw info"); - - group->mBuilt = 1.f; - - static std::vector locked_buffer; - locked_buffer.resize(0); - - U32 buffer_count = 0; - - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) - { - LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - - if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL)) - { - LLVOVolume* vobj = drawablep->getVOVolume(); - - if (!vobj) continue; - - if (vobj->isNoLOD()) continue; - - vobj->preRebuild(); - - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) - { - vobj->updateRelativeXform(true); - } - - LLVolume* volume = vobj->getVolume(); - if (!volume) continue; - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - if (face) - { - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) - { - if (!face->getGeometryVolume(*volume, // volume - face->getTEOffset(), // face_index - vobj->getRelativeXform(), // mat_vert_in - vobj->getRelativeXformInvTrans(), // mat_norm_in - face->getGeomIndex(), // index_offset - false, // force_rebuild - true)) // no_debug_assert - { // Something's gone wrong with the vertex buffer accounting, - // rebuild this group with no debug assert because MESH_DIRTY - group->dirtyGeom(); - gPipeline.markRebuild(group); - } - } - } - } - - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) - { - vobj->updateRelativeXform(); - } - - drawablep->clearState(LLDrawable::REBUILD_ALL); - } - } - - { - LL_PROFILE_ZONE_NAMED("rebuildMesh - flush"); - LLVertexBuffer::flushBuffers(); - } - - group->clearState(LLSpatialGroup::MESH_DIRTY); - } - } -} - -struct CompareBatchBreaker -{ - bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) - { - const LLTextureEntry* lte = lhs->getTextureEntry(); - const LLTextureEntry* rte = rhs->getTextureEntry(); - - if (lte->getBumpmap() != rte->getBumpmap()) - { - return lte->getBumpmap() < rte->getBumpmap(); - } - else if (lte->getFullbright() != rte->getFullbright()) - { - return lte->getFullbright() < rte->getFullbright(); - } - else if (lte->getMaterialID() != rte->getMaterialID()) - { - return lte->getMaterialID() < rte->getMaterialID(); - } - else if (lte->getShiny() != rte->getShiny()) - { - return lte->getShiny() < rte->getShiny(); - } - else if (lhs->getTexture() != rhs->getTexture()) - { - return lhs->getTexture() < rhs->getTexture(); - } - else - { - // all else being equal, maintain consistent draw order - return lhs->getDrawOrderIndex() < rhs->getDrawOrderIndex(); - } - } -}; - -struct CompareBatchBreakerRigged -{ - bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) - { - if (lhs->mAvatar != rhs->mAvatar) - { - return lhs->mAvatar < rhs->mAvatar; - } - else if (lhs->mSkinInfo->mHash != rhs->mSkinInfo->mHash) - { - return lhs->mSkinInfo->mHash < rhs->mSkinInfo->mHash; - } - else - { - // "inherit" non-rigged behavior - CompareBatchBreaker comp; - return comp(lhs, rhs); - } - } -}; - -U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, bool distance_sort, bool batch_textures, bool rigged) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - - U32 geometryBytes = 0; - - //calculate maximum number of vertices to store in a single buffer - static LLCachedControl max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); - U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); - max_vertices = llmin(max_vertices, (U32) 65535); - - { - LL_PROFILE_ZONE_NAMED("genDrawInfo - sort"); - - if (rigged) - { - if (!distance_sort) // <--- alpha "sort" rigged faces by maintaining original draw order - { - //sort faces by things that break batches, including avatar and mesh id - std::sort(faces, faces + face_count, CompareBatchBreakerRigged()); - } - } - else if (!distance_sort) - { - //sort faces by things that break batches, not including avatar and mesh id - std::sort(faces, faces + face_count, CompareBatchBreaker()); - } - else - { - //sort faces by distance - std::sort(faces, faces+face_count, LLFace::CompareDistanceGreater()); - } - } - - bool hud_group = group->isHUDGroup() ; - LLFace** face_iter = faces; - LLFace** end_faces = faces+face_count; - - LLSpatialGroup::buffer_map_t buffer_map; - - LLViewerTexture* last_tex = NULL; - - S32 texture_index_channels = LLGLSLShader::sIndexedTextureChannels; - - bool flexi = false; - - while (face_iter != end_faces) - { - //pull off next face - LLFace* facep = *face_iter; - LLViewerTexture* tex = facep->getTexture(); - const LLTextureEntry* te = facep->getTextureEntry(); - LLMaterialPtr mat = te->getMaterialParams(); - LLMaterialID matId = te->getMaterialID(); - - if (distance_sort) - { - tex = NULL; - } - - if (last_tex != tex) - { - last_tex = tex; - } - - bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); - - U32 index_count = facep->getIndicesCount(); - U32 geom_count = facep->getGeomCount(); - - flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); - - //sum up vertices needed for this render batch - LLFace** i = face_iter; - ++i; - - const U32 MAX_TEXTURE_COUNT = 32; - LLViewerTexture* texture_list[MAX_TEXTURE_COUNT]; - - U32 texture_count = 0; - - { - LL_PROFILE_ZONE_NAMED("genDrawInfo - face size"); - if (batch_textures) - { - U8 cur_tex = 0; - facep->setTextureIndex(cur_tex); - if (texture_count < MAX_TEXTURE_COUNT) - { - texture_list[texture_count++] = tex; - } - - if (can_batch_texture(facep)) - { //populate texture_list with any textures that can be batched - //move i to the next unbatchable face - while (i != end_faces) - { - facep = *i; - - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time - facep->setTextureIndex(0); - break; - } - - if (facep->getTexture() != tex) - { - if (distance_sort) - { //textures might be out of order, see if texture exists in current batch - bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_count; ++tex_idx) - { - if (facep->getTexture() == texture_list[tex_idx]) - { - cur_tex = tex_idx; - found = true; - break; - } - } - - if (!found) - { - cur_tex = texture_count; - } - } - else - { - cur_tex++; - } - - if (cur_tex >= texture_index_channels) - { //cut batches when index channels are depleted - break; - } - - tex = facep->getTexture(); - - if (texture_count < MAX_TEXTURE_COUNT) - { - texture_list[texture_count++] = tex; - } - } - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - - flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); - - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - - facep->setTextureIndex(cur_tex); - } - } - else - { - facep->setTextureIndex(0); - } - - tex = texture_list[0]; - } - else - { - while (i != end_faces && - (LLPipeline::sTextureBindTest || - (distance_sort || - ((*i)->getTexture() == tex)))) - { - facep = *i; - const LLTextureEntry* nextTe = facep->getTextureEntry(); - if (nextTe->getMaterialID() != matId) - { - break; - } - - //face has no texture index - facep->mDrawInfo = NULL; - facep->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES); - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - - flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); - } - } - } - - //create vertex buffer - LLPointer buffer; - - { - LL_PROFILE_ZONE_NAMED("genDrawInfo - allocate"); - buffer = new LLVertexBuffer(mask); - if(!buffer->allocateBuffer(geom_count, index_count)) - { - LL_WARNS() << "Failed to allocate group Vertex Buffer to " - << geom_count << " vertices and " - << index_count << " indices" << LL_ENDL; - buffer = NULL; - } - } - - if (buffer) - { - geometryBytes += buffer->getSize() + buffer->getIndicesSize(); - buffer_map[mask][*face_iter].push_back(buffer); - } - - //add face geometry - - U32 indices_index = 0; - U16 index_offset = 0; - - while (face_iter < i) - { - //update face indices for new buffer - facep = *face_iter; - - if (buffer.isNull()) - { - // Bulk allocation failed - facep->setVertexBuffer(buffer); - facep->setSize(0, 0); // mark as no geometry - ++face_iter; - continue; - } - facep->setIndicesIndex(indices_index); - facep->setGeomIndex(index_offset); - facep->setVertexBuffer(buffer); - - if (batch_textures && facep->getTextureIndex() == FACE_DO_NOT_BATCH_TEXTURES) - { - LL_ERRS() << "Invalid texture index." << LL_ENDL; - } - - { - //for debugging, set last time face was updated vs moved - facep->updateRebuildFlags(); - - { //copy face geometry into vertex buffer - LLDrawable* drawablep = facep->getDrawable(); - LLVOVolume* vobj = drawablep->getVOVolume(); - LLVolume* volume = vobj->getVolume(); - - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) - { - vobj->updateRelativeXform(true); - } - - U32 te_idx = facep->getTEOffset(); - - if (!facep->getGeometryVolume(*volume, te_idx, - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true)) - { - LL_WARNS() << "Failed to get geometry for face!" << LL_ENDL; - } - - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) - { - vobj->updateRelativeXform(false); - } - } - } - - index_offset += facep->getGeomCount(); - indices_index += facep->getIndicesCount(); - - //append face to appropriate render batch - - bool force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA; - bool fullbright = facep->isState(LLFace::FULLBRIGHT); - if ((mask & LLVertexBuffer::MAP_NORMAL) == 0) - { //paranoia check to make sure GL doesn't try to read non-existant normals - fullbright = true; - } - - const LLTextureEntry* te = facep->getTextureEntry(); - LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial(); - - if (hud_group && gltf_mat == nullptr) - { //all hud attachments are fullbright - fullbright = true; - } - - tex = facep->getTexture(); - - bool is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA; - - LLMaterial* mat = nullptr; - bool can_be_shiny = false; - - // ignore traditional material if GLTF material is present - if (gltf_mat == nullptr) - { - mat = te->getMaterialParams().get(); - - can_be_shiny = true; - if (mat) - { - U8 mode = mat->getDiffuseAlphaMode(); - can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || - mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; - } - } - - F32 blinn_phong_alpha = te->getColor().mV[3]; - bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull()); - bool blinn_phong_opaque = blinn_phong_alpha >= 0.999f; - bool blinn_phong_transparent = blinn_phong_alpha < 0.999f; - - if (!gltf_mat) - { - is_alpha |= blinn_phong_transparent; - } - - if (gltf_mat || (mat && !hud_group)) - { - bool material_pass = false; - - if (gltf_mat) - { // all other parameters ignored if gltf material is present - if (gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - is_alpha = true; - } - else if (gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK) - { - registerFace(group, facep, LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_GLTF_PBR); - } - } - else - // do NOT use 'fullbright' for this logic or you risk sending - // things without normals down the materials pipeline and will - // render poorly if not crash NORSPEC-240,314 - // - if (te->getFullbright()) - { - if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) - { - if (blinn_phong_opaque) - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - } - else if (is_alpha) - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - else - { - if (mat->getEnvironmentIntensity() > 0 || te->getShiny() > 0) - { - material_pass = true; - } - else - { - if (blinn_phong_opaque) - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - } - } - } - else if (blinn_phong_transparent) - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - else if (use_legacy_bump) - { - llassert(mask & LLVertexBuffer::MAP_TANGENT); - // we have a material AND legacy bump settings, but no normal map - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - else - { - material_pass = true; - } - - if (material_pass) - { - static const U32 pass[] = - { - LLRenderPass::PASS_MATERIAL, - LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA, - LLRenderPass::PASS_MATERIAL_ALPHA_MASK, - LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, - LLRenderPass::PASS_SPECMAP, - LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND, - LLRenderPass::PASS_SPECMAP_MASK, - LLRenderPass::PASS_SPECMAP_EMISSIVE, - LLRenderPass::PASS_NORMMAP, - LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND, - LLRenderPass::PASS_NORMMAP_MASK, - LLRenderPass::PASS_NORMMAP_EMISSIVE, - LLRenderPass::PASS_NORMSPEC, - LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND, - LLRenderPass::PASS_NORMSPEC_MASK, - LLRenderPass::PASS_NORMSPEC_EMISSIVE, - }; - - U32 alpha_mode = mat->getDiffuseAlphaMode(); - if (!distance_sort && alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) - { // HACK - this should never happen, but sometimes we get a material that thinks it has alpha blending when it ought not - alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; - } - U32 mask = mat->getShaderMask(alpha_mode, is_alpha); - - U32 vb_mask = facep->getVertexBuffer()->getTypeMask(); - - // HACK - this should also never happen, but sometimes we get here and the material thinks it has a specmap now - // even though it didn't appear to have a specmap when the face was added to the list of faces - if ((mask & 0x4) && !(vb_mask & LLVertexBuffer::MAP_TEXCOORD2)) - { - mask &= ~0x4; - } - - llassert(mask < sizeof(pass)/sizeof(U32)); - - mask = llmin(mask, (U32)(sizeof(pass)/sizeof(U32)-1)); - - // if this is going into alpha pool, distance sort MUST be true - llassert(pass[mask] == LLRenderPass::PASS_ALPHA ? distance_sort : true); - registerFace(group, facep, pass[mask]); - } - } - else if (mat) - { - U8 mode = mat->getDiffuseAlphaMode(); - - is_alpha = (is_alpha || (mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)); - - if (is_alpha) - { - mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; - } - - if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) - { - registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK : LLRenderPass::PASS_ALPHA_MASK); - } - else if (is_alpha ) - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - else if (gPipeline.shadersLoaded() - && te->getShiny() - && can_be_shiny) - { - registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_SHINY); - } - else - { - registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT : LLRenderPass::PASS_SIMPLE); - } - } - else if (is_alpha) - { - // can we safely treat this as an alpha mask? - if (facep->getFaceColor().mV[3] <= 0.f) - { //100% transparent, don't render unless we're highlighting transparent - registerFace(group, facep, LLRenderPass::PASS_ALPHA_INVISIBLE); - } - else if (facep->canRenderAsMask() && !hud_group) - { - if (te->getFullbright() || LLPipeline::sNoAlpha) - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK); - } - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - } - else if (gPipeline.shadersLoaded() - && te->getShiny() - && can_be_shiny) - { //shiny - if (tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim+shiny - registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (!hud_group) - { //deferred rendering - if (te->getFullbright()) - { //register in post deferred fullbright shiny pass - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); - if (te->getBumpmap()) - { //register in post deferred bump pass - registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); - } - } - else if (use_legacy_bump) - { //register in deferred bump pass - llassert(mask& LLVertexBuffer::MAP_TANGENT); - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - else - { //register in deferred simple pass (deferred simple includes shiny) - llassert(mask & LLVertexBuffer::MAP_NORMAL); - registerFace(group, facep, LLRenderPass::PASS_SIMPLE); - } - } - else if (fullbright) - { //not deferred, register in standard fullbright shiny pass - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); - } - else - { //not deferred or fullbright, register in standard shiny pass - registerFace(group, facep, LLRenderPass::PASS_SHINY); - } - } - else - { //not alpha and not shiny - if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (fullbright || bake_sunlight) - { //fullbright - if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); - } - if (!hud_group && use_legacy_bump) - { //if this is the deferred render and a bump map is present, register in post deferred bump - registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); - } - } - else - { - if (use_legacy_bump) - { //non-shiny or fullbright deferred bump - llassert(mask& LLVertexBuffer::MAP_TANGENT); - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - else - { //all around simple - llassert(mask & LLVertexBuffer::MAP_NORMAL); - if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) - { //material alpha mask can be respected in non-deferred - registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_SIMPLE); - } - } - } - - - if (!gPipeline.shadersLoaded() && - !is_alpha && - te->getShiny()) - { //shiny as an extra pass when shaders are disabled - registerFace(group, facep, LLRenderPass::PASS_SHINY); - } - } - - //not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010 - if (!is_alpha && hud_group) - { - llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright); - facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE); - - if (!force_simple && use_legacy_bump) - { - llassert(mask & LLVertexBuffer::MAP_TANGENT); - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - } - - if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) - { - if (gltf_mat) - { - registerFace(group, facep, LLRenderPass::PASS_GLTF_GLOW); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_GLOW); - } - } - - ++face_iter; - } - } - - group->mBufferMap[mask].clear(); - for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i) - { - group->mBufferMap[mask][i->first] = i->second; - } - - return geometryBytes; } void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 4a7e231f302..bdf77c88eea 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -134,8 +134,9 @@ bool LLVOWater::updateGeometry(LLDrawable *drawable) static const unsigned int vertices_per_quad = 4; static const unsigned int indices_per_quad = 6; - S32 size_x = LLPipeline::sRenderTransparentWater ? 8 : 1; - S32 size_y = LLPipeline::sRenderTransparentWater ? 8 : 1; + static LLCachedControl render_transparent_water(gSavedSettings, "RenderTransparentWater"); + S32 size_x = render_transparent_water ? 8 : 1; + S32 size_y = render_transparent_water ? 8 : 1; const LLVector3& scale = getScale(); size_x *= (S32)llmin(llround(scale.mV[0] / 256.f), 8); diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 2d59712142c..dd6ea605e68 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -106,6 +106,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID LLAppViewer::instance()->postToMainCoro([=]() { + LL_PROFILE_ZONE_NAMED("LLWearableList::processGetAssetReply (lambda)"); processGetAssetReply(filename_in.c_str(), uuid_in, userdata, status, ext_status); }); diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index aab19a4d5fd..785cb6b124c 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -193,12 +193,12 @@ const S32 MAP_MAX_SIZE = 2048; const S32 MAP_BLOCK_SIZE = 4; const S32 MAP_BLOCK_RES = (MAP_MAX_SIZE / MAP_BLOCK_SIZE); -class LLWorldMap : public LLSingleton +class LLWorldMap : public LLSimpleton { - LLSINGLETON(LLWorldMap); - ~LLWorldMap(); - public: + LLWorldMap(); + virtual ~LLWorldMap(); + // Clear all: list of region info, tiles, blocks and items void reset(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index cd45d1e779e..506bd77086c 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -309,7 +309,6 @@ bool LLPipeline::sForceOldBakedUpload = false; S32 LLPipeline::sUseOcclusion = 0; bool LLPipeline::sAutoMaskAlphaDeferred = true; bool LLPipeline::sAutoMaskAlphaNonDeferred = false; -bool LLPipeline::sRenderTransparentWater = true; bool LLPipeline::sBakeSunlight = false; bool LLPipeline::sNoAlpha = false; bool LLPipeline::sUseFarClip = true; @@ -332,7 +331,7 @@ F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f; // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; -static LLCullResult* sCull = NULL; +LLCullResult* sCull = NULL; void validate_framebuffer_object(); @@ -405,6 +404,29 @@ void LLPipeline::connectRefreshCachedSettingsSafe(const std::string name) void LLPipeline::init() { + LLImageGL::sTexNameReferenceCheck = [](U32 texName) + { + if (!gDebugGL) + { // expensive check, do not run unless we're debugging GL + return; + } + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->checkTexNameReferences(texName); + } + } + } + }; + refreshCachedSettings(); mRT = &mMainRT; @@ -605,6 +627,7 @@ void LLPipeline::cleanup() assertInitialized(); mGroupQ1.clear() ; + mGroupTransformQ.clear(); for(pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ) @@ -1012,11 +1035,6 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY) return true; } -//static -void LLPipeline::updateRenderTransparentWater() -{ - sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); -} // static void LLPipeline::refreshCachedSettings() @@ -2401,8 +2419,9 @@ static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); // static bool LLPipeline::isWaterClip() { + static LLCachedControl render_transparent_water(gSavedSettings, "RenderTransparentWater", false); // We always pretend that we're not clipping water when rendering mirrors. - return (gPipeline.mHeroProbeManager.isMirrorPass()) ? false : (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs; + return (gPipeline.mHeroProbeManager.isMirrorPass()) ? false : (render_transparent_water || gCubeSnapshot) && !sRenderingHUDs; } void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result) @@ -2765,10 +2784,10 @@ void LLPipeline::rebuildPriorityGroups() void LLPipeline::updateGeom(F32 max_dtime) { - LLTimer update_timer; + LL_PROFILE_ZONE_SCOPED; LLPointer drawablep; - LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE); + if (gCubeSnapshot) { return; @@ -2807,6 +2826,18 @@ void LLPipeline::updateGeom(F32 max_dtime) } updateMovedList(mMovedBridge); + + for (auto& drawable : mDrawableTransformQ) + { + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (group) + { + group->updateTransform(drawable); + } + + drawable->clearState(LLDrawable::IN_TRANSFORM_Q); + } + mDrawableTransformQ.clear(); } void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) @@ -3011,6 +3042,28 @@ void LLPipeline::markMeshDirty(LLSpatialGroup* group) mMeshDirtyGroup.push_back(group); } +void LLPipeline::markTransformDirty(LLSpatialGroup* group) +{ + if (group && group->getSpatialPartition()->mDrawableType == LLPipeline::RENDER_TYPE_VOLUME) + { + group->setState(LLSpatialGroup::IN_TRANSFORM_BUILD_Q); + group->mBPBatches.clear(); + group->mGLTFBatches.clear(); + group->mShadowBatches.clear(); + + // NOTE: don't clear mVertexBuffers or delete UBOs here as VBOs/UBOs may still be referenced by a CullResult + } +} + +void LLPipeline::markTransformDirty(LLDrawable* drawablep) +{ + if (drawablep && !drawablep->isState(LLDrawable::IN_TRANSFORM_Q)) + { + drawablep->setState(LLDrawable::IN_TRANSFORM_Q); + mDrawableTransformQ.push_back(drawablep); + } +} + void LLPipeline::markRebuild(LLSpatialGroup* group) { if (group && !group->isDead() && group->getSpatialPartition()) @@ -3247,18 +3300,15 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { - //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here + if (!drawablep->isActive()) { - if (!drawablep->isActive()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); - } - else if (drawablep->isAvatar()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() - } + bool force_update = false; + drawablep->updateDistance(camera, force_update); + } + else if (drawablep->isAvatar()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() } } @@ -3501,6 +3551,7 @@ void LLPipeline::postSort(LLCamera &camera) if (!gCubeSnapshot) { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - rebuild groups"); // rebuild drawable geometry for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) { @@ -3521,97 +3572,86 @@ void LLPipeline::postSort(LLCamera &camera) } // build render map - for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { - LLSpatialGroup *group = *i; - - if (group->isDead()) + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - build render map"); + for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { - continue; - } + LLSpatialGroup* group = *i; - if ((sUseOcclusion && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) || - (RenderAutoHideSurfaceAreaLimit > 0.f && - group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit * llmax(group->mObjectBoxSize, 10.f))) - { - continue; - } + if (group->isDead()) + { + continue; + } - for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) - { - LLSpatialGroup::drawmap_elem_t &src_vec = j->second; - if (!hasRenderType(j->first)) + if ((sUseOcclusion && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) || + (RenderAutoHideSurfaceAreaLimit > 0.f && + group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit * llmax(group->mObjectBoxSize, 10.f))) { continue; } - for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) + for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) { - LLDrawInfo *info = *k; + LLSpatialGroup::drawmap_elem_t& src_vec = j->second; + if (!hasRenderType(j->first)) + { + continue; + } - sCull->pushDrawInfo(j->first, info); - if (!sShadowRender && !sReflectionRender && !gCubeSnapshot) + for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) { - addTrianglesDrawn(info->mCount); + LLDrawInfo* info = *k; + + sCull->pushDrawInfo(j->first, info); + if (!sShadowRender && !sReflectionRender && !gCubeSnapshot) + { + addTrianglesDrawn(info->mCount); + } } } - } - if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) - { - LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); + if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) + { + LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); - if (alpha != group->mDrawMap.end()) - { // store alpha groups for sorting - LLSpatialBridge *bridge = group->getSpatialPartition()->asBridge(); - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) - { - if (bridge) + if (alpha != group->mDrawMap.end()) + { // store alpha groups for sorting + LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { - LLCamera trans_camera = bridge->transformCamera(camera); - group->updateDistance(trans_camera); + if (bridge) + { + LLCamera trans_camera = bridge->transformCamera(camera); + group->updateDistance(trans_camera); + } + else + { + group->updateDistance(camera); + } } - else + + if (hasRenderType(LLDrawPool::POOL_ALPHA)) { - group->updateDistance(camera); + sCull->pushAlphaGroup(group); } } - if (hasRenderType(LLDrawPool::POOL_ALPHA)) - { - sCull->pushAlphaGroup(group); - } - } - - LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED); + LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED); - if (rigged_alpha != group->mDrawMap.end()) - { // store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer) - if (hasRenderType(LLDrawPool::POOL_ALPHA)) - { - sCull->pushRiggedAlphaGroup(group); + if (rigged_alpha != group->mDrawMap.end()) + { // store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer) + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + sCull->pushRiggedAlphaGroup(group); + } } } } } - /*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty(); - - if (use_transform_feedback) - { //place a query around potential transform feedback code for synchronization - mTransformFeedbackPrimitives = 0; - - if (!mMeshDirtyQueryObject) - { - glGenQueries(1, &mMeshDirtyQueryObject); - } - - - glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); - }*/ - // pack vertex buffers for groups that chose to delay their updates { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - rebuild mesh"); LL_PROFILE_GPU_ZONE("rebuildMesh"); for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) { @@ -3619,15 +3659,63 @@ void LLPipeline::postSort(LLCamera &camera) } } - /*if (use_transform_feedback) + static LLCachedControl depth_pre_pass(gSavedSettings, "RenderDepthPrePass"); + + // build render map { - glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); - }*/ + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - build GLTF/BP render map"); + + for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - group GLTF/BP render map"); + LLSpatialGroup* group = *i; + + if (group->isDead()) + { + continue; + } + + if ((sUseOcclusion && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) || + (RenderAutoHideSurfaceAreaLimit > 0.f && + group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit * llmax(group->mObjectBoxSize, 10.f))) + { + continue; + } + + // make sure any pending transform updates are done BEFORE we add the group to the render map + if (group->hasState(LLSpatialGroup::IN_TRANSFORM_BUILD_Q)) + { + group->updateTransformUBOs(); + group->clearState(LLSpatialGroup::IN_TRANSFORM_BUILD_Q); + } + + + // add group->mGLTFBatches to sCull->mGLTFBatches, etc + if (sShadowRender) + { + sCull->mGLTFBatches.addShadow(group->mGLTFBatches); + sCull->mBPBatches.addShadow(group->mBPBatches); + sCull->mShadowBatches.add(group->mShadowBatches); + } + else + { + // add group->mGLTFBatches to sCull->mGLTFBatches + sCull->mGLTFBatches.add(group->mGLTFBatches); + sCull->mBPBatches.add(group->mBPBatches); + + if (depth_pre_pass) + { + sCull->mShadowBatches.add(group->mShadowBatches); + } + } + } + } mMeshDirtyGroup.clear(); if (!sShadowRender) { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - alpha sort"); // order alpha groups by distance std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); @@ -3635,9 +3723,104 @@ void LLPipeline::postSort(LLCamera &camera) std::sort(sCull->beginRiggedAlphaGroups(), sCull->endRiggedAlphaGroups(), LLSpatialGroup::CompareRenderOrder()); } + { + struct CompareMaterialVBO + { + bool operator()(const LLGLTFDrawInfo& lhs, const LLGLTFDrawInfo& rhs) + { + if (rhs.mMaterialID != lhs.mMaterialID) + { + return lhs.mMaterialID < rhs.mMaterialID; + } + else + { + return lhs.mVBO < rhs.mVBO; + } + } + }; + + struct CompareVBO + { + bool operator()(const LLGLTFDrawInfo& lhs, const LLGLTFDrawInfo& rhs) + { + return lhs.mVBO < rhs.mVBO; + } + }; + + struct CompareSkinnedMaterialVBO + { + bool operator()(const LLSkinnedGLTFDrawInfo& lhs, const LLSkinnedGLTFDrawInfo& rhs) + { + if (rhs.mAvatar != lhs.mAvatar) + { + return lhs.mAvatar < rhs.mAvatar; + } + else if (rhs.mSkinInfo->mHash != lhs.mSkinInfo->mHash) + { + return lhs.mSkinInfo->mHash < rhs.mSkinInfo->mHash; + } + else if (rhs.mMaterialID != lhs.mMaterialID) + { + return lhs.mMaterialID < rhs.mMaterialID; + } + else + { + return lhs.mVBO < rhs.mVBO; + } + } + }; + + + struct CompareSkinnedVBO + { + bool operator()(const LLSkinnedGLTFDrawInfo& lhs, const LLSkinnedGLTFDrawInfo& rhs) + { + if (rhs.mAvatar != lhs.mAvatar) + { + return lhs.mAvatar < rhs.mAvatar; + } + else if (rhs.mSkinInfo->mHash != lhs.mSkinInfo->mHash) + { + return lhs.mSkinInfo->mHash < rhs.mSkinInfo->mHash; + } + else + { + return lhs.mVBO < rhs.mVBO; + } + } + }; + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - gltf sort"); + sCull->mGLTFBatches.sort(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareMaterialVBO()); + sCull->mGLTFBatches.sort(LLGLTFMaterial::ALPHA_MODE_MASK, CompareMaterialVBO()); + sCull->mGLTFBatches.sort(LLGLTFMaterial::ALPHA_MODE_BLEND, CompareMaterialVBO()); + sCull->mGLTFBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareSkinnedMaterialVBO()); + sCull->mGLTFBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_MASK, CompareSkinnedMaterialVBO()); + sCull->mGLTFBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_BLEND, CompareSkinnedMaterialVBO()); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - bp sort"); + sCull->mBPBatches.sort(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareMaterialVBO()); + sCull->mBPBatches.sort(LLGLTFMaterial::ALPHA_MODE_MASK, CompareMaterialVBO()); + sCull->mBPBatches.sort(LLGLTFMaterial::ALPHA_MODE_BLEND, CompareMaterialVBO()); + sCull->mBPBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareSkinnedMaterialVBO()); + sCull->mBPBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_MASK, CompareSkinnedMaterialVBO()); + sCull->mBPBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_BLEND, CompareSkinnedMaterialVBO()); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - shadow sort"); + sCull->mShadowBatches.sort(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareVBO()); + sCull->mShadowBatches.sortSkinned(LLGLTFMaterial::ALPHA_MODE_OPAQUE, CompareSkinnedVBO()); + } + } + // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender && !gCubeSnapshot) { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("postSort - beacons"); if (sRenderScriptedTouchBeacons) { // Only show the beacon on the root object. @@ -3746,6 +3929,7 @@ void LLPipeline::postSort(LLCamera &camera) } } + LLVertexBuffer::flushBuffers(); // LLSpatialGroup::sNoDelete = false; } @@ -3910,6 +4094,29 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } + + static LLCachedControl render_depth_pre_pass(gSavedSettings, "RenderDepthPrePass", false); + if (render_depth_pre_pass) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("depth pre-pass"); + LL_PROFILE_GPU_ZONE("depth pre-pass"); + gGL.setColorMask(false, false); + + bool planar = false; + bool tex_anim = false; + U8 tex_mask = 0; + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); + + gGLTFPBRShaderPack.mShadowShader[LLGLTFMaterial::ALPHA_MODE_OPAQUE][double_sided][planar][tex_anim].bind(); + LLRenderPass::pushShadowBatches(sCull->mShadowBatches.mDrawInfo[LLGLTFMaterial::ALPHA_MODE_OPAQUE][tex_mask][double_sided][planar][tex_anim]); + } + } + + gGL.setColorMask(true, true); + + if (&camera == LLViewerCamera::getInstance()) { // a bit hacky, this is the start of the main render frame, figure out delta between last modelview matrix and // current modelview matrix @@ -3926,7 +4133,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) gGLInverseDeltaModelView = n; } - bool occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion && !LLGLSLShader::sProfileEnabled; + bool occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion; setupHWLights(); @@ -4039,6 +4246,14 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LL_PROFILE_GPU_ZONE("renderGeomPostDeferred"); + static LLCachedControl reflection_detail(gSavedSettings, "RenderReflectionProbeLevel", 0); + + if (gCubeSnapshot && reflection_detail == 0) + { + // skip alpha, etc. passes for cube snapshots when probes are disabled + return; + } + if (gUseWireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -4062,7 +4277,6 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) // do water haze just before pre water alpha U32 water_haze_pass = LLDrawPool::POOL_ALPHA_PRE_WATER; - calcNearbyLights(camera); setupHWLights(); gGL.setSceneBlendType(LLRender::BT_ALPHA); @@ -4679,6 +4893,89 @@ void LLPipeline::renderDebug() } } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE)) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + for (U32 rigged = 0; rigged < 2; ++rigged) + { + gGLTFPBRShaderPack.mDebugShader.bind((bool)rigged); + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + for (U32 planar = 0; planar < 2; ++planar) + { + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + for (U32 alpha_mode = 0; alpha_mode < 3; ++alpha_mode) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + if (rigged) + { + LLRenderPass::pushRiggedDebugBatches(sCull->mGLTFBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + else + { + LLRenderPass::pushDebugBatches(sCull->mGLTFBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + } + + if (!double_sided) + { + for (U32 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + if (rigged) + { + LLRenderPass::pushRiggedDebugBatches(sCull->mBPBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + else + { + LLRenderPass::pushDebugBatches(sCull->mBPBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + } + } + } + } + } + } + } + + if (shader) + { + shader->bind(); + } + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_BATCH_SIZE)) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + bool planar = false; + U32 alpha_mode = LLGLTFMaterial::ALPHA_MODE_OPAQUE; + bool double_sided = false; + bool tex_anim = false; + U8 tex_mask = 0; + + for (U32 rigged = 0; rigged < 2; ++rigged) + { + gGLTFPBRShaderPack.mDebugShader.bind((bool)rigged); + if (rigged) + { + LLRenderPass::pushRiggedDebugBatches(sCull->mShadowBatches.mSkinnedDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + else + { + LLRenderPass::pushDebugBatches(sCull->mShadowBatches.mDrawInfo[alpha_mode][tex_mask][double_sided][planar][tex_anim]); + } + } + + if (shader) + { + shader->bind(); + } + } + + LL::GLTFSceneManager::instance().renderDebug(); if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) @@ -6015,6 +6312,11 @@ void LLPipeline::findReferences(LLDrawable *drawablep) LL_INFOS() << "In mBuildQ1" << LL_ENDL; } + if (std::find(mDrawableTransformQ.begin(), mDrawableTransformQ.end(), drawablep) != mDrawableTransformQ.end()) + { + LL_INFOS() << "In mDrawableTransformQ" << LL_ENDL; + } + S32 count; count = gObjectList.findReferences(drawablep); @@ -6714,34 +7016,6 @@ void LLPipeline::renderObjects(U32 type, bool texture, bool batch_texture, bool gGLLastMatrix = NULL; } -void LLPipeline::renderGLTFObjects(U32 type, bool texture, bool rigged) -{ - assertInitialized(); - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - - if (rigged) - { - mSimplePool->pushRiggedGLTFBatches(type + 1, texture); - } - else - { - mSimplePool->pushGLTFBatches(type, texture); - } - - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - - if (!rigged) - { - LL::GLTFSceneManager::instance().renderOpaque(); - } - else - { - LL::GLTFSceneManager::instance().render(true, true); - } -} - // Currently only used for shadows -Cosmic,2023-04-19 void LLPipeline::renderAlphaObjects(bool rigged) { @@ -6757,9 +7031,9 @@ void LLPipeline::renderAlphaObjects(bool rigged) U64 lastMeshId = 0; bool skipLastSkin; // for gDeferredShadowGLTFAlphaBlendProgram - const LLVOAvatar* lastAvatarGLTF = nullptr; - U64 lastMeshIdGLTF = 0; - bool skipLastSkinGLTF; + //const LLVOAvatar* lastAvatarGLTF = nullptr; + //U64 lastMeshIdGLTF = 0; + //bool skipLastSkinGLTF; auto* begin = gPipeline.beginRenderMap(type); auto* end = gPipeline.endRenderMap(type); @@ -6783,7 +7057,7 @@ void LLPipeline::renderAlphaObjects(bool rigged) LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); - LLRenderPass::pushRiggedGLTFBatch(*pparams, lastAvatarGLTF, lastMeshIdGLTF, skipLastSkinGLTF); + //LLRenderPass::pushRiggedGLTFBatch(*pparams, lastAvatarGLTF, lastMeshIdGLTF, skipLastSkinGLTF); } else { @@ -6805,7 +7079,9 @@ void LLPipeline::renderAlphaObjects(bool rigged) LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); +#if 0 LLRenderPass::pushGLTFBatch(*pparams); +#endif } else { @@ -9179,7 +9455,7 @@ void LLPipeline::bindReflectionProbes(LLGLSLShader& shader) void LLPipeline::unbindReflectionProbes(LLGLSLShader& shader) { - S32 channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP); + S32 channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); if (channel > -1 && mReflectionMapManager.mTexture.notNull()) { mReflectionMapManager.mTexture->unbind(); @@ -9259,24 +9535,6 @@ void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCa U32 saved_occlusion = sUseOcclusion; sUseOcclusion = 0; - // List of render pass types that use the prim volume as the shadow, - // ignoring textures. - static const U32 types[] = { - LLRenderPass::PASS_SIMPLE, - LLRenderPass::PASS_FULLBRIGHT, - LLRenderPass::PASS_SHINY, - LLRenderPass::PASS_BUMP, - LLRenderPass::PASS_FULLBRIGHT_SHINY, - LLRenderPass::PASS_MATERIAL, - LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, - LLRenderPass::PASS_SPECMAP, - LLRenderPass::PASS_SPECMAP_EMISSIVE, - LLRenderPass::PASS_NORMMAP, - LLRenderPass::PASS_NORMMAP_EMISSIVE, - LLRenderPass::PASS_NORMSPEC, - LLRenderPass::PASS_NORMSPEC_EMISSIVE - }; - LLGLEnable cull(GL_CULL_FACE); //enable depth clamping if available @@ -9303,22 +9561,10 @@ void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCa stop_glerror(); - struct CompareVertexBuffer - { - bool operator()(const LLDrawInfo* const& lhs, const LLDrawInfo* const& rhs) - { - return lhs->mVertexBuffer > rhs->mVertexBuffer; - } - }; - - LLVertexBuffer::unbind(); for (int j = 0; j < 2; ++j) // 0 -- static, 1 -- rigged { bool rigged = j == 1; - gDeferredShadowProgram.bind(rigged); - - gGL.diffuseColor4f(1, 1, 1, 1); S32 shadow_detail = RenderShadowDetail; @@ -9330,16 +9576,24 @@ void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCa LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); LL_PROFILE_GPU_ZONE("shadow simple"); - gGL.getTexUnit(0)->disable(); - for (U32 type : types) + bool planar = false; + bool tex_anim = false; + U8 tex_mask = 0; + for (U32 double_sided = 0; double_sided < 2; ++double_sided) { - renderObjects(type, false, false, rigged); - } - - renderGLTFObjects(LLRenderPass::PASS_GLTF_PBR, false, rigged); + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + gGLTFPBRShaderPack.mShadowShader[LLGLTFMaterial::ALPHA_MODE_OPAQUE][double_sided][planar][tex_anim].bind(rigged); + if (rigged) + { + LLRenderPass::pushRiggedShadowBatches(sCull->mShadowBatches.mSkinnedDrawInfo[LLGLTFMaterial::ALPHA_MODE_OPAQUE][tex_mask][double_sided][planar][tex_anim]); + } + else + { + LLRenderPass::pushShadowBatches(sCull->mShadowBatches.mDrawInfo[LLGLTFMaterial::ALPHA_MODE_OPAQUE][tex_mask][double_sided][planar][tex_anim]); + } + } } if (LLPipeline::sUseOcclusion > 1) @@ -9347,7 +9601,6 @@ void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCa doOcclusion(shadow_cam); } - { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); renderGeomShadow(shadow_cam); @@ -9359,80 +9612,55 @@ void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCa const S32 sun_up = LLEnvironment::instance().getIsSunUp() ? 1 : 0; U32 target_width = LLRenderTarget::sCurResX; - for (int i = 0; i < 2; ++i) { - bool rigged = i == 1; + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); + LL_PROFILE_GPU_ZONE("shadow alpha grass"); + gDeferredTreeShadowProgram.bind(); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); - LL_PROFILE_GPU_ZONE("shadow alpha masked"); - gDeferredShadowAlphaMaskProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); - LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, true, true, rigged); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); - LL_PROFILE_GPU_ZONE("shadow alpha blend"); - renderAlphaObjects(rigged); - } + renderObjects(LLRenderPass::PASS_GRASS, true); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); - LL_PROFILE_GPU_ZONE("shadow alpha masked"); - gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); - LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true, rigged); - } + // alpha mask GLTF + // NOTE: don't use "shadow" push here -- "shadow" push ignores material, but alpha mask shaders need the baseColor map + for (U32 double_sided = 0; double_sided < 2; ++double_sided) + { + LLGLDisable cull(double_sided ? GL_CULL_FACE : 0); + for (U32 rigged = 0; rigged < 2; ++rigged) { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); - LL_PROFILE_GPU_ZONE("shadow alpha grass"); - gDeferredTreeShadowProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); - - if (i == 0) + for (U32 planar = 0; planar < 2; ++planar) { - renderObjects(LLRenderPass::PASS_GRASS, true); - } + for (U32 tex_anim = 0; tex_anim < 2; ++tex_anim) + { + bool bound = false; + auto& shader = gGLTFPBRShaderPack.mShadowShader[LLGLTFMaterial::ALPHA_MODE_MASK][double_sided][planar][tex_anim]; + for (U8 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + for (U32 alpha_mode = 1; alpha_mode < 3; ++alpha_mode) // skip opaque + { + LLRenderPass::pushGLTFBatches(shader, rigged, alpha_mode, tex_mask, double_sided, planar, tex_anim); + } + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha material"); - LL_PROFILE_GPU_ZONE("shadow alpha material"); - renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, true, false, rigged); - renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, true, false, rigged); - renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, true, false, rigged); - renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, true, false, rigged); + if (!double_sided) + { // push alpha mask BP batches + auto& shader = gBPShaderPack.mShadowShader[LLGLTFMaterial::ALPHA_MODE_MASK][planar][tex_anim]; + for (U8 tex_mask = 0; tex_mask < LLGLTFBatches::MAX_PBR_TEX_MASK; ++tex_mask) + { + for (U32 alpha_mode = 1; alpha_mode < 3; ++alpha_mode) // skip opaque + { + LLRenderPass::pushBPBatches(shader, rigged, alpha_mode, tex_mask, planar, tex_anim); + } + } + } + } } } } - for (int i = 0; i < 2; ++i) - { - bool rigged = i == 1; - gDeferredShadowGLTFAlphaMaskProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); - LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - - U32 type = LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK; - - if (rigged) - { - mAlphaMaskPool->pushRiggedGLTFBatches(type + 1); - } - else - { - mAlphaMaskPool->pushGLTFBatches(type); - } - - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - } + LL::GLTFSceneManager::instance().render(false, false); + LL::GLTFSceneManager::instance().render(false, true); } gDeferredShadowCubeProgram.bind(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 9f9bd9ffe77..f5fdbb4a3a4 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -206,6 +206,9 @@ class LLPipeline void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL); void markPartitionMove(LLDrawable* drawablep); void markMeshDirty(LLSpatialGroup* group); + void markTransformDirty(LLSpatialGroup* group); + void markTransformDirty(LLDrawable* drawablep); + //get the object between start and end that's closest to start. LLViewerObject* lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end, @@ -288,7 +291,6 @@ class LLPipeline void forAllVisibleDrawables(void (*func)(LLDrawable*)); void renderObjects(U32 type, bool texture = true, bool batch_texture = false, bool rigged = false); - void renderGLTFObjects(U32 type, bool texture = true, bool rigged = false); void renderAlphaObjects(bool rigged = false); void renderMaskedObjects(U32 type, bool texture = true, bool batch_texture = false, bool rigged = false); @@ -453,7 +455,6 @@ class LLPipeline static bool getRenderHighlights(); static void setRenderHighlightTextureChannel(LLRender::eTexIndex channel); // sets which UV setup to display in highlight overlay - static void updateRenderTransparentWater(); static void refreshCachedSettings(); void addDebugBlip(const LLVector3& position, const LLColor4& color); @@ -608,7 +609,7 @@ class LLPipeline RENDER_DEBUG_TEXTURE_ANIM = 0x00001000, RENDER_DEBUG_LIGHTS = 0x00002000, RENDER_DEBUG_BATCH_SIZE = 0x00004000, - RENDER_DEBUG_ALPHA_BINS = 0x00008000, // not used + RENDER_DEBUG_SHADOW_BATCH_SIZE = 0x00008000, // not used RENDER_DEBUG_RAYCAST = 0x00010000, RENDER_DEBUG_AVATAR_DRAW_INFO = 0x00020000, RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000, @@ -657,7 +658,6 @@ class LLPipeline static S32 sUseOcclusion; // 0 = no occlusion, 1 = read only, 2 = read/write static bool sAutoMaskAlphaDeferred; static bool sAutoMaskAlphaNonDeferred; - static bool sRenderTransparentWater; static bool sBakeSunlight; static bool sNoAlpha; static bool sUseFarClip; @@ -859,7 +859,9 @@ class LLPipeline // Different queues of drawables being processed. // LLDrawable::drawable_list_t mBuildQ1; // priority + LLDrawable::drawable_list_t mDrawableTransformQ; // transform rebuilds LLSpatialGroup::sg_vector_t mGroupQ1; //priority + LLSpatialGroup::sg_vector_t mGroupTransformQ; //transform updates LLSpatialGroup::sg_vector_t mGroupSaveQ1; // a place to save mGroupQ1 until it is safe to unref diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 53615968e08..b9e816f6704 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2295,6 +2295,16 @@ function="World.EnvPreset" function="Advanced.ToggleRenderType" parameter="pbr" /> + + + + + + + + diff --git a/tail_sl_log.sh b/tail_sl_log.sh new file mode 100755 index 00000000000..b21bd456de5 --- /dev/null +++ b/tail_sl_log.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +tail -F ~/Library/Application\ Support/SecondLife/logs/SecondLife.log +