diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 76cc64f3e3..0800c27839 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -207,7 +207,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) { } } - { // Sync all the buffers + { // Sync all the transform states PROFILE_RANGE(render_gpu_gl_detail, "syncCPUTransform"); _transform._cameras.clear(); _transform._cameraOffsets.clear(); @@ -275,7 +275,7 @@ void GLBackend::renderPassDraw(const Batch& batch) { updateInput(); updateTransform(batch); updatePipeline(); - + CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); break; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 80649c4d64..84806d82c3 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -72,7 +72,6 @@ GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& incrementTextureGPUCount(); withPreservedTexture([&] { GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat()); - const Sampler& sampler = _gpuObject.getSampler(); auto numMips = _gpuObject.evalNumMips(); for (uint16_t mipLevel = 0; mipLevel < numMips; ++mipLevel) { // Get the mip level dimensions, accounting for the downgrade level diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index f0ef2ac7a8..12c4b818f7 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -18,6 +18,12 @@ Q_LOGGING_CATEGORY(gpugl45logging, "hifi.gpu.gl45") using namespace gpu; using namespace gpu::gl45; +void GL45Backend::recycle() const { + Parent::recycle(); + GL45VariableAllocationTexture::manageMemory(); + GL45VariableAllocationTexture::_frameTexturesCreated = 0; +} + void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index cfdcc356a6..6a9811b055 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -147,6 +147,7 @@ public: using TransferQueue = std::queue>; static MemoryPressureState _memoryPressureState; protected: + static size_t _frameTexturesCreated; static std::atomic _memoryPressureStateStale; static std::list _memoryManagedTextures; static WorkQueue _transferQueue; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index d5ad0204bf..36aaf75e81 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -28,6 +28,7 @@ using namespace gpu::gl; using namespace gpu::gl45; #define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f +#define MAX_RESOURCE_TEXTURES_PER_FRAME 2 GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { @@ -57,19 +58,23 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { break; case TextureUsageType::RESOURCE: { - - GL45VariableAllocationTexture* varObject { nullptr }; + if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) { #if 0 - if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) { - varObject = new GL45SparseResourceTexture(shared_from_this(), texture); - } else { - varObject = new GL45ResourceTexture(shared_from_this(), texture); - } + if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) { + object = new GL45SparseResourceTexture(shared_from_this(), texture); + } else { + object = new GL45ResourceTexture(shared_from_this(), texture); + } #else - varObject = new GL45ResourceTexture(shared_from_this(), texture); + object = new GL45ResourceTexture(shared_from_this(), texture); #endif - GL45VariableAllocationTexture::addMemoryManagedTexture(texturePointer); - object = varObject; + GL45VariableAllocationTexture::addMemoryManagedTexture(texturePointer); + } else { + auto fallback = texturePointer->getFallbackTexture(); + if (fallback) { + object = static_cast(syncGPUObject(fallback)); + } + } break; } @@ -81,11 +86,6 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { return object; } -void GL45Backend::recycle() const { - Parent::recycle(); - GL45VariableAllocationTexture::manageMemory(); -} - void GL45Backend::initTextureManagementStage() { // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 92251bd381..d54ad1ea4b 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -405,7 +405,10 @@ void GL45VariableAllocationTexture::manageMemory() { processWorkQueues(); } +size_t GL45VariableAllocationTexture::_frameTexturesCreated { 0 }; + GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture) { + ++_frameTexturesCreated; } GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 6b9087333c..5cd1ebd31f 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -412,7 +412,6 @@ void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) { // THen check that the mem texture passed make sense with its format Size expectedSize = evalStoredMipSize(level, getStoredMipFormat()); auto size = storage->size(); - auto bytes = storage->data(); if (storage->size() == expectedSize) { _storage->assignMipData(level, storage); _maxMip = std::max(_maxMip, level); @@ -442,7 +441,6 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin // THen check that the mem texture passed make sense with its format Size expectedSize = evalStoredMipFaceSize(level, getStoredMipFormat()); auto size = storage->size(); - auto bytes = storage->data(); if (size == expectedSize) { _storage->assignMipFaceData(level, face, storage); _maxMip = std::max(_maxMip, level); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index d840687af2..9996026254 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -503,6 +503,9 @@ public: const Sampler& getSampler() const { return _sampler; } Stamp getSamplerStamp() const { return _samplerStamp; } + void setFallbackTexture(const TexturePointer& fallback) { _fallback = fallback; } + TexturePointer getFallbackTexture() const { return _fallback.lock(); } + void setExternalTexture(uint32 externalId, void* externalFence); void setExternalRecycler(const ExternalRecycler& recycler); ExternalRecycler getExternalRecycler() const; @@ -526,6 +529,7 @@ protected: ExternalRecycler _externalRecycler; + std::weak_ptr _fallback; // Not strictly necessary, but incredibly useful for debugging std::string _source; std::unique_ptr< Storage > _storage; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index c7da499e98..bd34246f51 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -117,6 +117,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } auto ktxBuffer = ktx::KTX::create(header, images); +#if 0 auto expectedMipCount = texture.evalNumMips(); assert(expectedMipCount == ktxBuffer->_images.size()); assert(expectedMipCount == header.numberOfMipmapLevels); @@ -141,6 +142,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { assert(0 == memcmp(expectedFace, actualFace, expected._faceSize)); } } +#endif return ktxBuffer; } diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index cc9c1069b1..bee31e3200 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -77,7 +77,7 @@ KTX::KTX() { KTX::~KTX() { } -void KTX::resetStorage(StoragePointer& storage) { +void KTX::resetStorage(const StoragePointer& storage) { _storage = storage; } diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 7aef33704e..3ea14b2cb5 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -402,15 +402,15 @@ namespace ktx { Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) : _numFaces(1), _imageSize(imageSize), - _padding(padding), _faceSize(imageSize), + _padding(padding), _faceBytes(1, bytes) {} Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) : _numFaces(NUM_CUBEMAPFACES), _imageSize(pageSize * NUM_CUBEMAPFACES), - _padding(padding), - _faceSize(pageSize) + _faceSize(pageSize), + _padding(padding) { if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) { _faceBytes = cubeFaceBytes; @@ -420,7 +420,7 @@ namespace ktx { using Images = std::vector; class KTX { - void resetStorage(StoragePointer& src); + void resetStorage(const StoragePointer& src); KTX(); public: @@ -448,7 +448,7 @@ namespace ktx { static Images writeImages(Byte* destBytes, size_t destByteSize, const Images& images); // Parse a block of memory and create a KTX object from it - static std::unique_ptr create(StoragePointer& src); + static std::unique_ptr create(const StoragePointer& src); static bool checkHeaderFromStorage(size_t srcSize, const Byte* srcBytes); static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes); diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index d74b45c01c..f8004cf21a 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -12,6 +12,7 @@ #include #include +#include #ifndef _MSC_VER #define NOEXCEPT noexcept @@ -68,7 +69,7 @@ namespace ktx { } // find the first null character \0 - int keyLength = 0; + uint32_t keyLength = 0; while (reinterpret_cast(src[++keyLength]) != '\0') { if (keyLength == keyValueByteSize) { // key must be null-terminated, and there must be space for the value @@ -119,8 +120,8 @@ namespace ktx { return true; } - catch (ReaderException& e) { - qWarning(e.what()); + catch (const ReaderException& e) { + qWarning() << e.what(); return false; } } @@ -128,7 +129,6 @@ namespace ktx { Images KTX::parseImages(const Header& header, size_t srcSize, const Byte* srcBytes) { Images images; auto currentPtr = srcBytes; - auto numMips = header.getNumberOfLevels(); auto numFaces = header.numberOfFaces; // Keep identifying new mip as long as we can at list query the next imageSize @@ -163,7 +163,7 @@ namespace ktx { return images; } - std::unique_ptr KTX::create(StoragePointer& src) { + std::unique_ptr KTX::create(const StoragePointer& src) { if (!src) { return nullptr; } diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index 901571f804..005b8e9e45 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -105,14 +105,14 @@ namespace ktx { // Single face vs cubes if (srcImages[l]._numFaces == 1) { - auto copied = memcpy(currentPtr, srcImages[l]._faceBytes[0], imageSize); + memcpy(currentPtr, srcImages[l]._faceBytes[0], imageSize); destImages.emplace_back(Image((uint32_t) imageSize, padding, currentPtr)); currentPtr += imageSize; } else { Image::FaceBytes faceBytes(6); auto faceSize = srcImages[l]._faceSize; for (int face = 0; face < 6; face++) { - auto copied = memcpy(currentPtr, srcImages[l]._faceBytes[face], faceSize); + memcpy(currentPtr, srcImages[l]._faceBytes[face], faceSize); faceBytes[face] = currentPtr; currentPtr += faceSize; } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1f21e9e78d..f4473ceb39 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -186,6 +186,39 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } +gpu::TexturePointer getFallbackTextureForType(NetworkTexture::Type type) { + auto textureCache = DependencyManager::get(); + + gpu::TexturePointer result; + switch (type) { + case NetworkTexture::DEFAULT_TEXTURE: + case NetworkTexture::ALBEDO_TEXTURE: + case NetworkTexture::ROUGHNESS_TEXTURE: + case NetworkTexture::OCCLUSION_TEXTURE: + result = textureCache->getWhiteTexture(); + break; + + case NetworkTexture::NORMAL_TEXTURE: + result = textureCache->getBlueTexture(); + break; + + case NetworkTexture::EMISSIVE_TEXTURE: + case NetworkTexture::LIGHTMAP_TEXTURE: + result = textureCache->getBlackTexture(); + break; + + case NetworkTexture::BUMP_TEXTURE: + case NetworkTexture::SPECULAR_TEXTURE: + case NetworkTexture::GLOSS_TEXTURE: + case NetworkTexture::CUBE_TEXTURE: + case NetworkTexture::CUSTOM_TEXTURE: + case NetworkTexture::STRICT_TEXTURE: + default: + break; + } + return result; +} + NetworkTexture::TextureLoaderFunc getTextureLoaderForType(NetworkTexture::Type type, const QVariantMap& options = QVariantMap()) { @@ -299,6 +332,13 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { return getTextureLoaderForType(_type); } +gpu::TexturePointer NetworkTexture::getFallbackTexture() const { + if (_type == CUSTOM_TEXTURE) { + return gpu::TexturePointer(); + } + return getFallbackTextureForType(_type); +} + class ImageReader : public QRunnable { public: @@ -428,7 +468,11 @@ void ImageReader::run() { auto url = _url.toString().toStdString(); PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffffff00, 0); - texture.reset(resource.dynamicCast()->getTextureLoader()(image, url)); + auto networkTexture = resource.dynamicCast(); + texture.reset(networkTexture->getTextureLoader()(image, url)); + if (texture) { + texture->setFallbackTexture(networkTexture->getFallbackTexture()); + } } // Ensure the resource has not been deleted diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 749b5a2ebb..c77bafe447 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -75,6 +75,7 @@ public: Type getTextureType() const { return _type; } TextureLoaderFunc getTextureLoader() const; + gpu::TexturePointer getFallbackTexture() const; signals: void networkTextureCreated(const QWeakPointer& self); diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 23e892ba2b..4f9d57b21b 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -116,12 +116,10 @@ gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bo auto ktxMemory = gpu::Texture::serialize(*srcTexture); if (ktxMemory) { const auto& ktxStorage = ktxMemory->getStorage(); - auto header = ktxMemory->getHeader(); QFile outFile(cacheFilename.c_str()); if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) { throw std::runtime_error("Unable to open file"); } - //auto ktxSize = sizeof(ktx::Header); // ktxStorage->size() auto ktxSize = ktxStorage->size(); outFile.resize(ktxSize); auto dest = outFile.map(0, ktxSize); diff --git a/tests/ktx/src/main.cpp b/tests/ktx/src/main.cpp index 34280cb263..aa6795e17b 100644 --- a/tests/ktx/src/main.cpp +++ b/tests/ktx/src/main.cpp @@ -38,7 +38,7 @@ #include #include -#include + #include #include #include @@ -99,12 +99,10 @@ int main(int argc, char** argv) { auto ktxMemory = gpu::Texture::serialize(*testTexture); { const auto& ktxStorage = ktxMemory->getStorage(); - auto header = ktxMemory->getHeader(); QFile outFile(TEST_IMAGE_KTX); if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) { throw std::runtime_error("Unable to open file"); } - //auto ktxSize = sizeof(ktx::Header); // ktxStorage->size() auto ktxSize = ktxStorage->size(); outFile.resize(ktxSize); auto dest = outFile.map(0, ktxSize);