Merge branch 'master' of https://github.com/highfidelity/hifi into uniform-story-handling

This commit is contained in:
howard-stearns 2016-09-23 13:16:36 -07:00
commit a5fb0c9bd5
49 changed files with 1306 additions and 584 deletions

View file

@ -19,6 +19,7 @@
#include <AccountManager.h> #include <AccountManager.h>
#include <HTTPConnection.h> #include <HTTPConnection.h>
#include <LogHandler.h> #include <LogHandler.h>
#include <shared/NetworkUtils.h>
#include <NetworkingConstants.h> #include <NetworkingConstants.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <UUID.h> #include <UUID.h>

View file

@ -20,8 +20,8 @@ if (WIN32)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip URL https://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.8.0_public.zip
URL_MD5 a2dcf695e0f03a70fdd1ed7480585e82 URL_MD5 bea17e04acc1dd8cf7cabefa1b28cc3c
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""
@ -29,8 +29,8 @@ if (WIN32)
) )
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
message("LIBOVR dir ${SOURCE_DIR}")
set(LIBOVR_DIR ${SOURCE_DIR}/OculusSDK/LibOVR) set(LIBOVR_DIR ${SOURCE_DIR}/LibOVR)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL) set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL)
else() else()
@ -38,6 +38,7 @@ if (WIN32)
endif() endif()
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL)
message("LIBOVR include dir ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS}")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL)
elseif(APPLE) elseif(APPLE)

View file

@ -44,12 +44,12 @@
#include <AbstractUriHandler.h> #include <AbstractUriHandler.h>
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <ThreadSafeValueCache.h> #include <ThreadSafeValueCache.h>
#include <shared/FileLogger.h>
#include "avatar/MyAvatar.h" #include "avatar/MyAvatar.h"
#include "Bookmarks.h" #include "Bookmarks.h"
#include "Camera.h" #include "Camera.h"
#include "ConnectionMonitor.h" #include "ConnectionMonitor.h"
#include "FileLogger.h"
#include "gpu/Context.h" #include "gpu/Context.h"
#include "Menu.h" #include "Menu.h"
#include "octree/OctreePacketProcessor.h" #include "octree/OctreePacketProcessor.h"

View file

@ -58,7 +58,10 @@ void CachesSizeDialog::confirmClicked(bool checked) {
DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES); DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<ModelCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES); DependencyManager::get<ModelCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
// Disabling the texture cache because it's a liability in cases where we're overcommiting GPU memory
#if 0
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES); DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
#endif
QDialog::close(); QDialog::close();
} }
@ -78,4 +81,4 @@ void CachesSizeDialog::reject() {
void CachesSizeDialog::closeEvent(QCloseEvent* event) { void CachesSizeDialog::closeEvent(QCloseEvent* event) {
QDialog::closeEvent(event); QDialog::closeEvent(event);
emit closed(); emit closed();
} }

View file

@ -20,7 +20,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QSyntaxHighlighter> #include <QSyntaxHighlighter>
#include "AbstractLoggerInterface.h" #include <shared/AbstractLoggerInterface.h>
class KeywordHighlighter : public QSyntaxHighlighter { class KeywordHighlighter : public QSyntaxHighlighter {
Q_OBJECT Q_OBJECT

View file

@ -25,7 +25,7 @@
#include <AddressManager.h> #include <AddressManager.h>
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <avatar/MyAvatar.h> #include <avatar/MyAvatar.h>
#include <FileUtils.h> #include <shared/FileUtils.h>
#include <NodeList.h> #include <NodeList.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
#include <SharedUtil.h> #include <SharedUtil.h>

View file

@ -39,6 +39,10 @@ static GLBackend* INSTANCE{ nullptr };
static const char* GL_BACKEND_PROPERTY_NAME = "com.highfidelity.gl.backend"; static const char* GL_BACKEND_PROPERTY_NAME = "com.highfidelity.gl.backend";
BackendPointer GLBackend::createBackend() { BackendPointer GLBackend::createBackend() {
// The ATI memory info extension only exposes 'free memory' so we want to force it to
// cache the value as early as possible
getDedicatedMemory();
// FIXME provide a mechanism to override the backend for testing // FIXME provide a mechanism to override the backend for testing
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned // Where the gpuContext is initialized and where the TRUE Backend is created and assigned
auto version = QOpenGLContextWrapper::currentContextVersion(); auto version = QOpenGLContextWrapper::currentContextVersion();
@ -589,7 +593,23 @@ void GLBackend::releaseQuery(GLuint id) const {
_queriesTrash.push_back(id); _queriesTrash.push_back(id);
} }
void GLBackend::queueLambda(const std::function<void()> lambda) const {
Lock lock(_trashMutex);
_lambdaQueue.push_back(lambda);
}
void GLBackend::recycle() const { void GLBackend::recycle() const {
{
std::list<std::function<void()>> lamdbasTrash;
{
Lock lock(_trashMutex);
std::swap(_lambdaQueue, lamdbasTrash);
}
for (auto lambda : lamdbasTrash) {
lambda();
}
}
{ {
std::vector<GLuint> ids; std::vector<GLuint> ids;
std::list<std::pair<GLuint, Size>> buffersTrash; std::list<std::pair<GLuint, Size>> buffersTrash;
@ -679,6 +699,10 @@ void GLBackend::recycle() const {
glDeleteQueries((GLsizei)ids.size(), ids.data()); glDeleteQueries((GLsizei)ids.size(), ids.data());
} }
} }
#ifndef THREADED_TEXTURE_TRANSFER
gl::GLTexture::_textureTransferHelper->process();
#endif
} }
void GLBackend::setCameraCorrection(const Mat4& correction) { void GLBackend::setCameraCorrection(const Mat4& correction) {

View file

@ -175,6 +175,7 @@ public:
virtual void releaseShader(GLuint id) const; virtual void releaseShader(GLuint id) const;
virtual void releaseProgram(GLuint id) const; virtual void releaseProgram(GLuint id) const;
virtual void releaseQuery(GLuint id) const; virtual void releaseQuery(GLuint id) const;
virtual void queueLambda(const std::function<void()> lambda) const;
protected: protected:
@ -197,6 +198,7 @@ protected:
mutable std::list<GLuint> _shadersTrash; mutable std::list<GLuint> _shadersTrash;
mutable std::list<GLuint> _programsTrash; mutable std::list<GLuint> _programsTrash;
mutable std::list<GLuint> _queriesTrash; mutable std::list<GLuint> _queriesTrash;
mutable std::list<std::function<void()>> _lambdaQueue;
void renderPassTransfer(const Batch& batch); void renderPassTransfer(const Batch& batch);
void renderPassDraw(const Batch& batch); void renderPassDraw(const Batch& batch);
@ -365,6 +367,7 @@ protected:
typedef void (GLBackend::*CommandCall)(const Batch&, size_t); typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
static CommandCall _commandCalls[Batch::NUM_COMMANDS]; static CommandCall _commandCalls[Batch::NUM_COMMANDS];
friend class GLState; friend class GLState;
friend class GLTexture;
}; };
} } } }

View file

@ -165,7 +165,7 @@ void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
_uniform._buffers[slot] = uniformBuffer; _uniform._buffers[slot] = uniformBuffer;
(void) CHECK_GL_ERROR(); (void) CHECK_GL_ERROR();
} else { } else {
releaseResourceTexture(slot); releaseUniformBuffer(slot);
return; return;
} }
} }

View file

@ -60,6 +60,32 @@ bool checkGLErrorDebug(const char* name) {
#endif #endif
} }
gpu::Size getFreeDedicatedMemory() {
Size result { 0 };
static bool nvidiaMemorySupported { true };
static bool atiMemorySupported { true };
if (nvidiaMemorySupported) {
GLint nvGpuMemory { 0 };
glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &nvGpuMemory);
if (GL_NO_ERROR == glGetError()) {
result = KB_TO_BYTES(nvGpuMemory);
} else {
nvidiaMemorySupported = false;
}
} else if (atiMemorySupported) {
GLint atiGpuMemory[4];
// not really total memory, but close enough if called early enough in the application lifecycle
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory);
if (GL_NO_ERROR == glGetError()) {
result = KB_TO_BYTES(atiGpuMemory[0]);
} else {
atiMemorySupported = false;
}
}
return result;
}
gpu::Size getDedicatedMemory() { gpu::Size getDedicatedMemory() {
static Size dedicatedMemory { 0 }; static Size dedicatedMemory { 0 };
static std::once_flag once; static std::once_flag once;

View file

@ -25,6 +25,7 @@ void serverWait();
void clientWait(); void clientWait();
gpu::Size getDedicatedMemory(); gpu::Size getDedicatedMemory();
gpu::Size getFreeDedicatedMemory();
ComparisonFunction comparisonFuncFromGL(GLenum func); ComparisonFunction comparisonFuncFromGL(GLenum func);
State::StencilOp stencilOpFromGL(GLenum stencilOp); State::StencilOp stencilOpFromGL(GLenum stencilOp);
State::BlendOp blendOpFromGL(GLenum blendOp); State::BlendOp blendOpFromGL(GLenum blendOp);

View file

@ -12,9 +12,244 @@ using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; GLenum result = GL_RGBA8;
return texel; switch (dstFormat.getDimension()) {
case gpu::SCALAR: {
switch (dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
case gpu::SRGB:
case gpu::SRGBA:
switch (dstFormat.getType()) {
case gpu::UINT32:
result = GL_R32UI;
break;
case gpu::INT32:
result = GL_R32I;
break;
case gpu::NUINT32:
result = GL_R8;
break;
case gpu::NINT32:
result = GL_R8_SNORM;
break;
case gpu::FLOAT:
result = GL_R32F;
break;
case gpu::UINT16:
result = GL_R16UI;
break;
case gpu::INT16:
result = GL_R16I;
break;
case gpu::NUINT16:
result = GL_R16;
break;
case gpu::NINT16:
result = GL_R16_SNORM;
break;
case gpu::HALF:
result = GL_R16F;
break;
case gpu::UINT8:
result = GL_R8UI;
break;
case gpu::INT8:
result = GL_R8I;
break;
case gpu::NUINT8:
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
result = GL_SLUMINANCE8;
} else {
result = GL_R8;
}
break;
case gpu::NINT8:
result = GL_R8_SNORM;
break;
default:
Q_UNREACHABLE();
break;
}
break;
case gpu::COMPRESSED_R:
result = GL_COMPRESSED_RED_RGTC1;
break;
case gpu::R11G11B10:
// the type should be float
result = GL_R11F_G11F_B10F;
break;
case gpu::DEPTH:
result = GL_DEPTH_COMPONENT32;
switch (dstFormat.getType()) {
case gpu::UINT32:
case gpu::INT32:
case gpu::NUINT32:
case gpu::NINT32:
result = GL_DEPTH_COMPONENT32;
break;
case gpu::FLOAT:
result = GL_DEPTH_COMPONENT32F;
break;
case gpu::UINT16:
case gpu::INT16:
case gpu::NUINT16:
case gpu::NINT16:
case gpu::HALF:
result = GL_DEPTH_COMPONENT16;
break;
case gpu::UINT8:
case gpu::INT8:
case gpu::NUINT8:
case gpu::NINT8:
result = GL_DEPTH_COMPONENT24;
break;
default:
Q_UNREACHABLE();
break;
}
break;
case gpu::DEPTH_STENCIL:
result = GL_DEPTH24_STENCIL8;
break;
default:
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
case gpu::VEC2: {
switch (dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
result = GL_RG8;
break;
default:
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
case gpu::VEC3: {
switch (dstFormat.getSemantic()) {
case gpu::RGB:
case gpu::RGBA:
result = GL_RGB8;
break;
case gpu::SRGB:
case gpu::SRGBA:
result = GL_SRGB8; // standard 2.2 gamma correction color
break;
case gpu::COMPRESSED_RGB:
result = GL_COMPRESSED_RGB;
break;
case gpu::COMPRESSED_SRGB:
result = GL_COMPRESSED_SRGB;
break;
default:
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
case gpu::VEC4: {
switch (dstFormat.getSemantic()) {
case gpu::RGB:
result = GL_RGB8;
break;
case gpu::RGBA:
switch (dstFormat.getType()) {
case gpu::UINT32:
result = GL_RGBA32UI;
break;
case gpu::INT32:
result = GL_RGBA32I;
break;
case gpu::FLOAT:
result = GL_RGBA32F;
break;
case gpu::UINT16:
result = GL_RGBA16UI;
break;
case gpu::INT16:
result = GL_RGBA16I;
break;
case gpu::NUINT16:
result = GL_RGBA16;
break;
case gpu::NINT16:
result = GL_RGBA16_SNORM;
break;
case gpu::HALF:
result = GL_RGBA16F;
break;
case gpu::UINT8:
result = GL_RGBA8UI;
break;
case gpu::INT8:
result = GL_RGBA8I;
break;
case gpu::NUINT8:
result = GL_RGBA8;
break;
case gpu::NINT8:
result = GL_RGBA8_SNORM;
break;
case gpu::NUINT32:
case gpu::NINT32:
case gpu::NUM_TYPES: // quiet compiler
Q_UNREACHABLE();
}
break;
case gpu::SRGB:
result = GL_SRGB8;
break;
case gpu::SRGBA:
result = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
break;
case gpu::COMPRESSED_RGBA:
result = GL_COMPRESSED_RGBA;
break;
case gpu::COMPRESSED_SRGBA:
result = GL_COMPRESSED_SRGB_ALPHA;
break;
// FIXME: WE will want to support this later
/*
case gpu::COMPRESSED_BC3_RGBA:
result = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
case gpu::COMPRESSED_BC3_SRGBA:
result = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
case gpu::COMPRESSED_BC7_RGBA:
result = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
break;
case gpu::COMPRESSED_BC7_SRGBA:
result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
break;
*/
default:
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
default:
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
return result;
} }
GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {

View file

@ -21,7 +21,7 @@ public:
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) { static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) {
return evalGLTexelFormat(dstFormat, dstFormat); return evalGLTexelFormat(dstFormat, dstFormat);
} }
static GLTexelFormat evalGLTexelFormatInternal(const Element& dstFormat); static GLenum evalGLTexelFormatInternal(const Element& dstFormat);
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat); static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat);
}; };

View file

@ -17,11 +17,11 @@ using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
std::shared_ptr<GLTextureTransferHelper> GLTexture::_textureTransferHelper; std::shared_ptr<GLTextureTransferHelper> GLTexture::_textureTransferHelper;
static std::map<uint16, size_t> _textureCountByMips;
static uint16 _currentMaxMipCount { 0 };
// FIXME placeholder for texture memory over-use // FIXME placeholder for texture memory over-use
#define DEFAULT_MAX_MEMORY_MB 256 #define DEFAULT_MAX_MEMORY_MB 256
#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f
#define OVER_MEMORY_PRESSURE 2.0f
const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = { const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
@ -94,6 +94,7 @@ const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) {
return faceTargets; return faceTargets;
} }
float GLTexture::getMemoryPressure() { float GLTexture::getMemoryPressure() {
// Check for an explicit memory limit // Check for an explicit memory limit
auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage(); auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage();
@ -102,15 +103,28 @@ float GLTexture::getMemoryPressure() {
if (!availableTextureMemory) { if (!availableTextureMemory) {
auto totalGpuMemory = getDedicatedMemory(); auto totalGpuMemory = getDedicatedMemory();
// If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB
if (!totalGpuMemory) { if (!totalGpuMemory) {
// If we can't query the dedicated memory just use a fallback fixed value of 256 MB
totalGpuMemory = MB_TO_BYTES(DEFAULT_MAX_MEMORY_MB); totalGpuMemory = MB_TO_BYTES(DEFAULT_MAX_MEMORY_MB);
} else {
// Check the global free GPU memory
auto freeGpuMemory = getFreeDedicatedMemory();
if (freeGpuMemory) {
static gpu::Size lastFreeGpuMemory = 0;
auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory;
if (freeGpuMemory != lastFreeGpuMemory) {
lastFreeGpuMemory = freeGpuMemory;
if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) {
qDebug() << "Exceeded max GPU memory";
return OVER_MEMORY_PRESSURE;
}
}
}
} }
// Allow 75% of all available GPU memory to be consumed by textures // Allow 50% of all available GPU memory to be consumed by textures
// FIXME overly conservative? // FIXME overly conservative?
availableTextureMemory = (totalGpuMemory >> 2) * 3; availableTextureMemory = (totalGpuMemory >> 1);
} }
// Return the consumed texture memory divided by the available texture memory. // Return the consumed texture memory divided by the available texture memory.
@ -118,80 +132,27 @@ float GLTexture::getMemoryPressure() {
return (float)consumedGpuMemory / (float)availableTextureMemory; return (float)consumedGpuMemory / (float)availableTextureMemory;
} }
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<GLBackend>& backend, GLTexture* oldTexture) :
_backend(backend),
_size(oldTexture ? oldTexture->_size : 0),
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
_minMip(oldTexture ? oldTexture->_minMip : 0),
_maxMip(oldTexture ? oldTexture->_maxMip : 0)
{
}
GLTexture::DownsampleSource::~DownsampleSource() {
if (_texture) {
auto backend = _backend.lock();
if (backend) {
backend->releaseTexture(_texture, _size);
}
}
}
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture, bool transferrable) :
GLObject(backend, texture, id),
_storageStamp(texture.getStamp()),
_target(getGLTextureType(texture)),
_maxMip(texture.maxMip()),
_minMip(texture.minMip()),
_virtualSize(texture.evalTotalSize()),
_transferrable(transferrable),
_downsampleSource(backend, originalTexture)
{
if (_transferrable) {
uint16 mipCount = usedMipLevels();
_currentMaxMipCount = std::max(_currentMaxMipCount, mipCount);
if (!_textureCountByMips.count(mipCount)) {
_textureCountByMips[mipCount] = 1;
} else {
++_textureCountByMips[mipCount];
}
}
Backend::incrementTextureGPUCount();
Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize);
}
// Create the texture and allocate storage // Create the texture and allocate storage
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) : GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
GLTexture(backend, texture, id, nullptr, transferrable) GLObject(backend, texture, id),
_source(texture.source()),
_storageStamp(texture.getStamp()),
_target(getGLTextureType(texture)),
_internalFormat(gl::GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat())),
_maxMip(texture.maxMip()),
_minMip(texture.minMip()),
_virtualSize(texture.evalTotalSize()),
_transferrable(transferrable)
{ {
// FIXME, do during allocation auto strongBackend = _backend.lock();
//Backend::updateTextureGPUMemoryUsage(0, _size); strongBackend->recycle();
Backend::setGPUObject(texture, this); Backend::incrementTextureGPUCount();
} Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize);
// Create the texture and copy from the original higher resolution version
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
{
Q_ASSERT(_minMip >= originalTexture->_minMip);
// Set the GPU object last because that implicitly destroys the originalTexture object
Backend::setGPUObject(texture, this); Backend::setGPUObject(texture, this);
} }
GLTexture::~GLTexture() { GLTexture::~GLTexture() {
if (_transferrable) {
uint16 mipCount = usedMipLevels();
Q_ASSERT(_textureCountByMips.count(mipCount));
auto& numTexturesForMipCount = _textureCountByMips[mipCount];
--numTexturesForMipCount;
if (0 == numTexturesForMipCount) {
_textureCountByMips.erase(mipCount);
if (mipCount == _currentMaxMipCount) {
_currentMaxMipCount = (_textureCountByMips.empty() ? 0 : _textureCountByMips.rbegin()->first);
}
}
}
if (_id) { if (_id) {
auto backend = _backend.lock(); auto backend = _backend.lock();
if (backend) { if (backend) {
@ -210,6 +171,28 @@ void GLTexture::createTexture() {
}); });
} }
void GLTexture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1;
switch (_target) {
case GL_TEXTURE_2D:
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
break;
case GL_TEXTURE_CUBE_MAP:
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
break;
default:
qFatal("Unsupported texture type");
}
(void)CHECK_GL_ERROR();
glBindTexture(_target, _texture);
f();
glBindTexture(_target, boundTex);
(void)CHECK_GL_ERROR();
}
void GLTexture::setSize(GLuint size) const { void GLTexture::setSize(GLuint size) const {
Backend::updateTextureGPUMemoryUsage(_size, size); Backend::updateTextureGPUMemoryUsage(_size, size);
const_cast<GLuint&>(_size) = size; const_cast<GLuint&>(_size) = size;
@ -223,20 +206,6 @@ bool GLTexture::isOutdated() const {
return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp(); return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp();
} }
bool GLTexture::isOverMaxMemory() const {
// FIXME switch to using the max mip count used from the previous frame
if (usedMipLevels() < _currentMaxMipCount) {
return false;
}
Q_ASSERT(usedMipLevels() == _currentMaxMipCount);
if (getMemoryPressure() < 1.0f) {
return false;
}
return true;
}
bool GLTexture::isReady() const { bool GLTexture::isReady() const {
// If we have an invalid texture, we're never ready // If we have an invalid texture, we're never ready
if (isInvalid()) { if (isInvalid()) {
@ -257,11 +226,6 @@ void GLTexture::postTransfer() {
setSyncState(GLSyncState::Idle); setSyncState(GLSyncState::Idle);
++_transferCount; ++_transferCount;
//// The public gltexture becaomes available
//_id = _privateTexture;
_downsampleSource.reset();
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
switch (_gpuObject.getType()) { switch (_gpuObject.getType()) {
case Texture::TEX_2D: case Texture::TEX_2D:

View file

@ -73,14 +73,7 @@ public:
return nullptr; return nullptr;
} }
// Do we need to reduce texture memory usage? ((GLTexture*)object)->updateMips();
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
// WARNING, this code path will essentially `delete this`,
// so no dereferencing of this instance should be done past this point
object = new GLTextureType(backend.shared_from_this(), texture, object);
_textureTransferHelper->transferTexture(texturePointer);
return nullptr;
}
return object; return object;
} }
@ -96,57 +89,38 @@ public:
} else { } else {
object = Backend::getGPUObject<GLTextureType>(*texture); object = Backend::getGPUObject<GLTextureType>(*texture);
} }
if (!object) { if (!object) {
return 0; return 0;
} }
GLuint result = object->_id; if (!shouldSync) {
return object->_id;
}
// Don't return textures that are in transfer state // Don't return textures that are in transfer state
if (shouldSync) { if ((object->getSyncState() != GLSyncState::Idle) ||
if ((object->getSyncState() != GLSyncState::Idle) || // Don't return transferrable textures that have never completed transfer
// Don't return transferrable textures that have never completed transfer (!object->_transferrable || 0 != object->_transferCount)) {
(!object->_transferrable || 0 != object->_transferCount)) { return 0;
// Will be either 0 or the original texture being downsampled.
result = object->_downsampleSource._texture;
}
} }
return result; return object->_id;
}
// Used by derived classes and helpers to ensure the actual GL object exceeds the lifetime of `this`
GLuint takeOwnership() {
GLuint result = _id;
const_cast<GLuint&>(_id) = 0;
return result;
} }
~GLTexture(); ~GLTexture();
const GLuint& _texture { _id }; const GLuint& _texture { _id };
const std::string _source;
const Stamp _storageStamp; const Stamp _storageStamp;
const GLenum _target; const GLenum _target;
const GLenum _internalFormat;
const uint16 _maxMip; const uint16 _maxMip;
const uint16 _minMip; uint16 _minMip;
const GLuint _virtualSize; // theoretical size as expected const GLuint _virtualSize; // theoretical size as expected
Stamp _contentStamp { 0 }; Stamp _contentStamp { 0 };
const bool _transferrable; const bool _transferrable;
Size _transferCount { 0 }; Size _transferCount { 0 };
struct DownsampleSource {
using Pointer = std::shared_ptr<DownsampleSource>;
DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend) : _backend(backend), _size(0), _texture(0), _minMip(0), _maxMip(0) {}
DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* originalTexture);
~DownsampleSource();
void reset() const { const_cast<GLuint&>(_texture) = 0; }
const std::weak_ptr<gl::GLBackend>& _backend;
const GLuint _size { 0 };
const GLuint _texture { 0 };
const uint16 _minMip { 0 };
const uint16 _maxMip { 0 };
} _downsampleSource;
GLuint size() const { return _size; } GLuint size() const { return _size; }
GLSyncState getSyncState() const { return _syncState; } GLSyncState getSyncState() const { return _syncState; }
@ -160,9 +134,7 @@ public:
bool isReady() const; bool isReady() const;
// Execute any post-move operations that must occur only on the main thread // Execute any post-move operations that must occur only on the main thread
void postTransfer(); virtual void postTransfer();
bool isOverMaxMemory() const;
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
@ -170,33 +142,34 @@ public:
static const GLenum CUBE_FACE_LAYOUT[6]; static const GLenum CUBE_FACE_LAYOUT[6];
static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS]; static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS];
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES]; static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
protected:
static const std::vector<GLenum>& getFaceTargets(GLenum textureType);
static GLenum getGLTextureType(const Texture& texture);
// Return a floating point value indicating how much of the allowed // Return a floating point value indicating how much of the allowed
// texture memory we are currently consuming. A value of 0 indicates // texture memory we are currently consuming. A value of 0 indicates
// no texture memory usage, while a value of 1 indicates all available / allowed memory // no texture memory usage, while a value of 1 indicates all available / allowed memory
// is consumed. A value above 1 indicates that there is a problem. // is consumed. A value above 1 indicates that there is a problem.
static float getMemoryPressure(); static float getMemoryPressure();
protected:
static const std::vector<GLenum>& getFaceTargets(GLenum textureType);
static GLenum getGLTextureType(const Texture& texture);
const GLuint _size { 0 }; // true size as reported by the gl api const GLuint _size { 0 }; // true size as reported by the gl api
std::atomic<GLSyncState> _syncState { GLSyncState::Idle }; std::atomic<GLSyncState> _syncState { GLSyncState::Idle };
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable); GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable);
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, GLTexture* originalTexture);
void setSyncState(GLSyncState syncState) { _syncState = syncState; } void setSyncState(GLSyncState syncState) { _syncState = syncState; }
void createTexture(); void createTexture();
virtual void updateMips() {}
virtual void allocateStorage() const = 0; virtual void allocateStorage() const = 0;
virtual void updateSize() const = 0; virtual void updateSize() const = 0;
virtual void syncSampler() const = 0; virtual void syncSampler() const = 0;
virtual void generateMips() const = 0; virtual void generateMips() const = 0;
virtual void withPreservedTexture(std::function<void()> f) const = 0; virtual void withPreservedTexture(std::function<void()> f) const;
protected: protected:
void setSize(GLuint size) const; void setSize(GLuint size) const;
@ -207,9 +180,6 @@ protected:
virtual void finishTransfer(); virtual void finishTransfer();
private: private:
GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);
friend class GLTextureTransferHelper; friend class GLTextureTransferHelper;
friend class GLBackend; friend class GLBackend;
}; };

View file

@ -35,6 +35,8 @@ GLTextureTransferHelper::GLTextureTransferHelper() {
initialize(true, QThread::LowPriority); initialize(true, QThread::LowPriority);
// Clean shutdown on UNIX, otherwise _canvas is freed early // Clean shutdown on UNIX, otherwise _canvas is freed early
connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); }); connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); });
#else
initialize(false, QThread::LowPriority);
#endif #endif
} }
@ -43,23 +45,18 @@ GLTextureTransferHelper::~GLTextureTransferHelper() {
if (isStillRunning()) { if (isStillRunning()) {
terminate(); terminate();
} }
#else
terminate();
#endif #endif
} }
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer); GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
#ifdef THREADED_TEXTURE_TRANSFER
Backend::incrementTextureGPUTransferCount(); Backend::incrementTextureGPUTransferCount();
object->setSyncState(GLSyncState::Pending); object->setSyncState(GLSyncState::Pending);
Lock lock(_mutex); Lock lock(_mutex);
_pendingTextures.push_back(texturePointer); _pendingTextures.push_back(texturePointer);
#else
for (object->startTransfer(); object->continueTransfer(); ) { }
object->finishTransfer();
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLSyncState::Transferred);
#endif
} }
void GLTextureTransferHelper::setup() { void GLTextureTransferHelper::setup() {
@ -100,13 +97,28 @@ void GLTextureTransferHelper::shutdown() {
#endif #endif
} }
void GLTextureTransferHelper::queueExecution(VoidLambda lambda) {
Lock lock(_mutex);
_pendingCommands.push_back(lambda);
}
#define MAX_TRANSFERS_PER_PASS 2
bool GLTextureTransferHelper::process() { bool GLTextureTransferHelper::process() {
#ifdef THREADED_TEXTURE_TRANSFER // Take any new textures or commands off the queue
// Take any new textures off the queue VoidLambdaList pendingCommands;
TextureList newTransferTextures; TextureList newTransferTextures;
{ {
Lock lock(_mutex); Lock lock(_mutex);
newTransferTextures.swap(_pendingTextures); newTransferTextures.swap(_pendingTextures);
pendingCommands.swap(_pendingCommands);
}
if (!pendingCommands.empty()) {
for (auto command : pendingCommands) {
command();
}
glFlush();
} }
if (!newTransferTextures.empty()) { if (!newTransferTextures.empty()) {
@ -119,11 +131,16 @@ bool GLTextureTransferHelper::process() {
_transferringTextures.push_back(texturePointer); _transferringTextures.push_back(texturePointer);
_textureIterator = _transferringTextures.begin(); _textureIterator = _transferringTextures.begin();
} }
_transferringTextures.sort([](const gpu::TexturePointer& a, const gpu::TexturePointer& b)->bool {
return a->getSize() < b->getSize();
});
} }
// No transfers in progress, sleep // No transfers in progress, sleep
if (_transferringTextures.empty()) { if (_transferringTextures.empty()) {
#ifdef THREADED_TEXTURE_TRANSFER
QThread::usleep(1); QThread::usleep(1);
#endif
return true; return true;
} }
@ -135,7 +152,11 @@ bool GLTextureTransferHelper::process() {
qDebug() << "Texture list " << _transferringTextures.size(); qDebug() << "Texture list " << _transferringTextures.size();
} }
for (auto _textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) { size_t transferCount = 0;
for (_textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) {
if (++transferCount > MAX_TRANSFERS_PER_PASS) {
break;
}
auto texture = *_textureIterator; auto texture = *_textureIterator;
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture); GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture);
if (gltexture->continueTransfer()) { if (gltexture->continueTransfer()) {
@ -144,9 +165,9 @@ bool GLTextureTransferHelper::process() {
} }
gltexture->finishTransfer(); gltexture->finishTransfer();
glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, gltexture->_id, 0); #ifdef THREADED_TEXTURE_TRANSFER
glBlitNamedFramebuffer(_readFramebuffer, _drawFramebuffer, 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
clientWait(); clientWait();
#endif
gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp();
gltexture->updateSize(); gltexture->updateSize();
gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); gltexture->setSyncState(gpu::gl::GLSyncState::Transferred);
@ -159,6 +180,7 @@ bool GLTextureTransferHelper::process() {
_textureIterator = _transferringTextures.erase(_textureIterator); _textureIterator = _transferringTextures.erase(_textureIterator);
} }
#ifdef THREADED_TEXTURE_TRANSFER
if (!_transferringTextures.empty()) { if (!_transferringTextures.empty()) {
// Don't saturate the GPU // Don't saturate the GPU
clientWait(); clientWait();
@ -166,8 +188,7 @@ bool GLTextureTransferHelper::process() {
// Don't saturate the CPU // Don't saturate the CPU
QThread::msleep(1); QThread::msleep(1);
} }
#else
QThread::msleep(1);
#endif #endif
return true; return true;
} }

View file

@ -28,12 +28,14 @@ using TextureListIterator = TextureList::iterator;
class GLTextureTransferHelper : public GenericThread { class GLTextureTransferHelper : public GenericThread {
public: public:
using VoidLambda = std::function<void()>;
using VoidLambdaList = std::list<VoidLambda>;
using Pointer = std::shared_ptr<GLTextureTransferHelper>; using Pointer = std::shared_ptr<GLTextureTransferHelper>;
GLTextureTransferHelper(); GLTextureTransferHelper();
~GLTextureTransferHelper(); ~GLTextureTransferHelper();
void transferTexture(const gpu::TexturePointer& texturePointer); void transferTexture(const gpu::TexturePointer& texturePointer);
void queueExecution(VoidLambda lambda);
protected:
void setup() override; void setup() override;
void shutdown() override; void shutdown() override;
bool process() override; bool process() override;
@ -41,8 +43,15 @@ protected:
private: private:
#ifdef THREADED_TEXTURE_TRANSFER #ifdef THREADED_TEXTURE_TRANSFER
::gl::OffscreenContext _context; ::gl::OffscreenContext _context;
// Framebuffers / renderbuffers for forcing access to the texture on the transfer thread
GLuint _drawRenderbuffer { 0 };
GLuint _drawFramebuffer { 0 };
GLuint _readFramebuffer { 0 };
#endif
// A mutex for protecting items access on the render and transfer threads // A mutex for protecting items access on the render and transfer threads
Mutex _mutex; Mutex _mutex;
// Commands that have been submitted for execution on the texture transfer thread
VoidLambdaList _pendingCommands;
// Textures that have been submitted for transfer // Textures that have been submitted for transfer
TextureList _pendingTextures; TextureList _pendingTextures;
// Textures currently in the transfer process // Textures currently in the transfer process
@ -50,11 +59,6 @@ private:
TextureList _transferringTextures; TextureList _transferringTextures;
TextureListIterator _textureIterator; TextureListIterator _textureIterator;
// Framebuffers / renderbuffers for forcing access to the texture on the transfer thread
GLuint _drawRenderbuffer { 0 };
GLuint _drawFramebuffer { 0 };
GLuint _readFramebuffer { 0 };
#endif
}; };
} } } }

View file

@ -43,7 +43,6 @@ public:
GLuint allocate(); GLuint allocate();
public: public:
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, bool transferrable); GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, bool transferrable);
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original);
protected: protected:
void transferMip(uint16_t mipLevel, uint8_t face) const; void transferMip(uint16_t mipLevel, uint8_t face) const;
@ -52,7 +51,6 @@ public:
void updateSize() const override; void updateSize() const override;
void syncSampler() const override; void syncSampler() const override;
void generateMips() const override; void generateMips() const override;
void withPreservedTexture(std::function<void()> f) const override;
}; };

View file

@ -40,30 +40,6 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texture, bool transf
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(), transferrable) {} GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(), transferrable) {}
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {}
void GL41Texture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1;
switch (_target) {
case GL_TEXTURE_2D:
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
break;
case GL_TEXTURE_CUBE_MAP:
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
break;
default:
qFatal("Unsupported texture type");
}
(void)CHECK_GL_ERROR();
glBindTexture(_target, _texture);
f();
glBindTexture(_target, boundTex);
(void)CHECK_GL_ERROR();
}
void GL41Texture::generateMips() const { void GL41Texture::generateMips() const {
withPreservedTexture([&] { withPreservedTexture([&] {
glGenerateMipmap(_target); glGenerateMipmap(_target);
@ -147,35 +123,12 @@ void GL41Texture::startTransfer() {
glBindTexture(_target, _id); glBindTexture(_target, _id);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
if (_downsampleSource._texture) { // transfer pixels from each faces
GLuint fbo { 0 }; uint8_t numFaces = (Texture::TEX_CUBE == _gpuObject.getType()) ? CUBE_NUM_FACES : 1;
glGenFramebuffers(1, &fbo); for (uint8_t f = 0; f < numFaces; f++) {
(void)CHECK_GL_ERROR(); for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
(void)CHECK_GL_ERROR(); transferMip(i, f);
// Find the distance between the old min mip and the new one
uint16 mipOffset = _minMip - _downsampleSource._minMip;
for (uint16 i = _minMip; i <= _maxMip; ++i) {
uint16 targetMip = i - _minMip;
uint16 sourceMip = targetMip + mipOffset;
Vec3u dimensions = _gpuObject.evalMipDimensions(i);
for (GLenum target : getFaceTargets(_target)) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, _downsampleSource._texture, sourceMip);
(void)CHECK_GL_ERROR();
glCopyTexSubImage2D(target, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR();
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
} else {
// transfer pixels from each faces
uint8_t numFaces = (Texture::TEX_CUBE == _gpuObject.getType()) ? CUBE_NUM_FACES : 1;
for (uint8_t f = 0; f < numFaces; f++) {
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
transferMip(i, f);
}
} }
} }
} }

View file

@ -147,3 +147,8 @@ void GL45Backend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOf
_stats._DSNumAPIDrawcalls++; _stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL45Backend::recycle() const {
Parent::recycle();
derezTextures();
}

View file

@ -18,29 +18,6 @@ namespace gpu { namespace gl45 {
using namespace gpu::gl; using namespace gpu::gl;
struct TransferState {
GLTexture& _texture;
GLenum _internalFormat { GL_RGBA8 };
GLTexelFormat _texelFormat;
uint8_t _face { 0 };
uint16_t _mipLevel { 0 };
uint32_t _bytesPerLine { 0 };
uint32_t _bytesPerPixel { 0 };
uint32_t _bytesPerPage { 0 };
GLuint _maxSparseLevel { 0 };
uvec3 _mipDimensions;
uvec3 _mipOffset;
uvec3 _pageSize;
const uint8_t* _srcPointer { nullptr };
uvec3 currentPageSize() const;
void updateSparse();
void updateMip();
void populatePage(std::vector<uint8_t>& dest);
bool increment();
TransferState(GLTexture& texture);
};
class GL45Backend : public GLBackend { class GL45Backend : public GLBackend {
using Parent = GLBackend; using Parent = GLBackend;
// Context Backend static interface required // Context Backend static interface required
@ -53,14 +30,54 @@ public:
class GL45Texture : public GLTexture { class GL45Texture : public GLTexture {
using Parent = GLTexture; using Parent = GLTexture;
static GLuint allocate(const Texture& texture); static GLuint allocate(const Texture& texture);
static const uint32_t DEFAULT_PAGE_DIMENSION = 128;
static const uint32_t DEFAULT_MAX_SPARSE_LEVEL = 0xFFFF;
public: public:
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable); GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable);
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original);
~GL45Texture(); ~GL45Texture();
void postTransfer() override;
struct SparseInfo {
SparseInfo(GL45Texture& texture);
void maybeMakeSparse();
void update();
uvec3 getPageCounts(const uvec3& dimensions) const;
uint32_t getPageCount(const uvec3& dimensions) const;
GL45Texture& texture;
bool sparse { false };
uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION };
GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL };
uint32_t maxPages { 0 };
uint32_t pageBytes { 0 };
GLint pageDimensionsIndex { 0 };
};
struct TransferState {
TransferState(GL45Texture& texture);
uvec3 currentPageSize() const;
void updateMip();
void populatePage(std::vector<uint8_t>& dest);
bool increment();
GL45Texture& texture;
GLTexelFormat texelFormat;
uint8_t face { 0 };
uint16_t mipLevel { 0 };
uint32_t bytesPerLine { 0 };
uint32_t bytesPerPixel { 0 };
uint32_t bytesPerPage { 0 };
uvec3 mipDimensions;
uvec3 mipOffset;
const uint8_t* srcPointer { nullptr };
};
protected: protected:
void updateMips() override;
void stripToMip(uint16_t newMinMip);
void startTransfer() override; void startTransfer() override;
bool continueTransfer() override; bool continueTransfer() override;
void finishTransfer() override;
void incrementalTransfer(const uvec3& size, const gpu::Texture::PixelsPointer& mip, std::function<void(const ivec3& offset, const uvec3& size)> f) const; void incrementalTransfer(const uvec3& size, const gpu::Texture::PixelsPointer& mip, std::function<void(const ivec3& offset, const uvec3& size)> f) const;
void transferMip(uint16_t mipLevel, uint8_t face = 0) const; void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
void allocateMip(uint16_t mipLevel, uint8_t face = 0) const; void allocateMip(uint16_t mipLevel, uint8_t face = 0) const;
@ -69,12 +86,20 @@ public:
void syncSampler() const override; void syncSampler() const override;
void generateMips() const override; void generateMips() const override;
void withPreservedTexture(std::function<void()> f) const override; void withPreservedTexture(std::function<void()> f) const override;
void derez();
SparseInfo _sparseInfo;
TransferState _transferState; TransferState _transferState;
uint32_t _allocatedPages { 0 };
uint32_t _lastMipAllocatedPages { 0 };
friend class GL45Backend;
}; };
protected: protected:
void recycle() const override;
void derezTextures() const;
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;

View file

@ -17,6 +17,7 @@
#include <glm/gtx/component_wise.hpp> #include <glm/gtx/component_wise.hpp>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtCore/QProcessEnvironment>
#include "../gl/GLTexelFormat.h" #include "../gl/GLTexelFormat.h"
@ -24,79 +25,191 @@ using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
using namespace gpu::gl45; using namespace gpu::gl45;
#define SPARSE_TEXTURES 1 #ifdef Q_OS_WIN
static const QString DEBUG_FLAG("HIFI_DISABLE_SPARSE_TEXTURES");
static bool enableSparseTextures = !QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
#else
static bool enableSparseTextures = false;
#endif
// Allocate 1 MB of buffer space for paged transfers // Allocate 1 MB of buffer space for paged transfers
#define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024)
#define DEFAULT_GL_PIXEL_ALIGNMENT 4
using GL45Texture = GL45Backend::GL45Texture; using GL45Texture = GL45Backend::GL45Texture;
static std::map<uint16_t, std::unordered_set<GL45Texture*>> texturesByMipCounts;
static Mutex texturesByMipCountsMutex;
using TextureTypeFormat = std::pair<GLenum, GLenum>;
std::map<TextureTypeFormat, std::vector<uvec3>> sparsePageDimensionsByFormat;
Mutex sparsePageDimensionsByFormatMutex;
static std::vector<uvec3> getPageDimensionsForFormat(const TextureTypeFormat& typeFormat) {
{
Lock lock(sparsePageDimensionsByFormatMutex);
if (sparsePageDimensionsByFormat.count(typeFormat)) {
return sparsePageDimensionsByFormat[typeFormat];
}
}
GLint count = 0;
glGetInternalformativ(typeFormat.first, typeFormat.second, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, 1, &count);
std::vector<uvec3> result;
if (count > 0) {
std::vector<GLint> x, y, z;
x.resize(count);
glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_X_ARB, 1, &x[0]);
y.resize(count);
glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_Y_ARB, 1, &y[0]);
z.resize(count);
glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_Z_ARB, 1, &z[0]);
result.resize(count);
for (GLint i = 0; i < count; ++i) {
result[i] = uvec3(x[i], y[i], z[i]);
}
qCDebug(gpugl45logging) << "Got " << count << " page sizes";
}
{
Lock lock(sparsePageDimensionsByFormatMutex);
if (0 == sparsePageDimensionsByFormat.count(typeFormat)) {
sparsePageDimensionsByFormat[typeFormat] = result;
}
}
return result;
}
static std::vector<uvec3> getPageDimensionsForFormat(GLenum target, GLenum format) {
return getPageDimensionsForFormat({ target, format });
}
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
return GL45Texture::sync<GL45Texture>(*this, texture, transfer); return GL45Texture::sync<GL45Texture>(*this, texture, transfer);
} }
TransferState::TransferState(GLTexture& texture) : _texture(texture) { using SparseInfo = GL45Backend::GL45Texture::SparseInfo;
SparseInfo::SparseInfo(GL45Texture& texture)
: texture(texture) {
} }
void TransferState::updateSparse() { void SparseInfo::maybeMakeSparse() {
glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); // Don't enable sparse for objects with explicitly managed mip levels
_internalFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), _texture._gpuObject.getTexelFormat()).internalFormat; if (!texture._gpuObject.isAutogenerateMips()) {
ivec3 pageSize; qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << texture._source.c_str();
glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_X_ARB, 1, &pageSize.x);
glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_Y_ARB, 1, &pageSize.y);
glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_Z_ARB, 1, &pageSize.z);
_pageSize = uvec3(pageSize);
}
void TransferState::updateMip() {
_mipDimensions = _texture._gpuObject.evalMipDimensions(_mipLevel);
_mipOffset = uvec3();
if (!_texture._gpuObject.isStoredMipFaceAvailable(_mipLevel, _face)) {
_srcPointer = nullptr;
return; return;
} }
auto mip = _texture._gpuObject.accessStoredMipFace(_mipLevel, _face); const uvec3 dimensions = texture._gpuObject.getDimensions();
_texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), mip->getFormat()); auto allowedPageDimensions = getPageDimensionsForFormat(texture._target, texture._internalFormat);
_srcPointer = mip->readData(); // In order to enable sparse the texture size must be an integer multiple of the page size
_bytesPerLine = (uint32_t)mip->getSize() / _mipDimensions.y; for (size_t i = 0; i < allowedPageDimensions.size(); ++i) {
_bytesPerPixel = _bytesPerLine / _mipDimensions.x; pageDimensionsIndex = (uint32_t) i;
pageDimensions = allowedPageDimensions[i];
// Is this texture an integer multiple of page dimensions?
if (uvec3(0) == (dimensions % pageDimensions)) {
qCDebug(gpugl45logging) << "Enabling sparse for texture " << texture._source.c_str();
sparse = true;
break;
}
}
if (sparse) {
glTextureParameteri(texture._id, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
glTextureParameteri(texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, pageDimensionsIndex);
} else {
qCDebug(gpugl45logging) << "Size " << dimensions.x << " x " << dimensions.y <<
" is not supported by any sparse page size for texture" << texture._source.c_str();
}
}
// This can only be called after we've established our storage size
void SparseInfo::update() {
if (!sparse) {
return;
}
glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel);
pageBytes = texture._gpuObject.getTexelFormat().getSize();
pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z;
for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) {
auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel);
auto mipPageCount = getPageCount(mipDimensions);
maxPages += mipPageCount;
}
if (texture._target == GL_TEXTURE_CUBE_MAP) {
maxPages *= GLTexture::CUBE_NUM_FACES;
}
}
uvec3 SparseInfo::getPageCounts(const uvec3& dimensions) const {
auto result = (dimensions / pageDimensions) +
glm::clamp(dimensions % pageDimensions, glm::uvec3(0), glm::uvec3(1));
return result;
}
uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const {
auto pageCounts = getPageCounts(dimensions);
return pageCounts.x * pageCounts.y * pageCounts.z;
}
using TransferState = GL45Backend::GL45Texture::TransferState;
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
}
void TransferState::updateMip() {
mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel);
mipOffset = uvec3();
if (!texture._gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
srcPointer = nullptr;
return;
}
auto mip = texture._gpuObject.accessStoredMipFace(mipLevel, face);
texelFormat = gl::GLTexelFormat::evalGLTexelFormat(texture._gpuObject.getTexelFormat(), mip->getFormat());
srcPointer = mip->readData();
bytesPerLine = (uint32_t)mip->getSize() / mipDimensions.y;
bytesPerPixel = bytesPerLine / mipDimensions.x;
} }
bool TransferState::increment() { bool TransferState::increment() {
if ((_mipOffset.x + _pageSize.x) < _mipDimensions.x) { const SparseInfo& sparse = texture._sparseInfo;
_mipOffset.x += _pageSize.x; if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) {
mipOffset.x += sparse.pageDimensions.x;
return true; return true;
} }
if ((_mipOffset.y + _pageSize.y) < _mipDimensions.y) { if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) {
_mipOffset.x = 0; mipOffset.x = 0;
_mipOffset.y += _pageSize.y; mipOffset.y += sparse.pageDimensions.y;
return true; return true;
} }
if (_mipOffset.z + _pageSize.z < _mipDimensions.z) { if (mipOffset.z + sparse.pageDimensions.z < mipDimensions.z) {
_mipOffset.x = 0; mipOffset.x = 0;
_mipOffset.y = 0; mipOffset.y = 0;
++_mipOffset.z; ++mipOffset.z;
return true; return true;
} }
// Done with this mip?, move on to the next mip // Done with this mip?, move on to the next mip
if (_mipLevel + 1 < _texture.usedMipLevels()) { if (mipLevel + 1 < texture.usedMipLevels()) {
_mipOffset = uvec3(0); mipOffset = uvec3(0);
++_mipLevel; ++mipLevel;
updateMip(); updateMip();
return true; return true;
} }
uint8_t maxFace = (uint8_t)((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); uint8_t maxFace = (uint8_t)((texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
uint8_t nextFace = _face + 1; uint8_t nextFace = face + 1;
// Done with this face? Move on to the next // Done with this face? Move on to the next
if (nextFace < maxFace) { if (nextFace < maxFace) {
++_face; ++face;
_mipOffset = uvec3(0); mipOffset = uvec3(0);
_mipLevel = 0; mipLevel = 0;
updateMip(); updateMip();
return true; return true;
} }
@ -104,10 +217,9 @@ bool TransferState::increment() {
return false; return false;
} }
#define DEFAULT_GL_PIXEL_ALIGNMENT 4
void TransferState::populatePage(std::vector<uint8_t>& buffer) { void TransferState::populatePage(std::vector<uint8_t>& buffer) {
uvec3 pageSize = currentPageSize(); uvec3 pageSize = currentPageSize();
auto bytesPerPageLine = _bytesPerPixel * pageSize.x; auto bytesPerPageLine = bytesPerPixel * pageSize.x;
if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) {
bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT);
assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT));
@ -118,14 +230,14 @@ void TransferState::populatePage(std::vector<uint8_t>& buffer) {
} }
uint8_t* dst = &buffer[0]; uint8_t* dst = &buffer[0];
for (uint32_t y = 0; y < pageSize.y; ++y) { for (uint32_t y = 0; y < pageSize.y; ++y) {
uint32_t srcOffset = (_bytesPerLine * (_mipOffset.y + y)) + (_bytesPerPixel * _mipOffset.x); uint32_t srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x);
uint32_t dstOffset = bytesPerPageLine * y; uint32_t dstOffset = bytesPerPageLine * y;
memcpy(dst + dstOffset, _srcPointer + srcOffset, pageSize.x * _bytesPerPixel); memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel);
} }
} }
uvec3 TransferState::currentPageSize() const { uvec3 TransferState::currentPageSize() const {
return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _pageSize); return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions);
} }
GLuint GL45Texture::allocate(const Texture& texture) { GLuint GL45Texture::allocate(const Texture& texture) {
@ -139,25 +251,64 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
} }
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
: GLTexture(backend, texture, allocate(texture), transferrable), _transferState(*this) { : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) {
#if SPARSE_TEXTURES if (enableSparseTextures && _transferrable) {
if (transferrable) { _sparseInfo.maybeMakeSparse();
glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE);
} }
#endif
} }
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
: GLTexture(backend, texture, allocate(texture), original), _transferState(*this) { }
GL45Texture::~GL45Texture() { GL45Texture::~GL45Texture() {
// FIXME do we need to explicitly deallocate the virtual memory here? qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str();
//if (_transferrable) { if (_sparseInfo.sparse) {
// for (uint16_t mipLevel = 0; mipLevel < usedMipLevels(); ++i) { // Remove this texture from the candidate list of derezzable textures
// glTexturePageCommitmentEXT(_id, mipLevel, offset.x, offset.y, offset.z, size.x, size.y, size.z, GL_TRUE); {
// } auto mipLevels = usedMipLevels();
//} Lock lock(texturesByMipCountsMutex);
if (texturesByMipCounts.count(mipLevels)) {
auto& textures = texturesByMipCounts[mipLevels];
textures.erase(this);
if (textures.empty()) {
texturesByMipCounts.erase(mipLevels);
}
}
}
// Experimenation suggests that allocating sparse textures on one context/thread and deallocating
// them on another is buggy. So for sparse textures we need to queue a lambda with the deallocation
// callls to the transfer thread
auto id = _id;
// Set the class _id to 0 so we don't try to double delete
const_cast<GLuint&>(_id) = 0;
std::list<std::function<void()>> destructionFunctions;
uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
auto maxSparseMip = std::min<uint16_t>(_maxMip, _sparseInfo.maxSparseLevel);
for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) {
auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel);
destructionFunctions.push_back([id, maxFace, mipLevel, mipDimensions] {
glTexturePageCommitmentEXT(id, mipLevel, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE);
});
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
assert(deallocatedPages <= _allocatedPages);
_allocatedPages -= deallocatedPages;
}
if (0 != _allocatedPages) {
qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages;
}
auto size = _size;
_textureTransferHelper->queueExecution([id, size, destructionFunctions] {
for (auto function : destructionFunctions) {
function();
}
glDeleteTextures(1, &id);
Backend::decrementTextureGPUCount();
Backend::updateTextureGPUMemoryUsage(size, 0);
});
}
} }
void GL45Texture::withPreservedTexture(std::function<void()> f) const { void GL45Texture::withPreservedTexture(std::function<void()> f) const {
@ -165,37 +316,38 @@ void GL45Texture::withPreservedTexture(std::function<void()> f) const {
} }
void GL45Texture::generateMips() const { void GL45Texture::generateMips() const {
qCDebug(gpugl45logging) << "Generating mipmaps for " << _source.c_str();
glGenerateTextureMipmap(_id); glGenerateTextureMipmap(_id);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL45Texture::allocateStorage() const { void GL45Texture::allocateStorage() const {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
if (_gpuObject.getTexelFormat().isCompressed()) { if (_gpuObject.getTexelFormat().isCompressed()) {
qFatal("Compressed textures not yet supported"); qFatal("Compressed textures not yet supported");
} }
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
// Get the dimensions, accounting for the downgrade level // Get the dimensions, accounting for the downgrade level
Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip);
glTextureStorage2D(_id, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y); glTextureStorage2D(_id, usedMipLevels(), _internalFormat, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }
void GL45Texture::updateSize() const { void GL45Texture::updateSize() const {
setSize(_virtualSize);
if (!_id) {
return;
}
if (_gpuObject.getTexelFormat().isCompressed()) { if (_gpuObject.getTexelFormat().isCompressed()) {
qFatal("Compressed textures not yet supported"); qFatal("Compressed textures not yet supported");
} }
if (_transferrable) {
setSize(_allocatedPages * _sparseInfo.pageBytes);
} else {
setSize(_virtualSize);
}
} }
void GL45Texture::startTransfer() { void GL45Texture::startTransfer() {
Parent::startTransfer(); Parent::startTransfer();
_transferState.updateSparse(); _sparseInfo.update();
_transferState.updateMip(); _transferState.updateMip();
} }
@ -204,48 +356,65 @@ bool GL45Texture::continueTransfer() {
if (buffer.empty()) { if (buffer.empty()) {
buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
} }
uvec3 pageSize = _transferState.currentPageSize(); const uvec3 pageSize = _transferState.currentPageSize();
uvec3 offset = _transferState._mipOffset; const uvec3& offset = _transferState.mipOffset;
#if SPARSE_TEXTURES if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) {
if (_transferState._mipLevel <= _transferState._maxSparseLevel) { if (_allocatedPages > _sparseInfo.maxPages) {
glTexturePageCommitmentEXT(_id, _transferState._mipLevel, qCWarning(gpugl45logging) << "Exceeded max page allocation!";
offset.x, offset.y, _transferState._face, }
glTexturePageCommitmentEXT(_id, _transferState.mipLevel,
offset.x, offset.y, _transferState.face,
pageSize.x, pageSize.y, pageSize.z, pageSize.x, pageSize.y, pageSize.z,
GL_TRUE); GL_TRUE);
++_allocatedPages;
} }
#endif
if (_transferState._srcPointer) { if (_transferState.srcPointer) {
// Transfer the mip data // Transfer the mip data
_transferState.populatePage(buffer); _transferState.populatePage(buffer);
if (GL_TEXTURE_2D == _target) { if (GL_TEXTURE_2D == _target) {
glTextureSubImage2D(_id, _transferState._mipLevel, glTextureSubImage2D(_id, _transferState.mipLevel,
offset.x, offset.y, offset.x, offset.y,
pageSize.x, pageSize.y, pageSize.x, pageSize.y,
_transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]);
} else if (GL_TEXTURE_CUBE_MAP == _target) { } else if (GL_TEXTURE_CUBE_MAP == _target) {
auto target = CUBE_FACE_LAYOUT[_transferState._face]; auto target = CUBE_FACE_LAYOUT[_transferState.face];
// DSA ARB does not work on AMD, so use EXT // DSA ARB does not work on AMD, so use EXT
// glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
glTextureSubImage2DEXT(_id, target, _transferState._mipLevel, glTextureSubImage2DEXT(_id, target, _transferState.mipLevel,
offset.x, offset.y, offset.x, offset.y,
pageSize.x, pageSize.y, pageSize.x, pageSize.y,
_transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]);
} }
} }
serverWait(); serverWait();
return _transferState.increment(); auto currentMip = _transferState.mipLevel;
auto result = _transferState.increment();
if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) {
auto mipDimensions = _gpuObject.evalMipDimensions(currentMip);
auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions);
auto newPages = _allocatedPages - _lastMipAllocatedPages;
if (newPages != mipExpectedPages) {
qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages;
}
_lastMipAllocatedPages = _allocatedPages;
}
return result;
} }
void GL45Backend::GL45Texture::syncSampler() const { void GL45Texture::finishTransfer() {
Parent::finishTransfer();
}
void GL45Texture::syncSampler() const {
const Sampler& sampler = _gpuObject.getSampler(); const Sampler& sampler = _gpuObject.getSampler();
const auto& fm = FILTER_MODES[sampler.getFilter()]; const auto& fm = FILTER_MODES[sampler.getFilter()];
glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) { if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
@ -257,9 +426,131 @@ void GL45Backend::GL45Texture::syncSampler() const {
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), _minMip);
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip);
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
} }
void GL45Texture::postTransfer() {
Parent::postTransfer();
if (_sparseInfo.sparse) {
auto mipLevels = usedMipLevels();
if (mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) {
Lock lock(texturesByMipCountsMutex);
texturesByMipCounts[mipLevels].insert(this);
}
}
}
void GL45Texture::stripToMip(uint16_t newMinMip) {
if (!_sparseInfo.sparse) {
return;
}
if (newMinMip < _minMip) {
qCWarning(gpugl45logging) << "Cannot decrease the min mip";
return;
}
if (newMinMip > _sparseInfo.maxSparseLevel) {
qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail";
return;
}
auto mipLevels = usedMipLevels();
{
Lock lock(texturesByMipCountsMutex);
assert(0 != texturesByMipCounts.count(mipLevels));
assert(0 != texturesByMipCounts[mipLevels].count(this));
texturesByMipCounts[mipLevels].erase(this);
if (texturesByMipCounts[mipLevels].empty()) {
texturesByMipCounts.erase(mipLevels);
}
}
// If we weren't generating mips before, we need to now that we're stripping down mip levels.
if (!_gpuObject.isAutogenerateMips()) {
qCDebug(gpugl45logging) << "Force mip generation for texture";
glGenerateTextureMipmap(_id);
}
uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
for (uint16_t mip = _minMip; mip < newMinMip; ++mip) {
auto id = _id;
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
_textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] {
glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE);
});
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
assert(deallocatedPages < _allocatedPages);
_allocatedPages -= deallocatedPages;
}
_minMip = newMinMip;
// Re-sync the sampler to force access to the new mip level
syncSampler();
size_t oldSize = _size;
updateSize();
Q_ASSERT(_size > oldSize);
// Re-insert into the texture-by-mips map if appropriate
mipLevels = usedMipLevels();
if (_sparseInfo.sparse && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) {
Lock lock(texturesByMipCountsMutex);
texturesByMipCounts[mipLevels].insert(this);
}
}
void GL45Texture::updateMips() {
if (!_sparseInfo.sparse) {
return;
}
auto newMinMip = std::min<uint16_t>(_gpuObject.minMip(), _sparseInfo.maxSparseLevel);
if (_minMip < newMinMip) {
stripToMip(newMinMip);
}
}
void GL45Texture::derez() {
assert(_sparseInfo.sparse);
assert(_minMip < _sparseInfo.maxSparseLevel);
assert(_minMip < _maxMip);
assert(_transferrable);
stripToMip(_minMip + 1);
}
void GL45Backend::derezTextures() const {
if (GLTexture::getMemoryPressure() < 1.0f) {
return;
}
Lock lock(texturesByMipCountsMutex);
if (texturesByMipCounts.empty()) {
qCDebug(gpugl45logging) << "No available textures to derez";
return;
}
auto mipLevel = texturesByMipCounts.rbegin()->first;
if (mipLevel <= 1) {
qCDebug(gpugl45logging) << "Max mip levels " << mipLevel;
return;
}
qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage();
qCDebug(gpugl45logging) << "Used texture memory " << Context::getTextureGPUMemoryUsage();
GL45Texture* targetTexture = nullptr;
{
auto& textures = texturesByMipCounts[mipLevel];
assert(!textures.empty());
targetTexture = *textures.begin();
}
lock.unlock();
targetTexture->derez();
qCDebug(gpugl45logging) << "New Used texture memory " << Context::getTextureGPUMemoryUsage();
}

View file

@ -10,6 +10,7 @@
// //
#include "Context.h" #include "Context.h"
#include "Frame.h" #include "Frame.h"
#include "GPULogging.h"
using namespace gpu; using namespace gpu;
Context::CreateBackend Context::_createBackendCallback = nullptr; Context::CreateBackend Context::_createBackendCallback = nullptr;
@ -161,8 +162,9 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S
} }
// Counters for Buffer and Texture usage in GPU/Context // Counters for Buffer and Texture usage in GPU/Context
std::atomic<uint32_t> Context::_bufferGPUCount{ 0 }; std::atomic<uint32_t> Context::_fenceCount { 0 };
std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage{ 0 }; std::atomic<uint32_t> Context::_bufferGPUCount { 0 };
std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage { 0 };
std::atomic<uint32_t> Context::_textureGPUCount{ 0 }; std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 }; std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
@ -170,10 +172,15 @@ std::atomic<Texture::Size> Context::_textureGPUVirtualMemoryUsage{ 0 };
std::atomic<uint32_t> Context::_textureGPUTransferCount{ 0 }; std::atomic<uint32_t> Context::_textureGPUTransferCount{ 0 };
void Context::incrementBufferGPUCount() { void Context::incrementBufferGPUCount() {
_bufferGPUCount++; static std::atomic<uint32_t> max { 0 };
auto total = ++_bufferGPUCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU buffers " << total;
}
} }
void Context::decrementBufferGPUCount() { void Context::decrementBufferGPUCount() {
_bufferGPUCount--; --_bufferGPUCount;
} }
void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
if (prevObjectSize == newObjectSize) { if (prevObjectSize == newObjectSize) {
@ -186,12 +193,30 @@ void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize
} }
} }
void Context::incrementFenceCount() {
static std::atomic<uint32_t> max { 0 };
auto total = ++_fenceCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max Fences " << total;
}
}
void Context::decrementFenceCount() {
--_fenceCount;
}
void Context::incrementTextureGPUCount() { void Context::incrementTextureGPUCount() {
_textureGPUCount++; static std::atomic<uint32_t> max { 0 };
auto total = ++_textureGPUCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU textures " << total;
}
} }
void Context::decrementTextureGPUCount() { void Context::decrementTextureGPUCount() {
_textureGPUCount--; --_textureGPUCount;
} }
void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
if (prevObjectSize == newObjectSize) { if (prevObjectSize == newObjectSize) {
return; return;
@ -215,10 +240,15 @@ void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newOb
} }
void Context::incrementTextureGPUTransferCount() { void Context::incrementTextureGPUTransferCount() {
_textureGPUTransferCount++; static std::atomic<uint32_t> max { 0 };
auto total = ++_textureGPUTransferCount;
if (total > max.load()) {
max = total;
qCDebug(gpulogging) << "New max GPU textures transfers" << total;
}
} }
void Context::decrementTextureGPUTransferCount() { void Context::decrementTextureGPUTransferCount() {
_textureGPUTransferCount--; --_textureGPUTransferCount;
} }
uint32_t Context::getBufferGPUCount() { uint32_t Context::getBufferGPUCount() {

View file

@ -230,6 +230,9 @@ protected:
static void decrementBufferGPUCount(); static void decrementBufferGPUCount();
static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
static void incrementFenceCount();
static void decrementFenceCount();
static void incrementTextureGPUCount(); static void incrementTextureGPUCount();
static void decrementTextureGPUCount(); static void decrementTextureGPUCount();
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
@ -237,7 +240,9 @@ protected:
static void incrementTextureGPUTransferCount(); static void incrementTextureGPUTransferCount();
static void decrementTextureGPUTransferCount(); static void decrementTextureGPUTransferCount();
// Buffer and Texture Counters // Buffer, Texture and Fence Counters
static std::atomic<uint32_t> _fenceCount;
static std::atomic<uint32_t> _bufferGPUCount; static std::atomic<uint32_t> _bufferGPUCount;
static std::atomic<Size> _bufferGPUMemoryUsage; static std::atomic<Size> _bufferGPUMemoryUsage;

View file

@ -32,6 +32,7 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width,
auto framebuffer = Framebuffer::create(); auto framebuffer = Framebuffer::create();
auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
colorTexture->setSource("Framebuffer::colorTexture");
framebuffer->setRenderBuffer(0, colorTexture); framebuffer->setRenderBuffer(0, colorTexture);
@ -42,8 +43,9 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format&
auto framebuffer = Framebuffer::create(); auto framebuffer = Framebuffer::create();
auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
colorTexture->setSource("Framebuffer::colorTexture");
auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT)));
depthTexture->setSource("Framebuffer::depthTexture");
framebuffer->setRenderBuffer(0, colorTexture); framebuffer->setRenderBuffer(0, colorTexture);
framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat); framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat);
@ -55,7 +57,7 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) {
auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format
auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width)); auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width));
depthTexture->setSource("Framebuffer::shadowMap");
Sampler::Desc samplerDesc; Sampler::Desc samplerDesc;
samplerDesc._borderColor = glm::vec4(1.0f); samplerDesc._borderColor = glm::vec4(1.0f);
samplerDesc._wrapModeU = Sampler::WRAP_BORDER; samplerDesc._wrapModeU = Sampler::WRAP_BORDER;
@ -113,30 +115,6 @@ void Framebuffer::updateSize(const TexturePointer& texture) {
} }
} }
void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) {
if (width && height && numSamples && !isEmpty() && !isSwapchain()) {
if ((width != _width) || (height != _height) || (numSamples != _numSamples)) {
for (uint32 i = 0; i < _renderBuffers.size(); ++i) {
if (_renderBuffers[i]) {
_renderBuffers[i]._texture->resize2D(width, height, numSamples);
_numSamples = _renderBuffers[i]._texture->getNumSamples();
++_colorStamps[i];
}
}
if (_depthStencilBuffer) {
_depthStencilBuffer._texture->resize2D(width, height, numSamples);
_numSamples = _depthStencilBuffer._texture->getNumSamples();
++_depthStamp;
}
_width = width;
_height = height;
// _numSamples = numSamples;
}
}
}
uint16 Framebuffer::getWidth() const { uint16 Framebuffer::getWidth() const {
if (isSwapchain()) { if (isSwapchain()) {
return getSwapchain()->getWidth(); return getSwapchain()->getWidth();

View file

@ -130,9 +130,6 @@ public:
float getAspectRatio() const { return getWidth() / (float) getHeight() ; } float getAspectRatio() const { return getWidth() / (float) getHeight() ; }
// If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call
void resize( uint16 width, uint16 height, uint16 samples = 1 );
static const uint32 MAX_NUM_RENDER_BUFFERS = 8; static const uint32 MAX_NUM_RENDER_BUFFERS = 8;
static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; }

View file

@ -389,6 +389,8 @@ public:
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
const std::string& source() const { return _source; }
void setSource(const std::string& source) { _source = source; }
bool setMinMip(uint16 newMinMip); bool setMinMip(uint16 newMinMip);
bool incremementMinMip(uint16 count = 1); bool incremementMinMip(uint16 count = 1);
@ -450,6 +452,8 @@ public:
const GPUObjectPointer gpuObject {}; const GPUObjectPointer gpuObject {};
protected: protected:
// Not strictly necessary, but incredibly useful for debugging
std::string _source;
std::unique_ptr< Storage > _storage; std::unique_ptr< Storage > _storage;
Stamp _stamp = 0; Stamp _stamp = 0;

View file

@ -35,8 +35,7 @@
#include "ModelNetworkingLogging.h" #include "ModelNetworkingLogging.h"
TextureCache::TextureCache() { TextureCache::TextureCache() {
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; setUnusedResourceCacheSize(0);
setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE);
setObjectName("TextureCache"); setObjectName("TextureCache");
// Expose enum Type to JS/QML via properties // Expose enum Type to JS/QML via properties
@ -118,6 +117,7 @@ const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF };
const gpu::TexturePointer& TextureCache::getWhiteTexture() { const gpu::TexturePointer& TextureCache::getWhiteTexture() {
if (!_whiteTexture) { if (!_whiteTexture) {
_whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
_whiteTexture->setSource("TextureCache::_whiteTexture");
_whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE); _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE);
} }
return _whiteTexture; return _whiteTexture;
@ -126,6 +126,7 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() {
const gpu::TexturePointer& TextureCache::getGrayTexture() { const gpu::TexturePointer& TextureCache::getGrayTexture() {
if (!_grayTexture) { if (!_grayTexture) {
_grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
_grayTexture->setSource("TextureCache::_grayTexture");
_grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY); _grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY);
} }
return _grayTexture; return _grayTexture;
@ -134,6 +135,7 @@ const gpu::TexturePointer& TextureCache::getGrayTexture() {
const gpu::TexturePointer& TextureCache::getBlueTexture() { const gpu::TexturePointer& TextureCache::getBlueTexture() {
if (!_blueTexture) { if (!_blueTexture) {
_blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
_blueTexture->setSource("TextureCache::_blueTexture");
_blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE); _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE);
} }
return _blueTexture; return _blueTexture;
@ -142,6 +144,7 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() {
const gpu::TexturePointer& TextureCache::getBlackTexture() { const gpu::TexturePointer& TextureCache::getBlackTexture() {
if (!_blackTexture) { if (!_blackTexture) {
_blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
_blackTexture->setSource("TextureCache::_blackTexture");
_blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK); _blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK);
} }
return _blackTexture; return _blackTexture;

View file

@ -176,7 +176,7 @@ void generateFaceMips(gpu::Texture* texture, QImage& image, gpu::Element formatM
#endif #endif
} }
gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) { gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips) {
bool validAlpha = false; bool validAlpha = false;
bool alphaAsMask = true; bool alphaAsMask = true;
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask); QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
@ -189,7 +189,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
auto usage = gpu::Texture::Usage::Builder().withColor(); auto usage = gpu::Texture::Usage::Builder().withColor();
if (validAlpha) { if (validAlpha) {
usage.withAlpha(); usage.withAlpha();
@ -210,20 +210,20 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
} }
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
return process2DTextureColorFromImage(srcImage, false, false, true); return process2DTextureColorFromImage(srcImage, srcImageName, false, false, true);
} }
gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
return process2DTextureColorFromImage(srcImage, false, true, true); return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true);
} }
gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
return process2DTextureColorFromImage(srcImage, false, true, true); return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true);
} }
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
return process2DTextureColorFromImage(srcImage, false, true, true); return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true);
} }
@ -241,6 +241,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
generateMips(theTexture, image, formatMip); generateMips(theTexture, image, formatMip);
} }
@ -324,6 +325,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
generateMips(theTexture, image, formatMip); generateMips(theTexture, image, formatMip);
} }
@ -355,6 +357,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
generateMips(theTexture, image, formatMip); generateMips(theTexture, image, formatMip);
@ -392,6 +395,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
generateMips(theTexture, image, formatMip); generateMips(theTexture, image, formatMip);
@ -426,6 +430,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
theTexture->setSource(srcImageName);
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
generateMips(theTexture, image, formatMip); generateMips(theTexture, image, formatMip);
@ -737,6 +742,7 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
// If the 6 faces have been created go on and define the true Texture // If the 6 faces have been created go on and define the true Texture
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) { if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
theTexture->setSource(srcImageName);
int f = 0; int f = 0;
for (auto& face : faces) { for (auto& face : faces) {
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);

View file

@ -47,7 +47,7 @@ public:
static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask); static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask);
static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip,
const QImage& srcImage, bool isLinear, bool doCompress); const QImage& srcImage, bool isLinear, bool doCompress);
static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips); static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips);
static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance); static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance);
}; };

View file

@ -124,36 +124,6 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) {
return dataStream; return dataStream;
} }
QHostAddress getGuessedLocalAddress() {
QHostAddress localAddress;
foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
if (networkInterface.flags() & QNetworkInterface::IsUp
&& networkInterface.flags() & QNetworkInterface::IsRunning
&& networkInterface.flags() & ~QNetworkInterface::IsLoopBack) {
// we've decided that this is the active NIC
// enumerate it's addresses to grab the IPv4 address
foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
// make sure it's an IPv4 address that isn't the loopback
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
// set our localAddress and break out
localAddress = entry.ip();
break;
}
}
}
if (!localAddress.isNull()) {
break;
}
}
// return the looked up local address
return localAddress;
}
uint qHash(const HifiSockAddr& key, uint seed) { uint qHash(const HifiSockAddr& key, uint seed) {
// use the existing QHostAddress and quint16 hash functions to get our hash // use the existing QHostAddress and quint16 hash functions to get our hash
return qHash(key.getAddress(), seed) ^ qHash(key.getPort(), seed); return qHash(key.getAddress(), seed) ^ qHash(key.getPort(), seed);

View file

@ -91,9 +91,6 @@ namespace std {
}; };
} }
QHostAddress getGuessedLocalAddress();
Q_DECLARE_METATYPE(HifiSockAddr); Q_DECLARE_METATYPE(HifiSockAddr);
#endif // hifi_HifiSockAddr_h #endif // hifi_HifiSockAddr_h

View file

@ -25,6 +25,7 @@
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <LogHandler.h> #include <LogHandler.h>
#include <shared/NetworkUtils.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <SharedUtil.h> #include <SharedUtil.h>

View file

@ -34,7 +34,21 @@ Antialiasing::Antialiasing() {
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
int width = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(); int width = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width();
int height = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height(); int height = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height();
if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) {
_antialiasingBuffer.reset();
}
if (!_antialiasingBuffer) {
// Link the antialiasing FBO to texture
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
_antialiasingTexture->setSource("Antialiasing::_antialiasingTexture");
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
}
if (!_antialiasingPipeline) { if (!_antialiasingPipeline) {
auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); auto vs = gpu::Shader::createVertex(std::string(fxaa_vert));
auto ps = gpu::Shader::createPixel(std::string(fxaa_frag)); auto ps = gpu::Shader::createPixel(std::string(fxaa_frag));
@ -51,21 +65,10 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
state->setDepthTest(false, false, gpu::LESS_EQUAL); state->setDepthTest(false, false, gpu::LESS_EQUAL);
// Link the antialiasing FBO to texture
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
// Good to go add the brand new pipeline // Good to go add the brand new pipeline
_antialiasingPipeline = gpu::Pipeline::create(program, state); _antialiasingPipeline = gpu::Pipeline::create(program, state);
} }
if (width != _antialiasingBuffer->getWidth() || height != _antialiasingBuffer->getHeight()) {
_antialiasingBuffer->resize(width, height);
}
return _antialiasingPipeline; return _antialiasingPipeline;
} }

View file

@ -54,9 +54,11 @@ void DeferredFramebuffer::allocate() {
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
_deferredColorTexture->setSource("DeferredFramebuffer::_deferredColorTexture");
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(linearFormat, width, height, defaultSampler)); _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(linearFormat, width, height, defaultSampler));
_deferredNormalTexture->setSource("DeferredFramebuffer::_deferredNormalTexture");
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
_deferredSpecularTexture->setSource("DeferredFramebuffer::_deferredSpecularTexture");
_deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture); _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture);
_deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture); _deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture);
@ -67,6 +69,7 @@ void DeferredFramebuffer::allocate() {
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
if (!_primaryDepthTexture) { if (!_primaryDepthTexture) {
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
_primaryDepthTexture->setSource("DeferredFramebuffer::_primaryDepthTexture");
} }
_deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
@ -77,6 +80,7 @@ void DeferredFramebuffer::allocate() {
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler)); _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler));
_lightingTexture->setSource("DeferredFramebuffer::_lightingTexture");
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);

View file

@ -337,7 +337,13 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con
auto framebufferCache = DependencyManager::get<FramebufferCache>(); auto framebufferCache = DependencyManager::get<FramebufferCache>();
auto framebufferSize = framebufferCache->getFrameBufferSize(); auto framebufferSize = framebufferCache->getFrameBufferSize();
glm::ivec2 frameSize(framebufferSize.width(), framebufferSize.height()); glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height());
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
// rendering
if (_primaryFramebuffer && _primaryFramebuffer->getSize() != frameSize) {
_primaryFramebuffer.reset();
}
if (!_primaryFramebuffer) { if (!_primaryFramebuffer) {
_primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
@ -345,6 +351,7 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler)); auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler));
primaryColorTexture->setSource("PreparePrimaryFramebuffer::primaryColorTexture");
_primaryFramebuffer->setRenderBuffer(0, primaryColorTexture); _primaryFramebuffer->setRenderBuffer(0, primaryColorTexture);
@ -352,11 +359,10 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler)); auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler));
primaryDepthTexture->setSource("PreparePrimaryFramebuffer::primaryDepthTexture");
_primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat);
} }
_primaryFramebuffer->resize(frameSize.x, frameSize.y);
primaryFramebuffer = _primaryFramebuffer; primaryFramebuffer = _primaryFramebuffer;
} }

View file

@ -415,6 +415,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringProfile(Rend
// const auto pixelFormat = gpu::Element::COLOR_SRGBA_32; // const auto pixelFormat = gpu::Element::COLOR_SRGBA_32;
const auto pixelFormat = gpu::Element::COLOR_R11G11B10; const auto pixelFormat = gpu::Element::COLOR_R11G11B10;
auto profileMap = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, PROFILE_RESOLUTION, 1, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); auto profileMap = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, PROFILE_RESOLUTION, 1, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
profileMap->setSource("Generated Scattering Profile");
diffuseProfileGPU(profileMap, args); diffuseProfileGPU(profileMap, args);
return profileMap; return profileMap;
} }
@ -426,6 +427,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin
const auto pixelFormat = gpu::Element::COLOR_R11G11B10; const auto pixelFormat = gpu::Element::COLOR_R11G11B10;
auto scatteringLUT = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, TABLE_RESOLUTION, TABLE_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); auto scatteringLUT = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, TABLE_RESOLUTION, TABLE_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
//diffuseScatter(scatteringLUT); //diffuseScatter(scatteringLUT);
scatteringLUT->setSource("Generated pre-integrated scattering");
diffuseScatterGPU(profile, scatteringLUT, args); diffuseScatterGPU(profile, scatteringLUT, args);
return scatteringLUT; return scatteringLUT;
} }
@ -433,6 +435,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin
gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringSpecularBeckmann(RenderArgs* args) { gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringSpecularBeckmann(RenderArgs* args) {
const int SPECULAR_RESOLUTION = 256; const int SPECULAR_RESOLUTION = 256;
auto beckmannMap = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32 /*gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB)*/, SPECULAR_RESOLUTION, SPECULAR_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); auto beckmannMap = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32 /*gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB)*/, SPECULAR_RESOLUTION, SPECULAR_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)));
beckmannMap->setSource("Generated beckmannMap");
computeSpecularBeckmannGPU(beckmannMap, args); computeSpecularBeckmannGPU(beckmannMap, args);
return beckmannMap; return beckmannMap;
} }

View file

@ -74,6 +74,7 @@ void LinearDepthFramebuffer::allocate() {
// For Linear Depth: // For Linear Depth:
_linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_linearDepthTexture->setSource("LinearDepthFramebuffer::_linearDepthTexture");
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
@ -81,10 +82,12 @@ void LinearDepthFramebuffer::allocate() {
// For Downsampling: // For Downsampling:
_halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_halfLinearDepthTexture->setSource("LinearDepthFramebuffer::_halfLinearDepthTexture");
_halfLinearDepthTexture->autoGenerateMips(5); _halfLinearDepthTexture->autoGenerateMips(5);
_halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_halfNormalTexture->setSource("LinearDepthFramebuffer::_halfNormalTexture");
_downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_downsampleFramebuffer->setRenderBuffer(0, _halfLinearDepthTexture); _downsampleFramebuffer->setRenderBuffer(0, _halfLinearDepthTexture);
@ -301,14 +304,17 @@ void SurfaceGeometryFramebuffer::allocate() {
auto height = _frameSize.y; auto height = _frameSize.y;
_curvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); _curvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_curvatureTexture->setSource("SurfaceGeometryFramebuffer::_curvatureTexture");
_curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture); _curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture);
_lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); _lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_lowCurvatureTexture->setSource("SurfaceGeometryFramebuffer::_lowCurvatureTexture");
_lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture); _lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture);
_blurringTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); _blurringTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_blurringTexture->setSource("SurfaceGeometryFramebuffer::_blurringTexture");
_blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_blurringFramebuffer->setRenderBuffer(0, _blurringTexture); _blurringFramebuffer->setRenderBuffer(0, _blurringTexture);
} }

View file

@ -96,6 +96,9 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
if (!sourceFramebuffer) { if (!sourceFramebuffer) {
return false; return false;
} }
if (_blurredFramebuffer && _blurredFramebuffer->getSize() != sourceFramebuffer->getSize()) {
_blurredFramebuffer.reset();
}
if (!_blurredFramebuffer) { if (!_blurredFramebuffer) {
_blurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _blurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
@ -107,21 +110,17 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler)); auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
_blurredFramebuffer->setRenderBuffer(0, blurringTarget); _blurredFramebuffer->setRenderBuffer(0, blurringTarget);
} else { }
// it would be easier to just call resize on the bluredFramebuffer and let it work if needed but the source might loose it's depth buffer when doing so
if ((_blurredFramebuffer->getWidth() != sourceFramebuffer->getWidth()) || (_blurredFramebuffer->getHeight() != sourceFramebuffer->getHeight())) {
_blurredFramebuffer->resize(sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), sourceFramebuffer->getNumSamples());
//if (sourceFramebuffer->hasDepthStencil()) {
// _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
//}
}
}
blurringResources.sourceTexture = sourceFramebuffer->getRenderBuffer(0); blurringResources.sourceTexture = sourceFramebuffer->getRenderBuffer(0);
blurringResources.blurringFramebuffer = _blurredFramebuffer; blurringResources.blurringFramebuffer = _blurredFramebuffer;
blurringResources.blurringTexture = _blurredFramebuffer->getRenderBuffer(0); blurringResources.blurringTexture = _blurredFramebuffer->getRenderBuffer(0);
if (_generateOutputFramebuffer) { if (_generateOutputFramebuffer) {
if (_outputFramebuffer && _outputFramebuffer->getSize() != sourceFramebuffer->getSize()) {
_outputFramebuffer.reset();
}
// The job output the blur result in a new Framebuffer spawning here. // The job output the blur result in a new Framebuffer spawning here.
// Let s make sure it s ready for this // Let s make sure it s ready for this
if (!_outputFramebuffer) { if (!_outputFramebuffer) {
@ -134,13 +133,6 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler)); auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler));
_outputFramebuffer->setRenderBuffer(0, blurringTarget); _outputFramebuffer->setRenderBuffer(0, blurringTarget);
} else {
if ((_outputFramebuffer->getWidth() != sourceFramebuffer->getWidth()) || (_outputFramebuffer->getHeight() != sourceFramebuffer->getHeight())) {
_outputFramebuffer->resize(sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), sourceFramebuffer->getNumSamples());
/* if (sourceFramebuffer->hasDepthStencil()) {
_outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
}*/
}
} }
// Should be good to use the output Framebuffer as final // Should be good to use the output Framebuffer as final

View file

@ -15,11 +15,12 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtGui/QDesktopServices> #include <QtGui/QDesktopServices>
#include <NumericalConstants.h> #include "FileUtils.h"
#include <FileUtils.h> #include "NetworkUtils.h"
#include <SharedUtil.h>
#include "../NumericalConstants.h"
#include "../SharedUtil.h"
#include "HifiSockAddr.h"
static const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt"; static const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt";
static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss"; static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";

View file

@ -13,7 +13,7 @@
#define hifi_FileLogger_h #define hifi_FileLogger_h
#include "AbstractLoggerInterface.h" #include "AbstractLoggerInterface.h"
#include <GenericQueueThread.h> #include "../GenericQueueThread.h"
#include <QtCore/QFile> #include <QtCore/QFile>

View file

@ -9,14 +9,29 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <qdir.h>
#include <qfileinfo.h>
#include <qdesktopservices.h>
#include <qprocess.h>
#include <qurl.h>
#include "FileUtils.h" #include "FileUtils.h"
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QUrl>
#include <QtCore/QTextStream>
#include <QtCore/QRegularExpression>
#include <QtGui/QDesktopServices>
QString FileUtils::readFile(const QString& filename) {
QFile file(filename);
file.open(QFile::Text | QFile::ReadOnly);
QString result;
result.append(QTextStream(&file).readAll());
return result;
}
QStringList FileUtils::readLines(const QString& filename, QString::SplitBehavior splitBehavior) {
return readFile(filename).split(QRegularExpression("[\\r\\n]"), QString::SkipEmptyParts);
}
void FileUtils::locateFile(QString filePath) { void FileUtils::locateFile(QString filePath) {

View file

@ -19,7 +19,8 @@ class FileUtils {
public: public:
static void locateFile(QString fileName); static void locateFile(QString fileName);
static QString standardPath(QString subfolder); static QString standardPath(QString subfolder);
static QString readFile(const QString& filename);
static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts);
}; };
#endif // hifi_FileUtils_h #endif // hifi_FileUtils_h

View file

@ -0,0 +1,42 @@
//
// Created by Bradley Austin Davis on 2016/09/20
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "NetworkUtils.h"
#include <QtNetwork/QNetworkInterface>
QHostAddress getGuessedLocalAddress() {
QHostAddress localAddress;
foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
if (networkInterface.flags() & QNetworkInterface::IsUp
&& networkInterface.flags() & QNetworkInterface::IsRunning
&& networkInterface.flags() & ~QNetworkInterface::IsLoopBack) {
// we've decided that this is the active NIC
// enumerate it's addresses to grab the IPv4 address
foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
// make sure it's an IPv4 address that isn't the loopback
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
// set our localAddress and break out
localAddress = entry.ip();
break;
}
}
}
if (!localAddress.isNull()) {
break;
}
}
// return the looked up local address
return localAddress;
}

View file

@ -0,0 +1,17 @@
//
// Created by Bradley Austin Davis on 2016/09/20
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_shared_NetworkUtils_h
#define hifi_shared_NetworkUtils_h
#include <QtNetwork/QHostAddress>
QHostAddress getGuessedLocalAddress();
#endif // hifi_shared_NetworkUtils_h

View file

@ -14,9 +14,10 @@ protected:
public: public:
glm::quat getOrientation() const { glm::quat getOrientation() const {
return glm::angleAxis(yaw, Vectors::UP); return glm::angleAxis(yawPitch.x, Vectors::UP) * glm::angleAxis(yawPitch.y, Vectors::RIGHT);
} }
float yaw { 0 };
vec2 yawPitch { 0 };
glm::vec3 position; glm::vec3 position;
float rotationSpeed { 1.0f }; float rotationSpeed { 1.0f };
float movementSpeed { 1.0f }; float movementSpeed { 1.0f };
@ -76,7 +77,12 @@ public:
}; };
void rotate(const float delta) { void rotate(const float delta) {
yaw += delta; yawPitch.x += delta;
updateViewMatrix();
}
void rotate(const glm::vec2& delta) {
yawPitch += delta;
updateViewMatrix(); updateViewMatrix();
} }
@ -84,7 +90,11 @@ public:
glm::vec3 f = rotation * Vectors::UNIT_NEG_Z; glm::vec3 f = rotation * Vectors::UNIT_NEG_Z;
f.y = 0; f.y = 0;
f = glm::normalize(f); f = glm::normalize(f);
yaw = angleBetween(Vectors::UNIT_NEG_Z, f); yawPitch.x = angleBetween(Vectors::UNIT_NEG_Z, f);
f = rotation * Vectors::UNIT_NEG_Z;
f.x = 0;
f = glm::normalize(f);
yawPitch.y = angleBetween(Vectors::UNIT_NEG_Z, f);
updateViewMatrix(); updateViewMatrix();
} }

View file

@ -17,6 +17,7 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QElapsedTimer> #include <QtCore/QElapsedTimer>
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
#include <QtCore/QRegularExpression>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtCore/QThreadPool> #include <QtCore/QThreadPool>
@ -32,12 +33,12 @@
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <shared/NetworkUtils.h>
#include <shared/FileLogger.h>
#include <shared/FileUtils.h>
#include <LogHandler.h>
#include <AssetClient.h> #include <AssetClient.h>
//#include <gl/OffscreenGLCanvas.h>
//#include <gl/GLHelpers.h>
//#include <gl/QOpenGLContextWrapper.h>
#include <gpu/gl/GLBackend.h> #include <gpu/gl/GLBackend.h>
#include <gpu/gl/GLFramebuffer.h> #include <gpu/gl/GLFramebuffer.h>
#include <gpu/gl/GLTexture.h> #include <gpu/gl/GLTexture.h>
@ -99,56 +100,6 @@ public:
} }
}; };
#if 0
class GlfwCamera : public Camera {
Key forKey(int key) {
switch (key) {
case GLFW_KEY_W: return FORWARD;
case GLFW_KEY_S: return BACK;
case GLFW_KEY_A: return LEFT;
case GLFW_KEY_D: return RIGHT;
case GLFW_KEY_E: return UP;
case GLFW_KEY_C: return DOWN;
case GLFW_MOUSE_BUTTON_LEFT: return MLEFT;
case GLFW_MOUSE_BUTTON_RIGHT: return MRIGHT;
case GLFW_MOUSE_BUTTON_MIDDLE: return MMIDDLE;
default: break;
}
return INVALID;
}
vec2 _lastMouse;
public:
void keyHandler(int key, int scancode, int action, int mods) {
Key k = forKey(key);
if (k == INVALID) {
return;
}
if (action == GLFW_PRESS) {
keys.set(k);
} else if (action == GLFW_RELEASE) {
keys.reset(k);
}
}
//static void MouseMoveHandler(GLFWwindow* window, double posx, double posy);
//static void MouseScrollHandler(GLFWwindow* window, double xoffset, double yoffset);
void onMouseMove(double posx, double posy) {
vec2 mouse = vec2(posx, posy);
vec2 delta = mouse - _lastMouse;
if (keys.at(Key::MRIGHT)) {
dolly(delta.y * 0.01f);
} else if (keys.at(Key::MLEFT)) {
rotate(delta.x * -0.01f);
} else if (keys.at(Key::MMIDDLE)) {
delta.y *= -1.0f;
translate(delta * -0.01f);
}
_lastMouse = mouse;
}
};
#else
class QWindowCamera : public Camera { class QWindowCamera : public Camera {
Key forKey(int key) { Key forKey(int key) {
switch (key) { switch (key) {
@ -188,7 +139,8 @@ public:
if (buttons & Qt::RightButton) { if (buttons & Qt::RightButton) {
dolly(delta.y * 0.01f); dolly(delta.y * 0.01f);
} else if (buttons & Qt::LeftButton) { } else if (buttons & Qt::LeftButton) {
rotate(delta.x * -0.01f); //rotate(delta.x * -0.01f);
rotate(delta * -0.01f);
} else if (buttons & Qt::MiddleButton) { } else if (buttons & Qt::MiddleButton) {
delta.y *= -1.0f; delta.y *= -1.0f;
translate(delta * -0.01f); translate(delta * -0.01f);
@ -197,7 +149,6 @@ public:
_lastMouse = mouse; _lastMouse = mouse;
} }
}; };
#endif
static QString toHumanSize(size_t size, size_t maxUnit = std::numeric_limits<size_t>::max()) { static QString toHumanSize(size_t size, size_t maxUnit = std::numeric_limits<size_t>::max()) {
static const std::vector<QString> SUFFIXES{ { "B", "KB", "MB", "GB", "TB", "PB" } }; static const std::vector<QString> SUFFIXES{ { "B", "KB", "MB", "GB", "TB", "PB" } };
@ -240,7 +191,7 @@ public:
std::mutex _mutex; std::mutex _mutex;
std::shared_ptr<gpu::Backend> _backend; std::shared_ptr<gpu::Backend> _backend;
std::vector<uint64_t> _frameTimes; std::vector<uint64_t> _frameTimes;
size_t _frameIndex; size_t _frameIndex { 0 };
std::mutex _frameLock; std::mutex _frameLock;
std::queue<gpu::FramePointer> _pendingFrames; std::queue<gpu::FramePointer> _pendingFrames;
gpu::FramePointer _activeFrame; gpu::FramePointer _activeFrame;
@ -252,7 +203,6 @@ public:
_pendingFrames.push(frame); _pendingFrames.push(frame);
} }
void initialize(QWindow* window, gl::Context& initContext) { void initialize(QWindow* window, gl::Context& initContext) {
setObjectName("RenderThread"); setObjectName("RenderThread");
_context.setWindow(window); _context.setWindow(window);
@ -286,10 +236,6 @@ public:
} }
_context.makeCurrent(); _context.makeCurrent();
glewExperimental = true;
glewInit();
glGetError();
_frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0); _frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0);
{ {
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
@ -375,7 +321,6 @@ public:
} }
} }
bool process() override { bool process() override {
std::queue<gpu::FramePointer> pendingFrames; std::queue<gpu::FramePointer> pendingFrames;
{ {
@ -420,6 +365,7 @@ public:
}; };
render::ItemID BackgroundRenderData::_item = 0; render::ItemID BackgroundRenderData::_item = 0;
QSharedPointer<FileLogger> logger;
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) {
@ -552,36 +498,6 @@ public:
_renderThread.initialize(this, _initContext); _renderThread.initialize(this, _initContext);
_initContext.makeCurrent(); _initContext.makeCurrent();
#if 0
glfwInit();
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
resizeWindow(QSize(800, 600));
_window = glfwCreateWindow(_size.width(), _size.height(), "Window Title", NULL, NULL);
if (!_window) {
throw std::runtime_error("Could not create window");
}
glfwSetWindowUserPointer(_window, this);
glfwSetKeyCallback(_window, KeyboardHandler);
glfwSetMouseButtonCallback(_window, MouseHandler);
glfwSetCursorPosCallback(_window, MouseMoveHandler);
glfwSetWindowCloseCallback(_window, CloseHandler);
glfwSetFramebufferSizeCallback(_window, FramebufferSizeHandler);
glfwSetScrollCallback(_window, MouseScrollHandler);
glfwMakeContextCurrent(_window);
GLDebug::setupLogger(this);
#endif
#ifdef Q_OS_WIN
//wglSwapIntervalEXT(0);
#endif
// FIXME use a wait condition // FIXME use a wait condition
QThread::msleep(1000); QThread::msleep(1000);
_renderThread.submitFrame(gpu::FramePointer()); _renderThread.submitFrame(gpu::FramePointer());
@ -622,6 +538,16 @@ public:
DependencyManager::destroy<NodeList>(); DependencyManager::destroy<NodeList>();
} }
void loadCommands(const QString& filename) {
QFileInfo fileInfo(filename);
if (!fileInfo.exists()) {
return;
}
_commandPath = fileInfo.absolutePath();
_commands = FileUtils::readLines(filename);
_commandIndex = 0;
}
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override { bool eventFilter(QObject *obj, QEvent *event) override {
@ -666,6 +592,14 @@ protected:
toggleCulling(); toggleCulling();
return; return;
case Qt::Key_Home:
gpu::Texture::setAllowedGPUMemoryUsage(0);
return;
case Qt::Key_End:
gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(256));
return;
default: default:
break; break;
@ -776,10 +710,11 @@ private:
}; };
void updateText() { void updateText() {
QString title = QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4") QString title = QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4 Max GPU %5")
.arg(_fps).arg(_cullingEnabled) .arg(_fps).arg(_cullingEnabled)
.arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2)) .arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2))
.arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2)); .arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2))
.arg(toHumanSize(gpu::Texture::getAllowedGPUMemoryUsage(), 2));
setTitle(title); setTitle(title);
#if 0 #if 0
{ {
@ -803,10 +738,77 @@ private:
#endif #endif
} }
void runCommand(const QString& command) {
qDebug() << "Running command: " << command;
QStringList commandParams = command.split(QRegularExpression(QString("\\s")));
QString verb = commandParams[0].toLower();
if (verb == "loop") {
if (commandParams.length() > 1) {
int maxLoops = commandParams[1].toInt();
if (maxLoops < ++_commandLoops) {
qDebug() << "Exceeded loop count";
return;
}
}
_commandIndex = 0;
} else if (verb == "wait") {
if (commandParams.length() < 2) {
qDebug() << "No wait time specified";
return;
}
int seconds = commandParams[1].toInt();
_nextCommandTime = usecTimestampNow() + seconds * USECS_PER_SECOND;
} else if (verb == "load") {
if (commandParams.length() < 2) {
qDebug() << "No load file specified";
return;
}
QString file = commandParams[1];
if (QFileInfo(file).isRelative()) {
file = _commandPath + "/" + file;
}
if (!QFileInfo(file).exists()) {
qDebug() << "Cannot find scene file " + file;
return;
}
importScene(file);
} else if (verb == "go") {
if (commandParams.length() < 2) {
qDebug() << "No destination specified for go command";
return;
}
parsePath(commandParams[1]);
} else {
qDebug() << "Unknown command " << command;
}
}
void runNextCommand(quint64 now) {
if (_commands.empty()) {
return;
}
if (_commandIndex >= _commands.size()) {
_commands.clear();
return;
}
if (now < _nextCommandTime) {
return;
}
_nextCommandTime = 0;
QString command = _commands[_commandIndex++];
runCommand(command);
}
void update() { void update() {
auto now = usecTimestampNow(); auto now = usecTimestampNow();
static auto last = now; static auto last = now;
runNextCommand(now);
float delta = now - last; float delta = now - last;
// Update the camera // Update the camera
_camera.update(delta / USECS_PER_SECOND); _camera.update(delta / USECS_PER_SECOND);
@ -959,7 +961,6 @@ private:
QString atpUrl = QUrl::fromLocalFile(atpPath).toString(); QString atpUrl = QUrl::fromLocalFile(atpPath).toString();
ResourceManager::setUrlPrefixOverride("atp:/", atpUrl + "/"); ResourceManager::setUrlPrefixOverride("atp:/", atpUrl + "/");
} }
_settings.setValue(LAST_SCENE_KEY, fileName);
_octree->clear(); _octree->clear();
_octree->getTree()->readFromURL(fileName); _octree->getTree()->readFromURL(fileName);
} }
@ -978,6 +979,7 @@ private:
if (fileName.isNull()) { if (fileName.isNull()) {
return; return;
} }
_settings.setValue(LAST_SCENE_KEY, fileName);
importScene(fileName); importScene(fileName);
} }
@ -1015,7 +1017,7 @@ private:
} }
void resetPosition() { void resetPosition() {
_camera.yaw = 0; _camera.yawPitch = vec3(0);
_camera.setPosition(vec3()); _camera.setPosition(vec3());
} }
@ -1077,6 +1079,13 @@ private:
model::SunSkyStage _sunSkyStage; model::SunSkyStage _sunSkyStage;
model::LightPointer _globalLight { std::make_shared<model::Light>() }; model::LightPointer _globalLight { std::make_shared<model::Light>() };
bool _ready { false }; bool _ready { false };
QStringList _commands;
QString _commandPath;
int _commandLoops { 0 };
int _commandIndex { -1 };
uint64_t _nextCommandTime { 0 };
//TextOverlay* _textOverlay; //TextOverlay* _textOverlay;
static bool _cullingEnabled; static bool _cullingEnabled;
@ -1093,12 +1102,14 @@ private:
bool QTestWindow::_cullingEnabled = true; bool QTestWindow::_cullingEnabled = true;
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
if (!message.isEmpty()) { QString logMessage = LogHandler::getInstance().printMessage((LogMsgType)type, context, message);
if (!logMessage.isEmpty()) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
OutputDebugStringA(message.toLocal8Bit().constData()); OutputDebugStringA(logMessage.toLocal8Bit().constData());
OutputDebugStringA("\n"); OutputDebugStringA("\n");
#endif #endif
std::cout << message.toLocal8Bit().constData() << std::endl; logger->addMessage(qPrintable(logMessage + "\n"));
} }
} }
@ -1106,16 +1117,19 @@ const char * LOG_FILTER_RULES = R"V0G0N(
hifi.gpu=true hifi.gpu=true
)V0G0N"; )V0G0N";
int main(int argc, char** argv) { int main(int argc, char** argv) {
QApplication app(argc, argv); QApplication app(argc, argv);
QCoreApplication::setApplicationName("RenderPerf"); QCoreApplication::setApplicationName("RenderPerf");
QCoreApplication::setOrganizationName("High Fidelity"); QCoreApplication::setOrganizationName("High Fidelity");
QCoreApplication::setOrganizationDomain("highfidelity.com"); QCoreApplication::setOrganizationDomain("highfidelity.com");
logger.reset(new FileLogger());
qInstallMessageHandler(messageHandler); qInstallMessageHandler(messageHandler);
QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QTestWindow::setup(); QTestWindow::setup();
QTestWindow window; QTestWindow window;
//window.loadCommands("C:/Users/bdavis/Git/dreaming/exports/commands.txt");
app.exec(); app.exec();
return 0; return 0;
} }

View file

@ -297,8 +297,6 @@ public:
}; };
QTestWindow() { QTestWindow() {
_currentTexture = _textures.end();
{ {
QStringList stringList; QStringList stringList;
QFile textFile(DATA_DIR.path() + "/loads.txt"); QFile textFile(DATA_DIR.path() + "/loads.txt");
@ -318,12 +316,13 @@ public:
QString timeStr = s.left(index); QString timeStr = s.left(index);
auto time = timeStr.toUInt(); auto time = timeStr.toUInt();
QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed(); QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed();
qDebug() << "Path " << path;
if (!QFileInfo(path).exists()) { if (!QFileInfo(path).exists()) {
continue; continue;
} }
_textureLoads.push({ time, path, s }); qDebug() << "Path " << path;
_texturesFiles.push_back({ time, path, s });
} }
_textures.resize(_texturesFiles.size());
} }
installEventFilter(this); installEventFilter(this);
@ -383,6 +382,33 @@ protected:
} }
void keyPressEvent(QKeyEvent* event) override { void keyPressEvent(QKeyEvent* event) override {
switch (event->key()) {
case Qt::Key_Left:
prevTexture();
break;
case Qt::Key_Right:
nextTexture();
break;
case Qt::Key_Return:
reportMemory();
break;
case Qt::Key_PageDown:
derezTexture();
break;
case Qt::Key_Home:
unloadAll();
break;
case Qt::Key_End:
loadAll();
break;
case Qt::Key_Down:
loadTexture();
break;
case Qt::Key_Up:
unloadTexture();
break;
}
QWindow::keyPressEvent(event);
} }
void keyReleaseEvent(QKeyEvent* event) override { void keyReleaseEvent(QKeyEvent* event) override {
@ -395,10 +421,80 @@ protected:
resizeWindow(ev->size()); resizeWindow(ev->size());
} }
void nextTexture() {
if (_textures.empty()) {
return;
}
auto textureCount = _textures.size();
_currentTextureIndex = (_currentTextureIndex + 1) % textureCount;
loadTexture();
}
void prevTexture() {
if (_textures.empty()) {
return;
}
auto textureCount = _textures.size();
_currentTextureIndex = (_currentTextureIndex + textureCount - 1) % textureCount;
loadTexture();
}
void reportMemory() {
static GLint lastMemory = 0;
GLint availableMem;
glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &availableMem);
qDebug() << "Memory available " << availableMem;
if (lastMemory != 0) {
qDebug() << "Delta " << availableMem - lastMemory;
}
lastMemory = availableMem;
}
void derezTexture() {
if (!_textures[_currentTextureIndex]) {
return;
}
auto texture = _textures[_currentTextureIndex];
texture->setMinMip(texture->minMip() + 1);
}
void loadTexture() {
if (_textures[_currentTextureIndex]) {
return;
}
auto file = _texturesFiles[_currentTextureIndex].file;
qDebug() << "Loading texture " << file;
_textures[_currentTextureIndex] = DependencyManager::get<TextureCache>()->getImageTexture(file);
}
void unloadTexture() {
if (_textures.empty()) {
return;
}
_textures[_currentTextureIndex].reset();
}
void loadAll() {
for (size_t i = 0; i < _texturesFiles.size(); ++i) {
if (_textures[i]) {
continue;
}
auto file = _texturesFiles[i].file;
qDebug() << "Loading texture " << file;
_textures[i] = DependencyManager::get<TextureCache>()->getImageTexture(file);
}
}
void unloadAll() {
for (auto& texture : _textures) {
texture.reset();
}
}
private: private:
std::queue<TextureLoad> _textureLoads; size_t _currentTextureIndex { 0 };
std::list<gpu::TexturePointer> _textures; std::vector<TextureLoad> _texturesFiles;
std::list<gpu::TexturePointer>::iterator _currentTexture; std::vector<gpu::TexturePointer> _textures;
uint16_t _fps; uint16_t _fps;
gpu::PipelinePointer _simplePipeline; gpu::PipelinePointer _simplePipeline;
@ -438,7 +534,9 @@ private:
auto now = usecTimestampNow(); auto now = usecTimestampNow();
static auto last = now; static auto last = now;
auto delta = (now - last) / USECS_PER_MSEC; auto delta = (now - last) / USECS_PER_MSEC;
if (!_textureLoads.empty()) { Q_UNUSED(delta);
#if 0
if (!_textures.empty()) {
const auto& front = _textureLoads.front(); const auto& front = _textureLoads.front();
if (delta >= front.time) { if (delta >= front.time) {
QFileInfo fileInfo(front.file); QFileInfo fileInfo(front.file);
@ -456,6 +554,7 @@ private:
} }
} }
} }
#endif
} }
void render() { void render() {
@ -474,14 +573,8 @@ private:
auto vpsize = framebuffer->getSize(); auto vpsize = framebuffer->getSize();
auto vppos = ivec2(0); auto vppos = ivec2(0);
batch.setViewportTransform(ivec4(vppos, vpsize)); batch.setViewportTransform(ivec4(vppos, vpsize));
if (_currentTexture != _textures.end()) { if (!_textures.empty()) {
++_currentTexture; batch.setResourceTexture(0, _textures[_currentTextureIndex]);
}
if (_currentTexture == _textures.end()) {
_currentTexture = _textures.begin();
}
if (_currentTexture != _textures.end()) {
batch.setResourceTexture(0, *_currentTexture);
} }
batch.setPipeline(_simplePipeline); batch.setPipeline(_simplePipeline);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
@ -564,7 +657,6 @@ int main(int argc, char** argv) {
}).waitForDownload(); }).waitForDownload();
} }
QTestWindow::setup(); QTestWindow::setup();
QTestWindow window; QTestWindow window;
app.exec(); app.exec();